使用UFPDF的FPDF Unicode支持

时间:2014-08-22 05:54:04

标签: php unicode fpdf

我长期以来一直在努力,我怀疑其他用户也这样做。

首先我要说我没有替代FPDF因为我使用了很多其他FPDF模块,所以请尽量不要建议使用像TCPDF这样的其他库。

我真的需要让FPDF能够以稳定的方式处理UTF-8字符。

我已经找到了什么:

有一个名为UFPDF的扩展名 http://acko.net/blog/ufpdf-unicode-utf-8-extension-for-fpdf/

该扩展程序目前仅支持TrueType字体,但它应该适用于我。 .ttf文件必须由名为ttf2ufm的工具转换,生成的.ufm和源.ttf通过使用给定的工具makefontuni.php转换为font.php,font.z和font.ctg.z文件。 / p>

到目前为止一切顺利。所以我试图从我的电脑转换Arial字体。 (arial.ttf,arialbd.ttf,arialbi.ttf,ariali.ttf)

它工作正常,我能够生成带有unicode字符的test.pdf。但是AdobeReader显示的是一个错误弹出窗口,其中包含:Bad Parameter - 字体ArialMT包含错误/宽度。

我注意到所有字符都有相同的宽度(我怀疑默认宽度)所以我试着调试。

我发现UPDF将宽度添加到PDF中:

charnumber [width] charnumber [width]

85 [276] (for the "u" character)

我发现有些字符的索引值为负值:

-70 [266]

索引值由ttf2ufm创建。如果我查看结果arial.ufm,我发现这样的条目:

U -70 ; WX 450 ; N uni06BE ; G 1003 ; B -70 256 788 1136 ;

我怀疑U是utf-8表中的索引,我修改了makefontuni.php,使其忽略了U的负值。再次创建了font.php,font.z和font.ctg.z工作。错误通知未显示,字符显示正确的宽度。

所以第一个问题是: 为什么ttf2ufm会为U产生负值?它是否正确?如果它是正确的,为什么AdobeReader无法处理它?<​​/ p>

我希望这一切都可以,但事实并非如此。

我使用BOLD字体和较低的&#34; u&#34;进行了一些测试。使用arial粗体时,字符显示为一个奇怪的符号。

我再次调试,我发现这条线路为&#34; u&#34; arialbd.ufm中的字符

U 117 ; WX 611 ; N u ; G 88 ; B 141 -24 1107 1062 ;

我搜索了&#34; U 117&#34;在那个文件中,我找到了另一个以&#34; U 117开头的角色;&#34;。我已经删除了它,所以我不能在这里发布。然而,这是pdf中显示的错误字符,删除后,您已正确显示。

所以第二个问题是:为什么ttf2ufm生成一个包含2个字符并具有相同索引的.ufm文件的原因是什么?这种情况仅适用于arialbd.ttf而不适用于arial.ttf。

但是我现在解决了这个问题,希望没有其他的双索引字符。

更多问题:

我认识到生成的arial.php包含字符宽度:

$cw=array(
    32=>278, 160=>278, 33=>278, 34=>355, 35=>556, 36=>556, 
    37=>889, 38=>667, 39=>191, 40=>333, 41=>333, 42=>389, 43=>584, 
    44=>278, 45=>333, 173=>333, [...]

非unicode版本中的arial.php也包含$cw数组。但它使用字符本身作为索引,而不是索引号:

$cw=array(  
    chr(0)=>750,chr(1)=>750,chr(2)=>750,chr(3)=>750,chr(4)=>750,
    chr(5)=>750,chr(6)=>750,chr(7)=>750,chr(8)=>750,chr(9)=>750,chr(10)=>750,
    chr(11)=>750,chr(12)=>750, [...]

并且fpdf.php有时会尝试访问$cw值,而其他一些模块也会这样做,以便能够计算给定字符串的宽度。所有这一切都失败了UFPDF。

我尝试通过修改fpdf.php以及尝试访问$cw的所有模块来修复它:

我在fpdf类中创建了一个名为charlength的方法:

function charlength($char) 
{
    $cw = &$this->CurrentFont['cw'];
    return $cw[$char];
}

让FPDF在想要访问charlength时致电$this->CurrentFont['cw']

function GetStringWidth($s)
{
    // Get width of a string in the current font
    $s = (string)$s;
    // $cw = &$this->CurrentFont['cw']; // Old FPDF-Code
    $w = 0;
    $l = strlen($s);
    for($i=0;$i<$l;$i++) {
        // $w += $cw[$s[$i]]; // Old FPDF-Code
        $w += $this->charlength($s[$i]); // My replacement
    }
    return $w*$this->FontSize/1000;
}

在ufpdf.php中,我重写方法charlength,如下所示:

function charlength($char) {    
    $cw = &$this->CurrentFont['cw'];
    $utf8dec = $this->ordutf8($char, $offset);        
    if(!isset($cw[$utf8dec])) {
        return 0;
    }
    return $cw[$utf8dec];
}


function ordutf8($string, &$offset) {
    $string = class_stringTools::utf8_decode($string);
    $code = ord(substr($string, $offset,1));
    if ($code >= 128) {        //otherwise 0xxxxxxx
        if ($code < 224) $bytesnumber = 2;                //110xxxxx
        else if ($code < 240) $bytesnumber = 3;        //1110xxxx
        else if ($code < 248) $bytesnumber = 4;    //11110xxx
        else return -1;
        $codetemp = $code - 192 - ($bytesnumber > 2 ? 32 : 0) - ($bytesnumber > 3 ? 16 : 0);
        for ($i = 2; $i <= $bytesnumber; $i++) {
            $offset ++;
            $code2 = ord(substr($string, $offset, 1)) - 128;        //10xxxxxx
            $codetemp = $codetemp*64 + $code2;
        }
        $code = $codetemp;
    }
    $offset += 1;
    if ($offset >= strlen($string)) $offset = -1;
    return $code;
}

ordutf8方法来自php.net,但我不得不修改它,因为我$code的存储值一次$code的值为252,导致未定义{ {1}}。

然而它似乎现在有用,但我对编辑fpdf.php的源代码和其他模块的来源不是很满意。我想知道没有其他人报告我遇到的问题。

我知道我写得非常多,但我想知道每个人是否都有同样的问题。你怎么看待最后的修改?你有一些改进吗?我真的需要一种稳定的方法来使FPDF支持unicode字符。请帮帮我。

令人遗憾的是,ufpdf的作者没有时间支持这一点。

0 个答案:

没有答案