我长期以来一直在努力,我怀疑其他用户也这样做。
首先我要说我没有替代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的作者没有时间支持这一点。