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

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