Documentation TYPO3 par Ameos |
00001 <?php 00002 /******************************************************************************* 00003 * Software: UFPDF, Unicode Free PDF generator * 00004 * Version: 0.1 * 00005 * based on FPDF 1.52 by Olivier PLATHEY * 00006 * Date: 2004-09-01 * 00007 * Author: Steven Wittens <steven@acko.net> * 00008 * License: GPL * 00009 * * 00010 * UFPDF is a modification of FPDF to support Unicode through UTF-8. * 00011 * * 00012 *******************************************************************************/ 00013 00014 if(!class_exists('UFPDF')) 00015 { 00016 define('UFPDF_VERSION','0.1'); 00017 00018 include_once './libraries/fpdf/fpdf.php'; 00019 00020 class UFPDF extends FPDF 00021 { 00022 00023 /******************************************************************************* 00024 * * 00025 * Public methods * 00026 * * 00027 *******************************************************************************/ 00028 function UFPDF($orientation='P',$unit='mm',$format='A4') 00029 { 00030 FPDF::FPDF($orientation, $unit, $format); 00031 } 00032 00033 function GetStringWidth($s) 00034 { 00035 //Get width of a string in the current font 00036 $s = (string)$s; 00037 $codepoints=$this->utf8_to_codepoints($s); 00038 $cw=&$this->CurrentFont['cw']; 00039 $w=0; 00040 foreach($codepoints as $cp) 00041 $w+=isset($cw[$cp])?$cw[$cp]:0; 00042 return $w*$this->FontSize/1000; 00043 } 00044 00045 function AddFont($family,$style='',$file='') 00046 { 00047 //Add a TrueType or Type1 font 00048 $family=strtolower($family); 00049 if($family=='arial') 00050 $family='helvetica'; 00051 $style=strtoupper($style); 00052 if($style=='IB') 00053 $style='BI'; 00054 if(isset($this->fonts[$family.$style])) 00055 $this->Error('Font already added: '.$family.' '.$style); 00056 if($file=='') 00057 $file=str_replace(' ','',$family).strtolower($style).'.php'; 00058 if(defined('FPDF_FONTPATH')) 00059 $file=FPDF_FONTPATH.$file; 00060 include($file); 00061 if(!isset($name)) 00062 $this->Error('Could not include font definition file'); 00063 $i=count($this->fonts)+1; 00064 $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'file'=>$file,'ctg'=>$ctg); 00065 if($file) 00066 { 00067 if($type=='TrueTypeUnicode') 00068 $this->FontFiles[$file]=array('length1'=>$originalsize); 00069 else 00070 $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); 00071 } 00072 } 00073 00074 function Text($x,$y,$txt) 00075 { 00076 //Output a string 00077 $s=sprintf('BT %.2f %.2f Td %s Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escapetext($txt)); 00078 if($this->underline and $txt!='') 00079 $s.=' '.$this->_dounderline($x,$y,$this->GetStringWidth($txt),$txt); 00080 if($this->ColorFlag) 00081 $s='q '.$this->TextColor.' '.$s.' Q'; 00082 $this->_out($s); 00083 } 00084 00085 function AcceptPageBreak() 00086 { 00087 //Accept automatic page break or not 00088 return $this->AutoPageBreak; 00089 } 00090 00091 function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='') 00092 { 00093 //Output a cell 00094 $k=$this->k; 00095 if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) 00096 { 00097 //Automatic page break 00098 $x=$this->x; 00099 $ws=$this->ws; 00100 if($ws>0) 00101 { 00102 $this->ws=0; 00103 $this->_out('0 Tw'); 00104 } 00105 $this->AddPage($this->CurOrientation); 00106 $this->x=$x; 00107 if($ws>0) 00108 { 00109 $this->ws=$ws; 00110 $this->_out(sprintf('%.3f Tw',$ws*$k)); 00111 } 00112 } 00113 if($w==0) 00114 $w=$this->w-$this->rMargin-$this->x; 00115 $s=''; 00116 if($fill==1 or $border==1) 00117 { 00118 if($fill==1) 00119 $op=($border==1) ? 'B' : 'f'; 00120 else 00121 $op='S'; 00122 $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); 00123 } 00124 if(is_string($border)) 00125 { 00126 $x=$this->x; 00127 $y=$this->y; 00128 if(is_int(strpos($border,'L'))) 00129 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); 00130 if(is_int(strpos($border,'T'))) 00131 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); 00132 if(is_int(strpos($border,'R'))) 00133 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); 00134 if(is_int(strpos($border,'B'))) 00135 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); 00136 } 00137 if($txt!='') 00138 { 00139 $width = $this->GetStringWidth($txt); 00140 if($align=='R') 00141 $dx=$w-$this->cMargin-$width; 00142 elseif($align=='C') 00143 $dx=($w-$width)/2; 00144 else 00145 $dx=$this->cMargin; 00146 if($this->ColorFlag) 00147 $s.='q '.$this->TextColor.' '; 00148 $txtstring=$this->_escapetext($txt); 00149 $s.=sprintf('BT %.2f %.2f Td %s Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txtstring); 00150 if($this->underline) 00151 $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$width,$txt); 00152 if($this->ColorFlag) 00153 $s.=' Q'; 00154 if($link) 00155 $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$width,$this->FontSize,$link); 00156 } 00157 if($s) 00158 $this->_out($s); 00159 $this->lasth=$h; 00160 if($ln>0) 00161 { 00162 //Go to next line 00163 $this->y+=$h; 00164 if($ln==1) 00165 $this->x=$this->lMargin; 00166 } 00167 else 00168 $this->x+=$w; 00169 } 00170 00171 /******************************************************************************* 00172 * * 00173 * Protected methods * 00174 * * 00175 *******************************************************************************/ 00176 00177 function _puttruetypeunicode($font) { 00178 //Type0 Font 00179 $this->_newobj(); 00180 $this->_out('<</Type /Font'); 00181 $this->_out('/Subtype /Type0'); 00182 $this->_out('/BaseFont /'. $font['name'] .'-UCS'); 00183 $this->_out('/Encoding /Identity-H'); 00184 $this->_out('/DescendantFonts ['. ($this->n + 1) .' 0 R]'); 00185 $this->_out('>>'); 00186 $this->_out('endobj'); 00187 00188 //CIDFont 00189 $this->_newobj(); 00190 $this->_out('<</Type /Font'); 00191 $this->_out('/Subtype /CIDFontType2'); 00192 $this->_out('/BaseFont /'. $font['name']); 00193 $this->_out('/CIDSystemInfo <</Registry (Adobe) /Ordering (UCS) /Supplement 0>>'); 00194 $this->_out('/FontDescriptor '. ($this->n + 1) .' 0 R'); 00195 $c = 0; 00196 $widths = ''; 00197 foreach ($font['cw'] as $i => $w) { 00198 $widths .= $i .' ['. $w.'] '; 00199 } 00200 $this->_out('/W ['. $widths .']'); 00201 $this->_out('/CIDToGIDMap '. ($this->n + 2) .' 0 R'); 00202 $this->_out('>>'); 00203 $this->_out('endobj'); 00204 00205 //Font descriptor 00206 $this->_newobj(); 00207 $this->_out('<</Type /FontDescriptor'); 00208 $this->_out('/FontName /'.$font['name']); 00209 $s = ''; 00210 foreach ($font['desc'] as $k => $v) { 00211 $s .= ' /'. $k .' '. $v; 00212 } 00213 if ($font['file']) { 00214 $s .= ' /FontFile2 '. $this->FontFiles[$font['file']]['n'] .' 0 R'; 00215 } 00216 $this->_out($s); 00217 $this->_out('>>'); 00218 $this->_out('endobj'); 00219 00220 //Embed CIDToGIDMap 00221 $this->_newobj(); 00222 if(defined('FPDF_FONTPATH')) 00223 $file=FPDF_FONTPATH.$font['ctg']; 00224 else 00225 $file=$font['ctg']; 00226 $size=filesize($file); 00227 if(!$size) 00228 $this->Error('Font file not found'); 00229 $this->_out('<</Length '.$size); 00230 if(substr($file,-2) == '.z') 00231 $this->_out('/Filter /FlateDecode'); 00232 $this->_out('>>'); 00233 $f = fopen($file,'rb'); 00234 $this->_putstream(fread($f,$size)); 00235 fclose($f); 00236 $this->_out('endobj'); 00237 } 00238 00239 function _dounderline($x,$y,$width,$txt) 00240 { 00241 //Underline text 00242 $up=$this->CurrentFont['up']; 00243 $ut=$this->CurrentFont['ut']; 00244 $w=$width+$this->ws*substr_count($txt,' '); 00245 return sprintf('%.2f %.2f %.2f %.2f re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); 00246 } 00247 00248 function _textstring($s) 00249 { 00250 //Convert to UTF-16BE 00251 $s = $this->utf8_to_utf16be($s); 00252 //Escape necessary characters 00253 return '('. strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) .')'; 00254 } 00255 00256 function _strreplace($what, $to, $where) { 00257 $to = '' . $to; 00258 return str_replace($this->utf8_to_utf16be($what, false), $this->utf8_to_utf16be($to, false), $where); 00259 } 00260 00261 function _escapetext($s) 00262 { 00263 //Convert to UTF-16BE 00264 $s = $this->utf8_to_utf16be($s, false); 00265 //Escape necessary characters 00266 return '('. strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) .')'; 00267 } 00268 00269 function _putinfo() 00270 { 00271 $this->_out('/Producer '.$this->_textstring('UFPDF '. UFPDF_VERSION)); 00272 if(!empty($this->title)) 00273 $this->_out('/Title '.$this->_textstring($this->title)); 00274 if(!empty($this->subject)) 00275 $this->_out('/Subject '.$this->_textstring($this->subject)); 00276 if(!empty($this->author)) 00277 $this->_out('/Author '.$this->_textstring($this->author)); 00278 if(!empty($this->keywords)) 00279 $this->_out('/Keywords '.$this->_textstring($this->keywords)); 00280 if(!empty($this->creator)) 00281 $this->_out('/Creator '.$this->_textstring($this->creator)); 00282 $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis'))); 00283 } 00284 00285 // UTF-8 to UTF-16BE conversion. 00286 // Correctly handles all illegal UTF-8 sequences. 00287 function utf8_to_utf16be(&$txt, $bom = true) { 00288 $l = strlen($txt); 00289 $out = $bom ? "\xFE\xFF" : ''; 00290 for ($i = 0; $i < $l; ++$i) { 00291 $c = ord($txt{$i}); 00292 // ASCII 00293 if ($c < 0x80) { 00294 $out .= "\x00". $txt{$i}; 00295 } 00296 // Lost continuation byte 00297 else if ($c < 0xC0) { 00298 $out .= "\xFF\xFD"; 00299 continue; 00300 } 00301 // Multibyte sequence leading byte 00302 else { 00303 if ($c < 0xE0) { 00304 $s = 2; 00305 } 00306 else if ($c < 0xF0) { 00307 $s = 3; 00308 } 00309 else if ($c < 0xF8) { 00310 $s = 4; 00311 } 00312 // 5/6 byte sequences not possible for Unicode. 00313 else { 00314 $out .= "\xFF\xFD"; 00315 while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; } 00316 continue; 00317 } 00318 00319 $q = array($c); 00320 // Fetch rest of sequence 00321 $l = strlen($txt); 00322 while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; $q[] = ord($txt{$i}); } 00323 00324 // Check length 00325 if (count($q) != $s) { 00326 $out .= "\xFF\xFD"; 00327 continue; 00328 } 00329 00330 switch ($s) { 00331 case 2: 00332 $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); 00333 // Overlong sequence 00334 if ($cp < 0x80) { 00335 $out .= "\xFF\xFD"; 00336 } 00337 else { 00338 $out .= chr($cp >> 8); 00339 $out .= chr($cp & 0xFF); 00340 } 00341 continue; 00342 00343 case 3: 00344 $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); 00345 // Overlong sequence 00346 if ($cp < 0x800) { 00347 $out .= "\xFF\xFD"; 00348 } 00349 // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) 00350 else if ($c > 0xD800 && $c < 0xDFFF) { 00351 $out .= "\xFF\xFD"; 00352 } 00353 else { 00354 $out .= chr($cp >> 8); 00355 $out .= chr($cp & 0xFF); 00356 } 00357 continue; 00358 00359 case 4: 00360 $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); 00361 // Overlong sequence 00362 if ($cp < 0x10000) { 00363 $out .= "\xFF\xFD"; 00364 } 00365 // Outside of the Unicode range 00366 else if ($cp >= 0x10FFFF) { 00367 $out .= "\xFF\xFD"; 00368 } 00369 else { 00370 // Use surrogates 00371 $cp -= 0x10000; 00372 $s1 = 0xD800 | ($cp >> 10); 00373 $s2 = 0xDC00 | ($cp & 0x3FF); 00374 00375 $out .= chr($s1 >> 8); 00376 $out .= chr($s1 & 0xFF); 00377 $out .= chr($s2 >> 8); 00378 $out .= chr($s2 & 0xFF); 00379 } 00380 continue; 00381 } 00382 } 00383 } 00384 return $out; 00385 } 00386 00387 // UTF-8 to codepoint array conversion. 00388 // Correctly handles all illegal UTF-8 sequences. 00389 function utf8_to_codepoints(&$txt) { 00390 $l = strlen($txt); 00391 $out = array(); 00392 for ($i = 0; $i < $l; ++$i) { 00393 $c = ord($txt{$i}); 00394 // ASCII 00395 if ($c < 0x80) { 00396 $out[] = ord($txt{$i}); 00397 } 00398 // Lost continuation byte 00399 else if ($c < 0xC0) { 00400 $out[] = 0xFFFD; 00401 continue; 00402 } 00403 // Multibyte sequence leading byte 00404 else { 00405 if ($c < 0xE0) { 00406 $s = 2; 00407 } 00408 else if ($c < 0xF0) { 00409 $s = 3; 00410 } 00411 else if ($c < 0xF8) { 00412 $s = 4; 00413 } 00414 // 5/6 byte sequences not possible for Unicode. 00415 else { 00416 $out[] = 0xFFFD; 00417 while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; } 00418 continue; 00419 } 00420 00421 $q = array($c); 00422 // Fetch rest of sequence 00423 $l = strlen($txt); 00424 while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; $q[] = ord($txt{$i}); } 00425 00426 // Check length 00427 if (count($q) != $s) { 00428 $out[] = 0xFFFD; 00429 continue; 00430 } 00431 00432 switch ($s) { 00433 case 2: 00434 $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); 00435 // Overlong sequence 00436 if ($cp < 0x80) { 00437 $out[] = 0xFFFD; 00438 } 00439 else { 00440 $out[] = $cp; 00441 } 00442 continue; 00443 00444 case 3: 00445 $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); 00446 // Overlong sequence 00447 if ($cp < 0x800) { 00448 $out[] = 0xFFFD; 00449 } 00450 // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) 00451 else if ($c > 0xD800 && $c < 0xDFFF) { 00452 $out[] = 0xFFFD; 00453 } 00454 else { 00455 $out[] = $cp; 00456 } 00457 continue; 00458 00459 case 4: 00460 $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); 00461 // Overlong sequence 00462 if ($cp < 0x10000) { 00463 $out[] = 0xFFFD; 00464 } 00465 // Outside of the Unicode range 00466 else if ($cp >= 0x10FFFF) { 00467 $out[] = 0xFFFD; 00468 } 00469 else { 00470 $out[] = $cp; 00471 } 00472 continue; 00473 } 00474 } 00475 } 00476 return $out; 00477 } 00478 00479 //End of class 00480 } 00481 00482 } 00483 ?>