FPDF中的编码
最近在用FPDF生成pdf时,用UTF-8编码的日文或者繁体文字始终都是乱码。查了相关资料后,才发现FPDF本身并不支持UTF-8,除此之外,FPDF对中,日,韩支持的扩展类中使用的是CID字体,和我们window中用到的字体的都不同。因此当你使用支持中文的扩展类时,生成pdf时对日文肯定是不支持的。而TCPDF据说是支持UTF-8,但使用后发现对中文的支持很烂,还要手工转换字体,其方式和UFPDF是一样的。而我们很难找到一种同时对中,日,韩都支持的字体。用msgothic也只是对日文和繁体支持的比较好而已,对简体中文用华文中宋等字体显示更好一些,因此我的结论是,用FPDF生成pdf时,如果文件包含中文,日文,韩文等内容时,生成的pdf肯定有乱码或者空白。除非我们确切的知道文件中哪些地方显示中文,哪些地方显示日文,那我们就可以在开始的时用addfont添加这些字体,然后在输出的时候用setfont指定要输出的内容采取哪种字体。
此外,在解决乱码问题时容易遇到的以下问题:
现象一:当修改页面字符集为UTF-8,页面出现空白,不显示任何内容
都是字符集charset惹的祸,理由在于用charset指定为UTF-8之前,已经有非UTF-8编码文字的输出。比如一般html页面都是把title标签放在meta标签前面,因此80%的可能是title内容的编码和UTF-8引起的,最好的解决方法就是把title用UTF-8编码后再输出,或者在meta之后指定title。
现象二:页面报js错误,但仔细查看源代码后,发现没有任何问题。
同样是编码不一致导致的。这时要仔细查看页面是否引用了非UTF-8编码的文件,一个典型的情况就是外部js文件中的中文(包含注释等)引起的,解决方法就是把中文去掉,或者全部改为英文即可。
FPDF实现中文换行
关于fpdf对中文的支持,这里就不多讲了,已经有达人写了一个pdf的子类PDF_chinese实现了对中文的支持。我们重点考虑的是中文换行,提到换行,就不得不提ln和multicell和cell方法,ln是显式换行,multicell和cell最大的差别就是cell有一个是否换行的参数,而multicell没有,详细见手册。其实,如果对于要生成的pdf文档,只有一个字段的内容需要换行时,并且该字段是最右边的那个字段(当然你可以调整),那么使用multicell是大致可以得到想要的结果的。对于多个字段需要换行时,该方法就无能为力了。在官方的script库中,我们可以找到这个一段代码table with multicell,该方法是专门为有多个需要换行的字段设计的。但该方法仅提供了对英文字符换行的支持,中文换行仍然存在问题,解决方法如下:
1.首先将属性和方法加到基类的适当处。
2.修改Nblines方法,该方法是用来计算内容在宽度固定的条件,需要几行来显示该数据才不至于撑破单元格。并且我们在使用中文换行时,出现的现象是一致的,就是每个中文内容字段在一个cell中显示2行就不再显示。仔细查看代码:
2 {
3 //Computes the number of lines a MultiCell of width w will take
4 $cw=&$this->CurrentFont['cw'];
5 if($w==0)
6 $w=$this->w-$this->rMargin-$this->x;
7 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
8 $s=str_replace("\r",'',$txt);
9 $nb=strlen($s);
10 if($nb>0 and $s[$nb-1]=="\n")
11 $nb--;
12 $sep=-1;
13 $i=0;
14 $j=0;
15 $l=0;
16 $nl=1;
17 while($i<$nb)
18 {
19 $c=$s[$i];
20 if($c=="\n")
21 {
22 $i++;
23 $sep=-1;
24 $j=$i;
25 $l=0;
26 $nl++;
27 continue;
28 }
29 if($c==' ')
30 $sep=$i;
31 $l+=$cw[$c];
32 if($l>$wmax)
33 {
34 if($sep==-1)
35 {
36 if($i==$j)
37 $i++;
38 }
39 else
40 $i=$sep+1;
41 $sep=-1;
42 $j=$i;
43 $l=0;
44 $nl++;
45 }
46 else
47 $i++;
48 }
49 return $nl;
50 }
发现31行存在问题,由于这里的cw就是我们在chinese.php中定义的$GB_widths数组。而$GB_widths中并没有对中文的判断,因此每次遇到中文时,都没有进行累加操作。因此需改变为如下的代码:
if(!$cw[$c]) $l+=500; else $l+$cw[$c];
也就是说,我们把一个中文字看作一个占据一个空间的字母/数字代替,也就解决了中文不能换行的问题
3.如果要生成pdf文档颜色交替显示,需要修改Rows方法,添加一个参数fill,并修改其中的
$this->Rect($x,$y,$w,$h);为 if($fill) $this->sect($x,$y,$w,$h,"FD"); else $this->Rect($x,$y,$w,$h);