用PHP创建PDF中文文档

发表于:2007-07-01来源:作者:点击数: 标签:
我使用的是FPDF(www.fpdf.org),下载了fpdf类库后,还要使用下面的中文类库才能支持中文,但只能使用一种中文字体(华文仿宋)。为此我烦恼了很长时间,现在终于搞定了,将TrueType字体转化为pt1字体使用: 下面是在FPDF上找的一个中文类库: ? php require(
我使用的是FPDF(www.fpdf.org),下载了fpdf类库后,还要使用下面的中文类库才能支持中文,但只能使用一种中文字体(华文仿宋)。为此我烦恼了很长时间,现在终于搞定了,将TrueType字体转化为pt1字体使用:

下面是在FPDF上找的一个中文类库:
<?php
require(@#@#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);
else
return 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);
else
parent::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 break
if($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 break
if($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 chunk
if($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);
else
parent::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 break
if($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 chunk
if($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();
?>

原文转自:http://www.ltesting.net