«
PHP开发实例:创建PDF中文文档的程序代码

时间:2008-5-31    作者:Deri    分类: 分享


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

   <p>  1: Replace the following line in the AddGBFont() method:</p><code>function AddGBFont($family='GB',$name='STSongStd-Light-Acro')<br />{<br />$cw=$GLOBALS['GB_widths'];<br />// $name='STSongStd-Light-Acro';<br />$CMap='GBKp-EUC-H';<br />........</code><p>  2: This is a Sample.</p><code><?php<br />require('chinese.php');<br />$pdf=new PDF_Chinese();<br />$pdf->AddGBFont('simsun','宋体');<br />$pdf->AddGBFont('simhei','黑体');<br />$pdf->AddGBFont('simkai','楷体_GB2312');<br />$pdf->AddGBFont('sinfang','仿宋_GB2312'');<br />$pdf->Open();<br />$pdf->AddPage();<br />$pdf->SetFont('simsun','',20);<br />$pdf->Write(10,'简体中文汉字‘);<br />$pdf->SetFont('simhei','',20);<br />$pdf->Write(10,'简体中文汉字’);<br />$pdf->SetFont('simkai','',20);<br />$pdf->Write(10,'简体中文汉字‘);<br />$pdf->SetFont('sinfang','',20);<br />$pdf->Write(10,'简体中文汉字’);<br />$pdf->Output();<br />?></code></p></p>