home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / fpdf.php < prev    next >
Encoding:
PHP Script  |  2003-11-20  |  76.8 KB  |  2,491 lines

  1. <?php
  2. /* $Id: fpdf.php,v 2.1 2003/11/20 16:31:51 garvinhicking Exp $ */
  3. // vim: expandtab sw=4 ts=4 sts=4:
  4.  
  5. /****************************************************************************
  6. * Software : FPDF                                                           *
  7. * Version :  1.51                                                           *
  8. * Date :     2002/08/03                                                     *
  9. * Author :   Olivier PLATHEY                                                *
  10. * Website :  http://www.fpdf.org                                            *
  11. * Licence :  Freeware                                                       *
  12. *                                                                           *
  13. * You are entitled to modify this soft as you want to.                      *
  14. ****************************************************************************/
  15.  
  16.  
  17. $FPDF_version = (string) '1.51';
  18.  
  19.  
  20. /**
  21.  * The FPDF class
  22.  */
  23. class FPDF
  24. {
  25.     /**
  26.      * Defines private properties
  27.      */
  28.     var $page;               // current page number
  29.     var $n;                  // current object number
  30.     var $offsets;            // array of object offsets
  31.     var $buffer;             // buffer holding in-memory PDF
  32.     var $pages;              // array containing pages
  33.     var $state;              // current document state
  34.     var $compress;           // compression flag
  35.     var $DefOrientation;     // default orientation
  36.     var $CurOrientation;     // current orientation
  37.     var $OrientationChanges; // array indicating orientation changes
  38.     var $fwPt, $fhPt;        // dimensions of page format in points
  39.     var $fw, $fh;            // dimensions of page format in user unit
  40.     var $wPt, $hPt;          // current dimensions of page in points
  41.     var $k;                  // scale factor (number of points in user unit)
  42.     var $w, $h;              // current dimensions of page in user unit
  43.     var $lMargin;            // left margin
  44.     var $tMargin;            // top margin
  45.     var $rMargin;            // right margin
  46.     var $bMargin;            // page break margin
  47.     var $cMargin;            // cell margin
  48.     var $x, $y;              // current position in user unit for cell positionning
  49.     var $lasth;              // height of last cell printed
  50.     var $LineWidth;          // line width in user unit
  51.     var $CoreFonts;          // array of standard font names
  52.     var $fonts;              // array of used fonts
  53.     var $FontFiles;          // array of font files
  54.     var $diffs;              // array of encoding differences
  55.     var $images;             // array of used images
  56.     var $PageLinks;          // array of links in pages
  57.     var $links;              // array of internal links
  58.     var $FontFamily;         // current font family
  59.     var $FontStyle;          // current font style
  60.     var $CurrentFont;        // current font info
  61.     var $FontSizePt;         // current font size in points
  62.     var $FontSize;           // current font size in user unit
  63.     var $DrawColor;          // commands for drawing color
  64.     var $FillColor;          // commands for filling color
  65.     var $TextColor;          // commands for text color
  66.     var $ColorFlag;          // indicates whether fill and text colors are different
  67.     var $ws;                 // word spacing
  68.     var $underline;          // whether underline is current state or not
  69.     var $AutoPageBreak;      // automatic page breaking
  70.     var $PageBreakTrigger;   // threshold used to trigger page breaks
  71.     var $InFooter;           // flag set when processing footer
  72.     var $ZoomMode;           // zoom display mode
  73.     var $LayoutMode;         // layout display mode
  74.     var $title;              // title
  75.     var $subject;            // subject
  76.     var $author;             // author
  77.     var $keywords;           // keywords
  78.     var $creator;            // creator
  79.     var $AliasNbPages;       // alias for total number of pages
  80.  
  81.  
  82.  
  83.     /**************************************************************************
  84.     *                                                                         *
  85.     *      Public methods below are used by some private ones. Then they      *
  86.     *      are placed at the top of the class.                                *
  87.     *                                                                         *
  88.     **************************************************************************/
  89.  
  90.     /**
  91.      * Gets the width of a string in the current font
  92.      *
  93.      * @param   string   The string to check
  94.      *
  95.      * @return  double  The string width
  96.      *
  97.      * @access  public
  98.      */
  99.     function GetStringWidth($s)
  100.     {
  101.         $s     = (string) $s;
  102.         // loic1: PHP3 compatibility
  103.         // $cw    = &$this->CurrentFont['cw'];
  104.         $w     = 0;
  105.         $l     = strlen($s);
  106.         for ($i = 0; $i < $l; $i++) {
  107.             // $w += $cw[$s[$i]];
  108.             $w += $this->CurrentFont['cw'][$s[$i]];
  109.         } // end for
  110.  
  111.         return $w * $this->FontSize / 1000;
  112.     } // end of the "GetStringWidth()" method
  113.  
  114.  
  115.     /**
  116.      * Displays an error message then exists
  117.      *
  118.      * @param  string  The error message
  119.      *
  120.      * @access public
  121.      */
  122.     function Error($msg)
  123.     {
  124.         die('<b>FPDF error: </b>' . $msg);
  125.     } // end of the "Error()" method
  126.  
  127.  
  128.  
  129.     /**************************************************************************
  130.     *                                                                         *
  131.     *                             Private methods                             *
  132.     *                                                                         *
  133.     **************************************************************************/
  134.  
  135.     /**
  136.      * Adds a line to the document
  137.      *
  138.      * @param   string   The string to add
  139.      *
  140.      * @access  private
  141.      */
  142.     function _out($s)
  143.     {
  144.         if ($this->state == 2) {
  145.             $this->pages[$this->page] .= $s . "\n";
  146.         } else {
  147.             $this->buffer             .= $s . "\n";
  148.         }
  149.     } // end of the "_out()" method
  150.  
  151.  
  152.     /**
  153.      * Starts a new object
  154.      *
  155.      * @access private
  156.      */
  157.     function _newobj()
  158.     {
  159.         $this->n++;
  160.         $this->offsets[$this->n] = strlen($this->buffer);
  161.         $this->_out($this->n . ' 0 obj');
  162.     } // end of the "_newobj()" method
  163.  
  164.  
  165.     /**
  166.      * Adds a "\" before "\", "(" and ")" characters
  167.      *
  168.      * @param   string   The string to slash
  169.      *
  170.      * @return  integer  The slashed string
  171.      *
  172.      * @access  private
  173.      */
  174.     function _escape($s)
  175.     {
  176.         return str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $s)));
  177.     } // end of the "_escape()" method
  178.  
  179.  
  180.     /**
  181.      * Formats a text stringrs
  182.      *
  183.      * @param   string   The string to format
  184.      *
  185.      * @return  integer  The formatted string
  186.      *
  187.      * @access  private
  188.      *
  189.      * @see     _escape()
  190.      */
  191.     function _textstring($s)
  192.     {
  193.         return '(' . $this->_escape($s) . ')';
  194.     } // end of the "_textstring()" method
  195.  
  196.  
  197.     /**
  198.      * Outputs a stream
  199.      *
  200.      * @param   string   The stream to ouput
  201.      *
  202.      * @access  private
  203.      *
  204.      * @see     _out()
  205.      */
  206.     function _putstream($s)
  207.     {
  208.         $this->_out('stream');
  209.         $this->_out($s);
  210.         $this->_out('endstream');
  211.     } // end of the "_putstream()" method
  212.  
  213.  
  214.     /**
  215.      * Starts document
  216.      *
  217.      * @access private
  218.      */
  219.     function _begindoc()
  220.     {
  221.         $this->state = 1;
  222.         $this->_out('%PDF-1.3');
  223.     } // end of the "_begindoc()" method
  224.  
  225.  
  226.     /**
  227.      * Puts pages
  228.      *
  229.      * @access private
  230.      */
  231.     function _putpages()
  232.     {
  233.         $nb = $this->page;
  234.  
  235.         if (!empty($this->AliasNbPages)) {
  236.             // Replaces number of pages
  237.             for ($n = 1; $n <= $nb; $n++) {
  238.                 $this->pages[$n] = str_replace($this->AliasNbPages, $nb, $this->pages[$n]);
  239.             }
  240.         }
  241.         if ($this->DefOrientation == 'P') {
  242.             $wPt = $this->fwPt;
  243.             $hPt = $this->fhPt;
  244.         } else {
  245.             $wPt = $this->fhPt;
  246.             $hPt = $this->fwPt;
  247.         }
  248.         $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
  249.  
  250.         for ($n=1; $n <= $nb; $n++) {
  251.             // Page
  252.             $this->_newobj();
  253.             $this->_out('<</Type /Page');
  254.             $this->_out('/Parent 1 0 R');
  255.             if (isset($this->OrientationChanges[$n])) {
  256.                 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $hPt, $wPt));
  257.             }
  258.             $this->_out('/Resources 2 0 R');
  259.             if (isset($this->PageLinks[$n])) {
  260.                 // Links
  261.                 $annots         = '/Annots [';
  262.                 reset($this->PageLinks[$n]);
  263.                 while (list(, $pl) = each($this->PageLinks[$n])) {
  264.                     $rect       = sprintf('%.2f %.2f %.2f %.2f', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]);
  265.                     $annots     .= '<</Type /Annot /Subtype /Link /Rect [' . $rect . '] /Border [0 0 0] ';
  266.                     if (is_string($pl[4])) {
  267.                         $annots .= '/A <</S /URI /URI ' . $this->_textstring($pl[4]) . '>>>>';
  268.                     }
  269.                     else {
  270.                         $l      = $this->links[$pl[4]];
  271.                         $h      = isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt;
  272.                         $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>', 1 + 2 * $l[0], $h - $l[1] * $this->k);
  273.                     }
  274.                 } // end while
  275.                 $this->_out($annots . ']');
  276.             } // end if
  277.             $this->_out('/Contents ' . ($this->n+1).' 0 R>>');
  278.             $this->_out('endobj');
  279.  
  280.             // Page content
  281.             $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
  282.             $this->_newobj();
  283.             $this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>');
  284.             $this->_putstream($p);
  285.             $this->_out('endobj');
  286.         } // end for
  287.  
  288.         // Pages root
  289.         $this->offsets[1]=strlen($this->buffer);
  290.         $this->_out('1 0 obj');
  291.         $this->_out('<</Type /Pages');
  292.         $kids     = '/Kids [';
  293.         for ($i = 0; $i < $nb; $i++) {
  294.             $kids .= (3 + 2 * $i) . ' 0 R ';
  295.         }
  296.         $this->_out($kids . ']');
  297.         $this->_out('/Count ' . $nb);
  298.         $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $wPt, $hPt));
  299.         $this->_out('>>');
  300.         $this->_out('endobj');
  301.     } // end of the "_putpages()" method
  302.  
  303.  
  304.     /**
  305.      * Puts font faces
  306.      *
  307.      * @access private
  308.      */
  309.     function _putfonts()
  310.     {
  311.         $nf = $this->n;
  312.  
  313.         foreach($this->diffs AS $diff) {
  314.             // Encodings
  315.             $this->_newobj();
  316.             $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' . $diff . ']>>');
  317.             $this->_out('endobj');
  318.         } // end while
  319.  
  320.         $mqr = get_magic_quotes_runtime();
  321.         set_magic_quotes_runtime(0);
  322.  
  323.         foreach($this->FontFiles AS $file => $info) {
  324.             // Font file embedding
  325.             $this->_newobj();
  326.             $this->FontFiles[$file]['n'] = $this->n;
  327.             if (isset($GLOBALS['FPDF_font_path'])) {
  328.                 $file = $GLOBALS['FPDF_font_path'] . $file;
  329.             }
  330.             $size     = filesize($file);
  331.             if (!$size) {
  332.                 $this->Error('Font file not found');
  333.             }
  334.             $this->_out('<</Length ' . $size);
  335.             if (substr($file, -2) == '.z') {
  336.                 $this->_out('/Filter /FlateDecode');
  337.             }
  338.             $this->_out('/Length1 ' . $info['length1']);
  339.             if (isset($info['length2'])) {
  340.                 $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0');
  341.             }
  342.             $this->_out('>>');
  343.             $f = fopen($file, 'rb');
  344.             $this->_putstream(fread($f, $size));
  345.             fclose($f);
  346.             $this->_out('endobj');
  347.         } // end while
  348.         set_magic_quotes_runtime($mqr);
  349.  
  350.         foreach($this->fonts AS $k => $font) {
  351.             // Font objects
  352.             $this->_newobj();
  353.             $this->fonts[$k]['n'] = $this->n;
  354.             $name                 = $font['name'];
  355.             $this->_out('<</Type /Font');
  356.             $this->_out('/BaseFont /' . $name);
  357.             if ($font['type'] == 'core')  {
  358.                 // Standard font
  359.                 $this->_out('/Subtype /Type1');
  360.                 if ($name != 'Symbol' && $name != 'ZapfDingbats') {
  361.                     $this->_out('/Encoding /WinAnsiEncoding');
  362.                 }
  363.             }
  364.             else {
  365.                 // Additional font
  366.                 $this->_out('/Subtype /' . $font['type']);
  367.                 $this->_out('/FirstChar 32');
  368.                 $this->_out('/LastChar 255');
  369.                 $this->_out('/Widths ' . ($this->n + 1) . ' 0 R');
  370.                 $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R');
  371.                 if ($font['enc']) {
  372.                     if (isset($font['diff'])) {
  373.                         $this->_out('/Encoding ' . ($nf + $font['diff']) . ' 0 R');
  374.                     } else {
  375.                         $this->_out('/Encoding /WinAnsiEncoding');
  376.                     }
  377.                 }
  378.             } // end if... else...
  379.             $this->_out('>>');
  380.             $this->_out('endobj');
  381.             if ($font['type'] != 'core')  {
  382.                 // Widths
  383.                 $this->_newobj();
  384.                 $s     = '[';
  385.                 for ($i = 32; $i <= 255; $i++) {
  386.                     $s .= $font['cw'][chr($i)] . ' ';
  387.                 }
  388.                 $this->_out($s . ']');
  389.                 $this->_out('endobj');
  390.                 // Descriptor
  391.                 $this->_newobj();
  392.                 $s     = '<</Type /FontDescriptor /FontName /' . $name;
  393.                 foreach($font['desc'] AS $k => $v) {
  394.                     $s .= ' /' . $k . ' ' . $v;
  395.                 }
  396.                 $file = $font['file'];
  397.                 if ($file) {
  398.                     $s .= ' /FontFile' . ($font['type'] == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$file]['n'] . ' 0 R';
  399.                 }
  400.                 $this->_out($s . '>>');
  401.                 $this->_out('endobj');
  402.             } // end if
  403.         } // end while
  404.     } // end of the "_putfonts()" method
  405.  
  406.  
  407.     /**
  408.      * Puts images
  409.      *
  410.      * @access private
  411.      */
  412.     function _putimages()
  413.     {
  414.         $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
  415.  
  416.         foreach($this->images AS $file => $info) {
  417.             $this->_newobj();
  418.             $this->images[$file]['n'] = $this->n;
  419.             $this->_out('<</Type /XObject');
  420.             $this->_out('/Subtype /Image');
  421.             $this->_out('/Width ' . $info['w']);
  422.             $this->_out('/Height ' . $info['h']);
  423.             if ($info['cs'] == 'Indexed') {
  424.                 $this->_out('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal'])/ 3 - 1) . ' ' . ($this->n + 1) . ' 0 R]');
  425.             }
  426.             else {
  427.                 $this->_out('/ColorSpace /' . $info['cs']);
  428.                 if ($info['cs'] == 'DeviceCMYK') {
  429.                     $this->_out('/Decode [1 0 1 0 1 0 1 0]');
  430.                 }
  431.             } // end if... else...
  432.             $this->_out('/BitsPerComponent ' . $info['bpc']);
  433.             $this->_out('/Filter /' . $info['f']);
  434.             if (isset($info['parms'])) {
  435.                 $this->_out($info['parms']);
  436.             }
  437.             if (isset($info['trns']) && is_array($info['trns'])) {
  438.                 $trns     = '';
  439.                 $trns_cnt = count($info['trns']);
  440.                 for ($i = 0; $i < $trns_cnt; $i++) {
  441.                     $trns .= $info['trns'][$i] . ' ' . $info['trns'][$i] . ' ';
  442.                 }
  443.                 $this->_out('/Mask [' . $trns . ']');
  444.             } // end if
  445.             $this->_out('/Length ' . strlen($info['data']) . '>>');
  446.             $this->_putstream($info['data']);
  447.             $this->_out('endobj');
  448.  
  449.             // Palette
  450.             if ($info['cs'] == 'Indexed') {
  451.                 $this->_newobj();
  452.                 $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal'];
  453.                 $this->_out('<<' . $filter . '/Length ' . strlen($pal) . '>>');
  454.                 $this->_putstream($pal);
  455.                 $this->_out('endobj');
  456.             } // end if
  457.         } // end while
  458.     } // end of the "_putimages()" method
  459.  
  460.  
  461.     /**
  462.      * Puts resources
  463.      *
  464.      * @access private
  465.      */
  466.     function _putresources()
  467.     {
  468.         $this->_putfonts();
  469.         $this->_putimages();
  470.         // Resource dictionary
  471.         $this->offsets[2] = strlen($this->buffer);
  472.         $this->_out('2 0 obj');
  473.         $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
  474.         $this->_out('/Font <<');
  475.         foreach($this->fonts AS $font) {
  476.             $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
  477.         }
  478.         $this->_out('>>');
  479.         if (count($this->images)) {
  480.             $this->_out('/XObject <<');
  481.             foreach($this->images AS $image) {
  482.                 $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
  483.             }
  484.             $this->_out('>>');
  485.         }
  486.         $this->_out('>>');
  487.         $this->_out('endobj');
  488.     } // end of the "_putresources()" method
  489.  
  490.  
  491.     /**
  492.      * Puts document informations
  493.      *
  494.      * @access private
  495.      */
  496.     function _putinfo()
  497.     {
  498.         // loic1: PHP3 compatibility
  499.         // $this->_out('/Producer ' . $this->_textstring('FPDF ' . FPDF_VERSION));
  500.         $this->_out('/Producer ' . $this->_textstring('FPDF ' . $GLOBALS['FPDF_version']));
  501.         if (!empty($this->title)) {
  502.             $this->_out('/Title ' . $this->_textstring($this->title));
  503.         }
  504.         if (!empty($this->subject)) {
  505.             $this->_out('/Subject ' . $this->_textstring($this->subject));
  506.         }
  507.         if (!empty($this->author)) {
  508.             $this->_out('/Author ' . $this->_textstring($this->author));
  509.         }
  510.         if (!empty($this->keywords)) {
  511.             $this->_out('/Keywords ' . $this->_textstring($this->keywords));
  512.         }
  513.         if (!empty($this->creator)) {
  514.             $this->_out('/Creator ' . $this->_textstring($this->creator));
  515.         }
  516.         $this->_out('/CreationDate ' . $this->_textstring('D:' . date('YmdHis')));
  517.     } // end of the "_putinfo()" method
  518.  
  519.  
  520.     /**
  521.      * Puts catalog informations
  522.      *
  523.      * @access private
  524.      */
  525.     function _putcatalog()
  526.     {
  527.         $this->_out('/Type /Catalog');
  528.         $this->_out('/Pages 1 0 R');
  529.         if ($this->ZoomMode == 'fullpage') {
  530.             $this->_out('/OpenAction [3 0 R /Fit]');
  531.         } else if ($this->ZoomMode == 'fullwidth') {
  532.             $this->_out('/OpenAction [3 0 R /FitH null]');
  533.         } else if ($this->ZoomMode == 'real') {
  534.             $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
  535.         } else if (!is_string($this->ZoomMode)) {
  536.             $this->_out('/OpenAction [3 0 R /XYZ null null ' . ($this->ZoomMode / 100) . ']');
  537.         }
  538.         if ($this->LayoutMode == 'single') {
  539.             $this->_out('/PageLayout /SinglePage');
  540.         } else if ($this->LayoutMode == 'continuous') {
  541.             $this->_out('/PageLayout /OneColumn');
  542.         } else if ($this->LayoutMode == 'two') {
  543.             $this->_out('/PageLayout /TwoColumnLeft');
  544.         }
  545.     } // end of the "_putcatalog()" method
  546.  
  547.  
  548.     /**
  549.      * Puts trailer
  550.      *
  551.      * @access private
  552.      */
  553.     function _puttrailer()
  554.     {
  555.         $this->_out('/Size ' . ($this->n + 1));
  556.         $this->_out('/Root ' . $this->n . ' 0 R');
  557.         $this->_out('/Info ' . ($this->n - 1) . ' 0 R');
  558.     } // end of the "_puttrailer()" method
  559.  
  560.  
  561.     /**
  562.      * Terminates document
  563.      *
  564.      * @access private
  565.      */
  566.     function _enddoc()
  567.     {
  568.         $this->_putpages();
  569.         $this->_putresources();
  570.  
  571.         // Info
  572.         $this->_newobj();
  573.         $this->_out('<<');
  574.         $this->_putinfo();
  575.         $this->_out('>>');
  576.         $this->_out('endobj');
  577.  
  578.         // Catalog
  579.         $this->_newobj();
  580.         $this->_out('<<');
  581.         $this->_putcatalog();
  582.         $this->_out('>>');
  583.         $this->_out('endobj');
  584.  
  585.         // Cross-ref
  586.         $o = strlen($this->buffer);
  587.         $this->_out('xref');
  588.         $this->_out('0 ' . ($this->n + 1));
  589.         $this->_out('0000000000 65535 f ');
  590.         for ($i = 1; $i <= $this->n; $i++) {
  591.             $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
  592.         }
  593.  
  594.         // Trailer
  595.         $this->_out('trailer');
  596.         $this->_out('<<');
  597.         $this->_puttrailer();
  598.         $this->_out('>>');
  599.         $this->_out('startxref');
  600.         $this->_out($o);
  601.         $this->_out('%%EOF');
  602.         $this->state=3;
  603.     } // end of the "_enddoc()" method
  604.  
  605.  
  606.     /**
  607.      * Starts a new page
  608.      *
  609.      * @param  string   The page orientation
  610.      *
  611.      * @access private
  612.      */
  613.     function _beginpage($orientation)
  614.     {
  615.         $this->page++;
  616.         $this->pages[$this->page] = '';
  617.         $this->state              = 2;
  618.         $this->x                  = $this->lMargin;
  619.         $this->y                  = $this->tMargin;
  620.         $this->lasth              = 0;
  621.         $this->FontFamily         = '';
  622.  
  623.         // Page orientation
  624.         if (!$orientation) {
  625.             $orientation = $this->DefOrientation;
  626.         } else {
  627.             $orientation = strtoupper($orientation[0]);
  628.         }
  629.         if ($orientation != $this->DefOrientation) {
  630.             $this->OrientationChanges[$this->page] = TRUE;
  631.         }
  632.         if ($orientation != $this->CurOrientation) {
  633.             // Changes orientation
  634.             if ($orientation == 'P') {
  635.                 $this->wPt = $this->fwPt;
  636.                 $this->hPt = $this->fhPt;
  637.                 $this->w   = $this->fw;
  638.                 $this->h   = $this->fh;
  639.             }
  640.             else {
  641.                 $this->wPt = $this->fhPt;
  642.                 $this->hPt = $this->fwPt;
  643.                 $this->w   = $this->fh;
  644.                 $this->h   = $this->fw;
  645.             }
  646.             $this->PageBreakTrigger = $this->h - $this->bMargin;
  647.             $this->CurOrientation   = $orientation;
  648.         } // end if
  649.     } // end of the "_beginpage()" method
  650.  
  651.  
  652.     /**
  653.      * Ends page contents
  654.      *
  655.      * @access private
  656.      */
  657.     function _endpage()
  658.     {
  659.         $this->state=1;
  660.     } // end of the "_endpage()" method
  661.  
  662.  
  663.     /**
  664.      * Underlines text
  665.      *
  666.      * @param   double  The x position
  667.      * @param   double  The y position
  668.      * @param   string  The text
  669.      *
  670.      * @return  string  The underlined text
  671.      *
  672.      * @access  private
  673.      */
  674.     function _dounderline($x,$y,$txt)
  675.     {
  676.         $up = $this->CurrentFont['up'];
  677.         $ut = $this->CurrentFont['ut'];
  678.         $w  = $this->GetStringWidth($txt) + $this->ws * substr_count($txt, ' ');
  679.  
  680.         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);
  681.     } // end of the "_dounderline()" method
  682.  
  683.  
  684.     /**
  685.      * Extracts info from a JPEG file
  686.      *
  687.      * @param   string  The file name and path
  688.      *
  689.      * @return  array   The images informations
  690.      *
  691.      * @access  private
  692.      */
  693.     function _parsejpg($file)
  694.     {
  695.         $a = GetImageSize($file);
  696.         if (!$a) {
  697.             $this->Error('Missing or incorrect image file: ' . $file);
  698.         }
  699.         if ($a[2] != 2) {
  700.             $this->Error('Not a JPEG file: ' . $file);
  701.         }
  702.         if (!isset($a['channels']) || $a['channels'] == 3) {
  703.             $colspace = 'DeviceRGB';
  704.         }
  705.         else if($a['channels'] == 4) {
  706.             $colspace = 'DeviceCMYK';
  707.         }
  708.         else {
  709.             $colspace = 'DeviceGray';
  710.         }
  711.         $bpc = isset($a['bits']) ? $a['bits'] : 8;
  712.  
  713.         // Reads whole file
  714.         $f    = fopen($file, 'rb');
  715.         $data = fread($f, filesize($file));
  716.         fclose($f);
  717.  
  718.         return array('w'    => $a[0],
  719.                      'h'    => $a[1],
  720.                      'cs'   => $colspace,
  721.                      'bpc'  => $bpc,
  722.                      'f'    => 'DCTDecode',
  723.                      'data' => $data);
  724.     } // end of the "_parsejpg()" method
  725.  
  726.  
  727.     /**
  728.      * Reads a 4-byte integer from a file
  729.      *
  730.      * @param   string   The file name and path
  731.      *
  732.      * @return  integer  The 4-byte integer
  733.      *
  734.      * @access  private
  735.      *
  736.      * @see     _parsepng()
  737.      */
  738.     function _freadint($f)
  739.     {
  740.         $i = ord(fread($f, 1)) << 24;
  741.         $i += ord(fread($f, 1)) << 16;
  742.         $i += ord(fread($f, 1)) << 8;
  743.         $i += ord(fread($f, 1));
  744.  
  745.         return $i;
  746.     } // end of the "_freadint()" method
  747.  
  748.  
  749.     /**
  750.      * Extracts info from a PNG file
  751.      *
  752.      * @param   string  The file name and path
  753.      *
  754.      * @return  array   The images informations
  755.      *
  756.      * @access  private
  757.      *
  758.      * @see     _freadint()
  759.      */
  760.     function _parsepng($file)
  761.     {
  762.         $f = fopen($file, 'rb');
  763.         if (!$f) {
  764.             $this->Error('Can\'t open image file: ' . $file);
  765.         }
  766.  
  767.         // Checks signature
  768.         if (fread($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) {
  769.             $this->Error('Not a PNG file: ' . $file);
  770.         }
  771.  
  772.         // Reads header chunk
  773.         fread($f,4);
  774.         if (fread($f, 4) != 'IHDR') {
  775.             $this->Error('Incorrect PNG file: ' . $file);
  776.         }
  777.         $w   = $this->_freadint($f);
  778.         $h   = $this->_freadint($f);
  779.         $bpc = ord(fread($f,1));
  780.         if ($bpc > 8) {
  781.             $this->Error('16-bit depth not supported: ' . $file);
  782.         }
  783.         $ct  = ord(fread($f, 1));
  784.         if ($ct == 0) {
  785.             $colspace = 'DeviceGray';
  786.         }
  787.         else if ($ct == 2) {
  788.             $colspace = 'DeviceRGB';
  789.         }
  790.         else if ($ct == 3) {
  791.             $colspace = 'Indexed';
  792.         }
  793.         else {
  794.             $this->Error('Alpha channel not supported: ' . $file);
  795.         }
  796.         if (ord(fread($f, 1)) != 0) {
  797.             $this->Error('Unknown compression method: ' . $file);
  798.         }
  799.         if (ord(fread($f, 1)) != 0) {
  800.             $this->Error('Unknown filter method: ' . $file);
  801.         }
  802.         if (ord(fread($f, 1)) != 0) {
  803.             $this->Error('Interlacing not supported: ' . $file);
  804.         }
  805.         fread($f, 4);
  806.         $parms = '/DecodeParms <</Predictor 15 /Colors ' . ($ct == 2 ? 3 : 1)
  807.                . ' /BitsPerComponent ' . $bpc
  808.                . ' /Columns ' . $w . '>>';
  809.  
  810.         // Scans chunks looking for palette, transparency and image data
  811.         $pal  = '';
  812.         $trns = '';
  813.         $data = '';
  814.         do {
  815.             $n    = $this->_freadint($f);
  816.             $type = fread($f, 4);
  817.             if ($type == 'PLTE') {
  818.                 // Reads palette
  819.                 $pal = fread($f, $n);
  820.                 fread($f, 4);
  821.             }
  822.             else if ($type == 'tRNS') {
  823.                 // Reads transparency info
  824.                 $t            = fread($f, $n);
  825.                 if ($ct == 0) {
  826.                     $trns     = array(ord(substr($t, 1, 1)));
  827.                 }
  828.                 else if ($ct == 2) {
  829.                     $trns     = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1)));
  830.                 }
  831.                 else {
  832.                     $pos      = strpos(' ' . $t, chr(0));
  833.                     if ($pos) {
  834.                         $trns = array($pos - 1);
  835.                     }
  836.                     fread($f,4);
  837.                 } // end if... else if... else
  838.             }
  839.             else if ($type == 'IDAT') {
  840.                 // Reads image data block
  841.                 $data .= fread($f, $n);
  842.                 fread($f, 4);
  843.             }
  844.             else if ($type == 'IEND') {
  845.                 break;
  846.             }
  847.             else {
  848.                 fread($f, $n + 4);
  849.             } // end if... else if... else
  850.         } while($n); // end do
  851.  
  852.         if ($colspace == 'Indexed' && empty($pal)) {
  853.             $this->Error('Missing palette in ' . $file);
  854.         }
  855.         fclose($f);
  856.  
  857.         return array('w'     => $w,
  858.                      'h'     => $h,
  859.                      'cs'    => $colspace,
  860.                      'bpc'   => $bpc,
  861.                      'f'     => 'FlateDecode',
  862.                      'parms' => $parms,
  863.                      'pal'   => $pal,
  864.                      'trns'  => $trns,
  865.                      'data'  => $data);
  866.     } // end of the "_parsepng()" method
  867.  
  868.  
  869.  
  870.     /**************************************************************************
  871.     *                                                                         *
  872.     *                             Public methods                              *
  873.     *                                                                         *
  874.     **************************************************************************/
  875.  
  876.     /**
  877.      * Sets auto page break mode and triggering margin
  878.      *
  879.      * @param  string  The auto page break mode
  880.      * @param  double  Maximum size till the bottom of the page to start adding
  881.      *                 page break
  882.      *
  883.      * @access public
  884.      */
  885.     function SetAutoPageBreak($auto, $margin = 0)
  886.     {
  887.         $this->AutoPageBreak    = $auto;
  888.         $this->bMargin          = $margin;
  889.         $this->PageBreakTrigger = $this->h - $margin;
  890.     } // end of the "SetAutoPageBreak()" method
  891.  
  892.  
  893.     /**
  894.      * Sets display mode in viewer
  895.      *
  896.      * @param  mixed   The zoom mode (fullpage, fullwidth, real, default,
  897.      *                 zoom or an zoom factor -real-)
  898.      * @param  string  The layout mode (single, continuous, two or default)
  899.      *
  900.      * @access public
  901.      */
  902.     function SetDisplayMode($zoom = 'default', $layout = 'continuous')
  903.     {
  904.         if (is_string($zoom)) {
  905.             $zoom = strtolower($zoom);
  906.         }
  907.         $layout   = strtolower($layout);
  908.  
  909.         // Zoom mode
  910.         if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real' || $zoom == 'default'
  911.             || !is_string($zoom)) {
  912.             $this->ZoomMode = $zoom;
  913.         } else if ($zoom == 'zoom') {
  914.             $this->ZoomMode = $layout;
  915.         } else {
  916.             $this->Error('Incorrect zoom display mode: ' . $zoom);
  917.         } // end if... else if... else...
  918.  
  919.         // Layout mode
  920.         if ($layout == 'single' || $layout == 'continuous' || $layout=='two' || $layout=='default') {
  921.             $this->LayoutMode = $layout;
  922.         } else if ($zoom != 'zoom') {
  923.             $this->Error('Incorrect layout display mode: ' . $layout);
  924.         } // end if... else if...
  925.     } // end of the "SetDisplayMode()" method
  926.  
  927.  
  928.     /**
  929.      * Sets page compression
  930.      *
  931.      * @param  boolean  whether to compress file or not
  932.      *
  933.      * @access public
  934.      */
  935.     function SetCompression($compress)
  936.     {
  937.         if (function_exists('gzcompress')) {
  938.             $this->compress = $compress;
  939.         } else {
  940.             $this->compress = FALSE;
  941.         } // end if... else...
  942.     } // end of the "SetCompression()" method
  943.  
  944.  
  945.     /**
  946.      * Sets page margins
  947.      *
  948.      * @param  double  The left margin
  949.      * @param  double  The top margin
  950.      * @param  double  The right margin
  951.      *
  952.      * @access public
  953.      */
  954.     function SetMargins($left, $top, $right = -1)
  955.     {
  956.         $this->lMargin = $left;
  957.         $this->tMargin = $top;
  958.         if ($right == -1) {
  959.             $right = $left;
  960.         }
  961.         $this->rMargin = $right;
  962.     } // end of the "SetMargins()" method
  963.  
  964.  
  965.     /**
  966.      * The FPDF constructor
  967.      *
  968.      * @param  string  The page orientation (p, portrait, l or landscape)
  969.      * @param  string  The unit for sizes (pt, mm, cm or in)
  970.      * @param  mixed   The page format (A3, A4, A5, letter, legal or an array
  971.      *                 with page sizes)
  972.      *
  973.      * @access public
  974.      */
  975.     function FPDF($orientation = 'P', $unit = 'mm', $format = 'A4')
  976.     {
  977.         // Check for PHP locale-related bug
  978.         if (1.1 == 1) {
  979.             $this->Error('Don\'t call setlocale() before including class file');
  980.         }
  981.  
  982.         // Initialization of properties
  983.         $this->page               = 0;
  984.         $this->n                  = 2;
  985.         $this->buffer             = '';
  986.         $this->pages              = array();
  987.         $this->OrientationChanges = array();
  988.         $this->state              = 0;
  989.         $this->fonts              = array();
  990.         $this->FontFiles          = array();
  991.         $this->diffs              = array();
  992.         $this->images             = array();
  993.         $this->links              = array();
  994.         $this->InFooter           = FALSE;
  995.         $this->FontFamily         = '';
  996.         $this->FontStyle          = '';
  997.         $this->FontSizePt         = 12;
  998.         $this->underline          = FALSE;
  999.         $this->DrawColor          = '0 G';
  1000.         $this->FillColor          = '0 g';
  1001.         $this->TextColor          = '0 g';
  1002.         $this->ColorFlag          = FALSE;
  1003.         $this->ws                 = 0;
  1004.  
  1005.         // Standard fonts
  1006.         $this->CoreFonts['courier']      = 'Courier';
  1007.         $this->CoreFonts['courierB']     = 'Courier-Bold';
  1008.         $this->CoreFonts['courierI']     = 'Courier-Oblique';
  1009.         $this->CoreFonts['courierBI']    = 'Courier-BoldOblique';
  1010.         $this->CoreFonts['helvetica']    = 'Helvetica';
  1011.         $this->CoreFonts['helveticaB']   = 'Helvetica-Bold';
  1012.         $this->CoreFonts['helveticaI']   = 'Helvetica-Oblique';
  1013.         $this->CoreFonts['helveticaBI']  = 'Helvetica-BoldOblique';
  1014.         $this->CoreFonts['times']        = 'Times-Roman';
  1015.         $this->CoreFonts['timesB']       = 'Times-Bold';
  1016.         $this->CoreFonts['timesI']       = 'Times-Italic';
  1017.         $this->CoreFonts['timesBI']      = 'Times-BoldItalic';
  1018.         $this->CoreFonts['symbol']       = 'Symbol';
  1019.         $this->CoreFonts['zapfdingbats'] = 'ZapfDingbats';
  1020.  
  1021.         // Scale factor
  1022.         if ($unit == 'pt') {
  1023.             $this->k = 1;
  1024.         } else if ($unit == 'mm') {
  1025.             $this->k = 72/25.4;
  1026.         } else if ($unit == 'cm') {
  1027.             $this->k = 72/2.54;
  1028.         } else if ($unit == 'in') {
  1029.             $this->k = 72;
  1030.         } else {
  1031.             $this->Error('Incorrect unit: ' . $unit);
  1032.         } // end if... else if... else...
  1033.  
  1034.         // Page format
  1035.         if (is_string($format)) {
  1036.             // 2002-07-24 - Nicola Asuni (info@tecnick.com)
  1037.             // Added new page formats (45 standard ISO paper formats and 4
  1038.             // american common formats).
  1039.             // Paper cordinates are calculated in this way:
  1040.             //    (inches * 72) where (1 inch = 2.54 cm)
  1041.             switch (strtoupper($format)) {
  1042.                 case '4A0':
  1043.                     $format = array(4767.87, 6740.79);
  1044.                     break;
  1045.                 case '2A0':
  1046.                     $format = array(3370.39, 4767.87);
  1047.                     break;
  1048.                 case 'A0':
  1049.                     $format = array(2383.94, 3370.39);
  1050.                     break;
  1051.                 case 'A1':
  1052.                     $format = array(1683.78, 2383.94);
  1053.                     break;
  1054.                 case 'A2':
  1055.                     $format = array(1190.55, 1683.78);
  1056.                     break;
  1057.                 case 'A3':
  1058.                     $format = array(841.89, 1190.55);
  1059.                     break;
  1060.                 case 'A4':
  1061.                     $format = array(595.28, 841.89);
  1062.                     break;
  1063.                 case 'A5':
  1064.                     $format = array(419.53, 595.28);
  1065.                     break;
  1066.                 case 'A6':
  1067.                     $format = array(297.64, 419.53);
  1068.                     break;
  1069.                 case 'A7':
  1070.                     $format = array(209.76, 297.64);
  1071.                     break;
  1072.                 case 'A8':
  1073.                     $format = array(147.40, 209.76);
  1074.                     break;
  1075.                 case 'A9':
  1076.                     $format = array(104.88, 147.40);
  1077.                     break;
  1078.                 case 'A10':
  1079.                     $format = array(73.70, 104.88);
  1080.                     break;
  1081.                 case 'B0':
  1082.                     $format = array(2834.65, 4008.19);
  1083.                     break;
  1084.                 case 'B1':
  1085.                     $format = array(2004.09, 2834.65);
  1086.                     break;
  1087.                 case 'B2':
  1088.                     $format = array(1417.32, 2004.09);
  1089.                     break;
  1090.                 case 'B3':
  1091.                     $format = array(1000.63, 1417.32);
  1092.                     break;
  1093.                 case 'B4':
  1094.                     $format = array(708.66, 1000.63);
  1095.                     break;
  1096.                 case 'B5':
  1097.                     $format = array(498.90, 708.66);
  1098.                     break;
  1099.                 case 'B6':
  1100.                     $format = array(354.33, 498.90);
  1101.                     break;
  1102.                 case 'B7':
  1103.                     $format = array(249.45, 354.33);
  1104.                     break;
  1105.                 case 'B8':
  1106.                     $format = array(175.75, 249.45);
  1107.                     break;
  1108.                 case 'B9':
  1109.                     $format = array(124.72, 175.75);
  1110.                     break;
  1111.                 case 'B10':
  1112.                     $format = array(87.87, 124.72);
  1113.                     break;
  1114.                 case 'C0':
  1115.                     $format = array(2599.37, 3676.54);
  1116.                     break;
  1117.                 case 'C1':
  1118.                     $format = array(1836.85, 2599.37);
  1119.                     break;
  1120.                 case 'C2':
  1121.                     $format = array(1298.27, 1836.85);
  1122.                     break;
  1123.                 case 'C3':
  1124.                     $format = array(918.43, 1298.27);
  1125.                     break;
  1126.                 case 'C4':
  1127.                     $format = array(649.13, 918.43);
  1128.                     break;
  1129.                 case 'C5':
  1130.                     $format = array(459.21, 649.13);
  1131.                     break;
  1132.                 case 'C6':
  1133.                     $format = array(323.15, 459.21);
  1134.                     break;
  1135.                 case 'C7':
  1136.                     $format = array(229.61, 323.15);
  1137.                     break;
  1138.                 case 'C8':
  1139.                     $format = array(161.57, 229.61);
  1140.                     break;
  1141.                 case 'C9':
  1142.                     $format = array(113.39, 161.57);
  1143.                     break;
  1144.                 case 'C10':
  1145.                     $format = array(79.37, 113.39);
  1146.                     break;
  1147.                 case 'RA0':
  1148.                     $format = array(2437.80, 3458.27);
  1149.                     break;
  1150.                 case 'RA1':
  1151.                     $format = array(1729.13, 2437.80);
  1152.                     break;
  1153.                 case 'RA2':
  1154.                     $format = array(1218.90, 1729.13);
  1155.                     break;
  1156.                 case 'RA3':
  1157.                     $format = array(864.57, 1218.90);
  1158.                     break;
  1159.                 case 'RA4':
  1160.                     $format = array(609.45, 864.57);
  1161.                     break;
  1162.                 case 'SRA0':
  1163.                     $format = array(2551.18, 3628.35);
  1164.                     break;
  1165.                 case 'SRA1':
  1166.                     $format = array(1814.17, 2551.18);
  1167.                     break;
  1168.                 case 'SRA2':
  1169.                     $format = array(1275.59, 1814.17);
  1170.                     break;
  1171.                 case 'SRA3':
  1172.                     $format = array(907.09, 1275.59);
  1173.                     break;
  1174.                 case 'SRA4':
  1175.                     $format = array(637.80, 907.09);
  1176.                     break;
  1177.                 case 'LETTER':
  1178.                     $format = array(612.00, 792.00);
  1179.                     break;
  1180.                 case 'LEGAL':
  1181.                     $format = array(612.00, 1008.00);
  1182.                     break;
  1183.                 case 'EXECUTIVE':
  1184.                     $format = array(521.86, 756.00);
  1185.                     break;
  1186.                 case 'FOLIO':
  1187.                     $format = array(612.00, 936.00);
  1188.                     break;
  1189.                 default:
  1190.                     $this->Error('Unknown page format: ' . $format);
  1191.                     break;
  1192.             } // end switch
  1193.             $this->fwPt = $format[0];
  1194.             $this->fhPt = $format[1];
  1195.         }
  1196.         else {
  1197.             $this->fwPt = $format[0] * $this->k;
  1198.             $this->fhPt = $format[1] * $this->k;
  1199.         } // end if... else...
  1200.         $this->fw       = $this->fwPt / $this->k;
  1201.         $this->fh       = $this->fhPt / $this->k;
  1202.  
  1203.         // Page orientation
  1204.         $orientation    = strtolower($orientation);
  1205.         if ($orientation == 'p' || $orientation == 'portrait') {
  1206.             $this->DefOrientation = 'P';
  1207.             $this->wPt            = $this->fwPt;
  1208.             $this->hPt            = $this->fhPt;
  1209.         }
  1210.         else if ($orientation == 'l' || $orientation == 'landscape') {
  1211.             $this->DefOrientation = 'L';
  1212.             $this->wPt            = $this->fhPt;
  1213.             $this->hPt            = $this->fwPt;
  1214.         }
  1215.         else {
  1216.             $this->Error('Incorrect orientation: ' . $orientation);
  1217.         } // end if... else if... else...
  1218.         $this->CurOrientation     = $this->DefOrientation;
  1219.         $this->w                  = $this->wPt / $this->k;
  1220.         $this->h                  = $this->hPt / $this->k;
  1221.  
  1222.         // Page margins (1 cm)
  1223.         $margin          = 28.35 / $this->k;
  1224.         $this->SetMargins($margin, $margin);
  1225.  
  1226.         // Interior cell margin (1 mm)
  1227.         $this->cMargin   = $margin / 10;
  1228.  
  1229.         // Line width (0.2 mm)
  1230.         $this->LineWidth = .567 / $this->k;
  1231.  
  1232.         // Automatic page break
  1233.         $this->SetAutoPageBreak(TRUE, 2 * $margin);
  1234.  
  1235.         // Full width display mode
  1236.         $this->SetDisplayMode('fullwidth');
  1237.  
  1238.         // Compression
  1239.         $this->SetCompression(TRUE);
  1240.     } // end of the "FPDF()" constructor
  1241.  
  1242.  
  1243.     /**
  1244.      * Sets left margin of the page
  1245.      *
  1246.      * @param  double  The left margin
  1247.      *
  1248.      * @access public
  1249.      */
  1250.     function SetLeftMargin($margin)
  1251.     {
  1252.         $this->lMargin = $margin;
  1253.         if ($this->page > 0 && $this->x < $margin) {
  1254.             $this->x   = $margin;
  1255.         }
  1256.     } // end of the "SetLeftMargin()" method
  1257.  
  1258.  
  1259.     /**
  1260.      * Sets top margin of the page
  1261.      *
  1262.      * @param  double  The top margin
  1263.      *
  1264.      * @access public
  1265.      */
  1266.     function SetTopMargin($margin)
  1267.     {
  1268.         $this->tMargin = $margin;
  1269.     } // end of the "SetTopMargin()" method
  1270.  
  1271.  
  1272.     /**
  1273.      * Sets right margin of the page
  1274.      *
  1275.      * @param  double  The right margin
  1276.      *
  1277.      * @access public
  1278.      */
  1279.     function SetRightMargin($margin)
  1280.     {
  1281.         $this->rMargin = $margin;
  1282.     } // end of the "SetRightMargin()" method
  1283.  
  1284.  
  1285.     /**
  1286.      * Sets the title of the document (among the document properties)
  1287.      *
  1288.      * @param  string  The title of the document
  1289.      *
  1290.      * @access public
  1291.      */
  1292.     function SetTitle($title)
  1293.     {
  1294.         $this->title = $title;
  1295.     } // end of the "SetTitle()" method
  1296.  
  1297.  
  1298.     /**
  1299.      * Sets the subject of the document (among the document properties)
  1300.      *
  1301.      * @param  string  The subject of the document
  1302.      *
  1303.      * @access public
  1304.      */
  1305.     function SetSubject($subject)
  1306.     {
  1307.         $this->subject = $subject;
  1308.     } // end of the "SetSubject()" method
  1309.  
  1310.  
  1311.     /**
  1312.      * Sets the author of the document (among the document properties)
  1313.      *
  1314.      * @param  string  The author of the document
  1315.      *
  1316.      * @access public
  1317.      */
  1318.     function SetAuthor($author)
  1319.     {
  1320.         $this->author = $author;
  1321.     } // end of the "SetAuthor()" method
  1322.  
  1323.  
  1324.     /**
  1325.      * Sets keywords of the document (among the document properties)
  1326.      *
  1327.      * @param  string  The keyword list for the document
  1328.      *
  1329.      * @access public
  1330.      */
  1331.     function SetKeywords($keywords)
  1332.     {
  1333.         $this->keywords = $keywords;
  1334.     } // end of the "SetKeywords()" method
  1335.  
  1336.  
  1337.     /**
  1338.      * Sets the creator of the document (among the document properties)
  1339.      *
  1340.      * @param  string  The creator of the document
  1341.      *
  1342.      * @access public
  1343.      */
  1344.     function SetCreator($creator)
  1345.     {
  1346.         $this->creator = $creator;
  1347.     } // end of the "SetCreator()" method
  1348.  
  1349.  
  1350.     /**
  1351.      * Defines an alias for the total number of pages
  1352.      *
  1353.      * @param  string  The alias string
  1354.      *
  1355.      * @access public
  1356.      */
  1357.     function AliasNbPages($alias = '{nb}')
  1358.     {
  1359.         $this->AliasNbPages = $alias;
  1360.     } // end of the "AliasNbPages()" method
  1361.  
  1362.  
  1363.     /**
  1364.      * Selects a font
  1365.      *
  1366.      * @param   string   The font name
  1367.      * @param   string   The font style (B, I, BI)
  1368.      * @param   double   The font size (in points)
  1369.      *
  1370.      * @global  double   The character width
  1371.      *
  1372.      * @access  public
  1373.      */
  1374.     function SetFont($family, $style = '', $size = 0)
  1375.     {
  1376.         global $fpdf_charwidths;
  1377.  
  1378.         $family     = strtolower($family);
  1379.         if ($family == '') {
  1380.             $family = $this->FontFamily;
  1381.         }
  1382.         if ($family == 'arial') {
  1383.             $family = 'helvetica';
  1384.         }
  1385.         else if ($family == 'symbol' || $family == 'zapfdingbats') {
  1386.             $style  = '';
  1387.         }
  1388.         $style      = strtoupper($style);
  1389.  
  1390.         if (strpos(' ' . $style, 'U')) {
  1391.             $this->underline = TRUE;
  1392.             $style           = str_replace('U', '', $style);
  1393.         } else {
  1394.             $this->underline = FALSE;
  1395.         }
  1396.         if ($style == 'IB') {
  1397.             $style  = 'BI';
  1398.         }
  1399.         if ($size == 0) {
  1400.             $size   = $this->FontSizePt;
  1401.         }
  1402.  
  1403.         // Tests if the font is already selected
  1404.         if ($this->FontFamily == $family && $this->FontStyle == $style && $this->FontSizePt == $size) {
  1405.             return;
  1406.         }
  1407.  
  1408.         // Tests if used for the first time
  1409.         $fontkey = $family . $style;
  1410.         if (!isset($this->fonts[$fontkey])) {
  1411.             // Checks if one of the standard fonts
  1412.             if (isset($this->CoreFonts[$fontkey])) {
  1413.                 if (!isset($fpdf_charwidths[$fontkey])) {
  1414.                     // Loads metric file
  1415.                     $file     = $family;
  1416.                     if ($family == 'times' || $family == 'helvetica') {
  1417.                         $file .= strtolower($style);
  1418.                     }
  1419.                     $file     .= '.php';
  1420.                     if (isset($GLOBALS['FPDF_font_path'])) {
  1421.                         $file = $GLOBALS['FPDF_font_path'] . $file;
  1422.                     }
  1423.                     include($file);
  1424.                     if (!isset($fpdf_charwidths[$fontkey])) {
  1425.                         $this->Error('Could not include font metric file');
  1426.                     }
  1427.                 } // end if
  1428.                 $i = count($this->fonts) + 1;
  1429.                 $this->fonts[$fontkey] = array('i'    => $i,
  1430.                                                'type' => 'core',
  1431.                                                'name' => $this->CoreFonts[$fontkey],
  1432.                                                'up'   => -100,
  1433.                                                'ut'   => 50,
  1434.                                                'cw'   => $fpdf_charwidths[$fontkey]);
  1435.             }
  1436.             else {
  1437.                 $this->Error('Undefined font: ' . $family . ' ' . $style);
  1438.             } // end if... else...
  1439.         } // end if
  1440.  
  1441.         // Selects it
  1442.         $this->FontFamily  = $family;
  1443.         $this->FontStyle   = $style;
  1444.         $this->FontSizePt  = $size;
  1445.         $this->FontSize    = $size / $this->k;
  1446.         $this->CurrentFont = &$this->fonts[$fontkey];
  1447.         if ($this->page > 0) {
  1448.             $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  1449.         }
  1450.     } // end of the "SetFont()" method
  1451.  
  1452.  
  1453.     /**
  1454.      * Sends the header of the page
  1455.      *
  1456.      * This method has to be implemented in your own inherited class
  1457.      *
  1458.      * @access public
  1459.      */
  1460.     function Header()
  1461.     {
  1462.         // void
  1463.     } // end of the "Header()" method
  1464.  
  1465.  
  1466.     /**
  1467.      * Sends the footer of the page
  1468.      *
  1469.      * This method has to be implemented in your own inherited class
  1470.      *
  1471.      * @access public
  1472.      */
  1473.     function Footer()
  1474.     {
  1475.         // void
  1476.     } // end of the "Footer()" method
  1477.  
  1478.  
  1479.     /**
  1480.      * Begin the document
  1481.      *
  1482.      * @access public
  1483.      */
  1484.     function Open()
  1485.     {
  1486.         $this->_begindoc();
  1487.     } // end of the "Open()" method
  1488.  
  1489.  
  1490.     /**
  1491.      * Starts a new page
  1492.      *
  1493.      * @param  string  The page orientation (p, portrait, l or landscape)
  1494.      *
  1495.      * @access public
  1496.      */
  1497.     function AddPage($orientation = '')
  1498.     {
  1499.         // Backups some core variables
  1500.         $family             = $this->FontFamily;
  1501.         $style              = $this->FontStyle . ($this->underline ? 'U' : '');
  1502.         $size               = $this->FontSizePt;
  1503.         $lw                 = $this->LineWidth;
  1504.         $dc                 = $this->DrawColor;
  1505.         $fc                 = $this->FillColor;
  1506.         $tc                 = $this->TextColor;
  1507.         $cf                 = $this->ColorFlag;
  1508.  
  1509.         // If a page is already defined close it before starting the new one
  1510.         if ($this->page > 0) {
  1511.             // Page footer
  1512.             $this->InFooter = TRUE;
  1513.             $this->Footer();
  1514.             $this->InFooter = FALSE;
  1515.             // Close page
  1516.             $this->_endpage();
  1517.         }
  1518.  
  1519.         // Do start the new page
  1520.         $this->_beginpage($orientation);
  1521.         // Sets line cap style to square
  1522.         $this->_out('2 J');
  1523.         // Sets line width
  1524.         $this->LineWidth = $lw;
  1525.         $this->_out(sprintf('%.2f w', $lw * $this->k));
  1526.         // Sets font
  1527.         if ($family) {
  1528.             $this->SetFont($family, $style, $size);
  1529.         }
  1530.         // Sets colors
  1531.         $this->DrawColor = $dc;
  1532.         if ($dc != '0 G') {
  1533.             $this->_out($dc);
  1534.         }
  1535.         $this->FillColor = $fc;
  1536.         if ($fc != '0 g') {
  1537.             $this->_out($fc);
  1538.         }
  1539.         $this->TextColor = $tc;
  1540.         $this->ColorFlag = $cf;
  1541.         // Sets Page header
  1542.         $this->Header();
  1543.         // Restores line width
  1544.         if ($this->LineWidth != $lw) {
  1545.             $this->LineWidth = $lw;
  1546.             $this->_out(sprintf('%.2f w', $lw * $this->k));
  1547.         }
  1548.         // Restores font
  1549.         if ($family) {
  1550.             $this->SetFont($family, $style, $size);
  1551.         }
  1552.         // Restores colors
  1553.         if ($this->DrawColor!=$dc) {
  1554.             $this->DrawColor = $dc;
  1555.             $this->_out($dc);
  1556.         }
  1557.         if ($this->FillColor!=$fc) {
  1558.             $this->FillColor = $fc;
  1559.             $this->_out($fc);
  1560.         }
  1561.         $this->TextColor     = $tc;
  1562.         $this->ColorFlag     = $cf;
  1563.     } // end of the "AddPage()" method
  1564.  
  1565.  
  1566.     /**
  1567.      * Terminates and closes the document
  1568.      *
  1569.      * @access public
  1570.      */
  1571.     function Close()
  1572.     {
  1573.         // Terminates document
  1574.         if ($this->page == 0) {
  1575.             $this->AddPage();
  1576.         }
  1577.  
  1578.         // Displays the page footer
  1579.         $this->InFooter = TRUE;
  1580.         $this->Footer();
  1581.         $this->InFooter = FALSE;
  1582.  
  1583.         // Closes page and document
  1584.         $this->_endpage();
  1585.         $this->_enddoc();
  1586.     } // end of the "Close()" method
  1587.  
  1588.  
  1589.     /**
  1590.      * Gets the current page number
  1591.      *
  1592.      * @return  integer  The current page number
  1593.      *
  1594.      * @access  public
  1595.      */
  1596.     function PageNo()
  1597.     {
  1598.         return $this->page;
  1599.     } // end of the "PageNo()" method
  1600.  
  1601.  
  1602.     /**
  1603.      * Sets color for all stroking operations
  1604.      *
  1605.      * @param  integer  The red level (0 to 255)
  1606.      * @param  integer  The green level (0 to 255)
  1607.      * @param  integer  The blue level (0 to 255)
  1608.      *
  1609.      * @access public
  1610.      */
  1611.     function SetDrawColor($r, $g = -1, $b = -1)
  1612.     {
  1613.         if (($r == 0 && $g == 0 && $b == 0) || $g == -1) {
  1614.             $this->DrawColor = sprintf('%.3f G', $r / 255);
  1615.         } else {
  1616.             $this->DrawColor = sprintf('%.3f %.3f %.3f RG', $r / 255, $g / 255, $b / 255);
  1617.         } // end if... else...
  1618.  
  1619.         // If a page is defined, applies this property
  1620.         if ($this->page > 0) {
  1621.             $this->_out($this->DrawColor);
  1622.         }
  1623.     } // end of the "SetDrawColor()" method
  1624.  
  1625.  
  1626.     /**
  1627.      * Sets color for all filling operations
  1628.      *
  1629.      * @param  integer  The red level (0 to 255)
  1630.      * @param  integer  The green level (0 to 255)
  1631.      * @param  integer  The blue level (0 to 255)
  1632.      *
  1633.      * @access public
  1634.      */
  1635.     function SetFillColor($r, $g = -1, $b =-1)
  1636.     {
  1637.         if (($r == 0 && $g == 0 && $b == 0) || $g == -1) {
  1638.             $this->FillColor = sprintf('%.3f g', $r / 255);
  1639.         } else {
  1640.             $this->FillColor = sprintf('%.3f %.3f %.3f rg', $r / 255, $g / 255, $b / 255);
  1641.         } // end if... else...
  1642.  
  1643.         $this->ColorFlag     = ($this->FillColor != $this->TextColor);
  1644.  
  1645.         // If a page is defined, applies this property
  1646.         if ($this->page > 0) {
  1647.             $this->_out($this->FillColor);
  1648.         }
  1649.     } // end of the "SetDrawColor()" method
  1650.  
  1651.  
  1652.     /**
  1653.      * Sets color for text
  1654.      *
  1655.      * @param  integer  The red level (0 to 255)
  1656.      * @param  integer  The green level (0 to 255)
  1657.      * @param  integer  The blue level (0 to 255)
  1658.      *
  1659.      * @access public
  1660.      */
  1661.     function SetTextColor($r, $g = -1, $b =-1)
  1662.     {
  1663.         if (($r == 0 && $g == 0 && $b == 0) || $g == -1) {
  1664.             $this->TextColor = sprintf('%.3f g', $r / 255);
  1665.         } else {
  1666.             $this->TextColor = sprintf('%.3f %.3f %.3f rg', $r / 255, $g / 255, $b / 255);
  1667.         } // end if... else...
  1668.  
  1669.         $this->ColorFlag     = ($this->FillColor != $this->TextColor);
  1670.     } // end of the "SetTextColor()" method
  1671.  
  1672.  
  1673.     /**
  1674.      * Sets the line width
  1675.      *
  1676.      * @param   double  The line width
  1677.      *
  1678.      * @access  public
  1679.      */
  1680.     function SetLineWidth($width)
  1681.     {
  1682.         $this->LineWidth = $width;
  1683.  
  1684.         // If a page is defined, applies this property
  1685.         if ($this->page > 0) {
  1686.             $this->_out(sprintf('%.2f w', $width * $this->k));
  1687.         }
  1688.     } // end of the "SetLineWidth()" method
  1689.  
  1690.  
  1691.     /**
  1692.      * Draws a line
  1693.      *
  1694.      * @param   double  The horizontal position of the starting point
  1695.      * @param   double  The vertical position of the starting point
  1696.      * @param   double  The horizontal position of the ending point
  1697.      * @param   double  The vertical position of the ending point
  1698.      *
  1699.      * @access  public
  1700.      */
  1701.     function Line($x1, $y1, $x2, $y2)
  1702.     {
  1703.         $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));
  1704.     } // end of the "Line()" method
  1705.  
  1706.  
  1707.     /**
  1708.      * Draws a rectangle
  1709.      *
  1710.      * @param   double  The horizontal position of the top left corner
  1711.      * @param   double  The vertical position of the top left corner
  1712.      * @param   double  The horizontal position of the bottom right corner
  1713.      * @param   double  The vertical position of the bottom right corner
  1714.      * @param   string  The rectangle style
  1715.      *
  1716.      * @access  public
  1717.      */
  1718.     function Rect($x, $y, $w, $h, $style = '')
  1719.     {
  1720.         if ($style == 'F') {
  1721.             $op = 'f';
  1722.         } else if ($style == 'FD' || $style=='DF') {
  1723.             $op = 'B';
  1724.         } else {
  1725.             $op = 'S';
  1726.         } // end if... else if... else
  1727.  
  1728.         $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s', $x * $this->k, ($this->h - $y) * $this->k, $w * $this->k, -$h * $this->k, $op));
  1729.     } // end of the "Rect()" method
  1730.  
  1731.  
  1732.     /**
  1733.      * Adds a TrueType or Type1 font
  1734.      *
  1735.      * @param   string  The font name
  1736.      * @param   string  The font style (B, I, BI)
  1737.      * @param   string  The font file definition
  1738.      *
  1739.      * @access  public
  1740.      */
  1741.     function AddFont($family, $style = '', $file = '')
  1742.     {
  1743.         $family     = strtolower($family);
  1744.         if ($family == 'arial') {
  1745.             $family = 'helvetica';
  1746.         }
  1747.  
  1748.         $style  = strtoupper($style);
  1749.         if ($style == 'IB') {
  1750.             $style = 'BI';
  1751.         }
  1752.         if (isset($this->fonts[$family . $style])) {
  1753.             $this->Error('Font already added: ' . $family . ' ' . $style);
  1754.         }
  1755.         if ($file == '') {
  1756.             $file = str_replace(' ', '', $family) . strtolower($style) . '.php';
  1757.         }
  1758.         if (isset($GLOBALS['FPDF_font_path'])) {
  1759.             $file = $GLOBALS['FPDF_font_path'] . $file;
  1760.         }
  1761.         include($file);
  1762.         if (!isset($name)) {
  1763.             $this->Error('Could not include font definition file');
  1764.         }
  1765.  
  1766.         $i = count($this->fonts) + 1;
  1767.         $this->fonts[$family . $style] = array('i'    => $i,
  1768.                                                'type' => $type,
  1769.                                                'name' => $name,
  1770.                                                'desc' => $desc,
  1771.                                                'up'   => $up,
  1772.                                                'ut'   => $ut,
  1773.                                                'cw'   => $cw,
  1774.                                                'enc'  => $enc,
  1775.                                                'file' => $file);
  1776.         // Searches existing encodings
  1777.         if ($diff) {
  1778.             $d  = 0;
  1779.             $nb = count($this->diffs);
  1780.             for ($i = 1; $i <= $nb; $i++) {
  1781.                 if ($this->diffs[$i] == $diff) {
  1782.                     $d = $i;
  1783.                     break;
  1784.                 } // end if
  1785.             } // end for
  1786.             if ($d == 0) {
  1787.                 $d               = $nb + 1;
  1788.                 $this->diffs[$d] = $diff;
  1789.             } // end if
  1790.             $this->fonts[$family . $style]['diff'] = $d;
  1791.         } // end if
  1792.  
  1793.         if ($file) {
  1794.             if ($type == 'TrueType') {
  1795.                 $this->FontFiles[$file] = array('length1' => $originalsize);
  1796.             } else {
  1797.                 $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2);
  1798.             }
  1799.         } // end if
  1800.     } // end of the "AddFont()" method
  1801.  
  1802.  
  1803.     /**
  1804.      * Sets font size
  1805.      *
  1806.      * @param   double   The font size (in points)
  1807.      *
  1808.      * @access  public
  1809.      */
  1810.     function SetFontSize($size)
  1811.     {
  1812.         if ($this->FontSizePt == $size) {
  1813.             return;
  1814.         }
  1815.         $this->FontSizePt = $size;
  1816.         $this->FontSize   = $size / $this->k;
  1817.         if ($this->page > 0) {
  1818.             $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  1819.         }
  1820.     } // end of the "SetFontSize()" method
  1821.  
  1822.  
  1823.     /**
  1824.      * Creates a new internal link
  1825.      *
  1826.      * @return  integer  The link id
  1827.      *
  1828.      * @access  public
  1829.      */
  1830.     function AddLink()
  1831.     {
  1832.         $n = count($this->links) + 1;
  1833.         $this->links[$n] = array(0, 0);
  1834.         return $n;
  1835.     } // end of the "AddLink()" method
  1836.  
  1837.  
  1838.     /**
  1839.      * Sets destination of internal link
  1840.      *
  1841.      * @param   integer  The link id
  1842.      * @param   double   The y position on the page
  1843.      * @param   integer  The page number
  1844.      *
  1845.      * @access  public
  1846.      */
  1847.     function SetLink($link, $y = 0, $page = -1)
  1848.     {
  1849.         if ($y == -1) {
  1850.             $y    = $this->y;
  1851.         }
  1852.         if ($page == -1) {
  1853.             $page = $this->page;
  1854.         }
  1855.         $this->links[$link] = array($page, $y);
  1856.     } // end of the "SetLink()" method
  1857.  
  1858.  
  1859.     /**
  1860.      * Put a link inside a rectangular area of the page
  1861.      *
  1862.      * @param   double   The top left x position
  1863.      * @param   double   The top left y position
  1864.      * @param   double   The rectangle width
  1865.      * @param   double   The rectangle height
  1866.      * @param   mixed    The link id or an url
  1867.      *
  1868.      * @access  public
  1869.      */
  1870.     function Link($x, $y, $w, $h, $link)
  1871.     {
  1872.         $this->PageLinks[$this->page][] = array($x * $this->k,
  1873.                                                 $this->hPt - $y * $this->k,
  1874.                                                 $w * $this->k,
  1875.                                                 $h * $this->k,
  1876.                                                 $link);
  1877.     } // end of the "Link()" method
  1878.  
  1879.  
  1880.     /**
  1881.      * Outputs a string
  1882.      *
  1883.      * @param   double  The x position
  1884.      * @param   double  The y position
  1885.      * @param   string  The string
  1886.      *
  1887.      * @access  public
  1888.      */
  1889.     function Text($x, $y, $txt)
  1890.     {
  1891.         $txt   = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt)));
  1892.         $s     = sprintf('BT %.2f %.2f Td (%s) Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $txt);
  1893.         if ($this->underline && $txt != '') {
  1894.             $s .= ' ' . $this->_dounderline($x, $y, $txt);
  1895.         }
  1896.         if ($this->ColorFlag) {
  1897.             $s = 'q ' . $this->TextColor . ' ' . $s . ' Q';
  1898.         }
  1899.         $this->_out($s);
  1900.     } // end of the "Text()" method
  1901.  
  1902.  
  1903.     /**
  1904.      * Gets whether automatic page break is on or not
  1905.      *
  1906.      * @return  boolean  Whether automatic page break is on or not
  1907.      *
  1908.      * @access  public
  1909.      */
  1910.     function AcceptPageBreak()
  1911.     {
  1912.         return $this->AutoPageBreak;
  1913.     } // end of the "AcceptPageBreak()" method
  1914.  
  1915.  
  1916.     /**
  1917.      * Output a cell
  1918.      *
  1919.      * @param   double   The cell width
  1920.      * @param   double   The cell height
  1921.      * @param   string   The text to output
  1922.      * @param   mixed    Wether to add borders or not (see the manual)
  1923.      * @param   integer  Where to put the cursor once the output is done
  1924.      * @param   string   Align mode
  1925.      * @param   integer  Whether to fill the cell with a color or not
  1926.      * @param   mixed    The link id or an url
  1927.      *
  1928.      * @access  public
  1929.      */
  1930.     function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '')
  1931.     {
  1932.         $k = $this->k;
  1933.  
  1934.         if ($this->y + $h > $this->PageBreakTrigger
  1935.             && !$this->InFooter
  1936.             && $this->AcceptPageBreak()) {
  1937.             $x  = $this->x;
  1938.             $ws = $this->ws;
  1939.             if ($ws > 0) {
  1940.                 $this->ws = 0;
  1941.                 $this->_out('0 Tw');
  1942.             }
  1943.             $this->AddPage($this->CurOrientation);
  1944.             $this->x = $x;
  1945.             if ($ws > 0) {
  1946.                 $this->ws = $ws;
  1947.                 $this->_out(sprintf('%.3f Tw', $ws * $k));
  1948.             }
  1949.         } // end if
  1950.  
  1951.         if ($w == 0) {
  1952.             $w = $this->w - $this->rMargin - $this->x;
  1953.         }
  1954.  
  1955.         $s          = '';
  1956.         if ($fill == 1 || $border == 1) {
  1957.             if ($fill == 1) {
  1958.                 $op = ($border == 1) ? 'B' : 'f';
  1959.             } else {
  1960.                 $op = 'S';
  1961.             }
  1962.             $s      = sprintf('%.2f %.2f %.2f %.2f re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, -$h * $k, $op);
  1963.         } // end if
  1964.  
  1965.         if (is_string($border)) {
  1966.             $x     = $this->x;
  1967.             $y     = $this->y;
  1968.             if (strpos(' ' . $border, 'L')) {
  1969.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y+$h)) * $k);
  1970.             }
  1971.             if (strpos(' ' . $border, 'T')) {
  1972.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k);
  1973.             }
  1974.             if (strpos(' ' . $border, 'R')) {
  1975.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k);
  1976.             }
  1977.             if (strpos(' ' . $border, 'B')) {
  1978.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k);
  1979.             }
  1980.         } // end if
  1981.  
  1982.         if ($txt != '') {
  1983.             if ($align == 'R') {
  1984.                 $dx = $w - $this->cMargin - $this->GetStringWidth($txt);
  1985.             }
  1986.             else if ($align == 'C') {
  1987.                 $dx = ($w - $this->GetStringWidth($txt)) / 2;
  1988.             }
  1989.             else {
  1990.                 $dx = $this->cMargin;
  1991.             }
  1992.             $txt    = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt)));
  1993.             if ($this->ColorFlag) {
  1994.                 $s  .= 'q ' . $this->TextColor . ' ';
  1995.             }
  1996.             $s      .= sprintf('BT %.2f %.2f Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $txt);
  1997.             if ($this->underline) {
  1998.                 $s  .= ' ' . $this->_dounderline($this->x+$dx, $this->y + .5 * $h + .3 * $this->FontSize, $txt);
  1999.             }
  2000.             if ($this->ColorFlag) {
  2001.                 $s  .= ' Q';
  2002.             }
  2003.             if ($link) {
  2004.                 $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link);
  2005.             }
  2006.         } // end if
  2007.  
  2008.         if ($s) {
  2009.             $this->_out($s);
  2010.         }
  2011.         $this->lasth = $h;
  2012.  
  2013.         if ($ln > 0) {
  2014.             // Go to next line
  2015.             $this->y     += $h;
  2016.             if ($ln == 1) {
  2017.                 $this->x = $this->lMargin;
  2018.             }
  2019.         } else {
  2020.             $this->x     += $w;
  2021.         }
  2022.     } // end of the "Cell()" method
  2023.  
  2024.  
  2025.     /**
  2026.      * Output text with automatic or explicit line breaks
  2027.      *
  2028.      * @param   double   The cell width
  2029.      * @param   double   The cell height
  2030.      * @param   string   The text to output
  2031.      * @param   mixed    Wether to add borders or not (see the manual)
  2032.      * @param   string   Align mode
  2033.      * @param   integer  Whether to fill the cell with a color or not
  2034.      *
  2035.      * @access  public
  2036.      */
  2037.     function MultiCell($w, $h, $txt, $border = 0, $align = 'J', $fill = 0)
  2038.     {
  2039.         // loic1: PHP3 compatibility
  2040.         // $cw    = &$this->CurrentFont['cw'];
  2041.         if ($w == 0) {
  2042.             $w = $this->w - $this->lMargin - $this->x;
  2043.         }
  2044.         $wmax  = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
  2045.         $s     = str_replace("\r", '', $txt);
  2046.         $nb    = strlen($s);
  2047.         if ($nb>0 && $s[$nb - 1] == "\n") {
  2048.             $nb--;
  2049.         }
  2050.  
  2051.         $b              = 0;
  2052.         if ($border) {
  2053.             if ($border == 1) {
  2054.                 $border = 'LTRB';
  2055.                 $b      = 'LRT';
  2056.                 $b2     = 'LR';
  2057.             }
  2058.             else {
  2059.                 $b2     = '';
  2060.                 if (strpos(' ' . $border, 'L')) {
  2061.                     $b2 .= 'L';
  2062.                 }
  2063.                 if (strpos(' ' . $border, 'R')) {
  2064.                     $b2 .= 'R';
  2065.                 }
  2066.                 $b      = (strpos(' ' . $border, 'T')) ? $b2 . 'T' : $b2;
  2067.             } // end if... else...
  2068.         } // end if
  2069.  
  2070.         $sep = -1;
  2071.         $i   = 0;
  2072.         $j   = 0;
  2073.         $l   = 0;
  2074.         $ns  = 0;
  2075.         $nl  = 1;
  2076.         while ($i < $nb) {
  2077.             // Gets next character
  2078.             $c = $s[$i];
  2079.  
  2080.             // Explicit line break
  2081.             if ($c == "\n") {
  2082.                 if ($this->ws > 0) {
  2083.                     $this->ws = 0;
  2084.                     $this->_out('0 Tw');
  2085.                 }
  2086.                 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
  2087.                 $i++;
  2088.                 $sep   = -1;
  2089.                 $j     = $i;
  2090.                 $l     = 0;
  2091.                 $ns    = 0;
  2092.                 $nl++;
  2093.                 if ($border && $nl == 2) {
  2094.                     $b = $b2;
  2095.                 }
  2096.                 continue;
  2097.             } // end if
  2098.  
  2099.             // Space character
  2100.             if ($c == ' ') {
  2101.                 $sep = $i;
  2102.                 $ls  = $l;
  2103.                 $ns++;
  2104.             } // end if
  2105.  
  2106.             $l += $this->CurrentFont['cw'][$c];
  2107.             if ($l > $wmax) {
  2108.                 // Automatic line break
  2109.                 if ($sep == -1) {
  2110.                     if ($i == $j) {
  2111.                         $i++;
  2112.                     }
  2113.                     if ($this->ws > 0) {
  2114.                         $this->ws = 0;
  2115.                         $this->_out('0 Tw');
  2116.                     }
  2117.                     $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
  2118.                 }
  2119.                 else {
  2120.                     if ($align == 'J') {
  2121.                         $this->ws = ($ns > 1)
  2122.                                   ? ($wmax - $ls) / 1000 * $this->FontSize / ($ns - 1)
  2123.                                   : 0;
  2124.                         $this->_out(sprintf('%.3f Tw', $this->ws * $this->k));
  2125.                     }
  2126.                     $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill);
  2127.                     $i = $sep + 1;
  2128.                 } // end if... else...
  2129.  
  2130.                 $sep   = -1;
  2131.                 $j     = $i;
  2132.                 $l     = 0;
  2133.                 $ns    = 0;
  2134.                 $nl++;
  2135.                 if ($border && $nl == 2) {
  2136.                     $b = $b2;
  2137.                 }
  2138.             }
  2139.             else {
  2140.                 $i++;
  2141.             } // end if... else
  2142.         } // end while
  2143.  
  2144.         // Last chunk
  2145.         if ($this->ws > 0) {
  2146.             $this->ws = 0;
  2147.             $this->_out('0 Tw');
  2148.         }
  2149.  
  2150.         if ($border && strpos(' ' . $border, 'B')) {
  2151.             $b .= 'B';
  2152.         }
  2153.         $this->Cell($w, $h, substr($s, $j, $i), $b, 2, $align, $fill);
  2154.         $this->x = $this->lMargin;
  2155.     } // end of the "MultiCell()" method
  2156.  
  2157.  
  2158.     /**
  2159.      * Output text in flowing mode
  2160.      *
  2161.      * @param   double   The line height
  2162.      * @param   string   The text to output
  2163.      * @param   mixed    The link id or an url
  2164.      *
  2165.      * @access  public
  2166.      */
  2167.     function Write($h, $txt, $link = '')
  2168.     {
  2169.         $w    = $this->w - $this->rMargin - $this->x;
  2170.         $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
  2171.         $s    = str_replace("\r", '', $txt);
  2172.         $nb   = strlen($s);
  2173.         $sep  = -1;
  2174.         $i    = 0;
  2175.         $j    = 0;
  2176.         $l    = 0;
  2177.         $nl   = 1;
  2178.  
  2179.         while ($i < $nb) {
  2180.             // Gets next character
  2181.             $c = $s[$i];
  2182.  
  2183.             // Explicit line break
  2184.             if ($c == "\n") {
  2185.                 $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
  2186.                 $i++;
  2187.                 $sep = -1;
  2188.                 $j   = $i;
  2189.                 $l   = 0;
  2190.                 if ($nl == 1) {
  2191.                     $this->x = $this->lMargin;
  2192.                     $w       = $this->w - $this->rMargin - $this->x;
  2193.                     $wmax    = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
  2194.                 }
  2195.                 $nl++;
  2196.                 continue;
  2197.             }
  2198.  
  2199.             // Space character
  2200.             if ($c == ' ') {
  2201.                 $sep = $i;
  2202.                 $ls  = $l;
  2203.             } // end if
  2204.  
  2205.             $l += $this->CurrentFont['cw'][$c];
  2206.             if ($l > $wmax) {
  2207.                 // Automatic line break
  2208.                 if ($sep == -1) {
  2209.                     if($this->x > $this->lMargin)  {
  2210.                         // Move to next line
  2211.                         $this->x =$this->lMargin;
  2212.                         $this->y +=$h;
  2213.                         $w       = $this->w - $this->rMargin - $this->x;
  2214.                         $wmax    =($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
  2215.                         $i++;
  2216.                         $nl++;
  2217.                         continue;
  2218.                     }
  2219.                     if ($i == $j) {
  2220.                         $i++;
  2221.                     }
  2222.                     $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
  2223.                 }
  2224.                 else {
  2225.                     $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link);
  2226.                     $i = $sep + 1;
  2227.                 } // end if... else...
  2228.  
  2229.                 $sep         = -1;
  2230.                 $j           = $i;
  2231.                 $l           = 0;
  2232.                 if ($nl == 1) {
  2233.                     $this->x = $this->lMargin;
  2234.                     $w       = $this->w - $this->rMargin - $this->x;
  2235.                     $wmax    = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
  2236.                 }
  2237.                 $nl++;
  2238.             }
  2239.             else {
  2240.                 $i++;
  2241.             } // end if... else...
  2242.         } // end while
  2243.  
  2244.         // Last chunk
  2245.         if ($i != $j) {
  2246.             $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j, $i), 0, 0, '', 0, $link);
  2247.         }
  2248.     } // end of the "Write()" method
  2249.  
  2250.  
  2251.     /**
  2252.      * Puts an image on the page
  2253.      *
  2254.      * @param   string   The image file (JPEG or PNG format)
  2255.      * @param   double   The top left x position
  2256.      * @param   double   The top left y position
  2257.      * @param   double   The image width
  2258.      * @param   double   The image height
  2259.      * @param   string   The image type (JPG, JPEG or PNG)
  2260.      * @param   mixed    The link id or an url
  2261.      *
  2262.      * @access  public
  2263.      */
  2264.     function Image($file, $x, $y, $w, $h = 0, $type = '', $link = '')
  2265.     {
  2266.         if (!isset($this->images[$file])) {
  2267.             // First use of image, get info
  2268.             if ($type == '') {
  2269.                 $pos = strrpos($file, '.');
  2270.                 if (!$pos) {
  2271.                     $this->Error('Image file has no extension and no type was specified: ' . $file);
  2272.                 }
  2273.                 $type = substr($file, $pos + 1);
  2274.             } // end if
  2275.  
  2276.             $type = strtolower($type);
  2277.             $mqr  = get_magic_quotes_runtime();
  2278.             set_magic_quotes_runtime(0);
  2279.             if ($type == 'jpg' || $type == 'jpeg') {
  2280.                 $info = $this->_parsejpg($file);
  2281.             }
  2282.             else if ($type == 'png') {
  2283.                 $info = $this->_parsepng($file);
  2284.             }
  2285.             else {
  2286.                 $this->Error('Unsupported image file type: ' . $type);
  2287.             }
  2288.             set_magic_quotes_runtime($mqr);
  2289.             $info['i']           = count($this->images) + 1;
  2290.             $this->images[$file] = $info;
  2291.         }
  2292.         else {
  2293.             $info                = $this->images[$file];
  2294.         } // end if... else...
  2295.  
  2296.         // Automatic width or height calculation
  2297.         if ($w == 0) {
  2298.             $w = $h * $info['w'] / $info['h'];
  2299.         }
  2300.         if ($h == 0) {
  2301.             $h = $w * $info['h'] / $info['w'];
  2302.         }
  2303.         $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']));
  2304.  
  2305.         if ($link) {
  2306.             $this->Link($x, $y, $w, $h, $link);
  2307.         }
  2308.     } // end of the "Image()" method
  2309.  
  2310.  
  2311.     /**
  2312.      * Appends a line feed
  2313.      *
  2314.      * @param   double   The line height
  2315.      *
  2316.      * @access  public
  2317.      */
  2318.     function Ln($h = '')
  2319.     {
  2320.         $this->x = $this->lMargin;
  2321.         // Sets default line height to last cell height
  2322.         if (is_string($h)) {
  2323.             $this->y += $this->lasth;
  2324.         }
  2325.         else {
  2326.             $this->y += $h;
  2327.         }
  2328.     } // end of the "Ln()" method
  2329.  
  2330.  
  2331.     /**
  2332.      * Gets x position
  2333.      *
  2334.      * @return  double  The x position
  2335.      *
  2336.      * @access  public
  2337.      */
  2338.     function GetX()
  2339.     {
  2340.         return $this->x;
  2341.     } // end of the "GetX()" method
  2342.  
  2343.  
  2344.     /**
  2345.      * Sets x position
  2346.      *
  2347.      * @param   double  The x position
  2348.      *
  2349.      * @access  public
  2350.      */
  2351.     function SetX($x)
  2352.     {
  2353.         if ($x >= 0) {
  2354.             $this->x = $x;
  2355.         } else {
  2356.             $this->x = $this->w + $x;
  2357.         }
  2358.     } // end of the "SetX()" method
  2359.  
  2360.  
  2361.     /**
  2362.      * Gets y position
  2363.      *
  2364.      * @return  double  The y position
  2365.      *
  2366.      * @access  public
  2367.      */
  2368.     function GetY()
  2369.     {
  2370.         return $this->y;
  2371.     } // end of the "GetY()" method
  2372.  
  2373.  
  2374.     /**
  2375.      * Sets y position and resets x
  2376.      *
  2377.      * @param   double  The y position
  2378.      *
  2379.      * @access  public
  2380.      */
  2381.     function SetY($y)
  2382.     {
  2383.         $this->x = $this->lMargin;
  2384.         if ($y >= 0) {
  2385.             $this->y = $y;
  2386.         } else {
  2387.             $this->y = $this->h + $y;
  2388.         }
  2389.     } // end of the "SetY()" method
  2390.  
  2391.  
  2392.     /**
  2393.      * Sets x and y positions
  2394.      *
  2395.      * @param   double  The x position
  2396.      * @param   double  The y position
  2397.      *
  2398.      * @access  public
  2399.      */
  2400.     function SetXY($x,$y)
  2401.     {
  2402.         $this->SetY($y);
  2403.         $this->SetX($x);
  2404.     } // end of the "SetXY()" method
  2405.  
  2406.  
  2407.     /**
  2408.      * Outputs PDF to file or browser
  2409.      *
  2410.      * @param   string   The file name
  2411.      * @param   boolean  Whether to display the document inside the browser
  2412.      *                   (with Acrobat plugin), to enforce download as file or
  2413.      *                   to save it on the server
  2414.      *
  2415.      * @global  string   The browser id string
  2416.      *
  2417.      * @access  public
  2418.      */
  2419.     function Output($file = '', $download = FALSE)
  2420.     {
  2421.         global $HTTP_USER_AGENT;
  2422.  
  2423.         if ($this->state < 3) {
  2424.             $this->Close();
  2425.         }
  2426.  
  2427.         // Send to browser
  2428.         if ($file == '') {
  2429.             header('Content-Type: application/pdf');
  2430.             if (headers_sent()) {
  2431.                 $this->Error('Some data has already been output to browser, can\'t send PDF file');
  2432.             }
  2433.             header('Content-Length: ' . strlen($this->buffer));
  2434.             header('Content-Disposition: inline; filename=doc.pdf');
  2435.             echo $this->buffer;
  2436.         }
  2437.         // Download file
  2438.         else if ($download) {
  2439.             if (!empty($HTTP_USER_AGENT)
  2440.                 && (strpos($HTTP_USER_AGENT, 'MSIE 5.5') || strpos($HTTP_USER_AGENT, 'Opera'))) {
  2441.                 header('Content-Type: application/dummy');
  2442.             }
  2443.             // fix for Gecko-based browsers < 1.1
  2444.             else if (!empty($HTTP_USER_AGENT)
  2445.                   &&  (strpos($HTTP_USER_AGENT, 'Gecko') &&
  2446.                   (strpos($HTTP_USER_AGENT, 'rv:0.') || strpos($HTTP_USER_AGENT, 'rv:1.0') || strpos($HTTP_USER_AGENT, 'rv:1.1')))) {
  2447.                      header('Content-Type: application/');
  2448.             }
  2449.             else {
  2450.                 header('Content-Type: application/pdf');
  2451.             }
  2452.             if (headers_sent()) {
  2453.                 $this->Error('Some data has already been output to browser, can\'t send PDF file');
  2454.             }
  2455.             header('Content-Length: ' . strlen($this->buffer));
  2456.             header('Content-Disposition: attachment; filename=' . $file);
  2457.             echo $this->buffer;
  2458.         }
  2459.         // Save file locally
  2460.         else {
  2461.             $f = fopen($file, 'wb');
  2462.             if (!$f) {
  2463.                 $this->Error('Unable to create output file: ' . $file);
  2464.             }
  2465.             fwrite($f, $this->buffer, strlen($this->buffer));
  2466.             fclose($f);
  2467.         } // end if... else if... else
  2468.     } // end of the "Output()" method
  2469.  
  2470. } // End of the "FPDF" class
  2471.  
  2472.  
  2473.  
  2474. /**
  2475.  * Handles silly IE contype request
  2476.  */
  2477. if (!empty($_ENV) && isset($_ENV['HTTP_USER_AGENT'])) {
  2478.     $HTTP_USER_AGENT = $_ENV['HTTP_USER_AGENT'];
  2479. }
  2480. else if (!empty($_SERVER) && isset($_SERVER['HTTP_USER_AGENT'])) {
  2481.     $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
  2482. }
  2483. else if (@getenv('HTTP_USER_AGENT')) {
  2484.     $HTTP_USER_AGENT = getenv('HTTP_USER_AGENT');
  2485. }
  2486.  
  2487. if ($HTTP_USER_AGENT == 'contype') {
  2488.     header('Content-Type: application/pdf');
  2489.     exit();
  2490. }
  2491. ?>