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

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