loreng

[SETTING] FPDF

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