From d6ed2191d7deae02a2c345ef585adcf93397d224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= Date: Sun, 2 Sep 2012 15:58:25 +0200 Subject: [PATCH] MDL-35188 import tcpdf 5.9.181 --- lib/tcpdf/2dbarcodes.php | 12 +- lib/tcpdf/CHANGELOG.TXT | 97 +++- lib/tcpdf/README.TXT | 6 +- lib/tcpdf/barcodes.php | 12 +- lib/tcpdf/composer.json | 38 ++ lib/tcpdf/config/tcpdf_config.php | 0 lib/tcpdf/qrcode.php | 22 +- lib/tcpdf/readme_moodle.txt | 4 +- lib/tcpdf/tcpdf.php | 734 +++++++++++++++++++++++------- lib/tcpdf/tcpdf_parser.php | 35 +- lib/thirdpartylibs.xml | 2 +- 11 files changed, 747 insertions(+), 215 deletions(-) create mode 100644 lib/tcpdf/composer.json mode change 100644 => 100755 lib/tcpdf/config/tcpdf_config.php diff --git a/lib/tcpdf/2dbarcodes.php b/lib/tcpdf/2dbarcodes.php index e04b3073ce1..6490dfa7eaf 100644 --- a/lib/tcpdf/2dbarcodes.php +++ b/lib/tcpdf/2dbarcodes.php @@ -1,9 +1,9 @@ barcode_array['bcode'][$r][$c] == 1) { // draw a single barcode cell if ($imagick) { - $bar->rectangle($x, $y, ($x + $w), ($y + $h)); + $bar->rectangle($x, $y, ($x + $w - 1), ($y + $h - 1)); } else { - imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); + imagefilledrectangle($png, $x, $y, ($x + $w - 1), ($y + $h - 1), $fgcol); } } $x += $w; diff --git a/lib/tcpdf/CHANGELOG.TXT b/lib/tcpdf/CHANGELOG.TXT index 23a14f9991d..3b87c8c356d 100644 --- a/lib/tcpdf/CHANGELOG.TXT +++ b/lib/tcpdf/CHANGELOG.TXT @@ -1,3 +1,98 @@ +5.9.181 (2012-08-31) + - composer.json file was added. + - Bug item #3563369 "Cached images are not unlinked some time" was fixed. + +5.9.180 (2012-08-22) + - Bug item #3560493 "Problems with nested cells in HTML" was fixed. + +5.9.179 (2012-08-04) + - SVG 'use' tag was fixed for 'circle' and 'ellipse' shift problem. + - Alpha status is now correctly stored and restored by getGraphicVars() and SetGraphicVars() methods. + +5.9.178 (2012-08-02) + - SVG 'use' tag was fixed for 'circle' and 'ellipse'. + +5.9.177 (2012-08-02) + - An additional control on annotations was fixed. + +5.9.176 (2012-07-25) + - A bug related to stroke width was fixed. + - A problem related to font spacing in HTML was fixed. + +5.9.175 (2012-07-25) + - The problem of missing letter on hyphen break was fixed. + +5.9.174 (2012-07-25) + - The problem of wrong filename when downloading PDF from an Android device was fixed. + - The method setHeaderData() was extended to set text and line color for header (see example n. 1). + - The method setFooterData() was added to set text and line color for footer (see example n. 1). + - The methods setTextShadow() and getTextShadow() were added to set text shadows (see example n. 1). + - The GetCharWidth() method was fixed for negative character spacing. + - A 'none' border mode is now correctly recognized. + - Break on hyphen problem was fixed. + +5.9.173 (2012-07-23) + - Some additional control wher added on barcode methods. + - The option CURLOPT_FOLLOWLOCATION on Image method is now disabled if PHP safe_mode is on or open_basedir is set. + - Method Bookmark() was extended to include X parameter. + - Method setDestination() was extended to include X parameter. + - A problem with Thai language was fixed. + +5.9.172 (2012-07-02) + - A PNG color profile issue was fixed. + +5.9.171 (2012-07-01) + - Some SVG rendering problems were fixed. + +5.9.170 (2012-06-27) + - Bug #3538227 "Numerous errors inserting shared images" was fixed. + +5.9.169 (2012-06-25) + - Some SVG rendering problems were fixed. + +5.9.168 (2012-06-22) + - Thai language rendering was fixed. + +5.9.167 (2012-06-22) + - Thai language rendering was fixed and improved. + - Method isCharDefined() was improved. + - Protected method replaceChar() was added. + - Font "kerning" word was corrected to "tracking". + +5.9.166 (2012-06-21) + - Array to string conversion on file_id creation was fixed. + - Thai language rendering was fixed (thanks to Atsawin Chaowanakritsanakul). + +5.9.165 (2012-06-07) + - Some HTML form related bugs were fixed. + +5.9.164 (2012-06-06) + - A bug introduced on the latest release was fixed. + +5.9.163 (2012-06-05) + - Method getGDgamma() was changed. + - Rendering performances of PNG images with alpha channel were improved. + +5.9.162 (2012-05-11) + - A bug related to long text on TD cells was fixed. + +5.9.161 (2012-05-09) + - A bug on XREF table was fixed (Bug ID: 3525051). + - Deprecated Imagick:clone was replaced. + - Method objclone() was fixed for PHP4. + +5.9.160 (2012-05-03) + - A bug on tcpdf_parser.php was fixed. + +5.9.159 (2012-04-30) + - Barcode classes were updated to fix PNG export Bug (ID: 3522291). + +5.9.158 (2012-04-22) + - Some SVG-related bugs were fixed. + +5.9.157 (2012-04-16) + - Some SVG-related bugs were fixed. + 5.9.156 (2012-04-10) - Bug item #3515885 "TOC and booklet: left and right page exchanged". - SetAutoPageBreak(false) now works also in multicolumn mode. @@ -567,7 +662,7 @@ - The problem of blank page for nobr table higher than a single page was fixed. 5.9.000 (2010-10-06) - - Support for text stretching and spacing (kerning) was added, see example n. 63 and methods setFontStretching(), getFontStretching(), setFontSpacing(), getFontSpacing(). + - Support for text stretching and spacing (tracking) was added, see example n. 63 and methods setFontStretching(), getFontStretching(), setFontSpacing(), getFontSpacing(). - Support for CSS properties 'font-stretch' and 'letter-spacing' was added (see example n. 63). - The cMargin state was replaced by cell_padding array that can be set/get using setCellPadding() and getCellPadding() methods. - Methods getCellPaddings() and setCellPaddings() were added to fine tune cell paddings (see example n. 5). diff --git a/lib/tcpdf/README.TXT b/lib/tcpdf/README.TXT index 83520bb1272..1d0fc015deb 100644 --- a/lib/tcpdf/README.TXT +++ b/lib/tcpdf/README.TXT @@ -8,8 +8,8 @@ http://sourceforge.net/donate/index.php?group_id=128076 ------------------------------------------------------------ Name: TCPDF -Version: 5.9.156 -Release date: 2012-04-10 +Version: 5.9.181 +Release date: 2012-08-31 Author: Nicola Asuni Copyright (c) 2002-2012: @@ -47,7 +47,7 @@ Main Features: * no-write page regions; * bookmarks, named destinations and table of content; * text hyphenation; - * text stretching and spacing (tracking/kerning); + * text stretching and spacing (tracking); * automatic page break, line break and text alignments including justification; * automatic page numbering and page groups; * move and delete pages; diff --git a/lib/tcpdf/barcodes.php b/lib/tcpdf/barcodes.php index 4027aa7109a..c6c0172e4a3 100644 --- a/lib/tcpdf/barcodes.php +++ b/lib/tcpdf/barcodes.php @@ -1,9 +1,9 @@ * @package com.tecnick.tcpdf - * @version 1.0.023 + * @version 1.0.024 * @author Nicola Asuni */ class TCPDFBarcode { @@ -201,9 +201,9 @@ class TCPDFBarcode { $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3); // draw a vertical bar if ($imagick) { - $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); + $bar->rectangle($x, $y, ($x + $bw - 1), ($y + $bh - 1)); } else { - imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); + imagefilledrectangle($png, $x, $y, ($x + $bw - 1), ($y + $bh - 1), $fgcol); } } $x += $bw; diff --git a/lib/tcpdf/composer.json b/lib/tcpdf/composer.json new file mode 100644 index 00000000000..4cbb538103d --- /dev/null +++ b/lib/tcpdf/composer.json @@ -0,0 +1,38 @@ +{ + "name": "tcpdf/tcpdf", + "version": "5.9.181", + "homepage": "http://www.tcpdf.org/", + "type": "library", + "description": "TCPDF is a PHP class for generating PDF files on-the-fly without requiring external extensions.", + "keywords": ["pdf"], + "license": "LGPLv3", + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + } + ], + "require": { + "php": ">5.2" + }, + "autoload": { + "classmap": [ + "fonts", + "config/lang", + "config", + "2dbarcodes.php", + "barcodes.php", + "datamatrix.php", + "encodings_maps.php", + "htmlcolors.php", + "pdf417.php", + "qrcode.php", + "spotcolors.php", + "tcpdf.php", + "tcpdf_filters.php", + "tcpdf_parser.php", + "unicode_data.php" + ] + } +} diff --git a/lib/tcpdf/config/tcpdf_config.php b/lib/tcpdf/config/tcpdf_config.php old mode 100644 new mode 100755 diff --git a/lib/tcpdf/qrcode.php b/lib/tcpdf/qrcode.php index 1fab6b58a77..93b05cbe0a2 100644 --- a/lib/tcpdf/qrcode.php +++ b/lib/tcpdf/qrcode.php @@ -1,9 +1,9 @@ dataStr) > 0) { - if ($this->dataStr == '') { - return 0; - } $mode = $this->identifyMode(0); switch ($mode) { case QR_MODE_NM: { @@ -1476,6 +1474,7 @@ class QRcode { } $this->dataStr = substr($this->dataStr, $length); } + return 0; } /** @@ -2028,7 +2027,7 @@ class QRcode { if ($ver > $this->version) { $this->version = $ver; } - for (;;) { + while (true) { $cbs = $this->createBitStream($items); $items = $cbs[0]; $bits = $cbs[1]; @@ -2315,17 +2314,18 @@ class QRcode { /** * Return a version number that satisfies the input code length. - * @param $size (int) input code length (byte) + * @param $size (int) input code length (bytes) * @param $level (int) error correction level * @return int version number */ protected function getMinimumVersion($size, $level) { - for ($i=1; $i <= QRSPEC_VERSION_MAX; ++$i) { - $words = $this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]; + for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) { + $words = ($this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]); if ($words >= $size) { return $i; } } + // the size of input data is greater than QR capacity, try to lover the error correction mode return -1; } diff --git a/lib/tcpdf/readme_moodle.txt b/lib/tcpdf/readme_moodle.txt index 1b6d92480dd..e953af35e22 100644 --- a/lib/tcpdf/readme_moodle.txt +++ b/lib/tcpdf/readme_moodle.txt @@ -1,5 +1,5 @@ -Description of TCPDF library import 5.9.156 -=================================== +Description of TCPDF library import 5.9.181 +=========================================== * delete cache/ doc/ examples/ config/tcpdf_config_alt.php config/lang/ images/ * remove all fonts but the core ones (courier.php, helveticabi.php, helveticab.php, helveticai.php, helvetica.php, symbol.php, timesbi.php, diff --git a/lib/tcpdf/tcpdf.php b/lib/tcpdf/tcpdf.php index 7c18096a52a..c5109bf4a68 100644 --- a/lib/tcpdf/tcpdf.php +++ b/lib/tcpdf/tcpdf.php @@ -1,9 +1,9 @@ no-write page regions; *
  • bookmarks, named destinations and table of content;
  • *
  • text hyphenation;
  • - *
  • text stretching and spacing (tracking/kerning);
  • + *
  • text stretching and spacing (tracking);
  • *
  • automatic page break, line break and text alignments including justification;
  • *
  • automatic page numbering and page groups;
  • *
  • move and delete pages;
  • @@ -137,7 +138,7 @@ * Tools to encode your unicode fonts are on fonts/utils directory.

    * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 5.9.156 + * @version 5.9.181 */ // Main configuration file. Define the K_TCPDF_EXTERNAL_CONFIG constant to skip this file. @@ -149,7 +150,7 @@ require_once(dirname(__FILE__).'/config/tcpdf_config.php'); * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
    * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 5.9.156 + * @version 5.9.181 * @author Nicola Asuni - info@tecnick.com */ class TCPDF { @@ -160,7 +161,7 @@ class TCPDF { * Current TCPDF version. * @private */ - private $tcpdf_version = '5.9.156'; + private $tcpdf_version = '5.9.181'; // Protected properties @@ -180,7 +181,13 @@ class TCPDF { * Array of object offsets. * @protected */ - protected $offsets; + protected $offsets = array(); + + /** + * Array of object IDs for each page. + * @protected + */ + protected $pageobjects = array(); /** * Buffer holding in-memory PDF. @@ -352,6 +359,12 @@ class TCPDF { */ protected $images = array(); + /** + * Array of cached files. + * @protected + */ + protected $cached_files = array(); + /** * Array of Annotations in pages. * @protected @@ -705,6 +718,41 @@ class TCPDF { */ protected $header_string = ''; + /** + * Color for header text (RGB array). + * @since 5.9.174 (2012-07-25) + * @protected + */ + protected $header_text_color = array(0,0,0); + + /** + * Color for header line (RGB array). + * @since 5.9.174 (2012-07-25) + * @protected + */ + protected $header_line_color = array(0,0,0); + + /** + * Color for footer text (RGB array). + * @since 5.9.174 (2012-07-25) + * @protected + */ + protected $footer_text_color = array(0,0,0); + + /** + * Color for footer line (RGB array). + * @since 5.9.174 (2012-07-25) + * @protected + */ + protected $footer_line_color = array(0,0,0); + + /** + * Text shadow data array. + * @since 5.9.174 (2012-07-25) + * @protected + */ + protected $txtshadow = array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal'); + /** * Default number of columns for html table. * @protected @@ -1590,7 +1638,7 @@ class TCPDF { protected $font_stretching = 100; /** - * Increases or decreases the space between characters in a text by the specified amount (tracking/kerning). + * Increases or decreases the space between characters in a text by the specified amount (tracking). * @protected * @since 5.9.000 (2010-09-29) */ @@ -1873,6 +1921,13 @@ class TCPDF { */ protected $tcpdflink = true; + /** + * Cache array for computed GD gamma values. + * @protected + * @since 5.9.1632 (2012-06-05) + */ + protected $gdgammacache = array(); + //------------------------------------------------------------ // METHODS //------------------------------------------------------------ @@ -2006,6 +2061,7 @@ class TCPDF { $this->strokecolor = array('R' => 0, 'G' => 0, 'B' => 0); $this->bgcolor = array('R' => 255, 'G' => 255, 'B' => 255); $this->extgstates = array(); + $this->setTextShadow(); // user's rights $this->sign = false; $this->ur['enabled'] = false; @@ -2037,7 +2093,8 @@ class TCPDF { } $this->default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128)); // set file ID for trailer - $this->file_id = md5($this->getRandomSeed('TCPDF'.$orientation.$unit.$format.$encoding)); + $serformat = (is_array($format) ? serialize($format) : $format); + $this->file_id = md5($this->getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding)); // set document creation and modification timestamp $this->doc_creation_timestamp = time(); $this->doc_modification_timestamp = $this->doc_creation_timestamp; @@ -3059,8 +3116,8 @@ class TCPDF { // swap X and Y coordinates (change page orientation) $this->swapPageBoxCoordinates($this->page); } - $this->w = $this->wPt / $this->k; - $this->h = $this->hPt / $this->k; + $this->w = ($this->wPt / $this->k); + $this->h = ($this->hPt / $this->k); if ($this->empty_string($autopagebreak)) { if (isset($this->AutoPageBreak)) { $autopagebreak = $this->AutoPageBreak; @@ -4083,13 +4140,28 @@ class TCPDF { * @param $lw (string) header image logo width in mm * @param $ht (string) string to print as title on document header * @param $hs (string) string to print on document header + * @param $tc (array) RGB array color for text. + * @param $lc (array) RGB array color for line. * @public */ - public function setHeaderData($ln='', $lw=0, $ht='', $hs='') { + public function setHeaderData($ln='', $lw=0, $ht='', $hs='', $tc=array(0,0,0), $lc=array(0,0,0)) { $this->header_logo = $ln; $this->header_logo_width = $lw; $this->header_title = $ht; $this->header_string = $hs; + $this->header_text_color = $tc; + $this->header_line_color = $lc; + } + + /** + * Set footer data. + * @param $tc (array) RGB array color for text. + * @param $lc (array) RGB array color for line. + * @public + */ + public function setFooterData($tc=array(0,0,0), $lc=array(0,0,0)) { + $this->footer_text_color = $tc; + $this->footer_line_color = $lc; } /** @@ -4105,6 +4177,8 @@ class TCPDF { $ret['logo_width'] = $this->header_logo_width; $ret['title'] = $this->header_title; $ret['string'] = $this->header_string; + $ret['text_color'] = $this->header_text_color; + $ret['line_color'] = $this->header_line_color; return $ret; } @@ -4238,7 +4312,7 @@ class TCPDF { $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1); } $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1); - $this->SetTextColor(0, 0, 0); + $this->SetTextColorArray($this->header_text_color); // header title $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1); $this->SetX($header_x); @@ -4248,7 +4322,7 @@ class TCPDF { $this->SetX($header_x); $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false, true, 0, 'T', false); // print an ending header line - $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))); + $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color'])); $this->SetY((2.835 / $this->k) + max($imgy, $this->y)); if ($this->rtl) { $this->SetX($this->original_rMargin); @@ -4284,10 +4358,10 @@ class TCPDF { */ public function Footer() { $cur_y = $this->y; - $this->SetTextColor(0, 0, 0); + $this->SetTextColorArray($this->footer_text_color); //set style for cell border - $line_width = 0.85 / $this->k; - $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))); + $line_width = (0.85 / $this->k); + $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color)); //print document barcode $barcode = $this->getBarcode(); if (!empty($barcode)) { @@ -4919,9 +4993,9 @@ class TCPDF { } /** - * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking/kerning). + * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking). * @param $char (int) The char code whose length is to be returned - * @param $notlast (boolean) set to false for the latest character on string, true otherwise (default) + * @param $notlast (boolean) If false ignore the font-spacing. * @return float char width * @author Nicola Asuni * @public @@ -4930,7 +5004,7 @@ class TCPDF { public function GetCharWidth($char, $notlast=true) { // get raw width $chw = $this->getRawCharWidth($char); - if (($this->font_spacing != 0) AND $notlast) { + if (($this->font_spacing < 0) OR (($this->font_spacing > 0) AND $notlast)) { // increase/decrease font spacing $chw += $this->font_spacing; } @@ -5400,7 +5474,7 @@ class TCPDF { } /** - * Return the font ascent value + * Return the font ascent value. * @param $font (string) font name * @param $style (string) font style * @param $size (float) The size (in points) @@ -5421,7 +5495,7 @@ class TCPDF { } /** - * Return the font descent value + * Return true in the character is present in the specified font. * @param $char (mixed) Character to check (integer value or string) * @param $font (string) Font name (family name). * @param $style (string) Font style. @@ -5436,6 +5510,9 @@ class TCPDF { $char = $char[0]; } if ($this->empty_string($font)) { + if ($this->empty_string($style)) { + return (isset($this->CurrentFont['cw'][intval($char)])); + } $font = $this->FontFamily; } $fontdata = $this->AddFont($font, $style); @@ -5828,6 +5905,35 @@ class TCPDF { } } $this->checkPageBreak($h + $this->cell_margin['T'] + $this->cell_margin['B']); + // apply text shadow if enabled + if ($this->txtshadow['enabled']) { + // save data + $x = $this->x; + $y = $this->y; + $bc = $this->bgcolor; + $fc = $this->fgcolor; + $sc = $this->strokecolor; + $alpha = $this->alpha; + // print shadow + $this->x += $this->txtshadow['depth_w']; + $this->y += $this->txtshadow['depth_h']; + $this->SetFillColorArray($this->txtshadow['color']); + $this->SetTextColorArray($this->txtshadow['color']); + $this->SetDrawColorArray($this->txtshadow['color']); + if ($this->txtshadow['opacity'] != $alpha['CA']) { + $this->setAlpha($this->txtshadow['opacity'], $this->txtshadow['blend_mode']); + } + $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign)); + //restore data + $this->x = $x; + $this->y = $y; + $this->SetFillColorArray($bc); + $this->SetTextColorArray($fc); + $this->SetDrawColorArray($sc); + if ($this->txtshadow['opacity'] != $alpha['CA']) { + $this->setAlpha($alpha['CA'], $alpha['BM'], $alpha['ca'], $alpha['AIS']); + } + } $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign)); $this->cell_padding = $prev_cell_padding; $this->cell_margin = $prev_cell_margin; @@ -6023,34 +6129,97 @@ class TCPDF { } else { $unicode = $this->UTF8StringToArray($txt); // array of UTF-8 unicode values $unicode = $this->utf8Bidi($unicode, '', $this->tmprtl); + // replace thai chars (if any) if (defined('K_THAI_TOPCHARS') AND (K_THAI_TOPCHARS == true)) { - // ---- Fix for bug #2977340 "Incorrect Thai characters position arrangement" ---- - // NOTE: this doesn't work with HTML justification - // Symbols that could overlap on the font top (only works in LTR) - $topchar = array(3611, 3613, 3615, 3650, 3651, 3652); // chars that extends on top - $topsym = array(3633, 3636, 3637, 3638, 3639, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662); // symbols with top position - $numchars = count($unicode); // number of chars - $unik = 0; - $uniblock = array(); - $uniblock[$unik] = array(); - $uniblock[$unik][] = $unicode[0]; - // resolve overlapping conflicts by splitting the string in several parts - for ($i = 1; $i < $numchars; ++$i) { - // check if symbols overlaps at top - if (in_array($unicode[$i], $topsym) AND (in_array($unicode[($i - 1)], $topsym) OR in_array($unicode[($i - 1)], $topchar))) { - // move symbols to another array - ++$unik; - $uniblock[$unik] = array(); - $uniblock[$unik][] = $unicode[$i]; - ++$unik; - $uniblock[$unik] = array(); - $unicode[$i] = 0x200b; // Unicode Character 'ZERO WIDTH SPACE' (DEC:8203, U+200B) + // number of chars + $numchars = count($unicode); + // po pla, for far, for fan + $longtail = array(0x0e1b, 0x0e1d, 0x0e1f); + // do chada, to patak + $lowtail = array(0x0e0e, 0x0e0f); + // mai hun arkad, sara i, sara ii, sara ue, sara uee + $upvowel = array(0x0e31, 0x0e34, 0x0e35, 0x0e36, 0x0e37); + // mai ek, mai tho, mai tri, mai chattawa, karan + $tonemark = array(0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c); + // sara u, sara uu, pinthu + $lowvowel = array(0x0e38, 0x0e39, 0x0e3a); + $output = array(); + for ($i = 0; $i < $numchars; $i++) { + if (($unicode[$i] >= 0x0e00) && ($unicode[$i] <= 0x0e5b)) { + $ch0 = $unicode[$i]; + $ch1 = ($i > 0) ? $unicode[($i - 1)] : 0; + $ch2 = ($i > 1) ? $unicode[($i - 2)] : 0; + $chn = ($i < ($numchars - 1)) ? $unicode[($i + 1)] : 0; + if (in_array($ch0, $tonemark)) { + if ($chn == 0x0e33) { + // sara um + if (in_array($ch1, $longtail)) { + // tonemark at upper left + $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48)); + } else { + // tonemark at upper right (normal position) + $output[] = $ch0; + } + } elseif (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $lowvowel))) { + // tonemark at lower left + $output[] = $this->replaceChar($ch0, (0xf705 + $ch0 - 0x0e48)); + } elseif (in_array($ch1, $upvowel)) { + if (in_array($ch2, $longtail)) { + // tonemark at upper left + $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48)); + } else { + // tonemark at upper right (normal position) + $output[] = $ch0; + } + } else { + // tonemark at lower right + $output[] = $this->replaceChar($ch0, (0xf70a + $ch0 - 0x0e48)); + } + } elseif (($ch0 == 0x0e33) AND (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $tonemark)))) { + // add lower left nikhahit and sara aa + if ($this->isCharDefined(0xf711) AND $this->isCharDefined(0x0e32)) { + $output[] = 0xf711; + $this->CurrentFont['subsetchars'][0xf711] = true; + $output[] = 0x0e32; + $this->CurrentFont['subsetchars'][0x0e32] = true; + } else { + $output[] = $ch0; + } + } elseif (in_array($ch1, $longtail)) { + if ($ch0 == 0x0e31) { + // lower left mai hun arkad + $output[] = $this->replaceChar($ch0, 0xf710); + } elseif (in_array($ch0, $upvowel)) { + // lower left + $output[] = $this->replaceChar($ch0, (0xf701 + $ch0 - 0x0e34)); + } elseif ($ch0 == 0x0e47) { + // lower left mai tai koo + $output[] = $this->replaceChar($ch0, 0xf712); + } else { + // normal character + $output[] = $ch0; + } + } elseif (in_array($ch1, $lowtail) AND in_array($ch0, $lowvowel)) { + // lower vowel + $output[] = $this->replaceChar($ch0, (0xf718 + $ch0 - 0x0e38)); + } elseif (($ch0 == 0x0e0d) AND in_array($chn, $lowvowel)) { + // yo ying without lower part + $output[] = $this->replaceChar($ch0, 0xf70f); + } elseif (($ch0 == 0x0e10) AND in_array($chn, $lowvowel)) { + // tho santan without lower part + $output[] = $this->replaceChar($ch0, 0xf700); + } else { + $output[] = $ch0; + } } else { - $uniblock[$unik][] = $unicode[$i]; + // non-thai character + $output[] = $unicode[$i]; } } - // ---- END OF Fix for bug #2977340 - } + $unicode = $output; + // update font subsetchars + $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']); + } // end of K_THAI_TOPCHARS $txt2 = $this->arrUTF8ToUTF16BE($unicode, false); } } @@ -6094,7 +6263,7 @@ class TCPDF { $s .= 'q '.$this->TextColor.' '; } // rendering mode - $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, $this->textstrokewidth); + $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, ($this->textstrokewidth * $this->k)); // count number of spaces $ns = substr_count($txt, chr(32)); // Justification @@ -6250,6 +6419,25 @@ class TCPDF { return $rs; } + /** + * Replace a char if is defined on the current font. + * @param $oldchar (int) Integer code (unicode) of the character to replace. + * @param $newchar (int) Integer code (unicode) of the new character. + * @return int the replaced char or the old char in case the new char i not defined + * @protected + * @since 5.9.167 (2012-06-22) + */ + protected function replaceChar($oldchar, $newchar) { + if ($this->isCharDefined($newchar)) { + // add the new char on the subset list + $this->CurrentFont['subsetchars'][$newchar] = true; + // return the new character + return $newchar; + } + // return the old char + return $oldchar; + } + /** * Returns the code to draw the cell border * @param $x (float) X coordinate. @@ -7069,7 +7257,7 @@ class TCPDF { $w = $this->w - $this->rMargin - $this->x; } // max column width - $wmax = $w - $wadj; + $wmax = ($w - $wadj); if (!$firstline) { $wmax -= ($this->cell_padding['L'] + $this->cell_padding['R']); } @@ -7155,18 +7343,27 @@ class TCPDF { $this->rMargin += $margin['R']; } $w = $this->getRemainingWidth(); - $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R']; + $wmax = ($w - $this->cell_padding['L'] - $this->cell_padding['R']); } else { // 160 is the non-breaking space. // 173 is SHY (Soft Hypen). // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator. // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants. // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between. - if (($c != 160) AND (($c == 173) OR preg_match($this->re_spaces, $this->unichr($c)))) { + if (($c != 160) + AND (($c == 173) + OR preg_match($this->re_spaces, $this->unichr($c)) + OR (($c == 45) + AND ($i < ($nb - 1)) + AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($pc)) + AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($chars[($i + 1)])) + ) + ) + ) { // update last blank space position $sep = $i; // check if is a SHY - if ($c == 173) { + if (($c == 173) OR ($c == 45)) { $shy = true; if ($pc == 45) { $tmp_shy_replacement_width = 0; @@ -7191,8 +7388,8 @@ class TCPDF { // we have reached the end of column if ($sep == -1) { // check if the line was already started - if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $chrwidth))) - OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $chrwidth)))) { + if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $this->cell_padding['R'] - $margin['R'] - $chrwidth))) + OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $this->cell_padding['L'] + $margin['L'] + $chrwidth)))) { // print a void cell and go to next line $this->Cell($w, $h, '', 0, 1); $linebreak = true; @@ -7255,9 +7452,9 @@ class TCPDF { $linew = $this->GetArrStringWidth($tmparr); unset($tmparr); if ($this->rtl) { - $this->endlinex = $startx - $linew; + $this->endlinex = ($startx - $linew); } else { - $this->endlinex = $startx + $linew; + $this->endlinex = ($startx + $linew); } $w = $linew; $tmpcellpadding = $this->cell_padding; @@ -7320,6 +7517,9 @@ class TCPDF { $this->Cell($w, $h, $shy_char_left.$tmpstr.$shy_char_right, 0, 1, $align, $fill, $link, $stretch); unset($tmpstr); if ($firstline) { + if ($chars[$sep] == 45) { + $endspace += 1; + } // return the remaining text $this->cell_padding = $tmpcellpadding; return ($this->UniArrSubString($uchars, ($sep + $endspace))); @@ -7327,7 +7527,7 @@ class TCPDF { $i = $sep; $sep = -1; $shy = false; - $j = ($i+1); + $j = ($i + 1); } } // account for margin changes @@ -7655,22 +7855,21 @@ class TCPDF { } // check page for no-write regions and adapt page margins if necessary list($x, $y) = $this->checkPageRegions($h, $x, $y); - $cached_file = false; // true when the file is cached $exurl = ''; // external streams // check if we are passing an image as file or string if ($file[0] === '@') { // image from string $imgdata = substr($file, 1); - $file = K_PATH_CACHE.'img_'.md5($imgdata); + $file = $this->getObjFilename('img'); $fp = fopen($file, 'w'); fwrite($fp, $imgdata); fclose($fp); unset($imgdata); - $cached_file = true; $imsize = @getimagesize($file); if ($imsize === FALSE) { unlink($file); - $cached_file = false; + } else { + $this->cached_files[] = $file; } } else { // image file if ($file{0} === '*') { @@ -7697,7 +7896,9 @@ class TCPDF { curl_setopt($cs, CURLOPT_BINARYTRANSFER, true); curl_setopt($cs, CURLOPT_FAILONERROR, true); curl_setopt($cs, CURLOPT_RETURNTRANSFER, true); - curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true); + if ((ini_get('open_basedir') == '') AND (ini_get('safe_mode') == 'Off')) { + curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true); + } curl_setopt($cs, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($cs, CURLOPT_TIMEOUT, 30); curl_setopt($cs, CURLOPT_SSL_VERIFYPEER, false); @@ -7707,16 +7908,16 @@ class TCPDF { curl_close($cs); if ($imgdata !== FALSE) { // copy image to cache - $file = K_PATH_CACHE.'img_'.md5($imgdata); + $file = $this->getObjFilename('img'); $fp = fopen($file, 'w'); fwrite($fp, $imgdata); fclose($fp); unset($imgdata); - $cached_file = true; $imsize = @getimagesize($file); if ($imsize === FALSE) { unlink($file); - $cached_file = false; + } else { + $this->cached_files[] = $file; } } } elseif (($w > 0) AND ($h > 0)) { @@ -7738,7 +7939,7 @@ class TCPDF { } } // file hash - $filehash = md5($file); + $filehash = md5($this->file_id.$file); // get original image width and height in pixels list($pixw, $pixh) = $imsize; // calculate image width and height on document @@ -7976,10 +8177,6 @@ class TCPDF { // add image to document $this->setImageBuffer($file, $info); } - if ($cached_file) { - // remove cached file - unlink($file); - } // set alignment $this->img_rb_y = $y + $h; // set alignment @@ -8320,11 +8517,13 @@ class TCPDF { $data .= $this->rfread($f, $n); fread($f, 4); } elseif ($type == 'iCCP') { - // skip profile name and null separator + // skip profile name $len = 0; while ((ord(fread($f, 1)) > 0) AND ($len < 80)) { ++$len; } + // skip null separator + fread($f, 1); // get compression method if (ord(fread($f, 1)) != 0) { //$this->Error('Unknown filter method: '.$file); @@ -8396,7 +8595,7 @@ class TCPDF { */ protected function ImagePngAlpha($file, $x, $y, $wpx, $hpx, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $filehash='') { if (empty($filehash)) { - $filehash = md5($file); + $filehash = md5($this->file_id.$file); } // create temp image file (without alpha channel) $tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash; @@ -8407,7 +8606,7 @@ class TCPDF { $img = new Imagick(); $img->readImage($file); // clone image object - $imga = $img->clone(); + $imga = $this->objclone($img); // extract alpha channel $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE); $img->negateImage(true); @@ -8429,9 +8628,7 @@ class TCPDF { for ($xpx = 0; $xpx < $wpx; ++$xpx) { for ($ypx = 0; $ypx < $hpx; ++$ypx) { $color = imagecolorat($img, $xpx, $ypx); - $alpha = ($color >> 24); // shifts off the first 24 bits (where 8x3 are used for each color), and returns the remaining 7 allocated bits (commonly used for alpha) - $alpha = (((127 - $alpha) / 127) * 255); // GD alpha is only 7 bit (0 -> 127) - $alpha = $this->getGDgamma($alpha); // correct gamma + $alpha = $this->getGDgamma($color); // correct gamma imagesetpixel($imgalpha, $xpx, $ypx, $alpha); } } @@ -8455,13 +8652,27 @@ class TCPDF { } /** - * Correct the gamma value to be used with GD library - * @param $v (float) the gamma value to be corrected + * Get the GD-corrected PNG gamma value from alpha color + * @param $c (int) alpha color * @protected * @since 4.3.007 (2008-12-04) */ - protected function getGDgamma($v) { - return (pow(($v / 255), 2.2) * 255); + protected function getGDgamma($c) { + if (!isset($this->gdgammacache["'".$c."'"])) { + // shifts off the first 24 bits (where 8x3 are used for each color), + // and returns the remaining 7 allocated bits (commonly used for alpha) + $alpha = ($c >> 24); + // GD alpha is only 7 bit (0 -> 127) + $alpha = (((127 - $alpha) / 127) * 255); + // correct gamma + $this->gdgammacache["'".$c."'"] = (pow(($alpha / 255), 2.2) * 255); + // store the latest values on cache to improve performances + if (count($this->gdgammacache) > 8) { + // remove one element from the cache array + array_shift($this->gdgammacache); + } + } + return $this->gdgammacache["'".$c."'"]; } /** @@ -8736,7 +8947,7 @@ class TCPDF { header('Pragma: public'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - header('Content-Disposition: inline; filename="'.basename($name).'";'); + header('Content-Disposition: inline; filename="'.basename($name).'"'); $this->sendOutputData($this->getBuffer(), $this->bufferlen); } else { echo $this->getBuffer(); @@ -8767,7 +8978,7 @@ class TCPDF { header('Content-Type: application/pdf'); } // use the Content-Disposition header to supply a recommended filename - header('Content-Disposition: attachment; filename="'.basename($name).'";'); + header('Content-Disposition: attachment; filename="'.basename($name).'"'); header('Content-Transfer-Encoding: binary'); $this->sendOutputData($this->getBuffer(), $this->bufferlen); break; @@ -8794,7 +9005,7 @@ class TCPDF { header('Pragma: public'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - header('Content-Disposition: inline; filename="'.basename($name).'";'); + header('Content-Disposition: inline; filename="'.basename($name).'"'); $this->sendOutputData(file_get_contents($name), filesize($name)); } elseif ($dest == 'FD') { // send headers to browser @@ -8819,7 +9030,7 @@ class TCPDF { header('Content-Type: application/pdf'); } // use the Content-Disposition header to supply a recommended filename - header('Content-Disposition: attachment; filename="'.basename($name).'";'); + header('Content-Disposition: attachment; filename="'.basename($name).'"'); header('Content-Transfer-Encoding: binary'); $this->sendOutputData(file_get_contents($name), filesize($name)); } @@ -8865,6 +9076,7 @@ class TCPDF { AND ($val != 'bufferlen') AND ($val != 'buffer') AND ($val != 'diskcache') + AND ($val != 'cached_files') AND ($val != 'sign') AND ($val != 'signature_data') AND ($val != 'signature_max_length') @@ -8875,6 +9087,15 @@ class TCPDF { } } } + if (isset($this->cached_files) AND !empty($this->cached_files)) { + // remove cached files + foreach ($this->cached_files as $cachefile) { + if (is_file($cachefile)) { + unlink($cachefile); + } + } + unset($this->cached_files); + } } /** @@ -9430,7 +9651,7 @@ class TCPDF { if (isset($pl['opt']['be']) AND (is_array($pl['opt']['be']))) { $annots .= ' /BE <<'; $bstyles = array('S', 'C'); - if (isset($pl['opt']['be']['s']) AND in_array($pl['opt']['be']['s'], $markups)) { + if (isset($pl['opt']['be']['s']) AND in_array($pl['opt']['be']['s'], $bstyles)) { $annots .= ' /S /'.$pl['opt']['bs']['s']; } else { $annots .= ' /S /S'; @@ -9509,9 +9730,11 @@ class TCPDF { $annots .= ' /A <_datastring($this->unhtmlentities($pl['txt']), $annot_obj_id).'>>'; } else { // internal link - $l = $this->links[$pl['txt']]; - if (isset($this->page_obj_id[($l[0])])) { - $annots .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($l[0])], ($this->pagedim[$l[0]]['h'] - ($l[1] * $this->k))); + if (isset($this->links[$pl['txt']])) { + $l = $this->links[$pl['txt']]; + if (isset($this->page_obj_id[($l[0])])) { + $annots .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($l[0])], ($this->pagedim[$l[0]]['h'] - ($l[1] * $this->k))); + } } } $hmodes = array('N', 'I', 'O', 'P'); @@ -12855,11 +13078,14 @@ class TCPDF { $this->_out('xref'); $this->_out('0 '.($this->n + 1)); $this->_out('0000000000 65535 f '); + $freegen = ($this->n + 2); for ($i=1; $i <= $this->n; ++$i) { if (!isset($this->offsets[$i]) AND ($i > 1)) { - $this->offsets[$i] = $this->offsets[($i - 1)]; + $this->_out(sprintf('0000000000 %05d f ', $freegen)); + ++$freegen; + } else { + $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i])); } - $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i])); } // TRAILER $out = 'trailer'."\n"; @@ -12899,6 +13125,7 @@ class TCPDF { */ protected function _beginpage($orientation='', $format='') { ++$this->page; + $this->pageobjects[$this->page] = array(); $this->setPageBuffer($this->page, ''); // initialize array for graphics tranformation positions inside a page buffer $this->transfmrk[$this->page] = array(); @@ -12967,6 +13194,7 @@ class TCPDF { $objid = $this->n; } $this->offsets[$objid] = $this->bufferlen; + $this->pageobjects[$this->page][] = $objid; return $objid.' 0 obj'; } @@ -15012,7 +15240,7 @@ class TCPDF { * @since 2.1.000 (2008-01-08) */ protected function _outPoint($x, $y) { - $this->_out(sprintf('%F %F m', $x * $this->k, ($this->h - $y) * $this->k)); + $this->_out(sprintf('%F %F m', ($x * $this->k), (($this->h - $y) * $this->k))); } /** @@ -15024,7 +15252,7 @@ class TCPDF { * @since 2.1.000 (2008-01-08) */ protected function _outLine($x, $y) { - $this->_out(sprintf('%F %F l', $x * $this->k, ($this->h - $y) * $this->k)); + $this->_out(sprintf('%F %F l', ($x * $this->k), (($this->h - $y) * $this->k))); } /** @@ -16404,12 +16632,13 @@ class TCPDF { * @param $name (string) Destination name. * @param $y (float) Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;). * @param $page (int) Target page number (leave empty for current page). + * @param $x (float) X position in user units of the destiantion on the selected page (default = -1 = current position;). * @return (string) Stripped named destination identifier or false in case of error. * @public * @author Christian Deligant, Nicola Asuni * @since 5.9.097 (2011-06-23) */ - public function setDestination($name, $y=-1, $page='') { + public function setDestination($name, $y=-1, $page='', $x=-1) { // remove unsupported characters $name = $this->encodeNameObject($name); if ($this->empty_string($name)) { @@ -16417,6 +16646,17 @@ class TCPDF { } if ($y == -1) { $y = $this->GetY(); + } elseif ($y < 0) { + $y = 0; + } elseif ($y > $this->h) { + $y = $this->h; + } + if ($x == -1) { + $x = $this->GetX(); + } elseif ($x < 0) { + $x = 0; + } elseif ($x > $this->w) { + $x = $this->w; } if (empty($page)) { $page = $this->PageNo(); @@ -16424,7 +16664,7 @@ class TCPDF { return; } } - $this->dests[$name] = array('y' => $y, 'p' => $page); + $this->dests[$name] = array('x' => $x, 'y' => $y, 'p' => $page); return $name; } @@ -16452,7 +16692,7 @@ class TCPDF { $this->n_dests = $this->_newobj(); $out = ' <<'; foreach($this->dests as $name => $o) { - $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($o['p'])], ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k))); + $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k))); } $out .= ' >>'; $out .= "\n".'endobj'; @@ -16481,11 +16721,12 @@ class TCPDF { * @param $page (int) Target page number (leave empty for current page). * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic. * @param $color (array) RGB color array (values from 0 to 255). + * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;). * @public * @author Olivier Plathey, Nicola Asuni * @since 2.1.002 (2008-02-12) */ - public function Bookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0)) { + public function Bookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0), $x=-1) { if ($level < 0) { $level = 0; } @@ -16500,6 +16741,17 @@ class TCPDF { } if ($y == -1) { $y = $this->GetY(); + } elseif ($y < 0) { + $y = 0; + } elseif ($y > $this->h) { + $y = $this->h; + } + if ($x == -1) { + $x = $this->GetX(); + } elseif ($x < 0) { + $x = 0; + } elseif ($x > $this->w) { + $x = $this->w; } if (empty($page)) { $page = $this->PageNo(); @@ -16507,7 +16759,7 @@ class TCPDF { return; } } - $this->outlines[] = array('t' => $txt, 'l' => $level, 'y' => $y, 'p' => $page, 's' => strtoupper($style), 'c' => $color); + $this->outlines[] = array('t' => $txt, 'l' => $level, 'x' => $x, 'y' => $y, 'p' => $page, 's' => strtoupper($style), 'c' => $color); } /** @@ -16590,7 +16842,7 @@ class TCPDF { $out .= ' /Last '.($n + $o['last']).' 0 R'; } if (isset($this->page_obj_id[($o['p'])])) { - $out .= ' '.sprintf('/Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($o['p'])], ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k))); + $out .= ' '.sprintf('/Dest [%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k))); } // set font style $style = 0; @@ -19169,7 +19421,7 @@ class TCPDF { */ public function PieSectorXY($xc, $yc, $rx, $ry, $a, $b, $style='FD', $cw=false, $o=0, $nc=2) { if ($this->rtl) { - $xc = $this->w - $xc; + $xc = ($this->w - $xc); } $op = $this->getPathPaintOperator($style); if ($op == 'f') { @@ -19177,8 +19429,8 @@ class TCPDF { } if ($cw) { $d = $b; - $b = 360 - $a + $o; - $a = 360 - $d + $o; + $b = (360 - $a + $o); + $a = (360 - $d + $o); } else { $b += $o; $a += $o; @@ -19578,7 +19830,7 @@ class TCPDF { // create new barcode object $barcodeobj = new TCPDFBarcode($code, $type); $arrcode = $barcodeobj->getBarcodeArray(); - if ($arrcode === false) { + if (($arrcode === false) OR empty($arrcode) OR ($arrcode['maxw'] == 0)) { $this->Error('Error in 1D barcode string'); } // set default values @@ -19949,7 +20201,7 @@ class TCPDF { // create new barcode object $barcodeobj = new TCPDF2DBarcode($code, $type); $arrcode = $barcodeobj->getBarcodeArray(); - if (($arrcode === false) OR empty($arrcode)) { + if (($arrcode === false) OR empty($arrcode) OR !isset($arrcode['num_rows']) OR ($arrcode['num_rows'] == 0) OR !isset($arrcode['num_cols']) OR ($arrcode['num_cols'] == 0)) { $this->Error('Error in 2D barcode string'); } // set default values @@ -20004,6 +20256,9 @@ class TCPDF { // module width and height $mw = $style['module_width']; $mh = $style['module_height']; + if (($mw == 0) OR ($mh == 0)) { + $this->Error('Error in 2D barcode string'); + } // get max dimensions if ($this->rtl) { $maxw = $x - $this->lMargin; @@ -20886,7 +21141,7 @@ class TCPDF { /** * Returns the letter-spacing value from CSS value * @param $spacing (string) letter-spacing value - * @param $parent (float) font spacing (tracking/kerning) value of the parent element + * @param $parent (float) font spacing (tracking) value of the parent element * @return float quantity to increases or decreases the space between characters in a text. * @protected * @since 5.9.000 (2010-10-02) @@ -21499,7 +21754,7 @@ class TCPDF { } if (isset($dom[$key]['style']['border-style'])) { $brd_styles = preg_split('/[\s]+/', trim($dom[$key]['style']['border-style'])); - if (isset($brd_styles[3])) { + if (isset($brd_styles[3]) AND ($brd_styles[3]!='none')) { $dom[$key]['border']['L']['cap'] = 'square'; $dom[$key]['border']['L']['join'] = 'miter'; $dom[$key]['border']['L']['dash'] = $this->getCSSBorderDashStyle($brd_styles[3]); @@ -21834,7 +22089,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $curfontascent = $this->getFontAscent($curfontname, $curfontstyle, $curfontsize); $curfontdescent = $this->getFontDescent($curfontname, $curfontstyle, $curfontsize); $curfontstretcing = $this->font_stretching; - $curfontkerning = $this->font_spacing; + $curfonttracking = $this->font_spacing; $this->newline = true; $newline = true; $startlinepage = $this->page; @@ -21973,7 +22228,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this_method_vars['curfontascent'] = $curfontascent; $this_method_vars['curfontdescent'] = $curfontdescent; $this_method_vars['curfontstretcing'] = $curfontstretcing; - $this_method_vars['curfontkerning'] = $curfontkerning; + $this_method_vars['curfonttracking'] = $curfonttracking; $this_method_vars['minstartliney'] = $minstartliney; $this_method_vars['maxbottomliney'] = $maxbottomliney; $this_method_vars['yshift'] = $yshift; @@ -23051,9 +23306,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } else { $wadj = 0; // space to leave for block continuity if ($this->rtl) { - $cwa = $this->x - $this->lMargin; + $cwa = ($this->x - $this->lMargin); } else { - $cwa = $this->w - $this->rMargin - $this->x; + $cwa = ($this->w - $this->rMargin - $this->x); } if (($strlinelen < $cwa) AND (isset($dom[($key + 1)])) AND ($dom[($key + 1)]['tag']) AND (!$dom[($key + 1)]['block'])) { // check the next text blocks for continuity @@ -23143,6 +23398,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } else { $loop = 0; + // add the positive font spacing of the last character (if any) + if ($this->font_spacing > 0) { + if ($this->rtl) { + $this->x -= $this->font_spacing; + } else { + $this->x += $this->font_spacing; + } + } } } ++$key; @@ -23740,7 +24003,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $value = $tag['attribute']['value']; } if (isset($tag['attribute']['maxlength']) AND !$this->empty_string($tag['attribute']['maxlength'])) { - $opt['maxlen'] = intval($tag['attribute']['value']); + $opt['maxlen'] = intval($tag['attribute']['maxlength']); } $h = $this->FontSize * $this->cell_height_ratio; if (isset($tag['attribute']['size']) AND !$this->empty_string($tag['attribute']['size'])) { @@ -23786,14 +24049,23 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'checkbox': { + if (!isset($value)) { + break; + } $this->CheckBox($name, $w, $checked, $prop, $opt, $value, '', '', false); break; } case 'radio': { + if (!isset($value)) { + break; + } $this->RadioButton($name, $w, $prop, $opt, $value, $checked, '', '', false); break; } case 'submit': { + if (!isset($value)) { + $value = 'submit'; + } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255)); @@ -23810,6 +24082,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'reset': { + if (!isset($value)) { + $value = 'reset'; + } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255)); @@ -23855,6 +24130,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'button': { + if (!isset($value)) { + $value = ' '; + } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255)); @@ -24328,13 +24606,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (end($this->transfmrk[$this->page]) !== false) { $pagemarkkey = key($this->transfmrk[$this->page]); $pagemark = $this->transfmrk[$this->page][$pagemarkkey]; - $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen; } elseif ($this->InFooter) { $pagemark = $this->footerpos[$this->page]; - $this->footerpos[$this->page] += $offsetlen; } else { $pagemark = $this->intmrk[$this->page]; - $this->intmrk[$this->page] += $offsetlen; } $pagebuff = $this->getPageBuffer($this->page); $pstart = substr($pagebuff, 0, $pagemark); @@ -24738,17 +25013,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (end($this->transfmrk[$this->page]) !== false) { $pagemarkkey = key($this->transfmrk[$this->page]); $pagemark = $this->transfmrk[$this->page][$pagemarkkey]; - $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen; } elseif ($this->InFooter) { $pagemark = $this->footerpos[$this->page]; - $this->footerpos[$this->page] += $offsetlen; } else { $pagemark = $this->intmrk[$this->page]; - $this->intmrk[$this->page] += $offsetlen; } $pagebuff = $this->getPageBuffer($this->page); - $pstart = substr($pagebuff, 0, $this->bordermrk[$this->page]); - $pend = substr($pagebuff, $this->bordermrk[$this->page]); + $pstart = substr($pagebuff, 0, $pagemark); + $pend = substr($pagebuff, $pagemark); $this->setPageBuffer($this->page, $pstart.$ccode.$pend); $this->bordermrk[$this->page] += $offsetlen; $this->cntmrk[$this->page] += $offsetlen; @@ -25278,6 +25550,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 'cell_height_ratio' => $this->cell_height_ratio, 'font_stretching' => $this->font_stretching, 'font_spacing' => $this->font_spacing, + 'alpha' => $this->alpha, // extended 'lasth' => $this->lasth, 'tMargin' => $this->tMargin, @@ -25337,6 +25610,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->cell_height_ratio = $gvars['cell_height_ratio']; $this->font_stretching = $gvars['font_stretching']; $this->font_spacing = $gvars['font_spacing']; + $this->alpha = $gvars['alpha']; if ($extended) { // restore extended values $this->lasth = $gvars['lasth']; @@ -25651,6 +25925,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $tmpintmrk = $this->intmrk[$frompage]; $tmpbordermrk = $this->bordermrk[$frompage]; $tmpcntmrk = $this->cntmrk[$frompage]; + $tmppageobjects = $this->pageobjects[$frompage]; if (isset($this->footerpos[$frompage])) { $tmpfooterpos = $this->footerpos[$frompage]; } @@ -25686,6 +25961,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->intmrk[$i] = $this->intmrk[$j]; $this->bordermrk[$i] = $this->bordermrk[$j]; $this->cntmrk[$i] = $this->cntmrk[$j]; + $this->pageobjects[$i] = $this->pageobjects[$j]; if (isset($this->footerpos[$j])) { $this->footerpos[$i] = $this->footerpos[$j]; } elseif (isset($this->footerpos[$i])) { @@ -25720,6 +25996,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->intmrk[$topage] = $tmpintmrk; $this->bordermrk[$topage] = $tmpbordermrk; $this->cntmrk[$topage] = $tmpcntmrk; + $this->pageobjects[$topage] = $tmppageobjects; if (isset($tmpfooterpos)) { $this->footerpos[$topage] = $tmpfooterpos; } elseif (isset($this->footerpos[$topage])) { @@ -25807,6 +26084,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: unset($this->intmrk[$page]); unset($this->bordermrk[$page]); unset($this->cntmrk[$page]); + foreach ($this->pageobjects[$page] as $oid) { + if (isset($this->offsets[$oid])){ + unset($this->offsets[$oid]); + } + } + unset($this->pageobjects[$page]); if (isset($this->footerpos[$page])) { unset($this->footerpos[$page]); } @@ -25841,6 +26124,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->intmrk[$i] = $this->intmrk[$j]; $this->bordermrk[$i] = $this->bordermrk[$j]; $this->cntmrk[$i] = $this->cntmrk[$j]; + $this->pageobjects[$i] = $this->pageobjects[$j]; if (isset($this->footerpos[$j])) { $this->footerpos[$i] = $this->footerpos[$j]; } elseif (isset($this->footerpos[$i])) { @@ -25881,6 +26165,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: unset($this->intmrk[$this->numpages]); unset($this->bordermrk[$this->numpages]); unset($this->cntmrk[$this->numpages]); + foreach ($this->pageobjects[$this->numpages] as $oid) { + if (isset($this->offsets[$oid])){ + unset($this->offsets[$oid]); + } + } + unset($this->pageobjects[$this->numpages]); if (isset($this->footerpos[$this->numpages])) { unset($this->footerpos[$this->numpages]); } @@ -25982,6 +26272,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->intmrk[$this->page] = $this->intmrk[$page]; $this->bordermrk[$this->page] = $this->bordermrk[$page]; $this->cntmrk[$this->page] = $this->cntmrk[$page]; + $this->pageobjects[$this->page] = $this->pageobjects[$page]; $this->pageopen[$this->page] = false; if (isset($this->footerpos[$page])) { $this->footerpos[$this->page] = $this->footerpos[$page]; @@ -26007,7 +26298,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $tmpoutlines = $this->outlines; foreach ($tmpoutlines as $key => $outline) { if ($outline['p'] == $page) { - $this->outlines[] = array('t' => $outline['t'], 'l' => $outline['l'], 'y' => $outline['y'], 'p' => $this->page, 's' => $outline['s'], 'c' => $outline['c']); + $this->outlines[] = array('t' => $outline['t'], 'l' => $outline['l'], 'x' => $outline['x'], 'y' => $outline['y'], 'p' => $this->page, 's' => $outline['s'], 'c' => $outline['c']); } } // copy links @@ -26695,7 +26986,59 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } $this->textrendermode = $textrendermode; - $this->textstrokewidth = $stroke * $this->k; + $this->textstrokewidth = $stroke; + } + + /** + * Set parameters for drop shadow effect for text. + * @param $params (array) Array of parameters: enabled (boolean) set to true to enable shadow; depth_w (float) shadow width in user units; depth_h (float) shadow height in user units; color (array) shadow color or false to use the stroke color; opacity (float) Alpha value: real value from 0 (transparent) to 1 (opaque); blend_mode (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity. + * @since 5.9.174 (2012-07-25) + * @public + */ + public function setTextShadow($params=array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal')) { + if (isset($params['enabled'])) { + $this->txtshadow['enabled'] = $params['enabled']?true:false; + } else { + $this->txtshadow['enabled'] = false; + } + if (isset($params['depth_w'])) { + $this->txtshadow['depth_w'] = floatval($params['depth_w']); + } else { + $this->txtshadow['depth_w'] = 0; + } + if (isset($params['depth_h'])) { + $this->txtshadow['depth_h'] = floatval($params['depth_h']); + } else { + $this->txtshadow['depth_h'] = 0; + } + if (isset($params['color']) AND ($params['color'] !== false) AND is_array($params['color'])) { + $this->txtshadow['color'] = $params['color']; + } else { + $this->txtshadow['color'] = $this->strokecolor; + } + if (isset($params['opacity'])) { + $this->txtshadow['opacity'] = min(1, max(0, floatval($params['opacity']))); + } else { + $this->txtshadow['opacity'] = 1; + } + if (isset($params['blend_mode']) AND in_array($params['blend_mode'], array('Normal', 'Multiply', 'Screen', 'Overlay', 'Darken', 'Lighten', 'ColorDodge', 'ColorBurn', 'HardLight', 'SoftLight', 'Difference', 'Exclusion', 'Hue', 'Saturation', 'Color', 'Luminosity'))) { + $this->txtshadow['blend_mode'] = $params['blend_mode']; + } else { + $this->txtshadow['blend_mode'] = 'Normal'; + } + if ((($this->txtshadow['depth_w'] == 0) AND ($this->txtshadow['depth_h'] == 0)) OR ($this->txtshadow['opacity'] == 0)) { + $this->txtshadow['enabled'] = false; + } + } + + /** + * Return the text shadow parameters array. + * @return Array of parameters. + * @since 5.9.174 (2012-07-25) + * @public + */ + public function getTextShadow() { + return $this->txtshadow; } /** @@ -27337,7 +27680,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Get the amount to increase or decrease the space between characters in a text. - * @return int font spacing (tracking/kerning) value + * @return int font spacing (tracking) value * @author Nicola Asuni * @public * @since 5.9.000 (2010-09-29) @@ -27741,7 +28084,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // scale and translate $e = $ox * $this->k * (1 - $svgscale_x); $f = ($this->h - $oy) * $this->k * (1 - $svgscale_y); - $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, $e + $svgoffset_x, $f + $svgoffset_y)); + $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y))); // creates a new XML parser to be used by the other XML functions $this->parser = xml_parser_create('UTF-8'); // the following function allows to use parser inside object @@ -28089,10 +28432,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $gradient['coords'][3] += $y; } // calculate percentages - $gradient['coords'][0] = ($gradient['coords'][0] - $x) / $w; - $gradient['coords'][1] = ($gradient['coords'][1] - $y) / $h; - $gradient['coords'][2] = ($gradient['coords'][2] - $x) / $w; - $gradient['coords'][3] = ($gradient['coords'][3] - $y) / $h; + $gradient['coords'][0] = (($gradient['coords'][0] - $x) / $w); + $gradient['coords'][1] = (($gradient['coords'][1] - $y) / $h); + $gradient['coords'][2] = (($gradient['coords'][2] - $x) / $w); + $gradient['coords'][3] = (($gradient['coords'][3] - $y) / $h); if (isset($gradient['coords'][4])) { $gradient['coords'][4] /= $w; } @@ -28121,9 +28464,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($gradient['type'] == 3) { // circular gradient $cy = $this->h - $y - ($gradient['coords'][1] * ($w + $h)); - $this->_out(sprintf('%F 0 0 %F %F %F cm', $w*$this->k, $w*$this->k, $x*$this->k, $cy*$this->k)); + $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($w * $this->k), ($x * $this->k), ($cy * $this->k))); } else { - $this->_out(sprintf('%F 0 0 %F %F %F cm', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k)); + $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), (($this->h - ($y + $h)) * $this->k))); } if (count($gradient['stops']) > 1) { $this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false); @@ -28331,6 +28674,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } else { $this->_outLine($x, $y); } + $x0 = $x; + $y0 = $y; } $xmin = min($xmin, $x); $ymin = min($ymin, $y); @@ -28352,6 +28697,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $y = $cp + $yoffset; if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) { $this->_outLine($x, $y); + $x0 = $x; + $y0 = $y; } $xmin = min($xmin, $x); $ymin = min($ymin, $y); @@ -28370,6 +28717,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $x = $cp + $xoffset; if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) { $this->_outLine($x, $y); + $x0 = $x; + $y0 = $y; } $xmin = min($xmin, $x); $xmax = max($xmax, $x); @@ -28384,6 +28733,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $y = $cp + $yoffset; if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) { $this->_outLine($x, $y); + $x0 = $x; + $y0 = $y; } $ymin = min($ymin, $y); $ymax = max($ymax, $y); @@ -28661,6 +29012,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // get styling properties $prev_svgstyle = $this->svgstyles[(count($this->svgstyles) - 1)]; // previous style $svgstyle = $this->svgstyles[0]; // set default style + if ($clipping AND !isset($attribs['fill']) AND (!isset($attribs['style']) OR (!preg_match('/[;\"\s]{1}fill[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval)))) { + // default fill attribute for clipping + $attribs['fill'] = 'none'; + } if (isset($attribs['style']) AND !$this->empty_string($attribs['style'])) { // fix style for regular expression $attribs['style'] = ';'.$attribs['style']; @@ -28693,7 +29048,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (!empty($ctm)) { $tm = $ctm; } else { - $tm = $this->svgstyles[(count($this->svgstyles) - 1)]['transfmatrix']; + //$tm = $this->svgstyles[(count($this->svgstyles) - 1)]['transfmatrix']; + $tm = array(1,0,0,1,0,0); } if (isset($attribs['transform']) AND !empty($attribs['transform'])) { $tm = $this->getTransformationMatrixProduct($tm, $this->getSVGTransformMatrix($attribs['transform'])); @@ -28732,6 +29088,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // group together related graphics elements array_push($this->svgstyles, $svgstyle); $this->StartTransform(); + $this->SVGTransform($tm); $this->setSVGStyles($svgstyle, $prev_svgstyle); break; } @@ -28752,15 +29109,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox'; } //$attribs['spreadMethod'] - $x1 = (isset($attribs['x1'])?$attribs['x1']:'0%'); - $y1 = (isset($attribs['y1'])?$attribs['y1']:'0%'); - $x2 = (isset($attribs['x2'])?$attribs['x2']:'100%'); - $y2 = (isset($attribs['y2'])?$attribs['y2']:'0%'); - if (substr($x1, -1) != '%') { - $this->svggradients[$this->svggradientid]['mode'] = 'measure'; - } else { + if (((!isset($attribs['x1'])) AND (!isset($attribs['y1'])) AND (!isset($attribs['x2'])) AND (!isset($attribs['y2']))) + OR ((isset($attribs['x1']) AND (substr($attribs['x1'], -1) == '%')) + OR (isset($attribs['y1']) AND (substr($attribs['y1'], -1) == '%')) + OR (isset($attribs['x2']) AND (substr($attribs['x2'], -1) == '%')) + OR (isset($attribs['y2']) AND (substr($attribs['y2'], -1) == '%')))) { $this->svggradients[$this->svggradientid]['mode'] = 'percentage'; + } else { + $this->svggradients[$this->svggradientid]['mode'] = 'measure'; } + $x1 = (isset($attribs['x1'])?$attribs['x1']:'0'); + $y1 = (isset($attribs['y1'])?$attribs['y1']:'0'); + $x2 = (isset($attribs['x2'])?$attribs['x2']:'100'); + $y2 = (isset($attribs['y2'])?$attribs['y2']:'0'); if (isset($attribs['gradientTransform'])) { $this->svggradients[$this->svggradientid]['gradientTransform'] = $this->getSVGTransformMatrix($attribs['gradientTransform']); } @@ -28788,16 +29149,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox'; } //$attribs['spreadMethod'] - $cx = (isset($attribs['cx'])?$attribs['cx']:0.5); - $cy = (isset($attribs['cy'])?$attribs['cy']:0.5); - $fx = (isset($attribs['fx'])?$attribs['fx']:$cx); - $fy = (isset($attribs['fy'])?$attribs['fy']:$cy); - $r = (isset($attribs['r'])?$attribs['r']:0.5); - if (isset($attribs['cx']) AND (substr($attribs['cx'], -1) != '%')) { - $this->svggradients[$this->svggradientid]['mode'] = 'measure'; - } else { + if (((!isset($attribs['cx'])) AND (!isset($attribs['cy']))) + OR ((isset($attribs['cx']) AND (substr($attribs['cx'], -1) == '%')) + OR (isset($attribs['cy']) AND (substr($attribs['cy'], -1) == '%')) )) { $this->svggradients[$this->svggradientid]['mode'] = 'percentage'; + } else { + $this->svggradients[$this->svggradientid]['mode'] = 'measure'; } + $cx = (isset($attribs['cx']) ? $attribs['cx'] : 0.5); + $cy = (isset($attribs['cy']) ? $attribs['cy'] : 0.5); + $fx = (isset($attribs['fx']) ? $attribs['fx'] : $cx); + $fy = (isset($attribs['fy']) ? $attribs['fy'] : $cy); + $r = (isset($attribs['r']) ? $attribs['r'] : 0.5); if (isset($attribs['gradientTransform'])) { $this->svggradients[$this->svggradientid]['gradientTransform'] = $this->getSVGTransformMatrix($attribs['gradientTransform']); } @@ -28876,12 +29239,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($invisible) { break; } - $cx = (isset($attribs['cx'])?$this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false):0); - $cy = (isset($attribs['cy'])?$this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false):0); - $r = (isset($attribs['r'])?$this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false):0); - $x = $cx - $r; - $y = $cy - $r; - $w = 2 * $r; + $r = (isset($attribs['r']) ? $this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false) : 0); + $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0)); + $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0)); + $x = ($cx - $r); + $y = ($cy - $r); + $w = (2 * $r); $h = $w; if ($clipping) { $this->SVGTransform($tm); @@ -28901,14 +29264,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($invisible) { break; } - $cx = (isset($attribs['cx'])?$this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false):0); - $cy = (isset($attribs['cy'])?$this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false):0); - $rx = (isset($attribs['rx'])?$this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false):0); - $ry = (isset($attribs['ry'])?$this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false):0); - $x = $cx - $rx; - $y = $cy - $ry; - $w = 2 * $rx; - $h = 2 * $ry; + $rx = (isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0); + $ry = (isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : 0); + $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0)); + $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0)); + $x = ($cx - $rx); + $y = ($cy - $ry); + $w = (2 * $rx); + $h = (2 * $ry); if ($clipping) { $this->SVGTransform($tm); $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ', array(), array(), 8); @@ -28981,7 +29344,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->StartTransform(); $this->SVGTransform($tm); $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ')); - $this->PolyLine($p, 'D', array(), array()); + if (!empty($obstyle)) { + $this->PolyLine($p, $obstyle, array(), array()); + } $this->StopTransform(); } else { // polygon if ($clipping) { @@ -29050,14 +29415,26 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // text case 'text': case 'tspan': { + // only basic support - advanced features must be implemented $this->svgtextmode['invisible'] = $invisible; if ($invisible) { break; } array_push($this->svgstyles, $svgstyle); - // only basic support - advanced features must be implemented - $x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):$this->x); - $y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):$this->y); + if (isset($attribs['x'])) { + $x = $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false); + } elseif ($name == 'tspan') { + $x = $this->x; + } else { + $x = 0; + } + if (isset($attribs['y'])) { + $y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false); + } elseif ($name == 'tspan') { + $y = $this->y; + } else { + $y = 0; + } $svgstyle['text-color'] = $svgstyle['fill']; $this->svgtext = ''; if (isset($svgstyle['text-anchor'])) { @@ -29088,16 +29465,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } // use case 'use': { - if (isset($attribs['xlink:href'])) { - $use = $this->svgdefs[substr($attribs['xlink:href'], 1)]; - if (isset($attribs['xlink:href'])) { - unset($attribs['xlink:href']); + if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) { + $svgdefid = substr($attribs['xlink:href'], 1); + if (isset($this->svgdefs[$svgdefid])) { + $use = $this->svgdefs[$svgdefid]; + if (isset($attribs['xlink:href'])) { + unset($attribs['xlink:href']); + } + if (isset($attribs['id'])) { + unset($attribs['id']); + } + $attribs = array_merge($attribs, $use['attribs']); + $this->startSVGElementHandler($parser, $use['name'], $attribs); } - if (isset($attribs['id'])) { - unset($attribs['id']); - } - $attribs = array_merge($use['attribs'], $attribs); - $this->startSVGElementHandler($parser, $use['name'], $use['attribs']); } break; } @@ -29162,7 +29542,17 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $textrendermode = $this->textrendermode; $textstrokewidth = $this->textstrokewidth; $this->setTextRenderingMode($this->svgtextmode['stroke'], true, false); + if ($name == 'text') { + // store current coordinates + $tmpx = $this->x; + $tmpy = $this->y; + } $this->Cell($textlen, 0, $text, 0, 0, '', false, '', 0, false, 'L', 'T'); + if ($name == 'text') { + // restore coordinates + $this->x = $tmpx; + $this->y = $tmpy; + } // restore previous rendering mode $this->textrendermode = $textrendermode; $this->textstrokewidth = $textstrokewidth; diff --git a/lib/tcpdf/tcpdf_parser.php b/lib/tcpdf/tcpdf_parser.php index 122676034d3..f17359f2134 100644 --- a/lib/tcpdf/tcpdf_parser.php +++ b/lib/tcpdf/tcpdf_parser.php @@ -1,9 +1,9 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.000 + * @version 1.0.001 */ // include class for decoding filters @@ -48,7 +48,7 @@ require_once(dirname(__FILE__).'/tcpdf_filters.php'); * This is a PHP class for parsing PDF documents.
    * @package com.tecnick.tcpdf * @brief This is a PHP class for parsing PDF documents.. - * @version 1.0.000 + * @version 1.0.001 * @author Nicola Asuni - info@tecnick.com */ class TCPDF_PARSER { @@ -127,20 +127,29 @@ class TCPDF_PARSER { * @since 1.0.000 (2011-05-24) */ protected function getXrefData($offset=0, $xref=array()) { - // find last startxref - if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) { - $this->Error('Unable to find startxref'); + if ($offset == 0) { + // find last startxref + if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) { + $this->Error('Unable to find startxref'); + } + $matches = array_pop($matches); + $startxref = $matches[1]; + } else { + // get the first xref at the specified offset + if (preg_match('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) == 0) { + $this->Error('Unable to find startxref'); + } + $startxref = $matches[1][0]; } - $matches = array_pop($matches); - $startxref = $matches[1]; // check xref position if (strpos($this->pdfdata, 'xref', $startxref) != $startxref) { $this->Error('Unable to find xref'); } // extract xref data (object indexes and offsets) - $offset = $startxref + 5; + $xoffset = $startxref + 5; // initialize object number $obj_num = 0; + $offset = $xoffset; while (preg_match('/^([0-9]+)[\s]([0-9]+)[\s]?([nf]?)/im', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { $offset = (strlen($matches[0][0]) + $matches[0][1]); if ($matches[3][0] == 'n') { @@ -162,7 +171,7 @@ class TCPDF_PARSER { } } // get trailer data - if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { + if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $xoffset) > 0) { $trailer_data = $matches[1][0]; if (!isset($xref['trailer'])) { // get only the last updated version @@ -188,7 +197,7 @@ class TCPDF_PARSER { } if (preg_match('/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) { // get previous xref - $xref = getXrefData(substr($this->pdfdata, 0, $startxref), intval($matches[1]), $xref); + $xref = $this->getXrefData(intval($matches[1]), $xref); } } else { $this->Error('Unable to find trailer'); @@ -399,7 +408,7 @@ class TCPDF_PARSER { $offset = $element[2]; // decode stream using stream's dictionary information if ($decoding AND ($element[0] == 'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] == '<<')) { - $element[3] = $this->decodeStream($objdata[($i - 1)][1], $element[1]); + $element[3] = $this->decodeStream($objdata[($i - 1)][1], substr($element[1], 1)); } $objdata[$i] = $element; ++$i; diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index 48811300c00..43a932fe4c2 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -179,7 +179,7 @@ tcpdf TCPDF LGPL - 5.9.156 + 5.9.181 3