File_PDF
[ class tree: File_PDF ] [ index: File_PDF ] [ all elements ]

Source for file PDF.php

Documentation is available at PDF.php

  1. <?php
  2. /**
  3.  * File_PDF::
  4.  *
  5.  * The File_PDF:: class provides a PHP-only implementation of a PDF library.
  6.  * No external libs or PHP extensions are required.
  7.  *
  8.  * Based on the FPDF class by Olivier Plathey (http://www.fpdf.org).
  9.  *
  10.  * Copyright 2003-2005 Olivier Plathey <olivier@fpdf.org>
  11.  * Copyright 2003-2005 Marko Djukic <marko@oblo.com>
  12.  *
  13.  * See the enclosed file COPYING for license information (LGPL). If you did not
  14.  * receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  15.  *
  16.  * $Horde: framework/File_PDF/PDF.php,v 1.24 2005/03/04 15:11:18 jan Exp $
  17.  *
  18.  * @author  Olivier Plathey <olivier@fpdf.org>
  19.  * @author  Marko Djukic <marko@oblo.com>
  20.  * @package File_PDF
  21.  */
  22. class File_PDF {
  23.  
  24.     /**
  25.      * Current page number.
  26.      *
  27.      * @var $_page int
  28.      */
  29.     var $_page = 0;
  30.  
  31.     /**
  32.      * Current object number.
  33.      *
  34.      * @var $_n int
  35.      */
  36.     var $_n = 2;
  37.  
  38.     /**
  39.      * Array of object offsets.
  40.      *
  41.      * @var $_offsets array
  42.      */
  43.     var $_offsets = array();
  44.  
  45.     /**
  46.      * Buffer holding in-memory PDF.
  47.      *
  48.      * @var $_buffer string
  49.      */
  50.     var $_buffer '';
  51.  
  52.     /**
  53.      * Array containing the pages.
  54.      *
  55.      * @var $_pages array
  56.      */
  57.     var $_pages = array();
  58.  
  59.     /**
  60.      * Current document state.
  61.      *   0 - initial state
  62.      *   1 - document opened
  63.      *   2 - page opened
  64.      *   3 - document closed
  65.      *
  66.      * @var $_state int
  67.      */
  68.     var $_state = 0;
  69.  
  70.     /**
  71.      * Flag indicating if PDF file is to be compressed or not.
  72.      *
  73.      * @var $_compress bool
  74.      */
  75.     var $_compress;
  76.  
  77.     /**
  78.      * The default page orientation.
  79.      *
  80.      * @var $_default_orientation string
  81.      */
  82.     var $_default_orientation;
  83.  
  84.     /**
  85.      * The current page orientation.
  86.      *
  87.      * @var $_current_orientation string
  88.      */
  89.     var $_current_orientation;
  90.  
  91.     /**
  92.      * Array indicating orientation changes.
  93.      *
  94.      * @var $_orientation_changes array
  95.      */
  96.     var $_orientation_changes = array();
  97.  
  98.     /**
  99.      * Current dimensions of page format in points.
  100.      *
  101.      * @var $fwPt float
  102.      * @var $fhPt float
  103.      */
  104.     var $fwPt$fhPt;
  105.  
  106.     /**
  107.      * Current dimensions of page format in user units.
  108.      *
  109.      * @var $fw; 
  110.      * @var $fh; 
  111.      */
  112.     var $fw$fh;
  113.  
  114.     /**
  115.      * Current dimensions of page in points.
  116.      *
  117.      * @var $wPt; 
  118.      * @var $hPt; 
  119.      */
  120.     var $wPt$hPt;
  121.  
  122.     /**
  123.      * Current dimensions of page in user units
  124.      *
  125.      * @var $w; 
  126.      * @var $h; 
  127.      */
  128.     var $w$h;
  129.  
  130.     /**
  131.      * Scale factor (number of points in user units).
  132.      *
  133.      * @var $_scale float
  134.      */
  135.     var $_scale;
  136.  
  137.     /**
  138.      * Left page margin size.
  139.      *
  140.      * @var $_left_margin float
  141.      */
  142.     var $_left_margin;
  143.  
  144.     /**
  145.      * Top page margin size.
  146.      *
  147.      * @var $_top_margin float
  148.      */
  149.     var $_top_margin;
  150.  
  151.     /**
  152.      * Right page margin size.
  153.      *
  154.      * @var $_right_margin float
  155.      */
  156.     var $_right_margin;
  157.  
  158.     /**
  159.      * Break page margin size, the bottom margin which triggers a page break.
  160.      *
  161.      * @var $_break_margin float
  162.      */
  163.     var $_break_margin;
  164.  
  165.     /**
  166.      * Cell margin size.
  167.      *
  168.      * @var $_cell_margin float
  169.      */
  170.     var $_cell_margin;
  171.  
  172.     /**
  173.      * The current horizontal and vertical position for cell positioning.
  174.      * Value is set in user units and is calculated from the top left corner
  175.      * as origin.
  176.      *
  177.      * @var $x float
  178.      * @var $y float
  179.      */
  180.     var $x$y;
  181.  
  182.     /**
  183.      * The height of the last cell printed.
  184.      *
  185.      * @var $_last_height float
  186.      */
  187.     var $_last_height;
  188.  
  189.     /**
  190.      * Line width in user units.
  191.      *
  192.      * @var $_line_width float
  193.      */
  194.     var $_line_width;
  195.  
  196.     /**
  197.      * An array of standard font names.
  198.      *
  199.      * @var $_core_fonts array
  200.      */
  201.     var $_core_fonts = array('courier'      => 'Courier',
  202.                              'courierB'     => 'Courier-Bold',
  203.                              'courierI'     => 'Courier-Oblique',
  204.                              'courierBI'    => 'Courier-BoldOblique',
  205.                              'helvetica'    => 'Helvetica',
  206.                              'helveticaB'   => 'Helvetica-Bold',
  207.                              'helveticaI'   => 'Helvetica-Oblique',
  208.                              'helveticaBI'  => 'Helvetica-BoldOblique',
  209.                              'times'        => 'Times-Roman',
  210.                              'timesB'       => 'Times-Bold',
  211.                              'timesI'       => 'Times-Italic',
  212.                              'timesBI'      => 'Times-BoldItalic',
  213.                              'symbol'       => 'Symbol',
  214.                              'zapfdingbats' => 'ZapfDingbats');
  215.  
  216.     /**
  217.      * An array of used fonts.
  218.      *
  219.      * @var $_fonts array
  220.      */
  221.     var $_fonts = array();
  222.  
  223.     /**
  224.      * An array of font files.
  225.      *
  226.      * @var $_font_files array
  227.      */
  228.     var $_font_files = array();
  229.  
  230.     /**
  231.      * An array of encoding differences.
  232.      *
  233.      * @var $_diffs array
  234.      */
  235.     var $_diffs = array();
  236.  
  237.     /**
  238.      * An array of used images.
  239.      *
  240.      * @var $_images array
  241.      */
  242.     var $_images = array();
  243.  
  244.     /**
  245.      * An array of links in pages.
  246.      *
  247.      * @var $_page_links array
  248.      */
  249.     var $_page_links;
  250.  
  251.     /**
  252.      * An array of internal links.
  253.      *
  254.      * @var $_links array
  255.      */
  256.     var $_links = array();
  257.  
  258.     /**
  259.      * Current font family.
  260.      *
  261.      * @var $_font_family string
  262.      */
  263.     var $_font_family '';
  264.  
  265.     /**
  266.      * Current font style.
  267.      *
  268.      * @var $_font_style string
  269.      */
  270.     var $_font_style '';
  271.  
  272.     /**
  273.      * Underlining flag.
  274.      *
  275.      * @var $_underline bool
  276.      */
  277.     var $_underline = false;
  278.  
  279.     /**
  280.      * An array containing current font info.
  281.      *
  282.      * @var $_current_font array
  283.      */
  284.     var $_current_font;
  285.  
  286.     /**
  287.      * Current font size in points.
  288.      *
  289.      * @var $_font_size_pt float
  290.      */
  291.     var $_font_size_pt = 12;
  292.  
  293.     /**
  294.      * Current font size in user units.
  295.      *
  296.      * @var $_font_size float
  297.      */
  298.     var $_font_size;
  299.  
  300.     /**
  301.      * Commands for filling color.
  302.      *
  303.      * @var $_fill_color string
  304.      */
  305.     var $_fill_color '0 g';
  306.  
  307.     /**
  308.      * Commands for drawing color.
  309.      *
  310.      * @var $_draw_color string
  311.      */
  312.     var $_draw_color '0 G';
  313.  
  314.     /**
  315.      * Word spacing.
  316.      *
  317.      * @var $_word_spacing int
  318.      */
  319.     var $_word_spacing = 0;
  320.  
  321.     /**
  322.      * Automatic page breaking.
  323.      *
  324.      * @var $_auto_page_break bool
  325.      */
  326.     var $_auto_page_break;
  327.  
  328.     /**
  329.      * Threshold used to trigger page breaks.
  330.      *
  331.      * @var $_page_break_trigger float
  332.      */
  333.     var $_page_break_trigger;
  334.  
  335.     /**
  336.      * Flag set when processing footer.
  337.      *
  338.      * @var $_in_footer bool
  339.      */
  340.     var $_in_footer = false;
  341.  
  342.     /**
  343.      * Zoom display mode.
  344.      *
  345.      * @var $_zoom_mode string
  346.      */
  347.     var $_zoom_mode;
  348.  
  349.     /**
  350.      * Layout display mode.
  351.      *
  352.      * @var $_layout_mode string
  353.      */
  354.     var $_layout_mode;
  355.  
  356.     /**
  357.      * An array containing the document info, consisting of:
  358.      *   - title
  359.      *   - subject
  360.      *   - author
  361.      *   - keywords
  362.      *   - creator
  363.      *
  364.      * @var $_info array
  365.      */
  366.     var $_info = array();
  367.  
  368.     /**
  369.      * Alias for total number of pages.
  370.      *
  371.      * @var $_alias_nb_pages string
  372.      */
  373.     var $_alias_nb_pages '{nb}';
  374.  
  375.     /**
  376.      * Attempts to return a conrete PDF instance. It allows to set up the page
  377.      * format, the orientation and the units of measurement used in all the
  378.      * methods (except for the font sizes).
  379.      *
  380.      * Example:
  381.      * $pdf = &File_PDF::factory(array('orientation' => 'P',
  382.      *                                 'unit' => 'mm',
  383.      *                                 'format' => 'A4'));
  384.      *
  385.      * @access public
  386.      *
  387.      * @param array $params  A hash with parameters for the created PDF object.
  388.      *                        Possible parameters are:
  389.      *                        orientation - Default page orientation. Possible
  390.      *                        values are (case insensitive):
  391.      *                        <pre>
  392.      *                          - P or Portrait (default)
  393.      *                          - L or Landscape
  394.      *                        </pre>
  395.      *                        unit - User measure units. Possible values values
  396.      *                        are:
  397.      *                        <pre>
  398.      *                          - pt: point
  399.      *                          - mm: millimeter (default)
  400.      *                          - cm: centimeter
  401.      *                          - in: inch
  402.      *                        </pre>
  403.      *                        A point equals 1/72 of inch, that is to say about
  404.      *                        0.35 mm (an inch being 2.54 cm). This is a very
  405.      *                        common unit in typography; font sizes are
  406.      *                        expressed in that unit.
  407.      *                        format - The format used for pages. It can be
  408.      *                        either one of the following values (case
  409.      *                        insensitive):
  410.      *                        <pre>
  411.      *                          - A3
  412.      *                          - A4 (default)
  413.      *                          - A5
  414.      *                          - Letter
  415.      *                          - Legal
  416.      *                        </pre>
  417.      *                        or a custom format in the form of a two-element
  418.      *                        array containing the width and the height
  419.      *                        (expressed in the unit given by the unit
  420.      *                        parameter).
  421.      * @param string $class  The concrete class name to return an instance of.
  422.      *                        Defaults to File_PDF.
  423.      */
  424.     function &factory($params = array()$class 'File_PDF')
  425.     {
  426.         /* Check for PHP locale-related bug. */
  427.         if (1.1 == 1{
  428.             return File_PDF::raiseError('Do not alter the locale before including the class file.');
  429.         }
  430.  
  431.         /* Default parameters. */
  432.         $defaults = array('orientation' => 'P''unit' => 'mm''format' => 'A4');
  433.  
  434.         /* Backward compatibility with old method signature. */
  435.         /* Should be removed a few versions later. */
  436.         if (!is_array($params)) {
  437.             $class 'File_PDF';
  438.             $params $defaults;
  439.             $names array_keys($defaults);
  440.             for ($i = 0; $i func_num_args()$i++{
  441.                 $params[$names[$i]] func_get_arg($i);
  442.             }
  443.         else {
  444.             $params array_merge($defaults$params);
  445.         }
  446.  
  447.         /* Create the PDF object. */
  448.         $pdf &new $class();
  449.  
  450.         /* Scale factor. */
  451.         if ($params['unit'== 'pt'{
  452.             $pdf->_scale = 1;
  453.         elseif ($params['unit'== 'mm'{
  454.             $pdf->_scale = 72 / 25.4;
  455.         elseif ($params['unit'== 'cm'{
  456.             $pdf->_scale = 72 / 2.54;
  457.         elseif ($params['unit'== 'in'{
  458.             $pdf->_scale = 72;
  459.         else {
  460.             return File_PDF::raiseError(sprintf('Incorrect units: %s'$params['unit']));
  461.         }
  462.         /* Page format. */
  463.         if (is_string($params['format'])) {
  464.             $params['format'strtolower($params['format']);
  465.             if ($params['format'== 'a3'{
  466.                 $params['format'= array(841.891190.55);
  467.             elseif ($params['format'== 'a4'{
  468.                 $params['format'= array(595.28841.89);
  469.             elseif ($params['format'== 'a5'{
  470.                 $params['format'= array(420.94595.28);
  471.             elseif ($params['format'== 'letter'{
  472.                 $params['format'= array(612792);
  473.             elseif ($params['format'== 'legal'{
  474.                 $params['format'= array(6121008);
  475.             else {
  476.                 return File_PDF::raiseError(sprintf('Unknown page format: %s'$params['format']));
  477.             }
  478.             $pdf->fwPt = $params['format'][0];
  479.             $pdf->fhPt = $params['format'][1];
  480.         else {
  481.             $pdf->fwPt = $params['format'][0$pdf->_scale;
  482.             $pdf->fhPt = $params['format'][1$pdf->_scale;
  483.         }
  484.         $pdf->fw = $pdf->fwPt / $pdf->_scale;
  485.         $pdf->fh = $pdf->fhPt / $pdf->_scale;
  486.  
  487.         /* Page orientation. */
  488.         $params['orientation'strtolower($params['orientation']);
  489.         if ($params['orientation'== 'p' || $params['orientation'== 'portrait'{
  490.             $pdf->_default_orientation = 'P';
  491.             $pdf->wPt = $pdf->fwPt;
  492.             $pdf->hPt = $pdf->fhPt;
  493.         elseif ($params['orientation'== 'l' || $params['orientation'== 'landscape'{
  494.             $pdf->_default_orientation = 'L';
  495.             $pdf->wPt = $pdf->fhPt;
  496.             $pdf->hPt = $pdf->fwPt;
  497.         else {
  498.             return File_PDF::raiseError(sprintf('Incorrect orientation: %s'$params['orientation']));
  499.         }
  500.         $pdf->_current_orientation = $pdf->_default_orientation;
  501.         $pdf->w = $pdf->wPt / $pdf->_scale;
  502.         $pdf->h = $pdf->hPt / $pdf->_scale;
  503.  
  504.         /* Page margins (1 cm) */
  505.         $margin = 28.35 / $pdf->_scale;
  506.         $pdf->setMargins($margin$margin);
  507.  
  508.         /* Interior cell margin (1 mm) */
  509.         $pdf->_cell_margin = $margin / 10;
  510.  
  511.         /* Line width (0.2 mm) */
  512.         $pdf->_line_width = .567 / $pdf->_scale;
  513.  
  514.         /* Automatic page break */
  515.         $pdf->setAutoPageBreak(true2 * $margin);
  516.  
  517.         /* Full width display mode */
  518.         $pdf->setDisplayMode('fullwidth');
  519.  
  520.         /* Compression */
  521.         $pdf->setCompression(true);
  522.  
  523.         return $pdf;
  524.     }
  525.  
  526.     /**
  527.      * Returns a PEAR_Error object. Wraps around PEAR::raiseError() to
  528.      * avoid having to include PEAR.php unless an error occurs.
  529.      *
  530.      * @param mixed $error  The error message.
  531.      *
  532.      * @return object PEAR_Error 
  533.      */
  534.     function raiseError($error)
  535.     {
  536.         require_once 'PEAR.php';
  537.         return PEAR::raiseError($error);
  538.     }
  539.  
  540.     /**
  541.      * Defines the left, top and right margins. By default, they equal
  542.      * 1 cm.  Call this method to change them.
  543.      *
  544.      * @access public
  545.      *
  546.      * @param float $left            Left margin.
  547.      * @param float $top             Top margin.
  548.      * @param optional float $right  Right margin. If not specified default to
  549.      *                                the value of the left one.
  550.      *
  551.      * @see File_PDF::setAutoPageBreak
  552.      * @see File_PDF::setLeftMargin
  553.      * @see File_PDF::setRightMargin
  554.      * @see File_PDF::setTopMargin
  555.      */
  556.     function setMargins($left$top$right = null)
  557.     {
  558.         /* Set left and top margins. */
  559.         $this->_left_margin  $left;
  560.         $this->_top_margin   $top;
  561.         /* If no right margin set default to same as left. */
  562.         $this->_right_margin (is_null($right$left $right);
  563.     }
  564.  
  565.     /**
  566.      * Defines the left margin. The method can be called before creating the
  567.      * first page.
  568.      * If the current abscissa gets out of page, it is brought back to the
  569.      * margin.
  570.      *
  571.      * @access public
  572.      *
  573.      * @param float $margin   The margin.
  574.      *
  575.      * @see File_PDF::setAutoPageBreak
  576.      * @see File_PDF::setMargins
  577.      * @see File_PDF::setRightMargin
  578.      * @see File_PDF::setTopMargin
  579.      */
  580.     function setLeftMargin($margin)
  581.     {
  582.         $this->_left_margin $margin;
  583.         /* If there is a current page and the current X position is less than
  584.          * margin set the X position to the margin value. */
  585.         if ($this->_page > 0 && $this->x < $margin{
  586.             $this->x = $margin;
  587.         }
  588.     }
  589.  
  590.     /**
  591.      * Defines the top margin. The method can be called before creating the
  592.      * first page.
  593.      *
  594.      * @access public
  595.      *
  596.      * @param float $margin  The margin.
  597.      */
  598.     function setTopMargin($margin)
  599.     {
  600.         $this->_top_margin $margin;
  601.     }
  602.  
  603.     /**
  604.      * Defines the right margin. The method can be called before creating the
  605.      * first page.
  606.      *
  607.      * @access public
  608.      *
  609.      * @param float $margin  The margin.
  610.      */
  611.     function setRightMargin($margin)
  612.     {
  613.         $this->_right_margin $margin;
  614.     }
  615.  
  616.     /**
  617.      * Enables or disables the automatic page breaking mode. When enabling,
  618.      * the second parameter is the distance from the bottom of the page that
  619.      * defines the triggering limit. By default, the mode is on and the margin
  620.      * is 2 cm.
  621.      *
  622.      * @access public
  623.      *
  624.      * @param bool auto               Boolean indicating if mode should be on
  625.      *                                 or off.
  626.      * @param optional float $margin  Distance from the bottom of the page.
  627.      */
  628.     function setAutoPageBreak($auto$margin = 0)
  629.     {
  630.         $this->_auto_page_break    $auto;
  631.         $this->_break_margin       $margin;
  632.         $this->_page_break_trigger $this->h - $margin;
  633.     }
  634.  
  635.     /**
  636.      * Defines the way the document is to be displayed by the viewer. The zoom
  637.      * level can be set: pages can be displayed entirely on screen, occupy the
  638.      * full width of the window, use real size, be scaled by a specific
  639.      * zooming factor or use viewer default (configured in the Preferences
  640.      * menu of Acrobat). The page layout can be specified too: single at once,
  641.      * continuous display, two columns or viewer default.
  642.      * By default, documents use the full width mode with continuous display.
  643.      *
  644.      * @access public
  645.      *
  646.      * @param mixed $zoom             The zoom to use. It can be one of the
  647.      *                                 following string values:
  648.      *                                   - fullpage: entire page on screen
  649.      *                                   - fullwidth: maximum width of window
  650.      *                                   - real: uses real size (100% zoom)
  651.      *                                   - default: uses viewer default mode
  652.      *                                 or a number indicating the zooming factor.
  653.      * @param optional string layout  The page layout. Possible values are:
  654.      *                                   - single: one page at once
  655.      *                                   - continuous: pages in continuously
  656.      *                                   - two: two pages on two columns
  657.      *                                   - default: uses viewer default mode
  658.      *                                   Default value is continuous.
  659.      */
  660.     function setDisplayMode($zoom$layout 'continuous')
  661.     {
  662.         $zoom strtolower($zoom);
  663.         if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real'
  664.             || $zoom == 'default' || !is_string($zoom)) {
  665.             $this->_zoom_mode $zoom;
  666.         elseif ($zoom == 'zoom'{
  667.             $this->_zoom_mode $layout;
  668.         else {
  669.             return $this->raiseError(sprintf('Incorrect zoom display mode: %s'$zoom));
  670.         }
  671.  
  672.         $layout strtolower($layout);
  673.         if ($layout == 'single' || $layout == 'continuous' || $layout == 'two'
  674.             || $layout == 'default'{
  675.             $this->_layout_mode $layout;
  676.         elseif ($zoom != 'zoom'{
  677.             return $this->raiseError(sprintf('Incorrect layout display mode: %s'$layout));
  678.         }
  679.     }
  680.  
  681.     /**
  682.      * Activates or deactivates page compression. When activated, the internal
  683.      * representation of each page is compressed, which leads to a compression
  684.      * ratio of about 2 for the resulting document.
  685.      * Compression is on by default.
  686.      * Note: the Zlib extension is required for this feature. If not present,
  687.      * compression will be turned off.
  688.      *
  689.      * @param bool $compress  Boolean indicating if compression must be
  690.      *                         enabled or not.
  691.      */
  692.     function setCompression($compress)
  693.     {
  694.         /* If no gzcompress function is available then default to false. */
  695.         $this->_compress (function_exists('gzcompress'$compress : false);
  696.     }
  697.  
  698.     /**
  699.      * Set the info to a document. Possible info settings are:
  700.      *   - title
  701.      *   - subject
  702.      *   - author
  703.      *   - keywords
  704.      *   - creator
  705.      *
  706.      * @param mixed $info             If passed as an array then the complete
  707.      *                                 hash containing the info to be inserted
  708.      *                                 into the document. Otherwise the name of
  709.      *                                 setting to be set.
  710.      * @param optional string $value  The value of the setting.
  711.      */
  712.     function setInfo($info$value '')
  713.     {
  714.         if (is_array($info)) {
  715.             $this->_info $info;
  716.         else {
  717.             $this->_info[$info$value;
  718.         }
  719.     }
  720.  
  721.     /**
  722.      * Defines an alias for the total number of pages. It will be substituted
  723.      * as the document is closed.
  724.      *
  725.      * Example:
  726.      * class My_File_PDF extends File_PDF {
  727.      *     function footer()
  728.      *     {
  729.      *         // Go to 1.5 cm from bottom
  730.      *         $this->setY(-15);
  731.      *         // Select Arial italic 8
  732.      *         $this->setFont('Arial', 'I', 8);
  733.      *         // Print current and total page numbers
  734.      *         $this->cell(0, 10, 'Page ' . $this->getPageNo() . '/{nb}', 0,
  735.      *                     0, 'C');
  736.      *     }
  737.      * }
  738.      * $pdf = &My_File_PDF::factory();
  739.      * $pdf->aliasNbPages();
  740.      *
  741.      * @access public
  742.      *
  743.      * @param optional string $alias  The alias. Default value: {nb}.
  744.      *
  745.      * @see File_PDF::getPageNo
  746.      * @see File_PDF::footer
  747.      */
  748.     function aliasNbPages($alias '{nb}')
  749.     {
  750.         $this->_alias_nb_pages $alias;
  751.     }
  752.  
  753.     /**
  754.      * This method begins the generation of the PDF document; it must be
  755.      * called before any output commands. No page is created by this method,
  756.      * therefore it is necessary to call File_PDF::addPage.
  757.      *
  758.      * @access public
  759.      *
  760.      * @see File_PDF::addPage
  761.      * @see File_PDF::close
  762.      */
  763.     function open()
  764.     {
  765.         $this->_beginDoc();
  766.     }
  767.  
  768.     /**
  769.      * Terminates the PDF document. It is not necessary to call this method
  770.      * explicitly because File_PDF::output does it automatically.
  771.      * If the document contains no page, File_PDF::addPage is called to prevent
  772.      * from getting an invalid document.
  773.      *
  774.      * @access public
  775.      *
  776.      * @see File_PDF::open
  777.      * @see File_PDF::output
  778.      */
  779.     function close()
  780.     {
  781.         /* Terminate document */
  782.         if ($this->_page == 0{
  783.             $this->addPage();
  784.         }
  785.         /* Page footer */
  786.         $this->_in_footer = true;
  787.         $this->footer();
  788.         $this->_in_footer = false;
  789.         /* Close page */
  790.         $this->_endPage();
  791.         /* Close document */
  792.         $this->_endDoc();
  793.     }
  794.  
  795.     /**
  796.      * Adds a new page to the document. If a page is already present, the
  797.      * File_PDF::footer method is called first to output the footer. Then the
  798.      * page is added, the current position set to the top-left corner according
  799.      * to the left and top margins, and File_PDF::header is called to display
  800.      * the header.
  801.      * The font which was set before calling is automatically restored. There
  802.      * is no need to call File_PDF::setFont again if you want to continue with
  803.      * the same font. The same is true for colors and line width.
  804.      * The origin of the coordinate system is at the top-left corner and
  805.      * increasing ordinates go downwards.
  806.      *
  807.      * @access public
  808.      *
  809.      * @param optional string $orientation  Page orientation. Possible values
  810.      *                                       are (case insensitive):
  811.      *                                         - P or Portrait
  812.      *                                         - L or Landscape
  813.      *                                       The default value is the one
  814.      *                                       passed to the constructor.
  815.      *
  816.      * @see File_PDF::PDF
  817.      * @see File_PDF::header
  818.      * @see File_PDF::footer
  819.      * @see File_PDF::setMargins
  820.      */
  821.     function addPage($orientation '')
  822.     {
  823.         $style $this->_font_style ($this->_underline 'U' '');
  824.         $size  $this->_font_size_pt;
  825.         $lw $this->_line_width;
  826.         $dc $this->_draw_color;
  827.         $fc $this->_fill_color;
  828.         if ($this->_page > 0{
  829.             /* Page footer. */
  830.             $this->_in_footer = true;
  831.             $this->footer();
  832.             $this->_in_footer = false;
  833.             /* Close page. */
  834.             $this->_endPage();
  835.         }
  836.         /* Start new page. */
  837.         $this->_beginPage($orientation);
  838.         /* Set line cap style to square. */
  839.         $this->_out('2 J');
  840.         /* Set line width. */
  841.         $this->_line_width $lw;
  842.         $this->_out(sprintf('%.2f w'$lw $this->_scale));
  843.         /* Set font. */
  844.         if ($this->_font_family{
  845.             $this->setFont($this->_font_family$style$this->_font_size_pt);
  846.         }
  847.         /* Set colors. */
  848.         $this->_fill_color $fc;
  849.         /* Check if fill color has been set before this page. */
  850.         if ($this->_fill_color != '0 g'{
  851.             $this->_out($this->_fill_color);
  852.         }
  853.         $this->_draw_color $dc;
  854.         /* Check if draw color has been set before this page. */
  855.         if ($this->_draw_color != '0 G'{
  856.             $this->_out($this->_draw_color);
  857.         }
  858.         /* Page header. */
  859.         $this->header();
  860.         /* Restore line width. */
  861.         if ($this->_line_width != $lw{
  862.             $this->_line_width $lw;
  863.             $this->_out(sprintf('%.2f w'$lw $this->_scale));
  864.         }
  865.         /* Restore font. */
  866.         if ($this->_font_family{
  867.             $this->setFont($this->_font_family$style$this->_font_size_pt);
  868.         }
  869.         /* Restore colors. */
  870.         if ($this->_draw_color != $dc{
  871.             $this->_draw_color $dc;
  872.             $this->_out($dc);
  873.         }
  874.         if ($this->_fill_color != $fc{
  875.             $this->_fill_color $fc;
  876.             $this->_out($fc);
  877.         }
  878.     }
  879.  
  880.     /**
  881.      * This method is used to render the page header. It is automatically
  882.      * called by File_PDF::addPage and should not be called directly by the
  883.      * application. The implementation in File_PDF:: is empty, so you have to
  884.      * subclass it and override the method if you want a specific processing.
  885.      *
  886.      * Example:
  887.      *
  888.      * class My_File_PDF extends File_PDF {
  889.      *     function header()
  890.      *     {
  891.      *         // Select Arial bold 15
  892.      *         $this->setFont('Arial', 'B', 15);
  893.      *         // Move to the right
  894.      *         $this->cell(80);
  895.      *         // Framed title
  896.      *         $this->cell(30, 10, 'Title', 1, 0, 'C');
  897.      *         // Line break
  898.      *         $this->newLine(20);
  899.      *     }
  900.      * }
  901.      *
  902.      * @access public
  903.      *
  904.      * @see File_PDF::footer
  905.      */
  906.     function header()
  907.     {
  908.         /* To be implemented in your own inherited class. */
  909.     }
  910.  
  911.     /**
  912.      * This method is used to render the page footer. It is automatically
  913.      * called by File_PDF::addPage and File_PDF::close and should not be called
  914.      * directly by the application. The implementation in File_PDF:: is empty,
  915.      * so you have to subclass it and override the method if you want a specific
  916.      * processing.
  917.      *
  918.      * Example:
  919.      *
  920.      * class My_File_PDF extends File_PDF {
  921.      *    function footer()
  922.      *    {
  923.      *        // Go to 1.5 cm from bottom
  924.      *        $this->setY(-15);
  925.      *        // Select Arial italic 8
  926.      *        $this->setFont('Arial', 'I', 8);
  927.      *        // Print centered page number
  928.      *        $this->cell(0, 10, 'Page ' . $this->getPageNo(), 0, 0, 'C');
  929.      *    }
  930.      * }
  931.      *
  932.      * @access public
  933.      *
  934.      * @see File_PDF::header
  935.      */
  936.     function footer()
  937.     {
  938.         /* To be implemented in your own inherited class. */
  939.     }
  940.  
  941.     /**
  942.      * Returns the current page number.
  943.      *
  944.      * @access public
  945.      *
  946.      * @return int 
  947.      *
  948.      * @see File_PDF::aliasNbPages
  949.      */
  950.     function getPageNo()
  951.     {
  952.         return $this->_page;
  953.     }
  954.  
  955.     /**
  956.      * Sets the fill color. Specifies the color for both filled areas and
  957.      * text. Depending on the colorspace called, the number of color component
  958.      * parameters required can be either 1, 3 or 4. The method can be called
  959.      * before the first page is created and the color is retained from page to
  960.      * page.
  961.      *
  962.      * @access public
  963.      *
  964.      * @param string $cs          Indicates the colorspace which can be either
  965.      *                             'rgb', 'cmyk' or 'gray'. Defaults to 'rgb'.
  966.      * @param float $c1           First color component, floating point value
  967.      *                             between 0 and 1. Required for gray, rgb and
  968.      *                             cmyk.
  969.      * @param optional float $c2  Second color component, floating point value
  970.      *                             between 0 and 1. Required for rgb and cmyk.
  971.      * @param optional float $c3  Third color component, floating point value
  972.      *                             between 0 and 1. Required for rgb and cmyk.
  973.      * @param optional float $c4  Fourth color component, floating point value
  974.      *                             between 0 and 1. Required for cmyk.
  975.      *
  976.      * @see File_PDF::setDrawColor
  977.      * @see File_PDF::rect
  978.      * @see File_PDF::cell
  979.      * @see File_PDF::multiCell
  980.      */
  981.     function setFillColor($cs 'rgb'$c1$c2 = 0$c3 = 0$c4 = 0)
  982.     {
  983.         $cs strtolower($cs);
  984.         if ($cs == 'rgb'{
  985.             $this->_fill_color sprintf('%.3f %.3f %.3f rg'$c1$c2$c3);
  986.         elseif ($cs == 'cmyk'{
  987.             $this->_fill_color sprintf('%.3f %.3f %.3f %.3f k'$c1$c2$c3$c4);
  988.         else {
  989.             $this->_fill_color sprintf('%.3f g'$c1);
  990.         }
  991.         if ($this->_page > 0{
  992.             $this->_out($this->_fill_color);
  993.         }
  994.     }
  995.  
  996.     /**
  997.      * Sets the draw color, used when drawing lines. Depending on the
  998.      * colorspace called, the number of color component parameters required
  999.      * can be either 1, 3 or 4. The method can be called before the first page
  1000.      * is created and the color is retained from page to page.
  1001.      *
  1002.      * @access public
  1003.      *
  1004.      * @param string $cs          Indicates the colorspace which can be either
  1005.      *                             'rgb', 'cmyk' or 'gray'. Defaults to 'rgb'.
  1006.      * @param float $c1           First color component, floating point value
  1007.      *                             between 0 and 1. Required for gray, rgb and
  1008.      *                             cmyk.
  1009.      * @param optional float $c2  Second color component, floating point value
  1010.      *                             between 0 and 1. Required for rgb and cmyk.
  1011.      * @param optional float $c3  Third color component, floating point value
  1012.      *                             between 0 and 1. Required for rgb and cmyk.
  1013.      * @param optional float $c4  Fourth color component, floating point value
  1014.      *                             between 0 and 1. Required for cmyk.
  1015.      *
  1016.      * @see File_PDF::setFillColor
  1017.      * @see File_PDF::line
  1018.      * @see File_PDF::rect
  1019.      * @see File_PDF::cell
  1020.      * @see File_PDF::multiCell
  1021.      */
  1022.     function setDrawColor($cs 'rgb'$c1$c2 = 0$c3 = 0$c4 = 0)
  1023.     {
  1024.         $cs strtolower($cs);
  1025.         if ($cs == 'rgb'{
  1026.             $this->_draw_color sprintf('%.3f %.3f %.3f RG'$c1$c2$c3);
  1027.         elseif ($cs == 'cmyk'{
  1028.             $this->_draw_color sprintf('%.3f %.3f %.3f %.3f K'$c1$c2$c3$c4);
  1029.         else {
  1030.             $this->_draw_color sprintf('%.3f G'$c1);
  1031.         }
  1032.         if ($this->_page > 0{
  1033.             $this->_out($this->_draw_color);
  1034.         }
  1035.     }
  1036.  
  1037.     /**
  1038.      * Returns the length of a text string. A font must be selected.
  1039.      *
  1040.      * @access public
  1041.      *
  1042.      * @param string $text       The text whose length is to be computed.
  1043.      * @param optional bool $pt  Boolean to indicate if the width should be
  1044.      *                            returned in points or user unit. Default false.
  1045.      *
  1046.      * @return float 
  1047.      */
  1048.     function getStringWidth($text$pt = false)
  1049.     {
  1050.         $text = (string)$text;
  1051.         $width = 0;
  1052.         $length strlen($text);
  1053.         for ($i = 0; $i $length$i++{
  1054.             $width += $this->_current_font['cw'][$text{$i}];
  1055.         }
  1056.  
  1057.         /* Adjust for word spacing. */
  1058.         $width += $this->_word_spacing substr_count($text' '$this->_current_font['cw'][' '];
  1059.  
  1060.         if ($pt{
  1061.             return $width $this->_font_size_pt / 1000;
  1062.         else {
  1063.             return $width $this->_font_size / 1000;
  1064.         }
  1065.     }
  1066.  
  1067.     /**
  1068.      * Defines the line width. By default, the value equals 0.2 mm. The method
  1069.      * can be called before the first page is created and the value is
  1070.      * retained from page to page.
  1071.      *
  1072.      * @access public
  1073.      *
  1074.      * @param float $width  The width.
  1075.      *
  1076.      * @see File_PDF::line
  1077.      * @see File_PDF::rect
  1078.      * @see File_PDF::cell
  1079.      * @see File_PDF::multiCell
  1080.      */
  1081.     function setLineWidth($width)
  1082.     {
  1083.         $this->_line_width $width;
  1084.         if ($this->_page > 0{
  1085.             $this->_out(sprintf('%.2f w'$width $this->_scale));
  1086.         }
  1087.     }
  1088.  
  1089.     /**
  1090.      * Draws a line between two points.
  1091.      *
  1092.      * @access public
  1093.      *
  1094.      * @param float $x1  Abscissa of first point.
  1095.      * @param float $y1  Ordinate of first point.
  1096.      * @param float $x2  Abscissa of second point.
  1097.      * @param float $y2  Ordinate of second point.
  1098.      *
  1099.      * @see File_PDF::setLineWidth
  1100.      * @see File_PDF::setDrawColor.
  1101.      */
  1102.     function line($x1$y1$x2$y2)
  1103.     {
  1104.         $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S'$x1 $this->_scale($this->h - $y1$this->_scale$x2 $this->_scale($this->h - $y2$this->_scale));
  1105.     }
  1106.  
  1107.     /**
  1108.      * Outputs a rectangle. It can be drawn (border only), filled (with no
  1109.      * border) or both.
  1110.      *
  1111.      * @access public
  1112.      *
  1113.      * @param float $x               Abscissa of upper-left corner.
  1114.      * @param float $y               Ordinate of upper-left corner.
  1115.      * @param float $width           Width.
  1116.      * @param float $height          Height.
  1117.      * @param optional float $style  Style of rendering. Possible values are:
  1118.      *                                  - D or empty string: draw (default)
  1119.      *                                  - F: fill
  1120.      *                                  - DF or FD: draw and fill
  1121.      *
  1122.      * @see File_PDF::setLineWidth
  1123.      * @see File_PDF::setDrawColor
  1124.      * @see File_PDF::setFillColor
  1125.      */
  1126.     function rect($x$y$width$height$style '')
  1127.     {
  1128.         $style strtoupper($style);
  1129.         if ($style == 'F'{
  1130.             $op 'f';
  1131.         elseif ($style == 'FD' || $style == 'DF'{
  1132.             $op 'B';
  1133.         else {
  1134.             $op 'S';
  1135.         }
  1136.  
  1137.         $x      $this->_toPt($x);
  1138.         $y      $this->_toPt($y);
  1139.         $width  $this->_toPt($width);
  1140.         $height $this->_toPt($height);
  1141.  
  1142.         $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s'$x$this->hPt - $y$width-$height$op));
  1143.     }
  1144.  
  1145.     /**
  1146.      * Outputs a circle. It can be drawn (border only), filled (with no
  1147.      * border) or both.
  1148.      *
  1149.      * @access public
  1150.      *
  1151.      * @param float $x                Abscissa of the center of the circle.
  1152.      * @param float $y                Ordinate of the center of the circle.
  1153.      * @param float $r                Circle radius.
  1154.      * @param optional string $style  Style of rendering. Possible values are:
  1155.      *                                   - D or empty string: draw (default)
  1156.      *                                   - F: fill
  1157.      *                                   - DF or FD: draw and fill
  1158.      */
  1159.     function circle($x$y$r$style '')
  1160.     {
  1161.         $style strtolower($style);
  1162.         if ($style == 'f'{
  1163.             $op 'f';      // Style is fill only.
  1164.         elseif ($style == 'fd' || $style == 'df'{
  1165.             $op 'B';      // Style is fill and stroke.
  1166.         else {
  1167.             $op 'S';      // Style is stroke only.
  1168.         }
  1169.  
  1170.         $x $this->_toPt($x);
  1171.         $y $this->_toPt($y);
  1172.         $r $this->_toPt($r);
  1173.  
  1174.         /* Invert the y scale. */
  1175.         $y $this->hPt - $y;
  1176.         /* Length of the Bezier control. */
  1177.         $b $r * 0.552;
  1178.  
  1179.         /* Move from the given origin and set the current point
  1180.          * to the start of the first Bezier curve. */
  1181.         $c sprintf('%.2f %.2f m'$x $r$y);
  1182.         $x $x $r;
  1183.         /* First circle quarter. */
  1184.         $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
  1185.                       $x$y $b,           // First control point.
  1186.                       $x $r $b$y $r// Second control point.
  1187.                       $x $r$y $r);     // Final point.
  1188.         /* Set x/y to the final point. */
  1189.         $x $x $r;
  1190.         $y $y $r;
  1191.         /* Second circle quarter. */
  1192.         $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
  1193.                       $x $b$y,
  1194.                       $x $r$y $r $b,
  1195.                       $x $r$y $r);
  1196.         /* Set x/y to the final point. */
  1197.         $x $x $r;
  1198.         $y $y $r;
  1199.         /* Third circle quarter. */
  1200.         $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
  1201.                       $x$y $b,
  1202.                       $x $r $b$y $r,
  1203.                       $x $r$y $r);
  1204.         /* Set x/y to the final point. */
  1205.         $x $x $r;
  1206.         $y $y $r;
  1207.         /* Fourth circle quarter. */
  1208.         $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c %s',
  1209.                       $x $b$y,
  1210.                       $x $r$y $r $b,
  1211.                       $x $r$y $r,
  1212.                       $op);
  1213.         /* Output the whole string. */
  1214.         $this->_out($c);
  1215.     }
  1216.  
  1217.     /**
  1218.      * Imports a TrueType or Type1 font and makes it available. It is
  1219.      * necessary to generate a font definition file first with the
  1220.      * makefont.php utility.
  1221.      * The location of the definition file (and the font file itself when
  1222.      * embedding) must be found at the full path name included.
  1223.      *
  1224.      * Example:
  1225.      * $pdf->addFont('Comic', 'I');
  1226.      * is equivalent to:
  1227.      * $pdf->addFont('Comic', 'I', 'comici.php');
  1228.      *
  1229.      * @access public
  1230.      *
  1231.      * @param string family          Font family. The name can be chosen
  1232.      *                                arbitrarily. If it is a standard family
  1233.      *                                name, it will override the corresponding
  1234.      *                                font.
  1235.      * @param optional $style        Font style. Possible values are (case
  1236.      *                                insensitive):
  1237.      *                                  - empty string: regular (default)
  1238.      *                                  - B: bold
  1239.      *                                  - I: italic
  1240.      *                                  - BI or IB: bold italic
  1241.      * @param optional string $file  The font definition file. By default, the
  1242.      *                                name is built from the family and style,
  1243.      *                                in lower case with no space.
  1244.      *
  1245.      * @see File_PDF::setFont
  1246.      */
  1247.     function addFont($family$style ''$file '')
  1248.     {
  1249.         $family strtolower($family);
  1250.         if ($family == 'arial'{
  1251.             $family 'helvetica';
  1252.         }
  1253.  
  1254.         $style strtoupper($style);
  1255.         if ($style == 'IB'{
  1256.             $style 'BI';
  1257.         }
  1258.         if (isset($this->_fonts[$family $style])) {
  1259.             return $this->raiseError(sprintf('Font already added: %s %s'$family$style));
  1260.         }
  1261.         if ($file == ''{
  1262.             $file str_replace(' '''$familystrtolower($style'.php';
  1263.         }
  1264.         include($file);
  1265.         if (!isset($name)) {
  1266.             return $this->raiseError('Could not include font definition file.');
  1267.         }
  1268.         $i count($this->_fonts+ 1;
  1269.         $this->_fonts[$family $style= array('i' => $i'type' => $type'name' => $name'desc' => $desc'up' => $up'ut' => $ut'cw' => $cw'enc' => $enc'file' => $file);
  1270.         if ($diff{
  1271.             /* Search existing encodings. */
  1272.             $d = 0;
  1273.             $nb count($this->_diffs);
  1274.             for ($i = 1; $i <= $nb$i++{
  1275.                 if ($this->_diffs[$i== $diff{
  1276.                     $d $i;
  1277.                     break;
  1278.                 }
  1279.             }
  1280.             if ($d == 0{
  1281.                 $d $nb + 1;
  1282.                 $this->_diffs[$d$diff;
  1283.             }
  1284.             $this->_fonts[$family.$style]['diff'$d;
  1285.         }
  1286.         if ($file{
  1287.             if ($type == 'TrueType'{
  1288.                 $this->_font_files[$file= array('length1' => $originalsize);
  1289.             else {
  1290.                 $this->_font_files[$file= array('length1' => $size1'length2' => $size2);
  1291.             }
  1292.         }
  1293.     }
  1294.  
  1295.     /**
  1296.      * Sets the font used to print character strings. It is mandatory to call
  1297.      * this method at least once before printing text or the resulting
  1298.      * document would not be valid. The font can be either a standard one or a
  1299.      * font added via the File_PDF::addFont method. Standard fonts use Windows
  1300.      * encoding cp1252 (Western Europe).
  1301.      * The method can be called before the first page is created and the font
  1302.      * is retained from page to page.
  1303.      * If you just wish to change the current font size, it is simpler to call
  1304.      * File_PDF::setFontSize.
  1305.      *
  1306.      * @access public
  1307.      *
  1308.      * @param string $family          Family font. It can be either a name
  1309.      *                                 defined by File_PDF::addFont or one of the
  1310.      *                                 standard families (case insensitive):
  1311.      *                                   - Courier (fixed-width)
  1312.      *                                   - Helvetica or Arial (sans serif)
  1313.      *                                   - Times (serif)
  1314.      *                                   - Symbol (symbolic)
  1315.      *                                   - ZapfDingbats (symbolic)
  1316.      *                                 It is also possible to pass an empty
  1317.      *                                 string. In that case, the current
  1318.      *                                 family is retained.
  1319.      * @param optional string $style  Font style. Possible values are (case
  1320.      *                                 insensitive):
  1321.      *                                   - empty string: regular
  1322.      *                                   - B: bold
  1323.      *                                   - I: italic
  1324.      *                                   - U: underline
  1325.      *                                 or any combination. The default value is
  1326.      *                                 regular. Bold and italic styles do not
  1327.      *                                 apply to Symbol and ZapfDingbats.
  1328.      * @param optional int $size      Font size in points. The default value
  1329.      *                                 is the current size. If no size has been
  1330.      *                                 specified since the beginning of the
  1331.      *                                 document, the value taken is 12.
  1332.      *
  1333.      * @see File_PDF::addFont
  1334.      * @see File_PDF::setFontSize
  1335.      * @see File_PDF::cell
  1336.      * @see File_PDF::multiCell
  1337.      * @see File_PDF::Write
  1338.      */
  1339.     function setFont($family$style ''$size = null)
  1340.     {
  1341.         $family strtolower($family);
  1342.         if ($family == 'arial'{
  1343.             /* Use helvetica instead of arial. */
  1344.             $family 'helvetica';
  1345.         elseif ($family == 'symbol' || $family == 'zapfdingbats'{
  1346.             /* These two fonts do not have styles available. */
  1347.             $style '';
  1348.         }
  1349.  
  1350.         $style strtoupper($style);
  1351.  
  1352.         /* Underline is handled separately, if specified in the style var
  1353.          * remove it from the style and set the underline flag. */
  1354.         if (strpos($style'U'!== false{
  1355.             $this->_underline = true;
  1356.             $style str_replace('U'''$style);
  1357.         else {
  1358.             $this->_underline = false;
  1359.         }
  1360.  
  1361.         if ($style == 'IB'{
  1362.             $style 'BI';
  1363.         }
  1364.  
  1365.         /* If no size specified, use current size. */
  1366.         if (is_null($size)) {
  1367.             $size $this->_font_size_pt;
  1368.         }
  1369.  
  1370.         /* If font requested is already the current font don't bother with the
  1371.          * rest of the function, simply return. */
  1372.         if ($this->_font_family == $family && $this->_font_style == $style
  1373.                 && $this->_font_size_pt == $size{
  1374.             return;
  1375.         }
  1376.  
  1377.         /* Set the font key. */
  1378.         $fontkey $family $style;
  1379.  
  1380.         /* Test if already cached. */
  1381.         if (!isset($this->_fonts[$fontkey])) {
  1382.             /* Get the character width definition file. */
  1383.             $font_widths &File_PDF::_getFontFile($fontkey);
  1384.             if (is_a($font_widths'PEAR_Error')) {
  1385.                 return $font_widths;
  1386.             }
  1387.  
  1388.             $i count($this->_fonts+ 1;
  1389.             $this->_fonts[$fontkey= array(
  1390.                 'i'    => $i,
  1391.                 'type' => 'core',
  1392.                 'name' => $this->_core_fonts[$fontkey],
  1393.                 'up'   => -100,
  1394.                 'ut'   => 50,
  1395.                 'cw'   => $font_widths[$fontkey]);
  1396.         }
  1397.  
  1398.         /* Store font information as current font. */
  1399.         $this->_font_family  $family;
  1400.         $this->_font_style   $style;
  1401.         $this->_font_size_pt $size;
  1402.         $this->_font_size    $size $this->_scale;
  1403.         $this->_current_font &$this->_fonts[$fontkey];
  1404.  
  1405.         /* Output font information if at least one page has been defined. */
  1406.         if ($this->_page > 0{
  1407.             $this->_out(sprintf('BT /F%d %.2f Tf ET'$this->_current_font['i']$this->_font_size_pt));
  1408.         }
  1409.     }
  1410.  
  1411.     /**
  1412.      * Defines the size of the current font.
  1413.      *
  1414.      * @access public
  1415.      *
  1416.      * @param float $size  The size (in points).
  1417.      *
  1418.      * @see File_PDF::setFont
  1419.      */
  1420.     function setFontSize($size)
  1421.     {
  1422.         /* If the font size is already the current font size, just return. */
  1423.         if ($this->_font_size_pt == $size{
  1424.             return;
  1425.         }
  1426.         /* Set the current font size, both in points and scaled to user
  1427.          * units. */
  1428.         $this->_font_size_pt $size;
  1429.         $this->_font_size $size $this->_scale;
  1430.  
  1431.         /* Output font information if at least one page has been defined. */
  1432.         if ($this->_page > 0{
  1433.             $this->_out(sprintf('BT /F%d %.2f Tf ET'$this->_current_font['i']$this->_font_size_pt));
  1434.         }
  1435.     }
  1436.  
  1437.     /**
  1438.      * Creates a new internal link and returns its identifier. An internal
  1439.      * link is a clickable area which directs to another place within the
  1440.      * document.
  1441.      * The identifier can then be passed to File_PDF::cell, File_PDF::write,
  1442.      * File_PDF::image or File_PDF::link. The destination is defined with
  1443.      * File_PDF::setLink.
  1444.      *
  1445.      * @access public
  1446.      *
  1447.      * @see File_PDF::cell
  1448.      * @see File_PDF::Write
  1449.      * @see File_PDF::image
  1450.      * @see File_PDF::Link
  1451.      * @see File_PDF::SetLink
  1452.      */
  1453.     function addLink()
  1454.     {
  1455.         $n count($this->_links+ 1;
  1456.         $this->_links[$n= array(00);
  1457.         return $n;
  1458.     }
  1459.  
  1460.     /**
  1461.      * Defines the page and position a link points to.
  1462.      *
  1463.      * @access public
  1464.      *
  1465.      * @param int $link           The link identifier returned by
  1466.      *                             File_PDF::addLink.
  1467.      * @param optional float $y   Ordinate of target position; -1 indicates
  1468.      *                             the current position. The default value is 0
  1469.      *                             (top of page).
  1470.      * @param optional int $page  Number of target page; -1 indicates the
  1471.      *                             current page. This is the default value.
  1472.      *
  1473.      * @see File_PDF::addLink
  1474.      */
  1475.     function setLink($link$y = 0$page = -1)
  1476.     {
  1477.         if ($y == -1{
  1478.             $y $this->y;
  1479.         }
  1480.         if ($page == -1{
  1481.             $page $this->_page;
  1482.         }
  1483.         $this->_links[$link= array($page$y);
  1484.     }
  1485.  
  1486.     /**
  1487.      * Puts a link on a rectangular area of the page. Text or image links are
  1488.      * generally put via File_PDF::cell, File_PDF::Write or File_PDF::image,
  1489.      * but this method can be useful for instance to define a clickable area
  1490.      * inside an image.
  1491.      *
  1492.      * @access public
  1493.      *
  1494.      * @param float $x       Abscissa of the upper-left corner of the rectangle.
  1495.      * @param float $y       Ordinate of the upper-left corner of the rectangle.
  1496.      * @param float $width   Width of the rectangle.
  1497.      * @param float $height  Height of the rectangle.
  1498.      * @param mixed $link    URL or identifier returned by File_PDF::addLink.
  1499.      *
  1500.      * @see File_PDF::addLink
  1501.      * @see File_PDF::cell
  1502.      * @see File_PDF::Write
  1503.      * @see File_PDF::image
  1504.      */
  1505.     function link($x$y$width$height$link)
  1506.     {
  1507.         /* Set up the coordinates with correct scaling in pt. */
  1508.         $x      $this->_toPt($x);
  1509.         $y      $this->hPt - $this->_toPt($y);
  1510.         $width  $this->_toPt($width);
  1511.         $height $this->_toPt($height);
  1512.  
  1513.         /* Save link to page links array. */
  1514.         $this->_link($x$y$width$height$link);
  1515.     }
  1516.  
  1517.     /**
  1518.      * Prints a character string. The origin is on the left of the first
  1519.      * character, on the baseline. This method allows to place a string
  1520.      * precisely on the page, but it is usually easier to use File_PDF::cell,
  1521.      * File_PDF::multiCell or File_PDF::Write which are the standard methods to
  1522.      * print text.
  1523.      *
  1524.      * @access public
  1525.      *
  1526.      * @param float $x      Abscissa of the origin.
  1527.      * @param float $y      Ordinate of the origin.
  1528.      * @param string $text  String to print.
  1529.      *
  1530.      * @see File_PDF::setFont
  1531.      * @see File_PDF::cell
  1532.      * @see File_PDF::multiCell
  1533.      * @see File_PDF::Write
  1534.      */
  1535.     function text($x$y$text)
  1536.     {
  1537.         /* Scale coordinates into points and set correct Y position. */
  1538.         $x $this->_toPt($x);
  1539.         $y $this->hPt - $this->_toPt($y);
  1540.  
  1541.         /* Escape any potentially harmful characters. */
  1542.         $text $this->_escape($text);
  1543.  
  1544.         $out sprintf('BT %.2f %.2f Td (%s) Tj ET'$x$y$text);
  1545.         if ($this->_underline && $text != ''{
  1546.             $out .= ' ' $this->_doUnderline($x$y$text);
  1547.         }
  1548.         $this->_out($out);
  1549.     }
  1550.  
  1551.     /**
  1552.      * Whenever a page break condition is met, the method is called, and the
  1553.      * break is issued or not depending on the returned value. The default
  1554.      * implementation returns a value according to the mode selected by
  1555.      * File_PDF:setAutoPageBreak.
  1556.      * This method is called automatically and should not be called directly
  1557.      * by the application.
  1558.      *
  1559.      * @access public
  1560.      *
  1561.      * @return bool 
  1562.      *
  1563.      * @see File_PDF::setAutoPageBreak.
  1564.      */
  1565.     function acceptPageBreak()
  1566.     {
  1567.         return $this->_auto_page_break;
  1568.     }
  1569.  
  1570.     /**
  1571.      * Prints a cell (rectangular area) with optional borders, background
  1572.      * color and character string. The upper-left corner of the cell
  1573.      * corresponds to the current position. The text can be aligned or
  1574.      * centered. After the call, the current position moves to the right or to
  1575.      * the next line. It is possible to put a link on the text.
  1576.      * If automatic page breaking is enabled and the cell goes beyond the
  1577.      * limit, a page break is done before outputting.
  1578.      *
  1579.      * @param float $width            Cell width. If 0, the cell extends up to
  1580.      *                                 the right margin.
  1581.      * @param optional float $height  Cell height. Default value: 0.
  1582.      * @param optional string $text   String to print. Default value: empty.
  1583.      * @param optional mixed $border  Indicates if borders must be drawn
  1584.      *                                 around the cell. The value can be either
  1585.      *                                 a number:
  1586.      *                                   - 0: no border (default)
  1587.      *                                   - 1: frame
  1588.      *                                 or a string containing some or all of
  1589.      *                                 the following characters (in any order):
  1590.      *                                   - L: left
  1591.      *                                   - T: top
  1592.      *                                   - R: right
  1593.      *                                   - B: bottom
  1594.      * @param optional int $ln        Indicates where the current position
  1595.      *                                 should go after the call. Possible
  1596.      *                                 values are:
  1597.      *                                   - 0: to the right (default)
  1598.      *                                   - 1: to the beginning of the next line
  1599.      *                                   - 2: below
  1600.      *                                 Putting 1 is equivalent to putting 0 and
  1601.      *                                 calling File_PDF::newLine just after.
  1602.      * @param optional string $align  Allows to center or align the text.
  1603.      *                                 Possible values are:
  1604.      *                                   - L or empty string: left (default)
  1605.      *                                   - C: center
  1606.      *                                   - R: right
  1607.      * @param optional int $fill      Indicates if the cell fill type.
  1608.      *                                 Possible values are:
  1609.      *                                   - 0: transparent (default)
  1610.      *                                   - 1: painted
  1611.      * @param optional string $link   URL or identifier returned by
  1612.      *                                 File_PDF:addLink.
  1613.      *
  1614.      * @see File_PDF::setFont
  1615.      * @see File_PDF::setDrawColor
  1616.      * @see File_PDF::setFillColor
  1617.      * @see File_PDF::setLineWidth
  1618.      * @see File_PDF::addLink
  1619.      * @see File_PDF::newLine
  1620.      * @see File_PDF::multiCell
  1621.      * @see File_PDF::Write
  1622.      * @see File_PDF::setAutoPageBreak
  1623.      */
  1624.     function cell($width$height = 0$text ''$border = 0$ln = 0$align ''$fill = 0$link '')
  1625.     {
  1626.         $k $this->_scale;
  1627.         if ($this->y + $height $this->_page_break_trigger && !$this->_in_footer && $this->AcceptPageBreak()) {
  1628.             $x $this->x;
  1629.             $ws $this->_word_spacing;
  1630.             if ($ws > 0{
  1631.                 $this->_word_spacing = 0;
  1632.                 $this->_out('0 Tw');
  1633.             }
  1634.             $this->addPage($this->_current_orientation);
  1635.             $this->x = $x;
  1636.             if ($ws > 0{
  1637.                 $this->_word_spacing $ws;
  1638.                 $this->_out(sprintf('%.3f Tw'$ws $k));
  1639.             }
  1640.         }
  1641.         if ($width == 0{
  1642.             $width $this->w - $this->_right_margin $this->x;
  1643.         }
  1644.         $s '';
  1645.         if ($fill == 1 || $border == 1{
  1646.             if ($fill == 1{
  1647.                 $op ($border == 1'B' 'f';
  1648.             else {
  1649.                 $op 'S';
  1650.             }
  1651.             $s sprintf('%.2f %.2f %.2f %.2f re %s '$this->x * $k($this->h - $this->y$k$width $k-$height $k$op);
  1652.         }
  1653.         if (is_string($border)) {
  1654.             if (strpos($border'L'!== false{
  1655.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S '$this->x * $k($this->h - $this->y$k$this->x * $k($this->h - ($this->y + $height)) $k);
  1656.             }
  1657.             if (strpos($border'T'!== false{
  1658.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S '$this->x * $k($this->h - $this->y$k($this->x + $width$k($this->h - $this->y$k);
  1659.             }
  1660.             if (strpos($border'R'!== false{
  1661.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S '($this->x + $width$k($this->h - $this->y$k($this->x + $width$k($this->h - ($this->y + $height)) $k);
  1662.             }
  1663.             if (strpos($border'B'!== false{
  1664.                 $s .= sprintf('%.2f %.2f m %.2f %.2f l S '$this->x * $k($this->h - ($this->y + $height)) $k($this->x + $width$k($this->h - ($this->y + $height)) $k);
  1665.             }
  1666.         }
  1667.         if ($text != ''{
  1668.             if ($align == 'R'{
  1669.                 $dx $width $this->_cell_margin $this->getStringWidth($text);
  1670.             elseif ($align == 'C'{
  1671.                 $dx ($width $this->getStringWidth($text)) / 2;
  1672.             else {
  1673.                 $dx $this->_cell_margin;
  1674.             }
  1675.             $text str_replace(')''\\)'str_replace('(''\\('str_replace('\\''\\\\'$text)));
  1676.             $test2 ((.5 * $height(.3 * $this->_font_size));
  1677.             $test1 $this->fhPt - (($this->y + $test2$k);
  1678.             $s .= sprintf('BT %.2f %.2f Td (%s) Tj ET'($this->x + $dx$k($this->h - ($this->y + .5 * $height + .3 * $this->_font_size)) $k$text);
  1679.             if ($this->_underline{
  1680.                 $s .= ' ' $this->_doUnderline($this->x + $dx$this->y + .5 * $height + .3 * $this->_font_size$text);
  1681.             }
  1682.             if ($link{
  1683.                 $this->link($this->x + $dx$this->y + .5 * $height-.5 * $this->_font_size$this->getStringWidth($text)$this->_font_size$link);
  1684.             }
  1685.         }
  1686.         if ($s{
  1687.             $this->_out($s);
  1688.         }
  1689.         $this->_last_height $height;
  1690.         if ($ln > 0{
  1691.             /* Go to next line. */
  1692.             $this->y += $height;
  1693.             if ($ln == 1{
  1694.                 $this->x = $this->_left_margin;
  1695.             }
  1696.         else {
  1697.             $this->x += $width;
  1698.         }
  1699.     }
  1700.  
  1701.     /**
  1702.      * This method allows printing text with line breaks. They can be
  1703.      * automatic (as soon as the text reaches the right border of the cell) or
  1704.      * explicit (via the \n character). As many cells as necessary are output,
  1705.      * one below the other.
  1706.      * Text can be aligned, centered or justified. The cell block can be
  1707.      * framed and the background painted.
  1708.      *
  1709.      * @access public
  1710.      *
  1711.      * @param float $width            Width of cells. If 0, they extend up to
  1712.      *                                 the right margin of the page.
  1713.      * @param float $height           Height of cells.
  1714.      * @param string $text            String to print.
  1715.      * @param optional mixed $border  Indicates if borders must be drawn
  1716.      *                                 around the cell block. The value can be
  1717.      *                                 either a number:
  1718.      *                                   - 0: no border (default)
  1719.      *                                   - 1: frame
  1720.      *                                 or a string containing some or all of
  1721.      *                                 the following characters (in any order):
  1722.      *                                   - L: left
  1723.      *                                   - T: top
  1724.      *                                   - R: right
  1725.      *                                   - B: bottom
  1726.      * @param optional string $align  Sets the text alignment. Possible values
  1727.      *                                 are:
  1728.      *                                    - L: left alignment
  1729.      *                                    - C: center
  1730.      *                                    - R: right alignment
  1731.      *                                    - J: justification (default value)
  1732.      * @param optional int $fill      Indicates if the cell background must:
  1733.      *                                   - 0: transparent (default)
  1734.      *                                   - 1: painted
  1735.      *
  1736.      * @see File_PDF::setFont
  1737.      * @see File_PDF::setDrawColor
  1738.      * @see File_PDF::setFillColor
  1739.      * @see File_PDF::setLineWidth
  1740.      * @see File_PDF::cell
  1741.      * @see File_PDF::write
  1742.      * @see File_PDF::setAutoPageBreak
  1743.      */
  1744.     function multiCell($width$height$text$border = 0$align 'J'$fill = 0)
  1745.     {
  1746.         $cw &$this->_current_font['cw'];
  1747.         if ($width == 0{
  1748.             $width $this->w - $this->_right_margin $this->x;
  1749.         }
  1750.         $wmax ($width-2 * $this->_cell_margin* 1000 / $this->_font_size;
  1751.         $s str_replace("\r"''$text);
  1752.         $nb strlen($s);
  1753.         if ($nb > 0 && $s[$nb-1== "\n"{
  1754.             $nb--;
  1755.         }
  1756.         $b = 0;
  1757.         if ($border{
  1758.             if ($border == 1{
  1759.                 $border 'LTRB';
  1760.                 $b 'LRT';
  1761.                 $b2 'LR';
  1762.             else {
  1763.                 $b2 '';
  1764.                 if (strpos($border'L'!== false{
  1765.                     $b2 .= 'L';
  1766.                 }
  1767.                 if (strpos($border'R'!== false{
  1768.                     $b2 .= 'R';
  1769.                 }
  1770.                 $b (strpos($border'T'!== false$b2 'T' $b2;
  1771.             }
  1772.         }
  1773.         $sep = -1;
  1774.         $i   = 0;
  1775.         $j   = 0;
  1776.         $l   = 0;
  1777.         $ns  = 0;
  1778.         $nl  = 1;
  1779.         while ($i $nb{
  1780.             /* Get next character. */
  1781.             $c $s[$i];
  1782.             if ($c == "\n"{
  1783.                 /* Explicit line break. */
  1784.                 if ($this->_word_spacing > 0{
  1785.                     $this->_word_spacing = 0;
  1786.                     $this->_out('0 Tw');
  1787.                 }
  1788.                 $this->cell($width$heightsubstr($s$j$i-$j)$b2$align$fill);
  1789.                 $i++;
  1790.                 $sep = -1;
  1791.                 $j $i;
  1792.                 $l = 0;
  1793.                 $ns = 0;
  1794.                 $nl++;
  1795.                 if ($border && $nl == 2{
  1796.                     $b $b2;
  1797.                 }
  1798.                 continue;
  1799.             }
  1800.             if ($c == ' '{
  1801.                 $sep $i;
  1802.                 $ls $l;
  1803.                 $ns++;
  1804.             }
  1805.             $l += $cw[$c];
  1806.             if ($l $wmax{
  1807.                 /* Automatic line break. */
  1808.                 if ($sep == -1{
  1809.                     if ($i == $j{
  1810.                         $i++;
  1811.                     }
  1812.                     if ($this->_word_spacing>0{
  1813.                         $this->_word_spacing = 0;
  1814.                         $this->_out('0 Tw');
  1815.                     }
  1816.                     $this->cell($width$heightsubstr($s$j$i $j)$b2$align$fill);
  1817.                 else {
  1818.                     if ($align == 'J'{
  1819.                         $this->_word_spacing ($ns>1($wmax $ls)/1000 * $this->_font_size ($ns - 1: 0;
  1820.                         $this->_out(sprintf('%.3f Tw'$this->_word_spacing $this->_scale));
  1821.                     }
  1822.                     $this->cell($width$heightsubstr($s$j$sep $j)$b2$align$fill);
  1823.                     $i $sep + 1;
  1824.                 }
  1825.                 $sep = -1;
  1826.                 $j $i;
  1827.                 $l = 0;
  1828.                 $ns = 0;
  1829.                 $nl++;
  1830.                 if ($border && $nl == 2{
  1831.                     $b $b2;
  1832.                 }
  1833.             else {
  1834.                 $i++;
  1835.             }
  1836.         }
  1837.         /* Last chunk. */
  1838.         if ($this->_word_spacing>0{
  1839.             $this->_word_spacing = 0;
  1840.             $this->_out('0 Tw');
  1841.         }
  1842.         if ($border && strpos($border'B'!== false{
  1843.             $b .= 'B';
  1844.         }
  1845.         $this->cell($width$heightsubstr($s$j$i)$b2$align$fill);
  1846.         $this->x = $this->_left_margin;
  1847.     }
  1848.  
  1849.     /**
  1850.      * This method prints text from the current position. When the right
  1851.      * margin is reached (or the \n character is met) a line break occurs and
  1852.      * text continues from the left margin. Upon method exit, the current
  1853.      * position is left just at the end of the text.
  1854.      * It is possible to put a link on the text.
  1855.      *
  1856.      * Example:
  1857.      * //Begin with regular font
  1858.      * $pdf->setFont('Arial','',14);
  1859.      * $pdf->write(5,'Visit ');
  1860.      * //Then put a blue underlined link
  1861.      * $pdf->setTextColor(0,0,255);
  1862.      * $pdf->setFont('','U');
  1863.      * $pdf->write(5,'www.fpdf.org','http://www.fpdf.org');
  1864.      *
  1865.      * @access public
  1866.      *
  1867.      * @param float $height         Line height.
  1868.      * @param string $text          String to print.
  1869.      * @param optional mixed $link  URL or identifier returned by AddLink().
  1870.      *
  1871.      * @see File_PDF::setFont
  1872.      * @see File_PDF::addLink
  1873.      * @see File_PDF::multiCell
  1874.      * @see File_PDF::setAutoPageBreak
  1875.      */
  1876.     function write($height$text$link '')
  1877.     {
  1878.         $cw &$this->_current_font['cw'];
  1879.         $width $this->w - $this->_right_margin $this->x;
  1880.         $wmax ($width - 2 * $this->_cell_margin* 1000 / $this->_font_size;
  1881.         $s str_replace("\r"''$text);
  1882.         $nb strlen($s);
  1883.         $sep = -1;
  1884.         $i = 0;
  1885.         $j = 0;
  1886.         $l = 0;
  1887.         $nl = 1;
  1888.         while ($i $nb{
  1889.             /* Get next character. */
  1890.             $c $s{$i};
  1891.             if ($c == "\n"{
  1892.                 /* Explicit line break. */
  1893.                 $this->cell($width$heightsubstr($s$j$i $j)02''0$link);
  1894.                 $i++;
  1895.                 $sep = -1;
  1896.                 $j $i;
  1897.                 $l = 0;
  1898.                 if ($nl == 1{
  1899.                     $this->x = $this->_left_margin;
  1900.                     $width $this->w - $this->_right_margin $this->x;
  1901.                     $wmax ($width - 2 * $this->_cell_margin* 1000 / $this->_font_size;
  1902.                 }
  1903.                 $nl++;
  1904.                 continue;
  1905.             }
  1906.             if ($c == ' '{
  1907.                 $sep $i;
  1908.                 $ls $l;
  1909.             }
  1910.             $l += $cw[$c];
  1911.             if ($l $wmax{
  1912.                 /* Automatic line break. */
  1913.                 if ($sep == -1{
  1914.                     if ($this->x > $this->_left_margin{
  1915.                         /* Move to next line. */
  1916.                         $this->x = $this->_left_margin;
  1917.                         $this->y += $height;
  1918.                         $width $this->w - $this->_right_margin $this->x;
  1919.                         $wmax ($width - 2 * $this->_cell_margin* 1000 / $this->_font_size;
  1920.                         $i++;
  1921.                         $nl++;
  1922.                         continue;
  1923.                     }
  1924.                     if ($i == $j{
  1925.                         $i++;
  1926.                     }
  1927.                     $this->cell($width$heightsubstr($s$j$i $j)02''0$link);
  1928.                 else {
  1929.                     $this->cell($width$heightsubstr($s$j$sep $j)02''0$link);
  1930.                     $i $sep + 1;
  1931.                 }
  1932.                 $sep = -1;
  1933.                 $j $i;
  1934.                 $l = 0;
  1935.                 if ($nl == 1{
  1936.                     $this->x = $this->_left_margin;
  1937.                     $width $this->w - $this->_right_margin $this->x;
  1938.                     $wmax ($width - 2 * $this->_cell_margin* 1000 / $this->_font_size;
  1939.                 }
  1940.                 $nl++;
  1941.             }
  1942.             else
  1943.                 $i++;
  1944.         }
  1945.         /* Last chunk. */
  1946.         if ($i != $j{
  1947.             $this->cell($l / 1000 * $this->_font_size$heightsubstr($s$j$i)00''0$link);
  1948.         }
  1949.     }
  1950.  
  1951.      /**
  1952.      * write Rotated Text.
  1953.      *
  1954.      * Write text at an angle.
  1955.      *
  1956.      * @access   public
  1957.      *
  1958.      * @param int $x                      X coordinate.
  1959.      * @param int $y                      Y coordinate.
  1960.      * @param string $text                Text to write.
  1961.      * @param float $text_angle           Angle to rotate (Eg. 90 = bottom to
  1962.      *                                     top).
  1963.      * @param optional float $font_angle  Rotate characters as well as text.
  1964.      *
  1965.      * @return  none 
  1966.      *
  1967.      * @see File_PDF::setFont
  1968.      */
  1969.      function writeRotated($x$y$text$text_angle$font_angle = 0)
  1970.      {
  1971.          /* Escape text. */
  1972.          $text $this->_escape($text);
  1973.  
  1974.          $font_angle += 90 + $text_angle;
  1975.          $text_angle *= M_PI / 180;
  1976.          $font_angle *= M_PI / 180;
  1977.  
  1978.          $text_dx cos($text_angle);
  1979.          $text_dy sin($text_angle);
  1980.          $font_dx cos($font_angle);
  1981.          $font_dy sin($font_angle);
  1982.  
  1983.          $ssprintf('BT %.2f %.2f %.2f %.2f %.2f %.2f Tm (%s) Tj ET',
  1984.                      $text_dx$text_dy$font_dx$font_dy,
  1985.                      $x $this->_scale($this->h-$y$this->_scale$text);
  1986.  
  1987.          if $this->_draw_color{
  1988.              $s='q ' $this->_draw_color ' ' $s ' Q';
  1989.          }
  1990.          $this->_out($s);
  1991.      }
  1992.  
  1993.     /**
  1994.      * Prints an image in the page. The upper-left corner and at least one of
  1995.      * the dimensions must be specified; the height or the width can be
  1996.      * calculated automatically in order to keep the image proportions.
  1997.      * Supported formats are JPEG and PNG.
  1998.      *
  1999.      * For JPEG, all flavors are allowed:
  2000.      *   - gray scales
  2001.      *   - true colors (24 bits)
  2002.      *   - CMYK (32 bits)
  2003.      *
  2004.      * For PNG, are allowed:
  2005.      *   - gray scales on at most 8 bits (256 levels)
  2006.      *   - indexed colors
  2007.      *   - true colors (24 bits)
  2008.      * but are not supported:
  2009.      *   - Interlacing
  2010.      *   - Alpha channel
  2011.      *
  2012.      * If a transparent color is defined, it will be taken into account (but
  2013.      * will be only interpreted by Acrobat 4 and above).
  2014.      * The format can be specified explicitly or inferred from the file
  2015.      * extension.
  2016.      * It is possible to put a link on the image.
  2017.      *
  2018.      * Remark: if an image is used several times, only one copy will be
  2019.      * embedded in the file.
  2020.      *
  2021.      * @access public
  2022.      *
  2023.      * @param string $file            Name of the file containing the image.
  2024.      * @param float $x                Abscissa of the upper-left corner.
  2025.      * @param float $y                Ordinate of the upper-left corner.
  2026.      * @param float $width            Width of the image in the page. If equal
  2027.      *                                 to zero, it is automatically calculated
  2028.      *                                 to keep the original proportions.
  2029.      * @param optional float $height  Height of the image in the page. If not
  2030.      *                                 specified or equal to zero, it is
  2031.      *                                 automatically calculated to keep the
  2032.      *                                 original proportions.
  2033.      * @param string $type            Image format. Possible values are (case
  2034.      *                                 insensitive) : JPG, JPEG, PNG. If not
  2035.      *                                 specified, the type is inferred from the
  2036.      *                                 file extension.
  2037.      * @param mixed $link             URL or identifier returned by
  2038.      *                                 File_PDF::addLink.
  2039.      *
  2040.      * @see File_PDF::addLink
  2041.      */
  2042.     function image($file$x$y$width = 0$height = 0$type ''$link '')
  2043.     {
  2044.         if (!isset($this->_images[$file])) {
  2045.             /* First use of image, get some file info. */
  2046.             if ($type == ''{
  2047.                 $pos strrpos($file'.');
  2048.                 if ($pos === false{
  2049.                     return $this->raiseError(sprintf('Image file has no extension and no type was specified: %s'$file));
  2050.                 }
  2051.                 $type substr($file$pos + 1);
  2052.             }
  2053.             $type strtolower($type);
  2054.             $mqr get_magic_quotes_runtime();
  2055.             set_magic_quotes_runtime(0);
  2056.             if ($type == 'jpg' || $type == 'jpeg'{
  2057.                 $info $this->_parseJPG($file);
  2058.             elseif ($type == 'png'{
  2059.                 $info $this->_parsePNG($file);
  2060.             else {
  2061.                 return $this->raiseError(sprintf('Unsupported image file type: %s'$type));
  2062.             }
  2063.             set_magic_quotes_runtime($mqr);
  2064.             $info['i'count($this->_images+ 1;
  2065.             $this->_images[$file$info;
  2066.         else {
  2067.             $info $this->_images[$file];
  2068.         }
  2069.  
  2070.         /* Make sure all vars are converted to pt scale. */
  2071.         $x      $this->_toPt($x);
  2072.         $y      $this->_toPt($y);
  2073.         $width  $this->_toPt($width);
  2074.         $height $this->_toPt($height);
  2075.  
  2076.         /* If not specified do automatic width and height calculations. */
  2077.         if (empty($width&& empty($height)) {
  2078.             $width $info['w'];
  2079.             $height $info['h'];
  2080.         elseif (empty($width)) {
  2081.             $width $height $info['w'$info['h'];
  2082.         elseif (empty($height)) {
  2083.             $height $width $info['h'$info['w'];
  2084.         }
  2085.  
  2086.         $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q'$width$height$x$this->hPt - ($y $height)$info['i']));
  2087.  
  2088.         /* Set any link if requested. */
  2089.         if ($link{
  2090.             $this->_link($x$y$width$height$link);
  2091.         }
  2092.     }
  2093.  
  2094.     /**
  2095.      * Performs a line break. The current abscissa goes back to the left
  2096.      * margin and the ordinate increases by the amount passed in parameter.
  2097.      *
  2098.      * @access public
  2099.      *
  2100.      * @param optional float $height  The height of the break. By default, the
  2101.      *                                 value equals the height of the last
  2102.      *                                 printed cell.
  2103.      *
  2104.      * @see File_PDF::cell
  2105.      */
  2106.     function newLine($height '')
  2107.     {
  2108.         $this->x = $this->_left_margin;
  2109.         if (is_string($height)) {
  2110.             $this->y += $this->_last_height;
  2111.         else {
  2112.             $this->y += $height;
  2113.         }
  2114.     }
  2115.  
  2116.     /**
  2117.      * Returns the abscissa of the current position in user units.
  2118.      *
  2119.      * @access public
  2120.      *
  2121.      * @return float 
  2122.      *
  2123.      * @see File_PDF::setX
  2124.      * @see File_PDF::getY
  2125.      * @see File_PDF::setY
  2126.      */
  2127.     function getX()
  2128.     {
  2129.         return $this->x;
  2130.     }
  2131.  
  2132.     /**
  2133.      * Defines the abscissa of the current position. If the passed value is
  2134.      * negative, it is relative to the right of the page.
  2135.      *
  2136.      * @access public
  2137.      *
  2138.      * @param float $x  The value of the abscissa.
  2139.      *
  2140.      * @see File_PDF::getX
  2141.      * @see File_PDF::getY
  2142.      * @see File_PDF::setY
  2143.      * @see File_PDF::setXY
  2144.      */
  2145.     function setX($x)
  2146.     {
  2147.         if ($x >= 0{
  2148.             /* Absolute value. */
  2149.             $this->x = $x;
  2150.         else {
  2151.             /* Negative, so relative to right edge of the page. */
  2152.             $this->x = $this->w + $x;
  2153.         }
  2154.     }
  2155.  
  2156.     /**
  2157.      * Returns the ordinate of the current position in user units.
  2158.      *
  2159.      * @access public
  2160.      *
  2161.      * @return float 
  2162.      *
  2163.      * @see File_PDF::setY
  2164.      * @see File_PDF::getX
  2165.      * @see File_PDF::setX
  2166.      */
  2167.     function getY()
  2168.     {
  2169.         return $this->y;
  2170.     }
  2171.  
  2172.     /**
  2173.      * Defines the ordinate of the current position. If the passed value is
  2174.      * negative, it is relative to the bottom of the page.
  2175.      *
  2176.      * @access public
  2177.      *
  2178.      * @param float $y  The value of the ordinate.
  2179.      *
  2180.      * @see File_PDF::getX
  2181.      * @see File_PDF::getY
  2182.      * @see File_PDF::setY
  2183.      * @see File_PDF::setXY
  2184.      */
  2185.     function setY($y)
  2186.     {
  2187.         if ($y >= 0{
  2188.             $this->y = $y;
  2189.         else {
  2190.             $this->y = $this->h + $y;
  2191.         }
  2192.     }
  2193.  
  2194.     /**
  2195.      * Defines the abscissa and ordinate of the current position. If the
  2196.      * passed values are negative, they are relative respectively to the right
  2197.      * and bottom of the page.
  2198.      *
  2199.      * @param float $x  The value of the abscissa.
  2200.      * @param float $y  The value of the ordinate.
  2201.      *
  2202.      * @access public
  2203.      *
  2204.      * @see File_PDF::setX
  2205.      * @see File_PDF::setY
  2206.      */
  2207.     function setXY($x$y)
  2208.     {
  2209.         $this->setY($y);
  2210.         $this->setX($x);
  2211.     }
  2212.  
  2213.     /**
  2214.      * Returns the raw PDF file.
  2215.      *
  2216.      * @access public
  2217.      *
  2218.      * @see File_PDF::output
  2219.      */
  2220.     function getOutput()
  2221.     {
  2222.         /* Check whether file has been closed. */
  2223.         if ($this->_state < 3{
  2224.             $this->close();
  2225.         }
  2226.  
  2227.         return $this->_buffer;
  2228.     }
  2229.  
  2230.     /**
  2231.      * Function to output the buffered data to the browser.
  2232.      *
  2233.      * @access public
  2234.      *
  2235.      * @param string $filename  The filename for the output file.
  2236.      * @param bool $inline      True if inline, false if attachment.
  2237.      */
  2238.     function output($filename 'unknown.pdf'$inline = false)
  2239.     {
  2240.         /* Check whether file has been closed. */
  2241.         if ($this->_state < 3{
  2242.             $this->close();
  2243.         }
  2244.  
  2245.         /* If HTTP_Download is not available return PEAR_Error. */
  2246.         if (!@include_once 'HTTP/Download.php'{
  2247.             return $this->raiseError('Missing PEAR package HTTP_Download.');
  2248.         }
  2249.  
  2250.         /* Check if headers have been sent. */
  2251.         if (headers_sent()) {
  2252.             return $this->raiseError('Unable to send PDF file, some data has already been output to browser.');
  2253.         }
  2254.  
  2255.         /* Params for the output. */
  2256.         $disposition (!$inline? HTTP_DOWNLOAD_ATTACHMENT : HTTP_DOWNLOAD_INLINE;
  2257.         $params = array('data'               => $this->_buffer,
  2258.                         'contenttype'        => 'application/pdf',
  2259.                         'contentdisposition' => array($disposition$filename));
  2260.         /* Output the file. */
  2261.         return HTTP_Download::staticSend($params);
  2262.     }
  2263.  
  2264.     /**
  2265.      * Function to save the PDF file somewhere local to the server.
  2266.      *
  2267.      * @access public
  2268.      *
  2269.      * @param string $filename  The filename for the output file.
  2270.      */
  2271.     function save($filename 'unknown.pdf')
  2272.     {
  2273.         /* Check whether file has been closed. */
  2274.         if ($this->_state < 3{
  2275.             $this->close();
  2276.         }
  2277.  
  2278.         $f fopen($filename'wb');
  2279.         if (!$f{
  2280.             return $this->raiseError(sprintf('Unable to save PDF file: %s'$filename));
  2281.         }
  2282.         fwrite($f$this->_bufferstrlen($this->_buffer));
  2283.         fclose($f);
  2284.     }
  2285.  
  2286.     function _toPt($val)
  2287.     {
  2288.         return $val $this->_scale;
  2289.     }
  2290.  
  2291.     function &_getFontFile($fontkey$path '')
  2292.     {
  2293.         static $font_widths;
  2294.  
  2295.         if (!isset($font_widths[$fontkey])) {
  2296.             if (!empty($path)) {
  2297.                 $file $path strtolower($fontkey'.php';
  2298.             else {
  2299.                 $file 'File/PDF/fonts/' strtolower($fontkey'.php';
  2300.             }
  2301.             @require $file;
  2302.             if (!isset($font_widths[$fontkey])) {
  2303.                 return $this->raiseError(sprintf('Could not include font metric file: %s'$file));
  2304.             }
  2305.         }
  2306.  
  2307.         return $font_widths;
  2308.     }
  2309.  
  2310.     function _link($x$y$width$height$link)
  2311.     {
  2312.         /* Save link to page links array. */
  2313.         $this->_page_links[$this->_page][= array($x$y$width$height$link);
  2314.     }
  2315.  
  2316.     function _beginDoc()
  2317.     {
  2318.         /* Start document. */
  2319.         $this->_state = 1;
  2320.         $this->_out('%PDF-1.3');
  2321.     }
  2322.  
  2323.     function _putPages()
  2324.     {
  2325.         $nb $this->_page;
  2326.         if (!empty($this->_alias_nb_pages)) {
  2327.             /* Replace number of pages. */
  2328.             for ($n = 1; $n <= $nb$n++{
  2329.                 $this->_pages[$nstr_replace($this->_alias_nb_pages$nb$this->_pages[$n]);
  2330.             }
  2331.         }
  2332.         if ($this->_default_orientation == 'P'{
  2333.             $wPt $this->fwPt;
  2334.             $hPt $this->fhPt;
  2335.         else {
  2336.             $wPt $this->fhPt;
  2337.             $hPt $this->fwPt;
  2338.         }
  2339.         $filter ($this->_compress'/Filter /FlateDecode ' '';
  2340.         for ($n = 1; $n <= $nb$n++{
  2341.             /* Page */
  2342.             $this->_newobj();
  2343.             $this->_out('<</Type /Page');
  2344.             $this->_out('/Parent 1 0 R');
  2345.             if (isset($this->_orientation_changes[$n])) {
  2346.                 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]'$hPt$wPt));
  2347.             }
  2348.             $this->_out('/Resources 2 0 R');
  2349.             if (isset($this->_page_links[$n])) {
  2350.                 /* Links */
  2351.                 $annots '/Annots [';
  2352.                 foreach ($this->_page_links[$nas $pl{
  2353.                     $rect sprintf('%.2f %.2f %.2f %.2f'$pl[0]$pl[1]$pl[0$pl[2]$pl[1$pl[3]);
  2354.                     $annots .= '<</Type /Annot /Subtype /Link /Rect [' $rect '] /Border [0 0 0] ';
  2355.                     if (is_string($pl[4])) {
  2356.                         $annots .= '/A <</S /URI /URI ' $this->_textString($pl[4]'>>>>';
  2357.                     else {
  2358.                         $l $this->_links[$pl[4]];
  2359.                         $height = isset($this->_orientation_changes[$l[0]]$wPt $hPt;
  2360.                         $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>'1 + 2 * $l[0]$height $l[1$this->_scale);
  2361.                     }
  2362.                 }
  2363.                 $this->_out($annots.']');
  2364.             }
  2365.             $this->_out('/Contents ' ($this->_n + 1' 0 R>>');
  2366.             $this->_out('endobj');
  2367.             /* Page content */
  2368.             $p ($this->_compressgzcompress($this->_pages[$n]$this->_pages[$n];
  2369.             $this->_newobj();
  2370.             $this->_out('<<' $filter '/Length ' strlen($p'>>');
  2371.             $this->_putStream($p);
  2372.             $this->_out('endobj');
  2373.         }
  2374.         /* Pages root */
  2375.         $this->_offsets[1strlen($this->_buffer);
  2376.         $this->_out('1 0 obj');
  2377.         $this->_out('<</Type /Pages');
  2378.         $kids '/Kids [';
  2379.         for ($i = 0; $i $nb$i++{
  2380.             $kids .= (3 + 2 * $i' 0 R ';
  2381.         }
  2382.         $this->_out($kids ']');
  2383.         $this->_out('/Count ' $nb);
  2384.         $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]'$wPt$hPt));
  2385.         $this->_out('>>');
  2386.         $this->_out('endobj');
  2387.     }
  2388.  
  2389.     function _putFonts()
  2390.     {
  2391.         $nf $this->_n;
  2392.         foreach ($this->_diffs as $diff{
  2393.             /* Encodings */
  2394.             $this->_newobj();
  2395.             $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' $diff ']>>');
  2396.             $this->_out('endobj');
  2397.         }
  2398.         $mqr get_magic_quotes_runtime();
  2399.         set_magic_quotes_runtime(0);
  2400.         foreach ($this->_font_files as $file => $info{
  2401.             /* Font file embedding. */
  2402.             $this->_newobj();
  2403.             $this->_font_files[$file]['n'$this->_n;
  2404.             $size filesize($file);
  2405.             if (!$size{
  2406.                 return $this->raiseError('Font file not found.');
  2407.             }
  2408.             $this->_out('<</Length ' $size);
  2409.             if (substr($file-2== '.z'{
  2410.                 $this->_out('/Filter /FlateDecode');
  2411.             }
  2412.             $this->_out('/Length1 ' $info['length1']);
  2413.             if (isset($info['length2'])) {
  2414.                 $this->_out('/Length2 ' $info['length2'' /Length3 0');
  2415.             }
  2416.             $this->_out('>>');
  2417.             $f fopen($file'rb');
  2418.             $this->_putStream(fread($f$size));
  2419.             fclose($f);
  2420.             $this->_out('endobj');
  2421.         }
  2422.         set_magic_quotes_runtime($mqr);
  2423.         foreach ($this->_fonts as $k => $font{
  2424.             /* Font objects */
  2425.             $this->_newobj();
  2426.             $this->_fonts[$k]['n'$this->_n;
  2427.             $name $font['name'];
  2428.             $this->_out('<</Type /Font');
  2429.             $this->_out('/BaseFont /' $name);
  2430.             if ($font['type'== 'core'{
  2431.                 /* Standard font. */
  2432.                 $this->_out('/Subtype /Type1');
  2433.                 if ($name != 'Symbol' && $name != 'ZapfDingbats'{
  2434.                     $this->_out('/Encoding /WinAnsiEncoding');
  2435.                 }
  2436.             else {
  2437.                 /* Additional font. */
  2438.                 $this->_out('/Subtype /' $font['type']);
  2439.                 $this->_out('/FirstChar 32');
  2440.                 $this->_out('/LastChar 255');
  2441.                 $this->_out('/Widths ' ($this->_n + 1' 0 R');
  2442.                 $this->_out('/FontDescriptor ' ($this->_n + 2' 0 R');
  2443.                 if ($font['enc']{
  2444.                     if (isset($font['diff'])) {
  2445.                         $this->_out('/Encoding ' ($nf $font['diff']).' 0 R');
  2446.                     else {
  2447.                         $this->_out('/Encoding /WinAnsiEncoding');
  2448.                     }
  2449.                 }
  2450.             }
  2451.             $this->_out('>>');
  2452.             $this->_out('endobj');
  2453.             if ($font['type'!= 'core'{
  2454.                 /* Widths. */
  2455.                 $this->_newobj();
  2456.                 $cw &$font['cw'];
  2457.                 $s '[';
  2458.                 for ($i = 32; $i <= 255; $i++{
  2459.                     $s .= $cw[chr($i)' ';
  2460.                 }
  2461.                 $this->_out($s ']');
  2462.                 $this->_out('endobj');
  2463.                 /* Descriptor. */
  2464.                 $this->_newobj();
  2465.                 $s '<</Type /FontDescriptor /FontName /' $name;
  2466.                 foreach ($font['desc'as $k => $v{
  2467.                     $s .= ' /' $k ' ' $v;
  2468.                 }
  2469.                 $file $font['file'];
  2470.                 if ($file{
  2471.                     $s .= ' /FontFile' ($font['type'== 'Type1' '' '2'' ' $this->_font_files[$file]['n'' 0 R';
  2472.                 }
  2473.                 $this->_out($s '>>');
  2474.                 $this->_out('endobj');
  2475.             }
  2476.         }
  2477.     }
  2478.  
  2479.     function _putImages()
  2480.     {
  2481.         $filter ($this->_compress'/Filter /FlateDecode ' '';
  2482.         foreach ($this->_images as $file => $info{
  2483.             $this->_newobj();
  2484.             $this->_images[$file]['n'$this->_n;
  2485.             $this->_out('<</Type /XObject');
  2486.             $this->_out('/Subtype /Image');
  2487.             $this->_out('/Width ' $info['w']);
  2488.             $this->_out('/Height ' $info['h']);
  2489.             if ($info['cs'== 'Indexed'{
  2490.                 $this->_out('/ColorSpace [/Indexed /DeviceRGB ' (strlen($info['pal'])/3 - 1' ' ($this->_n + 1).' 0 R]');
  2491.             else {
  2492.                 $this->_out('/ColorSpace /' $info['cs']);
  2493.                 if ($info['cs'== 'DeviceCMYK'{
  2494.                     $this->_out('/Decode [1 0 1 0 1 0 1 0]');
  2495.                 }
  2496.             }
  2497.             $this->_out('/BitsPerComponent ' $info['bpc']);
  2498.             $this->_out('/Filter /' $info['f']);
  2499.             if (isset($info['parms'])) {
  2500.                 $this->_out($info['parms']);
  2501.             }
  2502.             if (isset($info['trns']&& is_array($info['trns'])) {
  2503.                 $trns '';
  2504.                 $i_max count($info['trns']);
  2505.                 for ($i = 0; $i $i_max$i++{
  2506.                     $trns .= $info['trns'][$i' ' $info['trns'][$i].' ';
  2507.                 }
  2508.                 $this->_out('/Mask [' $trns ']');
  2509.             }
  2510.             $this->_out('/Length ' strlen($info['data']'>>');
  2511.             $this->_putStream($info['data']);
  2512.             $this->_out('endobj');
  2513.  
  2514.             /* Palette. */
  2515.             if ($info['cs'== 'Indexed'{
  2516.                 $this->_newobj();
  2517.                 $pal ($this->_compressgzcompress($info['pal']$info['pal'];
  2518.                 $this->_out('<<' $filter '/Length ' strlen($pal'>>');
  2519.                 $this->_putStream($pal);
  2520.                 $this->_out('endobj');
  2521.             }
  2522.         }
  2523.     }
  2524.  
  2525.     function _putResources()
  2526.     {
  2527.         $this->_putFonts();
  2528.         $this->_putImages();
  2529.         /* Resource dictionary */
  2530.         $this->_offsets[2strlen($this->_buffer);
  2531.         $this->_out('2 0 obj');
  2532.         $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
  2533.         $this->_out('/Font <<');
  2534.         foreach ($this->_fonts as $font{
  2535.             $this->_out('/F' $font['i'' ' $font['n'' 0 R');
  2536.         }
  2537.         $this->_out('>>');
  2538.         if (count($this->_images)) {
  2539.             $this->_out('/XObject <<');
  2540.             foreach ($this->_images as $image{
  2541.                 $this->_out('/I' $image['i'' ' $image['n'' 0 R');
  2542.             }
  2543.             $this->_out('>>');
  2544.         }
  2545.         $this->_out('>>');
  2546.         $this->_out('endobj');
  2547.     }
  2548.  
  2549.     function _putInfo()
  2550.     {
  2551.         $this->_out('/Producer ' $this->_textString('Horde PDF'));
  2552.         if (!empty($this->_info['title'])) {
  2553.             $this->_out('/Title ' $this->_textString($this->_info['title']));
  2554.         }
  2555.         if (!empty($this->_info['subject'])) {
  2556.             $this->_out('/Subject ' $this->_textString($this->_info['subject']));
  2557.         }
  2558.         if (!empty($this->_info['author'])) {
  2559.             $this->_out('/Author ' $this->_textString($this->_info['author']));
  2560.         }
  2561.         if (!empty($this->keywords)) {
  2562.             $this->_out('/Keywords ' $this->_textString($this->keywords));
  2563.         }
  2564.         if (!empty($this->creator)) {
  2565.             $this->_out('/Creator ' $this->_textString($this->creator));
  2566.         }
  2567.         $this->_out('/CreationDate ' $this->_textString('D:' date('YmdHis')));
  2568.     }
  2569.  
  2570.     function _putCatalog()
  2571.     {
  2572.         $this->_out('/Type /Catalog');
  2573.         $this->_out('/Pages 1 0 R');
  2574.         if ($this->_zoom_mode == 'fullpage'{
  2575.             $this->_out('/OpenAction [3 0 R /Fit]');
  2576.         elseif ($this->_zoom_mode == 'fullwidth'{
  2577.             $this->_out('/OpenAction [3 0 R /FitH null]');
  2578.         elseif ($this->_zoom_mode == 'real'{
  2579.             $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
  2580.         elseif (!is_string($this->_zoom_mode)) {
  2581.             $this->_out('/OpenAction [3 0 R /XYZ null null ' ($this->_zoom_mode / 100).']');
  2582.         }
  2583.         if ($this->_layout_mode == 'single'{
  2584.             $this->_out('/PageLayout /SinglePage');
  2585.         elseif ($this->_layout_mode == 'continuous'{
  2586.             $this->_out('/PageLayout /OneColumn');
  2587.         elseif ($this->_layout_mode == 'two'{
  2588.             $this->_out('/PageLayout /TwoColumnLeft');
  2589.         }
  2590.     }
  2591.  
  2592.     function _putTrailer()
  2593.     {
  2594.         $this->_out('/Size ' ($this->_n + 1));
  2595.         $this->_out('/Root ' $this->_n ' 0 R');
  2596.         $this->_out('/Info ' ($this->_n - 1' 0 R');
  2597.     }
  2598.  
  2599.     function _endDoc()
  2600.     {
  2601.         $this->_putPages();
  2602.         $this->_putResources();
  2603.         /* Info */
  2604.         $this->_newobj();
  2605.         $this->_out('<<');
  2606.         $this->_putInfo();
  2607.         $this->_out('>>');
  2608.         $this->_out('endobj');
  2609.         /* Catalog */
  2610.         $this->_newobj();
  2611.         $this->_out('<<');
  2612.         $this->_putCatalog();
  2613.         $this->_out('>>');
  2614.         $this->_out('endobj');
  2615.         /* Cross-ref */
  2616.         $o strlen($this->_buffer);
  2617.         $this->_out('xref');
  2618.         $this->_out('0 ' ($this->_n + 1));
  2619.         $this->_out('0000000000 65535 f ');
  2620.         for ($i = 1; $i <= $this->_n$i++{
  2621.             $this->_out(sprintf('%010d 00000 n '$this->_offsets[$i]));
  2622.         }
  2623.         /* Trailer */
  2624.         $this->_out('trailer');
  2625.         $this->_out('<<');
  2626.         $this->_putTrailer();
  2627.         $this->_out('>>');
  2628.         $this->_out('startxref');
  2629.         $this->_out($o);
  2630.         $this->_out('%%EOF');
  2631.         $this->_state = 3;
  2632.     }
  2633.  
  2634.     function _beginPage($orientation)
  2635.     {
  2636.         $this->_page++;
  2637.         $this->_pages[$this->_page'';
  2638.         $this->_state = 2;
  2639.         $this->x = $this->_left_margin;
  2640.         $this->y = $this->_top_margin;
  2641.         $this->_last_height = 0;
  2642.         $this->_font_family '';
  2643.         /* Page orientation */
  2644.         if (!$orientation{
  2645.             $orientation $this->_default_orientation;
  2646.         else {
  2647.             $orientation strtoupper($orientation{0});
  2648.             if ($orientation != $this->_default_orientation{
  2649.                 $this->_orientation_changes[$this->_page= true;
  2650.             }
  2651.         }
  2652.         if ($orientation != $this->_current_orientation{
  2653.             /* Change orientation */
  2654.             if ($orientation == 'P'{
  2655.                 $this->wPt = $this->fwPt;
  2656.                 $this->hPt = $this->fhPt;
  2657.                 $this->w   = $this->fw;
  2658.                 $this->h   = $this->fh;
  2659.             else {
  2660.                 $this->wPt = $this->fhPt;
  2661.                 $this->hPt = $this->fwPt;
  2662.                 $this->w   = $this->fh;
  2663.                 $this->h   = $this->fw;
  2664.             }
  2665.             $this->_page_break_trigger $this->h - $this->_break_margin;
  2666.             $this->_current_orientation $orientation;
  2667.         }
  2668.     }
  2669.  
  2670.     function _endPage()
  2671.     {
  2672.         /* End of page contents */
  2673.         $this->_state = 1;
  2674.     }
  2675.  
  2676.     function _newobj()
  2677.     {
  2678.         /* Begin a new object */
  2679.         $this->_n++;
  2680.         $this->_offsets[$this->_nstrlen($this->_buffer);
  2681.         $this->_out($this->_n ' 0 obj');
  2682.     }
  2683.  
  2684.     function _doUnderline($x$y$text)
  2685.     {
  2686.         /* Set the rectangle width according to text width. */
  2687.         $width  $this->getStringWidth($texttrue);
  2688.  
  2689.         /* Set rectangle position and height, using underline position and
  2690.          * thickness settings scaled by the font size. */
  2691.         $y $y ($this->_current_font['up'$this->_font_size_pt / 1000);
  2692.         $height = -$this->_current_font['ut'$this->_font_size_pt / 1000;
  2693.  
  2694.         return sprintf('%.2f %.2f %.2f %.2f re f'$x$y$width$height);
  2695.     }
  2696.  
  2697.     function _parseJPG($file)
  2698.     {
  2699.         /* Extract info from a JPEG file. */
  2700.         $img @getimagesize($file);
  2701.         if (!$img{
  2702.             return $this->raiseError(sprintf('Missing or incorrect image file: %s'$file));
  2703.         }
  2704.         if ($img[2!= 2{
  2705.             return $this->raiseError(sprintf('Not a JPEG file: %s'$file));
  2706.         }
  2707.         if (!isset($img['channels']|| $img['channels'== 3{
  2708.             $colspace 'DeviceRGB';
  2709.         elseif ($img['channels'== 4{
  2710.             $colspace 'DeviceCMYK';
  2711.         else {
  2712.             $colspace 'DeviceGray';
  2713.         }
  2714.         $bpc = isset($img['bits']$img['bits': 8;
  2715.  
  2716.         /* Read whole file. */
  2717.         $f fopen($file'rb');
  2718.         $data fread($ffilesize($file));
  2719.         fclose($f);
  2720.  
  2721.         return array('w' => $img[0]'h' => $img[1]'cs' => $colspace'bpc' => $bpc'f' => 'DCTDecode''data' => $data);
  2722.     }
  2723.  
  2724.     function _parsePNG($file)
  2725.     {
  2726.         /* Extract info from a PNG file. */
  2727.         $f fopen($file'rb');
  2728.         if (!$f{
  2729.             return $this->raiseError(sprintf('Unable to open image file: %s'$file));
  2730.         }
  2731.  
  2732.         /* Check signature. */
  2733.         if (fread($f8!= chr(137'PNG' chr(13chr(10chr(26chr(10)) {
  2734.             return $this->raiseError(sprintf('Not a PNG file: %s'$file));
  2735.         }
  2736.  
  2737.         /* Read header chunk. */
  2738.         fread($f4);
  2739.         if (fread($f4!= 'IHDR'{
  2740.             return $this->raiseError(sprintf('Incorrect PNG file: %s'$file));
  2741.         }
  2742.         $width $this->_freadInt($f);
  2743.         $height $this->_freadInt($f);
  2744.         $bpc ord(fread($f1));
  2745.         if ($bpc > 8{
  2746.             return $this->raiseError(sprintf('16-bit depth not supported: %s'$file));
  2747.         }
  2748.         $ct ord(fread($f1));
  2749.         if ($ct == 0{
  2750.             $colspace 'DeviceGray';
  2751.         elseif ($ct == 2{
  2752.             $colspace 'DeviceRGB';
  2753.         elseif ($ct == 3{
  2754.             $colspace 'Indexed';
  2755.         else {
  2756.             return $this->raiseError(sprintf('Alpha channel not supported: %s'$file));
  2757.         }
  2758.         if (ord(fread($f1)) != 0{
  2759.             return $this->raiseError(sprintf('Unknown compression method: %s'$file));
  2760.         }
  2761.         if (ord(fread($f1)) != 0{
  2762.             return $this->raiseError(sprintf('Unknown filter method: %s'$file));
  2763.         }
  2764.         if (ord(fread($f1)) != 0{
  2765.             return $this->raiseError(sprintf('Interlacing not supported: %s'$file));
  2766.         }
  2767.         fread($f4);
  2768.         $parms '/DecodeParms <</Predictor 15 /Colors ' ($ct == 2 ? 3 : 1).' /BitsPerComponent ' $bpc ' /Columns ' $width.'>>';
  2769.         /* Scan chunks looking for palette, transparency and image data. */
  2770.         $pal '';
  2771.         $trns '';
  2772.         $data '';
  2773.         do {
  2774.             $n $this->_freadInt($f);
  2775.             $type fread($f4);
  2776.             if ($type == 'PLTE'{
  2777.                 /* Read palette */
  2778.                 $pal fread($f$n);
  2779.                 fread($f4);
  2780.             elseif ($type == 'tRNS'{
  2781.                 /* Read transparency info */
  2782.                 $t fread($f$n);
  2783.                 if ($ct == 0{
  2784.                     $trns = array(ord(substr($t11)));
  2785.                 elseif ($ct == 2{
  2786.                     $trns = array(ord(substr($t11))ord(substr($t31))ord(substr($t51)));
  2787.                 else {
  2788.                     $pos strpos($tchr(0));
  2789.                     if (is_int($pos)) {
  2790.                         $trns = array($pos);
  2791.                     }
  2792.                 }
  2793.                 fread($f4);
  2794.             elseif ($type == 'IDAT'{
  2795.                 /* Read image data block */
  2796.                 $data .= fread($f$n);
  2797.                 fread($f4);
  2798.             elseif ($type == 'IEND'{
  2799.                 break;
  2800.             else {
  2801.                 fread($f$n + 4);
  2802.             }
  2803.         while($n);
  2804.  
  2805.         if ($colspace == 'Indexed' && empty($pal)) {
  2806.             return $this->raiseError(sprintf('Missing palette in: %s'$file));
  2807.         }
  2808.         fclose($f);
  2809.  
  2810.         return array('w' => $width'h' => $height'cs' => $colspace'bpc' => $bpc'f' => 'FlateDecode''parms' => $parms'pal' => $pal'trns' => $trns'data' => $data);
  2811.     }
  2812.  
  2813.     function _freadInt($f)
  2814.     {
  2815.         /* Read a 4-byte integer from file. */
  2816.         $i  ord(fread($f1)) << 24;
  2817.         $i += ord(fread($f1)) << 16;
  2818.         $i += ord(fread($f1)) << 8;
  2819.         $i += ord(fread($f1));
  2820.         return $i;
  2821.     }
  2822.  
  2823.     function _textString($s)
  2824.     {
  2825.         /* Format a text string */
  2826.         return '(' $this->_escape($s')';
  2827.     }
  2828.  
  2829.     function _escape($s)
  2830.     {
  2831.         /* Add \ before \, ( and ) */
  2832.         return str_replace(array(')','(','\\'),
  2833.                            array('\\)','\\(','\\\\'),
  2834.                            $s);
  2835.     }
  2836.  
  2837.     function _putStream($s)
  2838.     {
  2839.         $this->_out('stream');
  2840.         $this->_out($s);
  2841.         $this->_out('endstream');
  2842.     }
  2843.  
  2844.     function _out($s)
  2845.     {
  2846.         /* Add a line to the document. */
  2847.         if ($this->_state == 2{
  2848.             $this->_pages[$this->_page.= $s "\n";
  2849.         else {
  2850.             $this->_buffer .= $s "\n";
  2851.         }
  2852.     }
  2853.  
  2854. }

Documentation generated on Mon, 11 Mar 2019 14:21:11 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.