A Qcodo based CMS/ecommerce framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1732 lines
44 KiB

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