From fc9cedb32122685014a9c00d6f69401aa8bd2df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0koda?= Date: Mon, 10 Mar 2014 14:05:33 +0800 Subject: [PATCH] MDL-44521 import TCPDF 6.0.062 --- lib/pdflib.php | 2 +- lib/tcpdf/CHANGELOG.TXT | 109 +++ lib/tcpdf/README.TXT | 9 +- lib/tcpdf/composer.json | 3 +- lib/tcpdf/config/tcpdf_config.php | 13 +- lib/tcpdf/include/barcodes/datamatrix.php | 6 +- lib/tcpdf/include/tcpdf_colors.php | 30 +- lib/tcpdf/include/tcpdf_fonts.php | 50 +- lib/tcpdf/include/tcpdf_images.php | 14 +- lib/tcpdf/include/tcpdf_static.php | 8 +- lib/tcpdf/readme_moodle.txt | 8 +- lib/tcpdf/tcpdf.php | 932 ++++++++++++++-------- lib/tcpdf/tcpdf_autoconfig.php | 10 +- lib/tcpdf/tcpdf_parser.php | 124 +-- lib/thirdpartylibs.xml | 2 +- 15 files changed, 871 insertions(+), 449 deletions(-) diff --git a/lib/pdflib.php b/lib/pdflib.php index 309698e3a76..1405ff1182e 100644 --- a/lib/pdflib.php +++ b/lib/pdflib.php @@ -73,7 +73,7 @@ define('K_PATH_CACHE', $CFG->cachedir . '/tcpdf/'); define('K_PATH_IMAGES', $CFG->dirroot . '/'); /** blank image */ -define('K_BLANK_IMAGE', K_PATH_IMAGES . '/pix/spacer.gif'); +define('K_BLANK_IMAGE', K_PATH_IMAGES . 'pix/spacer.gif'); /** height of cell repect font height */ define('K_CELL_HEIGHT_RATIO', 1.25); diff --git a/lib/tcpdf/CHANGELOG.TXT b/lib/tcpdf/CHANGELOG.TXT index 529f4732fdf..8eac585c5ec 100644 --- a/lib/tcpdf/CHANGELOG.TXT +++ b/lib/tcpdf/CHANGELOG.TXT @@ -1,3 +1,112 @@ +6.0.062 (2014-03-02) + - The method startLayer() now accepts the NULL value for the $print parameter to not set the print layer option. + +6.0.061 (2014-02-18) + - Bug #893 "Parsing error on streamed xref for secured pdf" was fixed. + +6.0.060 (2014-02-16) + - Bug #891 "Error on parsing hexa fields" was fixed. + - Bug #892 "Parsing pdf with trailing space at start" was fixed. + +6.0.059 (2014-02-03) + - SVG 'use' support was imporved. + +6.0.058 (2014-01-31) + - Bug #886 "Bugs with SVG using and " was fixed. + +6.0.057 (2014-01-26) + - Bug #883 "Parsing error" was fixed. + +6.0.056 (2014-01-25) + - The automatic cache folder selection now works also with some restricted hosting environments. + - CSS text-transform property is now supported (requires the multibyte string library for php) - see examle n. 061 (Thanks to Walter Ferraz). + - Bug #884 "Parsing error prev tag looking for" was fixed. + +6.0.055 (2014-01-15) + - Bug #880 "Error detecting hX tags (h1,h2..)" was fixed + - Bug #879 "Thead on the second page inherits style of previous tr" was fixed + +6.0.054 (2014-01-13) + - Bug #877 "Parenteses causing corrupt text" was fixed. + +6.0.053 (2014-01-03) + - Bug #876 "Cell padding should not be multiplied with number of lines in getStringHeight" was fixed. + - Patch #68 "Empty img src attribute leads to access of uninitialized string offset" was applied. + +6.0.052 (2013-12-12) + - Bug #871 "Datamatrix coding" was fixed. + +6.0.051 (2013-12-02) + - cbbox array values in addTTFfont() were converted to integers. + +6.0.050 (2013-12-01) + - The method getNumLines() was extended to support hyphenation. + - The CSS property line-height now supports non percentage values. + +6.0.050 (2013-11-27) + - A bug related to PNG images was fixed. + +6.0.048 (2013-11-24) + - SVG vars are now reset in ImageSVG() method. + +6.0.047 (2013-11-19) + - SVG support was extended to support some nested defs. + +6.0.046 (2013-11-17) + - preg_replace_callback functions were replaced to improve memory performances. + +6.0.045 (2013-11-17) + - Bug #862 "Parsing error on flate filter" was fixed. + +6.0.044 (2013-11-10) + - Bug #857 "Undefined offset error" was fixed. + - The uniord method now uses a static cache to improve performances (thanks to Mathieu Masseboeuf for the sugegstion). + - Two bugs in the TCPDF_FONTS class were fixed. + +6.0.043 (2013-10-29) + - Bug #854 "CSS instruction display" was fixed. + +6.0.042 (2013-10-25) + - Bug #852 "CMYK Colors Bug" was fixed. + +6.0.041 (2013-10-21) + - Bug #851 "Problem with images in PDF. PHP timing out" was fixed. + +6.0.040 (2013-10-20) + - Bug #849 "SVG import bug" was fixed. + +6.0.039 (2013-10-13) + - Bug #843 "Wrong call in parser" was fixed. + - Bug #844 "Wrong object type named" was fixed. + - Bug #845 "Parsing error on obj ref prefixed by '000000'" was fixed. + +6.0.038 (2013-10-06) + - Bug #841 "Division by zero warning at writeHTML a
  • tag" was fixed. + +6.0.037 (2013-09-30) + - Method getAllSpotColors() was added to return all spot colors. + - Method colorRegistrationBar() was extended to automatically print all spot colors and support individual spot colors. + - The method registrationMarkCMYK() was added to print a registration mark for CMYK colors. + - A bug related to page groups was fixed. + - Gradient() method now supports CMYK equivalents of spot colors. + - Example n. 56 was updated. + +6.0.036 (2013-09-29) + - Methods for registration bars and crop marks were extended to support registration color (see example n. 56). + - New default spot colors were added to tcpdf_colors.php, including the 'All' and 'None' special registration colors. + +6.0.035 (2013-09-25) + - TCPDF_PARSER class was improved. + +6.0.034 (2013-09-24) + - Bug #839 "Error in xref parsing in mixed newline chars" was fixed. + +6.0.033 (2013-09-23) + - Bug fix related to PNG image transparency using GD library. + +6.0.032 (2013-09-23) + - Bug #838 "Fatal error when imagick cannot handle the image, even though GD is available and can" was fixed. + 6.0.031 (2013-09-18) - Bug #836 "Optional EOL marker before endstream" was fixed. - Some additional controls were added to avoid "division by zero" error with badly formatted input. diff --git a/lib/tcpdf/README.TXT b/lib/tcpdf/README.TXT index 98b9c250ef5..7387366d557 100644 --- a/lib/tcpdf/README.TXT +++ b/lib/tcpdf/README.TXT @@ -8,11 +8,11 @@ http://sourceforge.net/donate/index.php?group_id=128076 ------------------------------------------------------------ Name: TCPDF -Version: 6.0.031 -Release date: 2013-09-18 +Version: 6.0.062 +Release date: 2014-03-02 Author: Nicola Asuni -Copyright (c) 2002-2013: +Copyright (c) 2002-2014: Nicola Asuni Tecnick.com LTD www.tecnick.com @@ -67,7 +67,7 @@ Additional Documentation: http://www.tcpdf.org License: - Copyright (C) 2002-2013 Nicola Asuni - Tecnick.com LTD + Copyright (C) 2002-2014 Nicola Asuni - Tecnick.com LTD TCPDF is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -107,4 +107,5 @@ Third party fonts: The binary files (.z) that begins with the prefix "ae" have been extracted from the Arabeyes.org collection (GNU-GPLv2). Link : http://projects.arabeyes.org/ + ============================================================ diff --git a/lib/tcpdf/composer.json b/lib/tcpdf/composer.json index 2f745dded37..0f5c0cde87a 100644 --- a/lib/tcpdf/composer.json +++ b/lib/tcpdf/composer.json @@ -1,6 +1,6 @@ { "name": "tecnick.com/tcpdf", - "version": "6.0.031", + "version": "6.0.062", "homepage": "http://www.tcpdf.org/", "type": "library", "description": "TCPDF is a PHP class for generating PDF documents.", @@ -23,7 +23,6 @@ "include", "tcpdf.php", "tcpdf_parser.php", - "tcpdf_import.php", "tcpdf_barcodes_1d.php", "tcpdf_barcodes_2d.php", "include/tcpdf_colors.php", diff --git a/lib/tcpdf/config/tcpdf_config.php b/lib/tcpdf/config/tcpdf_config.php index e6c1bf0d17c..b0931e57e70 100644 --- a/lib/tcpdf/config/tcpdf_config.php +++ b/lib/tcpdf/config/tcpdf_config.php @@ -2,13 +2,13 @@ //============================================================+ // File name : tcpdf_config.php // Begin : 2004-06-11 -// Last Update : 2013-05-16 +// Last Update : 2014-01-25 // // Description : Configuration file for TCPDF. // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- -// Copyright (C) 2004-2013 Nicola Asuni - Tecnick.com LTD +// Copyright (C) 2004-2014 Nicola Asuni - Tecnick.com LTD // // This file is part of TCPDF software library. // @@ -36,7 +36,10 @@ * @since 2004-10-27 */ -// If you define the constant K_TCPDF_EXTERNAL_CONFIG, the following settings will be ignored. +// IMPORTANT: +// If you define the constant K_TCPDF_EXTERNAL_CONFIG, all the following settings will be ignored. +// If you use the tcpdf_autoconfig.php, then you can overwrite some values here. + /** * Installation path (/var/www/tcpdf/). @@ -76,7 +79,7 @@ /** * Cache directory for temporary files (full path). */ -define ('K_PATH_CACHE', sys_get_temp_dir().'/'); +//define ('K_PATH_CACHE', '/tmp/'); /** * Generic name for a blank image. @@ -210,7 +213,7 @@ define('K_THAI_TOPCHARS', true); define('K_TCPDF_CALLS_IN_HTML', true); /** - * If true adn PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. + * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. */ define('K_TCPDF_THROW_EXCEPTION_ERROR', false); diff --git a/lib/tcpdf/include/barcodes/datamatrix.php b/lib/tcpdf/include/barcodes/datamatrix.php index 775e5cb15e1..95e4cbb9372 100644 --- a/lib/tcpdf/include/barcodes/datamatrix.php +++ b/lib/tcpdf/include/barcodes/datamatrix.php @@ -3,7 +3,7 @@ // File name : datamatrix.php // Version : 1.0.004 // Begin : 2010-06-07 -// Last Update : 2013-02-04 +// Last Update : 2013-12-12 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- @@ -860,6 +860,10 @@ class Datamatrix { ++$field_lenght; } if (($field_lenght == 4) OR ($epos == $data_lenght) OR !$this->isCharMode($chr, ENC_EDF)) { + if (($epos == $data_lenght) AND ($field_lenght < 3)) { + $enc = ENC_ASCII; + break; + } if ($field_lenght < 4) { // set unlatch character $temp_cw[] = 0x1f; diff --git a/lib/tcpdf/include/tcpdf_colors.php b/lib/tcpdf/include/tcpdf_colors.php index 37b91f4d188..a88fbb5a6d0 100644 --- a/lib/tcpdf/include/tcpdf_colors.php +++ b/lib/tcpdf/include/tcpdf_colors.php @@ -1,9 +1,9 @@ array(0, 0, 0, 100, 'My TCPDF Black'), - 'mytcpdfred' => array(30, 100, 90, 10, 'My TCPDF Red'), - 'mytcpdfgreen' => array(100, 30, 100, 0, 'My TCPDF Green'), - 'mytcpdfblue' => array(100, 60, 10, 5, 'My TCPDF Blue'), - 'mytcpdfyellow' => array(0, 20, 100, 0, 'My TCPDF Yellow'), + // special registration colors + 'none' => array( 0, 0, 0, 0, 'None'), + 'all' => array(100, 100, 100, 100, 'All'), + // standard CMYK colors + 'cyan' => array(100, 0, 0, 0, 'Cyan'), + 'magenta' => array( 0, 100, 0, 0, 'Magenta'), + 'yellow' => array( 0, 0, 100, 0, 'Yellow'), + 'key' => array( 0, 0, 0, 100, 'Key'), + // alias + 'white' => array( 0, 0, 0, 0, 'White'), + 'black' => array( 0, 0, 0, 100, 'Black'), + // standard RGB colors + 'red' => array( 0, 100, 100, 0, 'Red'), + 'green' => array(100, 0, 100, 0, 'Green'), + 'blue' => array(100, 100, 0, 0, 'Blue'), + // Add here standard spot colors or dynamically define them with AddSpotColor() // ... ); // end of spot colors @@ -296,7 +306,7 @@ class TCPDF_COLORS { } return $returncolor; } - } elseif (($dotpos = strpos($color, '.')) !== false) { + } elseif ((substr($color, 0, 4) != 'cmyk') AND ($dotpos = strpos($color, '.')) !== false) { // remove class parent (i.e.: color.red) $color = substr($color, ($dotpos + 1)); if ($color == 'transparent') { diff --git a/lib/tcpdf/include/tcpdf_fonts.php b/lib/tcpdf/include/tcpdf_fonts.php index 53f4eb5d603..bf7afdb82d3 100644 --- a/lib/tcpdf/include/tcpdf_fonts.php +++ b/lib/tcpdf/include/tcpdf_fonts.php @@ -1,13 +1,13 @@ array('.$xMin.','.$yMin.','.$xMax.','.$yMax.')'; } } @@ -1074,7 +1080,7 @@ class TCPDF_FONTS { $c = (($i << 8) + $j); if (isset($subsetchars[$c])) { $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']); - $g = ($glyphIndexArray[$idRangeOffset] + $idDelta[$k]) % 65536; + $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k]['idDelta']) % 65536; if ($g < 0) { $g = 0; } @@ -1134,7 +1140,7 @@ class TCPDF_FONTS { $subsetglyphs[$g] = true; } } - } + } break; } case 6: { // Format 6: Trimmed table mapping @@ -1597,9 +1603,9 @@ class TCPDF_FONTS { */ public static function UTF8ArrayToUniArray($ta, $isunicode=true) { if ($isunicode) { - return array_map(array('self', 'unichrUnicode'), $ta); + return array_map(array('TCPDF_FONTS', 'unichrUnicode'), $ta); } - return array_map(array('self', 'unichrASCII'), $ta); + return array_map(array('TCPDF_FONTS', 'unichrASCII'), $ta); } /** @@ -1756,6 +1762,20 @@ class TCPDF_FONTS { return $outstr; } + /** + * Converts UTF-8 character to integer value.
    + * Uses the getUniord() method if the value is not cached. + * @param $uch (string) character string to process. + * @return integer Unicode value + * @public static + */ + public static function uniord($uch) { + if (!isset(self::$cache_uniord[$uch])) { + self::$cache_uniord[$uch] = self::getUniord($uch); + } + return self::$cache_uniord[$uch]; + } + /** * Converts UTF-8 character to integer value.
    * Invalid byte sequences will be replaced with 0xFFFD (replacement character)
    @@ -1789,7 +1809,7 @@ class TCPDF_FONTS { * @author Nicola Asuni * @public static */ - public static function uniord($uch) { + public static function getUniord($uch) { if (function_exists('mb_convert_encoding')) { list(, $char) = @unpack('N', mb_convert_encoding($uch, 'UCS-4BE', 'UTF-8')); if ($char >= 0) { @@ -1862,7 +1882,7 @@ class TCPDF_FONTS { if ($isunicode) { // requires PCRE unicode support turned on $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY); - $carr = array_map(array('self', 'uniord'), $chars); + $carr = array_map(array('TCPDF_FONTS', 'uniord'), $chars); } else { $chars = str_split($str); $carr = array_map('ord', $chars); diff --git a/lib/tcpdf/include/tcpdf_images.php b/lib/tcpdf/include/tcpdf_images.php index 525649cb052..c1e31416bde 100644 --- a/lib/tcpdf/include/tcpdf_images.php +++ b/lib/tcpdf/include/tcpdf_images.php @@ -1,9 +1,9 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.001 + * @version 1.0.002 */ /** @@ -46,7 +46,7 @@ * Static image methods used by the TCPDF class. * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 1.0.000 + * @version 1.0.002 * @author Nicola Asuni - info@tecnick.com */ class TCPDF_IMAGES { @@ -121,7 +121,7 @@ class TCPDF_IMAGES { */ public static function _toPNG($image) { // set temporary image file name - $tempname = TCPDF_STATIC::getObjFilename('png'); + $tempname = TCPDF_STATIC::getObjFilename('img'); // turn off interlaced mode imageinterlace($image, 0); // create temporary PNG image @@ -144,7 +144,7 @@ class TCPDF_IMAGES { * @public static */ public static function _toJPEG($image, $quality) { - $tempname = TCPDF_STATIC::getObjFilename('jpg'); + $tempname = TCPDF_STATIC::getObjFilename('img'); imagejpeg($image, $tempname, $quality); imagedestroy($image); $retvars = self::_parsejpeg($tempname); @@ -235,7 +235,7 @@ class TCPDF_IMAGES { * @public static */ public static function _parsepng($file) { - $f = fopen($file, 'rb'); + $f = @fopen($file, 'rb'); if ($f === false) { // Can't open image file return false; diff --git a/lib/tcpdf/include/tcpdf_static.php b/lib/tcpdf/include/tcpdf_static.php index a6fa611424e..faafdba2efb 100644 --- a/lib/tcpdf/include/tcpdf_static.php +++ b/lib/tcpdf/include/tcpdf_static.php @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.0.031'; + private static $tcpdf_version = '6.0.062'; /** * String alias for total number of pages. @@ -1092,13 +1092,13 @@ class TCPDF_STATIC { /** * Returns a temporary filename for caching object on filesystem. - * @param $name (string) Prefix to add to the file name. + * @param $type (string) Type of file (name of the subdir on the tcpdf cache folder). * @return string filename. * @since 4.5.000 (2008-12-31) * @public static */ - public static function getObjFilename($name) { - return tempnam(K_PATH_CACHE, $name.'_'); + public static function getObjFilename($type='tmp') { + return tempnam(K_PATH_CACHE, '__tcpdf_'.$type.'_'.md5(getmypid().uniqid('', true).rand().microtime(true)).'_'); } /** diff --git a/lib/tcpdf/readme_moodle.txt b/lib/tcpdf/readme_moodle.txt index 3dd9dc59850..47f71a67ac9 100644 --- a/lib/tcpdf/readme_moodle.txt +++ b/lib/tcpdf/readme_moodle.txt @@ -1,10 +1,8 @@ -Description of TCPDF library import 6.0.031 +Description of TCPDF library import 6.0.062 =========================================== -* delete cache/ doc/ examples/ config/tcpdf_config_alt.php config/lang/ images/ +* delete examples/, tools/ and tcpdf_import.php * remove all fonts that were not already present -* remove font/utils/ - -TODO: create some automated script for deleting of extra fonts +* visit http://127.0.0.1/lib/tests/other/pdflibtestpage.php and view the pdf 2011/10/29 ---------- diff --git a/lib/tcpdf/tcpdf.php b/lib/tcpdf/tcpdf.php index de552bcd3ef..74acb26c042 100644 --- a/lib/tcpdf/tcpdf.php +++ b/lib/tcpdf/tcpdf.php @@ -1,13 +1,13 @@ value attribute. -// Patrick Benny for text stretch suggestion on Cell(). -// Johannes Güntert for JavaScript support. -// Denis Van Nuffelen for Dynamic Form. -// Jacek Czekaj for multibyte justification -// Anthony Ferrara for the reintroduction of legacy image methods. -// Sourceforge user 1707880 (hucste) for line-through mode. -// Larry Stanbery for page groups. -// Martin Hall-May for transparency. -// Aaron C. Spike for Polycurve method. -// Mohamad Ali Golkar, Saleh AlMatrafe, Charles Abbott for Arabic and Persian support. -// Moritz Wagner and Andreas Wurmser for graphic functions. -// Andrew Whitehead for core fonts support. -// Esteban Joël Marín for OpenType font conversion. -// Teus Hagen for several suggestions and fixes. -// Yukihiro Nakadaira for CID-0 CJK fonts fixes. -// Kosmas Papachristos for some CSS improvements. -// Marcel Partap for some fixes. -// Won Kyu Park for several suggestions, fixes and patches. -// Dominik Dzienia for QR-code support. -// Laurent Minguet for some suggestions. -// Christian Deligant for some suggestions and fixes. -// Travis Harris for crop mark suggestion. -// Aleksey Kuznetsov for some suggestions and text shadows. -// Jim Hanlon for several suggestions and patches. -// Anyone else that has reported a bug or sent a suggestion. +// * PDF/A-1b support //============================================================+ /** @@ -139,7 +104,7 @@ * Tools to encode your unicode fonts are on fonts/utils directory.

    * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 6.0.031 + * @version 6.0.061 */ // TCPDF configuration @@ -163,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.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 6.0.031 + * @version 6.0.061 * @author Nicola Asuni - info@tecnick.com */ class TCPDF { @@ -2438,13 +2403,27 @@ class TCPDF { $this->lasth = $h; } + /** + * Return the cell height + * @param $fontsize (int) Font size in internal units + * @param $padding (boolean) If true add cell padding + * @public + */ + public function getCellHeight($fontsize, $padding=TRUE) { + $height = ($fontsize * $this->cell_height_ratio); + if ($padding) { + $height += ($this->cell_padding['T'] + $this->cell_padding['B']); + } + return round($height, 3); + } + /** * Reset the last cell height. * @public * @since 5.9.000 (2010-10-03) */ public function resetLastH() { - $this->lasth = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B']; + $this->lasth = $this->getCellHeight($this->FontSize); } /** @@ -3420,7 +3399,7 @@ class TCPDF { } else { $imgy = $this->y; } - $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2); + $cell_height = $this->getCellHeight($headerfont[2] / $this->k); // set starting margin for text data cell if ($this->getRTL()) { $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1); @@ -3656,8 +3635,16 @@ class TCPDF { $this->x += $this->cell_padding['L']; } } + $gvars = $this->getGraphicVars(); + if (!empty($this->theadMargins['gvars'])) { + // set the correct graphic style + $this->setGraphicVars($this->theadMargins['gvars']); + $this->rMargin = $gvars['rMargin']; + $this->lMargin = $gvars['lMargin']; + } // print table header $this->writeHTML($this->thead, false, false, false, false, ''); + $this->setGraphicVars($gvars); // set new top margin to skip the table headers if (!isset($this->theadMargins['top'])) { $this->theadMargins['top'] = $this->tMargin; @@ -3687,6 +3674,16 @@ class TCPDF { return $this->page; } + /** + * Returns the array of spot colors. + * @return (array) Spot colors array. + * @public + * @since 6.0.038 (2013-09-30) + */ + public function getAllSpotColors() { + return $this->spot_colors; + } + /** * Defines a new spot color. * It can be expressed in RGB components or gray scale. @@ -3719,7 +3716,7 @@ class TCPDF { public function setSpotColor($type, $name, $tint=100) { $spotcolor = TCPDF_COLORS::getSpotColor($name, $this->spot_colors); if ($spotcolor === false) { - $this->Error('Undefined spot color: '.$name.', you must add it on the spotcolors.php file.'); + $this->Error('Undefined spot color: '.$name.', you must add it using the AddSpotColor() method.'); } $tint = (max(0, min(100, $tint)) / 100); $pdfcolor = sprintf('/CS%d ', $this->spot_colors[$name]['i']); @@ -5003,7 +5000,7 @@ class TCPDF { $prev_cell_padding = $this->cell_padding; $this->adjustCellPadding($border); if (!$ignore_min_height) { - $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B']; + $min_cell_height = $this->getCellHeight($this->FontSize); if ($h < $min_cell_height) { $h = $min_cell_height; } @@ -5076,7 +5073,7 @@ class TCPDF { $rs = ''; //string to be returned $this->adjustCellPadding($border); if (!$ignore_min_height) { - $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B']; + $min_cell_height = $this->getCellHeight($this->FontSize); if ($h < $min_cell_height) { $h = $min_cell_height; } @@ -6105,11 +6102,14 @@ class TCPDF { * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding. * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) * @return float Return the minimal height needed for multicell method for printing the $txt param. - * @author Alexander Escalona Fernández, Nicola Asuni + * @author Alexander Escalona Fern\E1ndez, Nicola Asuni * @public * @since 4.5.011 */ public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding='', $border=0) { + if ($txt === NULL) { + return 0; + } if ($txt === '') { // empty string return 1; @@ -6140,13 +6140,23 @@ class TCPDF { $length = count($chars); $lastSeparator = -1; for ($i = 0; $i < $length; ++$i) { + $c = $chars[$i]; $charWidth = $charsWidth[$i]; - if (preg_match($this->re_spaces, TCPDF_FONTS::unichr($chars[$i], $this->isunicode))) { + if (($c != 160) + AND (($c == 173) + OR preg_match($this->re_spaces, TCPDF_FONTS::unichr($c, $this->isunicode)) + OR (($c == 45) + AND ($i > 0) AND ($i < ($length - 1)) + AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i - 1)], $this->isunicode)) + AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i + 1)], $this->isunicode)) + ) + ) + ) { $lastSeparator = $i; } - if ((($sum + $charWidth) > $wmax) OR ($chars[$i] == 10)) { + if ((($sum + $charWidth) > $wmax) OR ($c == 10)) { ++$lines; - if ($chars[$i] == 10) { + if ($c == 10) { $lastSeparator = -1; $sum = 0; } elseif ($lastSeparator != -1) { @@ -6212,7 +6222,7 @@ class TCPDF { * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding. * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) * @return float Return the minimal height needed for multicell method for printing the $txt param. - * @author Nicola Asuni, Alexander Escalona Fernández + * @author Nicola Asuni, Alexander Escalona Fern\E1ndez * @public */ public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) { @@ -6224,11 +6234,7 @@ class TCPDF { } $this->adjustCellPadding($border); $lines = $this->getNumLines($txt, $w, $reseth, $autopadding, $cellpadding, $border); - $height = $lines * ($this->FontSize * $this->cell_height_ratio); - if ($autopadding) { - // add top and bottom padding - $height += ($this->cell_padding['T'] + $this->cell_padding['B']); - } + $height = $this->getCellHeight(($lines * $this->FontSize), $autopadding); $this->cell_padding = $prev_cell_padding; $this->lasth = $prev_lasth; return $height; @@ -6314,7 +6320,7 @@ class TCPDF { return ''; } // minimum row height - $row_height = max($h, $this->FontSize * $this->cell_height_ratio); + $row_height = max($h, $this->getCellHeight($this->FontSize)); $start_page = $this->page; $i = 0; // character position $j = 0; // current starting position @@ -6826,8 +6832,9 @@ class TCPDF { $imgdata = TCPDF_STATIC::fileGetContents($file); } } - if (isset($imgdata) AND ($imgdata !== FALSE)) { + if (isset($imgdata) AND ($imgdata !== FALSE) AND (strpos($file, '__tcpdf_img') === FALSE)) { // copy image to cache + $original_file = $file; $file = TCPDF_STATIC::getObjFilename('img'); $fp = fopen($file, 'w'); fwrite($fp, $imgdata); @@ -6836,6 +6843,7 @@ class TCPDF { $imsize = @getimagesize($file); if ($imsize === FALSE) { unlink($file); + $file = $original_file; } else { $this->cached_files[] = $file; } @@ -6847,7 +6855,7 @@ class TCPDF { $ph = $this->getHTMLUnitToUnits($h, 0, $this->pdfunit, true) * $this->imgscale * $this->k; $imsize = array($pw, $ph); } else { - $this->Error('[Image] Unable to get image: '.$file); + $this->Error('[Image] Unable to get the size of the image: '.$file); } } // file hash @@ -6941,17 +6949,19 @@ class TCPDF { $newimage = false; // get existing image data $info = $this->getImageBuffer($file); - if (substr($file, 0, -34) != K_PATH_CACHE.'msk') { + if (strpos($file, '__tcpdf_imgmask_') === FALSE) { // check if the newer image is larger $oldsize = ($info['w'] * $info['h']); if ((($oldsize < $newsize) AND ($resize)) OR (($oldsize < $pixsize) AND (!$resize))) { $newimage = true; } } - } elseif (substr($file, 0, -34) != K_PATH_CACHE.'msk') { - // check for cached images with alpha channel - $tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash; - $tempfile_alpha = K_PATH_CACHE.'mska_'.$filehash; + } elseif (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE)) { + // create temp image file (without alpha channel) + $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash; + // create temp alpha file + $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash; + // check for cached images if (in_array($tempfile_plain, $this->imagekeys)) { // get existing image data $info = $this->getImageBuffer($tempfile_plain); @@ -6986,33 +6996,41 @@ class TCPDF { if ((method_exists('TCPDF_IMAGES', $mtd)) AND (!($resize AND (function_exists($gdfunction) OR extension_loaded('imagick'))))) { // TCPDF image functions $info = TCPDF_IMAGES::$mtd($file); - if (($info === 'pngalpha') OR (isset($info['trns']) AND !empty($info['trns']))) { + if (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE) + AND (($info === 'pngalpha') OR (isset($info['trns']) AND !empty($info['trns'])))) { return $this->ImagePngAlpha($file, $x, $y, $pixw, $pixh, $w, $h, 'PNG', $link, $align, $resize, $dpi, $palign, $filehash); } } - if (!$info) { - if (function_exists($gdfunction)) { + if (($info === false) AND function_exists($gdfunction)) { + try { // GD library $img = $gdfunction($file); - if ($resize) { - $imgr = imagecreatetruecolor($neww, $newh); - if (($type == 'gif') OR ($type == 'png')) { - $imgr = TCPDF_IMAGES::setGDImageTransparency($imgr, $img); - } - imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh); - if (($type == 'gif') OR ($type == 'png')) { - $info = TCPDF_IMAGES::_toPNG($imgr); + if ($img !== false) { + if ($resize) { + $imgr = imagecreatetruecolor($neww, $newh); + if (($type == 'gif') OR ($type == 'png')) { + $imgr = TCPDF_IMAGES::setGDImageTransparency($imgr, $img); + } + imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh); + if (($type == 'gif') OR ($type == 'png')) { + $info = TCPDF_IMAGES::_toPNG($imgr); + } else { + $info = TCPDF_IMAGES::_toJPEG($imgr, $this->jpeg_quality); + } } else { - $info = TCPDF_IMAGES::_toJPEG($imgr, $this->jpeg_quality); - } - } else { - if (($type == 'gif') OR ($type == 'png')) { - $info = TCPDF_IMAGES::_toPNG($img); - } else { - $info = TCPDF_IMAGES::_toJPEG($img, $this->jpeg_quality); + if (($type == 'gif') OR ($type == 'png')) { + $info = TCPDF_IMAGES::_toPNG($img); + } else { + $info = TCPDF_IMAGES::_toJPEG($img, $this->jpeg_quality); + } } } - } elseif (extension_loaded('imagick')) { + } catch(Exception $e) { + $info = false; + } + } + if (($info === false) AND extension_loaded('imagick')) { + try { // ImageMagick library $img = new Imagick(); if ($type == 'SVG') { @@ -7058,17 +7076,17 @@ class TCPDF { } $img->setCompressionQuality($this->jpeg_quality); $img->setImageFormat('jpeg'); - $tempname = TCPDF_STATIC::getObjFilename('jpg'); + $tempname = TCPDF_STATIC::getObjFilename('img'); $img->writeImage($tempname); $info = TCPDF_IMAGES::_parsejpeg($tempname); unlink($tempname); $img->destroy(); - } else { - return; + } catch(Exception $e) { + $info = false; } } if ($info === false) { - //If false, we cannot process image + // unable to process image return; } TCPDF_STATIC::set_mqr($mqr); @@ -7192,61 +7210,85 @@ class TCPDF { * @see Image() */ protected function ImagePngAlpha($file, $x, $y, $wpx, $hpx, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $filehash='') { + // create temp images if (empty($filehash)) { $filehash = md5($this->file_id.$file); } // create temp image file (without alpha channel) - $tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash; + $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash; // create temp alpha file - $tempfile_alpha = K_PATH_CACHE.'mska_'.$filehash; - if (extension_loaded('imagick')) { // ImageMagick extension - // ImageMagick library - $img = new Imagick(); - $img->readImage($file); - // clone image object - $imga = TCPDF_STATIC::objclone($img); - // extract alpha channel - if (method_exists($img, 'setImageAlphaChannel') AND defined('Imagick::ALPHACHANNEL_EXTRACT')) { - $img->setImageAlphaChannel(Imagick::ALPHACHANNEL_EXTRACT); - } else { - $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE); - $img->negateImage(true); - } - $img->setImageFormat('png'); - $img->writeImage($tempfile_alpha); - // remove alpha channel - if (method_exists($imga, 'setImageMatte')) { - $imga->setImageMatte(false); - } else { - $imga->separateImageChannel(39); // 39 = (imagick::CHANNEL_ALL & ~(imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE)); - } - $imga->setImageFormat('png'); - $imga->writeImage($tempfile_plain); - } elseif (function_exists('imagecreatefrompng')) { // GD extension - // generate images - $img = imagecreatefrompng($file); - $imgalpha = imagecreate($wpx, $hpx); - // generate gray scale palette (0 -> 255) - for ($c = 0; $c < 256; ++$c) { - ImageColorAllocate($imgalpha, $c, $c, $c); - } - // extract alpha channel - for ($xpx = 0; $xpx < $wpx; ++$xpx) { - for ($ypx = 0; $ypx < $hpx; ++$ypx) { - $color = imagecolorat($img, $xpx, $ypx); - $alpha = $this->getGDgamma($color); // correct gamma - imagesetpixel($imgalpha, $xpx, $ypx, $alpha); + $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash; + $parsed = false; + $parse_error = ''; + // ImageMagick extension + if (($parsed === false) AND extension_loaded('imagick')) { + try { + // ImageMagick library + $img = new Imagick(); + $img->readImage($file); + // clone image object + $imga = TCPDF_STATIC::objclone($img); + // extract alpha channel + if (method_exists($img, 'setImageAlphaChannel') AND defined('Imagick::ALPHACHANNEL_EXTRACT')) { + $img->setImageAlphaChannel(Imagick::ALPHACHANNEL_EXTRACT); + } else { + $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE); + $img->negateImage(true); } + $img->setImageFormat('png'); + $img->writeImage($tempfile_alpha); + // remove alpha channel + if (method_exists($imga, 'setImageMatte')) { + $imga->setImageMatte(false); + } else { + $imga->separateImageChannel(39); // 39 = (imagick::CHANNEL_ALL & ~(imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE)); + } + $imga->setImageFormat('png'); + $imga->writeImage($tempfile_plain); + $parsed = true; + } catch (Exception $e) { + // Imagemagick fails, try with GD + $parse_error = 'Imagick library error: '.$e->getMessage(); + } + } + // GD extension + if (($parsed === false) AND function_exists('imagecreatefrompng')) { + try { + // generate images + $img = imagecreatefrompng($file); + $imgalpha = imagecreate($wpx, $hpx); + // generate gray scale palette (0 -> 255) + for ($c = 0; $c < 256; ++$c) { + ImageColorAllocate($imgalpha, $c, $c, $c); + } + // extract alpha channel + for ($xpx = 0; $xpx < $wpx; ++$xpx) { + for ($ypx = 0; $ypx < $hpx; ++$ypx) { + $color = imagecolorat($img, $xpx, $ypx); + // get and correct gamma color + $alpha = $this->getGDgamma($img, $color); + imagesetpixel($imgalpha, $xpx, $ypx, $alpha); + } + } + imagepng($imgalpha, $tempfile_alpha); + imagedestroy($imgalpha); + // extract image without alpha channel + $imgplain = imagecreatetruecolor($wpx, $hpx); + imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx); + imagepng($imgplain, $tempfile_plain); + imagedestroy($imgplain); + $parsed = true; + } catch (Exception $e) { + // GD fails + $parse_error = 'GD library error: '.$e->getMessage(); + } + } + if ($parsed === false) { + if (empty($parse_error)) { + $this->Error('TCPDF requires the Imagick or GD extension to handle PNG images with alpha channel.'); + } else { + $this->Error($parse_error); } - imagepng($imgalpha, $tempfile_alpha); - imagedestroy($imgalpha); - // extract image without alpha channel - $imgplain = imagecreatetruecolor($wpx, $hpx); - imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx); - imagepng($imgplain, $tempfile_plain); - imagedestroy($imgplain); - } else { - $this->Error('TCPDF requires the Imagick or GD extension to handle PNG images with alpha channel.'); } // embed mask image $imgmask = $this->Image($tempfile_alpha, $x, $y, $w, $h, 'PNG', '', '', $resize, $dpi, '', true, false); @@ -7259,26 +7301,25 @@ class TCPDF { /** * Get the GD-corrected PNG gamma value from alpha color + * @param $img (int) GD image Resource ID. * @param $c (int) alpha color * @protected * @since 4.3.007 (2008-12-04) */ - 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); + protected function getGDgamma($img, $c) { + if (!isset($this->gdgammacache['#'.$c])) { + $colors = imagecolorsforindex($img, $c); // GD alpha is only 7 bit (0 -> 127) - $alpha = (((127 - $alpha) / 127) * 255); + $this->gdgammacache['#'.$c] = (((127 - $colors['alpha']) / 127) * 255); // correct gamma - $this->gdgammacache["'".$c."'"] = (pow(($alpha / 255), 2.2) * 255); + $this->gdgammacache['#'.$c] = (pow(($this->gdgammacache['#'.$c] / 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."'"]; + return $this->gdgammacache['#'.$c]; } /** @@ -7522,7 +7563,7 @@ class TCPDF { $byterange .= str_repeat(' ', ($byterange_string_len - strlen($byterange))); $pdfdoc = str_replace(TCPDF_STATIC::$byterange_string, $byterange, $pdfdoc); // write the document to a temporary folder - $tempdoc = TCPDF_STATIC::getObjFilename('tmppdf'); + $tempdoc = TCPDF_STATIC::getObjFilename('doc'); $f = fopen($tempdoc, 'wb'); if (!$f) { $this->Error('Unable to create temporary file: '.$tempdoc); @@ -7531,7 +7572,7 @@ class TCPDF { fwrite($f, $pdfdoc, $pdfdoc_length); fclose($f); // get digital signature via openssl library - $tempsign = TCPDF_STATIC::getObjFilename('tmpsig'); + $tempsign = TCPDF_STATIC::getObjFilename('sig'); if (empty($this->signature_data['extracerts'])) { openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED); } else { @@ -7697,7 +7738,7 @@ class TCPDF { // remove buffer file from cache unlink($this->buffer); } - if ($destroyall AND isset($this->cached_files) AND !empty($this->cached_files)) { + if ($destroyall AND !empty($this->cached_files)) { // remove cached files foreach ($this->cached_files as $cachefile) { if (is_file($cachefile)) { @@ -7846,6 +7887,7 @@ class TCPDF { $groupnum = 0; $ptgu = 1; $ptga = 1; + $ptg_num_chars = 1; for ($n = 1; $n <= $num_pages; ++$n) { // get current page $temppage = $this->getPageBuffer($n); @@ -9393,7 +9435,7 @@ class TCPDF { } if (!TCPDF_STATIC::empty_string($this->keywords)) { // Keywords associated with the document. - $out .= ' /Keywords '.$this->_textstring($this->keywords.' TCPDF', $oid); + $out .= ' /Keywords '.$this->_textstring($this->keywords, $oid); } if (!TCPDF_STATIC::empty_string($this->creator)) { // If the document was converted to PDF from another format, the name of the conforming product that created the original document from which it was converted. @@ -9462,7 +9504,7 @@ class TCPDF { $xmp .= "\t\t\t".''."\n"; $xmp .= "\t\t\t".''."\n"; $xmp .= "\t\t\t\t".''."\n"; - $xmp .= "\t\t\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).' TCPDF'."\n"; + $xmp .= "\t\t\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).''."\n"; $xmp .= "\t\t\t\t".''."\n"; $xmp .= "\t\t\t".''."\n"; $xmp .= "\t\t".''."\n"; @@ -9485,7 +9527,7 @@ class TCPDF { $xmp .= "\t\t\t".''.$doccreationdate.''."\n"; $xmp .= "\t\t".''."\n"; $xmp .= "\t\t".''."\n"; - $xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).' TCPDF'."\n"; + $xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).''."\n"; $xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML(TCPDF_STATIC::getTCPDFProducer()).''."\n"; $xmp .= "\t\t".''."\n"; $xmp .= "\t\t".''."\n"; @@ -10763,7 +10805,7 @@ class TCPDF { // envelope data $envelope = $seed.$pkpermissions; // write the envelope data to a temporary file - $tempkeyfile = TCPDF_STATIC::getObjFilename('tmpkey'); + $tempkeyfile = TCPDF_STATIC::getObjFilename('key'); $f = fopen($tempkeyfile, 'wb'); if (!$f) { $this->Error('Unable to create temporary key file: '.$tempkeyfile); @@ -10771,7 +10813,7 @@ class TCPDF { $envelope_length = strlen($envelope); fwrite($f, $envelope, $envelope_length); fclose($f); - $tempencfile = TCPDF_STATIC::getObjFilename('tmpenc'); + $tempencfile = TCPDF_STATIC::getObjFilename('enc'); if (!openssl_pkcs7_encrypt($tempkeyfile, $tempencfile, $pubkey['c'], array(), PKCS7_BINARY | PKCS7_DETACHED)) { $this->Error('Unable to encrypt the file: '.$tempkeyfile); } @@ -11395,7 +11437,7 @@ class TCPDF { } /** - * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bézier control points. + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bezier control points. * The new current point shall be (x3, y3). * @param $x1 (float) Abscissa of control point 1. * @param $y1 (float) Ordinate of control point 1. @@ -11413,7 +11455,7 @@ class TCPDF { } /** - * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bézier control points. + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bezier control points. * The new current point shall be (x3, y3). * @param $x2 (float) Abscissa of control point 2. * @param $y2 (float) Ordinate of control point 2. @@ -11429,7 +11471,7 @@ class TCPDF { } /** - * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bézier control points. + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bezier control points. * The new current point shall be (x3, y3). * @param $x1 (float) Abscissa of control point 1. * @param $y1 (float) Ordinate of control point 1. @@ -11668,6 +11710,9 @@ class TCPDF { * @since 4.9.019 (2010-04-26) */ protected function _outellipticalarc($xc, $yc, $rx, $ry, $xang=0, $angs=0, $angf=360, $pie=false, $nc=2, $startpoint=true, $ccw=true, $svg=false) { + if (($rx <= 0) OR ($ry < 0)) { + return; + } $k = $this->k; if ($nc < 2) { $nc = 2; @@ -12221,7 +12266,7 @@ class TCPDF { /** * Insert Named Destinations. * @protected - * @author Johannes Güntert, Nicola Asuni + * @author Johannes G\FCntert, Nicola Asuni * @since 5.9.098 (2011-06-23) */ protected function _putdests() { @@ -12449,7 +12494,7 @@ class TCPDF { * Adds a javascript * @param $script (string) Javascript code * @public - * @author Johannes Güntert, Nicola Asuni + * @author Johannes G\FCntert, Nicola Asuni * @since 2.1.002 (2008-02-12) */ public function IncludeJS($script) { @@ -12478,7 +12523,7 @@ class TCPDF { /** * Create a javascript PDF string. * @protected - * @author Johannes Güntert, Nicola Asuni + * @author Johannes G\FCntert, Nicola Asuni * @since 2.1.002 (2008-02-12) */ protected function _putjavascript() { @@ -13613,7 +13658,9 @@ class TCPDF { $out = '<< /Type /OCG'; $out .= ' /Name '.$this->_textstring($layer['name'], $this->pdflayers[$key]['objid']); $out .= ' /Usage <<'; - $out .= ' /Print <>'; + if (isset($layer['print']) AND ($layer['print'] !== NULL)) { + $out .= ' /Print <>'; + } $out .= ' /View <>'; $out .= ' >> >>'; $out .= "\n".'endobj'; @@ -13624,7 +13671,7 @@ class TCPDF { /** * Start a new pdf layer. * @param $name (string) Layer name (only a-z letters and numbers). Leave empty for automatic name. - * @param $print (boolean) Set to true to print this layer. + * @param $print (boolean|null) Set to TRUE to print this layer, FALSE to not print and NULL to not set this option * @param $view (boolean) Set to true to view this layer. * @public * @since 5.9.102 (2011-07-13) @@ -13927,12 +13974,25 @@ class TCPDF { * @param $h (float) height of the rectangle. * @param $transition (boolean) if true prints tcolor transitions to white. * @param $vertical (boolean) if true prints bar vertically. - * @param $colors (string) colors to print, one letter per color separated by comma (for example 'A,W,R,G,B,C,M,Y,K'): A=black, W=white, R=red, G=green, B=blue, C=cyan, M=magenta, Y=yellow, K=black. + * @param $colors (string) colors to print separated by comma. Valid values are: A,W,R,G,B,C,M,Y,K,RGB,CMYK,ALL,ALLSPOT,. Where: A = grayscale black, W = grayscale white, R = RGB red, G RGB green, B RGB blue, C = CMYK cyan, M = CMYK magenta, Y = CMYK yellow, K = CMYK key/black, RGB = RGB registration color, CMYK = CMYK registration color, ALL = Spot registration color, ALLSPOT = print all defined spot colors, = name of the spot color to print. * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public */ public function colorRegistrationBar($x, $y, $w, $h, $transition=true, $vertical=false, $colors='A,R,G,B,C,M,Y,K') { + if (strpos($colors, 'ALLSPOT') !== false) { + // expand spot colors + $spot_colors = ''; + foreach ($this->spot_colors as $spot_color_name => $v) { + $spot_colors .= ','.$spot_color_name; + } + if (!empty($spot_colors)) { + $spot_colors = substr($spot_colors, 1); + $colors = str_replace('ALLSPOT', $spot_colors, $colors); + } else { + $colors = str_replace('ALLSPOT', 'NONE', $colors); + } + } $bars = explode(',', $colors); $numbars = count($bars); // number of bars to print if ($numbars <= 0) { @@ -13957,67 +14017,93 @@ class TCPDF { foreach ($bars as $col) { switch ($col) { // set transition colors - case 'A': { // BLACK + case 'A': { // BLACK (GRAYSCALE) $col_a = array(255); $col_b = array(0); break; } - case 'W': { // WHITE + case 'W': { // WHITE (GRAYSCALE) $col_a = array(0); $col_b = array(255); break; } - case 'R': { // R + case 'R': { // RED (RGB) $col_a = array(255,255,255); $col_b = array(255,0,0); break; } - case 'G': { // G + case 'G': { // GREEN (RGB) $col_a = array(255,255,255); $col_b = array(0,255,0); break; } - case 'B': { // B + case 'B': { // BLUE (RGB) $col_a = array(255,255,255); $col_b = array(0,0,255); break; } - case 'C': { // C + case 'C': { // CYAN (CMYK) $col_a = array(0,0,0,0); $col_b = array(100,0,0,0); break; } - case 'M': { // M + case 'M': { // MAGENTA (CMYK) $col_a = array(0,0,0,0); $col_b = array(0,100,0,0); break; } - case 'Y': { // Y + case 'Y': { // YELLOW (CMYK) $col_a = array(0,0,0,0); $col_b = array(0,0,100,0); break; } - case 'K': { // K + case 'K': { // KEY - BLACK (CMYK) $col_a = array(0,0,0,0); $col_b = array(0,0,0,100); break; } - default: { // GRAY - $col_a = array(255); - $col_b = array(0); + case 'RGB': { // BLACK REGISTRATION (RGB) + $col_a = array(255,255,255); + $col_b = array(0,0,0); + break; + } + case 'CMYK': { // BLACK REGISTRATION (CMYK) + $col_a = array(0,0,0,0); + $col_b = array(100,100,100,100); + break; + } + case 'ALL': { // SPOT COLOR REGISTRATION + $col_a = array(0,0,0,0,'None'); + $col_b = array(100,100,100,100,'All'); + break; + } + case 'NONE': { // SKIP THIS COLOR + $col_a = array(0,0,0,0,'None'); + $col_b = array(0,0,0,0,'None'); + break; + } + default: { // SPECIFIC SPOT COLOR NAME + $col_a = array(0,0,0,0,'None'); + $col_b = TCPDF_COLORS::getSpotColor($col, $this->spot_colors); + if ($col_b === false) { + // in case of error defaults to the registration color + $col_b = array(100,100,100,100,'All'); + } break; } } - if ($transition) { - // color gradient - $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords); - } else { - // color rectangle - $this->SetFillColorArray($col_b); - $this->Rect($xb, $yb, $wb, $hb, 'F', array()); + if ($col != 'NONE') { + if ($transition) { + // color gradient + $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords); + } else { + $this->SetFillColorArray($col_b); + // colored rectangle + $this->Rect($xb, $yb, $wb, $hb, 'F', array()); + } + $xb += $xd; + $yb += $yd; } - $xb += $xd; - $yb += $yd; } } @@ -14028,12 +14114,12 @@ class TCPDF { * @param $w (float) width of the crop mark. * @param $h (float) height of the crop mark. * @param $type (string) type of crop mark, one symbol per type separated by comma: T = TOP, F = BOTTOM, L = LEFT, R = RIGHT, TL = A = TOP-LEFT, TR = B = TOP-RIGHT, BL = C = BOTTOM-LEFT, BR = D = BOTTOM-RIGHT. - * @param $color (array) crop mark color (default black). + * @param $color (array) crop mark color (default spot registration color). * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public */ - public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(0,0,0)) { + public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(100,100,100,100,'All')) { $this->SetLineStyle(array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $color)); $type = strtoupper($type); $type = preg_replace('/[^A-Z\-\,]*/', '', $type); @@ -14098,30 +14184,70 @@ class TCPDF { * @param $y (float) ordinate of the registration mark center. * @param $r (float) radius of the crop mark. * @param $double (boolean) if true print two concentric crop marks. - * @param $cola (array) crop mark color (default black). - * @param $colb (array) second crop mark color. + * @param $cola (array) crop mark color (default spot registration color 'All'). + * @param $colb (array) second crop mark color (default spot registration color 'None'). * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public */ - public function registrationMark($x, $y, $r, $double=false, $cola=array(0,0,0), $colb=array(255,255,255)) { - $line_style = array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola); + public function registrationMark($x, $y, $r, $double=false, $cola=array(100,100,100,100,'All'), $colb=array(0,0,0,0,'None')) { + $line_style = array('width' => max((0.5 / $this->k),($r / 30)), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola); $this->SetFillColorArray($cola); $this->PieSector($x, $y, $r, 90, 180, 'F'); $this->PieSector($x, $y, $r, 270, 360, 'F'); $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8); if ($double) { - $r2 = $r * 0.5; + $ri = $r * 0.5; $this->SetFillColorArray($colb); - $this->PieSector($x, $y, $r2, 90, 180, 'F'); - $this->PieSector($x, $y, $r2, 270, 360, 'F'); + $this->PieSector($x, $y, $ri, 90, 180, 'F'); + $this->PieSector($x, $y, $ri, 270, 360, 'F'); $this->SetFillColorArray($cola); - $this->PieSector($x, $y, $r2, 0, 90, 'F'); - $this->PieSector($x, $y, $r2, 180, 270, 'F'); - $this->Circle($x, $y, $r2, 0, 360, 'C', $line_style, array(), 8); + $this->PieSector($x, $y, $ri, 0, 90, 'F'); + $this->PieSector($x, $y, $ri, 180, 270, 'F'); + $this->Circle($x, $y, $ri, 0, 360, 'C', $line_style, array(), 8); } } + /** + * Paints a CMYK registration mark + * @param $x (float) abscissa of the registration mark center. + * @param $y (float) ordinate of the registration mark center. + * @param $r (float) radius of the crop mark. + * @author Nicola Asuni + * @since 6.0.038 (2013-09-30) + * @public + */ + public function registrationMarkCMYK($x, $y, $r) { + // line width + $lw = max((0.5 / $this->k),($r / 8)); + // internal radius + $ri = ($r * 0.6); + // external radius + $re = ($r * 1.3); + // Cyan + $this->SetFillColorArray(array(100,0,0,0)); + $this->PieSector($x, $y, $ri, 270, 360, 'F'); + // Magenta + $this->SetFillColorArray(array(0,100,0,0)); + $this->PieSector($x, $y, $ri, 0, 90, 'F'); + // Yellow + $this->SetFillColorArray(array(0,0,100,0)); + $this->PieSector($x, $y, $ri, 90, 180, 'F'); + // Key - black + $this->SetFillColorArray(array(0,0,0,100)); + $this->PieSector($x, $y, $ri, 180, 270, 'F'); + // registration color + $line_style = array('width' => $lw, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(100,100,100,100,'All')); + $this->SetFillColorArray(array(100,100,100,100,'All')); + // external circle + $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8); + // cross lines + $this->Line($x, ($y - $re), $x, ($y - $ri)); + $this->Line($x, ($y + $ri), $x, ($y + $re)); + $this->Line(($x - $re), $y, ($x - $ri), $y); + $this->Line(($x + $ri), $y, ($x + $re), $y); + } + /** * Paints a linear colour gradient. * @param $x (float) abscissa of the top left corner of the rectangle. @@ -14131,7 +14257,7 @@ class TCPDF { * @param $col1 (array) first color (Grayscale, RGB or CMYK components). * @param $col2 (array) second color (Grayscale, RGB or CMYK components). * @param $coords (array) array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0). - * @author Andreas Würmser, Nicola Asuni + * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ @@ -14149,7 +14275,7 @@ class TCPDF { * @param $col1 (array) first color (Grayscale, RGB or CMYK components). * @param $col2 (array) second color (Grayscale, RGB or CMYK components). * @param $coords (array) array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined. - * @author Andreas Würmser, Nicola Asuni + * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ @@ -14172,7 +14298,7 @@ class TCPDF { * @param $coords_min (array) minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0 * @param $coords_max (array) maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1 * @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts. - * @author Andreas Würmser, Nicola Asuni + * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ @@ -14264,7 +14390,7 @@ class TCPDF { * @param $y (float) ordinate of the top left corner of the rectangle. * @param $w (float) width of the rectangle. * @param $h (float) height of the rectangle. - * @author Andreas Würmser, Nicola Asuni + * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @protected */ @@ -14310,6 +14436,7 @@ class TCPDF { $numcolspace = count($stops[0]['color']); $bcolor = array_values($background); switch($numcolspace) { + case 5: // SPOT case 4: { // CMYK $this->gradients[$n]['colspace'] = 'DeviceCMYK'; if (!empty($background)) { @@ -14324,7 +14451,7 @@ class TCPDF { } break; } - case 1: { // Gray scale + case 1: { // GRAY SCALE $this->gradients[$n]['colspace'] = 'DeviceGray'; if (!empty($background)) { $this->gradients[$n]['background'] = sprintf('%F', $bcolor[0]/255); @@ -14366,6 +14493,7 @@ class TCPDF { // set colors $color = array_values($stop['color']); switch($numcolspace) { + case 5: // SPOT case 4: { // CMYK $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F %F', $color[0]/100, $color[1]/100, $color[2]/100, $color[3]/100); break; @@ -14374,7 +14502,7 @@ class TCPDF { $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F', $color[0]/255, $color[1]/255, $color[2]/255); break; } - case 1: { // Gray scale + case 1: { // GRAY SCALE $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F', $color[0]/255); break; } @@ -15174,7 +15302,7 @@ class TCPDF { } } } - $text_height = ($this->cell_height_ratio * $fontsize / $this->k); + $text_height = $this->getCellHeight($fontsize / $this->k); // height if (($h === '') OR ($h <= 0)) { // set default height @@ -15185,7 +15313,7 @@ class TCPDF { // try to reduce font or padding to fit barcode on available height if ($text_height > $h) { $fontsize = (($h * $this->k) / (4 * $this->cell_height_ratio)); - $text_height = ($this->cell_height_ratio * $fontsize / $this->k); + $text_height = $this->getCellHeight($fontsize / $this->k); $this->SetFont($style['font'], '', $fontsize); } if ($vpadding > 0) { @@ -16206,6 +16334,8 @@ class TCPDF { $html = preg_replace('/'.$this->re_space['p'].'+/'.$this->re_space['m'], chr(32), $html); // replace multiple spaces with a single space // trim string $html = $this->stringTrim($html); + // fix br tag after li + $html = preg_replace('/
  • ]*)>/', '
  • ', $html); // fix first image tag alignment $html = preg_replace('/^
    rtl?'rtl':'ltr'; $thead = false; // true when we are inside the THEAD tag @@ -16293,6 +16424,7 @@ class TCPDF { $dom[$key]['fgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fgcolor']; $dom[$key]['strokecolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['strokecolor']; $dom[$key]['align'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['align']; + $dom[$key]['text-transform'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['text-transform']; $dom[$key]['dir'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['dir']; if (isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'])) { $dom[$key]['listtype'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype']; @@ -16364,6 +16496,7 @@ class TCPDF { $dom[$key]['align'] = $dom[$parentkey]['align']; $dom[$key]['listtype'] = $dom[$parentkey]['listtype']; $dom[$key]['text-indent'] = $dom[$parentkey]['text-indent']; + $dom[$key]['text-transform'] = $dom[$parentkey]['text-transform']; $dom[$key]['border'] = array(); $dom[$key]['dir'] = $dom[$parentkey]['dir']; } @@ -16414,6 +16547,10 @@ class TCPDF { $dom[$key]['text-indent'] = $dom[$parentkey]['text-indent']; } } + // text-transform + if (isset($dom[$key]['style']['text-transform'])) { + $dom[$key]['text-transform'] = $dom[$key]['style']['text-transform']; + } // font size if (isset($dom[$key]['style']['font-size'])) { $fsize = trim($dom[$key]['style']['font-size']); @@ -16427,7 +16564,7 @@ class TCPDF { if (isset($dom[$key]['style']['letter-spacing'])) { $dom[$key]['letter-spacing'] = $this->getCSSFontSpacing($dom[$key]['style']['letter-spacing'], $dom[$parentkey]['letter-spacing']); } - // line-height + // line-height (internally is the cell height ratio) if (isset($dom[$key]['style']['line-height'])) { $lineheight = trim($dom[$key]['style']['line-height']); switch ($lineheight) { @@ -16436,11 +16573,18 @@ class TCPDF { $dom[$key]['line-height'] = $dom[0]['line-height']; break; } + case 'inherit': { + $dom[$key]['line-height'] = $dom[$parentkey]['line-height']; + } default: { if (is_numeric($lineheight)) { - $lineheight = $lineheight * 100; + // convert to percentage of font height + $lineheight = ($lineheight * 100).'%'; } $dom[$key]['line-height'] = $this->getHTMLUnitToUnits($lineheight, 1, '%', true); + if (substr($lineheight, -1) !== '%') { + $dom[$key]['line-height'] = (($dom[$key]['line-height'] - $this->cell_padding['T'] - $this->cell_padding['B']) / $dom[$key]['fontsize']); + } } } } @@ -16706,7 +16850,7 @@ class TCPDF { if (($dom[$key]['value'] == 'pre') OR ($dom[$key]['value'] == 'tt')) { $dom[$key]['fontname'] = $this->default_monospaced_font; } - if (($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) { + if (!empty($dom[$key]['value']) AND ($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) { // headings h1, h2, h3, h4, h5, h6 if (!isset($dom[$key]['attribute']['size']) AND !isset($dom[$key]['style']['font-size'])) { $headsize = (4 - intval($dom[$key]['value']{1})) * 2; @@ -16799,10 +16943,33 @@ class TCPDF { // text $dom[$key]['tag'] = false; $dom[$key]['block'] = false; - //$element = str_replace(' ', TCPDF_FONTS::unichr(160, $this->isunicode), $element); - $dom[$key]['value'] = stripslashes($this->unhtmlentities($element)); $dom[$key]['parent'] = end($level); $dom[$key]['dir'] = $dom[$dom[$key]['parent']]['dir']; + if (!empty($dom[$dom[$key]['parent']]['text-transform'])) { + // text-transform for unicode requires mb_convert_case (Multibyte String Functions) + if (function_exists('mb_convert_case')) { + $ttm = array('capitalize' => MB_CASE_TITLE, 'uppercase' => MB_CASE_UPPER, 'lowercase' => MB_CASE_LOWER); + if (isset($ttm[$dom[$dom[$key]['parent']]['text-transform']])) { + $element = mb_convert_case($element, $ttm[$dom[$dom[$key]['parent']]['text-transform']], $this->encoding); + } + } elseif (!$this->isunicode) { + switch ($dom[$dom[$key]['parent']]['text-transform']) { + case 'capitalize': { + $element = ucwords(strtolower($element)); + break; + } + case 'uppercase': { + $element = strtoupper($element); + break; + } + case 'lowercase': { + $element = strtolower($element); + break; + } + } + } + } + $dom[$key]['value'] = stripslashes($this->unhtmlentities($element)); } ++$elkey; ++$key; @@ -16968,28 +17135,22 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $dom = $this->getHtmlDomArray($html); $maxel = count($dom); $key = 0; - $hidden_node_key = -1; while ($key < $maxel) { - if ($dom[$key]['tag']) { - if ($dom[$key]['opening']) { - if (($hidden_node_key <= 0) AND $dom[$key]['hide']) { - // store the node key - $hidden_node_key = $key; + if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND $dom[$key]['hide']) { + // store the node key + $hidden_node_key = $key; + if ($dom[$key]['self']) { + // skip just this self-closing tag + ++$key; + } else { + // skip this and all children tags + while (($key < $maxel) AND (!$dom[$key]['tag'] OR $dom[$key]['opening'] OR ($dom[$key]['parent'] != $hidden_node_key))) { + // skip hidden objects + ++$key; } - } elseif (($hidden_node_key > 0) AND ($dom[$key]['parent'] == $hidden_node_key)) { - // we have reached the closing tag of the hidden node - $hidden_node_key = 0; + ++$key; } } - if ($hidden_node_key >= 0) { - // skip this node - ++$key; - if ($hidden_node_key == 0) { - // reset hidden mode - $hidden_node_key = -1; - } - continue; - } if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) { // check for pagebreak if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) { @@ -17183,18 +17344,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $startliney = $this->y; $this->newline = false; } - $this->y += ((($curfontsize * $this->cell_height_ratio / $this->k) + $curfontascent - $curfontdescent) / 2) - $imgh; + $this->y += (($this->getCellHeight($curfontsize / $this->k) + $curfontascent - $curfontdescent) / 2) - $imgh; $minstartliney = min($this->y, $minstartliney); - $maxbottomliney = ($startliney + ($this->FontSize * $this->cell_height_ratio)); + $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize)); } } elseif (isset($dom[$key]['fontname']) OR isset($dom[$key]['fontstyle']) OR isset($dom[$key]['fontsize']) OR isset($dom[$key]['line-height'])) { // account for different font size $pfontname = $curfontname; $pfontstyle = $curfontstyle; $pfontsize = $curfontsize; - $fontname = isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname; - $fontstyle = isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle; - $fontsize = isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize; + $fontname = (isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname); + $fontstyle = (isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle); + $fontsize = (isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize); $fontascent = $this->getFontAscent($fontname, $fontstyle, $fontsize); $fontdescent = $this->getFontDescent($fontname, $fontstyle, $fontsize); if (($fontname != $curfontname) OR ($fontstyle != $curfontstyle) OR ($fontsize != $curfontsize) @@ -17256,10 +17417,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $current_line_align_data = array($key, $minstartliney, $maxbottomliney); if (isset($line_align_data) AND (($line_align_data[0] == ($key - 1)) OR (($line_align_data[0] == ($key - 2)) AND (isset($dom[($key - 1)])) AND (preg_match('/^([\s]+)$/', $dom[($key - 1)]['value']) > 0)))) { $minstartliney = min($this->y, $line_align_data[1]); - $maxbottomliney = max(($this->y + (($fontsize * $this->cell_height_ratio) / $this->k)), $line_align_data[2]); + $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $line_align_data[2]); } else { $minstartliney = min($this->y, $minstartliney); - $maxbottomliney = max(($this->y + (($fontsize * $this->cell_height_ratio) / $this->k)), $maxbottomliney); + $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $maxbottomliney); } $line_align_data = $current_line_align_data; } @@ -17476,7 +17637,6 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($this->isRTLTextDir()) { $textpos = $this->wPt; } - global $spacew; while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) { // check if we are inside a string section '[( ... )]' $stroffset = strpos($pmid, '[(', $offset); @@ -17522,6 +17682,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: case 'l': { // get current X position preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches); + if (!isset($xmatches[1])) { + break; + } $currentxpos = $xmatches[1]; $textpos = $currentxpos; if (($strcount <= $maxkk) AND ($strpiece[2][0] == 'Td')) { @@ -17532,10 +17695,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: ++$strcount; } // justify block - $pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', - create_function('$matches', 'global $spacew; - $newx = sprintf("%F",(floatval($matches[1]) + $spacew)); - return "".$newx." ".$matches[2]." x*#!#*x".$matches[3].$matches[4];'), $pmid, 1); + if (preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $pmatch) == 1) { + $newpmid = sprintf('%F',(floatval($pmatch[1]) + $spacew)).' '.$pmatch[2].' x*#!#*x'.$pmatch[3].$pmatch[4]; + $pmid = str_replace($pmatch[0], $newpmid, $pmid); + unset($pmatch, $newpmid); + } break; } case 're': { @@ -17545,8 +17709,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: continue; } preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $xmatches); + if (!isset($xmatches[1])) { + break; + } $currentxpos = $xmatches[1]; - global $x_diff, $w_diff; $x_diff = 0; $w_diff = 0; if ($this->isRTLTextDir()) { // RTL @@ -17574,24 +17740,31 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } } - $pmid = preg_replace_callback('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', - create_function('$matches', 'global $x_diff, $w_diff; - $newx = sprintf("%F",(floatval($matches[1]) + $x_diff)); - $neww = sprintf("%F",(floatval($matches[3]) + $w_diff)); - return "".$newx." ".$matches[2]." ".$neww." ".$matches[4]." x*#!#*x".$matches[5].$matches[6];'), $pmid, 1); + if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $pmatch) == 1) { + $newx = sprintf('%F',(floatval($pmatch[1]) + $x_diff)); + $neww = sprintf('%F',(floatval($pmatch[3]) + $w_diff)); + $newpmid = $newx.' '.$pmatch[2].' '.$neww.' '.$pmatch[4].' x*#!#*x'.$pmatch[5].$pmatch[6]; + $pmid = str_replace($pmatch[0], $newpmid, $pmid); + unset($pmatch, $newpmid, $newx, $neww); + } break; } case 'c': { // get current X position preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $xmatches); + if (!isset($xmatches[1])) { + break; + } $currentxpos = $xmatches[1]; // justify block - $pmid = preg_replace_callback('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$xmatches[4].')[\s]('.$xmatches[5].')[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', - create_function('$matches', 'global $spacew; - $newx1 = sprintf("%F",(floatval($matches[1]) + $spacew)); - $newx2 = sprintf("%F",(floatval($matches[3]) + $spacew)); - $newx3 = sprintf("%F",(floatval($matches[5]) + $spacew)); - return "".$newx1." ".$matches[2]." ".$newx2." ".$matches[4]." ".$newx3." ".$matches[6]." x*#!#*x".$matches[7].$matches[8];'), $pmid, 1); + if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$xmatches[4].')[\s]('.$xmatches[5].')[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $pmatch) == 1) { + $newx1 = sprintf('%F',(floatval($pmatch[1]) + $spacew)); + $newx2 = sprintf('%F',(floatval($pmatch[3]) + $spacew)); + $newx3 = sprintf('%F',(floatval($pmatch[5]) + $spacew)); + $newpmid = $newx1.' '.$pmatch[2].' '.$newx2.' '.$pmatch[4].' '.$newx3.' '.$pmatch[6].' x*#!#*x'.$pmatch[7].$pmatch[8]; + $pmid = str_replace($pmatch[0], $newpmid, $pmid); + unset($pmatch, $newpmid, $newx1, $newx2, $newx3); + } break; } } @@ -17634,15 +17807,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // word spacing is affected by stretching $spacew /= ($this->font_stretching / 100); } - $pmidtemp = $pmid; // escape special characters - $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp); - $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp); - $pmid = preg_replace_callback("/\[\(([^\)]*)\)\]/x", - create_function('$matches', 'global $spacew; - $matches[1] = str_replace("#!#OP#!#", "(", $matches[1]); - $matches[1] = str_replace("#!#CP#!#", ")", $matches[1]); - return "[(".str_replace(chr(0).chr(32), ") ".sprintf("%F", $spacew)." (", $matches[1]).")]";'), $pmidtemp); + $pos = 0; + $pmid = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmid); + $pmid = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmid); + if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmid, $pamatch) > 0) { + foreach($pamatch[0] as $pk => $pmatch) { + $replace = $pamatch[1][$pk]; + $replace = str_replace('#!#OP#!#', '(', $replace); + $replace = str_replace('#!#CP#!#', ')', $replace); + $newpmid = '[('.str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacew).' (', $replace).')]'; + $pos = strpos($pmid, $pmatch, $pos); + if ($pos !== FALSE) { + $pmid = substr_replace($pmid, $newpmid, $pos, strlen($pmatch)); + } + ++$pos; + } + unset($pamatch); + } if ($this->inxobj) { // we are inside an XObject template $this->xobjects[$this->xobjid]['outdata'] = $pstart."\n".$pmid."\n".$pend; @@ -17708,7 +17890,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $startliney -= (($this->FontSizePt / 0.7) / $this->k); } else { $minstartliney = $startliney; - $maxbottomliney = ($this->y + (($fontsize * $this->cell_height_ratio) / $this->k)); + $maxbottomliney = ($this->y + $this->getCellHeight($fontsize / $this->k)); } $startlinepage = $this->page; if (isset($endlinepos) AND (!$pbrk)) { @@ -18043,16 +18225,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->SetFont($pfontname, $pfontstyle, $pfontsize); $this->resetLastH(); $minstartliney = $this->y; - $maxbottomliney = ($startliney + ($this->FontSize * $this->cell_height_ratio)); - $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize); + $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize)); + if (is_numeric($pfontsize) AND ($pfontsize > 0)) { + $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize); + } $this->SetFont($curfontname, $curfontstyle, $curfontsize); $this->resetLastH(); if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) { $pfontascent = $this->getFontAscent($pfontname, $pfontstyle, $pfontsize); $pfontdescent = $this->getFontDescent($pfontname, $pfontstyle, $pfontsize); - $this->y += ((($pfontsize - $curfontsize) * $this->cell_height_ratio / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2; + $this->y += ($this->getCellHeight(($pfontsize - $curfontsize) / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2; $minstartliney = min($this->y, $minstartliney); - $maxbottomliney = max(($this->y + (($pfontsize * $this->cell_height_ratio) / $this->k)), $maxbottomliney); + $maxbottomliney = max(($this->y + $this->getCellHeight($pfontsize / $this->k)), $maxbottomliney); } } // text @@ -18425,9 +18609,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($this->tagvspaces[$tag['value']][0]['h']) AND ($this->tagvspaces[$tag['value']][0]['h'] >= 0)) { $cur_h = $this->tagvspaces[$tag['value']][0]['h']; } elseif (isset($tag['fontsize'])) { - $cur_h = ($tag['fontsize'] / $this->k) * $this->cell_height_ratio; + $cur_h = $this->getCellHeight($tag['fontsize'] / $this->k); } else { - $cur_h = $this->FontSize * $this->cell_height_ratio; + $cur_h = $this->getCellHeight($this->FontSize); } if (isset($this->tagvspaces[$tag['value']][0]['n'])) { $n = $this->tagvspaces[$tag['value']][0]['n']; @@ -18443,9 +18627,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } if (($this->htmlvspace <= 0) AND ($n > 0)) { if (isset($parent['fontsize'])) { - $hbz = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio); + $hbz = $this->getCellHeight($tag['fontsize'] / $this->k); } else { - $hbz = $this->FontSize * $this->cell_height_ratio; + $hbz = $this->getCellHeight($this->FontSize); } } if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == 'table')) { @@ -18472,6 +18656,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->theadMargins['rmargin'] = $this->rMargin; $this->theadMargins['page'] = $this->page; $this->theadMargins['cell'] = $cell; + $this->theadMargins['gvars'] = $this->getGraphicVars(); } } } @@ -18533,7 +18718,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'img': { - if (isset($tag['attribute']['src'])) { + if (!empty($tag['attribute']['src'])) { if ($tag['attribute']['src']{0} === '@') { // data stream $tag['attribute']['src'] = '@'.base64_decode(substr($tag['attribute']['src'], 1)); @@ -18797,7 +18982,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($tag['attribute']['maxlength']) AND !TCPDF_STATIC::empty_string($tag['attribute']['maxlength'])) { $opt['maxlen'] = intval($tag['attribute']['maxlength']); } - $h = $this->FontSize * $this->cell_height_ratio; + $h = $this->getCellHeight($this->FontSize); if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) { $w = intval($tag['attribute']['size']) * $this->GetStringWidth(chr(32)) * 2; } else { @@ -18959,7 +19144,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $w = 40; } if (isset($tag['attribute']['rows']) AND !TCPDF_STATIC::empty_string($tag['attribute']['rows'])) { - $h = intval($tag['attribute']['rows']) * $this->FontSize * $this->cell_height_ratio; + $h = intval($tag['attribute']['rows']) * $this->getCellHeight($this->FontSize); } else { $h = 10; } @@ -18968,7 +19153,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'select': { - $h = $this->FontSize * $this->cell_height_ratio; + $h = $this->getCellHeight($this->FontSize); if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) { $h *= ($tag['attribute']['size'] + 1); } @@ -19076,9 +19261,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($this->tagvspaces[$tag['value']][1]['h']) AND ($this->tagvspaces[$tag['value']][1]['h'] >= 0)) { $pre_h = $this->tagvspaces[$tag['value']][1]['h']; } elseif (isset($parent['fontsize'])) { - $pre_h = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio); + $pre_h = $this->getCellHeight($parent['fontsize'] / $this->k); } else { - $pre_h = $this->FontSize * $this->cell_height_ratio; + $pre_h = $this->getCellHeight($this->FontSize); } if (isset($this->tagvspaces[$tag['value']][1]['n'])) { $n = $this->tagvspaces[$tag['value']][1]['n']; @@ -19093,7 +19278,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $hb = ($n * $pre_h); } if ($maxbottomliney > $this->PageBreakTrigger) { - $hbz = ($this->FontSize * $this->cell_height_ratio); + $hbz = $this->getCellHeight($this->FontSize); } elseif ($this->y < $maxbottomliney) { $hbz = ($maxbottomliney - $this->y); } @@ -19844,32 +20029,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: return; } $symbol = strtolower($symbol); - switch ($symbol) { - case '!' : - case '#' : - case 'disc' : - case 'circle' : - case 'square' : - case '1': - case 'decimal': - case 'decimal-leading-zero': - case 'i': - case 'lower-roman': - case 'I': - case 'upper-roman': - case 'a': - case 'lower-alpha': - case 'lower-latin': - case 'A': - case 'upper-alpha': - case 'upper-latin': - case 'lower-greek': { - $this->lisymbol = $symbol; - break; - } - default : { - $this->lisymbol = ''; - } + $valid_symbols = array('!', '#', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek'); + if (in_array($symbol, $valid_symbols)) { + $this->lisymbol = $symbol; + } else { + $this->lisymbol = ''; } } @@ -20221,7 +20385,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (!TCPDF_STATIC::empty_string($textitem)) { // Check whether we need a new page or new column $prev_y = $this->y; - $h = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B']; + $h = $this->getCellHeight($this->FontSize); if ($this->checkPageBreak($h) OR ($this->y < $prev_y)) { $tmpx = $this->x; } @@ -20424,7 +20588,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->bufferlen += strlen($data); if ($this->diskcache) { if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) { - $this->buffer = TCPDF_STATIC::getObjFilename('buffer'); + $this->buffer = TCPDF_STATIC::getObjFilename('buf'); } $this->writeDiskCache($this->buffer, $data, true); } else { @@ -20442,7 +20606,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->bufferlen = strlen($data); if ($this->diskcache) { if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) { - $this->buffer = TCPDF_STATIC::getObjFilename('buffer'); + $this->buffer = TCPDF_STATIC::getObjFilename('buf'); } $this->writeDiskCache($this->buffer, $data, false); } else { @@ -20475,7 +20639,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: protected function setPageBuffer($page, $data, $append=false) { if ($this->diskcache) { if (!isset($this->pages[$page])) { - $this->pages[$page] = TCPDF_STATIC::getObjFilename('page'.$page); + $this->pages[$page] = TCPDF_STATIC::getObjFilename('page'); } $this->writeDiskCache($this->pages[$page], $data, $append); } else { @@ -20524,7 +20688,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } if ($this->diskcache) { if (!isset($this->images[$image])) { - $this->images[$image] = TCPDF_STATIC::getObjFilename('image'.$image); + $this->images[$image] = TCPDF_STATIC::getObjFilename('img'); } $this->writeDiskCache($this->images[$image], serialize($data)); } else { @@ -20775,22 +20939,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } // adjust javascript - $tmpjavascript = $this->javascript; - global $jfrompage, $jtopage; $jfrompage = $frompage; $jtopage = $topage; - $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', - create_function('$matches', 'global $jfrompage, $jtopage; - $pagenum = intval($matches[3]) + 1; - if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) { - $newpage = ($pagenum + 1); - } elseif ($pagenum == $jfrompage) { - $newpage = $jtopage; - } else { - $newpage = $pagenum; + if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) { + foreach($pamatch[0] as $pk => $pmatch) { + $pagenum = intval($pamatch[3][$pk]) + 1; + if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) { + $newpage = ($pagenum + 1); + } elseif ($pagenum == $jfrompage) { + $newpage = $jtopage; + } else { + $newpage = $pagenum; + } + --$newpage; + $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage; + $this->javascript = str_replace($pmatch, $newjs, $this->javascript); } - --$newpage; - return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript); + unset($pamatch); + } // return to last page $this->lastPage(true); return true; @@ -20956,21 +21122,23 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } // adjust javascript - $tmpjavascript = $this->javascript; - global $jpage; $jpage = $page; - $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', - create_function('$matches', 'global $jpage; - $pagenum = intval($matches[3]) + 1; - if ($pagenum >= $jpage) { - $newpage = ($pagenum - 1); - } elseif ($pagenum == $jpage) { - $newpage = 1; - } else { - $newpage = $pagenum; + if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) { + foreach($pamatch[0] as $pk => $pmatch) { + $pagenum = intval($pamatch[3][$pk]) + 1; + if ($pagenum >= $jpage) { + $newpage = ($pagenum - 1); + } elseif ($pagenum == $jpage) { + $newpage = 1; + } else { + $newpage = $pagenum; + } + --$newpage; + $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage; + $this->javascript = str_replace($pmatch, $newjs, $this->javascript); } - --$newpage; - return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript); + unset($pamatch); + } // return to last page if ($this->numpages > 0) { $this->lastPage(true); @@ -21112,7 +21280,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $this->SetTextColorArray($outline['c']); // check for page break - $this->checkPageBreak((2 * $this->FontSize * $this->cell_height_ratio)); + $this->checkPageBreak(2 * $this->getCellHeight($this->FontSize)); // set margins and X position if (($this->page == $current_page) AND ($this->current_column == $current_column)) { $this->lMargin = $lmargin; @@ -22355,7 +22523,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: return array($x, $y); } if (empty($h)) { - $h = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B']; + $h = $this->getCellHeight($this->FontSize); } // check for page break if ($this->checkPageBreak($h, $y)) { @@ -22449,6 +22617,17 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($this->state != 2) { return; } + // reseet SVG vars + $this->svggradients = array(); + $this->svggradientid = 0; + $this->svgdefsmode = false; + $this->svgdefs = array(); + $this->svgclipmode = false; + $this->svgclippaths = array(); + $this->svgcliptm = array(); + $this->svgclipid = 0; + $this->svgtext = ''; + $this->svgtextmode = array(); if ($this->rasterize_vector_images AND ($w > 0) AND ($h > 0)) { // convert SVG to raster image using GD or ImageMagick libraries return $this->Image($file, $x, $y, $w, $h, 'SVG', $link, $align, true, 300, $palign, false, false, $border, false, false, false); @@ -23268,7 +23447,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } break; } - case 'Q': { // quadratic Bézier curveto + case 'Q': { // quadratic Bezier curveto foreach ($params as $ck => $cp) { $params[$ck] = $cp; if ((($ck + 1) % 4) == 0) { @@ -23294,7 +23473,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } break; } - case 'T': { // shorthand/smooth quadratic Bézier curveto + case 'T': { // shorthand/smooth quadratic Bezier curveto foreach ($params as $ck => $cp) { $params[$ck] = $cp; if (($ck % 2) != 0) { @@ -23447,10 +23626,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: return; } if ($this->svgdefsmode AND !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) { - if (!isset($attribs['id'])) { - $attribs['id'] = 'DF_'.(count($this->svgdefs) + 1); + if (isset($attribs['id'])) { + $attribs['child_elements'] = array(); + $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs); + return; + } + if (end($this->svgdefs) !== FALSE) { + $last_svgdefs_id = key($this->svgdefs); + if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) { + $attribs['id'] = 'DF_'.(count($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements']) + 1); + $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$attribs['id']] = array('name' => $name, 'attribs' => $attribs); + return; + } } - $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs); return; } $clipping = false; @@ -23459,13 +23647,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $clipping = true; } // get styling properties - $prev_svgstyle = $this->svgstyles[(count($this->svgstyles) - 1)]; // previous style + $prev_svgstyle = $this->svgstyles[max(0,(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 !TCPDF_STATIC::empty_string($attribs['style'])) { + if (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style']) AND ($attribs['style'][0] != ';')) { // fix style for regular expression $attribs['style'] = ';'.$attribs['style']; } @@ -23497,7 +23685,6 @@ 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 = array(1,0,0,1,0,0); } if (isset($attribs['transform']) AND !empty($attribs['transform'])) { @@ -23537,6 +23724,11 @@ 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(); + $x = (isset($attribs['x'])?$attribs['x']:0); + $y = (isset($attribs['y'])?$attribs['y']:0); + $w = (isset($attribs['width'])?$attribs['width']:1); + $h = (isset($attribs['height'])?$attribs['height']:1); + $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y)); $this->SVGTransform($tm); $this->setSVGStyles($svgstyle, $prev_svgstyle); break; @@ -23643,13 +23835,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($attribs['d'])) { $d = trim($attribs['d']); if (!empty($d)) { + $x = (isset($attribs['x'])?$attribs['x']:0); + $y = (isset($attribs['y'])?$attribs['y']:0); + $w = (isset($attribs['width'])?$attribs['width']:1); + $h = (isset($attribs['height'])?$attribs['height']:1); + $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y)); if ($clipping) { $this->SVGTransform($tm); $this->SVGPath($d, 'CNZ'); } else { $this->StartTransform(); $this->SVGTransform($tm); - $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, 0, 0, 1, 1, 'SVGPath', array($d, 'CNZ')); + $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'SVGPath', array($d, 'CNZ')); if (!empty($obstyle)) { $this->SVGPath($d, $obstyle); } @@ -23938,8 +24135,22 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($attribs['id'])) { unset($attribs['id']); } - $attribs = array_merge($attribs, $use['attribs']); - $this->startSVGElementHandler($parser, $use['name'], $attribs); + if (isset($use['attribs']['x']) AND isset($attribs['x'])) { + $attribs['x'] += $use['attribs']['x']; + } + if (isset($use['attribs']['y']) AND isset($attribs['y'])) { + $attribs['y'] += $use['attribs']['y']; + } + if (empty($attribs['style'])) { + $attribs['style'] = ''; + } + if (!empty($use['attribs']['style'])) { + // merge styles + $attribs['style'] = str_replace(';;',';',';'.$use['attribs']['style'].$attribs['style']); + } + $attribs = array_merge($use['attribs'], $attribs); + $this->startSVGElementHandler('use-tag', $use['name'], $attribs); + return; } } break; @@ -23948,6 +24159,21 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } } // end of switch + // process child elements + if (!empty($attribs['child_elements'])) { + $child_elements = $attribs['child_elements']; + unset($attribs['child_elements']); + foreach($child_elements as $child_element) { + if (empty($child_element['attribs']['closing_tag'])) { + $this->startSVGElementHandler('child-tag', $child_element['name'], $child_element['attribs']); + } else { + if (isset($child_element['attribs']['content'])) { + $this->svgtext = $child_element['attribs']['content']; + } + $this->endSVGElementHandler('child-tag', $child_element['name']); + } + } + } } /** @@ -23959,6 +24185,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * @protected */ protected function endSVGElementHandler($parser, $name) { + if ($this->svgdefsmode AND !in_array($name, array('defs', 'clipPath', 'linearGradient', 'radialGradient', 'stop'))) {; + if (end($this->svgdefs) !== FALSE) { + $last_svgdefs_id = key($this->svgdefs); + if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) { + foreach($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'] as $child_element) { + if (isset($child_element['attribs']['id']) AND ($child_element['name'] == $name)) { + $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$child_element['attribs']['id'].'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext)); + return; + } + } + if ($this->svgdefs[$last_svgdefs_id]['name'] == $name) { + $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$last_svgdefs_id.'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext)); + return; + } + } + } + return; + } switch($name) { case 'defs': { $this->svgdefsmode = false; @@ -24021,7 +24265,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->textstrokewidth = $textstrokewidth; $this->svgtext = ''; $this->StopTransform(); - array_pop($this->svgstyles); + if (!$this->svgdefsmode) { + array_pop($this->svgstyles); + } break; } default: { diff --git a/lib/tcpdf/tcpdf_autoconfig.php b/lib/tcpdf/tcpdf_autoconfig.php index 2fc1da6da58..b2f013e72d3 100644 --- a/lib/tcpdf/tcpdf_autoconfig.php +++ b/lib/tcpdf/tcpdf_autoconfig.php @@ -3,11 +3,11 @@ // File name : tcpdf_autoconfig.php // Version : 1.0.000 // Begin : 2013-05-16 -// Last Update : 2013-05-16 +// Last Update : 2014-01-25 // Authors : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- -// Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD +// Copyright (C) 2011-2014 Nicola Asuni - Tecnick.com LTD // // This file is part of TCPDF software library. // @@ -117,7 +117,11 @@ if (!defined('PDF_HEADER_LOGO_WIDTH')) { } if (!defined('K_PATH_CACHE')) { - define ('K_PATH_CACHE', sys_get_temp_dir().'/'); + $K_PATH_CACHE = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(); + if (substr($K_PATH_CACHE, -1) != '/') { + $K_PATH_CACHE .= '/'; + } + define ('K_PATH_CACHE', $K_PATH_CACHE); } if (!defined('K_BLANK_IMAGE')) { diff --git a/lib/tcpdf/tcpdf_parser.php b/lib/tcpdf/tcpdf_parser.php index d3d8d45c481..0b2a7e144f3 100644 --- a/lib/tcpdf/tcpdf_parser.php +++ b/lib/tcpdf/tcpdf_parser.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.008 + * @version 1.0.014 */ // include class for decoding filters @@ -48,7 +48,7 @@ require_once(dirname(__FILE__).'/include/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.005 + * @version 1.0.010 * @author Nicola Asuni - info@tecnick.com */ class TCPDF_PARSER { @@ -103,7 +103,40 @@ class TCPDF_PARSER { if (empty($data)) { $this->Error('Empty PDF data.'); } + // find the pdf header starting position + if (($trimpos = strpos($data, '%PDF-')) === FALSE) { + $this->Error('Invalid PDF data: missing %PDF header.'); + } + // get PDF content string + $this->pdfdata = substr($data, $trimpos); + // get length + $pdflen = strlen($this->pdfdata); // set configuration parameters + $this->setConfig($cfg); + // get xref and trailer data + $this->xref = $this->getXrefData(); + // parse all document objects + $this->objects = array(); + foreach ($this->xref['xref'] as $obj => $offset) { + if (!isset($this->objects[$obj]) AND ($offset > 0)) { + // decode objects with positive offset + $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true); + } + } + // release some memory + unset($this->pdfdata); + $this->pdfdata = ''; + } + + /** + * Set the configuration parameters. + * @param $cfg (array) Array of configuration parameters: + * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception; + * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors; + * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors. + * @public + */ + protected function setConfig($cfg) { if (isset($cfg['die_for_errors'])) { $this->cfg['die_for_errors'] = !!$cfg['die_for_errors']; } @@ -113,25 +146,6 @@ class TCPDF_PARSER { if (isset($cfg['ignore_missing_filter_decoders'])) { $this->cfg['ignore_missing_filter_decoders'] = !!$cfg['ignore_missing_filter_decoders']; } - // get PDF content string - $this->pdfdata = $data; - // get length - $pdflen = strlen($this->pdfdata); - // initialize class for decoding filters - $this->FilterDecoders = new TCPDF_FILTERS(); - // get xref and trailer data - $this->xref = $this->getXrefData(); - // parse all document objects - $this->objects = array(); - foreach ($this->xref['xref'] as $obj => $offset) { - if (!isset($this->objects[$obj]) AND ($offset > 0)) { - // decode only objects with positive offset - $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true); - } - } - // release some memory - unset($this->pdfdata); - $this->pdfdata = ''; } /** @@ -188,20 +202,25 @@ class TCPDF_PARSER { /** * Decode the Cross-Reference section - * @param $startxref (int) Offset at which the xref section starts. + * @param $startxref (int) Offset at which the xref section starts (position of the 'xref' keyword). * @param $xref (array) Previous xref array (if any). * @return Array containing xref and trailer data. * @protected * @since 1.0.000 (2011-06-20) */ protected function decodeXref($startxref, $xref=array()) { - // extract xref data (object indexes and offsets) - $xoffset = $startxref + 5; + $startxref += 4; // 4 is the lenght of the word 'xref' + // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP) + $offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref); // 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]); + // search for cross-reference entries or subsection + while (preg_match('/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { + if ($matches[0][1] != $offset) { + // we are on another section + break; + } + $offset += strlen($matches[0][0]); if ($matches[3][0] == 'n') { // create unique object index: [object number]_[generation number] $index = $obj_num.'_'.intval($matches[2][0]); @@ -211,17 +230,15 @@ class TCPDF_PARSER { $xref['xref'][$index] = intval($matches[1][0]); } ++$obj_num; - $offset += 2; } elseif ($matches[3][0] == 'f') { ++$obj_num; - $offset += 2; } else { // object number (index) $obj_num = intval($matches[1][0]); } } // get trailer data - if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $xoffset) > 0) { + if (preg_match('/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { $trailer_data = $matches[1][0]; if (!isset($xref['trailer']) OR empty($xref['trailer'])) { // get only the last updated version @@ -274,7 +291,11 @@ class TCPDF_PARSER { } else { $filltrailer = false; } + if (!isset($xref['xref'])) { + $xref['xref'] = array(); + } $valid_crs = false; + $columns = 0; $sarr = $xrefcrs[0][1]; foreach ($sarr as $k => $v) { if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) { @@ -305,10 +326,12 @@ class TCPDF_PARSER { } elseif ($filltrailer) { if (($v[0] == '/') AND ($v[1] == 'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) { $xref['trailer']['size'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'ojbref'))) { + } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { $xref['trailer']['root'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'ojbref'))) { + } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { $xref['trailer']['info'] = $sarr[($k +1)][1]; + } elseif (($v[0] == '/') AND ($v[1] == 'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { + $xref['trailer']['encrypt'] = $sarr[($k +1)][1]; } elseif (($v[0] == '/') AND ($v[1] == 'ID') AND (isset($sarr[($k +1)]))) { $xref['trailer']['id'] = array(); $xref['trailer']['id'][0] = $sarr[($k +1)][1][0][1]; @@ -406,12 +429,14 @@ class TCPDF_PARSER { // default type field $sdata[$k][0] = 1; } - $i = 0; // count bytes on the row + $i = 0; // count bytes in the row // for every column for ($c = 0; $c < 3; ++$c) { // for every byte on the column for ($b = 0; $b < $wb[$c]; ++$b) { - $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8)); + if (isset($row[$i])) { + $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8)); + } ++$i; } } @@ -426,7 +451,6 @@ class TCPDF_PARSER { foreach ($sdata as $k => $row) { switch ($row[0]) { case 0: { // (f) linked list of free objects - ++$obj_num; break; } case 1: { // (n) objects that are in use but are not compressed @@ -437,7 +461,6 @@ class TCPDF_PARSER { // store object offset position $xref['xref'][$index] = $row[1]; } - ++$obj_num; break; } case 2: { // compressed objects @@ -451,6 +474,7 @@ class TCPDF_PARSER { break; } } + ++$obj_num; } } // end decoding data if (isset($prevxref)) { @@ -481,7 +505,7 @@ class TCPDF_PARSER { $next = strcspn($this->pdfdata, "\r\n", $offset); if ($next > 0) { $offset += $next; - return $this->getRawObject($this->pdfdata, $offset); + return $this->getRawObject($offset); } break; } @@ -575,7 +599,9 @@ class TCPDF_PARSER { // remove white space characters $objval = strtr($matches[1], "\x09\x0a\x0c\x0d\x20", ''); $offset += strlen($matches[0]); - } + } elseif (($endpos = strpos($this->pdfdata, '>', $offset)) !== FALSE) { + $offset = $endpos + 1; + } } break; } @@ -605,9 +631,9 @@ class TCPDF_PARSER { $offset += 6; if (preg_match('/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) { $offset += strlen($matches[0]); - if (preg_match('/([\r]?[\n])?(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) { + if (preg_match('/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) { $objval = substr($this->pdfdata, $offset, $matches[0][1]); - $offset += $matches[2][1]; + $offset += $matches[1][1]; } } } elseif (substr($this->pdfdata, $offset, 9) == 'endstream') { @@ -616,12 +642,12 @@ class TCPDF_PARSER { $offset += 9; } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) { // indirect object reference - $objtype = 'ojbref'; + $objtype = 'objref'; $offset += strlen($matches[0]); $objval = intval($matches[1]).'_'.intval($matches[2]); } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) { // object start - $objtype = 'ojb'; + $objtype = 'obj'; $objval = intval($matches[1]).'_'.intval($matches[2]); $offset += strlen ($matches[0]); } elseif (($numlen = strspn($this->pdfdata, '+-.0123456789', $offset)) > 0) { @@ -652,6 +678,8 @@ class TCPDF_PARSER { return; } $objref = $obj[0].' '.$obj[1].' obj'; + // ignore leading zeros + $offset += strspn($this->pdfdata, '0', $offset); if (strpos($this->pdfdata, $objref, $offset) != $offset) { // an indirect reference to an undefined object shall be considered a reference to the null object return array('null', 'null', $offset); @@ -744,13 +772,13 @@ class TCPDF_PARSER { // decode the stream $remaining_filters = array(); foreach ($filters as $filter) { - if (in_array($filter, $this->FilterDecoders->getAvailableFilters())) { + if (in_array($filter, TCPDF_FILTERS::getAvailableFilters())) { try { - $stream = $this->FilterDecoders->decodeFilter($filter, $stream); + $stream = TCPDF_FILTERS::decodeFilter($filter, $stream); } catch (Exception $e) { $emsg = $e->getMessage(); if ((($emsg[0] == '~') AND !$this->cfg['ignore_missing_filter_decoders']) - OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) { + OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) { $this->Error($e->getMessage()); } } diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index 7656bdc7c6c..03174c7fb08 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -165,7 +165,7 @@ tcpdf TCPDF LGPL - 6.0.031 + 6.0.062 3