tFPDF

The WooCommerce PDF & Print tFPDF class.

Defined (1)

The class is defined in the following location(s).

/tpdf/tfpdf.php  
  1. class tFPDF 
  2.  
  3. var $unifontSubset; 
  4. var $page; // current page number 
  5. var $n; // current object number 
  6. var $offsets; // array of object offsets 
  7. var $buffer; // buffer holding in-memory PDF 
  8. var $pages; // array containing pages 
  9. var $state; // current document state 
  10. var $compress; // compression flag 
  11. var $k; // scale factor (number of points in user unit) 
  12. var $DefOrientation; // default orientation 
  13. var $CurOrientation; // current orientation 
  14. var $StdPageSizes; // standard page sizes 
  15. var $DefPageSize; // default page size 
  16. var $CurPageSize; // current page size 
  17. var $PageSizes; // used for pages with non default sizes or orientations 
  18. var $wPt, $hPt; // dimensions of current page in points 
  19. var $w, $h; // dimensions of current page in user unit 
  20. var $lMargin; // left margin 
  21. var $tMargin; // top margin 
  22. var $rMargin; // right margin 
  23. var $bMargin; // page break margin 
  24. var $cMargin; // cell margin 
  25. var $x, $y; // current position in user unit 
  26. var $lasth; // height of last printed cell 
  27. var $LineWidth; // line width in user unit 
  28. var $fontpath; // path containing fonts 
  29. var $CoreFonts; // array of core font names 
  30. var $fonts; // array of used fonts 
  31. var $FontFiles; // array of font files 
  32. var $diffs; // array of encoding differences 
  33. var $FontFamily; // current font family 
  34. var $FontStyle; // current font style 
  35. var $underline; // underlining flag 
  36. var $CurrentFont; // current font info 
  37. var $FontSizePt; // current font size in points 
  38. var $FontSize; // current font size in user unit 
  39. var $DrawColor; // commands for drawing color 
  40. var $FillColor; // commands for filling color 
  41. var $TextColor; // commands for text color 
  42. var $ColorFlag; // indicates whether fill and text colors are different 
  43. var $ws; // word spacing 
  44. var $images; // array of used images 
  45. var $PageLinks; // array of links in pages 
  46. var $links; // array of internal links 
  47. var $AutoPageBreak; // automatic page breaking 
  48. var $PageBreakTrigger; // threshold used to trigger page breaks 
  49. var $InHeader; // flag set when processing header 
  50. var $InFooter; // flag set when processing footer 
  51. var $ZoomMode; // zoom display mode 
  52. var $LayoutMode; // layout display mode 
  53. var $title; // title 
  54. var $subject; // subject 
  55. var $author; // author 
  56. var $keywords; // keywords 
  57. var $creator; // creator 
  58. var $AliasNbPages; // alias for total number of pages 
  59. var $PDFVersion; // PDF version number 
  60.  
  61. /******************************************************************************* 
  62. * * 
  63. * Public methods * 
  64. * * 
  65. *******************************************************************************/ 
  66. function tFPDF($orientation='P', $unit='mm', $size='A4') 
  67. // Some checks 
  68. $this->_dochecks(); 
  69. // Initialization of properties 
  70. $this->page = 0; 
  71. $this->n = 2; 
  72. $this->buffer = ''; 
  73. $this->pages = array(); 
  74. $this->PageSizes = array(); 
  75. $this->state = 0; 
  76. $this->fonts = array(); 
  77. $this->FontFiles = array(); 
  78. $this->diffs = array(); 
  79. $this->images = array(); 
  80. $this->links = array(); 
  81. $this->InHeader = false; 
  82. $this->InFooter = false; 
  83. $this->lasth = 0; 
  84. $this->FontFamily = ''; 
  85. $this->FontStyle = ''; 
  86. $this->FontSizePt = 12; 
  87. $this->underline = false; 
  88. $this->DrawColor = '0 G'; 
  89. $this->FillColor = '0 g'; 
  90. $this->TextColor = '0 g'; 
  91. $this->ColorFlag = false; 
  92. $this->ws = 0; 
  93. // Font path 
  94. if(defined('FPDF_FONTPATH')) 
  95. $this->fontpath = FPDF_FONTPATH; 
  96. if(substr($this->fontpath, -1)!='/' && substr($this->fontpath, -1)!='\\') 
  97. $this->fontpath .= '/'; 
  98. elseif(is_dir(dirname(__FILE__).'/font')) 
  99. $this->fontpath = dirname(__FILE__).'/font/'; 
  100. else 
  101. $this->fontpath = ''; 
  102. // Core fonts 
  103. $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats'); 
  104. // Scale factor 
  105. if($unit=='pt') 
  106. $this->k = 1; 
  107. elseif($unit=='mm') 
  108. $this->k = 72/25.4; 
  109. elseif($unit=='cm') 
  110. $this->k = 72/2.54; 
  111. elseif($unit=='in') 
  112. $this->k = 72; 
  113. else 
  114. $this->Error('Incorrect unit: '.$unit); 
  115. // Page sizes 
  116. $this->StdPageSizes = array('a3'=>array(841.89, 1190.55), 'a4'=>array(595.28, 841.89), 'a5'=>array(420.94, 595.28),  
  117. 'letter'=>array(612, 792), 'legal'=>array(612, 1008)); 
  118. $size = $this->_getpagesize($size); 
  119. $this->DefPageSize = $size; 
  120. $this->CurPageSize = $size; 
  121. // Page orientation 
  122. $orientation = strtolower($orientation); 
  123. if($orientation=='p' || $orientation=='portrait') 
  124. $this->DefOrientation = 'P'; 
  125. $this->w = $size[0]; 
  126. $this->h = $size[1]; 
  127. elseif($orientation=='l' || $orientation=='landscape') 
  128. $this->DefOrientation = 'L'; 
  129. $this->w = $size[1]; 
  130. $this->h = $size[0]; 
  131. else 
  132. $this->Error('Incorrect orientation: '.$orientation); 
  133. $this->CurOrientation = $this->DefOrientation; 
  134. $this->wPt = $this->w*$this->k; 
  135. $this->hPt = $this->h*$this->k; 
  136. // Page margins (1 cm) 
  137. $margin = 28.35/$this->k; 
  138. $this->SetMargins($margin, $margin); 
  139. // Interior cell margin (1 mm) 
  140. $this->cMargin = $margin/10; 
  141. // Line width (0.2 mm) 
  142. $this->LineWidth = .567/$this->k; 
  143. // Automatic page break 
  144. $this->SetAutoPageBreak(true, 2*$margin); 
  145. // Default display mode 
  146. $this->SetDisplayMode('default'); 
  147. // Enable compression 
  148. $this->SetCompression(true); 
  149. // Set default PDF version number 
  150. $this->PDFVersion = '1.3'; 
  151.  
  152. function SetMargins($left, $top, $right=null) 
  153. // Set left, top and right margins 
  154. $this->lMargin = $left; 
  155. $this->tMargin = $top; 
  156. if($right===null) 
  157. $right = $left; 
  158. $this->rMargin = $right; 
  159.  
  160. function SetLeftMargin($margin) 
  161. // Set left margin 
  162. $this->lMargin = $margin; 
  163. if($this->page>0 && $this->x<$margin) 
  164. $this->x = $margin; 
  165.  
  166. function SetTopMargin($margin) 
  167. // Set top margin 
  168. $this->tMargin = $margin; 
  169.  
  170. function SetRightMargin($margin) 
  171. // Set right margin 
  172. $this->rMargin = $margin; 
  173.  
  174. function SetAutoPageBreak($auto, $margin=0) 
  175. // Set auto page break mode and triggering margin 
  176. $this->AutoPageBreak = $auto; 
  177. $this->bMargin = $margin; 
  178. $this->PageBreakTrigger = $this->h-$margin; 
  179.  
  180. function SetDisplayMode($zoom, $layout='default') 
  181. // Set display mode in viewer 
  182. if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom)) 
  183. $this->ZoomMode = $zoom; 
  184. else 
  185. $this->Error('Incorrect zoom display mode: '.$zoom); 
  186. if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default') 
  187. $this->LayoutMode = $layout; 
  188. else 
  189. $this->Error('Incorrect layout display mode: '.$layout); 
  190.  
  191. function SetCompression($compress) 
  192. // Set page compression 
  193. if(function_exists('gzcompress')) 
  194. $this->compress = $compress; 
  195. else 
  196. $this->compress = false; 
  197.  
  198. function SetTitle($title, $isUTF8=false) 
  199. // Title of document 
  200. if($isUTF8) 
  201. $title = $this->_UTF8toUTF16($title); 
  202. $this->title = $title; 
  203.  
  204. function SetSubject($subject, $isUTF8=false) 
  205. // Subject of document 
  206. if($isUTF8) 
  207. $subject = $this->_UTF8toUTF16($subject); 
  208. $this->subject = $subject; 
  209.  
  210. function SetAuthor($author, $isUTF8=false) 
  211. // Author of document 
  212. if($isUTF8) 
  213. $author = $this->_UTF8toUTF16($author); 
  214. $this->author = $author; 
  215.  
  216. function SetKeywords($keywords, $isUTF8=false) 
  217. // Keywords of document 
  218. if($isUTF8) 
  219. $keywords = $this->_UTF8toUTF16($keywords); 
  220. $this->keywords = $keywords; 
  221.  
  222. function SetCreator($creator, $isUTF8=false) 
  223. // Creator of document 
  224. if($isUTF8) 
  225. $creator = $this->_UTF8toUTF16($creator); 
  226. $this->creator = $creator; 
  227.  
  228. function AliasNbPages($alias='{nb}') 
  229. // Define an alias for total number of pages 
  230. $this->AliasNbPages = $alias; 
  231.  
  232. function Error($msg) 
  233. // Fatal error 
  234. die('<b>FPDF error:</b> '.$msg); 
  235.  
  236. function Open() 
  237. // Begin document 
  238. $this->state = 1; 
  239.  
  240. function Close() 
  241. // Terminate document 
  242. if($this->state==3) 
  243. return; 
  244. if($this->page==0) 
  245. $this->AddPage(); 
  246. // Page footer 
  247. $this->InFooter = true; 
  248. $this->Footer(); 
  249. $this->InFooter = false; 
  250. // Close page 
  251. $this->_endpage(); 
  252. // Close document 
  253. $this->_enddoc(); 
  254.  
  255. function AddPage($orientation='', $size='') 
  256. // Start a new page 
  257. if($this->state==0) 
  258. $this->Open(); 
  259. $family = $this->FontFamily; 
  260. $style = $this->FontStyle.($this->underline ? 'U' : ''); 
  261. $fontsize = $this->FontSizePt; 
  262. $lw = $this->LineWidth; 
  263. $dc = $this->DrawColor; 
  264. $fc = $this->FillColor; 
  265. $tc = $this->TextColor; 
  266. $cf = $this->ColorFlag; 
  267. if($this->page>0) 
  268. // Page footer 
  269. $this->InFooter = true; 
  270. $this->Footer(); 
  271. $this->InFooter = false; 
  272. // Close page 
  273. $this->_endpage(); 
  274. // Start new page 
  275. $this->_beginpage($orientation, $size); 
  276. // Set line cap style to square 
  277. $this->_out('2 J'); 
  278. // Set line width 
  279. $this->LineWidth = $lw; 
  280. $this->_out(sprintf('%.2F w', $lw*$this->k)); 
  281. // Set font 
  282. if($family) 
  283. $this->SetFont($family, $style, $fontsize); 
  284. // Set colors 
  285. $this->DrawColor = $dc; 
  286. if($dc!='0 G') 
  287. $this->_out($dc); 
  288. $this->FillColor = $fc; 
  289. if($fc!='0 g') 
  290. $this->_out($fc); 
  291. $this->TextColor = $tc; 
  292. $this->ColorFlag = $cf; 
  293. // Page header 
  294. $this->InHeader = true; 
  295. $this->Header(); 
  296. $this->InHeader = false; 
  297. // Restore line width 
  298. if($this->LineWidth!=$lw) 
  299. $this->LineWidth = $lw; 
  300. $this->_out(sprintf('%.2F w', $lw*$this->k)); 
  301. // Restore font 
  302. if($family) 
  303. $this->SetFont($family, $style, $fontsize); 
  304. // Restore colors 
  305. if($this->DrawColor!=$dc) 
  306. $this->DrawColor = $dc; 
  307. $this->_out($dc); 
  308. if($this->FillColor!=$fc) 
  309. $this->FillColor = $fc; 
  310. $this->_out($fc); 
  311. $this->TextColor = $tc; 
  312. $this->ColorFlag = $cf; 
  313.  
  314. function Header() 
  315. // To be implemented in your own inherited class 
  316.  
  317. function Footer() 
  318. // To be implemented in your own inherited class 
  319.  
  320. function PageNo() 
  321. // Get current page number 
  322. return $this->page; 
  323.  
  324. function SetDrawColor($r, $g=null, $b=null) 
  325. // Set color for all stroking operations 
  326. if(($r==0 && $g==0 && $b==0) || $g===null) 
  327. $this->DrawColor = sprintf('%.3F G', $r/255); 
  328. else 
  329. $this->DrawColor = sprintf('%.3F %.3F %.3F RG', $r/255, $g/255, $b/255); 
  330. if($this->page>0) 
  331. $this->_out($this->DrawColor); 
  332.  
  333. function SetFillColor($r, $g=null, $b=null) 
  334. // Set color for all filling operations 
  335. if(($r==0 && $g==0 && $b==0) || $g===null) 
  336. $this->FillColor = sprintf('%.3F g', $r/255); 
  337. else 
  338. $this->FillColor = sprintf('%.3F %.3F %.3F rg', $r/255, $g/255, $b/255); 
  339. $this->ColorFlag = ($this->FillColor!=$this->TextColor); 
  340. if($this->page>0) 
  341. $this->_out($this->FillColor); 
  342.  
  343. function SetTextColor($r, $g=null, $b=null) 
  344. // Set color for text 
  345. if(($r==0 && $g==0 && $b==0) || $g===null) 
  346. $this->TextColor = sprintf('%.3F g', $r/255); 
  347. else 
  348. $this->TextColor = sprintf('%.3F %.3F %.3F rg', $r/255, $g/255, $b/255); 
  349. $this->ColorFlag = ($this->FillColor!=$this->TextColor); 
  350.  
  351. function GetStringWidth($s) 
  352. // Get width of a string in the current font 
  353. $s = (string)$s; 
  354. $cw = &$this->CurrentFont['cw']; 
  355. $w=0; 
  356. if ($this->unifontSubset) { 
  357. $unicode = $this->UTF8StringToArray($s); 
  358. foreach($unicode as $char) { 
  359. if (isset($cw[$char])) { $w += (ord($cw[2*$char])<<8) + ord($cw[2*$char+1]); } 
  360. else if($char>0 && $char<128 && isset($cw[chr($char)])) { $w += $cw[chr($char)]; } 
  361. else if(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; } 
  362. else if(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; } 
  363. else { $w += 500; } 
  364. else { 
  365. $l = strlen($s); 
  366. for($i=0;$i<$l;$i++) 
  367. $w += $cw[$s[$i]]; 
  368. return $w*$this->FontSize/1000; 
  369.  
  370. function SetLineWidth($width) 
  371. // Set line width 
  372. $this->LineWidth = $width; 
  373. if($this->page>0) 
  374. $this->_out(sprintf('%.2F w', $width*$this->k)); 
  375.  
  376. function Line($x1, $y1, $x2, $y2) 
  377. // Draw a line 
  378. $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S', $x1*$this->k, ($this->h-$y1)*$this->k, $x2*$this->k, ($this->h-$y2)*$this->k)); 
  379.  
  380. function Rect($x, $y, $w, $h, $style='') 
  381. // Draw a rectangle 
  382. if($style=='F') 
  383. $op = 'f'; 
  384. elseif($style=='FD' || $style=='DF') 
  385. $op = 'B'; 
  386. else 
  387. $op = 'S'; 
  388. $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s', $x*$this->k, ($this->h-$y)*$this->k, $w*$this->k, -$h*$this->k, $op)); 
  389.  
  390. function AddFont($family, $style='', $file='', $uni=false) 
  391. // Add a TrueType, OpenType or Type1 font 
  392. $family = strtolower($family); 
  393. $style = strtoupper($style); 
  394. if($style=='IB') 
  395. $style='BI'; 
  396. if($file=='') { 
  397. if ($uni) { 
  398. $file = str_replace(' ', '', $family).strtolower($style).'.ttf'; 
  399. else { 
  400. $file = str_replace(' ', '', $family).strtolower($style).'.php'; 
  401. $fontkey = $family.$style; 
  402. if(isset($this->fonts[$fontkey])) 
  403. return; 
  404.  
  405. if ($uni) { 
  406. if (defined("_SYSTEM_TTFONTS") && file_exists(_SYSTEM_TTFONTS.$file )) { $ttffilename = _SYSTEM_TTFONTS.$file ; } 
  407. else { $ttffilename = $this->_getfontpath().'unifont/'.$file ; } 
  408. $unifilename = $this->_getfontpath().'unifont/'.strtolower(substr($file , 0, (strpos($file , '.')))); 
  409. $name = ''; 
  410. $originalsize = 0; 
  411. $ttfstat = stat($ttffilename); 
  412. if (file_exists($unifilename.'.mtx.php')) { 
  413. include($unifilename.'.mtx.php'); 
  414. if (!isset($type) || !isset($name) || $originalsize != $ttfstat['size']) { 
  415. $ttffile = $ttffilename; 
  416. require_once($this->_getfontpath().'unifont/ttfonts.php'); 
  417. $ttf = new TTFontFile(); 
  418. $ttf->getMetrics($ttffile); 
  419. $cw = $ttf->charWidths; 
  420. $name = preg_replace('/[ ()]/', '', $ttf->fullName); 
  421.  
  422. $desc= array('Ascent'=>round($ttf->ascent),  
  423. 'Descent'=>round($ttf->descent),  
  424. 'CapHeight'=>round($ttf->capHeight),  
  425. 'Flags'=>$ttf->flags,  
  426. 'FontBBox'=>'['.round($ttf->bbox[0])." ".round($ttf->bbox[1])." ".round($ttf->bbox[2])." ".round($ttf->bbox[3]).']',  
  427. 'ItalicAngle'=>$ttf->italicAngle,  
  428. 'StemV'=>round($ttf->stemV),  
  429. 'MissingWidth'=>round($ttf->defaultWidth)); 
  430. $up = round($ttf->underlinePosition); 
  431. $ut = round($ttf->underlineThickness); 
  432. $originalsize = $ttfstat['size']+0; 
  433. $type = 'TTF'; 
  434. // Generate metrics .php file 
  435. $s='<?php'."\n"; 
  436. $s.='$name=\''.$name."';\n"; 
  437. $s.='$type=\''.$type."';\n"; 
  438. $s.='$desc='.var_export($desc, true).";\n"; 
  439. $s.='$up='.$up.";\n"; 
  440. $s.='$ut='.$ut.";\n"; 
  441. $s.='$ttffile=\''.$ttffile."';\n"; 
  442. $s.='$originalsize='.$originalsize.";\n"; 
  443. $s.='$fontkey=\''.$fontkey."';\n"; 
  444. $s.="?>"; 
  445. if (is_writable(dirname($this->_getfontpath().'unifont/'.'x'))) { 
  446. $fh = fopen($unifilename.'.mtx.php', "w"); 
  447. fwrite($fh, $s, strlen($s)); 
  448. fclose($fh); 
  449. $fh = fopen($unifilename.'.cw.dat', "wb"); 
  450. fwrite($fh, $cw, strlen($cw)); 
  451. fclose($fh); 
  452. @unlink($unifilename.'.cw127.php'); 
  453. unset($ttf); 
  454. else { 
  455. $cw = @file_get_contents($unifilename.'.cw.dat');  
  456. $i = count($this->fonts)+1; 
  457. if(!empty($this->AliasNbPages)) 
  458. $sbarr = range(0, 57); 
  459. else 
  460. $sbarr = range(0, 32); 
  461. $this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'ttffile'=>$ttffile, 'fontkey'=>$fontkey, 'subset'=>$sbarr, 'unifilename'=>$unifilename); 
  462.  
  463. $this->FontFiles[$fontkey]=array('length1'=>$originalsize, 'type'=>"TTF", 'ttffile'=>$ttffile); 
  464. $this->FontFiles[$file]=array('type'=>"TTF"); 
  465. unset($cw); 
  466. else { 
  467. $info = $this->_loadfont($file); 
  468. $info['i'] = count($this->fonts)+1; 
  469. if(!empty($info['diff'])) 
  470. // Search existing encodings 
  471. $n = array_search($info['diff'], $this->diffs); 
  472. if(!$n) 
  473. $n = count($this->diffs)+1; 
  474. $this->diffs[$n] = $info['diff']; 
  475. $info['diffn'] = $n; 
  476. if(!empty($info['file'])) 
  477. // Embedded font 
  478. if($info['type']=='TrueType') 
  479. $this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']); 
  480. else 
  481. $this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']); 
  482. $this->fonts[$fontkey] = $info; 
  483.  
  484. function SetFont($family, $style='', $size=0) 
  485. // Select a font; size given in points 
  486. if($family=='') 
  487. $family = $this->FontFamily; 
  488. else 
  489. $family = strtolower($family); 
  490. $style = strtoupper($style); 
  491. if(strpos($style, 'U')!==false) 
  492. $this->underline = true; 
  493. $style = str_replace('U', '', $style); 
  494. else 
  495. $this->underline = false; 
  496. if($style=='IB') 
  497. $style = 'BI'; 
  498. if($size==0) 
  499. $size = $this->FontSizePt; 
  500. // Test if font is already selected 
  501. if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size) 
  502. return; 
  503. // Test if font is already loaded 
  504. $fontkey = $family.$style; 
  505. if(!isset($this->fonts[$fontkey])) 
  506. // Test if one of the core fonts 
  507. if($family=='arial') 
  508. $family = 'helvetica'; 
  509. if(in_array($family, $this->CoreFonts)) 
  510. if($family=='symbol' || $family=='zapfdingbats') 
  511. $style = ''; 
  512. $fontkey = $family.$style; 
  513. if(!isset($this->fonts[$fontkey])) 
  514. $this->AddFont($family, $style); 
  515. else 
  516. $this->Error('Undefined font: '.$family.' '.$style); 
  517. // Select it 
  518. $this->FontFamily = $family; 
  519. $this->FontStyle = $style; 
  520. $this->FontSizePt = $size; 
  521. $this->FontSize = $size/$this->k; 
  522. $this->CurrentFont = &$this->fonts[$fontkey]; 
  523. if ($this->fonts[$fontkey]['type']=='TTF') { $this->unifontSubset = true; } 
  524. else { $this->unifontSubset = false; } 
  525. if($this->page>0) 
  526. $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 
  527.  
  528. function SetFontSize($size) 
  529. // Set font size in points 
  530. if($this->FontSizePt==$size) 
  531. return; 
  532. $this->FontSizePt = $size; 
  533. $this->FontSize = $size/$this->k; 
  534. if($this->page>0) 
  535. $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 
  536.  
  537. function AddLink() 
  538. // Create a new internal link 
  539. $n = count($this->links)+1; 
  540. $this->links[$n] = array(0, 0); 
  541. return $n; 
  542.  
  543. function SetLink($link, $y=0, $page=-1) 
  544. // Set destination of internal link 
  545. if($y==-1) 
  546. $y = $this->y; 
  547. if($page==-1) 
  548. $page = $this->page; 
  549. $this->links[$link] = array($page, $y); 
  550.  
  551. function Link($x, $y, $w, $h, $link) 
  552. // Put a link on the page 
  553. $this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link); 
  554.  
  555. function Text($x, $y, $txt) 
  556. // Output a string 
  557. if ($this->unifontSubset) 
  558. $txt2 = '('.$this->_escape($this->UTF8ToUTF16BE($txt, false)).')'; 
  559. foreach($this->UTF8StringToArray($txt) as $uni) 
  560. $this->CurrentFont['subset'][$uni] = $uni; 
  561. else  
  562. $txt2 = '('.$this->_escape($txt).')'; 
  563. $s = sprintf('BT %.2F %.2F Td %s Tj ET', $x*$this->k, ($this->h-$y)*$this->k, $txt2); 
  564. if($this->underline && $txt!='') 
  565. $s .= ' '.$this->_dounderline($x, $y, $txt); 
  566. if($this->ColorFlag) 
  567. $s = 'q '.$this->TextColor.' '.$s.' Q'; 
  568. $this->_out($s); 
  569.  
  570. function AcceptPageBreak() 
  571. // Accept automatic page break or not 
  572. return $this->AutoPageBreak; 
  573.  
  574. function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='') 
  575. // Output a cell 
  576. $k = $this->k; 
  577. if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) 
  578. // Automatic page break 
  579. $x = $this->x; 
  580. $ws = $this->ws; 
  581. if($ws>0) 
  582. $this->ws = 0; 
  583. $this->_out('0 Tw'); 
  584. $this->AddPage($this->CurOrientation, $this->CurPageSize); 
  585. $this->x = $x; 
  586. if($ws>0) 
  587. $this->ws = $ws; 
  588. $this->_out(sprintf('%.3F Tw', $ws*$k)); 
  589. if($w==0) 
  590. $w = $this->w-$this->rMargin-$this->x; 
  591. $s = ''; 
  592. if($fill || $border==1) 
  593. if($fill) 
  594. $op = ($border==1) ? 'B' : 'f'; 
  595. else 
  596. $op = 'S'; 
  597. $s = sprintf('%.2F %.2F %.2F %.2F re %s ', $this->x*$k, ($this->h-$this->y)*$k, $w*$k, -$h*$k, $op); 
  598. if(is_string($border)) 
  599. $x = $this->x; 
  600. $y = $this->y; 
  601. if(strpos($border, 'L')!==false) 
  602. $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x*$k, ($this->h-$y)*$k, $x*$k, ($this->h-($y+$h))*$k); 
  603. if(strpos($border, 'T')!==false) 
  604. $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x*$k, ($this->h-$y)*$k, ($x+$w)*$k, ($this->h-$y)*$k); 
  605. if(strpos($border, 'R')!==false) 
  606. $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', ($x+$w)*$k, ($this->h-$y)*$k, ($x+$w)*$k, ($this->h-($y+$h))*$k); 
  607. if(strpos($border, 'B')!==false) 
  608. $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x*$k, ($this->h-($y+$h))*$k, ($x+$w)*$k, ($this->h-($y+$h))*$k); 
  609. if($txt!=='') 
  610. if($align=='R') 
  611. $dx = $w-$this->cMargin-$this->GetStringWidth($txt); 
  612. elseif($align=='C') 
  613. $dx = ($w-$this->GetStringWidth($txt))/2; 
  614. else 
  615. $dx = $this->cMargin; 
  616. if($this->ColorFlag) 
  617. $s .= 'q '.$this->TextColor.' '; 
  618.  
  619. // If multibyte, Tw has no effect - do word spacing using an adjustment before each space 
  620. if ($this->ws && $this->unifontSubset) { 
  621. foreach($this->UTF8StringToArray($txt) as $uni) 
  622. $this->CurrentFont['subset'][$uni] = $uni; 
  623. $space = $this->_escape($this->UTF8ToUTF16BE(' ', false)); 
  624. $s .= sprintf('BT 0 Tw %.2F %.2F Td [', ($this->x+$dx)*$k, ($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k); 
  625. $t = explode(' ', $txt); 
  626. $numt = count($t); 
  627. for($i=0;$i<$numt;$i++) { 
  628. $tx = $t[$i]; 
  629. $tx = '('.$this->_escape($this->UTF8ToUTF16BE($tx, false)).')'; 
  630. $s .= sprintf('%s ', $tx); 
  631. if (($i+1)<$numt) { 
  632. $adj = -($this->ws*$this->k)*1000/$this->FontSizePt; 
  633. $s .= sprintf('%d(%s) ', $adj, $space); 
  634. $s .= '] TJ'; 
  635. $s .= ' ET'; 
  636. else { 
  637. if ($this->unifontSubset) 
  638. $txt2 = '('.$this->_escape($this->UTF8ToUTF16BE($txt, false)).')'; 
  639. foreach($this->UTF8StringToArray($txt) as $uni) 
  640. $this->CurrentFont['subset'][$uni] = $uni; 
  641. else 
  642. $txt2='('.str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt))).')'; 
  643. $s .= sprintf('BT %.2F %.2F Td %s Tj ET', ($this->x+$dx)*$k, ($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k, $txt2); 
  644. if($this->underline) 
  645. $s .= ' '.$this->_dounderline($this->x+$dx, $this->y+.5*$h+.3*$this->FontSize, $txt); 
  646. if($this->ColorFlag) 
  647. $s .= ' Q'; 
  648. if($link) 
  649. $this->Link($this->x+$dx, $this->y+.5*$h-.5*$this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link); 
  650. if($s) 
  651. $this->_out($s); 
  652. $this->lasth = $h; 
  653. if($ln>0) 
  654. // Go to next line 
  655. $this->y += $h; 
  656. if($ln==1) 
  657. $this->x = $this->lMargin; 
  658. else 
  659. $this->x += $w; 
  660.  
  661. function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false) 
  662. // Output text with automatic or explicit line breaks 
  663. $cw = &$this->CurrentFont['cw']; 
  664. if($w==0) 
  665. $w = $this->w-$this->rMargin-$this->x; 
  666. $wmax = ($w-2*$this->cMargin); 
  667. $s = str_replace("\r", '', $txt); 
  668. if ($this->unifontSubset) { 
  669. $nb=mb_strlen($s, 'utf-8'); 
  670. while($nb>0 && mb_substr($s, $nb-1, 1, 'utf-8')=="\n") $nb--; 
  671. else { 
  672. $nb = strlen($s); 
  673. if($nb>0 && $s[$nb-1]=="\n") 
  674. $nb--; 
  675. $b = 0; 
  676. if($border) 
  677. if($border==1) 
  678. $border = 'LTRB'; 
  679. $b = 'LRT'; 
  680. $b2 = 'LR'; 
  681. else 
  682. $b2 = ''; 
  683. if(strpos($border, 'L')!==false) 
  684. $b2 .= 'L'; 
  685. if(strpos($border, 'R')!==false) 
  686. $b2 .= 'R'; 
  687. $b = (strpos($border, 'T')!==false) ? $b2.'T' : $b2; 
  688. $sep = -1; 
  689. $i = 0; 
  690. $j = 0; 
  691. $l = 0; 
  692. $ns = 0; 
  693. $nl = 1; 
  694. while($i<$nb) 
  695. // Get next character 
  696. if ($this->unifontSubset) { 
  697. $c = mb_substr($s, $i, 1, 'UTF-8'); 
  698. else { 
  699. $c=$s[$i]; 
  700. if($c=="\n") 
  701. // Explicit line break 
  702. if($this->ws>0) 
  703. $this->ws = 0; 
  704. $this->_out('0 Tw'); 
  705. if ($this->unifontSubset) { 
  706. $this->Cell($w, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), $b, 2, $align, $fill); 
  707. else { 
  708. $this->Cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill); 
  709. $i++; 
  710. $sep = -1; 
  711. $j = $i; 
  712. $l = 0; 
  713. $ns = 0; 
  714. $nl++; 
  715. if($border && $nl==2) 
  716. $b = $b2; 
  717. continue; 
  718. if($c==' ') 
  719. $sep = $i; 
  720. $ls = $l; 
  721. $ns++; 
  722.  
  723. if ($this->unifontSubset) { $l += $this->GetStringWidth($c); } 
  724. else { $l += $cw[$c]*$this->FontSize/1000; } 
  725.  
  726. if($l>$wmax) 
  727. // Automatic line break 
  728. if($sep==-1) 
  729. if($i==$j) 
  730. $i++; 
  731. if($this->ws>0) 
  732. $this->ws = 0; 
  733. $this->_out('0 Tw'); 
  734. if ($this->unifontSubset) { 
  735. $this->Cell($w, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), $b, 2, $align, $fill); 
  736. else { 
  737. $this->Cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill); 
  738. else 
  739. if($align=='J') 
  740. $this->ws = ($ns>1) ? ($wmax-$ls)/($ns-1) : 0; 
  741. $this->_out(sprintf('%.3F Tw', $this->ws*$this->k)); 
  742. if ($this->unifontSubset) { 
  743. $this->Cell($w, $h, mb_substr($s, $j, $sep-$j, 'UTF-8'), $b, 2, $align, $fill); 
  744. else { 
  745. $this->Cell($w, $h, substr($s, $j, $sep-$j), $b, 2, $align, $fill); 
  746. $i = $sep+1; 
  747. $sep = -1; 
  748. $j = $i; 
  749. $l = 0; 
  750. $ns = 0; 
  751. $nl++; 
  752. if($border && $nl==2) 
  753. $b = $b2; 
  754. else 
  755. $i++; 
  756. // Last chunk 
  757. if($this->ws>0) 
  758. $this->ws = 0; 
  759. $this->_out('0 Tw'); 
  760. if($border && strpos($border, 'B')!==false) 
  761. $b .= 'B'; 
  762. if ($this->unifontSubset) { 
  763. $this->Cell($w, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), $b, 2, $align, $fill); 
  764. else { 
  765. $this->Cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill); 
  766. $this->x = $this->lMargin; 
  767.  
  768. function Write($h, $txt, $link='') 
  769. // Output text in flowing mode 
  770. $cw = &$this->CurrentFont['cw']; 
  771. $w = $this->w-$this->rMargin-$this->x; 
  772.  
  773. $wmax = ($w-2*$this->cMargin); 
  774. $s = str_replace("\r", '', $txt); 
  775. if ($this->unifontSubset) { 
  776. $nb = mb_strlen($s, 'UTF-8'); 
  777. if($nb==1 && $s==" ") { 
  778. $this->x += $this->GetStringWidth($s); 
  779. return; 
  780. else { 
  781. $nb = strlen($s); 
  782. $sep = -1; 
  783. $i = 0; 
  784. $j = 0; 
  785. $l = 0; 
  786. $nl = 1; 
  787. while($i<$nb) 
  788. // Get next character 
  789. if ($this->unifontSubset) { 
  790. $c = mb_substr($s, $i, 1, 'UTF-8'); 
  791. else { 
  792. $c = $s[$i]; 
  793. if($c=="\n") 
  794. // Explicit line break 
  795. if ($this->unifontSubset) { 
  796. $this->Cell($w, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), 0, 2, '', 0, $link); 
  797. else { 
  798. $this->Cell($w, $h, substr($s, $j, $i-$j), 0, 2, '', 0, $link); 
  799. $i++; 
  800. $sep = -1; 
  801. $j = $i; 
  802. $l = 0; 
  803. if($nl==1) 
  804. $this->x = $this->lMargin; 
  805. $w = $this->w-$this->rMargin-$this->x; 
  806. $wmax = ($w-2*$this->cMargin); 
  807. $nl++; 
  808. continue; 
  809. if($c==' ') 
  810. $sep = $i; 
  811.  
  812. if ($this->unifontSubset) { $l += $this->GetStringWidth($c); } 
  813. else { $l += $cw[$c]*$this->FontSize/1000; } 
  814.  
  815. if($l>$wmax) 
  816. // Automatic line break 
  817. if($sep==-1) 
  818. if($this->x>$this->lMargin) 
  819. // Move to next line 
  820. $this->x = $this->lMargin; 
  821. $this->y += $h; 
  822. $w = $this->w-$this->rMargin-$this->x; 
  823. $wmax = ($w-2*$this->cMargin); 
  824. $i++; 
  825. $nl++; 
  826. continue; 
  827. if($i==$j) 
  828. $i++; 
  829. if ($this->unifontSubset) { 
  830. $this->Cell($w, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), 0, 2, '', 0, $link); 
  831. else { 
  832. $this->Cell($w, $h, substr($s, $j, $i-$j), 0, 2, '', 0, $link); 
  833. else 
  834. if ($this->unifontSubset) { 
  835. $this->Cell($w, $h, mb_substr($s, $j, $sep-$j, 'UTF-8'), 0, 2, '', 0, $link); 
  836. else { 
  837. $this->Cell($w, $h, substr($s, $j, $sep-$j), 0, 2, '', 0, $link); 
  838. $i = $sep+1; 
  839. $sep = -1; 
  840. $j = $i; 
  841. $l = 0; 
  842. if($nl==1) 
  843. $this->x = $this->lMargin; 
  844. $w = $this->w-$this->rMargin-$this->x; 
  845. $wmax = ($w-2*$this->cMargin); 
  846. $nl++; 
  847. else 
  848. $i++; 
  849. // Last chunk 
  850. if($i!=$j) { 
  851. if ($this->unifontSubset) { 
  852. $this->Cell($l, $h, mb_substr($s, $j, $i-$j, 'UTF-8'), 0, 0, '', 0, $link); 
  853. else { 
  854. $this->Cell($l, $h, substr($s, $j), 0, 0, '', 0, $link); 
  855.  
  856. function Ln($h=null) 
  857. // Line feed; default value is last cell height 
  858. $this->x = $this->lMargin; 
  859. if($h===null) 
  860. $this->y += $this->lasth; 
  861. else 
  862. $this->y += $h; 
  863.  
  864. function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='') 
  865. // Put an image on the page 
  866. if(!isset($this->images[$file])) 
  867. // First use of this image, get info 
  868. if($type=='') 
  869. $pos = strrpos($file, '.'); 
  870. if(!$pos) 
  871. $this->Error('Image file has no extension and no type was specified: '.$file); 
  872. $type = substr($file, $pos+1); 
  873. $type = strtolower($type); 
  874. if($type=='jpeg') 
  875. $type = 'jpg'; 
  876. $mtd = '_parse'.$type; 
  877. if(!method_exists($this, $mtd)) 
  878. $this->Error('Unsupported image type: '.$type); 
  879. $info = $this->$mtd($file); 
  880. $info['i'] = count($this->images)+1; 
  881. $this->images[$file] = $info; 
  882. else 
  883. $info = $this->images[$file]; 
  884.  
  885. // Automatic width and height calculation if needed 
  886. if($w==0 && $h==0) 
  887. // Put image at 96 dpi 
  888. $w = -96; 
  889. $h = -96; 
  890. if($w<0) 
  891. $w = -$info['w']*72/$w/$this->k; 
  892. if($h<0) 
  893. $h = -$info['h']*72/$h/$this->k; 
  894. if($w==0) 
  895. $w = $h*$info['w']/$info['h']; 
  896. if($h==0) 
  897. $h = $w*$info['h']/$info['w']; 
  898.  
  899. // Flowing mode 
  900. if($y===null) 
  901. if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) 
  902. // Automatic page break 
  903. $x2 = $this->x; 
  904. $this->AddPage($this->CurOrientation, $this->CurPageSize); 
  905. $this->x = $x2; 
  906. $y = $this->y; 
  907. $this->y += $h; 
  908.  
  909. if($x===null) 
  910. $x = $this->x; 
  911. $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k, $info['i'])); 
  912. if($link) 
  913. $this->Link($x, $y, $w, $h, $link); 
  914.  
  915. function GetX() 
  916. // Get x position 
  917. return $this->x; 
  918.  
  919. function SetX($x) 
  920. // Set x position 
  921. if($x>=0) 
  922. $this->x = $x; 
  923. else 
  924. $this->x = $this->w+$x; 
  925.  
  926. function GetY() 
  927. // Get y position 
  928. return $this->y; 
  929.  
  930. function SetY($y) 
  931. // Set y position and reset x 
  932. $this->x = $this->lMargin; 
  933. if($y>=0) 
  934. $this->y = $y; 
  935. else 
  936. $this->y = $this->h+$y; 
  937.  
  938. function SetXY($x, $y) 
  939. // Set x and y positions 
  940. $this->SetY($y); 
  941. $this->SetX($x); 
  942.  
  943. function Output($name='', $dest='') 
  944. // Output PDF to some destination 
  945. if($this->state<3) 
  946. $this->Close(); 
  947. $dest = strtoupper($dest); 
  948. if($dest=='') 
  949. if($name=='') 
  950. $name = 'doc.pdf'; 
  951. $dest = 'I'; 
  952. else 
  953. $dest = 'F'; 
  954. switch($dest) 
  955. case 'I': 
  956. // Send to standard output 
  957. $this->_checkoutput(); 
  958. if(PHP_SAPI!='cli') 
  959. // We send to a browser 
  960. header('Content-Type: application/pdf'); 
  961. header('Content-Disposition: inline; filename="'.$name.'"'); 
  962. header('Cache-Control: private, max-age=0, must-revalidate'); 
  963. header('Pragma: public'); 
  964. echo $this->buffer; 
  965. break; 
  966. case 'D': 
  967. // Download file 
  968. $this->_checkoutput(); 
  969. header('Content-Type: application/x-download'); 
  970. header('Content-Disposition: attachment; filename="'.$name.'"'); 
  971. header('Cache-Control: private, max-age=0, must-revalidate'); 
  972. header('Pragma: public'); 
  973. echo $this->buffer; 
  974. break; 
  975. case 'F': 
  976. // Save to local file 
  977. $f = fopen($name, 'wb'); 
  978. if(!$f) 
  979. $this->Error('Unable to create output file: '.$name); 
  980. fwrite($f, $this->buffer, strlen($this->buffer)); 
  981. fclose($f); 
  982. break; 
  983. case 'S': 
  984. // Return as a string 
  985. return $this->buffer; 
  986. default: 
  987. $this->Error('Incorrect output destination: '.$dest); 
  988. return ''; 
  989.  
  990. /******************************************************************************* 
  991. * * 
  992. * Protected methods * 
  993. * * 
  994. *******************************************************************************/ 
  995. function _dochecks() 
  996. // Check availability of %F 
  997. if(sprintf('%.1F', 1.0)!='1.0') 
  998. $this->Error('This version of PHP is not supported'); 
  999. // Check availability of mbstring 
  1000. if(!function_exists('mb_strlen')) 
  1001. $this->Error('mbstring extension is not available'); 
  1002. // Check mbstring overloading 
  1003. if(ini_get('mbstring.func_overload') & 2) 
  1004. $this->Error('mbstring overloading must be disabled'); 
  1005. // Ensure runtime magic quotes are disabled 
  1006. if(get_magic_quotes_runtime()) 
  1007. @set_magic_quotes_runtime(0); 
  1008.  
  1009. function _getfontpath() 
  1010. return $this->fontpath; 
  1011.  
  1012. function _checkoutput() 
  1013. if(PHP_SAPI!='cli') 
  1014. if(headers_sent($file, $line)) 
  1015. $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)"); 
  1016. if(ob_get_length()) 
  1017. // The output buffer is not empty 
  1018. if(preg_match('/^(\xEF\xBB\xBF)?\s*$/', ob_get_contents())) 
  1019. // It contains only a UTF-8 BOM and/or whitespace, let's clean it 
  1020. ob_clean(); 
  1021. else 
  1022. $this->Error("Some data has already been output, can't send PDF file"); 
  1023.  
  1024. function _getpagesize($size) 
  1025. if(is_string($size)) 
  1026. $size = strtolower($size); 
  1027. if(!isset($this->StdPageSizes[$size])) 
  1028. $this->Error('Unknown page size: '.$size); 
  1029. $a = $this->StdPageSizes[$size]; 
  1030. return array($a[0]/$this->k, $a[1]/$this->k); 
  1031. else 
  1032. if($size[0]>$size[1]) 
  1033. return array($size[1], $size[0]); 
  1034. else 
  1035. return $size; 
  1036.  
  1037. function _beginpage($orientation, $size) 
  1038. $this->page++; 
  1039. $this->pages[$this->page] = ''; 
  1040. $this->state = 2; 
  1041. $this->x = $this->lMargin; 
  1042. $this->y = $this->tMargin; 
  1043. $this->FontFamily = ''; 
  1044. // Check page size and orientation 
  1045. if($orientation=='') 
  1046. $orientation = $this->DefOrientation; 
  1047. else 
  1048. $orientation = strtoupper($orientation[0]); 
  1049. if($size=='') 
  1050. $size = $this->DefPageSize; 
  1051. else 
  1052. $size = $this->_getpagesize($size); 
  1053. if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1]) 
  1054. // New size or orientation 
  1055. if($orientation=='P') 
  1056. $this->w = $size[0]; 
  1057. $this->h = $size[1]; 
  1058. else 
  1059. $this->w = $size[1]; 
  1060. $this->h = $size[0]; 
  1061. $this->wPt = $this->w*$this->k; 
  1062. $this->hPt = $this->h*$this->k; 
  1063. $this->PageBreakTrigger = $this->h-$this->bMargin; 
  1064. $this->CurOrientation = $orientation; 
  1065. $this->CurPageSize = $size; 
  1066. if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1]) 
  1067. $this->PageSizes[$this->page] = array($this->wPt, $this->hPt); 
  1068.  
  1069. function _endpage() 
  1070. $this->state = 1; 
  1071.  
  1072. function _loadfont($font) 
  1073. // Load a font definition file from the font directory 
  1074. include($this->fontpath.$font); 
  1075. $a = get_defined_vars(); 
  1076. if(!isset($a['name'])) 
  1077. $this->Error('Could not include font definition file'); 
  1078. return $a; 
  1079.  
  1080. function _escape($s) 
  1081. // Escape special characters in strings 
  1082. $s = str_replace('\\', '\\\\', $s); 
  1083. $s = str_replace('(', '\\(', $s); 
  1084. $s = str_replace(')', '\\)', $s); 
  1085. $s = str_replace("\r", '\\r', $s); 
  1086. return $s; 
  1087.  
  1088. function _textstring($s) 
  1089. // Format a text string 
  1090. return '('.$this->_escape($s).')'; 
  1091.  
  1092. function _UTF8toUTF16($s) 
  1093. // Convert UTF-8 to UTF-16BE with BOM 
  1094. $res = "\xFE\xFF"; 
  1095. $nb = strlen($s); 
  1096. $i = 0; 
  1097. while($i<$nb) 
  1098. $c1 = ord($s[$i++]); 
  1099. if($c1>=224) 
  1100. // 3-byte character 
  1101. $c2 = ord($s[$i++]); 
  1102. $c3 = ord($s[$i++]); 
  1103. $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2)); 
  1104. $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F)); 
  1105. elseif($c1>=192) 
  1106. // 2-byte character 
  1107. $c2 = ord($s[$i++]); 
  1108. $res .= chr(($c1 & 0x1C)>>2); 
  1109. $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F)); 
  1110. else 
  1111. // Single-byte character 
  1112. $res .= "\0".chr($c1); 
  1113. return $res; 
  1114.  
  1115. function _dounderline($x, $y, $txt) 
  1116. // Underline text 
  1117. $up = $this->CurrentFont['up']; 
  1118. $ut = $this->CurrentFont['ut']; 
  1119. $w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt, ' '); 
  1120. 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); 
  1121.  
  1122. function _parsejpg($file) 
  1123. // Extract info from a JPEG file 
  1124. $a = getimagesize($file); 
  1125.  
  1126. if(!$a) { 
  1127. $makeitlocal = trim(get_option( 'siteurl' ), '/') . '/'; 
  1128. $file = str_replace($makeitlocal, '', $file); 
  1129. $a = getimagesize($file); 
  1130. if( !$a && strpos($file, 'http') !== FALSE ) { 
  1131. $this->Error('[Error] '.$file.' Missing or Please turn on "allow_url_fopen" on your server to allow insert images in PDF Document, more info here: http://stackoverflow.com/questions/3694240/add-allow-url-fopen-to-my-php-ini-using-htaccess'); 
  1132. if(!$a) { 
  1133. $a = getimagesize( './'. $file ); 
  1134.  
  1135. if(!$a) 
  1136. $this->Error('Missing or incorrect image file: '.$file); 
  1137. if($a[2]!=2) 
  1138. $this->Error('Not a JPEG file: '.$file); 
  1139. if(!isset($a['channels']) || $a['channels']==3) 
  1140. $colspace = 'DeviceRGB'; 
  1141. elseif($a['channels']==4) 
  1142. $colspace = 'DeviceCMYK'; 
  1143. else 
  1144. $colspace = 'DeviceGray'; 
  1145. $bpc = isset($a['bits']) ? $a['bits'] : 8; 
  1146. $data = file_get_contents($file); 
  1147. return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data); 
  1148.  
  1149. function _parsepng($file) 
  1150. // Extract info from a PNG file 
  1151. $f = fopen($file, 'rb'); 
  1152.  
  1153. if(!$f) { 
  1154. $makeitlocal = trim(get_option( 'siteurl' ), '/') . '/'; 
  1155. $file = str_replace($makeitlocal, '', $file); 
  1156. $f=fopen($file, 'rb'); 
  1157. if( !$f && strpos($file, 'http') !== FALSE ) { 
  1158. $this->Error('[Error] '.$file.' Missing or Please turn on "allow_url_fopen" on your server to allow insert images in PDF Document, more info here: http://stackoverflow.com/questions/3694240/add-allow-url-fopen-to-my-php-ini-using-htaccess'); 
  1159. if(!$f) { 
  1160. $f=fopen( './'.$file, 'rb'); 
  1161.  
  1162. if(!$f) 
  1163. $this->Error('Can\'t open image file: '.$file); 
  1164. $info = $this->_parsepngstream($f, $file); 
  1165. fclose($f); 
  1166. return $info; 
  1167.  
  1168. function _parsepngstream($f, $file) 
  1169. // Check signature 
  1170. if($this->_readstream($f, 8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) 
  1171. $this->Error('Not a PNG file: '.$file); 
  1172.  
  1173. // Read header chunk 
  1174. $this->_readstream($f, 4); 
  1175. if($this->_readstream($f, 4)!='IHDR') 
  1176. $this->Error('Incorrect PNG file: '.$file); 
  1177. $w = $this->_readint($f); 
  1178. $h = $this->_readint($f); 
  1179. $bpc = ord($this->_readstream($f, 1)); 
  1180. if($bpc>8) 
  1181. $this->Error('16-bit depth not supported: '.$file); 
  1182. $ct = ord($this->_readstream($f, 1)); 
  1183. if($ct==0 || $ct==4) 
  1184. $colspace = 'DeviceGray'; 
  1185. elseif($ct==2 || $ct==6) 
  1186. $colspace = 'DeviceRGB'; 
  1187. elseif($ct==3) 
  1188. $colspace = 'Indexed'; 
  1189. else 
  1190. $this->Error('Unknown color type: '.$file); 
  1191. if(ord($this->_readstream($f, 1))!=0) 
  1192. $this->Error('Unknown compression method: '.$file); 
  1193. if(ord($this->_readstream($f, 1))!=0) 
  1194. $this->Error('Unknown filter method: '.$file); 
  1195. if(ord($this->_readstream($f, 1))!=0) 
  1196. $this->Error('Interlacing not supported: '.$file); 
  1197. $this->_readstream($f, 4); 
  1198. $dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w; 
  1199.  
  1200. // Scan chunks looking for palette, transparency and image data 
  1201. $pal = ''; 
  1202. $trns = ''; 
  1203. $data = ''; 
  1204. do 
  1205. $n = $this->_readint($f); 
  1206. $type = $this->_readstream($f, 4); 
  1207. if($type=='PLTE') 
  1208. // Read palette 
  1209. $pal = $this->_readstream($f, $n); 
  1210. $this->_readstream($f, 4); 
  1211. elseif($type=='tRNS') 
  1212. // Read transparency info 
  1213. $t = $this->_readstream($f, $n); 
  1214. if($ct==0) 
  1215. $trns = array(ord(substr($t, 1, 1))); 
  1216. elseif($ct==2) 
  1217. $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))); 
  1218. else 
  1219. $pos = strpos($t, chr(0)); 
  1220. if($pos!==false) 
  1221. $trns = array($pos); 
  1222. $this->_readstream($f, 4); 
  1223. elseif($type=='IDAT') 
  1224. // Read image data block 
  1225. $data .= $this->_readstream($f, $n); 
  1226. $this->_readstream($f, 4); 
  1227. elseif($type=='IEND') 
  1228. break; 
  1229. else 
  1230. $this->_readstream($f, $n+4); 
  1231. while($n); 
  1232.  
  1233. if($colspace=='Indexed' && empty($pal)) 
  1234. $this->Error('Missing palette in '.$file); 
  1235. $info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns); 
  1236. if($ct>=4) 
  1237. // Extract alpha channel 
  1238. if(!function_exists('gzuncompress')) 
  1239. $this->Error('Zlib not available, can\'t handle alpha channel: '.$file); 
  1240. $data = gzuncompress($data); 
  1241. $color = ''; 
  1242. $alpha = ''; 
  1243. if($ct==4) 
  1244. // Gray image 
  1245. $len = 2*$w; 
  1246. for($i=0;$i<$h;$i++) 
  1247. $pos = (1+$len)*$i; 
  1248. $color .= $data[$pos]; 
  1249. $alpha .= $data[$pos]; 
  1250. $line = substr($data, $pos+1, $len); 
  1251. $color .= preg_replace('/(.)./s', '$1', $line); 
  1252. $alpha .= preg_replace('/.(.)/s', '$1', $line); 
  1253. else 
  1254. // RGB image 
  1255. $len = 4*$w; 
  1256. for($i=0;$i<$h;$i++) 
  1257. $pos = (1+$len)*$i; 
  1258. $color .= $data[$pos]; 
  1259. $alpha .= $data[$pos]; 
  1260. $line = substr($data, $pos+1, $len); 
  1261. $color .= preg_replace('/(.{3})./s', '$1', $line); 
  1262. $alpha .= preg_replace('/.{3}(.)/s', '$1', $line); 
  1263. unset($data); 
  1264. $data = gzcompress($color); 
  1265. $info['smask'] = gzcompress($alpha); 
  1266. if($this->PDFVersion<'1.4') 
  1267. $this->PDFVersion = '1.4'; 
  1268. $info['data'] = $data; 
  1269. return $info; 
  1270.  
  1271. function _readstream($f, $n) 
  1272. // Read n bytes from stream 
  1273. $res = ''; 
  1274. while($n>0 && !feof($f)) 
  1275. $s = fread($f, $n); 
  1276. if($s===false) 
  1277. $this->Error('Error while reading stream'); 
  1278. $n -= strlen($s); 
  1279. $res .= $s; 
  1280. if($n>0) 
  1281. $this->Error('Unexpected end of stream'); 
  1282. return $res; 
  1283.  
  1284. function _readint($f) 
  1285. // Read a 4-byte integer from stream 
  1286. $a = unpack('Ni', $this->_readstream($f, 4)); 
  1287. return $a['i']; 
  1288.  
  1289. function _parsegif($file) 
  1290. // Extract info from a GIF file (via PNG conversion) 
  1291. if(!function_exists('imagepng')) 
  1292. $this->Error('GD extension is required for GIF support'); 
  1293. if(!function_exists('imagecreatefromgif')) 
  1294. $this->Error('GD has no GIF read support'); 
  1295. $im = imagecreatefromgif($file); 
  1296.  
  1297. if(!$im) { 
  1298. $makeitlocal = trim(get_option( 'siteurl' ), '/') . '/'; 
  1299. $file = str_replace($makeitlocal, '', $file); 
  1300. $im = imagecreatefromgif($file); 
  1301. if( !$im && strpos($file, 'http') !== FALSE ) { 
  1302. $this->Error('[Error] '.$file.' Missing or Please turn on "allow_url_fopen" on your server to allow insert images in PDF Document, more info here: http://stackoverflow.com/questions/3694240/add-allow-url-fopen-to-my-php-ini-using-htaccess'); 
  1303. $im = imagecreatefromgif( './' . $file); 
  1304.  
  1305. if(!$im) 
  1306. $this->Error('Missing or incorrect image file: '.$file); 
  1307. imageinterlace($im, 0); 
  1308. $f = @fopen('php://temp', 'rb+'); 
  1309. if($f) 
  1310. // Perform conversion in memory 
  1311. ob_start(); 
  1312. imagepng($im); 
  1313. $data = ob_get_clean(); 
  1314. imagedestroy($im); 
  1315. fwrite($f, $data); 
  1316. rewind($f); 
  1317. $info = $this->_parsepngstream($f, $file); 
  1318. fclose($f); 
  1319. else 
  1320. // Use temporary file 
  1321. $tmp = tempnam('.', 'gif'); 
  1322. if(!$tmp) 
  1323. $this->Error('Unable to create a temporary file'); 
  1324. if(!imagepng($im, $tmp)) 
  1325. $this->Error('Error while saving to temporary file'); 
  1326. imagedestroy($im); 
  1327. $info = $this->_parsepng($tmp); 
  1328. unlink($tmp); 
  1329. return $info; 
  1330.  
  1331. function _newobj() 
  1332. // Begin a new object 
  1333. $this->n++; 
  1334. $this->offsets[$this->n] = strlen($this->buffer); 
  1335. $this->_out($this->n.' 0 obj'); 
  1336.  
  1337. function _putstream($s) 
  1338. $this->_out('stream'); 
  1339. $this->_out($s); 
  1340. $this->_out('endstream'); 
  1341.  
  1342. function _out($s) 
  1343. // Add a line to the document 
  1344. if($this->state==2) 
  1345. $this->pages[$this->page] .= $s."\n"; 
  1346. else 
  1347. $this->buffer .= $s."\n"; 
  1348.  
  1349. function _putpages() 
  1350. $nb = $this->page; 
  1351. if(!empty($this->AliasNbPages)) 
  1352. // Replace number of pages in fonts using subsets 
  1353. $alias = $this->UTF8ToUTF16BE($this->AliasNbPages, false); 
  1354. $r = $this->UTF8ToUTF16BE("$nb", false); 
  1355. for($n=1;$n<=$nb;$n++) 
  1356. $this->pages[$n] = str_replace($alias, $r, $this->pages[$n]); 
  1357. // Now repeat for no pages in non-subset fonts 
  1358. for($n=1;$n<=$nb;$n++) 
  1359. $this->pages[$n] = str_replace($this->AliasNbPages, $nb, $this->pages[$n]); 
  1360. if($this->DefOrientation=='P') 
  1361. $wPt = $this->DefPageSize[0]*$this->k; 
  1362. $hPt = $this->DefPageSize[1]*$this->k; 
  1363. else 
  1364. $wPt = $this->DefPageSize[1]*$this->k; 
  1365. $hPt = $this->DefPageSize[0]*$this->k; 
  1366. $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; 
  1367. for($n=1;$n<=$nb;$n++) 
  1368. // Page 
  1369. $this->_newobj(); 
  1370. $this->_out('<</Type /Page'); 
  1371. $this->_out('/Parent 1 0 R'); 
  1372. if(isset($this->PageSizes[$n])) 
  1373. $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->PageSizes[$n][0], $this->PageSizes[$n][1])); 
  1374. $this->_out('/Resources 2 0 R'); 
  1375. if(isset($this->PageLinks[$n])) 
  1376. // Links 
  1377. $annots = '/Annots ['; 
  1378. foreach($this->PageLinks[$n] as $pl) 
  1379. $rect = sprintf('%.2F %.2F %.2F %.2F', $pl[0], $pl[1], $pl[0]+$pl[2], $pl[1]-$pl[3]); 
  1380. $annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] '; 
  1381. if(is_string($pl[4])) 
  1382. $annots .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>'; 
  1383. else 
  1384. $l = $this->links[$pl[4]]; 
  1385. $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt; 
  1386. $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>', 1+2*$l[0], $h-$l[1]*$this->k); 
  1387. $this->_out($annots.']'); 
  1388. if($this->PDFVersion>'1.3') 
  1389. $this->_out('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>'); 
  1390. $this->_out('/Contents '.($this->n+1).' 0 R>>'); 
  1391. $this->_out('endobj'); 
  1392. // Page content 
  1393. $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; 
  1394. $this->_newobj(); 
  1395. $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); 
  1396. $this->_putstream($p); 
  1397. $this->_out('endobj'); 
  1398. // Pages root 
  1399. $this->offsets[1] = strlen($this->buffer); 
  1400. $this->_out('1 0 obj'); 
  1401. $this->_out('<</Type /Pages'); 
  1402. $kids = '/Kids ['; 
  1403. for($i=0;$i<$nb;$i++) 
  1404. $kids .= (3+2*$i).' 0 R '; 
  1405. $this->_out($kids.']'); 
  1406. $this->_out('/Count '.$nb); 
  1407. $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]', $wPt, $hPt)); 
  1408. $this->_out('>>'); 
  1409. $this->_out('endobj'); 
  1410.  
  1411. function _putfonts() 
  1412. $nf=$this->n; 
  1413. foreach($this->diffs as $diff) 
  1414. // Encodings 
  1415. $this->_newobj(); 
  1416. $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>'); 
  1417. $this->_out('endobj'); 
  1418. foreach($this->FontFiles as $file=>$info) 
  1419. if (!isset($info['type']) || $info['type']!='TTF') { 
  1420. // Font file embedding 
  1421. $this->_newobj(); 
  1422. $this->FontFiles[$file]['n']=$this->n; 
  1423. $font=''; 
  1424. $f=fopen($this->_getfontpath().$file, 'rb', 1); 
  1425. if(!$f) 
  1426. $this->Error('Font file not found'); 
  1427. while(!feof($f)) 
  1428. $font.=fread($f, 8192); 
  1429. fclose($f); 
  1430. $compressed=(substr($file, -2)=='.z'); 
  1431. if(!$compressed && isset($info['length2'])) 
  1432. $header=(ord($font[0])==128); 
  1433. if($header) 
  1434. // Strip first binary header 
  1435. $font=substr($font, 6); 
  1436. if($header && ord($font[$info['length1']])==128) 
  1437. // Strip second binary header 
  1438. $font=substr($font, 0, $info['length1']).substr($font, $info['length1']+6); 
  1439. $this->_out('<</Length '.strlen($font)); 
  1440. if($compressed) 
  1441. $this->_out('/Filter /FlateDecode'); 
  1442. $this->_out('/Length1 '.$info['length1']); 
  1443. if(isset($info['length2'])) 
  1444. $this->_out('/Length2 '.$info['length2'].' /Length3 0'); 
  1445. $this->_out('>>'); 
  1446. $this->_putstream($font); 
  1447. $this->_out('endobj'); 
  1448. foreach($this->fonts as $k=>$font) 
  1449. // Font objects 
  1450. //$this->fonts[$k]['n']=$this->n+1; 
  1451. $type = $font['type']; 
  1452. $name = $font['name']; 
  1453. if($type=='Core') 
  1454. // Standard font 
  1455. $this->fonts[$k]['n']=$this->n+1; 
  1456. $this->_newobj(); 
  1457. $this->_out('<</Type /Font'); 
  1458. $this->_out('/BaseFont /'.$name); 
  1459. $this->_out('/Subtype /Type1'); 
  1460. if($name!='Symbol' && $name!='ZapfDingbats') 
  1461. $this->_out('/Encoding /WinAnsiEncoding'); 
  1462. $this->_out('>>'); 
  1463. $this->_out('endobj'); 
  1464. elseif($type=='Type1' || $type=='TrueType') 
  1465. // Additional Type1 or TrueType font 
  1466. $this->fonts[$k]['n']=$this->n+1; 
  1467. $this->_newobj(); 
  1468. $this->_out('<</Type /Font'); 
  1469. $this->_out('/BaseFont /'.$name); 
  1470. $this->_out('/Subtype /'.$type); 
  1471. $this->_out('/FirstChar 32 /LastChar 255'); 
  1472. $this->_out('/Widths '.($this->n+1).' 0 R'); 
  1473. $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); 
  1474. if($font['enc']) 
  1475. if(isset($font['diff'])) 
  1476. $this->_out('/Encoding '.($nf+$font['diff']).' 0 R'); 
  1477. else 
  1478. $this->_out('/Encoding /WinAnsiEncoding'); 
  1479. $this->_out('>>'); 
  1480. $this->_out('endobj'); 
  1481. // Widths 
  1482. $this->_newobj(); 
  1483. $cw=&$font['cw']; 
  1484. $s='['; 
  1485. for($i=32;$i<=255;$i++) 
  1486. $s.=$cw[chr($i)].' '; 
  1487. $this->_out($s.']'); 
  1488. $this->_out('endobj'); 
  1489. // Descriptor 
  1490. $this->_newobj(); 
  1491. $s='<</Type /FontDescriptor /FontName /'.$name; 
  1492. foreach($font['desc'] as $k=>$v) 
  1493. $s.=' /'.$k.' '.$v; 
  1494. $file=$font['file']; 
  1495. if($file) 
  1496. $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R'; 
  1497. $this->_out($s.'>>'); 
  1498. $this->_out('endobj'); 
  1499. // TrueType embedded SUBSETS or FULL 
  1500. else if ($type=='TTF') { 
  1501. $this->fonts[$k]['n']=$this->n+1; 
  1502. require_once($this->_getfontpath().'unifont/ttfonts.php'); 
  1503. $ttf = new TTFontFile(); 
  1504. $fontname = 'MPDFAA'.'+'.$font['name']; 
  1505. $subset = $font['subset']; 
  1506. unset($subset[0]); 
  1507. $ttfontstream = $ttf->makeSubset($font['ttffile'], $subset); 
  1508. $ttfontsize = strlen($ttfontstream); 
  1509. $fontstream = gzcompress($ttfontstream); 
  1510. $codeToGlyph = $ttf->codeToGlyph; 
  1511. unset($codeToGlyph[0]); 
  1512.  
  1513. // Type0 Font 
  1514. // A composite font - a font composed of other fonts, organized hierarchically 
  1515. $this->_newobj(); 
  1516. $this->_out('<</Type /Font'); 
  1517. $this->_out('/Subtype /Type0'); 
  1518. $this->_out('/BaseFont /'.$fontname.''); 
  1519. $this->_out('/Encoding /Identity-H');  
  1520. $this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]'); 
  1521. $this->_out('/ToUnicode '.($this->n + 2).' 0 R'); 
  1522. $this->_out('>>'); 
  1523. $this->_out('endobj'); 
  1524.  
  1525. // CIDFontType2 
  1526. // A CIDFont whose glyph descriptions are based on TrueType font technology 
  1527. $this->_newobj(); 
  1528. $this->_out('<</Type /Font'); 
  1529. $this->_out('/Subtype /CIDFontType2'); 
  1530. $this->_out('/BaseFont /'.$fontname.''); 
  1531. $this->_out('/CIDSystemInfo '.($this->n + 2).' 0 R');  
  1532. $this->_out('/FontDescriptor '.($this->n + 3).' 0 R'); 
  1533. if (isset($font['desc']['MissingWidth'])) { 
  1534. $this->_out('/DW '.$font['desc']['MissingWidth'].'');  
  1535.  
  1536. $this->_putTTfontwidths($font, $ttf->maxUni); 
  1537.  
  1538. $this->_out('/CIDToGIDMap '.($this->n + 4).' 0 R'); 
  1539. $this->_out('>>'); 
  1540. $this->_out('endobj'); 
  1541.  
  1542. // ToUnicode 
  1543. $this->_newobj(); 
  1544. $toUni = "/CIDInit /ProcSet findresource begin\n"; 
  1545. $toUni .= "12 dict begin\n"; 
  1546. $toUni .= "begincmap\n"; 
  1547. $toUni .= "/CIDSystemInfo\n"; 
  1548. $toUni .= "<</Registry (Adobe)\n"; 
  1549. $toUni .= "/Ordering (UCS)\n"; 
  1550. $toUni .= "/Supplement 0\n"; 
  1551. $toUni .= ">> def\n"; 
  1552. $toUni .= "/CMapName /Adobe-Identity-UCS def\n"; 
  1553. $toUni .= "/CMapType 2 def\n"; 
  1554. $toUni .= "1 begincodespacerange\n"; 
  1555. $toUni .= "<0000> <FFFF>\n"; 
  1556. $toUni .= "endcodespacerange\n"; 
  1557. $toUni .= "1 beginbfrange\n"; 
  1558. $toUni .= "<0000> <FFFF> <0000>\n"; 
  1559. $toUni .= "endbfrange\n"; 
  1560. $toUni .= "endcmap\n"; 
  1561. $toUni .= "CMapName currentdict /CMap defineresource pop\n"; 
  1562. $toUni .= "end\n"; 
  1563. $toUni .= "end"; 
  1564. $this->_out('<</Length '.(strlen($toUni)).'>>'); 
  1565. $this->_putstream($toUni); 
  1566. $this->_out('endobj'); 
  1567.  
  1568. // CIDSystemInfo dictionary 
  1569. $this->_newobj(); 
  1570. $this->_out('<</Registry (Adobe)');  
  1571. $this->_out('/Ordering (UCS)'); 
  1572. $this->_out('/Supplement 0'); 
  1573. $this->_out('>>'); 
  1574. $this->_out('endobj'); 
  1575.  
  1576. // Font descriptor 
  1577. $this->_newobj(); 
  1578. $this->_out('<</Type /FontDescriptor'); 
  1579. $this->_out('/FontName /'.$fontname); 
  1580. foreach($font['desc'] as $kd=>$v) { 
  1581. if ($kd == 'Flags') { $v = $v | 4; $v = $v & ~32; } // SYMBOLIC font flag 
  1582. $this->_out(' /'.$kd.' '.$v); 
  1583. $this->_out('/FontFile2 '.($this->n + 2).' 0 R'); 
  1584. $this->_out('>>'); 
  1585. $this->_out('endobj'); 
  1586.  
  1587. // Embed CIDToGIDMap 
  1588. // A specification of the mapping from CIDs to glyph indices 
  1589. $cidtogidmap = ''; 
  1590. $cidtogidmap = str_pad('', 256*256*2, "\x00"); 
  1591. foreach($codeToGlyph as $cc=>$glyph) { 
  1592. $cidtogidmap[$cc*2] = chr($glyph >> 8); 
  1593. $cidtogidmap[$cc*2 + 1] = chr($glyph & 0xFF); 
  1594. $cidtogidmap = gzcompress($cidtogidmap); 
  1595. $this->_newobj(); 
  1596. $this->_out('<</Length '.strlen($cidtogidmap).''); 
  1597. $this->_out('/Filter /FlateDecode'); 
  1598. $this->_out('>>'); 
  1599. $this->_putstream($cidtogidmap); 
  1600. $this->_out('endobj'); 
  1601.  
  1602. //Font file  
  1603. $this->_newobj(); 
  1604. $this->_out('<</Length '.strlen($fontstream)); 
  1605. $this->_out('/Filter /FlateDecode'); 
  1606. $this->_out('/Length1 '.$ttfontsize); 
  1607. $this->_out('>>'); 
  1608. $this->_putstream($fontstream); 
  1609. $this->_out('endobj'); 
  1610. unset($ttf); 
  1611. }  
  1612. else 
  1613. // Allow for additional types 
  1614. $this->fonts[$k]['n'] = $this->n+1; 
  1615. $mtd='_put'.strtolower($type); 
  1616. if(!method_exists($this, $mtd)) 
  1617. $this->Error('Unsupported font type: '.$type); 
  1618. $this->$mtd($font); 
  1619.  
  1620. function _putTTfontwidths(&$font, $maxUni) { 
  1621. if (file_exists($font['unifilename'].'.cw127.php')) { 
  1622. include($font['unifilename'].'.cw127.php') ; 
  1623. $startcid = 128; 
  1624. else { 
  1625. $rangeid = 0; 
  1626. $range = array(); 
  1627. $prevcid = -2; 
  1628. $prevwidth = -1; 
  1629. $interval = false; 
  1630. $startcid = 1; 
  1631. $cwlen = $maxUni + 1;  
  1632.  
  1633. // for each character 
  1634. for ($cid=$startcid; $cid<$cwlen; $cid++) { 
  1635. if ($cid==128 && (!file_exists($font['unifilename'].'.cw127.php'))) { 
  1636. if (is_writable(dirname($this->_getfontpath().'unifont/x'))) { 
  1637. $fh = fopen($font['unifilename'].'.cw127.php', "wb"); 
  1638. $cw127='<?php'."\n"; 
  1639. $cw127.='$rangeid='.$rangeid.";\n"; 
  1640. $cw127.='$prevcid='.$prevcid.";\n"; 
  1641. $cw127.='$prevwidth='.$prevwidth.";\n"; 
  1642. if ($interval) { $cw127.='$interval=true'.";\n"; } 
  1643. else { $cw127.='$interval=false'.";\n"; } 
  1644. $cw127.='$range='.var_export($range, true).";\n"; 
  1645. $cw127.="?>"; 
  1646. fwrite($fh, $cw127, strlen($cw127)); 
  1647. fclose($fh); 
  1648. if ($font['cw'][$cid*2] == "\00" && $font['cw'][$cid*2+1] == "\00") { continue; } 
  1649. $width = (ord($font['cw'][$cid*2]) << 8) + ord($font['cw'][$cid*2+1]); 
  1650. if ($width == 65535) { $width = 0; } 
  1651. if ($cid > 255 && (!isset($font['subset'][$cid]) || !$font['subset'][$cid])) { continue; } 
  1652. if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) { 
  1653. if ($cid == ($prevcid + 1)) { 
  1654. if ($width == $prevwidth) { 
  1655. if ($width == $range[$rangeid][0]) { 
  1656. $range[$rangeid][] = $width; 
  1657. else { 
  1658. array_pop($range[$rangeid]); 
  1659. // new range 
  1660. $rangeid = $prevcid; 
  1661. $range[$rangeid] = array(); 
  1662. $range[$rangeid][] = $prevwidth; 
  1663. $range[$rangeid][] = $width; 
  1664. $interval = true; 
  1665. $range[$rangeid]['interval'] = true; 
  1666. } else { 
  1667. if ($interval) { 
  1668. // new range 
  1669. $rangeid = $cid; 
  1670. $range[$rangeid] = array(); 
  1671. $range[$rangeid][] = $width; 
  1672. else { $range[$rangeid][] = $width; } 
  1673. $interval = false; 
  1674. } else { 
  1675. $rangeid = $cid; 
  1676. $range[$rangeid] = array(); 
  1677. $range[$rangeid][] = $width; 
  1678. $interval = false; 
  1679. $prevcid = $cid; 
  1680. $prevwidth = $width; 
  1681. $prevk = -1; 
  1682. $nextk = -1; 
  1683. $prevint = false; 
  1684. foreach ($range as $k => $ws) { 
  1685. $cws = count($ws); 
  1686. if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) { 
  1687. if (isset($range[$k]['interval'])) { unset($range[$k]['interval']); } 
  1688. $range[$prevk] = array_merge($range[$prevk], $range[$k]); 
  1689. unset($range[$k]); 
  1690. else { $prevk = $k; } 
  1691. $nextk = $k + $cws; 
  1692. if (isset($ws['interval'])) { 
  1693. if ($cws > 3) { $prevint = true; } 
  1694. else { $prevint = false; } 
  1695. unset($range[$k]['interval']); 
  1696. --$nextk; 
  1697. else { $prevint = false; } 
  1698. $w = ''; 
  1699. foreach ($range as $k => $ws) { 
  1700. if (count(array_count_values($ws)) == 1) { $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0]; } 
  1701. else { $w .= ' '.$k.' [ '.implode(' ', $ws).' ]' . "\n"; } 
  1702. $this->_out('/W ['.$w.' ]'); 
  1703.  
  1704. function _putimages() 
  1705. foreach(array_keys($this->images) as $file) 
  1706. $this->_putimage($this->images[$file]); 
  1707. unset($this->images[$file]['data']); 
  1708. unset($this->images[$file]['smask']); 
  1709.  
  1710. function _putimage(&$info) 
  1711. $this->_newobj(); 
  1712. $info['n'] = $this->n; 
  1713. $this->_out('<</Type /XObject'); 
  1714. $this->_out('/Subtype /Image'); 
  1715. $this->_out('/Width '.$info['w']); 
  1716. $this->_out('/Height '.$info['h']); 
  1717. if($info['cs']=='Indexed') 
  1718. $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); 
  1719. else 
  1720. $this->_out('/ColorSpace /'.$info['cs']); 
  1721. if($info['cs']=='DeviceCMYK') 
  1722. $this->_out('/Decode [1 0 1 0 1 0 1 0]'); 
  1723. $this->_out('/BitsPerComponent '.$info['bpc']); 
  1724. if(isset($info['f'])) 
  1725. $this->_out('/Filter /'.$info['f']); 
  1726. if(isset($info['dp'])) 
  1727. $this->_out('/DecodeParms <<'.$info['dp'].'>>'); 
  1728. if(isset($info['trns']) && is_array($info['trns'])) 
  1729. $trns = ''; 
  1730. for($i=0;$i<count($info['trns']);$i++) 
  1731. $trns .= $info['trns'][$i].' '.$info['trns'][$i].' '; 
  1732. $this->_out('/Mask ['.$trns.']'); 
  1733. if(isset($info['smask'])) 
  1734. $this->_out('/SMask '.($this->n+1).' 0 R'); 
  1735. $this->_out('/Length '.strlen($info['data']).'>>'); 
  1736. $this->_putstream($info['data']); 
  1737. $this->_out('endobj'); 
  1738. // Soft mask 
  1739. if(isset($info['smask'])) 
  1740. $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w']; 
  1741. $smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']); 
  1742. $this->_putimage($smask); 
  1743. // Palette 
  1744. if($info['cs']=='Indexed') 
  1745. $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; 
  1746. $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal']; 
  1747. $this->_newobj(); 
  1748. $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); 
  1749. $this->_putstream($pal); 
  1750. $this->_out('endobj'); 
  1751.  
  1752. function _putxobjectdict() 
  1753. foreach($this->images as $image) 
  1754. $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); 
  1755.  
  1756. function _putresourcedict() 
  1757. $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); 
  1758. $this->_out('/Font <<'); 
  1759. foreach($this->fonts as $font) { 
  1760. $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); 
  1761. $this->_out('>>'); 
  1762. $this->_out('/XObject <<'); 
  1763. $this->_putxobjectdict(); 
  1764. $this->_out('>>'); 
  1765.  
  1766. function _putresources() 
  1767. $this->_putfonts(); 
  1768. $this->_putimages(); 
  1769. // Resource dictionary 
  1770. $this->offsets[2] = strlen($this->buffer); 
  1771. $this->_out('2 0 obj'); 
  1772. $this->_out('<<'); 
  1773. $this->_putresourcedict(); 
  1774. $this->_out('>>'); 
  1775. $this->_out('endobj'); 
  1776.  
  1777. function _putinfo() 
  1778. $this->_out('/Producer '.$this->_textstring('tFPDF '.tFPDF_VERSION)); 
  1779. if(!empty($this->title)) 
  1780. $this->_out('/Title '.$this->_textstring($this->title)); 
  1781. if(!empty($this->subject)) 
  1782. $this->_out('/Subject '.$this->_textstring($this->subject)); 
  1783. if(!empty($this->author)) 
  1784. $this->_out('/Author '.$this->_textstring($this->author)); 
  1785. if(!empty($this->keywords)) 
  1786. $this->_out('/Keywords '.$this->_textstring($this->keywords)); 
  1787. if(!empty($this->creator)) 
  1788. $this->_out('/Creator '.$this->_textstring($this->creator)); 
  1789. $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); 
  1790.  
  1791. function _putcatalog() 
  1792. $this->_out('/Type /Catalog'); 
  1793. $this->_out('/Pages 1 0 R'); 
  1794. if($this->ZoomMode=='fullpage') 
  1795. $this->_out('/OpenAction [3 0 R /Fit]'); 
  1796. elseif($this->ZoomMode=='fullwidth') 
  1797. $this->_out('/OpenAction [3 0 R /FitH null]'); 
  1798. elseif($this->ZoomMode=='real') 
  1799. $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); 
  1800. elseif(!is_string($this->ZoomMode)) 
  1801. $this->_out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2F', $this->ZoomMode/100).']'); 
  1802. if($this->LayoutMode=='single') 
  1803. $this->_out('/PageLayout /SinglePage'); 
  1804. elseif($this->LayoutMode=='continuous') 
  1805. $this->_out('/PageLayout /OneColumn'); 
  1806. elseif($this->LayoutMode=='two') 
  1807. $this->_out('/PageLayout /TwoColumnLeft'); 
  1808.  
  1809. function _putheader() 
  1810. $this->_out('%PDF-'.$this->PDFVersion); 
  1811.  
  1812. function _puttrailer() 
  1813. $this->_out('/Size '.($this->n+1)); 
  1814. $this->_out('/Root '.$this->n.' 0 R'); 
  1815. $this->_out('/Info '.($this->n-1).' 0 R'); 
  1816.  
  1817. function _enddoc() 
  1818. $this->_putheader(); 
  1819. $this->_putpages(); 
  1820. $this->_putresources(); 
  1821. // Info 
  1822. $this->_newobj(); 
  1823. $this->_out('<<'); 
  1824. $this->_putinfo(); 
  1825. $this->_out('>>'); 
  1826. $this->_out('endobj'); 
  1827. // Catalog 
  1828. $this->_newobj(); 
  1829. $this->_out('<<'); 
  1830. $this->_putcatalog(); 
  1831. $this->_out('>>'); 
  1832. $this->_out('endobj'); 
  1833. // Cross-ref 
  1834. $o = strlen($this->buffer); 
  1835. $this->_out('xref'); 
  1836. $this->_out('0 '.($this->n+1)); 
  1837. $this->_out('0000000000 65535 f '); 
  1838. for($i=1;$i<=$this->n;$i++) 
  1839. $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i])); 
  1840. // Trailer 
  1841. $this->_out('trailer'); 
  1842. $this->_out('<<'); 
  1843. $this->_puttrailer(); 
  1844. $this->_out('>>'); 
  1845. $this->_out('startxref'); 
  1846. $this->_out($o); 
  1847. $this->_out('%%EOF'); 
  1848. $this->state = 3; 
  1849.  
  1850. // ********* NEW FUNCTIONS ********* 
  1851. // Converts UTF-8 strings to UTF16-BE. 
  1852. function UTF8ToUTF16BE($str, $setbom=true) { 
  1853. $outstr = ""; 
  1854. if ($setbom) { 
  1855. $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM) 
  1856. $outstr .= mb_convert_encoding($str, 'UTF-16BE', 'UTF-8'); 
  1857. return $outstr; 
  1858.  
  1859. // Converts UTF-8 strings to codepoints array 
  1860. function UTF8StringToArray($str) { 
  1861. $out = array(); 
  1862. $len = strlen($str); 
  1863. for ($i = 0; $i < $len; $i++) { 
  1864. $uni = -1; 
  1865. $h = ord($str[$i]); 
  1866. if ( $h <= 0x7F ) 
  1867. $uni = $h; 
  1868. elseif ( $h >= 0xC2 ) { 
  1869. if ( ($h <= 0xDF) && ($i < $len -1) ) 
  1870. $uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F); 
  1871. elseif ( ($h <= 0xEF) && ($i < $len -2) ) 
  1872. $uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 
  1873. | (ord($str[++$i]) & 0x3F); 
  1874. elseif ( ($h <= 0xF4) && ($i < $len -3) ) 
  1875. $uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 
  1876. | (ord($str[++$i]) & 0x3F) << 6 
  1877. | (ord($str[++$i]) & 0x3F); 
  1878. if ($uni >= 0) { 
  1879. $out[] = $uni; 
  1880. return $out; 
  1881.  
  1882.  
  1883. // End of class