Fix #8052 - fixing pdf
[pear] / Fpdf / Unicode.php
1 <?php
2 require_once 'Chinese.php';
3
4 define ('FPDF_UNICODE_ENCODING', 'UCS-2BE');
5
6 class FPDF_Unicode extends FPDF_Chinese 
7 {
8   var $charset;     // input charset. User must add proper fonts by add font functions like AddUniCNShwFont
9   var $isUnicode;   // whether charset belongs to Unicode
10
11   function PDF_Unicode ($charset = 'UTF-8')
12   {
13     $this->FPDF('P', 'mm', 'A4');
14     $this->charset = strtoupper(str_replace ('-', '', $charset));
15     $this->isUnicode = in_array ($this->charset, array ('UTF8', 'UTF16', 'UCS2'));
16   }
17
18   function AddUniCNShwFont ($family='Uni', $name='PMingLiU')  // name for Kai font is DFKai-SB
19   {
20     //Add Unicode font with half-witdh Latin, character code must be utf16be
21     
22     for($i=32;$i<=126;$i++)
23       $cw[chr($i)]=500;
24     //$CMap='UniCNS-UCS2-H';  // for compatible with PDF 1.3 (Adobe-CNS1-0), 1.4 (Adobe-CNS1-3), 1.5 (Adobe-CNS1-3)
25     $CMap='UniCNS-UTF8-H';  // for compatible with 1.5 (Adobe-CNS1-4)
26     $registry=array('ordering'=>'CNS1','supplement'=>0);
27     $this->AddCIDFonts($family,$name,$cw,$CMap,$registry);
28   }
29
30   function AddUniCNSFont ($family='Uni', $cname='PMingLiU')  
31   {
32     //Add Unicode font with propotional Latin, character code must be utf16be
33     //$cw=$GLOBALS['Big5_widths'];
34     //  require 'font/helvetica.php';
35       
36     $cw=$GLOBALS['UTF8'];
37     $CMap='UniCNS-UTF8-H';
38     $registry=array('ordering'=>'CNS1','supplement'=>0);
39     $this->AddCIDFonts($family,$cname,$cw,$CMap,$registry);
40   }
41
42   function AddUniGBhwFont ($family='uGB', $name='AdobeSongStd-Light')  
43   {
44     //Add Unicode font with half-witdh Latin, character code must be utf16be
45     for($i=32;$i<=126;$i++)
46       $cw[chr($i)]=500;
47     $CMap='UniGB-UCS2-H';  
48     $registry=array('ordering'=>'GB1','supplement'=>4);
49     $this->AddCIDFonts($family,$name,$cw,$CMap,$registry);
50   }
51
52   function AddUniGBFont ($family='uGB', $name='AdobeSongStd-Light')  
53   {
54     //Add Unicode font with propotional Latin, character code must be utf16be
55     $cw=$GLOBALS['GB_widths'];
56     $CMap='UniGB-UCS2-H';
57     $registry=array('ordering'=>'GB1','supplement'=>4);
58     $this->AddCIDFonts($family,$name,$cw,$CMap,$registry);
59   }
60
61   // redefinition of FPDF functions
62
63   function GetStringWidth ($s)
64   {
65     //Get width of a string in the current font
66     if ($this->isUnicode) {
67       $txt = mb_convert_encoding ($s, FPDF_UNICODE_ENCODING, $this->charset);
68       $oEnc = mb_internal_encoding();
69       mb_internal_encoding (FPDF_UNICODE_ENCODING);
70       $w = $this->GetUniStringWidth ($txt);
71       mb_internal_encoding ($oEnc);
72       return $w;
73     } else
74       return parent::GetStringWidth($s);
75   }
76
77   function Text ($x, $y, $txt)
78   {
79     if ($this->isUnicode) {
80       $txt = mb_convert_encoding ($txt, FPDF_UNICODE_ENCODING, $this->charset);
81       $oEnc = mb_internal_encoding();
82       mb_internal_encoding (FPDF_UNICODE_ENCODING);
83       $this->UniText ($x, $y, $txt);
84       mb_internal_encoding ($oEnc);
85     } else 
86       parent::Text ($x, $y, $txt);
87   }
88
89   function Cell ($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
90   {
91     if ($this->isUnicode) {
92       $txt = mb_convert_encoding ($txt, FPDF_UNICODE_ENCODING, $this->charset);
93       $oEnc = mb_internal_encoding();
94       mb_internal_encoding (FPDF_UNICODE_ENCODING);
95       $this->UniCell ($w, $h, $txt, $border, $ln, $align, $fill, $link);
96       mb_internal_encoding ($oEnc);
97     } else 
98       parent::Cell ($w, $h, $txt, $border, $ln, $align, $fill, $link);
99   }
100
101   function MultiCell ($w,$h,$txt,$border=0,$align='J',$fill=0)
102   {
103     if ($this->isUnicode) {
104       $txt = mb_convert_encoding ($txt, FPDF_UNICODE_ENCODING, $this->charset);
105       $oEnc = mb_internal_encoding();
106       mb_internal_encoding (FPDF_UNICODE_ENCODING);
107       $this->UniMultiCell ($w, $h, $txt, $border, $align, $fill);
108       mb_internal_encoding ($oEnc);
109     } else {
110       parent::MultiCell ($w, $h, $txt, $border, $align, $fill);
111     }
112   }
113
114   function Write ($h,$txt,$link='')
115   {
116     if ($this->isUnicode) {
117       $txt = mb_convert_encoding ($txt, FPDF_UNICODE_ENCODING, $this->charset);
118       $oEnc = mb_internal_encoding();
119       mb_internal_encoding (FPDF_UNICODE_ENCODING);
120       $this->UniWrite ($h, $txt, $link);
121       mb_internal_encoding ($oEnc);
122     } else {
123       parent::Write ($h, $txt, $link);
124     }
125   }
126
127   // implementation in Unicode version 
128
129   function GetUniStringWidth ($s)
130   {
131     //Unicode version of GetStringWidth()
132     $l=0;
133     $cw=&$this->CurrentFont['cw'];
134     $nb=mb_strlen($s);
135     $i=0;
136     while($i<$nb) {
137       $c=mb_substr($s,$i,1);
138       $ord = hexdec(bin2hex($c));
139       if($ord<128) {
140         $l+=$cw[chr($ord)];
141       } else {
142         $l+=1000;
143       }
144       $i++;
145     }
146     return $l*$this->FontSize/1000;
147   }
148
149   function UniText ($x, $y, $txt)
150   {
151     // copied from parent::Text but just modify the line below
152     $s=sprintf('BT %.2f %.2f Td <%s> Tj ET',$x*$this->k,($this->h-$y)*$this->k, bin2hex($txt));
153
154     if($this->underline && $txt!='')
155       $s.=' '.$this->_dounderline($x,$y,$txt);
156     if($this->ColorFlag)
157       $s='q '.$this->TextColor.' '.$s.' Q';
158     $this->_out($s);
159   }
160
161   function UniCell ($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
162   {
163     // copied from parent::Text but just modify the line with an output "BT %.2f %.2f Td <%s> Tj ET" ...
164     $k=$this->k;
165     if($this->y+$h>$this->PageBreakTrigger && !$this->InFooter && $this->AcceptPageBreak())
166       {
167         //Automatic page break
168         $x=$this->x;
169         $ws=$this->ws;
170         if($ws>0)
171           {
172             $this->ws=0;
173             $this->_out('0 Tw');
174           }
175         $this->AddPage($this->CurOrientation);
176         $this->x=$x;
177         if($ws>0)
178           {
179             $this->ws=$ws;
180             $this->_out(sprintf('%.3f Tw',$ws*$k));
181           }
182       }
183     if($w==0)
184       $w=$this->w-$this->rMargin-$this->x;
185     $s='';
186     if($fill==1 || $border==1)
187       {
188         if($fill==1)
189           $op=($border==1) ? 'B' : 'f';
190         else
191           $op='S';
192         $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
193       }
194     if(is_string($border))
195       {
196         $x=$this->x;
197         $y=$this->y;
198         if(strpos($border,'L')!==false)
199           $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
200         if(strpos($border,'T')!==false)
201           $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
202         if(strpos($border,'R')!==false)
203           $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
204         if(strpos($border,'B')!==false)
205           $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
206       }
207     if($txt!=='')
208       {
209         if($align=='R')
210           $dx=$w-$this->cMargin-$this->GetUniStringWidth($txt);
211         elseif($align=='C')
212           $dx=($w-$this->GetUniStringWidth($txt))/2;
213         else
214           $dx=$this->cMargin;
215         if($this->ColorFlag)
216           $s.='q '.$this->TextColor.' ';
217         $s.=sprintf('BT %.2f %.2f Td <%s> Tj ET',($this->x+$dx)*$k,
218                     ($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,bin2hex($txt));
219         if($this->underline)
220           $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
221         if($this->ColorFlag)
222           $s.=' Q';
223         if($link)
224           $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetUniStringWidth($txt),$this->FontSize,$link);
225       }
226     if($s)
227       $this->_out($s);
228     $this->lasth=$h;
229     if($ln>0)
230       {
231         //Go to next line
232         $this->y+=$h;
233         if($ln==1)
234           $this->x=$this->lMargin;
235       }
236     else
237       $this->x+=$w;
238   }
239
240   function UniMultiCell($w,$h,$txt,$border=0,$align='L',$fill=0)
241   {
242     //Unicode version of MultiCell()
243
244     $enc = mb_internal_encoding();
245
246     $cw=&$this->CurrentFont['cw'];
247     if($w==0)
248       $w=$this->w-$this->rMargin-$this->x;
249     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
250     $s = $txt;
251     $nb=mb_strlen($s);
252     if ($nb>0 && mb_substr($s,-1)==mb_convert_encoding("\n", $enc, $this->charset))
253       $nb--;
254     $b=0;
255     if($border)
256       {
257         if($border==1)
258           {
259             $border='LTRB';
260             $b='LRT';
261             $b2='LR';
262           }
263         else
264           {
265             $b2='';
266             if(is_int(strpos($border,'L')))
267               $b2.='L';
268             if(is_int(strpos($border,'R')))
269               $b2.='R';
270             $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
271           }
272       }
273     $sep=-1;
274     $i=0;
275     $j=0;
276     $l=0;
277     $nl=1;
278     while($i<$nb)
279       {
280         //Get next character
281         $c=mb_substr($s,$i,1);
282         $ord = hexdec(bin2hex($c));
283         $ascii = ($ord < 128);
284         if($c==mb_convert_encoding("\n", $enc, $this->charset))
285           {
286             //Explicit line break
287             $this->UniCell($w,$h,mb_substr($s,$j,$i-$j),$b,2,$align,$fill);
288             $i++;
289             $sep=-1;
290             $j=$i;
291             $l=0;
292             $nl++;
293             if($border && $nl==2)
294               $b=$b2;
295             continue;
296           }
297         if(!$ascii || $c==mb_convert_encoding(' ', $enc, $this->charset))
298           {
299             $sep=$i;
300             $ls=$l;
301           }
302         $l+=$ascii ? $cw[chr($ord)] : 1000;
303         if($l>$wmax)
304           {
305             //Automatic line break
306             if($sep==-1 || $i==$j)
307               {
308                 if($i==$j)
309                   $i++; //=$ascii ? 1 : 2;
310                 $this->UniCell($w,$h,mb_substr($s,$j,$i-$j),$b,2,$align,$fill);
311               }
312             else
313               {
314                 $this->UniCell($w,$h,mb_substr($s,$j,$sep-$j),$b,2,$align,$fill);
315                 $i=(mb_substr($s,$sep,1)==mb_convert_encoding(' ', $enc, $this->charset)) ? $sep+1 : $sep;
316               }
317             $sep=-1;
318             $j=$i;
319             $l=0;
320             $nl++;
321             if($border && $nl==2)
322               $b=$b2;
323           }
324         else
325           $i++; //=$ascii ? 1 : 2;
326       }
327     //Last chunk
328     if($border && is_int(strpos($border,'B')))
329       $b.='B';
330     $this->UniCell($w,$h,mb_substr($s,$j,$i-$j),$b,2,$align,$fill);
331     $this->x=$this->lMargin;
332   }
333
334   function UniWrite($h,$txt,$link='')
335   {
336     //Unicode version of Write()
337     $enc = mb_internal_encoding();
338     $cw=&$this->CurrentFont['cw'];
339     $w=$this->w-$this->rMargin-$this->x;
340     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
341     $s = $txt;
342
343     $nb=mb_strlen($s);
344     $sep=-1;
345     $i=0;
346     $j=0;
347     $l=0;
348     $nl=1;
349     while($i<$nb)
350       {
351         //Get next character
352         $c=mb_substr($s,$i,1);
353         //Check if ASCII or MB
354         $ord = hexdec(bin2hex($c));
355         $ascii=($ord < 128);
356         if($c==mb_convert_encoding("\n", $enc, $this->charset))
357           {
358             //Explicit line break
359             $this->UniCell($w,$h,mb_substr($s,$j,$i-$j),0,2,'',0,$link);
360             $i++;
361             $sep=-1;
362             $j=$i;
363             $l=0;
364             if($nl==1)
365               {
366                 $this->x=$this->lMargin;
367                 $w=$this->w-$this->rMargin-$this->x;
368                 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
369               }
370             $nl++;
371             continue;
372           }
373         if(!$ascii || $c==mb_convert_encoding(' ', $enc, $this->charset))
374           $sep=$i;
375         $l+=$ascii ? $cw[chr($ord)] : 1000;
376         if($l>$wmax)
377           {
378             //Automatic line break
379             if($sep==-1 || $i==$j)
380               {
381                 if($this->x>$this->lMargin)
382                   {
383                     //Move to next line
384                     $this->x=$this->lMargin;
385                     $this->y+=$h;
386                     $w=$this->w-$this->rMargin-$this->x;
387                     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
388                     $i++;
389                     $nl++;
390                     continue;
391                   }
392                 if($i==$j)
393                   $i++; //=$ascii ? 1 : 2;
394                 $this->UniCell($w,$h,mb_substr($s,$j,$i-$j),0,2,'',0,$link);
395               }
396             else
397               {
398                 $this->UniCell($w,$h,mb_substr($s,$j,$sep-$j),0,2,'',0,$link);
399                 $i=(mb_substr($s,$sep,1)==mb_convert_encoding(' ', $enc, $this->charset)) ? $sep+1 : $sep;
400               }
401             $sep=-1;
402             $j=$i;
403             $l=0;
404             if($nl==1)
405               {
406                 $this->x=$this->lMargin;
407                 $w=$this->w-$this->rMargin-$this->x;
408                 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
409               }
410             $nl++;
411           }
412         else
413           $i++; //=$ascii ? 1 : 2;
414       }
415     //Last chunk
416     if($i!=$j)
417       $this->UniCell($l/1000*$this->FontSize,$h,mb_substr($s,$j,$i-$j),0,0,'',0,$link);
418   }
419
420 }