From 75e7ad39458e060d0cae6fcb7d50a2c9f3af1b01 Mon Sep 17 00:00:00 2001 From: nicolaasuni Date: Sat, 15 Nov 2014 12:35:49 +0000 Subject: [PATCH] 6.0.099 (2014-11-15) - Added basic support for nested SVG images (adapted PR from SamMousa). - A bug related to setGDImageTransparency() was fixed (thanks to Maarten Boerema). --- CHANGELOG.TXT | 4 ++ README.TXT | 4 +- composer.json | 2 +- include/tcpdf_images.php | 15 ++--- include/tcpdf_static.php | 2 +- tcpdf.php | 132 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 143 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 39840b4..29ab95b 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,3 +1,7 @@ +6.0.099 (2014-11-15) + - Added basic support for nested SVG images (adapted PR from SamMousa). + - A bug related to setGDImageTransparency() was fixed (thanks to Maarten Boerema). + 6.0.098 (2014-11-08) - Bug item #996 "getCharBBox($char) returns incorrect results for TTF glyphs without outlines" was fixed. - Bug item #991 "Text problem with SVG" was fixed (only the font style part). diff --git a/README.TXT b/README.TXT index efd8d7c..e57489f 100644 --- a/README.TXT +++ b/README.TXT @@ -8,8 +8,8 @@ http://sourceforge.net/donate/index.php?group_id=128076 ------------------------------------------------------------ Name: TCPDF -Version: 6.0.098 -Release date: 2014-11-08 +Version: 6.0.099 +Release date: 2014-11-15 Author: Nicola Asuni Copyright (c) 2002-2014: diff --git a/composer.json b/composer.json index 07ac191..0c7a8e0 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "tecnick.com/tcpdf", - "version": "6.0.098", + "version": "6.0.099", "homepage": "http://www.tcpdf.org/", "type": "library", "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", diff --git a/include/tcpdf_images.php b/include/tcpdf_images.php index 3e13d9d..7197039 100644 --- a/include/tcpdf_images.php +++ b/include/tcpdf_images.php @@ -1,9 +1,9 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.004 + * @version 1.0.005 */ /** @@ -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.004 + * @version 1.0.005 * @author Nicola Asuni - info@tecnick.com */ class TCPDF_IMAGES { @@ -97,11 +97,12 @@ class TCPDF_IMAGES { * @public static */ public static function setGDImageTransparency($new_image, $image) { + // default transparency color (white) + $tcol = array('red' => 255, 'green' => 255, 'blue' => 255); // transparency index $tid = imagecolortransparent($image); - // default transparency color - $tcol = array('red' => 255, 'green' => 255, 'blue' => 255); - if ($tid >= 0) { + $palletsize = imagecolorstotal($image); + if (($tid >= 0) AND ($tid < $palletsize)) { // get the colors for the transparency index $tcol = imagecolorsforindex($image, $tid); } diff --git a/include/tcpdf_static.php b/include/tcpdf_static.php index 54a65b9..539ce16 100644 --- a/include/tcpdf_static.php +++ b/include/tcpdf_static.php @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.0.098'; + private static $tcpdf_version = '6.0.099'; /** * String alias for total number of pages. diff --git a/tcpdf.php b/tcpdf.php index 7701e5d..cdc607c 100644 --- a/tcpdf.php +++ b/tcpdf.php @@ -1,9 +1,9 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 6.0.098 + * @version 6.0.099 */ // TCPDF configuration @@ -128,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.098 + * @version 6.0.099 * @author Nicola Asuni - info@tecnick.com */ class TCPDF { @@ -341,6 +341,12 @@ class TCPDF { */ protected $images = array(); + /** + * Depth of the svg tag, to keep track if the svg tag is a subtag or the root tag. + * @protected + */ + protected $svg_tag_depth = 0; + /** * Array of cached files. * @protected @@ -22894,7 +22900,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($this->state != 2) { return; } - // reseet SVG vars + // reset SVG vars $this->svggradients = array(); $this->svggradientid = 0; $this->svgdefsmode = false; @@ -23896,6 +23902,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: return array($xmin, $ymin, ($xmax - $xmin), ($ymax - $ymin)); } + /** + * Return the tag name without the namespace + * @param $name (string) Tag name + * @protected + */ + protected function removeTagNamespace($name) { + if(strpos($name, ':') !== false) { + $parts = explode(':', $name); + return $parts[(sizeof($parts) - 1)]; + } + return $name; + } + /** * Sets the opening SVG element handler function for the XML parser. (*** TO BE COMPLETED ***) * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler. @@ -23907,6 +23926,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * @protected */ protected function startSVGElementHandler($parser, $name, $attribs, $ctm=array()) { + $name = $this->removeTagNamespace($name); // check if we are in clip mode if ($this->svgclipmode) { $this->svgclippaths[$this->svgclipid][] = array('name' => $name, 'attribs' => $attribs, 'tm' => $this->svgcliptm[$this->svgclipid]); @@ -24005,6 +24025,80 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } case 'svg': { // start of SVG object + if(++$this->svg_tag_depth <= 1) { + break; + } + // inner SVG + array_push($this->svgstyles, $svgstyle); + $this->StartTransform(); + $svgX = (isset($attribs['x'])?$attribs['x']:0); + $svgY = (isset($attribs['y'])?$attribs['y']:0); + $svgW = (isset($attribs['width'])?$attribs['width']:0); + $svgH = (isset($attribs['height'])?$attribs['height']:0); + // set x, y position using transform matrix + $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array( 1, 0, 0, 1, $svgX, $svgY)); + $this->SVGTransform($tm); + // set clipping for width and height + $x = 0; + $y = 0; + $w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):$this->w); + $h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):$this->h); + // draw clipping rect + $this->Rect($x, $y, $w, $h, 'CNZ', array(), array()); + // parse viewbox, calculate extra transformation matrix + if (isset($attribs['viewBox'])) { + $tmp = array(); + preg_match_all("/[0-9]+/", $attribs['viewBox'], $tmp); + $tmp = $tmp[0]; + if (sizeof($tmp) == 4) { + $vx = $tmp[0]; + $vy = $tmp[1]; + $vw = $tmp[2]; + $vh = $tmp[3]; + // get aspect ratio + $tmp = array(); + $aspectX = 'xMid'; + $aspectY = 'YMid'; + $fit = 'meet'; + if (isset($attribs['preserveAspectRatio'])) { + if($attribs['preserveAspectRatio'] == 'none') { + $fit = 'none'; + } else { + preg_match_all('/[a-zA-Z]+/', $attribs['preserveAspectRatio'], $tmp); + $tmp = $tmp[0]; + if ((sizeof($tmp) == 2) AND (strlen($tmp[0]) == 8) AND (in_array($tmp[1], array('meet', 'slice', 'none')))) { + $aspectX = substr($tmp[0], 0, 4); + $aspectY = substr($tmp[0], 4, 4); + $fit = $tmp[1]; + } + } + } + $wr = ($svgW / $vw); + $hr = ($svgH / $vh); + $ax = $ay = 0; + if ((($fit == 'meet') AND ($hr < $wr)) OR (($fit == 'slice') AND ($hr > $wr))) { + if ($aspectX == 'xMax') { + $ax = (($vw * ($wr / $hr)) - $vw); + } + if ($aspectX == 'xMid') { + $ax = ((($vw * ($wr / $hr)) - $vw) / 2); + } + $wr = $hr; + } elseif ((($fit == 'meet') AND ($hr > $wr)) OR (($fit == 'slice') AND ($hr < $wr))) { + if ($aspectY == 'YMax') { + $ay = (($vh * ($hr / $wr)) - $vh); + } + if ($aspectY == 'YMid') { + $ay = ((($vh * ($hr / $wr)) - $vh) / 2); + } + $hr = $wr; + } + $newtm = array($wr, 0, 0, $hr, (($wr * ($ax - $vx)) - $svgX), (($hr * ($ay - $vy)) - $svgY)); + $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, $newtm); + $this->SVGTransform($tm); + } + } + $this->setSVGStyles($svgstyle, $prev_svgstyle); break; } case 'g': { @@ -24347,7 +24441,29 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (($imgtype == 'eps') OR ($imgtype == 'ai')) { $this->ImageEps($img, $x, $y, $w, $h); } elseif ($imgtype == 'svg') { + // store SVG vars + $svggradients = $this->svggradients; + $svggradientid = $this->svggradientid; + $svgdefsmode = $this->svgdefsmode; + $svgdefs = $this->svgdefs; + $svgclipmode = $this->svgclipmode; + $svgclippaths = $this->svgclippaths; + $svgcliptm = $this->svgcliptm; + $svgclipid = $this->svgclipid; + $svgtext = $this->svgtext; + $svgtextmode = $this->svgtextmode; $this->ImageSVG($img, $x, $y, $w, $h); + // restore SVG vars + $this->svggradients = $svggradients; + $this->svggradientid = $svggradientid; + $this->svgdefsmode = $svgdefsmode; + $this->svgdefs = $svgdefs; + $this->svgclipmode = $svgclipmode; + $this->svgclippaths = $svgclippaths; + $this->svgcliptm = $svgcliptm; + $this->svgclipid = $svgclipid; + $this->svgtext = $svgtext; + $this->svgtextmode = $svgtextmode; } else { $this->Image($img, $x, $y, $w, $h); } @@ -24477,6 +24593,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * @protected */ protected function endSVGElementHandler($parser, $name) { + $name = $this->removeTagNamespace($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); @@ -24505,6 +24622,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->svgclipmode = false; break; } + case 'svg': { + if (--$this->svg_tag_depth <= 0) { + break; + } + } case 'g': { // ungroup: remove last style from array array_pop($this->svgstyles);