Php 使用UFPDF的FPDF Unicode支持
我已经为此绞尽脑汁很久了,我怀疑其他用户也会这么做 首先我必须说,我没有FPDF的替代品,因为我使用了很多其他FPDF模块,所以请尽量不要建议使用其他库,如TCPDF 我真的需要使FPDF能够以稳定的方式处理UTF-8字符 我已经发现的: 有一个扩展名为UFPDF 该扩展目前只支持TrueType字体,但它应该适合我。 .ttf文件必须由一个名为ttf2ufm的工具进行转换,并使用给定的工具makefontuni.php将生成的.ufm和source.ttf转换为font.php、font.z和font.ctg.z文件 到目前为止还不错。所以我试着从我的电脑转换成Arial字体。(arial.ttf、arialbd.ttf、arialbi.ttf、ariali.ttf) 它成功了,我能够生成一个带有unicode字符的test.pdf。但是这是一个由AdobeReader显示的错误弹出窗口,上面写着:Bad参数-字体ArialMT包含Bad/Widths 我注意到所有字符都有相同的宽度(我怀疑是默认宽度),所以我尝试调试 我发现UPDF将宽度添加到PDF中,如下所示:Php 使用UFPDF的FPDF Unicode支持,php,unicode,fpdf,Php,Unicode,Fpdf,我已经为此绞尽脑汁很久了,我怀疑其他用户也会这么做 首先我必须说,我没有FPDF的替代品,因为我使用了很多其他FPDF模块,所以请尽量不要建议使用其他库,如TCPDF 我真的需要使FPDF能够以稳定的方式处理UTF-8字符 我已经发现的: 有一个扩展名为UFPDF 该扩展目前只支持TrueType字体,但它应该适合我。 .ttf文件必须由一个名为ttf2ufm的工具进行转换,并使用给定的工具makefontuni.php将生成的.ufm和source.ttf转换为font.php、font.z
charnumber [width] charnumber [width]
85 [276] (for the "u" character)
U -70 ; WX 450 ; N uni06BE ; G 1003 ; B -70 256 788 1136 ;
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;
}
我发现有些字符的索引值为负值:
-70 [266]
索引值由ttf2ufm创建。如果我查看结果arial.ufm,我发现如下条目:
charnumber [width] charnumber [width]
85 [276] (for the "u" character)
U -70 ; WX 450 ; N uni06BE ; G 1003 ; B -70 256 788 1136 ;
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;
}
我怀疑U是utf-8表中的索引,我修改了makefontuni.php,使其忽略U的负值。再次创建了font.php、font.z和font.ctg.z,它成功了。错误通知未显示,字符显示的宽度正确
所以第一个问题是:
为什么ttf2ufm为U产生负值?这是正确的吗?如果它是正确的,为什么AdobeReader不能处理它
我希望这是全部,但事实并非如此
我使用粗体字体做了一些测试,当使用arial粗体时,较低的“u”字符显示为一个奇怪的符号
我再次调试,在arialbd.ufm中找到了“u”字符的这一行
U 117 ; WX 611 ; N u ; G 88 ; B 141 -24 1107 1062 ;
我在那个文件中搜索了“U 117”,发现了另一个以“U 117;”开头的字符。我已经删除了它,所以我不能在这里发布该行。但是,这是pdf中显示的错误字符,删除后,u已正确显示
那么第二个问题是:ttf2ufm生成具有相同索引的两个字符的.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, [...]
php有时会尝试访问$cw
值,其他一些模块也会这样做,以便能够计算给定字符串的宽度。对于UFPDF,所有这些都失败了
我试图通过修改fpdf.php和所有试图访问$cw
的模块来修复它,如下所示:
charnumber [width] charnumber [width]
85 [276] (for the "u" character)
U -70 ; WX 450 ; N uni06BE ; G 1003 ; B -70 256 788 1136 ;
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;
}
我在fpdf类中创建了一个名为charlength
的方法:
function charlength($char)
{
$cw = &$this->CurrentFont['cw'];
return $cw[$char];
}
并使FPDF在需要访问$this->CurrentFont['cw']
时调用charlength
:
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;
}
ordutf8
方法来自php.net,但我不得不修改它,因为有一次$code
的值为252,导致未定义的$bytenumber
不过,它现在似乎可以工作,但我对编辑fpdf.php的源代码和其他模块的源代码不太满意。我想知道没有其他人报告我所遇到的问题
我知道我写了很多,但我想知道是否每个人都有同样的问题。你觉得最后的修改怎么样?你有什么改进吗?我真的需要一个稳定的方法使FPDF支持unicode字符。请帮帮我
令人遗憾的是,ufpdf的作者没有时间支持这一点。您也检查了吗?它支持UTF-8和字体子集设置。适用于从左到右的语言。