用PHP创建PDF中文文档
我使用的是FPDF(www.fpdf.org),下载了fpdf类库后,还要使用下面的中文类库才能支持中文,但只能使用一种中文字体(华文仿宋)。为此我烦恼了很长时间,现在终于搞定了,将TrueType字体转化为pt1字体使用:
下面是在FPDF上找的一个中文类库:<?phprequire('fpdf.php');
$Big5_widths=array(' '=>250,'!'=>250,'''=>408,'#'=>668,'$'=>490,'%'=>875,'&'=>698,'''=>250,'('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,';'=>250,'<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625,'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823,'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677,'Z'=>635,'['=>344,''=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427,'d'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802,'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677,'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'}'=>480,'~'=>667);
$GB_widths=array(' '=>207,'!'=>270,'''=>342,'#'=>467,'$'=>462,'%'=>797,'&'=>710,'''=>239,'('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462,'2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,';'=>238,'<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563,'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772,'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620,'Z'=>607,'['=>374,''=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427,'d'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793,'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652,'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'}'=>370,'~'=>605);
class PDF_Chinese extends FPDF{function AddCIDFont($family,$style,$name,$cw,$CMap,$registry){$i=count($this->fonts)+1;$fontkey=strtolower($family).strtoupper($style);$this->fonts[$fontkey]=array('i'=>$i,'type'=>'Type0','name'=>$name,'up'=>-120,'ut'=>40,'cw'=>$cw,'CMap'=>$CMap,'registry'=>$registry);}
function AddBig5Font($family='Big5'){$cw=$GLOBALS['Big5_widths'];$name='MSungStd-Light-Acro';$CMap='ETenms-B5-H';$registry=array('ordering'=>'CNS1','supplement'=>0);$this->AddCIDFont($family,'',$name,$cw,$CMap,$registry);$this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry);$this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry);$this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry);}
function AddGBFont($family='GB'){$cw=$GLOBALS['GB_widths'];$name='STSongStd-Light-Acro';$CMap='GBKp-EUC-H';$registry=array('ordering'=>'GB1','supplement'=>2);$this->AddCIDFont($family,'',$name,$cw,$CMap,$registry);$this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry);$this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry);$this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry);}
function GetStringWidth($s){if($this->CurrentFont['type']=='Type0')return $this->GetMBStringWidth($s);elsereturn parent::GetStringWidth($s);}
function GetMBStringWidth($s){//Multi-byte version of GetStringWidth()$l=0;$cw=&$this->CurrentFont['cw'];$nb=strlen($s);$i=0;while($i<$nb){$c=$s[$i];if(ord($c)<128){$l+=$cw[$c];$i++;}else{$l+=1000;$i+=2;}}return $l*$this->FontSize/1000;}
function MultiCell($w,$h,$txt,$border=0,$align='L',$fill=0){if($this->CurrentFont['type']=='Type0')$this->MBMultiCell($w,$h,$txt,$border,$align,$fill);elseparent::MultiCell($w,$h,$txt,$border,$align,$fill);}
function MBMultiCell($w,$h,$txt,$border=0,$align='L',$fill=0){//Multi-byte version of MultiCell()$cw=&$this->CurrentFont['cw'];if($w==0)$w=$this->w-$this->rMargin-$this->x;$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;$s=str_replace('r','',$txt);$nb=strlen($s);if($nb>0 and $s[$nb-1]=='n'$nb--;$b=0;if($border){if($border==1){$border='LTRB';$b='LRT';$b2='LR';}else{$b2='';if(is_int(strpos($border,'L')))$b2.='L';if(is_int(strpos($border,'R')))$b2.='R';$b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;}}$sep=-1;$i=0;$j=0;$l=0;$ns=0;$nl=1;while($i<$nb){//Get next character$c=$s[$i];//Check if ASCII or MB$ascii=(ord($c)<128);if($c=='n'{//Explicit line breakif($this->ws>0){$this->ws=0;$this->_out('0 Tw');}$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);$i++;$sep=-1;$j=$i;$l=0;$ns=0;$nl++;if($border and $nl==2)$b=$b2;continue;}if(!$ascii){$sep=$i;$ls=$l;}elseif($c==' '){$sep=$i;$ls=$l;$ns++;}$l+=$ascii ? $cw[$c] : 1000;if($l>$wmax){//Automatic line breakif($sep==-1 or $i==$j){if($i==$j)$i+=$ascii ? 1 : 2;if($this->ws>0){$this->ws=0;$this->_out('0 Tw');}$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);}else{if($align=='J'){if($s[$sep]==' ')$ns--;if($s[$i-1]==' '){$ns--;$ls-=$cw[' '];}$this->ws=($ns>0) ? ($wmax-$ls)/1000*$this->FontSize/$ns : 0;$this->_out(sprintf('%.3f Tw',$this->ws*$this->k));}$this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);$i=($s[$sep]==' ') ? $sep+1 : $sep;}$sep=-1;$j=$i;$l=0;$ns=0;$nl++;if($border and $nl==2)$b=$b2;}else$i+=$ascii ? 1 : 2;}//Last chunkif($this->ws>0){$this->ws=0;$this->_out('0 Tw');}if($border and is_int(strpos($border,'B')))$b.='B';$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);$this->x=$this->lMargin;}
function Write($h,$txt,$link=''){if($this->CurrentFont['type']=='Type0')$this->MBWrite($h,$txt,$link);elseparent::Write($h,$txt,$link);}
function MBWrite($h,$txt,$link){//Multi-byte version of Write()$cw=&$this->CurrentFont['cw'];$w=$this->w-$this->rMargin-$this->x;$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;$s=str_replace('r','',$txt);$nb=strlen($s);$sep=-1;$i=0;$j=0;$l=0;$nl=1;while($i<$nb){//Get next character$c=$s[$i];//Check if ASCII or MB$ascii=(ord($c)<128);if($c=='n'{//Explicit line break$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);$i++;$sep=-1;$j=$i;$l=0;if($nl==1){$this->x=$this->lMargin;$w=$this->w-$this->rMargin-$this->x;$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;}$nl++;continue;}if(!$ascii or $c==' ')$sep=$i;$l+=$ascii ? $cw[$c] : 1000;if($l>$wmax){//Automatic line breakif($sep==-1 or $i==$j){if($this->x>$this->lMargin){//Move to next line$this->x=$this->lMargin;$this->y+=$h;$w=$this->w-$this->rMargin-$this->x;$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;$i++;$nl++;continue;}if($i==$j)$i+=$ascii ? 1 : 2;$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);}else{$this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link);$i=($s[$sep]==' ') ? $sep+1 : $sep;}$sep=-1;$j=$i;$l=0;if($nl==1){$this->x=$this->lMargin;$w=$this->w-$this->rMargin-$this->x;$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;}$nl++;}else$i+=$ascii ? 1 : 2;}//Last chunkif($i!=$j)$this->Cell($l/1000*$this->FontSize,$h,substr($s,$j,$i-$j),0,0,'',0,$link);}
function _putfonts(){$nf=$this->n;foreach($this->diffs as $diff){//Encodings$this->_newobj();$this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>');$this->_out('endobj');}$mqr=get_magic_quotes_runtime();set_magic_quotes_runtime(0);foreach($this->FontFiles as $file=>$info){//Font file embedding$this->_newobj();$this->FontFiles[$file]['n']=$this->n;if(defined('FPDF_FONTPATH'))$file=FPDF_FONTPATH.$file;$size=filesize($file);if(!$size)$this->Error('Font file not found');$this->_out('<</Length '.$size);if(substr($file,-2)=='.z')$this->_out('/Filter /FlateDecode');$this->_out('/Length1 '.$info['length1']);if(isset($info['length2']))$this->_out('/Length2 '.$info['length2'].' /Length3 0');$this->_out('>>');$f=fopen($file,'rb');$this->_putstream(fread($f,$size));fclose($f);$this->_out('endobj');}set_magic_quotes_runtime($mqr);foreach($this->fonts as $k=>$font){//Font objects$this->_newobj();$this->fonts[$k]['n']=$this->n;$this->_out('<</Type /Font');if($font['type']=='Type0')$this->_putType0($font);else{$name=$font['name'];$this->_out('/BaseFont /'.$name);if($font['type']=='core'){//Standard font$this->_out('/Subtype /Type1');if($name!='Symbol' and $name!='ZapfDingbats')$this->_out('/Encoding /WinAnsiEncoding');}else{//Additional font$this->_out('/Subtype /'.$font['type']);$this->_out('/FirstChar 32');$this->_out('/LastChar 255');$this->_out('/Widths '.($this->n+1).' 0 R');$this->_out('/FontDescriptor '.($this->n+2).' 0 R');if($font['enc']){if(isset($font['diff']))$this->_out('/Encoding '.($nf+$font['diff']).' 0 R');else$this->_out('/Encoding /WinAnsiEncoding');}}$this->_out('>>');$this->_out('endobj');if($font['type']!='core'){//Widths$this->_newobj();$cw=&$font['cw'];$s='[';for($i=32;$i<=255;$i++)$s.=$cw[chr($i)].' ';$this->_out($s.']');$this->_out('endobj');//Descriptor$this->_newobj();$s='<</Type /FontDescriptor /FontName /'.$name;foreach($font['desc'] as $k=>$v)$s.=' /'.$k.' '.$v;$file=$font['file'];if($file)$s.=' /FontFile'.($font['type']=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R';$this->_out($s.'>>');$this->_out('endobj');}}}}
function _putType0($font){//Type0$this->_out('/Subtype /Type0');$this->_out('/BaseFont /'.$font['name'].'-'.$font['CMap']);$this->_out('/Encoding /'.$font['CMap']);$this->_out('/DescendantFonts ['.($this->n+1).' 0 R]');$this->_out('>>');$this->_out('endobj');//CIDFont$this->_newobj();$this->_out('<</Type /Font');$this->_out('/Subtype /CIDFontType0');$this->_out('/BaseFont /'.$font['name']);$this->_out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('.$font['registry']['ordering'].') /Supplement '.$font['registry']['supplement'].'>>');$this->_out('/FontDescriptor '.($this->n+1).' 0 R');$W='/W [1 [';foreach($font['cw'] as $w)$W.=$w.' ';$this->_out($W.']]');$this->_out('>>');$this->_out('endobj');//Font descriptor$this->_newobj();$this->_out('<</Type /FontDescriptor');$this->_out('/FontName /'.$font['name']);$this->_out('/Flags 6');$this->_out('/FontBBox [0 0 1000 1000]');$this->_out('/ItalicAngle 0');$this->_out('/Ascent 1000');$this->_out('/Descent 0');$this->_out('/CapHeight 1000');$this->_out('/StemV 10');$this->_out('>>');$this->_out('endobj');}}?>
将以上代码存为chinese.php即可引用。但用它只能得到一种字体。为了支持所有中文字体,可用ttf2pt1程序将TrueType字体转化pt1字体,一个一个地转(具体方法在FPDF的教程中有详细说明)。为了支持其他中文字体,养分要修改上面的chinese.php,如下:
1: Replace the following line in the AddGBFont() method:
function AddGBFont($family='GB',$name='STSongStd-Light-Acro') { $cw=$GLOBALS['GB_widths']; // $name='STSongStd-Light-Acro'; $CMap='GBKp-EUC-H'; ........
2: This is a Sample.
<?php require('chinese.php');
$pdf=new PDF_Chinese(); $pdf->AddGBFont('simsun','宋体'); $pdf->AddGBFont('simhei','黑体'); $pdf->AddGBFont('simkai','楷体_GB2312'); $pdf->AddGBFont('sinfang','仿宋_GB2312''); $pdf->Open(); $pdf->AddPage(); $pdf->SetFont('simsun','',20); $pdf->Write(10,'简体中文汉字‘); $pdf->SetFont('simhei','',20); $pdf->Write(10,'简体中文汉字’); $pdf->SetFont('simkai','',20); $pdf->Write(10,'简体中文汉字‘); $pdf->SetFont('sinfang','',20); $pdf->Write(10,'简体中文汉字’); $pdf->Output(); ?>