PEEL Shopping
Open source ecommerce : PEEL Shopping
tcpdf.php
Go to the documentation of this file.
1 <?php
2 //============================================================+
3 // File name : tcpdf.php
4 // Version : 5.9.202
5 // Begin : 2002-08-03
6 // Last Update : 2012-12-16
7 // Author : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - www.tecnick.com - info@tecnick.com
8 // License : http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT GNU-LGPLv3
9 // -------------------------------------------------------------------
10 // Copyright (C) 2002-2012 Nicola Asuni - Tecnick.com LTD
11 //
12 // This file is part of TCPDF software library.
13 //
14 // TCPDF is free software: you can redistribute it and/or modify it
15 // under the terms of the GNU Lesser General Public License as
16 // published by the Free Software Foundation, either version 3 of the
17 // License, or (at your option) any later version.
18 //
19 // TCPDF is distributed in the hope that it will be useful, but
20 // WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 // See the GNU Lesser General Public License for more details.
23 //
24 // You should have received a copy of the License
25 // along with TCPDF. If not, see
26 // <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27 //
28 // See LICENSE.TXT file for more information.
29 // -------------------------------------------------------------------
30 //
31 // Description :
32 // This is a PHP class for generating PDF documents without requiring external extensions.
33 //
34 // NOTE:
35 // This class was originally derived in 2002 from the Public
36 // Domain FPDF class by Olivier Plathey (http://www.fpdf.org),
37 // but now is almost entirely rewritten and contains thousands of
38 // new lines of code and hundreds new features.
39 //
40 // Main features:
41 // * no external libraries are required for the basic functions;
42 // * all standard page formats, custom page formats, custom margins and units of measure;
43 // * UTF-8 Unicode and Right-To-Left languages;
44 // * TrueTypeUnicode, TrueType, Type1 and CID-0 fonts;
45 // * font subsetting;
46 // * methods to publish some XHTML + CSS code, Javascript and Forms;
47 // * images, graphic (geometric figures) and transformation methods;
48 // * supports JPEG, PNG and SVG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html)
49 // * 1D and 2D barcodes: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS, Datamatrix, QR-Code, PDF417;
50 // * JPEG and PNG ICC profiles, Grayscale, RGB, CMYK, Spot Colors and Transparencies;
51 // * automatic page header and footer management;
52 // * document encryption up to 256 bit and digital signature certifications;
53 // * transactions to UNDO commands;
54 // * PDF annotations, including links, text and file attachments;
55 // * text rendering modes (fill, stroke and clipping);
56 // * multiple columns mode;
57 // * no-write page regions;
58 // * bookmarks, named destinations and table of content;
59 // * text hyphenation;
60 // * text stretching and spacing (tracking);
61 // * automatic page break, line break and text alignments including justification;
62 // * automatic page numbering and page groups;
63 // * move and delete pages;
64 // * page compression (requires php-zlib extension);
65 // * XOBject Templates;
66 // * Layers and object visibility.
67 // * PDF/A-1b support.
68 //
69 // -----------------------------------------------------------
70 // THANKS TO:
71 //
72 // Olivier Plathey (http://www.fpdf.org) for original FPDF.
73 // Efthimios Mavrogeorgiadis (emavro@yahoo.com) for suggestions on RTL language support.
74 // Klemen Vodopivec (http://www.fpdf.de/downloads/addons/37/) for Encryption algorithm.
75 // Warren Sherliker (wsherliker@gmail.com) for better image handling.
76 // dullus for text Justification.
77 // Bob Vincent (pillarsdotnet@users.sourceforge.net) for <li> value attribute.
78 // Patrick Benny for text stretch suggestion on Cell().
79 // Johannes Güntert for JavaScript support.
80 // Denis Van Nuffelen for Dynamic Form.
81 // Jacek Czekaj for multibyte justification
82 // Anthony Ferrara for the reintroduction of legacy image methods.
83 // Sourceforge user 1707880 (hucste) for line-trough mode.
84 // Larry Stanbery for page groups.
85 // Martin Hall-May for transparency.
86 // Aaron C. Spike for Polycurve method.
87 // Mohamad Ali Golkar, Saleh AlMatrafe, Charles Abbott for Arabic and Persian support.
88 // Moritz Wagner and Andreas Wurmser for graphic functions.
89 // Andrew Whitehead for core fonts support.
90 // Esteban Joël Marín for OpenType font conversion.
91 // Teus Hagen for several suggestions and fixes.
92 // Yukihiro Nakadaira for CID-0 CJK fonts fixes.
93 // Kosmas Papachristos for some CSS improvements.
94 // Marcel Partap for some fixes.
95 // Won Kyu Park for several suggestions, fixes and patches.
96 // Dominik Dzienia for QR-code support.
97 // Laurent Minguet for some suggestions.
98 // Christian Deligant for some suggestions and fixes.
99 // Travis Harris for crop mark suggestion.
100 // Aleksey Kuznetsov for some suggestions and text shadows.
101 // Jim Hanlon for several suggestions and patches.
102 // Anyone else that has reported a bug or sent a suggestion.
103 //============================================================+
104 
145 // Main configuration file. Define the K_TCPDF_EXTERNAL_CONFIG constant to skip this file.
146 require_once(dirname(__FILE__).'/config/tcpdf_config.php');
147 
157 class TCPDF {
158 
159  // private properties
160 
165  private $tcpdf_version = '5.9.202';
166 
167  // Protected properties
168 
173  protected $page;
174 
179  protected $n;
180 
185  protected $offsets = array();
186 
191  protected $pageobjects = array();
192 
197  protected $buffer;
198 
203  protected $pages = array();
204 
209  protected $state;
210 
215  protected $compress;
216 
221  protected $CurOrientation;
222 
227  protected $pagedim = array();
228 
233  protected $k;
234 
239  protected $fwPt;
240 
245  protected $fhPt;
246 
251  protected $wPt;
252 
257  protected $hPt;
258 
263  protected $w;
264 
269  protected $h;
270 
275  protected $lMargin;
276 
281  protected $rMargin;
282 
287  protected $clMargin;
288 
293  protected $crMargin;
294 
299  protected $tMargin;
300 
305  protected $bMargin;
306 
312  protected $cell_padding = array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
313 
319  protected $cell_margin = array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
320 
325  protected $x;
326 
331  protected $y;
332 
337  protected $lasth;
338 
343  protected $LineWidth;
344 
349  protected $CoreFonts;
350 
355  protected $fonts = array();
356 
361  protected $FontFiles = array();
362 
367  protected $diffs = array();
368 
373  protected $images = array();
374 
379  protected $cached_files = array();
380 
385  protected $PageAnnots = array();
386 
391  protected $links = array();
392 
397  protected $FontFamily;
398 
403  protected $FontStyle;
404 
410  protected $FontAscent;
411 
417  protected $FontDescent;
418 
423  protected $underline;
424 
429  protected $overline;
430 
435  protected $CurrentFont;
436 
441  protected $FontSizePt;
442 
447  protected $FontSize;
448 
453  protected $DrawColor;
454 
459  protected $FillColor;
460 
465  protected $TextColor;
466 
471  protected $ColorFlag;
472 
477  protected $AutoPageBreak;
478 
483  protected $PageBreakTrigger;
484 
489  protected $InHeader = false;
490 
495  protected $InFooter = false;
496 
501  protected $ZoomMode;
502 
507  protected $LayoutMode;
508 
513  protected $docinfounicode = true;
514 
519  protected $title = '';
520 
525  protected $subject = '';
526 
531  protected $author = '';
532 
537  protected $keywords = '';
538 
543  protected $creator = '';
544 
549  protected $starting_page_number = 1;
550 
555  protected $alias_tot_pages = '{:ptp:}';
556 
561  protected $alias_num_page = '{:pnp:}';
562 
567  protected $alias_group_tot_pages = '{:ptg:}';
568 
573  protected $alias_group_num_page = '{:png:}';
574 
579  protected $alias_right_shift = '{rsc:';
580 
587  protected $img_rb_x;
588 
595  protected $img_rb_y;
596 
603  protected $imgscale = 1;
604 
611  protected $isunicode = false;
612 
619  protected $unicode;
620 
627  protected $encmaps;
628 
634  protected $PDFVersion = '1.7';
635 
640  protected $header_xobjid = -1;
641 
646  protected $header_xobj_autoreset = false;
647 
652  protected $header_margin;
653 
658  protected $footer_margin;
659 
665  protected $original_lMargin;
666 
672  protected $original_rMargin;
673 
678  protected $header_font;
679 
684  protected $footer_font;
685 
690  protected $l;
691 
696  protected $barcode = false;
697 
702  protected $print_header = true;
703 
708  protected $print_footer = true;
709 
714  protected $header_logo = '';
715 
720  protected $header_logo_width = 30;
721 
726  protected $header_title = '';
727 
732  protected $header_string = '';
733 
739  protected $header_text_color = array(0,0,0);
740 
746  protected $header_line_color = array(0,0,0);
747 
753  protected $footer_text_color = array(0,0,0);
754 
760  protected $footer_line_color = array(0,0,0);
761 
767  protected $txtshadow = array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal');
768 
773  protected $default_table_columns = 4;
774 
775  // variables for html parser
776 
781  protected $HREF = array();
782 
787  protected $fontlist = array();
788 
793  protected $fgcolor;
794 
799  protected $listordered = array();
800 
805  protected $listcount = array();
806 
811  protected $listnum = 0;
812 
817  protected $listindent = 0;
818 
823  protected $listindentlevel = 0;
824 
829  protected $bgcolor;
830 
835  protected $tempfontsize = 10;
836 
841  protected $lispacer = '';
842 
848  protected $encoding = 'UTF-8';
849 
856 
862  protected $rtl = false;
863 
869  protected $tmprtl = false;
870 
871  // --- Variables used for document encryption:
872 
878  protected $encrypted;
879 
885  protected $encryptdata = array();
886 
892  protected $last_enc_key;
893 
899  protected $last_enc_key_c;
900 
905  protected $enc_padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
906 
912  protected $file_id;
913 
914  // --- bookmark ---
915 
921  protected $outlines = array();
922 
928  protected $OutlineRoot;
929 
930  // --- javascript and form ---
931 
937  protected $javascript = '';
938 
944  protected $n_js;
945 
951  protected $linethrough;
952 
958  protected $ur = array();
959 
965  protected $dpi = 72;
966 
972  protected $newpagegroup = array();
973 
979  protected $pagegroups = array();
980 
986  protected $currpagegroup = 0;
987 
993  protected $extgstates;
994 
1000  protected $jpeg_quality;
1001 
1008 
1015 
1021  protected $PageMode;
1022 
1028  protected $gradients = array();
1029 
1035  protected $intmrk = array();
1036 
1042  protected $bordermrk = array();
1043 
1049  protected $emptypagemrk = array();
1050 
1056  protected $cntmrk = array();
1057 
1063  protected $footerpos = array();
1064 
1070  protected $footerlen = array();
1071 
1077  protected $newline = true;
1078 
1084  protected $endlinex = 0;
1085 
1091  protected $linestyleWidth = '';
1092 
1098  protected $linestyleCap = '0 J';
1099 
1105  protected $linestyleJoin = '0 j';
1106 
1112  protected $linestyleDash = '[] 0 d';
1113 
1119  protected $openMarkedContent = false;
1120 
1126  protected $htmlvspace = 0;
1127 
1133  protected $spot_colors = array();
1134 
1140  protected $lisymbol = '';
1141 
1147  protected $epsmarker = 'x#!#EPS#!#x';
1148 
1154  protected $transfmatrix = array();
1155 
1161  protected $transfmatrix_key = 0;
1162 
1168  protected $booklet = false;
1169 
1175  protected $feps = 0.005;
1176 
1182  protected $tagvspaces = array();
1183 
1189  protected $customlistindent = -1;
1190 
1196  protected $opencell = true;
1197 
1203  protected $embeddedfiles = array();
1204 
1210  protected $premode = false;
1211 
1218  protected $transfmrk = array();
1219 
1225  protected $htmlLinkColorArray = array(0, 0, 255);
1226 
1232  protected $htmlLinkFontStyle = 'U';
1233 
1239  protected $numpages = 0;
1240 
1246  protected $pagelen = array();
1247 
1253  protected $numimages = 0;
1254 
1260  protected $imagekeys = array();
1261 
1267  protected $bufferlen = 0;
1268 
1274  protected $diskcache = false;
1275 
1281  protected $numfonts = 0;
1282 
1288  protected $fontkeys = array();
1289 
1295  protected $font_obj_ids = array();
1296 
1302  protected $pageopen = array();
1303 
1309  protected $default_monospaced_font = 'courier';
1310 
1316  protected $objcopy;
1317 
1323  protected $cache_file_length = array();
1324 
1330  protected $thead = '';
1331 
1337  protected $theadMargins = array();
1338 
1344  protected $cache_UTF8StringToArray = array();
1345 
1352 
1359 
1365  protected $sign = false;
1366 
1372  protected $signature_data = array();
1373 
1379  protected $signature_max_length = 11742;
1380 
1386  protected $signature_appearance = array('page' => 1, 'rect' => '0 0 0 0');
1387 
1393  protected $empty_signature_appearance = array();
1394 
1400  protected $re_spaces = '/[^\S\xa0]/';
1401 
1407  protected $re_space = array('p' => '[^\S\xa0]', 'm' => '');
1408 
1414  protected $sig_obj_id = 0;
1415 
1421  protected $byterange_string = '/ByteRange[0 ********** ********** **********]';
1422 
1428  protected $sig_annot_ref = '***SIGANNREF*** 0 R';
1429 
1435  protected $page_obj_id = array();
1436 
1442  protected $form_obj_id = array();
1443 
1449  protected $default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128));
1450 
1456  protected $js_objects = array();
1457 
1463  protected $form_action = '';
1464 
1470  protected $form_enctype = 'application/x-www-form-urlencoded';
1471 
1477  protected $form_mode = 'post';
1478 
1484  protected $annotation_fonts = array();
1485 
1491  protected $radiobutton_groups = array();
1492 
1498  protected $radio_groups = array();
1499 
1505  protected $textindent = 0;
1506 
1513 
1519  protected $start_transaction_y = 0;
1520 
1526  protected $inthead = false;
1527 
1533  protected $columns = array();
1534 
1540  protected $num_columns = 1;
1541 
1547  protected $current_column = 0;
1548 
1554  protected $column_start_page = 0;
1555 
1561  protected $maxselcol = array('page' => 0, 'column' => 0);
1562 
1568  protected $colxshift = array('x' => 0, 's' => array('H' => 0, 'V' => 0), 'p' => array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0));
1569 
1575  protected $textrendermode = 0;
1576 
1582  protected $textstrokewidth = 0;
1583 
1589  protected $strokecolor;
1590 
1596  protected $pdfunit = 'mm';
1597 
1602  protected $tocpage = false;
1603 
1609  protected $rasterize_vector_images = false;
1610 
1616  protected $font_subsetting = true;
1617 
1623  protected $default_graphic_vars = array();
1624 
1630  protected $xobjects = array();
1631 
1637  protected $inxobj = false;
1638 
1644  protected $xobjid = '';
1645 
1651  protected $font_stretching = 100;
1652 
1658  protected $font_spacing = 0;
1659 
1666  protected $page_regions = array();
1667 
1672  protected $check_page_regions = true;
1673 
1679  protected $webcolor = array();
1680 
1686  protected $spotcolor = array();
1687 
1693  protected $pdflayers = array();
1694 
1700  protected $dests = array();
1701 
1707  protected $n_dests;
1708 
1714  protected $svgdir = '';
1715 
1721  protected $svgunit = 'px';
1722 
1728  protected $svggradients = array();
1729 
1735  protected $svggradientid = 0;
1736 
1742  protected $svgdefsmode = false;
1743 
1749  protected $svgdefs = array();
1750 
1756  protected $svgclipmode = false;
1757 
1763  protected $svgclippaths = array();
1764 
1770  protected $svgcliptm = array();
1771 
1777  protected $svgclipid = 0;
1778 
1784  protected $svgtext = '';
1785 
1791  protected $svgtextmode = array();
1792 
1798  protected $svginheritprop = array('clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cursor', 'direction', 'fill', 'fill-opacity', 'fill-rule', 'font', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering', 'kerning', 'letter-spacing', 'marker', 'marker-end', 'marker-mid', 'marker-start', 'pointer-events', 'shape-rendering', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-rendering', 'visibility', 'word-spacing', 'writing-mode');
1799 
1805  protected $svgstyles = array(array(
1806  'alignment-baseline' => 'auto',
1807  'baseline-shift' => 'baseline',
1808  'clip' => 'auto',
1809  'clip-path' => 'none',
1810  'clip-rule' => 'nonzero',
1811  'color' => 'black',
1812  'color-interpolation' => 'sRGB',
1813  'color-interpolation-filters' => 'linearRGB',
1814  'color-profile' => 'auto',
1815  'color-rendering' => 'auto',
1816  'cursor' => 'auto',
1817  'direction' => 'ltr',
1818  'display' => 'inline',
1819  'dominant-baseline' => 'auto',
1820  'enable-background' => 'accumulate',
1821  'fill' => 'black',
1822  'fill-opacity' => 1,
1823  'fill-rule' => 'nonzero',
1824  'filter' => 'none',
1825  'flood-color' => 'black',
1826  'flood-opacity' => 1,
1827  'font' => '',
1828  'font-family' => 'helvetica',
1829  'font-size' => 'medium',
1830  'font-size-adjust' => 'none',
1831  'font-stretch' => 'normal',
1832  'font-style' => 'normal',
1833  'font-variant' => 'normal',
1834  'font-weight' => 'normal',
1835  'glyph-orientation-horizontal' => '0deg',
1836  'glyph-orientation-vertical' => 'auto',
1837  'image-rendering' => 'auto',
1838  'kerning' => 'auto',
1839  'letter-spacing' => 'normal',
1840  'lighting-color' => 'white',
1841  'marker' => '',
1842  'marker-end' => 'none',
1843  'marker-mid' => 'none',
1844  'marker-start' => 'none',
1845  'mask' => 'none',
1846  'opacity' => 1,
1847  'overflow' => 'auto',
1848  'pointer-events' => 'visiblePainted',
1849  'shape-rendering' => 'auto',
1850  'stop-color' => 'black',
1851  'stop-opacity' => 1,
1852  'stroke' => 'none',
1853  'stroke-dasharray' => 'none',
1854  'stroke-dashoffset' => 0,
1855  'stroke-linecap' => 'butt',
1856  'stroke-linejoin' => 'miter',
1857  'stroke-miterlimit' => 4,
1858  'stroke-opacity' => 1,
1859  'stroke-width' => 1,
1860  'text-anchor' => 'start',
1861  'text-decoration' => 'none',
1862  'text-rendering' => 'auto',
1863  'unicode-bidi' => 'normal',
1864  'visibility' => 'visible',
1865  'word-spacing' => 'normal',
1866  'writing-mode' => 'lr-tb',
1867  'text-color' => 'black',
1868  'transfmatrix' => array(1, 0, 0, 1, 0, 0)
1869  ));
1870 
1876  protected $force_srgb = false;
1877 
1883  protected $pdfa_mode = false;
1884 
1891 
1898 
1904  protected $custom_xmp = '';
1905 
1912  protected $overprint = array('OP' => false, 'op' => false, 'OPM' => 0);
1913 
1920  protected $alpha = array('CA' => 1, 'ca' => 1, 'BM' => '/Normal', 'AIS' => false);
1921 
1927  protected $page_boxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
1928 
1934  protected $pdfproducer;
1935 
1941  protected $tcpdflink = true;
1942 
1948  protected $gdgammacache = array();
1949 
1950  //------------------------------------------------------------
1951  // METHODS
1952  //------------------------------------------------------------
1953 
1967  public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) {
1968  /* Set internal character encoding to ASCII */
1969  if (function_exists('mb_internal_encoding') AND mb_internal_encoding()) {
1970  $this->internal_encoding = mb_internal_encoding();
1971  // DESACTIVATION PAR GB CAR INTERFERENCE AVEC LE RESTE DE PEEL : mb_internal_encoding('ASCII');
1972  }
1973  // get array of HTML colors
1974  require(dirname(__FILE__).'/htmlcolors.php');
1975  $this->webcolor = $webcolor;
1976  // get array of custom spot colors
1977  if (file_exists(dirname(__FILE__).'/spotcolors.php')) {
1978  require(dirname(__FILE__).'/spotcolors.php');
1979  $this->spotcolor = $spotcolor;
1980  } else {
1981  $this->spotcolor = array();
1982  }
1983  require_once(dirname(__FILE__).'/unicode_data.php');
1984  $this->unicode = new TCPDF_UNICODE_DATA();
1985  require_once(dirname(__FILE__).'/encodings_maps.php');
1986  $this->encmaps = new TCPDF_ENCODING_MAPS();
1987  $this->font_obj_ids = array();
1988  $this->page_obj_id = array();
1989  $this->form_obj_id = array();
1990  // set pdf/a mode
1991  $this->pdfa_mode = $pdfa;
1992  $this->force_srgb = false;
1993  // set disk caching
1994  $this->diskcache = $diskcache ? true : false;
1995  // set language direction
1996  $this->rtl = false;
1997  $this->tmprtl = false;
1998  // some checks
1999  $this->_dochecks();
2000  // initialization of properties
2001  $this->isunicode = $unicode;
2002  $this->page = 0;
2003  $this->transfmrk[0] = array();
2004  $this->pagedim = array();
2005  $this->n = 2;
2006  $this->buffer = '';
2007  $this->pages = array();
2008  $this->state = 0;
2009  $this->fonts = array();
2010  $this->FontFiles = array();
2011  $this->diffs = array();
2012  $this->images = array();
2013  $this->links = array();
2014  $this->gradients = array();
2015  $this->InFooter = false;
2016  $this->lasth = 0;
2017  $this->FontFamily = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica';
2018  $this->FontStyle = '';
2019  $this->FontSizePt = 12;
2020  $this->underline = false;
2021  $this->overline = false;
2022  $this->linethrough = false;
2023  $this->DrawColor = '0 G';
2024  $this->FillColor = '0 g';
2025  $this->TextColor = '0 g';
2026  $this->ColorFlag = false;
2027  $this->pdflayers = array();
2028  // encryption values
2029  $this->encrypted = false;
2030  $this->last_enc_key = '';
2031  // standard Unicode fonts
2032  $this->CoreFonts = array(
2033  'courier'=>'Courier',
2034  'courierB'=>'Courier-Bold',
2035  'courierI'=>'Courier-Oblique',
2036  'courierBI'=>'Courier-BoldOblique',
2037  'helvetica'=>'Helvetica',
2038  'helveticaB'=>'Helvetica-Bold',
2039  'helveticaI'=>'Helvetica-Oblique',
2040  'helveticaBI'=>'Helvetica-BoldOblique',
2041  'times'=>'Times-Roman',
2042  'timesB'=>'Times-Bold',
2043  'timesI'=>'Times-Italic',
2044  'timesBI'=>'Times-BoldItalic',
2045  'symbol'=>'Symbol',
2046  'zapfdingbats'=>'ZapfDingbats'
2047  );
2048  // set scale factor
2049  $this->setPageUnit($unit);
2050  // set page format and orientation
2051  $this->setPageFormat($format, $orientation);
2052  // page margins (1 cm)
2053  $margin = 28.35 / $this->k;
2054  $this->SetMargins($margin, $margin);
2055  $this->clMargin = $this->lMargin;
2056  $this->crMargin = $this->rMargin;
2057  // internal cell padding
2058  $cpadding = $margin / 10;
2059  $this->setCellPaddings($cpadding, 0, $cpadding, 0);
2060  // cell margins
2061  $this->setCellMargins(0, 0, 0, 0);
2062  // line width (0.2 mm)
2063  $this->LineWidth = 0.57 / $this->k;
2064  $this->linestyleWidth = sprintf('%F w', ($this->LineWidth * $this->k));
2065  $this->linestyleCap = '0 J';
2066  $this->linestyleJoin = '0 j';
2067  $this->linestyleDash = '[] 0 d';
2068  // automatic page break
2069  $this->SetAutoPageBreak(true, (2 * $margin));
2070  // full width display mode
2071  $this->SetDisplayMode('fullwidth');
2072  // compression
2073  $this->SetCompression();
2074  // set default PDF version number
2075  $this->setPDFVersion();
2076  $this->pdfproducer = "\x54\x43\x50\x44\x46\x20".$this->tcpdf_version."\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
2077  $this->tcpdflink = true;
2078  $this->encoding = $encoding;
2079  $this->HREF = array();
2080  $this->getFontsList();
2081  $this->fgcolor = array('R' => 0, 'G' => 0, 'B' => 0);
2082  $this->strokecolor = array('R' => 0, 'G' => 0, 'B' => 0);
2083  $this->bgcolor = array('R' => 255, 'G' => 255, 'B' => 255);
2084  $this->extgstates = array();
2085  $this->setTextShadow();
2086  // user's rights
2087  $this->sign = false;
2088  $this->ur['enabled'] = false;
2089  $this->ur['document'] = '/FullSave';
2090  $this->ur['annots'] = '/Create/Delete/Modify/Copy/Import/Export';
2091  $this->ur['form'] = '/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate';
2092  $this->ur['signature'] = '/Modify';
2093  $this->ur['ef'] = '/Create/Delete/Modify/Import';
2094  $this->ur['formex'] = '';
2095  $this->signature_appearance = array('page' => 1, 'rect' => '0 0 0 0');
2096  $this->empty_signature_appearance = array();
2097  // set default JPEG quality
2098  $this->jpeg_quality = $GLOBALS['site_parameters']['jpeg_quality'];
2099  // initialize some settings
2100  $this->utf8Bidi(array(''), '');
2101  // set default font
2102  $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt);
2103  // check if PCRE Unicode support is enabled
2104  if ($this->isunicode AND (@preg_match('/\pL/u', 'a') == 1)) {
2105  // PCRE unicode support is turned ON
2106  // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator.
2107  // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants.
2108  // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between.
2109  //$this->setSpacesRE('/[^\S\P{Z}\P{Lo}\xa0]/u');
2110  $this->setSpacesRE('/[^\S\P{Z}\xa0]/u');
2111  } else {
2112  // PCRE unicode support is turned OFF
2113  $this->setSpacesRE('/[^\S\xa0]/');
2114  }
2115  $this->default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128));
2116  // set file ID for trailer
2117  $serformat = (is_array($format) ? serialize($format) : $format);
2118  $this->file_id = md5($this->getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding));
2119  // set document creation and modification timestamp
2120  $this->doc_creation_timestamp = time();
2121  $this->doc_modification_timestamp = $this->doc_creation_timestamp;
2122  // get default graphic vars
2123  $this->default_graphic_vars = $this->getGraphicVars();
2124  $this->header_xobj_autoreset = false;
2125  $this->custom_xmp = '';
2126  }
2127 
2133  public function __destruct() {
2134  // restore internal encoding
2135  if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) {
2136  mb_internal_encoding($this->internal_encoding);
2137  }
2138  // unset all class variables
2139  $this->_destroy(true);
2140  }
2141 
2148  public function getTCPDFVersion() {
2149  return $this->tcpdf_version;
2150  }
2151 
2158  public function setPageUnit($unit) {
2159  $unit = strtolower($unit);
2160  //Set scale factor
2161  switch ($unit) {
2162  // points
2163  case 'px':
2164  case 'pt': {
2165  $this->k = 1;
2166  break;
2167  }
2168  // millimeters
2169  case 'mm': {
2170  $this->k = $this->dpi / 25.4;
2171  break;
2172  }
2173  // centimeters
2174  case 'cm': {
2175  $this->k = $this->dpi / 2.54;
2176  break;
2177  }
2178  // inches
2179  case 'in': {
2180  $this->k = $this->dpi;
2181  break;
2182  }
2183  // unsupported unit
2184  default : {
2185  $this->Error('Incorrect unit: '.$unit);
2186  break;
2187  }
2188  }
2189  $this->pdfunit = $unit;
2190  if (isset($this->CurOrientation)) {
2191  $this->setPageOrientation($this->CurOrientation);
2192  }
2193  }
2194 
2509  public function getPageSizeFromFormat($format) {
2510  // Paper cordinates are calculated in this way: (inches * 72) where (1 inch = 25.4 mm)
2511  switch (strtoupper($format)) {
2512  // ISO 216 A Series + 2 SIS 014711 extensions
2513  case 'A0' : {$pf = array( 2383.937, 3370.394); break;}
2514  case 'A1' : {$pf = array( 1683.780, 2383.937); break;}
2515  case 'A2' : {$pf = array( 1190.551, 1683.780); break;}
2516  case 'A3' : {$pf = array( 841.890, 1190.551); break;}
2517  case 'A4' : {$pf = array( 595.276, 841.890); break;}
2518  case 'A5' : {$pf = array( 419.528, 595.276); break;}
2519  case 'A6' : {$pf = array( 297.638, 419.528); break;}
2520  case 'A7' : {$pf = array( 209.764, 297.638); break;}
2521  case 'A8' : {$pf = array( 147.402, 209.764); break;}
2522  case 'A9' : {$pf = array( 104.882, 147.402); break;}
2523  case 'A10': {$pf = array( 73.701, 104.882); break;}
2524  case 'A11': {$pf = array( 51.024, 73.701); break;}
2525  case 'A12': {$pf = array( 36.850, 51.024); break;}
2526  // ISO 216 B Series + 2 SIS 014711 extensions
2527  case 'B0' : {$pf = array( 2834.646, 4008.189); break;}
2528  case 'B1' : {$pf = array( 2004.094, 2834.646); break;}
2529  case 'B2' : {$pf = array( 1417.323, 2004.094); break;}
2530  case 'B3' : {$pf = array( 1000.630, 1417.323); break;}
2531  case 'B4' : {$pf = array( 708.661, 1000.630); break;}
2532  case 'B5' : {$pf = array( 498.898, 708.661); break;}
2533  case 'B6' : {$pf = array( 354.331, 498.898); break;}
2534  case 'B7' : {$pf = array( 249.449, 354.331); break;}
2535  case 'B8' : {$pf = array( 175.748, 249.449); break;}
2536  case 'B9' : {$pf = array( 124.724, 175.748); break;}
2537  case 'B10': {$pf = array( 87.874, 124.724); break;}
2538  case 'B11': {$pf = array( 62.362, 87.874); break;}
2539  case 'B12': {$pf = array( 42.520, 62.362); break;}
2540  // ISO 216 C Series + 2 SIS 014711 extensions + 2 EXTENSION
2541  case 'C0' : {$pf = array( 2599.370, 3676.535); break;}
2542  case 'C1' : {$pf = array( 1836.850, 2599.370); break;}
2543  case 'C2' : {$pf = array( 1298.268, 1836.850); break;}
2544  case 'C3' : {$pf = array( 918.425, 1298.268); break;}
2545  case 'C4' : {$pf = array( 649.134, 918.425); break;}
2546  case 'C5' : {$pf = array( 459.213, 649.134); break;}
2547  case 'C6' : {$pf = array( 323.150, 459.213); break;}
2548  case 'C7' : {$pf = array( 229.606, 323.150); break;}
2549  case 'C8' : {$pf = array( 161.575, 229.606); break;}
2550  case 'C9' : {$pf = array( 113.386, 161.575); break;}
2551  case 'C10': {$pf = array( 79.370, 113.386); break;}
2552  case 'C11': {$pf = array( 56.693, 79.370); break;}
2553  case 'C12': {$pf = array( 39.685, 56.693); break;}
2554  case 'C76': {$pf = array( 229.606, 459.213); break;}
2555  case 'DL' : {$pf = array( 311.811, 623.622); break;}
2556  // SIS 014711 E Series
2557  case 'E0' : {$pf = array( 2491.654, 3517.795); break;}
2558  case 'E1' : {$pf = array( 1757.480, 2491.654); break;}
2559  case 'E2' : {$pf = array( 1247.244, 1757.480); break;}
2560  case 'E3' : {$pf = array( 878.740, 1247.244); break;}
2561  case 'E4' : {$pf = array( 623.622, 878.740); break;}
2562  case 'E5' : {$pf = array( 439.370, 623.622); break;}
2563  case 'E6' : {$pf = array( 311.811, 439.370); break;}
2564  case 'E7' : {$pf = array( 221.102, 311.811); break;}
2565  case 'E8' : {$pf = array( 155.906, 221.102); break;}
2566  case 'E9' : {$pf = array( 110.551, 155.906); break;}
2567  case 'E10': {$pf = array( 76.535, 110.551); break;}
2568  case 'E11': {$pf = array( 53.858, 76.535); break;}
2569  case 'E12': {$pf = array( 36.850, 53.858); break;}
2570  // SIS 014711 G Series
2571  case 'G0' : {$pf = array( 2715.591, 3838.110); break;}
2572  case 'G1' : {$pf = array( 1919.055, 2715.591); break;}
2573  case 'G2' : {$pf = array( 1357.795, 1919.055); break;}
2574  case 'G3' : {$pf = array( 958.110, 1357.795); break;}
2575  case 'G4' : {$pf = array( 677.480, 958.110); break;}
2576  case 'G5' : {$pf = array( 479.055, 677.480); break;}
2577  case 'G6' : {$pf = array( 337.323, 479.055); break;}
2578  case 'G7' : {$pf = array( 238.110, 337.323); break;}
2579  case 'G8' : {$pf = array( 167.244, 238.110); break;}
2580  case 'G9' : {$pf = array( 119.055, 167.244); break;}
2581  case 'G10': {$pf = array( 82.205, 119.055); break;}
2582  case 'G11': {$pf = array( 59.528, 82.205); break;}
2583  case 'G12': {$pf = array( 39.685, 59.528); break;}
2584  // ISO Press
2585  case 'RA0': {$pf = array( 2437.795, 3458.268); break;}
2586  case 'RA1': {$pf = array( 1729.134, 2437.795); break;}
2587  case 'RA2': {$pf = array( 1218.898, 1729.134); break;}
2588  case 'RA3': {$pf = array( 864.567, 1218.898); break;}
2589  case 'RA4': {$pf = array( 609.449, 864.567); break;}
2590  case 'SRA0': {$pf = array( 2551.181, 3628.346); break;}
2591  case 'SRA1': {$pf = array( 1814.173, 2551.181); break;}
2592  case 'SRA2': {$pf = array( 1275.591, 1814.173); break;}
2593  case 'SRA3': {$pf = array( 907.087, 1275.591); break;}
2594  case 'SRA4': {$pf = array( 637.795, 907.087); break;}
2595  // German DIN 476
2596  case '4A0': {$pf = array( 4767.874, 6740.787); break;}
2597  case '2A0': {$pf = array( 3370.394, 4767.874); break;}
2598  // Variations on the ISO Standard
2599  case 'A2_EXTRA' : {$pf = array( 1261.417, 1754.646); break;}
2600  case 'A3+' : {$pf = array( 932.598, 1369.134); break;}
2601  case 'A3_EXTRA' : {$pf = array( 912.756, 1261.417); break;}
2602  case 'A3_SUPER' : {$pf = array( 864.567, 1440.000); break;}
2603  case 'SUPER_A3' : {$pf = array( 864.567, 1380.472); break;}
2604  case 'A4_EXTRA' : {$pf = array( 666.142, 912.756); break;}
2605  case 'A4_SUPER' : {$pf = array( 649.134, 912.756); break;}
2606  case 'SUPER_A4' : {$pf = array( 643.465, 1009.134); break;}
2607  case 'A4_LONG' : {$pf = array( 595.276, 986.457); break;}
2608  case 'F4' : {$pf = array( 595.276, 935.433); break;}
2609  case 'SO_B5_EXTRA': {$pf = array( 572.598, 782.362); break;}
2610  case 'A5_EXTRA' : {$pf = array( 490.394, 666.142); break;}
2611  // ANSI Series
2612  case 'ANSI_E': {$pf = array( 2448.000, 3168.000); break;}
2613  case 'ANSI_D': {$pf = array( 1584.000, 2448.000); break;}
2614  case 'ANSI_C': {$pf = array( 1224.000, 1584.000); break;}
2615  case 'ANSI_B': {$pf = array( 792.000, 1224.000); break;}
2616  case 'ANSI_A': {$pf = array( 612.000, 792.000); break;}
2617  // Traditional 'Loose' North American Paper Sizes
2618  case 'USLEDGER':
2619  case 'LEDGER' : {$pf = array( 1224.000, 792.000); break;}
2620  case 'ORGANIZERK':
2621  case 'BIBLE':
2622  case 'USTABLOID':
2623  case 'TABLOID': {$pf = array( 792.000, 1224.000); break;}
2624  case 'ORGANIZERM':
2625  case 'USLETTER':
2626  case 'LETTER' : {$pf = array( 612.000, 792.000); break;}
2627  case 'USLEGAL':
2628  case 'LEGAL' : {$pf = array( 612.000, 1008.000); break;}
2629  case 'GOVERNMENTLETTER':
2630  case 'GLETTER': {$pf = array( 576.000, 756.000); break;}
2631  case 'JUNIORLEGAL':
2632  case 'JLEGAL' : {$pf = array( 576.000, 360.000); break;}
2633  // Other North American Paper Sizes
2634  case 'QUADDEMY': {$pf = array( 2520.000, 3240.000); break;}
2635  case 'SUPER_B': {$pf = array( 936.000, 1368.000); break;}
2636  case 'QUARTO': {$pf = array( 648.000, 792.000); break;}
2637  case 'GOVERNMENTLEGAL':
2638  case 'FOLIO': {$pf = array( 612.000, 936.000); break;}
2639  case 'MONARCH':
2640  case 'EXECUTIVE': {$pf = array( 522.000, 756.000); break;}
2641  case 'ORGANIZERL':
2642  case 'STATEMENT':
2643  case 'MEMO': {$pf = array( 396.000, 612.000); break;}
2644  case 'FOOLSCAP': {$pf = array( 595.440, 936.000); break;}
2645  case 'COMPACT': {$pf = array( 306.000, 486.000); break;}
2646  case 'ORGANIZERJ': {$pf = array( 198.000, 360.000); break;}
2647  // Canadian standard CAN 2-9.60M
2648  case 'P1': {$pf = array( 1587.402, 2437.795); break;}
2649  case 'P2': {$pf = array( 1218.898, 1587.402); break;}
2650  case 'P3': {$pf = array( 793.701, 1218.898); break;}
2651  case 'P4': {$pf = array( 609.449, 793.701); break;}
2652  case 'P5': {$pf = array( 396.850, 609.449); break;}
2653  case 'P6': {$pf = array( 303.307, 396.850); break;}
2654  // North American Architectural Sizes
2655  case 'ARCH_E' : {$pf = array( 2592.000, 3456.000); break;}
2656  case 'ARCH_E1': {$pf = array( 2160.000, 3024.000); break;}
2657  case 'ARCH_D' : {$pf = array( 1728.000, 2592.000); break;}
2658  case 'BROADSHEET':
2659  case 'ARCH_C' : {$pf = array( 1296.000, 1728.000); break;}
2660  case 'ARCH_B' : {$pf = array( 864.000, 1296.000); break;}
2661  case 'ARCH_A' : {$pf = array( 648.000, 864.000); break;}
2662  // --- North American Envelope Sizes ---
2663  // - Announcement Envelopes
2664  case 'ANNENV_A2' : {$pf = array( 314.640, 414.000); break;}
2665  case 'ANNENV_A6' : {$pf = array( 342.000, 468.000); break;}
2666  case 'ANNENV_A7' : {$pf = array( 378.000, 522.000); break;}
2667  case 'ANNENV_A8' : {$pf = array( 396.000, 584.640); break;}
2668  case 'ANNENV_A10' : {$pf = array( 450.000, 692.640); break;}
2669  case 'ANNENV_SLIM': {$pf = array( 278.640, 638.640); break;}
2670  // - Commercial Envelopes
2671  case 'COMMENV_N6_1/4': {$pf = array( 252.000, 432.000); break;}
2672  case 'COMMENV_N6_3/4': {$pf = array( 260.640, 468.000); break;}
2673  case 'COMMENV_N8' : {$pf = array( 278.640, 540.000); break;}
2674  case 'COMMENV_N9' : {$pf = array( 278.640, 638.640); break;}
2675  case 'COMMENV_N10' : {$pf = array( 296.640, 684.000); break;}
2676  case 'COMMENV_N11' : {$pf = array( 324.000, 746.640); break;}
2677  case 'COMMENV_N12' : {$pf = array( 342.000, 792.000); break;}
2678  case 'COMMENV_N14' : {$pf = array( 360.000, 828.000); break;}
2679  // - Catalogue Envelopes
2680  case 'CATENV_N1' : {$pf = array( 432.000, 648.000); break;}
2681  case 'CATENV_N1_3/4' : {$pf = array( 468.000, 684.000); break;}
2682  case 'CATENV_N2' : {$pf = array( 468.000, 720.000); break;}
2683  case 'CATENV_N3' : {$pf = array( 504.000, 720.000); break;}
2684  case 'CATENV_N6' : {$pf = array( 540.000, 756.000); break;}
2685  case 'CATENV_N7' : {$pf = array( 576.000, 792.000); break;}
2686  case 'CATENV_N8' : {$pf = array( 594.000, 810.000); break;}
2687  case 'CATENV_N9_1/2' : {$pf = array( 612.000, 756.000); break;}
2688  case 'CATENV_N9_3/4' : {$pf = array( 630.000, 810.000); break;}
2689  case 'CATENV_N10_1/2': {$pf = array( 648.000, 864.000); break;}
2690  case 'CATENV_N12_1/2': {$pf = array( 684.000, 900.000); break;}
2691  case 'CATENV_N13_1/2': {$pf = array( 720.000, 936.000); break;}
2692  case 'CATENV_N14_1/4': {$pf = array( 810.000, 882.000); break;}
2693  case 'CATENV_N14_1/2': {$pf = array( 828.000, 1044.000); break;}
2694  // Japanese (JIS P 0138-61) Standard B-Series
2695  case 'JIS_B0' : {$pf = array( 2919.685, 4127.244); break;}
2696  case 'JIS_B1' : {$pf = array( 2063.622, 2919.685); break;}
2697  case 'JIS_B2' : {$pf = array( 1459.843, 2063.622); break;}
2698  case 'JIS_B3' : {$pf = array( 1031.811, 1459.843); break;}
2699  case 'JIS_B4' : {$pf = array( 728.504, 1031.811); break;}
2700  case 'JIS_B5' : {$pf = array( 515.906, 728.504); break;}
2701  case 'JIS_B6' : {$pf = array( 362.835, 515.906); break;}
2702  case 'JIS_B7' : {$pf = array( 257.953, 362.835); break;}
2703  case 'JIS_B8' : {$pf = array( 181.417, 257.953); break;}
2704  case 'JIS_B9' : {$pf = array( 127.559, 181.417); break;}
2705  case 'JIS_B10': {$pf = array( 90.709, 127.559); break;}
2706  case 'JIS_B11': {$pf = array( 62.362, 90.709); break;}
2707  case 'JIS_B12': {$pf = array( 45.354, 62.362); break;}
2708  // PA Series
2709  case 'PA0' : {$pf = array( 2381.102, 3174.803,); break;}
2710  case 'PA1' : {$pf = array( 1587.402, 2381.102); break;}
2711  case 'PA2' : {$pf = array( 1190.551, 1587.402); break;}
2712  case 'PA3' : {$pf = array( 793.701, 1190.551); break;}
2713  case 'PA4' : {$pf = array( 595.276, 793.701); break;}
2714  case 'PA5' : {$pf = array( 396.850, 595.276); break;}
2715  case 'PA6' : {$pf = array( 297.638, 396.850); break;}
2716  case 'PA7' : {$pf = array( 198.425, 297.638); break;}
2717  case 'PA8' : {$pf = array( 147.402, 198.425); break;}
2718  case 'PA9' : {$pf = array( 99.213, 147.402); break;}
2719  case 'PA10': {$pf = array( 73.701, 99.213); break;}
2720  // Standard Photographic Print Sizes
2721  case 'PASSPORT_PHOTO': {$pf = array( 99.213, 127.559); break;}
2722  case 'E' : {$pf = array( 233.858, 340.157); break;}
2723  case 'L':
2724  case '3R' : {$pf = array( 252.283, 360.000); break;}
2725  case 'KG':
2726  case '4R' : {$pf = array( 289.134, 430.866); break;}
2727  case '4D' : {$pf = array( 340.157, 430.866); break;}
2728  case '2L':
2729  case '5R' : {$pf = array( 360.000, 504.567); break;}
2730  case '8P':
2731  case '6R' : {$pf = array( 430.866, 575.433); break;}
2732  case '6P':
2733  case '8R' : {$pf = array( 575.433, 720.000); break;}
2734  case '6PW':
2735  case 'S8R' : {$pf = array( 575.433, 864.567); break;}
2736  case '4P':
2737  case '10R' : {$pf = array( 720.000, 864.567); break;}
2738  case '4PW':
2739  case 'S10R': {$pf = array( 720.000, 1080.000); break;}
2740  case '11R' : {$pf = array( 790.866, 1009.134); break;}
2741  case 'S11R': {$pf = array( 790.866, 1224.567); break;}
2742  case '12R' : {$pf = array( 864.567, 1080.000); break;}
2743  case 'S12R': {$pf = array( 864.567, 1292.598); break;}
2744  // Common Newspaper Sizes
2745  case 'NEWSPAPER_BROADSHEET': {$pf = array( 2125.984, 1700.787); break;}
2746  case 'NEWSPAPER_BERLINER' : {$pf = array( 1332.283, 892.913); break;}
2747  case 'NEWSPAPER_TABLOID':
2748  case 'NEWSPAPER_COMPACT' : {$pf = array( 1218.898, 793.701); break;}
2749  // Business Cards
2750  case 'CREDIT_CARD':
2751  case 'BUSINESS_CARD':
2752  case 'BUSINESS_CARD_ISO7810': {$pf = array( 153.014, 242.646); break;}
2753  case 'BUSINESS_CARD_ISO216' : {$pf = array( 147.402, 209.764); break;}
2754  case 'BUSINESS_CARD_IT':
2755  case 'BUSINESS_CARD_UK':
2756  case 'BUSINESS_CARD_FR':
2757  case 'BUSINESS_CARD_DE':
2758  case 'BUSINESS_CARD_ES' : {$pf = array( 155.906, 240.945); break;}
2759  case 'BUSINESS_CARD_CA':
2760  case 'BUSINESS_CARD_US' : {$pf = array( 144.567, 252.283); break;}
2761  case 'BUSINESS_CARD_JP' : {$pf = array( 155.906, 257.953); break;}
2762  case 'BUSINESS_CARD_HK' : {$pf = array( 153.071, 255.118); break;}
2763  case 'BUSINESS_CARD_AU':
2764  case 'BUSINESS_CARD_DK':
2765  case 'BUSINESS_CARD_SE' : {$pf = array( 155.906, 255.118); break;}
2766  case 'BUSINESS_CARD_RU':
2767  case 'BUSINESS_CARD_CZ':
2768  case 'BUSINESS_CARD_FI':
2769  case 'BUSINESS_CARD_HU':
2770  case 'BUSINESS_CARD_IL' : {$pf = array( 141.732, 255.118); break;}
2771  // Billboards
2772  case '4SHEET' : {$pf = array( 2880.000, 4320.000); break;}
2773  case '6SHEET' : {$pf = array( 3401.575, 5102.362); break;}
2774  case '12SHEET': {$pf = array( 8640.000, 4320.000); break;}
2775  case '16SHEET': {$pf = array( 5760.000, 8640.000); break;}
2776  case '32SHEET': {$pf = array(11520.000, 8640.000); break;}
2777  case '48SHEET': {$pf = array(17280.000, 8640.000); break;}
2778  case '64SHEET': {$pf = array(23040.000, 8640.000); break;}
2779  case '96SHEET': {$pf = array(34560.000, 8640.000); break;}
2780  // Old European Sizes
2781  // - Old Imperial English Sizes
2782  case 'EN_EMPEROR' : {$pf = array( 3456.000, 5184.000); break;}
2783  case 'EN_ANTIQUARIAN' : {$pf = array( 2232.000, 3816.000); break;}
2784  case 'EN_GRAND_EAGLE' : {$pf = array( 2070.000, 3024.000); break;}
2785  case 'EN_DOUBLE_ELEPHANT' : {$pf = array( 1926.000, 2880.000); break;}
2786  case 'EN_ATLAS' : {$pf = array( 1872.000, 2448.000); break;}
2787  case 'EN_COLOMBIER' : {$pf = array( 1692.000, 2484.000); break;}
2788  case 'EN_ELEPHANT' : {$pf = array( 1656.000, 2016.000); break;}
2789  case 'EN_DOUBLE_DEMY' : {$pf = array( 1620.000, 2556.000); break;}
2790  case 'EN_IMPERIAL' : {$pf = array( 1584.000, 2160.000); break;}
2791  case 'EN_PRINCESS' : {$pf = array( 1548.000, 2016.000); break;}
2792  case 'EN_CARTRIDGE' : {$pf = array( 1512.000, 1872.000); break;}
2793  case 'EN_DOUBLE_LARGE_POST': {$pf = array( 1512.000, 2376.000); break;}
2794  case 'EN_ROYAL' : {$pf = array( 1440.000, 1800.000); break;}
2795  case 'EN_SHEET':
2796  case 'EN_HALF_POST' : {$pf = array( 1404.000, 1692.000); break;}
2797  case 'EN_SUPER_ROYAL' : {$pf = array( 1368.000, 1944.000); break;}
2798  case 'EN_DOUBLE_POST' : {$pf = array( 1368.000, 2196.000); break;}
2799  case 'EN_MEDIUM' : {$pf = array( 1260.000, 1656.000); break;}
2800  case 'EN_DEMY' : {$pf = array( 1260.000, 1620.000); break;}
2801  case 'EN_LARGE_POST' : {$pf = array( 1188.000, 1512.000); break;}
2802  case 'EN_COPY_DRAUGHT' : {$pf = array( 1152.000, 1440.000); break;}
2803  case 'EN_POST' : {$pf = array( 1116.000, 1386.000); break;}
2804  case 'EN_CROWN' : {$pf = array( 1080.000, 1440.000); break;}
2805  case 'EN_PINCHED_POST' : {$pf = array( 1062.000, 1332.000); break;}
2806  case 'EN_BRIEF' : {$pf = array( 972.000, 1152.000); break;}
2807  case 'EN_FOOLSCAP' : {$pf = array( 972.000, 1224.000); break;}
2808  case 'EN_SMALL_FOOLSCAP' : {$pf = array( 954.000, 1188.000); break;}
2809  case 'EN_POTT' : {$pf = array( 900.000, 1080.000); break;}
2810  // - Old Imperial Belgian Sizes
2811  case 'BE_GRAND_AIGLE' : {$pf = array( 1984.252, 2948.031); break;}
2812  case 'BE_COLOMBIER' : {$pf = array( 1757.480, 2409.449); break;}
2813  case 'BE_DOUBLE_CARRE': {$pf = array( 1757.480, 2607.874); break;}
2814  case 'BE_ELEPHANT' : {$pf = array( 1746.142, 2182.677); break;}
2815  case 'BE_PETIT_AIGLE' : {$pf = array( 1700.787, 2381.102); break;}
2816  case 'BE_GRAND_JESUS' : {$pf = array( 1559.055, 2069.291); break;}
2817  case 'BE_JESUS' : {$pf = array( 1530.709, 2069.291); break;}
2818  case 'BE_RAISIN' : {$pf = array( 1417.323, 1842.520); break;}
2819  case 'BE_GRAND_MEDIAN': {$pf = array( 1303.937, 1714.961); break;}
2820  case 'BE_DOUBLE_POSTE': {$pf = array( 1233.071, 1601.575); break;}
2821  case 'BE_COQUILLE' : {$pf = array( 1218.898, 1587.402); break;}
2822  case 'BE_PETIT_MEDIAN': {$pf = array( 1176.378, 1502.362); break;}
2823  case 'BE_RUCHE' : {$pf = array( 1020.472, 1303.937); break;}
2824  case 'BE_PROPATRIA' : {$pf = array( 977.953, 1218.898); break;}
2825  case 'BE_LYS' : {$pf = array( 898.583, 1125.354); break;}
2826  case 'BE_POT' : {$pf = array( 870.236, 1088.504); break;}
2827  case 'BE_ROSETTE' : {$pf = array( 765.354, 983.622); break;}
2828  // - Old Imperial French Sizes
2829  case 'FR_UNIVERS' : {$pf = array( 2834.646, 3685.039); break;}
2830  case 'FR_DOUBLE_COLOMBIER' : {$pf = array( 2551.181, 3571.654); break;}
2831  case 'FR_GRANDE_MONDE' : {$pf = array( 2551.181, 3571.654); break;}
2832  case 'FR_DOUBLE_SOLEIL' : {$pf = array( 2267.717, 3401.575); break;}
2833  case 'FR_DOUBLE_JESUS' : {$pf = array( 2154.331, 3174.803); break;}
2834  case 'FR_GRAND_AIGLE' : {$pf = array( 2125.984, 3004.724); break;}
2835  case 'FR_PETIT_AIGLE' : {$pf = array( 1984.252, 2664.567); break;}
2836  case 'FR_DOUBLE_RAISIN' : {$pf = array( 1842.520, 2834.646); break;}
2837  case 'FR_JOURNAL' : {$pf = array( 1842.520, 2664.567); break;}
2838  case 'FR_COLOMBIER_AFFICHE': {$pf = array( 1785.827, 2551.181); break;}
2839  case 'FR_DOUBLE_CAVALIER' : {$pf = array( 1757.480, 2607.874); break;}
2840  case 'FR_CLOCHE' : {$pf = array( 1700.787, 2267.717); break;}
2841  case 'FR_SOLEIL' : {$pf = array( 1700.787, 2267.717); break;}
2842  case 'FR_DOUBLE_CARRE' : {$pf = array( 1587.402, 2551.181); break;}
2843  case 'FR_DOUBLE_COQUILLE' : {$pf = array( 1587.402, 2494.488); break;}
2844  case 'FR_JESUS' : {$pf = array( 1587.402, 2154.331); break;}
2845  case 'FR_RAISIN' : {$pf = array( 1417.323, 1842.520); break;}
2846  case 'FR_CAVALIER' : {$pf = array( 1303.937, 1757.480); break;}
2847  case 'FR_DOUBLE_COURONNE' : {$pf = array( 1303.937, 2040.945); break;}
2848  case 'FR_CARRE' : {$pf = array( 1275.591, 1587.402); break;}
2849  case 'FR_COQUILLE' : {$pf = array( 1247.244, 1587.402); break;}
2850  case 'FR_DOUBLE_TELLIERE' : {$pf = array( 1247.244, 1927.559); break;}
2851  case 'FR_DOUBLE_CLOCHE' : {$pf = array( 1133.858, 1700.787); break;}
2852  case 'FR_DOUBLE_POT' : {$pf = array( 1133.858, 1757.480); break;}
2853  case 'FR_ECU' : {$pf = array( 1133.858, 1474.016); break;}
2854  case 'FR_COURONNE' : {$pf = array( 1020.472, 1303.937); break;}
2855  case 'FR_TELLIERE' : {$pf = array( 963.780, 1247.244); break;}
2856  case 'FR_POT' : {$pf = array( 878.740, 1133.858); break;}
2857  // DEFAULT ISO A4
2858  default: {$pf = array( 595.276, 841.890); break;}
2859  }
2860  return $pf;
2861  }
2862 
2918  protected function setPageFormat($format, $orientation='P') {
2919  if (!empty($format) AND isset($this->pagedim[$this->page])) {
2920  // remove inherited values
2921  unset($this->pagedim[$this->page]);
2922  }
2923  if (is_string($format)) {
2924  // get page measures from format name
2925  $pf = $this->getPageSizeFromFormat($format);
2926  $this->fwPt = $pf[0];
2927  $this->fhPt = $pf[1];
2928  } else {
2929  // the boundaries of the physical medium on which the page shall be displayed or printed
2930  if (isset($format['MediaBox'])) {
2931  $this->setPageBoxes($this->page, 'MediaBox', $format['MediaBox']['llx'], $format['MediaBox']['lly'], $format['MediaBox']['urx'], $format['MediaBox']['ury'], false);
2932  $this->fwPt = (($format['MediaBox']['urx'] - $format['MediaBox']['llx']) * $this->k);
2933  $this->fhPt = (($format['MediaBox']['ury'] - $format['MediaBox']['lly']) * $this->k);
2934  } else {
2935  if (isset($format[0]) AND is_numeric($format[0]) AND isset($format[1]) AND is_numeric($format[1])) {
2936  $pf = array(($format[0] * $this->k), ($format[1] * $this->k));
2937  } else {
2938  if (!isset($format['format'])) {
2939  // default value
2940  $format['format'] = 'A4';
2941  }
2942  $pf = $this->getPageSizeFromFormat($format['format']);
2943  }
2944  $this->fwPt = $pf[0];
2945  $this->fhPt = $pf[1];
2946  $this->setPageBoxes($this->page, 'MediaBox', 0, 0, $this->fwPt, $this->fhPt, true);
2947  }
2948  // the visible region of default user space
2949  if (isset($format['CropBox'])) {
2950  $this->setPageBoxes($this->page, 'CropBox', $format['CropBox']['llx'], $format['CropBox']['lly'], $format['CropBox']['urx'], $format['CropBox']['ury'], false);
2951  }
2952  // the region to which the contents of the page shall be clipped when output in a production environment
2953  if (isset($format['BleedBox'])) {
2954  $this->setPageBoxes($this->page, 'BleedBox', $format['BleedBox']['llx'], $format['BleedBox']['lly'], $format['BleedBox']['urx'], $format['BleedBox']['ury'], false);
2955  }
2956  // the intended dimensions of the finished page after trimming
2957  if (isset($format['TrimBox'])) {
2958  $this->setPageBoxes($this->page, 'TrimBox', $format['TrimBox']['llx'], $format['TrimBox']['lly'], $format['TrimBox']['urx'], $format['TrimBox']['ury'], false);
2959  }
2960  // the page's meaningful content (including potential white space)
2961  if (isset($format['ArtBox'])) {
2962  $this->setPageBoxes($this->page, 'ArtBox', $format['ArtBox']['llx'], $format['ArtBox']['lly'], $format['ArtBox']['urx'], $format['ArtBox']['ury'], false);
2963  }
2964  // specify the colours and other visual characteristics that should be used in displaying guidelines on the screen for the various page boundaries
2965  if (isset($format['BoxColorInfo'])) {
2966  $this->pagedim[$this->page]['BoxColorInfo'] = $format['BoxColorInfo'];
2967  }
2968  if (isset($format['Rotate']) AND (($format['Rotate'] % 90) == 0)) {
2969  // The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
2970  $this->pagedim[$this->page]['Rotate'] = intval($format['Rotate']);
2971  }
2972  if (isset($format['PZ'])) {
2973  // The page's preferred zoom (magnification) factor
2974  $this->pagedim[$this->page]['PZ'] = floatval($format['PZ']);
2975  }
2976  if (isset($format['trans'])) {
2977  // The style and duration of the visual transition to use when moving from another page to the given page during a presentation
2978  if (isset($format['trans']['Dur'])) {
2979  // The page's display duration
2980  $this->pagedim[$this->page]['trans']['Dur'] = floatval($format['trans']['Dur']);
2981  }
2982  $stansition_styles = array('Split', 'Blinds', 'Box', 'Wipe', 'Dissolve', 'Glitter', 'R', 'Fly', 'Push', 'Cover', 'Uncover', 'Fade');
2983  if (isset($format['trans']['S']) AND in_array($format['trans']['S'], $stansition_styles)) {
2984  // The transition style that shall be used when moving to this page from another during a presentation
2985  $this->pagedim[$this->page]['trans']['S'] = $format['trans']['S'];
2986  $valid_effect = array('Split', 'Blinds');
2987  $valid_vals = array('H', 'V');
2988  if (isset($format['trans']['Dm']) AND in_array($format['trans']['S'], $valid_effect) AND in_array($format['trans']['Dm'], $valid_vals)) {
2989  $this->pagedim[$this->page]['trans']['Dm'] = $format['trans']['Dm'];
2990  }
2991  $valid_effect = array('Split', 'Box', 'Fly');
2992  $valid_vals = array('I', 'O');
2993  if (isset($format['trans']['M']) AND in_array($format['trans']['S'], $valid_effect) AND in_array($format['trans']['M'], $valid_vals)) {
2994  $this->pagedim[$this->page]['trans']['M'] = $format['trans']['M'];
2995  }
2996  $valid_effect = array('Wipe', 'Glitter', 'Fly', 'Cover', 'Uncover', 'Push');
2997  if (isset($format['trans']['Di']) AND in_array($format['trans']['S'], $valid_effect)) {
2998  if (((($format['trans']['Di'] == 90) OR ($format['trans']['Di'] == 180)) AND ($format['trans']['S'] == 'Wipe'))
2999  OR (($format['trans']['Di'] == 315) AND ($format['trans']['S'] == 'Glitter'))
3000  OR (($format['trans']['Di'] == 0) OR ($format['trans']['Di'] == 270))) {
3001  $this->pagedim[$this->page]['trans']['Di'] = intval($format['trans']['Di']);
3002  }
3003  }
3004  if (isset($format['trans']['SS']) AND ($format['trans']['S'] == 'Fly')) {
3005  $this->pagedim[$this->page]['trans']['SS'] = floatval($format['trans']['SS']);
3006  }
3007  if (isset($format['trans']['B']) AND ($format['trans']['B'] === true) AND ($format['trans']['S'] == 'Fly')) {
3008  $this->pagedim[$this->page]['trans']['B'] = 'true';
3009  }
3010  } else {
3011  $this->pagedim[$this->page]['trans']['S'] = 'R';
3012  }
3013  if (isset($format['trans']['D'])) {
3014  // The duration of the transition effect, in seconds
3015  $this->pagedim[$this->page]['trans']['D'] = floatval($format['trans']['D']);
3016  } else {
3017  $this->pagedim[$this->page]['trans']['D'] = 1;
3018  }
3019  }
3020  }
3021  $this->setPageOrientation($orientation);
3022  }
3023 
3036  public function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points=false) {
3037  if (!isset($this->pagedim[$page])) {
3038  // initialize array
3039  $this->pagedim[$page] = array();
3040  }
3041  $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
3042  if (!in_array($type, $pageboxes)) {
3043  return;
3044  }
3045  if ($points) {
3046  $k = 1;
3047  } else {
3048  $k = $this->k;
3049  }
3050  $this->pagedim[$page][$type]['llx'] = ($llx * $k);
3051  $this->pagedim[$page][$type]['lly'] = ($lly * $k);
3052  $this->pagedim[$page][$type]['urx'] = ($urx * $k);
3053  $this->pagedim[$page][$type]['ury'] = ($ury * $k);
3054  }
3055 
3062  protected function swapPageBoxCoordinates($page) {
3063  $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
3064  foreach ($pageboxes as $type) {
3065  // swap X and Y coordinates
3066  if (isset($this->pagedim[$page][$type])) {
3067  $tmp = $this->pagedim[$page][$type]['llx'];
3068  $this->pagedim[$page][$type]['llx'] = $this->pagedim[$page][$type]['lly'];
3069  $this->pagedim[$page][$type]['lly'] = $tmp;
3070  $tmp = $this->pagedim[$page][$type]['urx'];
3071  $this->pagedim[$page][$type]['urx'] = $this->pagedim[$page][$type]['ury'];
3072  $this->pagedim[$page][$type]['ury'] = $tmp;
3073  }
3074  }
3075  }
3076 
3085  public function setPageOrientation($orientation, $autopagebreak='', $bottommargin='') {
3086  if (!isset($this->pagedim[$this->page]['MediaBox'])) {
3087  // the boundaries of the physical medium on which the page shall be displayed or printed
3088  $this->setPageBoxes($this->page, 'MediaBox', 0, 0, $this->fwPt, $this->fhPt, true);
3089  }
3090  if (!isset($this->pagedim[$this->page]['CropBox'])) {
3091  // the visible region of default user space
3092  $this->setPageBoxes($this->page, 'CropBox', $this->pagedim[$this->page]['MediaBox']['llx'], $this->pagedim[$this->page]['MediaBox']['lly'], $this->pagedim[$this->page]['MediaBox']['urx'], $this->pagedim[$this->page]['MediaBox']['ury'], true);
3093  }
3094  if (!isset($this->pagedim[$this->page]['BleedBox'])) {
3095  // the region to which the contents of the page shall be clipped when output in a production environment
3096  $this->setPageBoxes($this->page, 'BleedBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true);
3097  }
3098  if (!isset($this->pagedim[$this->page]['TrimBox'])) {
3099  // the intended dimensions of the finished page after trimming
3100  $this->setPageBoxes($this->page, 'TrimBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true);
3101  }
3102  if (!isset($this->pagedim[$this->page]['ArtBox'])) {
3103  // the page's meaningful content (including potential white space)
3104  $this->setPageBoxes($this->page, 'ArtBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true);
3105  }
3106  if (!isset($this->pagedim[$this->page]['Rotate'])) {
3107  // The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
3108  $this->pagedim[$this->page]['Rotate'] = 0;
3109  }
3110  if (!isset($this->pagedim[$this->page]['PZ'])) {
3111  // The page's preferred zoom (magnification) factor
3112  $this->pagedim[$this->page]['PZ'] = 1;
3113  }
3114  if ($this->fwPt > $this->fhPt) {
3115  // landscape
3116  $default_orientation = 'L';
3117  } else {
3118  // portrait
3119  $default_orientation = 'P';
3120  }
3121  $valid_orientations = array('P', 'L');
3122  if (empty($orientation)) {
3123  $orientation = $default_orientation;
3124  } else {
3125  $orientation = strtoupper($orientation{0});
3126  }
3127  if (in_array($orientation, $valid_orientations) AND ($orientation != $default_orientation)) {
3128  $this->CurOrientation = $orientation;
3129  $this->wPt = $this->fhPt;
3130  $this->hPt = $this->fwPt;
3131  } else {
3132  $this->CurOrientation = $default_orientation;
3133  $this->wPt = $this->fwPt;
3134  $this->hPt = $this->fhPt;
3135  }
3136  if ((abs($this->pagedim[$this->page]['MediaBox']['urx'] - $this->hPt) < $this->feps) AND (abs($this->pagedim[$this->page]['MediaBox']['ury'] - $this->wPt) < $this->feps)){
3137  // swap X and Y coordinates (change page orientation)
3138  $this->swapPageBoxCoordinates($this->page);
3139  }
3140  $this->w = ($this->wPt / $this->k);
3141  $this->h = ($this->hPt / $this->k);
3142  if ($this->empty_string($autopagebreak)) {
3143  if (isset($this->AutoPageBreak)) {
3144  $autopagebreak = $this->AutoPageBreak;
3145  } else {
3146  $autopagebreak = true;
3147  }
3148  }
3149  if ($this->empty_string($bottommargin)) {
3150  if (isset($this->bMargin)) {
3151  $bottommargin = $this->bMargin;
3152  } else {
3153  // default value = 2 cm
3154  $bottommargin = 2 * 28.35 / $this->k;
3155  }
3156  }
3157  $this->SetAutoPageBreak($autopagebreak, $bottommargin);
3158  // store page dimensions
3159  $this->pagedim[$this->page]['w'] = $this->wPt;
3160  $this->pagedim[$this->page]['h'] = $this->hPt;
3161  $this->pagedim[$this->page]['wk'] = $this->w;
3162  $this->pagedim[$this->page]['hk'] = $this->h;
3163  $this->pagedim[$this->page]['tm'] = $this->tMargin;
3164  $this->pagedim[$this->page]['bm'] = $bottommargin;
3165  $this->pagedim[$this->page]['lm'] = $this->lMargin;
3166  $this->pagedim[$this->page]['rm'] = $this->rMargin;
3167  $this->pagedim[$this->page]['pb'] = $autopagebreak;
3168  $this->pagedim[$this->page]['or'] = $this->CurOrientation;
3169  $this->pagedim[$this->page]['olm'] = $this->original_lMargin;
3170  $this->pagedim[$this->page]['orm'] = $this->original_rMargin;
3171  }
3172 
3190  public function setSpacesRE($re='/[^\S\xa0]/') {
3191  $this->re_spaces = $re;
3192  $re_parts = explode('/', $re);
3193  // get pattern parts
3194  $this->re_space = array();
3195  if (isset($re_parts[1]) AND !empty($re_parts[1])) {
3196  $this->re_space['p'] = $re_parts[1];
3197  } else {
3198  $this->re_space['p'] = '[\s]';
3199  }
3200  // set pattern modifiers
3201  if (isset($re_parts[2]) AND !empty($re_parts[2])) {
3202  $this->re_space['m'] = $re_parts[2];
3203  } else {
3204  $this->re_space['m'] = '';
3205  }
3206  }
3207 
3215  public function setRTL($enable, $resetx=true) {
3216  $enable = $enable ? true : false;
3217  $resetx = ($resetx AND ($enable != $this->rtl));
3218  $this->rtl = $enable;
3219  $this->tmprtl = false;
3220  if ($resetx) {
3221  $this->Ln(0);
3222  }
3223  }
3224 
3231  public function getRTL() {
3232  return $this->rtl;
3233  }
3234 
3241  public function setTempRTL($mode) {
3242  $newmode = false;
3243  switch (strtoupper($mode)) {
3244  case 'LTR':
3245  case 'L': {
3246  if ($this->rtl) {
3247  $newmode = 'L';
3248  }
3249  break;
3250  }
3251  case 'RTL':
3252  case 'R': {
3253  if (!$this->rtl) {
3254  $newmode = 'R';
3255  }
3256  break;
3257  }
3258  case false:
3259  default: {
3260  $newmode = false;
3261  break;
3262  }
3263  }
3264  $this->tmprtl = $newmode;
3265  }
3266 
3273  public function isRTLTextDir() {
3274  return ($this->rtl OR ($this->tmprtl == 'R'));
3275  }
3276 
3284  public function setLastH($h) {
3285  $this->lasth = $h;
3286  }
3287 
3293  public function resetLastH() {
3294  $this->lasth = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
3295  }
3296 
3303  public function getLastH() {
3304  return $this->lasth;
3305  }
3306 
3314  public function setImageScale($scale) {
3315  $this->imgscale = $scale;
3316  }
3317 
3325  public function getImageScale() {
3326  return $this->imgscale;
3327  }
3328 
3338  public function getPageDimensions($pagenum='') {
3339  if (empty($pagenum)) {
3340  $pagenum = $this->page;
3341  }
3342  return $this->pagedim[$pagenum];
3343  }
3344 
3354  public function getPageWidth($pagenum='') {
3355  if (empty($pagenum)) {
3356  return $this->w;
3357  }
3358  return $this->pagedim[$pagenum]['w'];
3359  }
3360 
3370  public function getPageHeight($pagenum='') {
3371  if (empty($pagenum)) {
3372  return $this->h;
3373  }
3374  return $this->pagedim[$pagenum]['h'];
3375  }
3376 
3386  public function getBreakMargin($pagenum='') {
3387  if (empty($pagenum)) {
3388  return $this->bMargin;
3389  }
3390  return $this->pagedim[$pagenum]['bm'];
3391  }
3392 
3400  public function getScaleFactor() {
3401  return $this->k;
3402  }
3403 
3414  public function SetMargins($left, $top, $right=-1, $keepmargins=false) {
3415  //Set left, top and right margins
3416  $this->lMargin = $left;
3417  $this->tMargin = $top;
3418  if ($right == -1) {
3419  $right = $left;
3420  }
3421  $this->rMargin = $right;
3422  if ($keepmargins) {
3423  // overwrite original values
3424  $this->original_lMargin = $this->lMargin;
3425  $this->original_rMargin = $this->rMargin;
3426  }
3427  }
3428 
3436  public function SetLeftMargin($margin) {
3437  //Set left margin
3438  $this->lMargin = $margin;
3439  if (($this->page > 0) AND ($this->x < $margin)) {
3440  $this->x = $margin;
3441  }
3442  }
3443 
3451  public function SetTopMargin($margin) {
3452  //Set top margin
3453  $this->tMargin = $margin;
3454  if (($this->page > 0) AND ($this->y < $margin)) {
3455  $this->y = $margin;
3456  }
3457  }
3458 
3466  public function SetRightMargin($margin) {
3467  $this->rMargin = $margin;
3468  if (($this->page > 0) AND ($this->x > ($this->w - $margin))) {
3469  $this->x = $this->w - $margin;
3470  }
3471  }
3472 
3480  public function SetCellPadding($pad) {
3481  if ($pad >= 0) {
3482  $this->cell_padding['L'] = $pad;
3483  $this->cell_padding['T'] = $pad;
3484  $this->cell_padding['R'] = $pad;
3485  $this->cell_padding['B'] = $pad;
3486  }
3487  }
3488 
3499  public function setCellPaddings($left='', $top='', $right='', $bottom='') {
3500  if (($left !== '') AND ($left >= 0)) {
3501  $this->cell_padding['L'] = $left;
3502  }
3503  if (($top !== '') AND ($top >= 0)) {
3504  $this->cell_padding['T'] = $top;
3505  }
3506  if (($right !== '') AND ($right >= 0)) {
3507  $this->cell_padding['R'] = $right;
3508  }
3509  if (($bottom !== '') AND ($bottom >= 0)) {
3510  $this->cell_padding['B'] = $bottom;
3511  }
3512  }
3513 
3521  public function getCellPaddings() {
3522  return $this->cell_padding;
3523  }
3524 
3535  public function setCellMargins($left='', $top='', $right='', $bottom='') {
3536  if (($left !== '') AND ($left >= 0)) {
3537  $this->cell_margin['L'] = $left;
3538  }
3539  if (($top !== '') AND ($top >= 0)) {
3540  $this->cell_margin['T'] = $top;
3541  }
3542  if (($right !== '') AND ($right >= 0)) {
3543  $this->cell_margin['R'] = $right;
3544  }
3545  if (($bottom !== '') AND ($bottom >= 0)) {
3546  $this->cell_margin['B'] = $bottom;
3547  }
3548  }
3549 
3557  public function getCellMargins() {
3558  return $this->cell_margin;
3559  }
3560 
3568  protected function adjustCellPadding($brd=0) {
3569  if (empty($brd)) {
3570  return;
3571  }
3572  if (is_string($brd)) {
3573  // convert string to array
3574  $slen = strlen($brd);
3575  $newbrd = array();
3576  for ($i = 0; $i < $slen; ++$i) {
3577  $newbrd[$brd[$i]] = true;
3578  }
3579  $brd = $newbrd;
3580  } elseif (($brd === 1) OR ($brd === true) OR (is_numeric($brd) AND (intval($brd) > 0))) {
3581  $brd = array('LRTB' => true);
3582  }
3583  if (!is_array($brd)) {
3584  return;
3585  }
3586  // store current cell padding
3587  $cp = $this->cell_padding;
3588  // select border mode
3589  if (isset($brd['mode'])) {
3590  $mode = $brd['mode'];
3591  unset($brd['mode']);
3592  } else {
3593  $mode = 'normal';
3594  }
3595  // process borders
3596  foreach ($brd as $border => $style) {
3597  $line_width = $this->LineWidth;
3598  if (is_array($style) AND isset($style['width'])) {
3599  // get border width
3600  $line_width = $style['width'];
3601  }
3602  $adj = 0; // line width inside the cell
3603  switch ($mode) {
3604  case 'ext': {
3605  $adj = 0;
3606  break;
3607  }
3608  case 'int': {
3609  $adj = $line_width;
3610  break;
3611  }
3612  case 'normal':
3613  default: {
3614  $adj = ($line_width / 2);
3615  break;
3616  }
3617  }
3618  // correct internal cell padding if required to avoid overlap between text and lines
3619  if ((strpos($border,'T') !== false) AND ($this->cell_padding['T'] < $adj)) {
3620  $this->cell_padding['T'] = $adj;
3621  }
3622  if ((strpos($border,'R') !== false) AND ($this->cell_padding['R'] < $adj)) {
3623  $this->cell_padding['R'] = $adj;
3624  }
3625  if ((strpos($border,'B') !== false) AND ($this->cell_padding['B'] < $adj)) {
3626  $this->cell_padding['B'] = $adj;
3627  }
3628  if ((strpos($border,'L') !== false) AND ($this->cell_padding['L'] < $adj)) {
3629  $this->cell_padding['L'] = $adj;
3630  }
3631  }
3632  return array('T' => ($this->cell_padding['T'] - $cp['T']), 'R' => ($this->cell_padding['R'] - $cp['R']), 'B' => ($this->cell_padding['B'] - $cp['B']), 'L' => ($this->cell_padding['L'] - $cp['L']));
3633  }
3634 
3643  public function SetAutoPageBreak($auto, $margin=0) {
3644  $this->AutoPageBreak = $auto ? true : false;
3645  $this->bMargin = $margin;
3646  $this->PageBreakTrigger = $this->h - ($margin*2);
3647  }
3648 
3655  public function getAutoPageBreak() {
3656  return $this->AutoPageBreak;
3657  }
3658 
3667  public function SetDisplayMode($zoom, $layout='SinglePage', $mode='UseNone') {
3668  if (($zoom == 'fullpage') OR ($zoom == 'fullwidth') OR ($zoom == 'real') OR ($zoom == 'default') OR (!is_string($zoom))) {
3669  $this->ZoomMode = $zoom;
3670  } else {
3671  $this->Error('Incorrect zoom display mode: '.$zoom);
3672  }
3673  switch ($layout) {
3674  case 'default':
3675  case 'single':
3676  case 'SinglePage': {
3677  $this->LayoutMode = 'SinglePage';
3678  break;
3679  }
3680  case 'continuous':
3681  case 'OneColumn': {
3682  $this->LayoutMode = 'OneColumn';
3683  break;
3684  }
3685  case 'two':
3686  case 'TwoColumnLeft': {
3687  $this->LayoutMode = 'TwoColumnLeft';
3688  break;
3689  }
3690  case 'TwoColumnRight': {
3691  $this->LayoutMode = 'TwoColumnRight';
3692  break;
3693  }
3694  case 'TwoPageLeft': {
3695  $this->LayoutMode = 'TwoPageLeft';
3696  break;
3697  }
3698  case 'TwoPageRight': {
3699  $this->LayoutMode = 'TwoPageRight';
3700  break;
3701  }
3702  default: {
3703  $this->LayoutMode = 'SinglePage';
3704  }
3705  }
3706  switch ($mode) {
3707  case 'UseNone': {
3708  $this->PageMode = 'UseNone';
3709  break;
3710  }
3711  case 'UseOutlines': {
3712  $this->PageMode = 'UseOutlines';
3713  break;
3714  }
3715  case 'UseThumbs': {
3716  $this->PageMode = 'UseThumbs';
3717  break;
3718  }
3719  case 'FullScreen': {
3720  $this->PageMode = 'FullScreen';
3721  break;
3722  }
3723  case 'UseOC': {
3724  $this->PageMode = 'UseOC';
3725  break;
3726  }
3727  case '': {
3728  $this->PageMode = 'UseAttachments';
3729  break;
3730  }
3731  default: {
3732  $this->PageMode = 'UseNone';
3733  }
3734  }
3735  }
3736 
3744  public function SetCompression($compress=true) {
3745  if (function_exists('gzcompress')) {
3746  $this->compress = $compress ? true : false;
3747  } else {
3748  $this->compress = false;
3749  }
3750  }
3751 
3758  public function setSRGBmode($mode=false) {
3759  $this->force_srgb = $mode ? true : false;
3760  }
3761 
3769  public function SetDocInfoUnicode($unicode=true) {
3770  $this->docinfounicode = $unicode ? true : false;
3771  }
3772 
3780  public function SetTitle($title) {
3781  $this->title = $title;
3782  }
3783 
3791  public function SetSubject($subject) {
3792  $this->subject = $subject;
3793  }
3794 
3802  public function SetAuthor($author) {
3803  $this->author = $author;
3804  }
3805 
3813  public function SetKeywords($keywords) {
3814  $this->keywords = $keywords;
3815  }
3816 
3824  public function SetCreator($creator) {
3825  $this->creator = $creator;
3826  }
3827 
3835  public function Error($msg) {
3836  // unset all class variables
3837  $this->_destroy(true);
3838  // exit program and print error
3839  die('<strong>TCPDF ERROR: </strong>'.$msg);
3840  }
3841 
3850  public function Open() {
3851  $this->state = 1;
3852  }
3853 
3862  public function Close() {
3863  if ($this->state == 3) {
3864  return;
3865  }
3866  if ($this->page == 0) {
3867  $this->AddPage();
3868  }
3869  $this->endLayer();
3870  if ($this->tcpdflink) {
3871  // save current graphic settings
3872  $gvars = $this->getGraphicVars();
3873  $this->setEqualColumns();
3874  $this->lastpage(true);
3875  $this->SetAutoPageBreak(false);
3876  $this->x = 0;
3877  $this->y = $this->h - (1 / $this->k);
3878  $this->lMargin = 0;
3879  $this->_out('q');
3880  $font = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica';
3881  $this->SetFont($font, '', 1);
3882  $this->setTextRenderingMode(0, false, false);
3883  $msg = "\x50\x6f\x77\x65\x72\x65\x64\x20\x62\x79\x20\x54\x43\x50\x44\x46\x20\x28\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
3884  $lnk = "\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67";
3885  $this->Cell(0, 0, $msg, 0, 0, 'L', 0, $lnk, 0, false, 'D', 'B');
3886  $this->_out('Q');
3887  // restore graphic settings
3888  $this->setGraphicVars($gvars);
3889  }
3890  // close page
3891  $this->endPage();
3892  // close document
3893  $this->_enddoc();
3894  // unset all class variables (except critical ones)
3895  $this->_destroy(false);
3896  }
3897 
3906  public function setPage($pnum, $resetmargins=false) {
3907  if (($pnum == $this->page) AND ($this->state == 2)) {
3908  return;
3909  }
3910  if (($pnum > 0) AND ($pnum <= $this->numpages)) {
3911  $this->state = 2;
3912  // save current graphic settings
3913  //$gvars = $this->getGraphicVars();
3914  $oldpage = $this->page;
3915  $this->page = $pnum;
3916  $this->wPt = $this->pagedim[$this->page]['w'];
3917  $this->hPt = $this->pagedim[$this->page]['h'];
3918  $this->w = $this->pagedim[$this->page]['wk'];
3919  $this->h = $this->pagedim[$this->page]['hk'];
3920  $this->tMargin = $this->pagedim[$this->page]['tm'];
3921  $this->bMargin = $this->pagedim[$this->page]['bm'];
3922  $this->original_lMargin = $this->pagedim[$this->page]['olm'];
3923  $this->original_rMargin = $this->pagedim[$this->page]['orm'];
3924  $this->AutoPageBreak = $this->pagedim[$this->page]['pb'];
3925  $this->CurOrientation = $this->pagedim[$this->page]['or'];
3926  $this->SetAutoPageBreak($this->AutoPageBreak, $this->bMargin);
3927  // restore graphic settings
3928  //$this->setGraphicVars($gvars);
3929  if ($resetmargins) {
3930  $this->lMargin = $this->pagedim[$this->page]['olm'];
3931  $this->rMargin = $this->pagedim[$this->page]['orm'];
3932  $this->SetY($this->tMargin);
3933  } else {
3934  // account for booklet mode
3935  if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) {
3936  $deltam = $this->pagedim[$this->page]['olm'] - $this->pagedim[$this->page]['orm'];
3937  $this->lMargin += $deltam;
3938  $this->rMargin -= $deltam;
3939  }
3940  }
3941  } else {
3942  $this->Error('Wrong page number on setPage() function: '.$pnum);
3943  }
3944  }
3945 
3953  public function lastPage($resetmargins=false) {
3954  $this->setPage($this->getNumPages(), $resetmargins);
3955  }
3956 
3964  public function getPage() {
3965  return $this->page;
3966  }
3967 
3975  public function getNumPages() {
3976  return $this->numpages;
3977  }
3978 
3988  public function addTOCPage($orientation='', $format='', $keepmargins=false) {
3989  $this->AddPage($orientation, $format, $keepmargins, true);
3990  }
3991 
3998  public function endTOCPage() {
3999  $this->endPage(true);
4000  }
4001 
4013  public function AddPage($orientation='', $format='', $keepmargins=false, $tocpage=false) {
4014  if ($this->inxobj) {
4015  // we are inside an XObject template
4016  return;
4017  }
4018  if (!isset($this->original_lMargin) OR $keepmargins) {
4019  $this->original_lMargin = $this->lMargin;
4020  }
4021  if (!isset($this->original_rMargin) OR $keepmargins) {
4022  $this->original_rMargin = $this->rMargin;
4023  }
4024  // terminate previous page
4025  $this->endPage();
4026  // start new page
4027  $this->startPage($orientation, $format, $tocpage);
4028  }
4029 
4037  public function endPage($tocpage=false) {
4038  // check if page is already closed
4039  if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) {
4040  return;
4041  }
4042  // print page footer
4043  $this->setFooter();
4044  // close page
4045  $this->_endpage();
4046  // mark page as closed
4047  $this->pageopen[$this->page] = false;
4048  if ($tocpage) {
4049  $this->tocpage = false;
4050  }
4051  }
4052 
4063  public function startPage($orientation='', $format='', $tocpage=false) {
4064  if ($tocpage) {
4065  $this->tocpage = true;
4066  }
4067  // move page numbers of documents to be attached
4068  if ($this->tocpage) {
4069  // move reference to unexistent pages (used for page attachments)
4070  // adjust outlines
4071  $tmpoutlines = $this->outlines;
4072  foreach ($tmpoutlines as $key => $outline) {
4073  if ($outline['p'] > $this->numpages) {
4074  $this->outlines[$key]['p'] = ($outline['p'] + 1);
4075  }
4076  }
4077  // adjust dests
4078  $tmpdests = $this->dests;
4079  foreach ($tmpdests as $key => $dest) {
4080  if ($dest['p'] > $this->numpages) {
4081  $this->dests[$key]['p'] = ($dest['p'] + 1);
4082  }
4083  }
4084  // adjust links
4085  $tmplinks = $this->links;
4086  foreach ($tmplinks as $key => $link) {
4087  if ($link[0] > $this->numpages) {
4088  $this->links[$key][0] = ($link[0] + 1);
4089  }
4090  }
4091  }
4092  if ($this->numpages > $this->page) {
4093  // this page has been already added
4094  $this->setPage($this->page + 1);
4095  $this->SetY($this->tMargin);
4096  return;
4097  }
4098  // start a new page
4099  if ($this->state == 0) {
4100  $this->Open();
4101  }
4102  ++$this->numpages;
4103  $this->swapMargins($this->booklet);
4104  // save current graphic settings
4105  $gvars = $this->getGraphicVars();
4106  // start new page
4107  $this->_beginpage($orientation, $format);
4108  // mark page as open
4109  $this->pageopen[$this->page] = true;
4110  // restore graphic settings
4111  $this->setGraphicVars($gvars);
4112  // mark this point
4113  $this->setPageMark();
4114  // print page header
4115  // Désactivation par PEEL : $this->setHeader();
4116  // restore graphic settings
4117  $this->setGraphicVars($gvars);
4118  // mark this point
4119  $this->setPageMark();
4120  // print table header (if any)
4121  $this->setTableHeader();
4122  // set mark for empty page check
4123  $this->emptypagemrk[$this->page]= $this->pagelen[$this->page];
4124  }
4125 
4134  public function setPageMark() {
4135  $this->intmrk[$this->page] = $this->pagelen[$this->page];
4136  $this->bordermrk[$this->page] = $this->intmrk[$this->page];
4137  $this->setContentMark();
4138  }
4139 
4147  protected function setContentMark($page=0) {
4148  if ($page <= 0) {
4149  $page = $this->page;
4150  }
4151  if (isset($this->footerlen[$page])) {
4152  $this->cntmrk[$page] = $this->pagelen[$page] - $this->footerlen[$page];
4153  } else {
4154  $this->cntmrk[$page] = $this->pagelen[$page];
4155  }
4156  }
4157 
4168  public function setHeaderData($ln='', $lw=0, $ht='', $hs='', $tc=array(0,0,0), $lc=array(0,0,0)) {
4169  $this->header_logo = $ln;
4170  $this->header_logo_width = $lw;
4171  $this->header_title = $ht;
4172  $this->header_string = $hs;
4173  $this->header_text_color = $tc;
4174  $this->header_line_color = $lc;
4175  }
4176 
4183  public function setFooterData($tc=array(0,0,0), $lc=array(0,0,0)) {
4184  $this->footer_text_color = $tc;
4185  $this->footer_line_color = $lc;
4186  }
4187 
4195  public function getHeaderData() {
4196  $ret = array();
4197  $ret['logo'] = $this->header_logo;
4198  $ret['logo_width'] = $this->header_logo_width;
4199  $ret['title'] = $this->header_title;
4200  $ret['string'] = $this->header_string;
4201  $ret['text_color'] = $this->header_text_color;
4202  $ret['line_color'] = $this->header_line_color;
4203  return $ret;
4204  }
4205 
4212  public function setHeaderMargin($hm=10) {
4213  $this->header_margin = $hm;
4214  }
4215 
4222  public function getHeaderMargin() {
4223  return $this->header_margin;
4224  }
4225 
4232  public function setFooterMargin($fm=10) {
4233  $this->footer_margin = $fm;
4234  }
4235 
4242  public function getFooterMargin() {
4243  return $this->footer_margin;
4244  }
4250  public function setPrintHeader($val=true) {
4251  $this->print_header = $val ? true : false;
4252  }
4253 
4259  public function setPrintFooter($val=true) {
4260  $this->print_footer = $val ? true : false;
4261  }
4262 
4268  public function getImageRBX() {
4269  return $this->img_rb_x;
4270  }
4271 
4277  public function getImageRBY() {
4278  return $this->img_rb_y;
4279  }
4280 
4285  public function resetHeaderTemplate() {
4286  $this->header_xobjid = -1;
4287  }
4288 
4294  public function setHeaderTemplateAutoreset($val=true) {
4295  $this->header_xobj_autoreset = $val ? true : false;
4296  }
4297 
4303  public function Header() {
4304  if ($this->header_xobjid < 0) {
4305  // start a new XObject Template
4306  $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin);
4307  $headerfont = $this->getHeaderFont();
4308  $headerdata = $this->getHeaderData();
4309  $this->y = $this->header_margin;
4310  if ($this->rtl) {
4311  $this->x = $this->w - $this->original_rMargin;
4312  } else {
4313  $this->x = $this->original_lMargin;
4314  }
4315  if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
4316  $imgtype = $this->getImageFileType(K_PATH_IMAGES.$headerdata['logo']);
4317  if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
4318  $this->ImageEps(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
4319  } elseif ($imgtype == 'svg') {
4320  $this->ImageSVG(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
4321  } else {
4322  $this->Image(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
4323  }
4324  $imgy = $this->getImageRBY();
4325  } else {
4326  $imgy = $this->y;
4327  }
4328  $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2);
4329  // set starting margin for text data cell
4330  if ($this->getRTL()) {
4331  $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
4332  } else {
4333  $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
4334  }
4335  $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
4336  $this->SetTextColorArray($this->header_text_color);
4337  // header title
4338  $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
4339  $this->SetX($header_x);
4340  $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
4341  // header string
4342  $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
4343  $this->SetX($header_x);
4344  $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false, true, 0, 'T', false);
4345  // print an ending header line
4346  $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color']));
4347  $this->SetY((2.835 / $this->k) + max($imgy, $this->y));
4348  if ($this->rtl) {
4349  $this->SetX($this->original_rMargin);
4350  } else {
4351  $this->SetX($this->original_lMargin);
4352  }
4353  $this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
4354  $this->endTemplate();
4355  }
4356  // print header template
4357  $x = 0;
4358  $dx = 0;
4359  if (!$this->header_xobj_autoreset AND $this->booklet AND (($this->page % 2) == 0)) {
4360  // adjust margins for booklet mode
4361  $dx = ($this->original_lMargin - $this->original_rMargin);
4362  }
4363  if ($this->rtl) {
4364  $x = $this->w + $dx;
4365  } else {
4366  $x = 0 + $dx;
4367  }
4368  $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
4369  if ($this->header_xobj_autoreset) {
4370  // reset header xobject template at each page
4371  $this->header_xobjid = -1;
4372  }
4373  }
4374 
4380  public function Footer() {
4381  $cur_y = $this->y;
4382  $this->SetTextColorArray($this->footer_text_color);
4383  //set style for cell border
4384  $line_width = (0.85 / $this->k);
4385  $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color));
4386  //print document barcode
4387  $barcode = $this->getBarcode();
4388  if (!empty($barcode)) {
4389  $this->Ln($line_width);
4390  $barcode_width = round(($this->w - $this->original_lMargin - $this->original_rMargin) / 3);
4391  $style = array(
4392  'position' => $this->rtl?'R':'L',
4393  'align' => $this->rtl?'R':'L',
4394  'stretch' => false,
4395  'fitwidth' => true,
4396  'cellfitalign' => '',
4397  'border' => false,
4398  'padding' => 0,
4399  'fgcolor' => array(0,0,0),
4400  'bgcolor' => false,
4401  'text' => false
4402  );
4403  $this->write1DBarcode($barcode, 'C128', '', $cur_y + $line_width, '', (($this->footer_margin / 3) - $line_width), 0.3, $style, '');
4404  }
4405  $w_page = isset($this->l['w_page']) ? $this->l['w_page'].' ' : '';
4406  if (empty($this->pagegroups)) {
4407  $pagenumtxt = $w_page.$this->getAliasNumPage().' / '.$this->getAliasNbPages();
4408  } else {
4409  $pagenumtxt = $w_page.$this->getPageNumGroupAlias().' / '.$this->getPageGroupAlias();
4410  }
4411  $this->SetY($cur_y);
4412  //Print page number
4413  if ($this->getRTL()) {
4414  $this->SetX($this->original_rMargin);
4415  $this->Cell(0, 0, $pagenumtxt, 'T', 0, 'L');
4416  } else {
4417  $this->SetX($this->original_lMargin);
4418  $this->Cell(0, 0, $this->getAliasRightShift().$pagenumtxt, 'T', 0, 'R');
4419  }
4420  }
4421 
4427  protected function setHeader() {
4428  if (!$this->print_header OR ($this->state != 2)) {
4429  return;
4430  }
4431  $this->InHeader = true;
4432  $this->setGraphicVars($this->default_graphic_vars);
4433  $temp_thead = $this->thead;
4434  $temp_theadMargins = $this->theadMargins;
4435  $lasth = $this->lasth;
4436  $this->_out('q');
4437  $this->rMargin = $this->original_rMargin;
4438  $this->lMargin = $this->original_lMargin;
4439  $this->SetCellPadding(0);
4440  //set current position
4441  if ($this->rtl) {
4442  $this->SetXY($this->original_rMargin, $this->header_margin);
4443  } else {
4444  $this->SetXY($this->original_lMargin, $this->header_margin);
4445  }
4446  $this->SetFont($this->header_font[0], $this->header_font[1], $this->header_font[2]);
4447  $this->Header();
4448  //restore position
4449  if ($this->rtl) {
4450  $this->SetXY($this->original_rMargin, $this->tMargin);
4451  } else {
4452  $this->SetXY($this->original_lMargin, $this->tMargin);
4453  }
4454  $this->_out('Q');
4455  $this->lasth = $lasth;
4456  $this->thead = $temp_thead;
4457  $this->theadMargins = $temp_theadMargins;
4458  $this->newline = false;
4459  $this->InHeader = false;
4460  }
4461 
4467  protected function setFooter() {
4468  if ($this->state != 2) {
4469  return;
4470  }
4471  $this->InFooter = true;
4472  // save current graphic settings
4473  $gvars = $this->getGraphicVars();
4474  // mark this point
4475  $this->footerpos[$this->page] = $this->pagelen[$this->page];
4476  $this->_out("\n");
4477  if ($this->print_footer) {
4478  $this->setGraphicVars($this->default_graphic_vars);
4479  $this->current_column = 0;
4480  $this->num_columns = 1;
4481  $temp_thead = $this->thead;
4482  $temp_theadMargins = $this->theadMargins;
4483  $lasth = $this->lasth;
4484  $this->_out('q');
4485  $this->rMargin = $this->original_rMargin;
4486  $this->lMargin = $this->original_lMargin;
4487  $this->SetCellPadding(0);
4488  //set current position
4489  $footer_y = $this->h - $this->footer_margin;
4490  if ($this->rtl) {
4491  $this->SetXY($this->original_rMargin, $footer_y);
4492  } else {
4493  $this->SetXY($this->original_lMargin, $footer_y);
4494  }
4495  $this->SetFont($this->footer_font[0], $this->footer_font[1], $this->footer_font[2]);
4496  $this->Footer();
4497  //restore position
4498  if ($this->rtl) {
4499  $this->SetXY($this->original_rMargin, $this->tMargin);
4500  } else {
4501  $this->SetXY($this->original_lMargin, $this->tMargin);
4502  }
4503  $this->_out('Q');
4504  $this->lasth = $lasth;
4505  $this->thead = $temp_thead;
4506  $this->theadMargins = $temp_theadMargins;
4507  }
4508  // restore graphic settings
4509  $this->setGraphicVars($gvars);
4510  $this->current_column = $gvars['current_column'];
4511  $this->num_columns = $gvars['num_columns'];
4512  // calculate footer length
4513  $this->footerlen[$this->page] = $this->pagelen[$this->page] - $this->footerpos[$this->page] + 1;
4514  $this->InFooter = false;
4515  }
4516 
4523  protected function inPageBody() {
4524  return (($this->InHeader === false) AND ($this->InFooter === false));
4525  }
4526 
4532  protected function setTableHeader() {
4533  if ($this->num_columns > 1) {
4534  // multi column mode
4535  return;
4536  }
4537  if (isset($this->theadMargins['top'])) {
4538  // restore the original top-margin
4539  $this->tMargin = $this->theadMargins['top'];
4540  $this->pagedim[$this->page]['tm'] = $this->tMargin;
4541  $this->y = $this->tMargin;
4542  }
4543  if (!$this->empty_string($this->thead) AND (!$this->inthead)) {
4544  // set margins
4545  $prev_lMargin = $this->lMargin;
4546  $prev_rMargin = $this->rMargin;
4547  $prev_cell_padding = $this->cell_padding;
4548  $this->lMargin = $this->theadMargins['lmargin'] + ($this->pagedim[$this->page]['olm'] - $this->pagedim[$this->theadMargins['page']]['olm']);
4549  $this->rMargin = $this->theadMargins['rmargin'] + ($this->pagedim[$this->page]['orm'] - $this->pagedim[$this->theadMargins['page']]['orm']);
4550  $this->cell_padding = $this->theadMargins['cell_padding'];
4551  if ($this->rtl) {
4552  $this->x = $this->w - $this->rMargin;
4553  } else {
4554  $this->x = $this->lMargin;
4555  }
4556  // account for special "cell" mode
4557  if ($this->theadMargins['cell']) {
4558  if ($this->rtl) {
4559  $this->x -= $this->cell_padding['R'];
4560  } else {
4561  $this->x += $this->cell_padding['L'];
4562  }
4563  }
4564  // print table header
4565  $this->writeHTML($this->thead, false, false, false, false, '');
4566  // set new top margin to skip the table headers
4567  if (!isset($this->theadMargins['top'])) {
4568  $this->theadMargins['top'] = $this->tMargin;
4569  }
4570  // store end of header position
4571  if (!isset($this->columns[0]['th'])) {
4572  $this->columns[0]['th'] = array();
4573  }
4574  $this->columns[0]['th']['\''.$this->page.'\''] = $this->y;
4575  $this->tMargin = $this->y;
4576  $this->pagedim[$this->page]['tm'] = $this->tMargin;
4577  $this->lasth = 0;
4578  $this->lMargin = $prev_lMargin;
4579  $this->rMargin = $prev_rMargin;
4580  $this->cell_padding = $prev_cell_padding;
4581  }
4582  }
4583 
4591  public function PageNo() {
4592  return $this->page;
4593  }
4594 
4608  public function AddSpotColor($name, $c, $m, $y, $k) {
4609  if (!isset($this->spot_colors[$name])) {
4610  $i = (1 + count($this->spot_colors));
4611  $this->spot_colors[$name] = array('C' => $c, 'M' => $m, 'Y' => $y, 'K' => $k, 'name' => $name, 'i' => $i);
4612  }
4613  }
4614 
4622  public function getSpotColor($name) {
4623  if (isset($this->spot_colors[$name])) {
4624  return $this->spot_colors[$name];
4625  }
4626  $color = preg_replace('/[\s]*/', '', $name); // remove extra spaces
4627  $color = strtolower($color);
4628  if (isset($this->spotcolor[$color])) {
4629  $this->AddSpotColor($this->spotcolor[$color][4], $this->spotcolor[$color][0], $this->spotcolor[$color][1], $this->spotcolor[$color][2], $this->spotcolor[$color][3]);
4630  return $this->spot_colors[$this->spotcolor[$color][4]];
4631  }
4632  return false;
4633  }
4634 
4644  public function setSpotColor($type, $name, $tint=100) {
4645  $spotcolor = $this->getSpotColor($name);
4646  if ($spotcolor === false) {
4647  $this->Error('Undefined spot color: '.$name.', you must add it on the spotcolors.php file.');
4648  }
4649  $tint = (max(0, min(100, $tint)) / 100);
4650  $pdfcolor = sprintf('/CS%d ', $this->spot_colors[$name]['i']);
4651  switch ($type) {
4652  case 'draw': {
4653  $pdfcolor .= sprintf('CS %F SCN', $tint);
4654  $this->DrawColor = $pdfcolor;
4655  $this->strokecolor = $spotcolor;
4656  break;
4657  }
4658  case 'fill': {
4659  $pdfcolor .= sprintf('cs %F scn', $tint);
4660  $this->FillColor = $pdfcolor;
4661  $this->bgcolor = $spotcolor;
4662  break;
4663  }
4664  case 'text': {
4665  $pdfcolor .= sprintf('cs %F scn', $tint);
4666  $this->TextColor = $pdfcolor;
4667  $this->fgcolor = $spotcolor;
4668  break;
4669  }
4670  }
4671  $this->ColorFlag = ($this->FillColor != $this->TextColor);
4672  if ($this->state == 2) {
4673  $this->_out($pdfcolor);
4674  }
4675  if ($this->inxobj) {
4676  // we are inside an XObject template
4677  $this->xobjects[$this->xobjid]['spot_colors'][$name] = $this->spot_colors[$name];
4678  }
4679  return $pdfcolor;
4680  }
4681 
4690  public function SetDrawSpotColor($name, $tint=100) {
4691  $this->setSpotColor('draw', $name, $tint);
4692  }
4693 
4702  public function SetFillSpotColor($name, $tint=100) {
4703  $this->setSpotColor('fill', $name, $tint);
4704  }
4705 
4714  public function SetTextSpotColor($name, $tint=100) {
4715  $this->setSpotColor('text', $name, $tint);
4716  }
4717 
4729  public function setColorArray($type, $color, $ret=false) {
4730  if (is_array($color)) {
4731  $color = array_values($color);
4732  // component: grey, RGB red or CMYK cyan
4733  $c = isset($color[0]) ? $color[0] : -1;
4734  // component: RGB green or CMYK magenta
4735  $m = isset($color[1]) ? $color[1] : -1;
4736  // component: RGB blue or CMYK yellow
4737  $y = isset($color[2]) ? $color[2] : -1;
4738  // component: CMYK black
4739  $k = isset($color[3]) ? $color[3] : -1;
4740  // color name
4741  $name = isset($color[4]) ? $color[4] : '';
4742  if ($c >= 0) {
4743  return $this->setColor($type, $c, $m, $y, $k, $ret, $name);
4744  }
4745  }
4746  return '';
4747  }
4748 
4760  public function SetDrawColorArray($color, $ret=false) {
4761  return $this->setColorArray('draw', $color, $ret);
4762  }
4763 
4774  public function SetFillColorArray($color, $ret=false) {
4775  return $this->setColorArray('fill', $color, $ret);
4776  }
4777 
4787  public function SetTextColorArray($color, $ret=false) {
4788  return $this->setColorArray('text', $color, $ret);
4789  }
4790 
4804  public function setColor($type, $col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4805  // set default values
4806  if (!is_numeric($col1)) {
4807  $col1 = 0;
4808  }
4809  if (!is_numeric($col2)) {
4810  $col2 = -1;
4811  }
4812  if (!is_numeric($col3)) {
4813  $col3 = -1;
4814  }
4815  if (!is_numeric($col4)) {
4816  $col4 = -1;
4817  }
4818  // set color by case
4819  $suffix = '';
4820  if (($col2 == -1) AND ($col3 == -1) AND ($col4 == -1)) {
4821  // Grey scale
4822  $col1 = max(0, min(255, $col1));
4823  $intcolor = array('G' => $col1);
4824  $pdfcolor = sprintf('%F ', ($col1 / 255));
4825  $suffix = 'g';
4826  } elseif ($col4 == -1) {
4827  // RGB
4828  $col1 = max(0, min(255, $col1));
4829  $col2 = max(0, min(255, $col2));
4830  $col3 = max(0, min(255, $col3));
4831  $intcolor = array('R' => $col1, 'G' => $col2, 'B' => $col3);
4832  $pdfcolor = sprintf('%F %F %F ', ($col1 / 255), ($col2 / 255), ($col3 / 255));
4833  $suffix = 'rg';
4834  } else {
4835  $col1 = max(0, min(100, $col1));
4836  $col2 = max(0, min(100, $col2));
4837  $col3 = max(0, min(100, $col3));
4838  $col4 = max(0, min(100, $col4));
4839  if (empty($name)) {
4840  // CMYK
4841  $intcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4);
4842  $pdfcolor = sprintf('%F %F %F %F ', ($col1 / 100), ($col2 / 100), ($col3 / 100), ($col4 / 100));
4843  $suffix = 'k';
4844  } else {
4845  // SPOT COLOR
4846  $intcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4, 'name' => $name);
4847  $this->AddSpotColor($name, $col1, $col2, $col3, $col4);
4848  $pdfcolor = $this->setSpotColor($type, $name, 100);
4849  }
4850  }
4851  switch ($type) {
4852  case 'draw': {
4853  $pdfcolor .= strtoupper($suffix);
4854  $this->DrawColor = $pdfcolor;
4855  $this->strokecolor = $intcolor;
4856  break;
4857  }
4858  case 'fill': {
4859  $pdfcolor .= $suffix;
4860  $this->FillColor = $pdfcolor;
4861  $this->bgcolor = $intcolor;
4862  break;
4863  }
4864  case 'text': {
4865  $pdfcolor .= $suffix;
4866  $this->TextColor = $pdfcolor;
4867  $this->fgcolor = $intcolor;
4868  break;
4869  }
4870  }
4871  $this->ColorFlag = ($this->FillColor != $this->TextColor);
4872  if (($type != 'text') AND ($this->state == 2)) {
4873  if (!$ret) {
4874  $this->_out($pdfcolor);
4875  }
4876  return $pdfcolor;
4877  }
4878  return '';
4879  }
4880 
4888  protected function getColorStringFromArray($c) {
4889  $c = array_values($c);
4890  $color = '[';
4891  switch (count($c)) {
4892  case 4: {
4893  // CMYK
4894  $color .= sprintf('%F %F %F %F', (max(0, min(100, floatval($c[0]))) / 100), (max(0, min(100, floatval($c[1]))) / 100), (max(0, min(100, floatval($c[2]))) / 100), (max(0, min(100, floatval($c[3]))) / 100));
4895  break;
4896  }
4897  case 3: {
4898  // RGB
4899  $color .= sprintf('%F %F %F', (max(0, min(255, floatval($c[0]))) / 255), (max(0, min(255, floatval($c[1]))) / 255), (max(0, min(255, floatval($c[2]))) / 255));
4900  break;
4901  }
4902  case 1: {
4903  // grayscale
4904  $color .= sprintf('%F', (max(0, min(255, floatval($c[0]))) / 255));
4905  break;
4906  }
4907  }
4908  $color .= ']';
4909  return $color;
4910  }
4911 
4925  public function SetDrawColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4926  return $this->setColor('draw', $col1, $col2, $col3, $col4, $ret, $name);
4927  }
4928 
4942  public function SetFillColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4943  return $this->setColor('fill', $col1, $col2, $col3, $col4, $ret, $name);
4944  }
4945 
4959  public function SetTextColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4960  return $this->setColor('text', $col1, $col2, $col3, $col4, $ret, $name);
4961  }
4962 
4975  public function GetStringWidth($s, $fontname='', $fontstyle='', $fontsize=0, $getarray=false) {
4976  return $this->GetArrStringWidth($this->utf8Bidi($this->UTF8StringToArray($s), $s, $this->tmprtl), $fontname, $fontstyle, $fontsize, $getarray);
4977  }
4978 
4991  public function GetArrStringWidth($sa, $fontname='', $fontstyle='', $fontsize=0, $getarray=false) {
4992  // store current values
4993  if (!$this->empty_string($fontname)) {
4994  $prev_FontFamily = $this->FontFamily;
4995  $prev_FontStyle = $this->FontStyle;
4996  $prev_FontSizePt = $this->FontSizePt;
4997  $this->SetFont($fontname, $fontstyle, $fontsize, '', 'default', false);
4998  }
4999  // convert UTF-8 array to Latin1 if required
5000  $sa = $this->UTF8ArrToLatin1($sa);
5001  $w = 0; // total width
5002  $wa = array(); // array of characters widths
5003  foreach ($sa as $ck => $char) {
5004  // character width
5005  $cw = $this->GetCharWidth($char, isset($sa[($ck + 1)]));
5006  $wa[] = $cw;
5007  $w += $cw;
5008  }
5009  // restore previous values
5010  if (!$this->empty_string($fontname)) {
5011  $this->SetFont($prev_FontFamily, $prev_FontStyle, $prev_FontSizePt, '', 'default', false);
5012  }
5013  if ($getarray) {
5014  return $wa;
5015  }
5016  return $w;
5017  }
5018 
5028  public function GetCharWidth($char, $notlast=true) {
5029  // get raw width
5030  $chw = $this->getRawCharWidth($char);
5031  if (($this->font_spacing < 0) OR (($this->font_spacing > 0) AND $notlast)) {
5032  // increase/decrease font spacing
5033  $chw += $this->font_spacing;
5034  }
5035  if ($this->font_stretching != 100) {
5036  // fixed stretching mode
5037  $chw *= ($this->font_stretching / 100);
5038  }
5039  return $chw;
5040  }
5041 
5050  public function getRawCharWidth($char) {
5051  if ($char == 173) {
5052  // SHY character will not be printed
5053  return (0);
5054  }
5055  if (isset($this->CurrentFont['cw'][$char])) {
5056  $w = $this->CurrentFont['cw'][$char];
5057  } elseif (isset($this->CurrentFont['dw'])) {
5058  // default width
5059  $w = $this->CurrentFont['dw'];
5060  } elseif (isset($this->CurrentFont['cw'][32])) {
5061  // default width
5062  $w = $this->CurrentFont['cw'][32];
5063  } else {
5064  $w = 600;
5065  }
5066  return $this->getAbsFontMeasure($w);
5067  }
5068 
5076  public function GetNumChars($s) {
5077  if ($this->isUnicodeFont()) {
5078  return count($this->UTF8StringToArray($s));
5079  }
5080  return strlen($s);
5081  }
5082 
5088  protected function getFontsList() {
5089  $fontsdir = opendir($this->_getfontpath());
5090  while (($file = readdir($fontsdir)) !== false) {
5091  if (substr($file, -4) == '.php') {
5092  array_push($this->fontlist, strtolower(basename($file, '.php')));
5093  }
5094  }
5095  closedir($fontsdir);
5096  }
5097 
5111  public function AddFont($family, $style='', $fontfile='', $subset='default') {
5112  if ($subset === 'default') {
5113  $subset = $this->font_subsetting;
5114  }
5115  if ($this->pdfa_mode) {
5116  $subset = false;
5117  }
5118  if ($this->empty_string($family)) {
5119  if (!$this->empty_string($this->FontFamily)) {
5120  $family = $this->FontFamily;
5121  } else {
5122  $this->Error('Empty font family');
5123  }
5124  }
5125  // move embedded styles on $style
5126  if (substr($family, -1) == 'I') {
5127  $style .= 'I';
5128  $family = substr($family, 0, -1);
5129  }
5130  if (substr($family, -1) == 'B') {
5131  $style .= 'B';
5132  $family = substr($family, 0, -1);
5133  }
5134  // normalize family name
5135  $family = strtolower($family);
5136  if ((!$this->isunicode) AND ($family == 'arial')) {
5137  $family = 'helvetica';
5138  }
5139  if (($family == 'symbol') OR ($family == 'zapfdingbats')) {
5140  $style = '';
5141  }
5142  if ($this->pdfa_mode AND (isset($this->CoreFonts[$family]))) {
5143  // all fonts must be embedded
5144  $family = 'pdfa'.$family;
5145  }
5146  $tempstyle = strtoupper($style);
5147  $style = '';
5148  // underline
5149  if (strpos($tempstyle, 'U') !== false) {
5150  $this->underline = true;
5151  } else {
5152  $this->underline = false;
5153  }
5154  // line-through (deleted)
5155  if (strpos($tempstyle, 'D') !== false) {
5156  $this->linethrough = true;
5157  } else {
5158  $this->linethrough = false;
5159  }
5160  // overline
5161  if (strpos($tempstyle, 'O') !== false) {
5162  $this->overline = true;
5163  } else {
5164  $this->overline = false;
5165  }
5166  // bold
5167  if (strpos($tempstyle, 'B') !== false) {
5168  $style .= 'B';
5169  }
5170  // oblique
5171  if (strpos($tempstyle, 'I') !== false) {
5172  $style .= 'I';
5173  }
5174  $bistyle = $style;
5175  $fontkey = $family.$style;
5176  $font_style = $style.($this->underline ? 'U' : '').($this->linethrough ? 'D' : '').($this->overline ? 'O' : '');
5177  $fontdata = array('fontkey' => $fontkey, 'family' => $family, 'style' => $font_style);
5178  // check if the font has been already added
5179  $fb = $this->getFontBuffer($fontkey);
5180  if ($fb !== false) {
5181  if ($this->inxobj) {
5182  // we are inside an XObject template
5183  $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $fb['i'];
5184  }
5185  return $fontdata;
5186  }
5187  if (isset($type)) {
5188  unset($type);
5189  }
5190  if (isset($cw)) {
5191  unset($cw);
5192  }
5193  // get specified font directory (if any)
5194  $fontdir = false;
5195  if (!$this->empty_string($fontfile)) {
5196  $fontdir = dirname($fontfile);
5197  if ($this->empty_string($fontdir) OR ($fontdir == '.')) {
5198  $fontdir = '';
5199  } else {
5200  $fontdir .= '/';
5201  }
5202  }
5203  $missing_style = false; // true when the font style variation is missing
5204  // search and include font file
5205  if ($this->empty_string($fontfile) OR (!file_exists($fontfile))) {
5206  // build a standard filenames for specified font
5207  $tmp_fontfile = str_replace(' ', '', $family).strtolower($style).'.php';
5208  // search files on various directories
5209  if (($fontdir !== false) AND file_exists($fontdir.$tmp_fontfile)) {
5210  $fontfile = $fontdir.$tmp_fontfile;
5211  } elseif (file_exists($this->_getfontpath().$tmp_fontfile)) {
5212  $fontfile = $this->_getfontpath().$tmp_fontfile;
5213  } elseif (file_exists($tmp_fontfile)) {
5214  $fontfile = $tmp_fontfile;
5215  } elseif (!$this->empty_string($style)) {
5216  $missing_style = true;
5217  // try to remove the style part
5218  $tmp_fontfile = str_replace(' ', '', $family).'.php';
5219  if (($fontdir !== false) AND file_exists($fontdir.$tmp_fontfile)) {
5220  $fontfile = $fontdir.$tmp_fontfile;
5221  } elseif (file_exists($this->_getfontpath().$tmp_fontfile)) {
5222  $fontfile = $this->_getfontpath().$tmp_fontfile;
5223  } else {
5224  $fontfile = $tmp_fontfile;
5225  }
5226  }
5227  }
5228  // include font file
5229  if (file_exists($fontfile)) {
5230  include($fontfile);
5231  } else {
5232  $this->Error('Could not include font definition file: '.$family.'');
5233  }
5234  // check font parameters
5235  if ((!isset($type)) OR (!isset($cw))) {
5236  $this->Error('The font definition file has a bad format: '.$fontfile.'');
5237  }
5238  // SET default parameters
5239  if (!isset($file) OR $this->empty_string($file)) {
5240  $file = '';
5241  }
5242  if (!isset($enc) OR $this->empty_string($enc)) {
5243  $enc = '';
5244  }
5245  if (!isset($cidinfo) OR $this->empty_string($cidinfo)) {
5246  $cidinfo = array('Registry'=>'Adobe', 'Ordering'=>'Identity', 'Supplement'=>0);
5247  $cidinfo['uni2cid'] = array();
5248  }
5249  if (!isset($ctg) OR $this->empty_string($ctg)) {
5250  $ctg = '';
5251  }
5252  if (!isset($desc) OR $this->empty_string($desc)) {
5253  $desc = array();
5254  }
5255  if (!isset($up) OR $this->empty_string($up)) {
5256  $up = -100;
5257  }
5258  if (!isset($ut) OR $this->empty_string($ut)) {
5259  $ut = 50;
5260  }
5261  if (!isset($cw) OR $this->empty_string($cw)) {
5262  $cw = array();
5263  }
5264  if (!isset($dw) OR $this->empty_string($dw)) {
5265  // set default width
5266  if (isset($desc['MissingWidth']) AND ($desc['MissingWidth'] > 0)) {
5267  $dw = $desc['MissingWidth'];
5268  } elseif (isset($cw[32])) {
5269  $dw = $cw[32];
5270  } else {
5271  $dw = 600;
5272  }
5273  }
5274  ++$this->numfonts;
5275  if ($type == 'core') {
5276  $name = $this->CoreFonts[$fontkey];
5277  $subset = false;
5278  } elseif (($type == 'TrueType') OR ($type == 'Type1')) {
5279  $subset = false;
5280  } elseif ($type == 'TrueTypeUnicode') {
5281  $enc = 'Identity-H';
5282  } elseif ($type == 'cidfont0') {
5283  if ($this->pdfa_mode) {
5284  $this->Error('All fonts must be embedded in PDF/A mode!');
5285  }
5286  } else {
5287  $this->Error('Unknow font type: '.$type.'');
5288  }
5289  // set name if unset
5290  if (!isset($name) OR empty($name)) {
5291  $name = $fontkey;
5292  }
5293  // create artificial font style variations if missing (only works with non-embedded fonts)
5294  if (($type != 'core') AND $missing_style) {
5295  // style variations
5296  $styles = array('' => '', 'B' => ',Bold', 'I' => ',Italic', 'BI' => ',BoldItalic');
5297  $name .= $styles[$bistyle];
5298  // artificial bold
5299  if (strpos($bistyle, 'B') !== false) {
5300  if (isset($desc['StemV'])) {
5301  // from normal to bold
5302  $desc['StemV'] = round($desc['StemV'] * 1.75);
5303  } else {
5304  // bold
5305  $desc['StemV'] = 123;
5306  }
5307  }
5308  // artificial italic
5309  if (strpos($bistyle, 'I') !== false) {
5310  if (isset($desc['ItalicAngle'])) {
5311  $desc['ItalicAngle'] -= 11;
5312  } else {
5313  $desc['ItalicAngle'] = -11;
5314  }
5315  if (isset($desc['Flags'])) {
5316  $desc['Flags'] |= 64; //bit 7
5317  } else {
5318  $desc['Flags'] = 64;
5319  }
5320  }
5321  }
5322  // check if the array of characters bounding boxes is defined
5323  if (!isset($cbbox)) {
5324  $cbbox = array();
5325  }
5326  // initialize subsetchars
5327  $subsetchars = array_fill(0, 255, true);
5328  $this->setFontBuffer($fontkey, array('fontkey' => $fontkey, 'i' => $this->numfonts, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'cbbox' => $cbbox, 'dw' => $dw, 'enc' => $enc, 'cidinfo' => $cidinfo, 'file' => $file, 'ctg' => $ctg, 'subset' => $subset, 'subsetchars' => $subsetchars));
5329  if ($this->inxobj) {
5330  // we are inside an XObject template
5331  $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $this->numfonts;
5332  }
5333  if (isset($diff) AND (!empty($diff))) {
5334  //Search existing encodings
5335  $d = 0;
5336  $nb = count($this->diffs);
5337  for ($i=1; $i <= $nb; ++$i) {
5338  if ($this->diffs[$i] == $diff) {
5339  $d = $i;
5340  break;
5341  }
5342  }
5343  if ($d == 0) {
5344  $d = $nb + 1;
5345  $this->diffs[$d] = $diff;
5346  }
5347  $this->setFontSubBuffer($fontkey, 'diff', $d);
5348  }
5349  if (!$this->empty_string($file)) {
5350  if (!isset($this->FontFiles[$file])) {
5351  if ((strcasecmp($type,'TrueType') == 0) OR (strcasecmp($type, 'TrueTypeUnicode') == 0)) {
5352  $this->FontFiles[$file] = array('length1' => $originalsize, 'fontdir' => $fontdir, 'subset' => $subset, 'fontkeys' => array($fontkey));
5353  } elseif ($type != 'core') {
5354  $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2, 'fontdir' => $fontdir, 'subset' => $subset, 'fontkeys' => array($fontkey));
5355  }
5356  } else {
5357  // update fontkeys that are sharing this font file
5358  $this->FontFiles[$file]['subset'] = ($this->FontFiles[$file]['subset'] AND $subset);
5359  if (!in_array($fontkey, $this->FontFiles[$file]['fontkeys'])) {
5360  $this->FontFiles[$file]['fontkeys'][] = $fontkey;
5361  }
5362  }
5363  }
5364  return $fontdata;
5365  }
5366 
5384  public function SetFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) {
5385  //Select a font; size given in points
5386  if ($size === null) {
5387  $size = $this->FontSizePt;
5388  }
5389  if ($size < 0) {
5390  $size = 0;
5391  }
5392  // try to add font (if not already added)
5393  $fontdata = $this->AddFont($family, $style, $fontfile, $subset);
5394  $this->FontFamily = $fontdata['family'];
5395  $this->FontStyle = $fontdata['style'];
5396  $this->CurrentFont = $this->getFontBuffer($fontdata['fontkey']);
5397  $this->SetFontSize($size, $out);
5398  }
5399 
5408  public function SetFontSize($size, $out=true) {
5409  // font size in points
5410  $this->FontSizePt = $size;
5411  // font size in user units
5412  $this->FontSize = $size / $this->k;
5413  // calculate some font metrics
5414  if (isset($this->CurrentFont['desc']['FontBBox'])) {
5415  $bbox = explode(' ', substr($this->CurrentFont['desc']['FontBBox'], 1, -1));
5416  $font_height = ((intval($bbox[3]) - intval($bbox[1])) * $size / 1000);
5417  } else {
5418  $font_height = $size * 1.219;
5419  }
5420  if (isset($this->CurrentFont['desc']['Ascent']) AND ($this->CurrentFont['desc']['Ascent'] > 0)) {
5421  $font_ascent = ($this->CurrentFont['desc']['Ascent'] * $size / 1000);
5422  }
5423  if (isset($this->CurrentFont['desc']['Descent']) AND ($this->CurrentFont['desc']['Descent'] <= 0)) {
5424  $font_descent = (- $this->CurrentFont['desc']['Descent'] * $size / 1000);
5425  }
5426  if (!isset($font_ascent) AND !isset($font_descent)) {
5427  // core font
5428  $font_ascent = 0.76 * $font_height;
5429  $font_descent = $font_height - $font_ascent;
5430  } elseif (!isset($font_descent)) {
5431  $font_descent = $font_height - $font_ascent;
5432  } elseif (!isset($font_ascent)) {
5433  $font_ascent = $font_height - $font_descent;
5434  }
5435  $this->FontAscent = ($font_ascent / $this->k);
5436  $this->FontDescent = ($font_descent / $this->k);
5437  if ($out AND ($this->page > 0) AND (isset($this->CurrentFont['i'])) AND ($this->state == 2)) {
5438  $this->_out(sprintf('BT /F%d %F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
5439  }
5440  }
5441 
5448  public function getFontBBox() {
5449  $fbbox = array();
5450  if (isset($this->CurrentFont['desc']['FontBBox'])) {
5451  $tmpbbox = explode(' ', substr($this->CurrentFont['desc']['FontBBox'], 1, -1));
5452  $fbbox = array_map(array($this,'getAbsFontMeasure'), $tmpbbox);
5453  } else {
5454  // Find max width
5455  if (isset($this->CurrentFont['desc']['MaxWidth'])) {
5456  $maxw = $this->getAbsFontMeasure(intval($this->CurrentFont['desc']['MaxWidth']));
5457  } else {
5458  $maxw = 0;
5459  if (isset($this->CurrentFont['desc']['MissingWidth'])) {
5460  $maxw = max($maxw, $this->CurrentFont['desc']['MissingWidth']);
5461  }
5462  if (isset($this->CurrentFont['desc']['AvgWidth'])) {
5463  $maxw = max($maxw, $this->CurrentFont['desc']['AvgWidth']);
5464  }
5465  if (isset($this->CurrentFont['dw'])) {
5466  $maxw = max($maxw, $this->CurrentFont['dw']);
5467  }
5468  foreach ($this->CurrentFont['cw'] as $char => $w) {
5469  $maxw = max($maxw, $w);
5470  }
5471  if ($maxw == 0) {
5472  $maxw = 600;
5473  }
5474  $maxw = $this->getAbsFontMeasure($maxw);
5475  }
5476  $fbbox = array(0, -$this->FontDescent, $maxw, $this->FontAscent);
5477  }
5478  return $fbbox;
5479  }
5480 
5487  public function getAbsFontMeasure($s) {
5488  return ($s * $this->FontSize / 1000);
5489  }
5490 
5497  public function getCharBBox($char) {
5498  if (isset($this->CurrentFont['cbbox'][$char])) {
5499  return array_map(array($this,'getAbsFontMeasure'), $this->CurrentFont['cbbox'][intval($char)]);
5500  }
5501  return false;
5502  }
5503 
5514  public function getFontDescent($font, $style='', $size=0) {
5515  $fontdata = $this->AddFont($font, $style);
5516  $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
5517  if (isset($fontinfo['desc']['Descent']) AND ($fontinfo['desc']['Descent'] <= 0)) {
5518  $descent = (- $fontinfo['desc']['Descent'] * $size / 1000);
5519  } else {
5520  $descent = (1.219 * 0.24 * $size);
5521  }
5522  return ($descent / $this->k);
5523  }
5524 
5535  public function getFontAscent($font, $style='', $size=0) {
5536  $fontdata = $this->AddFont($font, $style);
5537  $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
5538  if (isset($fontinfo['desc']['Ascent']) AND ($fontinfo['desc']['Ascent'] > 0)) {
5539  $ascent = ($fontinfo['desc']['Ascent'] * $size / 1000);
5540  } else {
5541  $ascent = 1.219 * 0.76 * $size;
5542  }
5543  return ($ascent / $this->k);
5544  }
5545 
5555  public function isCharDefined($char, $font='', $style='') {
5556  if (is_string($char)) {
5557  // get character code
5558  $char = $this->UTF8StringToArray($char);
5559  $char = $char[0];
5560  }
5561  if ($this->empty_string($font)) {
5562  if ($this->empty_string($style)) {
5563  return (isset($this->CurrentFont['cw'][intval($char)]));
5564  }
5565  $font = $this->FontFamily;
5566  }
5567  $fontdata = $this->AddFont($font, $style);
5568  $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
5569  return (isset($fontinfo['cw'][intval($char)]));
5570  }
5571 
5582  public function replaceMissingChars($text, $font='', $style='', $subs=array()) {
5583  if (empty($subs)) {
5584  return $text;
5585  }
5586  if ($this->empty_string($font)) {
5587  $font = $this->FontFamily;
5588  }
5589  $fontdata = $this->AddFont($font, $style);
5590  $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
5591  $uniarr = $this->UTF8StringToArray($text);
5592  foreach ($uniarr as $k => $chr) {
5593  if (!isset($fontinfo['cw'][$chr])) {
5594  // this character is missing on the selected font
5595  if (isset($subs[$chr])) {
5596  // we have available substitutions
5597  if (is_array($subs[$chr])) {
5598  foreach($subs[$chr] as $s) {
5599  if (isset($fontinfo['cw'][$s])) {
5600  $uniarr[$k] = $s;
5601  break;
5602  }
5603  }
5604  } elseif (isset($fontinfo['cw'][$subs[$chr]])) {
5605  $uniarr[$k] = $subs[$chr];
5606  }
5607  }
5608  }
5609  }
5610  return $this->UniArrSubString($this->UTF8ArrayToUniArray($uniarr));
5611  }
5612 
5619  public function SetDefaultMonospacedFont($font) {
5620  $this->default_monospaced_font = $font;
5621  }
5622 
5630  public function AddLink() {
5631  //Create a new internal link
5632  $n = count($this->links) + 1;
5633  $this->links[$n] = array(0, 0);
5634  return $n;
5635  }
5636 
5646  public function SetLink($link, $y=0, $page=-1) {
5647  if ($y == -1) {
5648  $y = $this->y;
5649  }
5650  if ($page == -1) {
5651  $page = $this->page;
5652  }
5653  $this->links[$link] = array($page, $y);
5654  }
5655 
5669  public function Link($x, $y, $w, $h, $link, $spaces=0) {
5670  $this->Annotation($x, $y, $w, $h, $link, array('Subtype'=>'Link'), $spaces);
5671  }
5672 
5686  public function Annotation($x, $y, $w, $h, $text, $opt=array('Subtype'=>'Text'), $spaces=0) {
5687  if ($this->inxobj) {
5688  // store parameters for later use on template
5689  $this->xobjects[$this->xobjid]['annotations'][] = array('x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'text' => $text, 'opt' => $opt, 'spaces' => $spaces);
5690  return;
5691  }
5692  if ($x === '') {
5693  $x = $this->x;
5694  }
5695  if ($y === '') {
5696  $y = $this->y;
5697  }
5698  // check page for no-write regions and adapt page margins if necessary
5699  list($x, $y) = $this->checkPageRegions($h, $x, $y);
5700  // recalculate coordinates to account for graphic transformations
5701  if (isset($this->transfmatrix) AND !empty($this->transfmatrix)) {
5702  for ($i=$this->transfmatrix_key; $i > 0; --$i) {
5703  $maxid = count($this->transfmatrix[$i]) - 1;
5704  for ($j=$maxid; $j >= 0; --$j) {
5705  $ctm = $this->transfmatrix[$i][$j];
5706  if (isset($ctm['a'])) {
5707  $x = $x * $this->k;
5708  $y = ($this->h - $y) * $this->k;
5709  $w = $w * $this->k;
5710  $h = $h * $this->k;
5711  // top left
5712  $xt = $x;
5713  $yt = $y;
5714  $x1 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
5715  $y1 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
5716  // top right
5717  $xt = $x + $w;
5718  $yt = $y;
5719  $x2 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
5720  $y2 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
5721  // bottom left
5722  $xt = $x;
5723  $yt = $y - $h;
5724  $x3 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
5725  $y3 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
5726  // bottom right
5727  $xt = $x + $w;
5728  $yt = $y - $h;
5729  $x4 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
5730  $y4 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
5731  // new coordinates (rectangle area)
5732  $x = min($x1, $x2, $x3, $x4);
5733  $y = max($y1, $y2, $y3, $y4);
5734  $w = (max($x1, $x2, $x3, $x4) - $x) / $this->k;
5735  $h = ($y - min($y1, $y2, $y3, $y4)) / $this->k;
5736  $x = $x / $this->k;
5737  $y = $this->h - ($y / $this->k);
5738  }
5739  }
5740  }
5741  }
5742  if ($this->page <= 0) {
5743  $page = 1;
5744  } else {
5745  $page = $this->page;
5746  }
5747  if (!isset($this->PageAnnots[$page])) {
5748  $this->PageAnnots[$page] = array();
5749  }
5750  ++$this->n;
5751  $this->PageAnnots[$page][] = array('n' => $this->n, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'txt' => $text, 'opt' => $opt, 'numspaces' => $spaces);
5752  if (!$this->pdfa_mode) {
5753  if ((($opt['Subtype'] == 'FileAttachment') OR ($opt['Subtype'] == 'Sound')) AND (!$this->empty_string($opt['FS'])) AND file_exists($opt['FS']) AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) {
5754  ++$this->n;
5755  $this->embeddedfiles[basename($opt['FS'])] = array('n' => $this->n, 'file' => $opt['FS']);
5756  }
5757  }
5758  // Add widgets annotation's icons
5759  if (isset($opt['mk']['i']) AND file_exists($opt['mk']['i'])) {
5760  $this->Image($opt['mk']['i'], '', '', 10, 10, '', '', '', false, 300, '', false, false, 0, false, true);
5761  }
5762  if (isset($opt['mk']['ri']) AND file_exists($opt['mk']['ri'])) {
5763  $this->Image($opt['mk']['ri'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
5764  }
5765  if (isset($opt['mk']['ix']) AND file_exists($opt['mk']['ix'])) {
5766  $this->Image($opt['mk']['ix'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
5767  }
5768  }
5769 
5776  protected function _putEmbeddedFiles() {
5777  if ($this->pdfa_mode) {
5778  // embedded files are not allowed in PDF/A mode
5779  return;
5780  }
5781  reset($this->embeddedfiles);
5782  foreach ($this->embeddedfiles as $filename => $filedata) {
5783  $data = file_get_contents($filedata['file']);
5784  $filter = '';
5785  if ($this->compress) {
5786  $data = gzcompress($data);
5787  $filter = ' /Filter /FlateDecode';
5788  }
5789  $stream = $this->_getrawstream($data, $filedata['n']);
5790  $out = $this->_getobj($filedata['n'])."\n";
5791  $out .= '<< /Type /EmbeddedFile'.$filter.' /Length '.strlen($stream).' >>';
5792  $out .= ' stream'."\n".$stream."\n".'endstream';
5793  $out .= "\n".'endobj';
5794  $this->_out($out);
5795  }
5796  }
5797 
5821  public function Text($x, $y, $txt, $fstroke=false, $fclip=false, $ffill=true, $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M', $rtloff=false) {
5824  $this->setTextRenderingMode($fstroke, $ffill, $fclip);
5825  $this->SetXY($x, $y, $rtloff);
5826  $this->Cell(0, 0, $txt, $border, $ln, $align, $fill, $link, $stretch, $ignore_min_height, $calign, $valign);
5827  // restore previous rendering mode
5828  $this->textrendermode = $textrendermode;
5829  $this->textstrokewidth = $textstrokewidth;
5830  }
5831 
5841  public function AcceptPageBreak() {
5842  if ($this->num_columns > 1) {
5843  // multi column mode
5844  if ($this->current_column < ($this->num_columns - 1)) {
5845  // go to next column
5846  $this->selectColumn($this->current_column + 1);
5847  } elseif ($this->AutoPageBreak) {
5848  // add a new page
5849  $this->AddPage();
5850  // set first column
5851  $this->selectColumn(0);
5852  }
5853  // avoid page breaking from checkPageBreak()
5854  return false;
5855  }
5856  return $this->AutoPageBreak;
5857  }
5858 
5868  protected function checkPageBreak($h=0, $y='', $addpage=true) {
5869  if ($this->empty_string($y)) {
5870  $y = $this->y;
5871  }
5872  $current_page = $this->page;
5873  if ((($y + $h) > $this->PageBreakTrigger) AND ($this->inPageBody()) AND ($this->AcceptPageBreak())) {
5874  if ($addpage) {
5875  //Automatic page break
5876  $x = $this->x;
5877  $this->AddPage($this->CurOrientation);
5878  $this->y = $this->tMargin;
5879  $oldpage = $this->page - 1;
5880  if ($this->rtl) {
5881  if ($this->pagedim[$this->page]['orm'] != $this->pagedim[$oldpage]['orm']) {
5882  $this->x = $x - ($this->pagedim[$this->page]['orm'] - $this->pagedim[$oldpage]['orm']);
5883  } else {
5884  $this->x = $x;
5885  }
5886  } else {
5887  if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) {
5888  $this->x = $x + ($this->pagedim[$this->page]['olm'] - $this->pagedim[$oldpage]['olm']);
5889  } else {
5890  $this->x = $x;
5891  }
5892  }
5893  }
5894  return true;
5895  }
5896  if ($current_page != $this->page) {
5897  // account for columns mode
5898  return true;
5899  }
5900  return false;
5901  }
5902 
5919  public function removeSHY($txt='') {
5920  $txt = preg_replace('/([\\xc2]{1}[\\xad]{1})/', '', $txt);
5921  if (!$this->isunicode) {
5922  $txt = preg_replace('/([\\xad]{1})/', '', $txt);
5923  }
5924  return $txt;
5925  }
5926 
5946  public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') {
5947  $prev_cell_margin = $this->cell_margin;
5948  $prev_cell_padding = $this->cell_padding;
5949  $this->adjustCellPadding($border);
5950  if (!$ignore_min_height) {
5951  $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
5952  if ($h < $min_cell_height) {
5953  $h = $min_cell_height;
5954  }
5955  }
5956  $this->checkPageBreak($h + $this->cell_margin['T'] + $this->cell_margin['B']);
5957  // apply text shadow if enabled
5958  if ($this->txtshadow['enabled']) {
5959  // save data
5960  $x = $this->x;
5961  $y = $this->y;
5962  $bc = $this->bgcolor;
5963  $fc = $this->fgcolor;
5964  $sc = $this->strokecolor;
5965  $alpha = $this->alpha;
5966  // print shadow
5967  $this->x += $this->txtshadow['depth_w'];
5968  $this->y += $this->txtshadow['depth_h'];
5969  $this->SetFillColorArray($this->txtshadow['color']);
5970  $this->SetTextColorArray($this->txtshadow['color']);
5971  $this->SetDrawColorArray($this->txtshadow['color']);
5972  if ($this->txtshadow['opacity'] != $alpha['CA']) {
5973  $this->setAlpha($this->txtshadow['opacity'], $this->txtshadow['blend_mode']);
5974  }
5975  if ($this->state == 2) {
5976  $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
5977  }
5978  //restore data
5979  $this->x = $x;
5980  $this->y = $y;
5981  $this->SetFillColorArray($bc);
5982  $this->SetTextColorArray($fc);
5983  $this->SetDrawColorArray($sc);
5984  if ($this->txtshadow['opacity'] != $alpha['CA']) {
5985  $this->setAlpha($alpha['CA'], $alpha['BM'], $alpha['ca'], $alpha['AIS']);
5986  }
5987  }
5988  if ($this->state == 2) {
5989  $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
5990  }
5991  $this->cell_padding = $prev_cell_padding;
5992  $this->cell_margin = $prev_cell_margin;
5993  }
5994 
6015  protected function getCellCode($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') {
6016  // replace 'NO-BREAK SPACE' (U+00A0) character with a simple space
6017  $txt = str_replace($this->unichr(160), ' ', $txt);
6018  $prev_cell_margin = $this->cell_margin;
6019  $prev_cell_padding = $this->cell_padding;
6020  $txt = $this->removeSHY($txt);
6021  $rs = ''; //string to be returned
6022  $this->adjustCellPadding($border);
6023  if (!$ignore_min_height) {
6024  $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
6025  if ($h < $min_cell_height) {
6026  $h = $min_cell_height;
6027  }
6028  }
6029  $k = $this->k;
6030  // check page for no-write regions and adapt page margins if necessary
6031  list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y);
6032  if ($this->rtl) {
6033  $x = $this->x - $this->cell_margin['R'];
6034  } else {
6035  $x = $this->x + $this->cell_margin['L'];
6036  }
6037  $y = $this->y + $this->cell_margin['T'];
6038  $prev_font_stretching = $this->font_stretching;
6039  $prev_font_spacing = $this->font_spacing;
6040  // cell vertical alignment
6041  switch ($calign) {
6042  case 'A': {
6043  // font top
6044  switch ($valign) {
6045  case 'T': {
6046  // top
6047  $y -= $this->cell_padding['T'];
6048  break;
6049  }
6050  case 'B': {
6051  // bottom
6052  $y -= ($h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent);
6053  break;
6054  }
6055  default:
6056  case 'C':
6057  case 'M': {
6058  // center
6059  $y -= (($h - $this->FontAscent - $this->FontDescent) / 2);
6060  break;
6061  }
6062  }
6063  break;
6064  }
6065  case 'L': {
6066  // font baseline
6067  switch ($valign) {
6068  case 'T': {
6069  // top
6070  $y -= ($this->cell_padding['T'] + $this->FontAscent);
6071  break;
6072  }
6073  case 'B': {
6074  // bottom
6075  $y -= ($h - $this->cell_padding['B'] - $this->FontDescent);
6076  break;
6077  }
6078  default:
6079  case 'C':
6080  case 'M': {
6081  // center
6082  $y -= (($h + $this->FontAscent - $this->FontDescent) / 2);
6083  break;
6084  }
6085  }
6086  break;
6087  }
6088  case 'D': {
6089  // font bottom
6090  switch ($valign) {
6091  case 'T': {
6092  // top
6093  $y -= ($this->cell_padding['T'] + $this->FontAscent + $this->FontDescent);
6094  break;
6095  }
6096  case 'B': {
6097  // bottom
6098  $y -= ($h - $this->cell_padding['B']);
6099  break;
6100  }
6101  default:
6102  case 'C':
6103  case 'M': {
6104  // center
6105  $y -= (($h + $this->FontAscent + $this->FontDescent) / 2);
6106  break;
6107  }
6108  }
6109  break;
6110  }
6111  case 'B': {
6112  // cell bottom
6113  $y -= $h;
6114  break;
6115  }
6116  case 'C':
6117  case 'M': {
6118  // cell center
6119  $y -= ($h / 2);
6120  break;
6121  }
6122  default:
6123  case 'T': {
6124  // cell top
6125  break;
6126  }
6127  }
6128  // text vertical alignment
6129  switch ($valign) {
6130  case 'T': {
6131  // top
6132  $yt = $y + $this->cell_padding['T'];
6133  break;
6134  }
6135  case 'B': {
6136  // bottom
6137  $yt = $y + $h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent;
6138  break;
6139  }
6140  default:
6141  case 'C':
6142  case 'M': {
6143  // center
6144  $yt = $y + (($h - $this->FontAscent - $this->FontDescent) / 2);
6145  break;
6146  }
6147  }
6148  $basefonty = $yt + $this->FontAscent;
6149  if ($this->empty_string($w) OR ($w <= 0)) {
6150  if ($this->rtl) {
6151  $w = $x - $this->lMargin;
6152  } else {
6153  $w = $this->w - $this->rMargin - $x;
6154  }
6155  }
6156  $s = '';
6157  // fill and borders
6158  if (is_string($border) AND (strlen($border) == 4)) {
6159  // full border
6160  $border = 1;
6161  }
6162  if ($fill OR ($border == 1)) {
6163  if ($fill) {
6164  $op = ($border == 1) ? 'B' : 'f';
6165  } else {
6166  $op = 'S';
6167  }
6168  if ($this->rtl) {
6169  $xk = (($x - $w) * $k);
6170  } else {
6171  $xk = ($x * $k);
6172  }
6173  $s .= sprintf('%F %F %F %F re %s ', $xk, (($this->h - $y) * $k), ($w * $k), (-$h * $k), $op);
6174  }
6175  // draw borders
6176  $s .= $this->getCellBorder($x, $y, $w, $h, $border);
6177  if ($txt != '') {
6178  $txt2 = $txt;
6179  if ($this->isunicode) {
6180  if (($this->CurrentFont['type'] == 'core') OR ($this->CurrentFont['type'] == 'TrueType') OR ($this->CurrentFont['type'] == 'Type1')) {
6181  $txt2 = $this->UTF8ToLatin1($txt2);
6182  } else {
6183  $unicode = $this->UTF8StringToArray($txt); // array of UTF-8 unicode values
6184  $unicode = $this->utf8Bidi($unicode, '', $this->tmprtl);
6185  // replace thai chars (if any)
6186  if (defined('K_THAI_TOPCHARS') AND (K_THAI_TOPCHARS == true)) {
6187  // number of chars
6188  $numchars = count($unicode);
6189  // po pla, for far, for fan
6190  $longtail = array(0x0e1b, 0x0e1d, 0x0e1f);
6191  // do chada, to patak
6192  $lowtail = array(0x0e0e, 0x0e0f);
6193  // mai hun arkad, sara i, sara ii, sara ue, sara uee
6194  $upvowel = array(0x0e31, 0x0e34, 0x0e35, 0x0e36, 0x0e37);
6195  // mai ek, mai tho, mai tri, mai chattawa, karan
6196  $tonemark = array(0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c);
6197  // sara u, sara uu, pinthu
6198  $lowvowel = array(0x0e38, 0x0e39, 0x0e3a);
6199  $output = array();
6200  for ($i = 0; $i < $numchars; $i++) {
6201  if (($unicode[$i] >= 0x0e00) && ($unicode[$i] <= 0x0e5b)) {
6202  $ch0 = $unicode[$i];
6203  $ch1 = ($i > 0) ? $unicode[($i - 1)] : 0;
6204  $ch2 = ($i > 1) ? $unicode[($i - 2)] : 0;
6205  $chn = ($i < ($numchars - 1)) ? $unicode[($i + 1)] : 0;
6206  if (in_array($ch0, $tonemark)) {
6207  if ($chn == 0x0e33) {
6208  // sara um
6209  if (in_array($ch1, $longtail)) {
6210  // tonemark at upper left
6211  $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
6212  } else {
6213  // tonemark at upper right (normal position)
6214  $output[] = $ch0;
6215  }
6216  } elseif (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $lowvowel))) {
6217  // tonemark at lower left
6218  $output[] = $this->replaceChar($ch0, (0xf705 + $ch0 - 0x0e48));
6219  } elseif (in_array($ch1, $upvowel)) {
6220  if (in_array($ch2, $longtail)) {
6221  // tonemark at upper left
6222  $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
6223  } else {
6224  // tonemark at upper right (normal position)
6225  $output[] = $ch0;
6226  }
6227  } else {
6228  // tonemark at lower right
6229  $output[] = $this->replaceChar($ch0, (0xf70a + $ch0 - 0x0e48));
6230  }
6231  } elseif (($ch0 == 0x0e33) AND (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $tonemark)))) {
6232  // add lower left nikhahit and sara aa
6233  if ($this->isCharDefined(0xf711) AND $this->isCharDefined(0x0e32)) {
6234  $output[] = 0xf711;
6235  $this->CurrentFont['subsetchars'][0xf711] = true;
6236  $output[] = 0x0e32;
6237  $this->CurrentFont['subsetchars'][0x0e32] = true;
6238  } else {
6239  $output[] = $ch0;
6240  }
6241  } elseif (in_array($ch1, $longtail)) {
6242  if ($ch0 == 0x0e31) {
6243  // lower left mai hun arkad
6244  $output[] = $this->replaceChar($ch0, 0xf710);
6245  } elseif (in_array($ch0, $upvowel)) {
6246  // lower left
6247  $output[] = $this->replaceChar($ch0, (0xf701 + $ch0 - 0x0e34));
6248  } elseif ($ch0 == 0x0e47) {
6249  // lower left mai tai koo
6250  $output[] = $this->replaceChar($ch0, 0xf712);
6251  } else {
6252  // normal character
6253  $output[] = $ch0;
6254  }
6255  } elseif (in_array($ch1, $lowtail) AND in_array($ch0, $lowvowel)) {
6256  // lower vowel
6257  $output[] = $this->replaceChar($ch0, (0xf718 + $ch0 - 0x0e38));
6258  } elseif (($ch0 == 0x0e0d) AND in_array($chn, $lowvowel)) {
6259  // yo ying without lower part
6260  $output[] = $this->replaceChar($ch0, 0xf70f);
6261  } elseif (($ch0 == 0x0e10) AND in_array($chn, $lowvowel)) {
6262  // tho santan without lower part
6263  $output[] = $this->replaceChar($ch0, 0xf700);
6264  } else {
6265  $output[] = $ch0;
6266  }
6267  } else {
6268  // non-thai character
6269  $output[] = $unicode[$i];
6270  }
6271  }
6272  $unicode = $output;
6273  // update font subsetchars
6274  $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']);
6275  } // end of K_THAI_TOPCHARS
6276  $txt2 = $this->arrUTF8ToUTF16BE($unicode, false);
6277  }
6278  }
6279  $txt2 = $this->_escape($txt2);
6280  // get current text width (considering general font stretching and spacing)
6281  $txwidth = $this->GetStringWidth($txt);
6282  $width = $txwidth;
6283  // check for stretch mode
6284  if ($stretch > 0) {
6285  // calculate ratio between cell width and text width
6286  if ($width <= 0) {
6287  $ratio = 1;
6288  } else {
6289  $ratio = (($w - $this->cell_padding['L'] - $this->cell_padding['R']) / $width);
6290  }
6291  // check if stretching is required
6292  if (($ratio < 1) OR (($ratio > 1) AND (($stretch % 2) == 0))) {
6293  // the text will be stretched to fit cell width
6294  if ($stretch > 2) {
6295  // set new character spacing
6296  $this->font_spacing += ($w - $this->cell_padding['L'] - $this->cell_padding['R'] - $width) / (max(($this->GetNumChars($txt) - 1), 1) * ($this->font_stretching / 100));
6297  } else {
6298  // set new horizontal stretching
6299  $this->font_stretching *= $ratio;
6300  }
6301  // recalculate text width (the text fills the entire cell)
6302  $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
6303  // reset alignment
6304  $align = '';
6305  }
6306  }
6307  if ($this->font_stretching != 100) {
6308  // apply font stretching
6309  $rs .= sprintf('BT %F Tz ET ', $this->font_stretching);
6310  }
6311  if ($this->font_spacing != 0) {
6312  // increase/decrease font spacing
6313  $rs .= sprintf('BT %F Tc ET ', ($this->font_spacing * $this->k));
6314  }
6315  if ($this->ColorFlag AND ($this->textrendermode < 4)) {
6316  $s .= 'q '.$this->TextColor.' ';
6317  }
6318  // rendering mode
6319  $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, ($this->textstrokewidth * $this->k));
6320  // count number of spaces
6321  $ns = substr_count($txt, chr(32));
6322  // Justification
6323  $spacewidth = 0;
6324  if (($align == 'J') AND ($ns > 0)) {
6325  if ($this->isUnicodeFont()) {
6326  // get string width without spaces
6327  $width = $this->GetStringWidth(str_replace(' ', '', $txt));
6328  // calculate average space width
6329  $spacewidth = -1000 * ($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1) / $this->FontSize;
6330  if ($this->font_stretching != 100) {
6331  // word spacing is affected by stretching
6332  $spacewidth /= ($this->font_stretching / 100);
6333  }
6334  // set word position to be used with TJ operator
6335  $txt2 = str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacewidth).' (', $txt2);
6336  $unicode_justification = true;
6337  } else {
6338  // get string width
6339  $width = $txwidth;
6340  // new space width
6341  $spacewidth = (($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1)) * $this->k;
6342  if ($this->font_stretching != 100) {
6343  // word spacing (Tw) is affected by stretching
6344  $spacewidth /= ($this->font_stretching / 100);
6345  }
6346  // set word spacing
6347  $rs .= sprintf('BT %F Tw ET ', $spacewidth);
6348  }
6349  $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
6350  }
6351  // replace carriage return characters
6352  $txt2 = str_replace("\r", ' ', $txt2);
6353  switch ($align) {
6354  case 'C': {
6355  $dx = ($w - $width) / 2;
6356  break;
6357  }
6358  case 'R': {
6359  if ($this->rtl) {
6360  $dx = $this->cell_padding['R'];
6361  } else {
6362  $dx = $w - $width - $this->cell_padding['R'];
6363  }
6364  break;
6365  }
6366  case 'L': {
6367  if ($this->rtl) {
6368  $dx = $w - $width - $this->cell_padding['L'];
6369  } else {
6370  $dx = $this->cell_padding['L'];
6371  }
6372  break;
6373  }
6374  case 'J':
6375  default: {
6376  if ($this->rtl) {
6377  $dx = $this->cell_padding['R'];
6378  } else {
6379  $dx = $this->cell_padding['L'];
6380  }
6381  break;
6382  }
6383  }
6384  if ($this->rtl) {
6385  $xdx = $x - $dx - $width;
6386  } else {
6387  $xdx = $x + $dx;
6388  }
6389  $xdk = $xdx * $k;
6390  // print text
6391  $s .= sprintf('BT %F %F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2);
6392  if (isset($uniblock)) {
6393  // print overlapping characters as separate string
6394  $xshift = 0; // horizontal shift
6395  $ty = (($this->h - $basefonty + (0.2 * $this->FontSize)) * $k);
6396  $spw = (($w - $txwidth - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1));
6397  foreach ($uniblock as $uk => $uniarr) {
6398  if (($uk % 2) == 0) {
6399  // x space to skip
6400  if ($spacewidth != 0) {
6401  // justification shift
6402  $xshift += (count(array_keys($uniarr, 32)) * $spw);
6403  }
6404  $xshift += $this->GetArrStringWidth($uniarr); // + shift justification
6405  } else {
6406  // character to print
6407  $topchr = $this->arrUTF8ToUTF16BE($uniarr, false);
6408  $topchr = $this->_escape($topchr);
6409  $s .= sprintf(' BT %F %F Td [(%s)] TJ ET', ($xdk + ($xshift * $k)), $ty, $topchr);
6410  }
6411  }
6412  }
6413  if ($this->underline) {
6414  $s .= ' '.$this->_dounderlinew($xdx, $basefonty, $width);
6415  }
6416  if ($this->linethrough) {
6417  $s .= ' '.$this->_dolinethroughw($xdx, $basefonty, $width);
6418  }
6419  if ($this->overline) {
6420  $s .= ' '.$this->_dooverlinew($xdx, $basefonty, $width);
6421  }
6422  if ($this->ColorFlag AND ($this->textrendermode < 4)) {
6423  $s .= ' Q';
6424  }
6425  if ($link) {
6426  $this->Link($xdx, $yt, $width, ($this->FontAscent + $this->FontDescent), $link, $ns);
6427  }
6428  }
6429  // output cell
6430  if ($s) {
6431  // output cell
6432  $rs .= $s;
6433  if ($this->font_spacing != 0) {
6434  // reset font spacing mode
6435  $rs .= ' BT 0 Tc ET';
6436  }
6437  if ($this->font_stretching != 100) {
6438  // reset font stretching mode
6439  $rs .= ' BT 100 Tz ET';
6440  }
6441  }
6442  // reset word spacing
6443  if (!$this->isUnicodeFont() AND ($align == 'J')) {
6444  $rs .= ' BT 0 Tw ET';
6445  }
6446  // reset stretching and spacing
6447  $this->font_stretching = $prev_font_stretching;
6448  $this->font_spacing = $prev_font_spacing;
6449  $this->lasth = $h;
6450  if ($ln > 0) {
6451  //Go to the beginning of the next line
6452  $this->y = $y + $h + $this->cell_margin['B'];
6453  if ($ln == 1) {
6454  if ($this->rtl) {
6455  $this->x = $this->w - $this->rMargin;
6456  } else {
6457  $this->x = $this->lMargin;
6458  }
6459  }
6460  } else {
6461  // go left or right by case
6462  if ($this->rtl) {
6463  $this->x = $x - $w - $this->cell_margin['L'];
6464  } else {
6465  $this->x = $x + $w + $this->cell_margin['R'];
6466  }
6467  }
6468  $gstyles = ''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor."\n";
6469  $rs = $gstyles.$rs;
6470  $this->cell_padding = $prev_cell_padding;
6471  $this->cell_margin = $prev_cell_margin;
6472  return $rs;
6473  }
6474 
6483  protected function replaceChar($oldchar, $newchar) {
6484  if ($this->isCharDefined($newchar)) {
6485  // add the new char on the subset list
6486  $this->CurrentFont['subsetchars'][$newchar] = true;
6487  // return the new character
6488  return $newchar;
6489  }
6490  // return the old char
6491  return $oldchar;
6492  }
6493 
6506  protected function getCellBorder($x, $y, $w, $h, $brd) {
6507  $s = ''; // string to be returned
6508  if (empty($brd)) {
6509  return $s;
6510  }
6511  if ($brd == 1) {
6512  $brd = array('LRTB' => true);
6513  }
6514  // calculate coordinates for border
6515  $k = $this->k;
6516  if ($this->rtl) {
6517  $xeL = ($x - $w) * $k;
6518  $xeR = $x * $k;
6519  } else {
6520  $xeL = $x * $k;
6521  $xeR = ($x + $w) * $k;
6522  }
6523  $yeL = (($this->h - ($y + $h)) * $k);
6524  $yeT = (($this->h - $y) * $k);
6525  $xeT = $xeL;
6526  $xeB = $xeR;
6527  $yeR = $yeT;
6528  $yeB = $yeL;
6529  if (is_string($brd)) {
6530  // convert string to array
6531  $slen = strlen($brd);
6532  $newbrd = array();
6533  for ($i = 0; $i < $slen; ++$i) {
6534  $newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter');
6535  }
6536  $brd = $newbrd;
6537  }
6538  if (isset($brd['mode'])) {
6539  $mode = $brd['mode'];
6540  unset($brd['mode']);
6541  } else {
6542  $mode = 'normal';
6543  }
6544  foreach ($brd as $border => $style) {
6545  if (is_array($style) AND !empty($style)) {
6546  // apply border style
6547  $prev_style = $this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' ';
6548  $s .= $this->SetLineStyle($style, true)."\n";
6549  }
6550  switch ($mode) {
6551  case 'ext': {
6552  $off = (($this->LineWidth / 2) * $k);
6553  $xL = $xeL - $off;
6554  $xR = $xeR + $off;
6555  $yT = $yeT + $off;
6556  $yL = $yeL - $off;
6557  $xT = $xL;
6558  $xB = $xR;
6559  $yR = $yT;
6560  $yB = $yL;
6561  $w += $this->LineWidth;
6562  $h += $this->LineWidth;
6563  break;
6564  }
6565  case 'int': {
6566  $off = ($this->LineWidth / 2) * $k;
6567  $xL = $xeL + $off;
6568  $xR = $xeR - $off;
6569  $yT = $yeT - $off;
6570  $yL = $yeL + $off;
6571  $xT = $xL;
6572  $xB = $xR;
6573  $yR = $yT;
6574  $yB = $yL;
6575  $w -= $this->LineWidth;
6576  $h -= $this->LineWidth;
6577  break;
6578  }
6579  case 'normal':
6580  default: {
6581  $xL = $xeL;
6582  $xT = $xeT;
6583  $xB = $xeB;
6584  $xR = $xeR;
6585  $yL = $yeL;
6586  $yT = $yeT;
6587  $yB = $yeB;
6588  $yR = $yeR;
6589  break;
6590  }
6591  }
6592  // draw borders by case
6593  if (strlen($border) == 4) {
6594  $s .= sprintf('%F %F %F %F re S ', $xT, $yT, ($w * $k), (-$h * $k));
6595  } elseif (strlen($border) == 3) {
6596  if (strpos($border,'B') === false) { // LTR
6597  $s .= sprintf('%F %F m ', $xL, $yL);
6598  $s .= sprintf('%F %F l ', $xT, $yT);
6599  $s .= sprintf('%F %F l ', $xR, $yR);
6600  $s .= sprintf('%F %F l ', $xB, $yB);
6601  $s .= 'S ';
6602  } elseif (strpos($border,'L') === false) { // TRB
6603  $s .= sprintf('%F %F m ', $xT, $yT);
6604  $s .= sprintf('%F %F l ', $xR, $yR);
6605  $s .= sprintf('%F %F l ', $xB, $yB);
6606  $s .= sprintf('%F %F l ', $xL, $yL);
6607  $s .= 'S ';
6608  } elseif (strpos($border,'T') === false) { // RBL
6609  $s .= sprintf('%F %F m ', $xR, $yR);
6610  $s .= sprintf('%F %F l ', $xB, $yB);
6611  $s .= sprintf('%F %F l ', $xL, $yL);
6612  $s .= sprintf('%F %F l ', $xT, $yT);
6613  $s .= 'S ';
6614  } elseif (strpos($border,'R') === false) { // BLT
6615  $s .= sprintf('%F %F m ', $xB, $yB);
6616  $s .= sprintf('%F %F l ', $xL, $yL);
6617  $s .= sprintf('%F %F l ', $xT, $yT);
6618  $s .= sprintf('%F %F l ', $xR, $yR);
6619  $s .= 'S ';
6620  }
6621  } elseif (strlen($border) == 2) {
6622  if ((strpos($border,'L') !== false) AND (strpos($border,'T') !== false)) { // LT
6623  $s .= sprintf('%F %F m ', $xL, $yL);
6624  $s .= sprintf('%F %F l ', $xT, $yT);
6625  $s .= sprintf('%F %F l ', $xR, $yR);
6626  $s .= 'S ';
6627  } elseif ((strpos($border,'T') !== false) AND (strpos($border,'R') !== false)) { // TR
6628  $s .= sprintf('%F %F m ', $xT, $yT);
6629  $s .= sprintf('%F %F l ', $xR, $yR);
6630  $s .= sprintf('%F %F l ', $xB, $yB);
6631  $s .= 'S ';
6632  } elseif ((strpos($border,'R') !== false) AND (strpos($border,'B') !== false)) { // RB
6633  $s .= sprintf('%F %F m ', $xR, $yR);
6634  $s .= sprintf('%F %F l ', $xB, $yB);
6635  $s .= sprintf('%F %F l ', $xL, $yL);
6636  $s .= 'S ';
6637  } elseif ((strpos($border,'B') !== false) AND (strpos($border,'L') !== false)) { // BL
6638  $s .= sprintf('%F %F m ', $xB, $yB);
6639  $s .= sprintf('%F %F l ', $xL, $yL);
6640  $s .= sprintf('%F %F l ', $xT, $yT);
6641  $s .= 'S ';
6642  } elseif ((strpos($border,'L') !== false) AND (strpos($border,'R') !== false)) { // LR
6643  $s .= sprintf('%F %F m ', $xL, $yL);
6644  $s .= sprintf('%F %F l ', $xT, $yT);
6645  $s .= 'S ';
6646  $s .= sprintf('%F %F m ', $xR, $yR);
6647  $s .= sprintf('%F %F l ', $xB, $yB);
6648  $s .= 'S ';
6649  } elseif ((strpos($border,'T') !== false) AND (strpos($border,'B') !== false)) { // TB
6650  $s .= sprintf('%F %F m ', $xT, $yT);
6651  $s .= sprintf('%F %F l ', $xR, $yR);
6652  $s .= 'S ';
6653  $s .= sprintf('%F %F m ', $xB, $yB);
6654  $s .= sprintf('%F %F l ', $xL, $yL);
6655  $s .= 'S ';
6656  }
6657  } else { // strlen($border) == 1
6658  if (strpos($border,'L') !== false) { // L
6659  $s .= sprintf('%F %F m ', $xL, $yL);
6660  $s .= sprintf('%F %F l ', $xT, $yT);
6661  $s .= 'S ';
6662  } elseif (strpos($border,'T') !== false) { // T
6663  $s .= sprintf('%F %F m ', $xT, $yT);
6664  $s .= sprintf('%F %F l ', $xR, $yR);
6665  $s .= 'S ';
6666  } elseif (strpos($border,'R') !== false) { // R
6667  $s .= sprintf('%F %F m ', $xR, $yR);
6668  $s .= sprintf('%F %F l ', $xB, $yB);
6669  $s .= 'S ';
6670  } elseif (strpos($border,'B') !== false) { // B
6671  $s .= sprintf('%F %F m ', $xB, $yB);
6672  $s .= sprintf('%F %F l ', $xL, $yL);
6673  $s .= 'S ';
6674  }
6675  }
6676  if (is_array($style) AND !empty($style)) {
6677  // reset border style to previous value
6678  $s .= "\n".$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor."\n";
6679  }
6680  }
6681  return $s;
6682  }
6683 
6709  public function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0, $valign='T', $fitcell=false) {
6710  $prev_cell_margin = $this->cell_margin;
6711  $prev_cell_padding = $this->cell_padding;
6712  // adjust internal padding
6713  $this->adjustCellPadding($border);
6714  $mc_padding = $this->cell_padding;
6715  $mc_margin = $this->cell_margin;
6716  $this->cell_padding['T'] = 0;
6717  $this->cell_padding['B'] = 0;
6718  $this->setCellMargins(0, 0, 0, 0);
6719  if ($this->empty_string($this->lasth) OR $reseth) {
6720  // reset row height
6721  $this->resetLastH();
6722  }
6723  if (!$this->empty_string($y)) {
6724  $this->SetY($y);
6725  } else {
6726  $y = $this->GetY();
6727  }
6728  $resth = 0;
6729  if (($h > 0) AND $this->inPageBody() AND (($y + $h + $mc_margin['T'] + $mc_margin['B']) > $this->PageBreakTrigger)) {
6730  // spit cell in more pages/columns
6731  $newh = ($this->PageBreakTrigger - $y);
6732  $resth = ($h - $newh); // cell to be printed on the next page/column
6733  $h = $newh;
6734  }
6735  // get current page number
6736  $startpage = $this->page;
6737  // get current column
6738  $startcolumn = $this->current_column;
6739  if (!$this->empty_string($x)) {
6740  $this->SetX($x);
6741  } else {
6742  $x = $this->GetX();
6743  }
6744  // check page for no-write regions and adapt page margins if necessary
6745  list($x, $y) = $this->checkPageRegions(0, $x, $y);
6746  // apply margins
6747  $oy = $y + $mc_margin['T'];
6748  if ($this->rtl) {
6749  $ox = ($this->w - $x - $mc_margin['R']);
6750  } else {
6751  $ox = ($x + $mc_margin['L']);
6752  }
6753  $this->x = $ox;
6754  $this->y = $oy;
6755  // set width
6756  if ($this->empty_string($w) OR ($w <= 0)) {
6757  if ($this->rtl) {
6758  $w = ($this->x - $this->lMargin - $mc_margin['L']);
6759  } else {
6760  $w = ($this->w - $this->x - $this->rMargin - $mc_margin['R']);
6761  }
6762  }
6763  // store original margin values
6766  if ($this->rtl) {
6767  $this->rMargin = ($this->w - $this->x);
6768  $this->lMargin = ($this->x - $w);
6769  } else {
6770  $this->lMargin = ($this->x);
6771  $this->rMargin = ($this->w - $this->x - $w);
6772  }
6773  $this->clMargin = $this->lMargin;
6774  $this->crMargin = $this->rMargin;
6775  if ($autopadding) {
6776  // add top padding
6777  $this->y += $mc_padding['T'];
6778  }
6779  if ($ishtml) { // ******* Write HTML text
6780  $this->writeHTML($txt, true, false, $reseth, true, $align);
6781  $nl = 1;
6782  } else { // ******* Write simple text
6783  $prev_FontSizePt = $this->FontSizePt;
6784  // vertical alignment
6785  if ($maxh > 0) {
6786  // get text height
6787  $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border);
6788  if ($fitcell) {
6789  // try to reduce font size to fit text on cell (use a quick search algorithm)
6790  $fmin = 1;
6791  $fmax = $this->FontSizePt;
6792  $prev_text_height = $text_height;
6793  $maxit = 100; // max number of iterations
6794  while ($maxit > 0) {
6795  $fmid = (($fmax + $fmin) / 2);
6796  $this->SetFontSize($fmid, false);
6797  $this->resetLastH();
6798  $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border);
6799  if (($text_height == $maxh) OR (($text_height < $maxh) AND ($fmin >= ($fmax - 0.01)))) {
6800  break;
6801  } elseif ($text_height < $maxh) {
6802  $fmin = $fmid;
6803  } else {
6804  $fmax = $fmid;
6805  }
6806  --$maxit;
6807  }
6808  $this->SetFontSize($this->FontSizePt);
6809  }
6810  if ($text_height < $maxh) {
6811  if ($valign == 'M') {
6812  // text vertically centered
6813  $this->y += (($maxh - $text_height) / 2);
6814  } elseif ($valign == 'B') {
6815  // text vertically aligned on bottom
6816  $this->y += ($maxh - $text_height);
6817  }
6818  }
6819  }
6820  $nl = $this->Write($this->lasth, $txt, '', 0, $align, true, $stretch, false, true, $maxh, 0, $mc_margin);
6821  if ($fitcell) {
6822  // restore font size
6823  $this->SetFontSize($prev_FontSizePt);
6824  }
6825  }
6826  if ($autopadding) {
6827  // add bottom padding
6828  $this->y += $mc_padding['B'];
6829  }
6830  // Get end-of-text Y position
6831  $currentY = $this->y;
6832  // get latest page number
6833  $endpage = $this->page;
6834  if ($resth > 0) {
6835  $skip = ($endpage - $startpage);
6836  $tmpresth = $resth;
6837  while ($tmpresth > 0) {
6838  if ($skip <= 0) {
6839  // add a page (or trig AcceptPageBreak() for multicolumn mode)
6840  $this->checkPageBreak($this->PageBreakTrigger + 1);
6841  }
6842  if ($this->num_columns > 1) {
6843  $tmpresth -= ($this->h - $this->y - $this->bMargin);
6844  } else {
6845  $tmpresth -= ($this->h - $this->tMargin - $this->bMargin);
6846  }
6847  --$skip;
6848  }
6849  $currentY = $this->y;
6850  $endpage = $this->page;
6851  }
6852  // get latest column
6853  $endcolumn = $this->current_column;
6854  if ($this->num_columns == 0) {
6855  $this->num_columns = 1;
6856  }
6857  // disable page regions check
6859  $this->check_page_regions = false;
6860  // get border modes
6861  $border_start = $this->getBorderMode($border, $position='start');
6862  $border_end = $this->getBorderMode($border, $position='end');
6863  $border_middle = $this->getBorderMode($border, $position='middle');
6864  // design borders around HTML cells.
6865  for ($page = $startpage; $page <= $endpage; ++$page) { // for each page
6866  $ccode = '';
6867  $this->setPage($page);
6868  if ($this->num_columns < 2) {
6869  // single-column mode
6870  $this->SetX($x);
6871  $this->y = $this->tMargin;
6872  }
6873  // account for margin changes
6874  if ($page > $startpage) {
6875  if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) {
6876  $this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']);
6877  } elseif ((!$this->rtl) AND ($this->pagedim[$page]['olm'] != $this->pagedim[$startpage]['olm'])) {
6878  $this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']);
6879  }
6880  }
6881  if ($startpage == $endpage) {
6882  // single page
6883  for ($column = $startcolumn; $column <= $endcolumn; ++$column) { // for each column
6884  $this->selectColumn($column);
6885  if ($this->rtl) {
6886  $this->x -= $mc_margin['R'];
6887  } else {
6888  $this->x += $mc_margin['L'];
6889  }
6890  if ($startcolumn == $endcolumn) { // single column
6891  $cborder = $border;
6892  $h = max($h, ($currentY - $oy));
6893  $this->y = $oy;
6894  } elseif ($column == $startcolumn) { // first column
6895  $cborder = $border_start;
6896  $this->y = $oy;
6897  $h = $this->h - $this->y - $this->bMargin;
6898  } elseif ($column == $endcolumn) { // end column
6899  $cborder = $border_end;
6900  $h = $currentY - $this->y;
6901  if ($resth > $h) {
6902  $h = $resth;
6903  }
6904  } else { // middle column
6905  $cborder = $border_middle;
6906  $h = $this->h - $this->y - $this->bMargin;
6907  $resth -= $h;
6908  }
6909  $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6910  } // end for each column
6911  } elseif ($page == $startpage) { // first page
6912  for ($column = $startcolumn; $column < $this->num_columns; ++$column) { // for each column
6913  $this->selectColumn($column);
6914  if ($this->rtl) {
6915  $this->x -= $mc_margin['R'];
6916  } else {
6917  $this->x += $mc_margin['L'];
6918  }
6919  if ($column == $startcolumn) { // first column
6920  $cborder = $border_start;
6921  $this->y = $oy;
6922  $h = $this->h - $this->y - $this->bMargin;
6923  } else { // middle column
6924  $cborder = $border_middle;
6925  $h = $this->h - $this->y - $this->bMargin;
6926  $resth -= $h;
6927  }
6928  $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6929  } // end for each column
6930  } elseif ($page == $endpage) { // last page
6931  for ($column = 0; $column <= $endcolumn; ++$column) { // for each column
6932  $this->selectColumn($column);
6933  if ($this->rtl) {
6934  $this->x -= $mc_margin['R'];
6935  } else {
6936  $this->x += $mc_margin['L'];
6937  }
6938  if ($column == $endcolumn) {
6939  // end column
6940  $cborder = $border_end;
6941  $h = $currentY - $this->y;
6942  if ($resth > $h) {
6943  $h = $resth;
6944  }
6945  } else {
6946  // middle column
6947  $cborder = $border_middle;
6948  $h = $this->h - $this->y - $this->bMargin;
6949  $resth -= $h;
6950  }
6951  $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6952  } // end for each column
6953  } else { // middle page
6954  for ($column = 0; $column < $this->num_columns; ++$column) { // for each column
6955  $this->selectColumn($column);
6956  if ($this->rtl) {
6957  $this->x -= $mc_margin['R'];
6958  } else {
6959  $this->x += $mc_margin['L'];
6960  }
6961  $cborder = $border_middle;
6962  $h = $this->h - $this->y - $this->bMargin;
6963  $resth -= $h;
6964  $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6965  } // end for each column
6966  }
6967  if ($cborder OR $fill) {
6968  $offsetlen = strlen($ccode);
6969  // draw border and fill
6970  if ($this->inxobj) {
6971  // we are inside an XObject template
6972  if (end($this->xobjects[$this->xobjid]['transfmrk']) !== false) {
6973  $pagemarkkey = key($this->xobjects[$this->xobjid]['transfmrk']);
6974  $pagemark = $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey];
6975  $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey] += $offsetlen;
6976  } else {
6977  $pagemark = $this->xobjects[$this->xobjid]['intmrk'];
6978  $this->xobjects[$this->xobjid]['intmrk'] += $offsetlen;
6979  }
6980  $pagebuff = $this->xobjects[$this->xobjid]['outdata'];
6981  $pstart = substr($pagebuff, 0, $pagemark);
6982  $pend = substr($pagebuff, $pagemark);
6983  $this->xobjects[$this->xobjid]['outdata'] = $pstart.$ccode.$pend;
6984  } else {
6985  if (end($this->transfmrk[$this->page]) !== false) {
6986  $pagemarkkey = key($this->transfmrk[$this->page]);
6987  $pagemark = $this->transfmrk[$this->page][$pagemarkkey];
6988  $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen;
6989  } elseif ($this->InFooter) {
6990  $pagemark = $this->footerpos[$this->page];
6991  $this->footerpos[$this->page] += $offsetlen;
6992  } else {
6993  $pagemark = $this->intmrk[$this->page];
6994  $this->intmrk[$this->page] += $offsetlen;
6995  }
6996  $pagebuff = $this->getPageBuffer($this->page);
6997  $pstart = substr($pagebuff, 0, $pagemark);
6998  $pend = substr($pagebuff, $pagemark);
6999  $this->setPageBuffer($this->page, $pstart.$ccode.$pend);
7000  }
7001  }
7002  } // end for each page
7003  // restore page regions check
7004  $this->check_page_regions = $check_page_regions;
7005  // Get end-of-cell Y position
7006  $currentY = $this->GetY();
7007  // restore previous values
7008  if ($this->num_columns > 1) {
7009  $this->selectColumn();
7010  } else {
7011  // restore original margins
7012  $this->lMargin = $lMargin;
7013  $this->rMargin = $rMargin;
7014  if ($this->page > $startpage) {
7015  // check for margin variations between pages (i.e. booklet mode)
7016  $dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$startpage]['olm']);
7017  $dr = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$startpage]['orm']);
7018  if (($dl != 0) OR ($dr != 0)) {
7019  $this->lMargin += $dl;
7020  $this->rMargin += $dr;
7021  }
7022  }
7023  }
7024  if ($ln > 0) {
7025  //Go to the beginning of the next line
7026  $this->SetY($currentY + $mc_margin['B']);
7027  if ($ln == 2) {
7028  $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']);
7029  }
7030  } else {
7031  // go left or right by case
7032  $this->setPage($startpage);
7033  $this->y = $y;
7034  $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']);
7035  }
7036  $this->setContentMark();
7037  $this->cell_padding = $prev_cell_padding;
7038  $this->cell_margin = $prev_cell_margin;
7039  $this->clMargin = $this->lMargin;
7040  $this->crMargin = $this->rMargin;
7041  return $nl;
7042  }
7043 
7052  protected function getBorderMode($brd, $position='start') {
7053  if ((!$this->opencell) OR empty($brd)) {
7054  return $brd;
7055  }
7056  if ($brd == 1) {
7057  $brd = 'LTRB';
7058  }
7059  if (is_string($brd)) {
7060  // convert string to array
7061  $slen = strlen($brd);
7062  $newbrd = array();
7063  for ($i = 0; $i < $slen; ++$i) {
7064  $newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter');
7065  }
7066  $brd = $newbrd;
7067  }
7068  foreach ($brd as $border => $style) {
7069  switch ($position) {
7070  case 'start': {
7071  if (strpos($border, 'B') !== false) {
7072  // remove bottom line
7073  $newkey = str_replace('B', '', $border);
7074  if (strlen($newkey) > 0) {
7075  $brd[$newkey] = $style;
7076  }
7077  unset($brd[$border]);
7078  }
7079  break;
7080  }
7081  case 'middle': {
7082  if (strpos($border, 'B') !== false) {
7083  // remove bottom line
7084  $newkey = str_replace('B', '', $border);
7085  if (strlen($newkey) > 0) {
7086  $brd[$newkey] = $style;
7087  }
7088  unset($brd[$border]);
7089  $border = $newkey;
7090  }
7091  if (strpos($border, 'T') !== false) {
7092  // remove bottom line
7093  $newkey = str_replace('T', '', $border);
7094  if (strlen($newkey) > 0) {
7095  $brd[$newkey] = $style;
7096  }
7097  unset($brd[$border]);
7098  }
7099  break;
7100  }
7101  case 'end': {
7102  if (strpos($border, 'T') !== false) {
7103  // remove bottom line
7104  $newkey = str_replace('T', '', $border);
7105  if (strlen($newkey) > 0) {
7106  $brd[$newkey] = $style;
7107  }
7108  unset($brd[$border]);
7109  }
7110  break;
7111  }
7112  }
7113  }
7114  return $brd;
7115  }
7116 
7130  public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
7131  if ($txt === '') {
7132  // empty string
7133  return 1;
7134  }
7135  // adjust internal padding
7136  $prev_cell_padding = $this->cell_padding;
7137  $prev_lasth = $this->lasth;
7138  if (is_array($cellpadding)) {
7139  $this->cell_padding = $cellpadding;
7140  }
7141  $this->adjustCellPadding($border);
7142  if ($this->empty_string($w) OR ($w <= 0)) {
7143  if ($this->rtl) {
7144  $w = $this->x - $this->lMargin;
7145  } else {
7146  $w = $this->w - $this->rMargin - $this->x;
7147  }
7148  }
7149  $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
7150  if ($reseth) {
7151  // reset row height
7152  $this->resetLastH();
7153  }
7154  $lines = 1;
7155  $sum = 0;
7156  $chars = $this->utf8Bidi($this->UTF8StringToArray($txt), $txt, $this->tmprtl);
7157  $charsWidth = $this->GetArrStringWidth($chars, '', '', 0, true);
7158  $length = count($chars);
7159  $lastSeparator = -1;
7160  for ($i = 0; $i < $length; ++$i) {
7161  $charWidth = $charsWidth[$i];
7162  if (preg_match($this->re_spaces, $this->unichr($chars[$i]))) {
7163  $lastSeparator = $i;
7164  }
7165  if ((($sum + $charWidth) > $wmax) OR ($chars[$i] == 10)) {
7166  ++$lines;
7167  if ($chars[$i] == 10) {
7168  $lastSeparator = -1;
7169  $sum = 0;
7170  } elseif ($lastSeparator != -1) {
7171  $i = $lastSeparator;
7172  $lastSeparator = -1;
7173  $sum = 0;
7174  } else {
7175  $sum = $charWidth;
7176  }
7177  } else {
7178  $sum += $charWidth;
7179  }
7180  }
7181  if ($chars[($length - 1)] == 10) {
7182  --$lines;
7183  }
7184  $this->cell_padding = $prev_cell_padding;
7185  $this->lasth = $prev_lasth;
7186  return $lines;
7187  }
7188 
7236  public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
7237  // adjust internal padding
7238  $prev_cell_padding = $this->cell_padding;
7239  $prev_lasth = $this->lasth;
7240  if (is_array($cellpadding)) {
7241  $this->cell_padding = $cellpadding;
7242  }
7243  $this->adjustCellPadding($border);
7244  $lines = $this->getNumLines($txt, $w, $reseth, $autopadding, $cellpadding, $border);
7245  $height = $lines * ($this->FontSize * $this->cell_height_ratio);
7246  if ($autopadding) {
7247  // add top and bottom padding
7248  $height += ($this->cell_padding['T'] + $this->cell_padding['B']);
7249  }
7250  $this->cell_padding = $prev_cell_padding;
7251  $this->lasth = $prev_lasth;
7252  return $height;
7253  }
7254 
7273  public function Write($h, $txt, $link='', $fill=false, $align='', $ln=false, $stretch=0, $firstline=false, $firstblock=false, $maxh=0, $wadj=0, $margin='') {
7274  // check page for no-write regions and adapt page margins if necessary
7275  list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y);
7276  if (strlen($txt) == 0) {
7277  // fix empty text
7278  $txt = ' ';
7279  }
7280  if ($margin === '') {
7281  // set default margins
7282  $margin = $this->cell_margin;
7283  }
7284  // remove carriage returns
7285  $s = str_replace("\r", '', $txt);
7286  // check if string contains arabic text
7287  if (preg_match($this->unicode->uni_RE_PATTERN_ARABIC, $s)) {
7288  $arabic = true;
7289  } else {
7290  $arabic = false;
7291  }
7292  // check if string contains RTL text
7293  if ($arabic OR ($this->tmprtl == 'R') OR preg_match($this->unicode->uni_RE_PATTERN_RTL, $s)) {
7294  $rtlmode = true;
7295  } else {
7296  $rtlmode = false;
7297  }
7298  // get a char width
7299  $chrwidth = $this->GetCharWidth(46); // dot character
7300  // get array of unicode values
7301  $chars = $this->UTF8StringToArray($s);
7302  // calculate maximum width for a single character on string
7303  $chrw = $this->GetArrStringWidth($chars, '', '', 0, true);
7304  array_walk($chrw, array($this, 'getRawCharWidth'));
7305  $maxchwidth = max($chrw);
7306  // get array of chars
7307  $uchars = $this->UTF8ArrayToUniArray($chars);
7308  // get the number of characters
7309  $nb = count($chars);
7310  // replacement for SHY character (minus symbol)
7311  $shy_replacement = 45;
7312  $shy_replacement_char = $this->unichr($shy_replacement);
7313  // widht for SHY replacement
7314  $shy_replacement_width = $this->GetCharWidth($shy_replacement);
7315  // max Y
7316  $maxy = $this->y + $maxh - $h - $this->cell_padding['T'] - $this->cell_padding['B'];
7317  // page width
7318  $pw = $w = $this->w - $this->lMargin - $this->rMargin;
7319  // calculate remaining line width ($w)
7320  if ($this->rtl) {
7321  $w = $this->x - $this->lMargin;
7322  } else {
7323  $w = $this->w - $this->rMargin - $this->x;
7324  }
7325  // max column width
7326  $wmax = ($w - $wadj);
7327  if (!$firstline) {
7328  $wmax -= ($this->cell_padding['L'] + $this->cell_padding['R']);
7329  }
7330  if ((!$firstline) AND (($chrwidth > $wmax) OR ($maxchwidth > $wmax))) {
7331  // the maximum width character do not fit on column
7332  return '';
7333  }
7334  // minimum row height
7335  $row_height = max($h, $this->FontSize * $this->cell_height_ratio);
7336  $start_page = $this->page;
7337  $i = 0; // character position
7338  $j = 0; // current starting position
7339  $sep = -1; // position of the last blank space
7340  $shy = false; // true if the last blank is a soft hypen (SHY)
7341  $l = 0; // current string length
7342  $nl = 0; //number of lines
7343  $linebreak = false;
7344  $pc = 0; // previous character
7345  // for each character
7346  while ($i < $nb) {
7347  if (($maxh > 0) AND ($this->y >= $maxy) ) {
7348  break;
7349  }
7350  //Get the current character
7351  $c = $chars[$i];
7352  if ($c == 10) { // 10 = "\n" = new line
7353  //Explicit line break
7354  if ($align == 'J') {
7355  if ($this->rtl) {
7356  $talign = 'R';
7357  } else {
7358  $talign = 'L';
7359  }
7360  } else {
7361  $talign = $align;
7362  }
7363  $tmpstr = $this->UniArrSubString($uchars, $j, $i);
7364  if ($firstline) {
7365  $startx = $this->x;
7366  $tmparr = array_slice($chars, $j, ($i - $j));
7367  if ($rtlmode) {
7368  $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl);
7369  }
7370  $linew = $this->GetArrStringWidth($tmparr);
7371  unset($tmparr);
7372  if ($this->rtl) {
7373  $this->endlinex = $startx - $linew;
7374  } else {
7375  $this->endlinex = $startx + $linew;
7376  }
7377  $w = $linew;
7378  $tmpcellpadding = $this->cell_padding;
7379  if ($maxh == 0) {
7380  $this->SetCellPadding(0);
7381  }
7382  }
7383  if ($firstblock AND $this->isRTLTextDir()) {
7384  $tmpstr = $this->stringRightTrim($tmpstr);
7385  }
7386  // Skip newlines at the begining of a page or column
7387  if (!empty($tmpstr) OR ($this->y < ($this->PageBreakTrigger - $row_height))) {
7388  $this->Cell($w, $h, $tmpstr, 0, 1, $talign, $fill, $link, $stretch);
7389  }
7390  unset($tmpstr);
7391  if ($firstline) {
7392  $this->cell_padding = $tmpcellpadding;
7393  return ($this->UniArrSubString($uchars, $i));
7394  }
7395  ++$nl;
7396  $j = $i + 1;
7397  $l = 0;
7398  $sep = -1;
7399  $shy = false;
7400  // account for margin changes
7401  if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) {
7402  $this->AcceptPageBreak();
7403  if ($this->rtl) {
7404  $this->x -= $margin['R'];
7405  } else {
7406  $this->x += $margin['L'];
7407  }
7408  $this->lMargin += $margin['L'];
7409  $this->rMargin += $margin['R'];
7410  }
7411  $w = $this->getRemainingWidth();
7412  $wmax = ($w - $this->cell_padding['L'] - $this->cell_padding['R']);
7413  } else {
7414  // 160 is the non-breaking space.
7415  // 173 is SHY (Soft Hypen).
7416  // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator.
7417  // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants.
7418  // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between.
7419  if (($c != 160)
7420  AND (($c == 173)
7421  OR preg_match($this->re_spaces, $this->unichr($c))
7422  OR (($c == 45)
7423  AND ($i < ($nb - 1))
7424  AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($pc))
7425  AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($chars[($i + 1)]))
7426  )
7427  )
7428  ) {
7429  // update last blank space position
7430  $sep = $i;
7431  // check if is a SHY
7432  if (($c == 173) OR ($c == 45)) {
7433  $shy = true;
7434  if ($pc == 45) {
7435  $tmp_shy_replacement_width = 0;
7436  $tmp_shy_replacement_char = '';
7437  } else {
7438  $tmp_shy_replacement_width = $shy_replacement_width;
7439  $tmp_shy_replacement_char = $shy_replacement_char;
7440  }
7441  } else {
7442  $shy = false;
7443  }
7444  }
7445  // update string length
7446  if ($this->isUnicodeFont() AND ($arabic)) {
7447  // with bidirectional algorithm some chars may be changed affecting the line length
7448  // *** very slow ***
7449  $l = $this->GetArrStringWidth($this->utf8Bidi(array_slice($chars, $j, ($i - $j)), '', $this->tmprtl));
7450  } else {
7451  $l += $this->GetCharWidth($c);
7452  }
7453  if (($l > $wmax) OR (($c == 173) AND (($l + $tmp_shy_replacement_width) > $wmax)) ) {
7454  // we have reached the end of column
7455  if ($sep == -1) {
7456  // check if the line was already started
7457  if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $this->cell_padding['R'] - $margin['R'] - $chrwidth)))
7458  OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $this->cell_padding['L'] + $margin['L'] + $chrwidth)))) {
7459  // print a void cell and go to next line
7460  $this->Cell($w, $h, '', 0, 1);
7461  $linebreak = true;
7462  if ($firstline) {
7463  return ($this->UniArrSubString($uchars, $j));
7464  }
7465  } else {
7466  // truncate the word because do not fit on column
7467  $tmpstr = $this->UniArrSubString($uchars, $j, $i);
7468  if ($firstline) {
7469  $startx = $this->x;
7470  $tmparr = array_slice($chars, $j, ($i - $j));
7471  if ($rtlmode) {
7472  $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl);
7473  }
7474  $linew = $this->GetArrStringWidth($tmparr);
7475  unset($tmparr);
7476  if ($this->rtl) {
7477  $this->endlinex = $startx - $linew;
7478  } else {
7479  $this->endlinex = $startx + $linew;
7480  }
7481  $w = $linew;
7482  $tmpcellpadding = $this->cell_padding;
7483  if ($maxh == 0) {
7484  $this->SetCellPadding(0);
7485  }
7486  }
7487  if ($firstblock AND $this->isRTLTextDir()) {
7488  $tmpstr = $this->stringRightTrim($tmpstr);
7489  }
7490  $this->Cell($w, $h, $tmpstr, 0, 1, $align, $fill, $link, $stretch);
7491  unset($tmpstr);
7492  if ($firstline) {
7493  $this->cell_padding = $tmpcellpadding;
7494  return ($this->UniArrSubString($uchars, $i));
7495  }
7496  $j = $i;
7497  --$i;
7498  }
7499  } else {
7500  // word wrapping
7501  if ($this->rtl AND (!$firstblock) AND ($sep < $i)) {
7502  $endspace = 1;
7503  } else {
7504  $endspace = 0;
7505  }
7506  // check the length of the next string
7507  $strrest = $this->UniArrSubString($uchars, ($sep + $endspace));
7508  $nextstr = preg_split('/'.$this->re_space['p'].'/'.$this->re_space['m'], $this->stringTrim($strrest));
7509  if (isset($nextstr[0]) AND ($this->GetStringWidth($nextstr[0]) > $pw)) {
7510  // truncate the word because do not fit on a full page width
7511  $tmpstr = $this->UniArrSubString($uchars, $j, $i);
7512  if ($firstline) {
7513  $startx = $this->x;
7514  $tmparr = array_slice($chars, $j, ($i - $j));
7515  if ($rtlmode) {
7516  $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl);
7517  }
7518  $linew = $this->GetArrStringWidth($tmparr);
7519  unset($tmparr);
7520  if ($this->rtl) {
7521  $this->endlinex = ($startx - $linew);
7522  } else {
7523  $this->endlinex = ($startx + $linew);
7524  }
7525  $w = $linew;
7526  $tmpcellpadding = $this->cell_padding;
7527  if ($maxh == 0) {
7528  $this->SetCellPadding(0);
7529  }
7530  }
7531  if ($firstblock AND $this->isRTLTextDir()) {
7532  $tmpstr = $this->stringRightTrim($tmpstr);
7533  }
7534  $this->Cell($w, $h, $tmpstr, 0, 1, $align, $fill, $link, $stretch);
7535  unset($tmpstr);
7536  if ($firstline) {
7537  $this->cell_padding = $tmpcellpadding;
7538  return ($this->UniArrSubString($uchars, $i));
7539  }
7540  $j = $i;
7541  --$i;
7542  } else {
7543  // word wrapping
7544  if ($shy) {
7545  // add hypen (minus symbol) at the end of the line
7546  $shy_width = $tmp_shy_replacement_width;
7547  if ($this->rtl) {
7548  $shy_char_left = $tmp_shy_replacement_char;
7549  $shy_char_right = '';
7550  } else {
7551  $shy_char_left = '';
7552  $shy_char_right = $tmp_shy_replacement_char;
7553  }
7554  } else {
7555  $shy_width = 0;
7556  $shy_char_left = '';
7557  $shy_char_right = '';
7558  }
7559  $tmpstr = $this->UniArrSubString($uchars, $j, ($sep + $endspace));
7560  if ($firstline) {
7561  $startx = $this->x;
7562  $tmparr = array_slice($chars, $j, (($sep + $endspace) - $j));
7563  if ($rtlmode) {
7564  $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl);
7565  }
7566  $linew = $this->GetArrStringWidth($tmparr);
7567  unset($tmparr);
7568  if ($this->rtl) {
7569  $this->endlinex = $startx - $linew - $shy_width;
7570  } else {
7571  $this->endlinex = $startx + $linew + $shy_width;
7572  }
7573  $w = $linew;
7574  $tmpcellpadding = $this->cell_padding;
7575  if ($maxh == 0) {
7576  $this->SetCellPadding(0);
7577  }
7578  }
7579  // print the line
7580  if ($firstblock AND $this->isRTLTextDir()) {
7581  $tmpstr = $this->stringRightTrim($tmpstr);
7582  }
7583  $this->Cell($w, $h, $shy_char_left.$tmpstr.$shy_char_right, 0, 1, $align, $fill, $link, $stretch);
7584  unset($tmpstr);
7585  if ($firstline) {
7586  if ($chars[$sep] == 45) {
7587  $endspace += 1;
7588  }
7589  // return the remaining text
7590  $this->cell_padding = $tmpcellpadding;
7591  return ($this->UniArrSubString($uchars, ($sep + $endspace)));
7592  }
7593  $i = $sep;
7594  $sep = -1;
7595  $shy = false;
7596  $j = ($i + 1);
7597  }
7598  }
7599  // account for margin changes
7600  if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) {
7601  $this->AcceptPageBreak();
7602  if ($this->rtl) {
7603  $this->x -= $margin['R'];
7604  } else {
7605  $this->x += $margin['L'];
7606  }
7607  $this->lMargin += $margin['L'];
7608  $this->rMargin += $margin['R'];
7609  }
7610  $w = $this->getRemainingWidth();
7611  $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
7612  if ($linebreak) {
7613  $linebreak = false;
7614  } else {
7615  ++$nl;
7616  $l = 0;
7617  }
7618  }
7619  }
7620  // save last character
7621  $pc = $c;
7622  ++$i;
7623  } // end while i < nb
7624  // print last substring (if any)
7625  if ($l > 0) {
7626  switch ($align) {
7627  case 'J':
7628  case 'C': {
7629  $w = $w;
7630  break;
7631  }
7632  case 'L': {
7633  if ($this->rtl) {
7634  $w = $w;
7635  } else {
7636  $w = $l;
7637  }
7638  break;
7639  }
7640  case 'R': {
7641  if ($this->rtl) {
7642  $w = $l;
7643  } else {
7644  $w = $w;
7645  }
7646  break;
7647  }
7648  default: {
7649  $w = $l;
7650  break;
7651  }
7652  }
7653  $tmpstr = $this->UniArrSubString($uchars, $j, $nb);
7654  if ($firstline) {
7655  $startx = $this->x;
7656  $tmparr = array_slice($chars, $j, ($nb - $j));
7657  if ($rtlmode) {
7658  $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl);
7659  }
7660  $linew = $this->GetArrStringWidth($tmparr);
7661  unset($tmparr);
7662  if ($this->rtl) {
7663  $this->endlinex = $startx - $linew;
7664  } else {
7665  $this->endlinex = $startx + $linew;
7666  }
7667  $w = $linew;
7668  $tmpcellpadding = $this->cell_padding;
7669  if ($maxh == 0) {
7670  $this->SetCellPadding(0);
7671  }
7672  }
7673  if ($firstblock AND $this->isRTLTextDir()) {
7674  $tmpstr = $this->stringRightTrim($tmpstr);
7675  }
7676  $this->Cell($w, $h, $tmpstr, 0, $ln, $align, $fill, $link, $stretch);
7677  unset($tmpstr);
7678  if ($firstline) {
7679  $this->cell_padding = $tmpcellpadding;
7680  return ($this->UniArrSubString($uchars, $nb));
7681  }
7682  ++$nl;
7683  }
7684  if ($firstline) {
7685  return '';
7686  }
7687  return $nl;
7688  }
7689 
7695  protected function getRemainingWidth() {
7696  list($this->x, $this->y) = $this->checkPageRegions(0, $this->x, $this->y);
7697  if ($this->rtl) {
7698  return ($this->x - $this->lMargin);
7699  } else {
7700  return ($this->w - $this->rMargin - $this->x);
7701  }
7702  }
7703 
7712  public function UTF8ArrSubString($strarr, $start='', $end='') {
7713  if (strlen($start) == 0) {
7714  $start = 0;
7715  }
7716  if (strlen($end) == 0) {
7717  $end = count($strarr);
7718  }
7719  $string = '';
7720  for ($i=$start; $i < $end; ++$i) {
7721  $string .= $this->unichr($strarr[$i]);
7722  }
7723  return $string;
7724  }
7725 
7735  public function UniArrSubString($uniarr, $start='', $end='') {
7736  if (strlen($start) == 0) {
7737  $start = 0;
7738  }
7739  if (strlen($end) == 0) {
7740  $end = count($uniarr);
7741  }
7742  $string = '';
7743  for ($i=$start; $i < $end; ++$i) {
7744  $string .= $uniarr[$i];
7745  }
7746  return $string;
7747  }
7748 
7756  public function UTF8ArrayToUniArray($ta) {
7757  return array_map(array($this, 'unichr'), $ta);
7758  }
7759 
7768  public function unichr($c) {
7769  if (!$this->isunicode) {
7770  return chr($c);
7771  } elseif ($c <= 0x7F) {
7772  // one byte
7773  return chr($c);
7774  } elseif ($c <= 0x7FF) {
7775  // two bytes
7776  return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
7777  } elseif ($c <= 0xFFFF) {
7778  // three bytes
7779  return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
7780  } elseif ($c <= 0x10FFFF) {
7781  // four bytes
7782  return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
7783  } else {
7784  return '';
7785  }
7786  }
7787 
7795  public function getImageFileType($imgfile, $iminfo=array()) {
7796  $type = '';
7797  if (isset($iminfo['mime']) AND !empty($iminfo['mime'])) {
7798  $mime = explode('/', $iminfo['mime']);
7799  if ((count($mime) > 1) AND ($mime[0] == 'image') AND (!empty($mime[1]))) {
7800  $type = strtolower(trim($mime[1]));
7801  }
7802  }
7803  if (empty($type)) {
7804  $fileinfo = pathinfo($imgfile);
7805  if (isset($fileinfo['extension']) AND (!$this->empty_string($fileinfo['extension']))) {
7806  $type = strtolower(trim($fileinfo['extension']));
7807  }
7808  }
7809  if ($type == 'jpg') {
7810  $type = 'jpeg';
7811  }
7812  return $type;
7813  }
7814 
7826  protected function fitBlock($w, $h, $x, $y, $fitonpage=false) {
7827  if ($w <= 0) {
7828  // set maximum width
7829  $w = ($this->w - $this->lMargin - $this->rMargin);
7830  }
7831  if ($h <= 0) {
7832  // set maximum height
7833  $h = ($this->PageBreakTrigger - $this->tMargin);
7834  }
7835  // resize the block to be vertically contained on a single page or single column
7836  if ($fitonpage OR $this->AutoPageBreak) {
7837  $ratio_wh = ($w / $h);
7838  if ($h > ($this->PageBreakTrigger - $this->tMargin)) {
7839  $h = $this->PageBreakTrigger - $this->tMargin;
7840  $w = ($h * $ratio_wh);
7841  }
7842  // resize the block to be horizontally contained on a single page or single column
7843  if ($fitonpage) {
7844  $maxw = ($this->w - $this->lMargin - $this->rMargin);
7845  if ($w > $maxw) {
7846  $w = $maxw;
7847  $h = ($w / $ratio_wh);
7848  }
7849  }
7850  }
7851  // Check whether we need a new page or new column first as this does not fit
7852  $prev_x = $this->x;
7853  $prev_y = $this->y;
7854  if ($this->checkPageBreak($h, $y) OR ($this->y < $prev_y)) {
7855  $y = $this->y;
7856  if ($this->rtl) {
7857  $x += ($prev_x - $this->x);
7858  } else {
7859  $x += ($this->x - $prev_x);
7860  }
7861  $this->newline = true;
7862  }
7863  // resize the block to be contained on the remaining available page or column space
7864  if ($fitonpage) {
7865  $ratio_wh = ($w / $h);
7866  if (($y + $h) > $this->PageBreakTrigger) {
7867  $h = $this->PageBreakTrigger - $y;
7868  $w = ($h * $ratio_wh);
7869  }
7870  if ((!$this->rtl) AND (($x + $w) > ($this->w - $this->rMargin))) {
7871  $w = $this->w - $this->rMargin - $x;
7872  $h = ($w / $ratio_wh);
7873  } elseif (($this->rtl) AND (($x - $w) < ($this->lMargin))) {
7874  $w = $x - $this->lMargin;
7875  $h = ($w / $ratio_wh);
7876  }
7877  }
7878  return array($w, $h, $x, $y);
7879  }
7880 
7915  public function Image($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0, $fitbox=false, $hidden=false, $fitonpage=false, $alt=false, $altimgs=array()) {
7916  if ($this->state != 2) {
7917  return;
7918  }
7919  if ($x === '') {
7920  $x = $this->x;
7921  }
7922  if ($y === '') {
7923  $y = $this->y;
7924  }
7925  // check page for no-write regions and adapt page margins if necessary
7926  list($x, $y) = $this->checkPageRegions($h, $x, $y);
7927  $exurl = ''; // external streams
7928  // check if we are passing an image as file or string
7929  if ($file[0] === '@') {
7930  // image from string
7931  $imgdata = substr($file, 1);
7932  $file = $this->getObjFilename('img');
7933  $fp = fopen($file, 'w');
7934  fwrite($fp, $imgdata);
7935  fclose($fp);
7936  unset($imgdata);
7937  $imsize = @getimagesize($file);
7938  if ($imsize === FALSE) {
7939  unlink($file);
7940  } else {
7941  $this->cached_files[] = $file;
7942  }
7943  } else { // image file
7944  if ($file{0} === '*') {
7945  // image as external stream
7946  $file = substr($file, 1);
7947  $exurl = $file;
7948  }
7949  // check if is local file
7950  if (!@file_exists($file)) {
7951  // encode spaces on filename (file is probably an URL)
7952  $file = str_replace(' ', '%20', $file);
7953  }
7954  if (@file_exists($file)) {
7955  // get image dimensions
7956  $imsize = @getimagesize($file);
7957  } else {
7958  $imsize = false;
7959  }
7960  if ($imsize === FALSE) {
7961  if (function_exists('curl_init')) {
7962  // try to get remote file data using cURL
7963  $cs = curl_init(); // curl session
7964  curl_setopt($cs, CURLOPT_URL, $file);
7965  curl_setopt($cs, CURLOPT_BINARYTRANSFER, true);
7966  curl_setopt($cs, CURLOPT_FAILONERROR, true);
7967  curl_setopt($cs, CURLOPT_RETURNTRANSFER, true);
7968  if ((ini_get('open_basedir') == '') AND (!ini_get('safe_mode'))) {
7969  curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true);
7970  }
7971  curl_setopt($cs, CURLOPT_CONNECTTIMEOUT, 5);
7972  curl_setopt($cs, CURLOPT_TIMEOUT, 30);
7973  curl_setopt($cs, CURLOPT_SSL_VERIFYPEER, false);
7974  curl_setopt($cs, CURLOPT_SSL_VERIFYHOST, false);
7975  curl_setopt($cs, CURLOPT_USERAGENT, 'TCPDF');
7976  $imgdata = curl_exec($cs);
7977  curl_close($cs);
7978  if ($imgdata !== FALSE) {
7979  // copy image to cache
7980  $file = $this->getObjFilename('img');
7981  $fp = fopen($file, 'w');
7982  fwrite($fp, $imgdata);
7983  fclose($fp);
7984  unset($imgdata);
7985  $imsize = @getimagesize($file);
7986  if ($imsize === FALSE) {
7987  unlink($file);
7988  } else {
7989  $this->cached_files[] = $file;
7990  }
7991  }
7992  } elseif (($w > 0) AND ($h > 0)) {
7993  // get measures from specified data
7994  $pw = $this->getHTMLUnitToUnits($w, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
7995  $ph = $this->getHTMLUnitToUnits($h, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
7996  $imsize = array($pw, $ph);
7997  }
7998  }
7999  }
8000  if ($imsize === FALSE) {
8001  if (substr($file, 0, -34) == K_PATH_CACHE.'msk') { // mask file
8002  // get measures from specified data
8003  $pw = $this->getHTMLUnitToUnits($w, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
8004  $ph = $this->getHTMLUnitToUnits($h, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
8005  $imsize = array($pw, $ph);
8006  } else {
8007  $this->Error('[Image] Unable to get image: '.$file);
8008  }
8009  }
8010  // file hash
8011  $filehash = md5($this->file_id.$file);
8012  // get original image width and height in pixels
8013  list($pixw, $pixh) = $imsize;
8014  // calculate image width and height on document
8015  if (($w <= 0) AND ($h <= 0)) {
8016  // convert image size to document unit
8017  $w = $this->pixelsToUnits($pixw);
8018  $h = $this->pixelsToUnits($pixh);
8019  } elseif ($w <= 0) {
8020  $w = $h * $pixw / $pixh;
8021  } elseif ($h <= 0) {
8022  $h = $w * $pixh / $pixw;
8023  } elseif (($fitbox !== false) AND ($w > 0) AND ($h > 0)) {
8024  if (strlen($fitbox) !== 2) {
8025  // set default alignment
8026  $fitbox = '--';
8027  }
8028  // scale image dimensions proportionally to fit within the ($w, $h) box
8029  if ((($w * $pixh) / ($h * $pixw)) < 1) {
8030  // store current height
8031  $oldh = $h;
8032  // calculate new height
8033  $h = $w * $pixh / $pixw;
8034  // height difference
8035  $hdiff = ($oldh - $h);