Example #1
0
 /**
  * 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.
  * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
  * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on.
  * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix).
  * @author Nicola Asuni
  * @since 5.0.000 (2010-05-02)
  * @protected
  */
 protected function startSVGElementHandler($parser, $name, $attribs, $ctm = array())
 {
     // check if we are in clip mode
     if ($this->svgclipmode) {
         $this->svgclippaths[$this->svgclipid][] = array('name' => $name, 'attribs' => $attribs, 'tm' => $this->svgcliptm[$this->svgclipid]);
         return;
     }
     if ($this->svgdefsmode and !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
         if (!isset($attribs['id'])) {
             $attribs['id'] = 'DF_' . (count($this->svgdefs) + 1);
         }
         $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
         return;
     }
     $clipping = false;
     if ($parser == 'clip-path') {
         // set clipping mode
         $clipping = true;
     }
     // get styling properties
     $prev_svgstyle = $this->svgstyles[count($this->svgstyles) - 1];
     // previous style
     $svgstyle = $this->svgstyles[0];
     // set default style
     if ($clipping and !isset($attribs['fill']) and (!isset($attribs['style']) or !preg_match('/[;\\"\\s]{1}fill[\\s]*:[\\s]*([^;\\"]*)/si', $attribs['style'], $attrval))) {
         // default fill attribute for clipping
         $attribs['fill'] = 'none';
     }
     if (isset($attribs['style']) and !TCPDF_STATIC::empty_string($attribs['style'])) {
         // fix style for regular expression
         $attribs['style'] = ';' . $attribs['style'];
     }
     foreach ($prev_svgstyle as $key => $val) {
         if (in_array($key, TCPDF_IMAGES::$svginheritprop)) {
             // inherit previous value
             $svgstyle[$key] = $val;
         }
         if (isset($attribs[$key]) and !TCPDF_STATIC::empty_string($attribs[$key])) {
             // specific attribute settings
             if ($attribs[$key] == 'inherit') {
                 $svgstyle[$key] = $val;
             } else {
                 $svgstyle[$key] = $attribs[$key];
             }
         } elseif (isset($attribs['style']) and !TCPDF_STATIC::empty_string($attribs['style'])) {
             // CSS style syntax
             $attrval = array();
             if (preg_match('/[;\\"\\s]{1}' . $key . '[\\s]*:[\\s]*([^;\\"]*)/si', $attribs['style'], $attrval) and isset($attrval[1])) {
                 if ($attrval[1] == 'inherit') {
                     $svgstyle[$key] = $val;
                 } else {
                     $svgstyle[$key] = $attrval[1];
                 }
             }
         }
     }
     // transformation matrix
     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'])) {
         $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, TCPDF_STATIC::getSVGTransformMatrix($attribs['transform']));
     }
     $svgstyle['transfmatrix'] = $tm;
     $invisible = false;
     if ($svgstyle['visibility'] == 'hidden' or $svgstyle['visibility'] == 'collapse' or $svgstyle['display'] == 'none') {
         // the current graphics element is invisible (nothing is painted)
         $invisible = true;
     }
     // process tag
     switch ($name) {
         case 'defs':
             $this->svgdefsmode = true;
             break;
             // clipPath
         // clipPath
         case 'clipPath':
             if ($invisible) {
                 break;
             }
             $this->svgclipmode = true;
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'CP_' . (count($this->svgcliptm) + 1);
             }
             $this->svgclipid = $attribs['id'];
             $this->svgclippaths[$this->svgclipid] = array();
             $this->svgcliptm[$this->svgclipid] = $tm;
             break;
         case 'svg':
             // start of SVG object
             break;
         case 'g':
             // group together related graphics elements
             array_push($this->svgstyles, $svgstyle);
             $this->StartTransform();
             $this->SVGTransform($tm);
             $this->setSVGStyles($svgstyle, $prev_svgstyle);
             break;
         case 'linearGradient':
             if ($this->pdfa_mode) {
                 break;
             }
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'GR_' . (count($this->svggradients) + 1);
             }
             $this->svggradientid = $attribs['id'];
             $this->svggradients[$this->svggradientid] = array();
             $this->svggradients[$this->svggradientid]['type'] = 2;
             $this->svggradients[$this->svggradientid]['stops'] = array();
             if (isset($attribs['gradientUnits'])) {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
             } else {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
             }
             //$attribs['spreadMethod']
             if (!isset($attribs['x1']) and !isset($attribs['y1']) and !isset($attribs['x2']) and !isset($attribs['y2']) or (isset($attribs['x1']) and substr($attribs['x1'], -1) == '%' or isset($attribs['y1']) and substr($attribs['y1'], -1) == '%' or isset($attribs['x2']) and substr($attribs['x2'], -1) == '%' or isset($attribs['y2']) and substr($attribs['y2'], -1) == '%')) {
                 $this->svggradients[$this->svggradientid]['mode'] = 'percentage';
             } else {
                 $this->svggradients[$this->svggradientid]['mode'] = 'measure';
             }
             $x1 = isset($attribs['x1']) ? $attribs['x1'] : '0';
             $y1 = isset($attribs['y1']) ? $attribs['y1'] : '0';
             $x2 = isset($attribs['x2']) ? $attribs['x2'] : '100';
             $y2 = isset($attribs['y2']) ? $attribs['y2'] : '0';
             if (isset($attribs['gradientTransform'])) {
                 $this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
             }
             $this->svggradients[$this->svggradientid]['coords'] = array($x1, $y1, $x2, $y2);
             if (isset($attribs['xlink:href']) and !empty($attribs['xlink:href'])) {
                 // gradient is defined on another place
                 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
             }
             break;
         case 'radialGradient':
             if ($this->pdfa_mode) {
                 break;
             }
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'GR_' . (count($this->svggradients) + 1);
             }
             $this->svggradientid = $attribs['id'];
             $this->svggradients[$this->svggradientid] = array();
             $this->svggradients[$this->svggradientid]['type'] = 3;
             $this->svggradients[$this->svggradientid]['stops'] = array();
             if (isset($attribs['gradientUnits'])) {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
             } else {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
             }
             //$attribs['spreadMethod']
             if (!isset($attribs['cx']) and !isset($attribs['cy']) or (isset($attribs['cx']) and substr($attribs['cx'], -1) == '%' or isset($attribs['cy']) and substr($attribs['cy'], -1) == '%')) {
                 $this->svggradients[$this->svggradientid]['mode'] = 'percentage';
             } else {
                 $this->svggradients[$this->svggradientid]['mode'] = 'measure';
             }
             $cx = isset($attribs['cx']) ? $attribs['cx'] : 0.5;
             $cy = isset($attribs['cy']) ? $attribs['cy'] : 0.5;
             $fx = isset($attribs['fx']) ? $attribs['fx'] : $cx;
             $fy = isset($attribs['fy']) ? $attribs['fy'] : $cy;
             $r = isset($attribs['r']) ? $attribs['r'] : 0.5;
             if (isset($attribs['gradientTransform'])) {
                 $this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
             }
             $this->svggradients[$this->svggradientid]['coords'] = array($cx, $cy, $fx, $fy, $r);
             if (isset($attribs['xlink:href']) and !empty($attribs['xlink:href'])) {
                 // gradient is defined on another place
                 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
             }
             break;
         case 'stop':
             // gradient stops
             if (substr($attribs['offset'], -1) == '%') {
                 $offset = floatval(substr($attribs['offset'], -1)) / 100;
             } else {
                 $offset = floatval($attribs['offset']);
                 if ($offset > 1) {
                     $offset /= 100;
                 }
             }
             $stop_color = isset($svgstyle['stop-color']) ? TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stop-color'], $this->spot_colors) : 'black';
             $opacity = isset($svgstyle['stop-opacity']) ? $svgstyle['stop-opacity'] : 1;
             $this->svggradients[$this->svggradientid]['stops'][] = array('offset' => $offset, 'color' => $stop_color, 'opacity' => $opacity);
             break;
             // paths
         // paths
         case 'path':
             if ($invisible) {
                 break;
             }
             if (isset($attribs['d'])) {
                 $d = trim($attribs['d']);
                 if (!empty($d)) {
                     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'));
                         if (!empty($obstyle)) {
                             $this->SVGPath($d, $obstyle);
                         }
                         $this->StopTransform();
                     }
                 }
             }
             break;
             // shapes
         // shapes
         case 'rect':
             if ($invisible) {
                 break;
             }
             $x = isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0;
             $y = isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0;
             $w = isset($attribs['width']) ? $this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false) : 0;
             $h = isset($attribs['height']) ? $this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false) : 0;
             $rx = isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0;
             $ry = isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : $rx;
             if ($clipping) {
                 $this->SVGTransform($tm);
                 $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ', array(), array());
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'RoundedRectXY', array($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', $obstyle, array(), array());
                 }
                 $this->StopTransform();
             }
             break;
         case 'circle':
             if ($invisible) {
                 break;
             }
             $r = isset($attribs['r']) ? $this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false) : 0;
             $cx = isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0);
             $cy = isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0);
             $x = $cx - $r;
             $y = $cy - $r;
             $w = 2 * $r;
             $h = $w;
             if ($clipping) {
                 $this->SVGTransform($tm);
                 $this->Circle($cx, $cy, $r, 0, 360, 'CNZ', array(), array(), 8);
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Circle', array($cx, $cy, $r, 0, 360, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->Circle($cx, $cy, $r, 0, 360, $obstyle, array(), array(), 8);
                 }
                 $this->StopTransform();
             }
             break;
         case 'ellipse':
             if ($invisible) {
                 break;
             }
             $rx = isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0;
             $ry = isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : 0;
             $cx = isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0);
             $cy = isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0);
             $x = $cx - $rx;
             $y = $cy - $ry;
             $w = 2 * $rx;
             $h = 2 * $ry;
             if ($clipping) {
                 $this->SVGTransform($tm);
                 $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ', array(), array(), 8);
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Ellipse', array($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, $obstyle, array(), array(), 8);
                 }
                 $this->StopTransform();
             }
             break;
         case 'line':
             if ($invisible) {
                 break;
             }
             $x1 = isset($attribs['x1']) ? $this->getHTMLUnitToUnits($attribs['x1'], 0, $this->svgunit, false) : 0;
             $y1 = isset($attribs['y1']) ? $this->getHTMLUnitToUnits($attribs['y1'], 0, $this->svgunit, false) : 0;
             $x2 = isset($attribs['x2']) ? $this->getHTMLUnitToUnits($attribs['x2'], 0, $this->svgunit, false) : 0;
             $y2 = isset($attribs['y2']) ? $this->getHTMLUnitToUnits($attribs['y2'], 0, $this->svgunit, false) : 0;
             $x = $x1;
             $y = $y1;
             $w = abs($x2 - $x1);
             $h = abs($y2 - $y1);
             if (!$clipping) {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Line', array($x1, $y1, $x2, $y2));
                 $this->Line($x1, $y1, $x2, $y2);
                 $this->StopTransform();
             }
             break;
         case 'polyline':
         case 'polygon':
             if ($invisible) {
                 break;
             }
             $points = isset($attribs['points']) ? $attribs['points'] : '0 0';
             $points = trim($points);
             // note that point may use a complex syntax not covered here
             $points = preg_split('/[\\,\\s]+/si', $points);
             if (count($points) < 4) {
                 break;
             }
             $p = array();
             $xmin = 2147483647;
             $xmax = 0;
             $ymin = 2147483647;
             $ymax = 0;
             foreach ($points as $key => $val) {
                 $p[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
                 if ($key % 2 == 0) {
                     // X coordinate
                     $xmin = min($xmin, $p[$key]);
                     $xmax = max($xmax, $p[$key]);
                 } else {
                     // Y coordinate
                     $ymin = min($ymin, $p[$key]);
                     $ymax = max($ymax, $p[$key]);
                 }
             }
             $x = $xmin;
             $y = $ymin;
             $w = $xmax - $xmin;
             $h = $ymax - $ymin;
             if ($name == 'polyline') {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->PolyLine($p, $obstyle, array(), array());
                 }
                 $this->StopTransform();
             } else {
                 // polygon
                 if ($clipping) {
                     $this->SVGTransform($tm);
                     $this->Polygon($p, 'CNZ', array(), array(), true);
                 } else {
                     $this->StartTransform();
                     $this->SVGTransform($tm);
                     $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Polygon', array($p, 'CNZ'));
                     if (!empty($obstyle)) {
                         $this->Polygon($p, $obstyle, array(), array(), true);
                     }
                     $this->StopTransform();
                 }
             }
             break;
             // image
         // image
         case 'image':
             if ($invisible) {
                 break;
             }
             if (!isset($attribs['xlink:href']) or empty($attribs['xlink:href'])) {
                 break;
             }
             $x = isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0;
             $y = isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0;
             $w = isset($attribs['width']) ? $this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false) : 0;
             $h = isset($attribs['height']) ? $this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false) : 0;
             $img = $attribs['xlink:href'];
             if (!$clipping) {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h);
                 if (preg_match('/^data:image\\/[^;]+;base64,/', $img, $m) > 0) {
                     // embedded image encoded as base64
                     $img = '@' . base64_decode(substr($img, strlen($m[0])));
                 } else {
                     // fix image path
                     if (!TCPDF_STATIC::empty_string($this->svgdir) and ($img[0] == '.' or basename($img) == $img)) {
                         // replace relative path with full server path
                         $img = $this->svgdir . '/' . $img;
                     }
                     if ($img[0] == '/' and !empty($_SERVER['DOCUMENT_ROOT']) and $_SERVER['DOCUMENT_ROOT'] != '/') {
                         $findroot = strpos($img, $_SERVER['DOCUMENT_ROOT']);
                         if ($findroot === false or $findroot > 1) {
                             if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
                                 $img = substr($_SERVER['DOCUMENT_ROOT'], 0, -1) . $img;
                             } else {
                                 $img = $_SERVER['DOCUMENT_ROOT'] . $img;
                             }
                         }
                     }
                     $img = urldecode($img);
                     $testscrtype = @parse_url($img);
                     if (!isset($testscrtype['query']) or empty($testscrtype['query'])) {
                         // convert URL to server path
                         $img = str_replace(K_PATH_URL, K_PATH_MAIN, $img);
                     }
                 }
                 // get image type
                 $imgtype = TCPDF_IMAGES::getImageFileType($img);
                 if ($imgtype == 'eps' or $imgtype == 'ai') {
                     $this->ImageEps($img, $x, $y, $w, $h);
                 } elseif ($imgtype == 'svg') {
                     $this->ImageSVG($img, $x, $y, $w, $h);
                 } else {
                     $this->Image($img, $x, $y, $w, $h);
                 }
                 $this->StopTransform();
             }
             break;
             // text
         // text
         case 'text':
         case 'tspan':
             // only basic support - advanced features must be implemented
             $this->svgtextmode['invisible'] = $invisible;
             if ($invisible) {
                 break;
             }
             array_push($this->svgstyles, $svgstyle);
             if (isset($attribs['x'])) {
                 $x = $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false);
             } elseif ($name == 'tspan') {
                 $x = $this->x;
             } else {
                 $x = 0;
             }
             if (isset($attribs['dx'])) {
                 $x += $this->getHTMLUnitToUnits($attribs['dx'], 0, $this->svgunit, false);
             }
             if (isset($attribs['y'])) {
                 $y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
             } elseif ($name == 'tspan') {
                 $y = $this->y;
             } else {
                 $y = 0;
             }
             if (isset($attribs['dy'])) {
                 $y += $this->getHTMLUnitToUnits($attribs['dy'], 0, $this->svgunit, false);
             }
             $svgstyle['text-color'] = $svgstyle['fill'];
             $this->svgtext = '';
             if (isset($svgstyle['text-anchor'])) {
                 $this->svgtextmode['text-anchor'] = $svgstyle['text-anchor'];
             } else {
                 $this->svgtextmode['text-anchor'] = 'start';
             }
             if (isset($svgstyle['direction'])) {
                 if ($svgstyle['direction'] == 'rtl') {
                     $this->svgtextmode['rtl'] = true;
                 } else {
                     $this->svgtextmode['rtl'] = false;
                 }
             } else {
                 $this->svgtextmode['rtl'] = false;
             }
             if (isset($svgstyle['stroke']) and $svgstyle['stroke'] != 'none' and isset($svgstyle['stroke-width']) and $svgstyle['stroke-width'] > 0) {
                 $this->svgtextmode['stroke'] = $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false);
             } else {
                 $this->svgtextmode['stroke'] = false;
             }
             $this->StartTransform();
             $this->SVGTransform($tm);
             $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, 1, 1);
             $this->x = $x;
             $this->y = $y;
             break;
             // use
         // use
         case 'use':
             if (isset($attribs['xlink:href']) and !empty($attribs['xlink:href'])) {
                 $svgdefid = substr($attribs['xlink:href'], 1);
                 if (isset($this->svgdefs[$svgdefid])) {
                     $use = $this->svgdefs[$svgdefid];
                     if (isset($attribs['xlink:href'])) {
                         unset($attribs['xlink:href']);
                     }
                     if (isset($attribs['id'])) {
                         unset($attribs['id']);
                     }
                     $attribs = array_merge($attribs, $use['attribs']);
                     $this->startSVGElementHandler($parser, $use['name'], $attribs);
                 }
             }
             break;
         default:
             break;
     }
     // end of switch
 }
	/**
	 * 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.
	 * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
	 * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on.
	 * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix).
	 * @author Nicola Asuni
	 * @since 5.0.000 (2010-05-02)
	 * @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]);
			return;
		}
		if ($this->svgdefsmode AND !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
			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;
				}
			}
			return;
		}
		$clipping = false;
		if ($parser == 'clip-path') {
			// set clipping mode
			$clipping = true;
		}
		// get styling properties
		$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']) AND ($attribs['style'][0] != ';')) {
			// fix style for regular expression
			$attribs['style'] = ';'.$attribs['style'];
		}
		foreach ($prev_svgstyle as $key => $val) {
			if (in_array($key, TCPDF_IMAGES::$svginheritprop)) {
				// inherit previous value
				$svgstyle[$key] = $val;
			}
			if (isset($attribs[$key]) AND !TCPDF_STATIC::empty_string($attribs[$key])) {
				// specific attribute settings
				if ($attribs[$key] == 'inherit') {
					$svgstyle[$key] = $val;
				} else {
					$svgstyle[$key] = $attribs[$key];
				}
			} elseif (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style'])) {
				// CSS style syntax
				$attrval = array();
				if (preg_match('/[;\"\s]{1}'.$key.'[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval) AND isset($attrval[1])) {
					if ($attrval[1] == 'inherit') {
						$svgstyle[$key] = $val;
					} else {
						$svgstyle[$key] = $attrval[1];
					}
				}
			}
		}
		// transformation matrix
		if (!empty($ctm)) {
			$tm = $ctm;
		} else {
			$tm = array(1,0,0,1,0,0);
		}
		if (isset($attribs['transform']) AND !empty($attribs['transform'])) {
			$tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, TCPDF_STATIC::getSVGTransformMatrix($attribs['transform']));
		}
		$svgstyle['transfmatrix'] = $tm;
		$invisible = false;
		if (($svgstyle['visibility'] == 'hidden') OR ($svgstyle['visibility'] == 'collapse') OR ($svgstyle['display'] == 'none')) {
			// the current graphics element is invisible (nothing is painted)
			$invisible = true;
		}
		// process tag
		switch($name) {
			case 'defs': {
				$this->svgdefsmode = true;
				break;
			}
			// clipPath
			case 'clipPath': {
				if ($invisible) {
					break;
				}
				$this->svgclipmode = true;
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'CP_'.(count($this->svgcliptm) + 1);
				}
				$this->svgclipid = $attribs['id'];
				$this->svgclippaths[$this->svgclipid] = array();
				$this->svgcliptm[$this->svgclipid] = $tm;
				break;
			}
			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': {
				// 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 = 1;//(isset($attribs['width'])?$attribs['width']:1);
				$h = 1;//(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;
			}
			case 'linearGradient': {
				if ($this->pdfa_mode) {
					break;
				}
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
				}
				$this->svggradientid = $attribs['id'];
				$this->svggradients[$this->svggradientid] = array();
				$this->svggradients[$this->svggradientid]['type'] = 2;
				$this->svggradients[$this->svggradientid]['stops'] = array();
				if (isset($attribs['gradientUnits'])) {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
				} else {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
				}
				//$attribs['spreadMethod']
				if (((!isset($attribs['x1'])) AND (!isset($attribs['y1'])) AND (!isset($attribs['x2'])) AND (!isset($attribs['y2'])))
					OR ((isset($attribs['x1']) AND (substr($attribs['x1'], -1) == '%'))
						OR (isset($attribs['y1']) AND (substr($attribs['y1'], -1) == '%'))
						OR (isset($attribs['x2']) AND (substr($attribs['x2'], -1) == '%'))
						OR (isset($attribs['y2']) AND (substr($attribs['y2'], -1) == '%')))) {
					$this->svggradients[$this->svggradientid]['mode'] = 'percentage';
				} else {
					$this->svggradients[$this->svggradientid]['mode'] = 'measure';
				}
				$x1 = (isset($attribs['x1'])?$attribs['x1']:'0');
				$y1 = (isset($attribs['y1'])?$attribs['y1']:'0');
				$x2 = (isset($attribs['x2'])?$attribs['x2']:'100');
				$y2 = (isset($attribs['y2'])?$attribs['y2']:'0');
				if (isset($attribs['gradientTransform'])) {
					$this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
				}
				$this->svggradients[$this->svggradientid]['coords'] = array($x1, $y1, $x2, $y2);
				if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
					// gradient is defined on another place
					$this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
				}
				break;
			}
			case 'radialGradient': {
				if ($this->pdfa_mode) {
					break;
				}
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
				}
				$this->svggradientid = $attribs['id'];
				$this->svggradients[$this->svggradientid] = array();
				$this->svggradients[$this->svggradientid]['type'] = 3;
				$this->svggradients[$this->svggradientid]['stops'] = array();
				if (isset($attribs['gradientUnits'])) {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
				} else {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
				}
				//$attribs['spreadMethod']
				if (((!isset($attribs['cx'])) AND (!isset($attribs['cy'])))
					OR ((isset($attribs['cx']) AND (substr($attribs['cx'], -1) == '%'))
					OR (isset($attribs['cy']) AND (substr($attribs['cy'], -1) == '%')))) {
					$this->svggradients[$this->svggradientid]['mode'] = 'percentage';
				} elseif (isset($attribs['r']) AND is_numeric($attribs['r']) AND ($attribs['r']) <= 1) {
					$this->svggradients[$this->svggradientid]['mode'] = 'ratio';
				} else {
					$this->svggradients[$this->svggradientid]['mode'] = 'measure';
				}
				$cx = (isset($attribs['cx']) ? $attribs['cx'] : 0.5);
				$cy = (isset($attribs['cy']) ? $attribs['cy'] : 0.5);
				$fx = (isset($attribs['fx']) ? $attribs['fx'] : $cx);
				$fy = (isset($attribs['fy']) ? $attribs['fy'] : $cy);
				$r = (isset($attribs['r']) ? $attribs['r'] : 0.5);
				if (isset($attribs['gradientTransform'])) {
					$this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
				}
				$this->svggradients[$this->svggradientid]['coords'] = array($cx, $cy, $fx, $fy, $r);
				if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
					// gradient is defined on another place
					$this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
				}
				break;
			}
			case 'stop': {
				// gradient stops
				if (substr($attribs['offset'], -1) == '%') {
					$offset = floatval(substr($attribs['offset'], -1)) / 100;
				} else {
					$offset = floatval($attribs['offset']);
					if ($offset > 1) {
						$offset /= 100;
					}
				}
				$stop_color = isset($svgstyle['stop-color'])?TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stop-color'], $this->spot_colors):'black';
				$opacity = isset($svgstyle['stop-opacity'])?$svgstyle['stop-opacity']:1;
				$this->svggradients[$this->svggradientid]['stops'][] = array('offset' => $offset, 'color' => $stop_color, 'opacity' => $opacity);
				break;
			}
			// paths
			case 'path': {
				if ($invisible) {
					break;
				}
				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, $x, $y, $w, $h, 'SVGPath', array($d, 'CNZ'));
							if (!empty($obstyle)) {
								$this->SVGPath($d, $obstyle);
							}
							$this->StopTransform();
						}
					}
				}
				break;
			}
			// shapes
			case 'rect': {
				if ($invisible) {
					break;
				}
				$x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
				$y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
				$w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
				$h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):0);
				$rx = (isset($attribs['rx'])?$this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false):0);
				$ry = (isset($attribs['ry'])?$this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false):$rx);
				if ($clipping) {
					$this->SVGTransform($tm);
					$this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ', array(), array());
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'RoundedRectXY', array($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ'));
					if (!empty($obstyle)) {
						$this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', $obstyle, array(), array());
					}
					$this->StopTransform();
				}
				break;
			}
			case 'circle': {
				if ($invisible) {
					break;
				}
				$r = (isset($attribs['r']) ? $this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false) : 0);
				$cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
				$cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
				$x = ($cx - $r);
				$y = ($cy - $r);
				$w = (2 * $r);
				$h = $w;
				if ($clipping) {
					$this->SVGTransform($tm);
					$this->Circle($cx, $cy, $r, 0, 360, 'CNZ', array(), array(), 8);
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Circle', array($cx, $cy, $r, 0, 360, 'CNZ'));
					if (!empty($obstyle)) {
						$this->Circle($cx, $cy, $r, 0, 360, $obstyle, array(), array(), 8);
					}
					$this->StopTransform();
				}
				break;
			}
			case 'ellipse': {
				if ($invisible) {
					break;
				}
				$rx = (isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0);
				$ry = (isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : 0);
				$cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
				$cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
				$x = ($cx - $rx);
				$y = ($cy - $ry);
				$w = (2 * $rx);
				$h = (2 * $ry);
				if ($clipping) {
					$this->SVGTransform($tm);
					$this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ', array(), array(), 8);
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Ellipse', array($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ'));
					if (!empty($obstyle)) {
						$this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, $obstyle, array(), array(), 8);
					}
					$this->StopTransform();
				}
				break;
			}
			case 'line': {
				if ($invisible) {
					break;
				}
				$x1 = (isset($attribs['x1'])?$this->getHTMLUnitToUnits($attribs['x1'], 0, $this->svgunit, false):0);
				$y1 = (isset($attribs['y1'])?$this->getHTMLUnitToUnits($attribs['y1'], 0, $this->svgunit, false):0);
				$x2 = (isset($attribs['x2'])?$this->getHTMLUnitToUnits($attribs['x2'], 0, $this->svgunit, false):0);
				$y2 = (isset($attribs['y2'])?$this->getHTMLUnitToUnits($attribs['y2'], 0, $this->svgunit, false):0);
				$x = $x1;
				$y = $y1;
				$w = abs($x2 - $x1);
				$h = abs($y2 - $y1);
				if (!$clipping) {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Line', array($x1, $y1, $x2, $y2));
					$this->Line($x1, $y1, $x2, $y2);
					$this->StopTransform();
				}
				break;
			}
			case 'polyline':
			case 'polygon': {
				if ($invisible) {
					break;
				}
				$points = (isset($attribs['points'])?$attribs['points']:'0 0');
				$points = trim($points);
				// note that point may use a complex syntax not covered here
				$points = preg_split('/[\,\s]+/si', $points);
				if (count($points) < 4) {
					break;
				}
				$p = array();
				$xmin = 2147483647;
				$xmax = 0;
				$ymin = 2147483647;
				$ymax = 0;
				foreach ($points as $key => $val) {
					$p[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
					if (($key % 2) == 0) {
						// X coordinate
						$xmin = min($xmin, $p[$key]);
						$xmax = max($xmax, $p[$key]);
					} else {
						// Y coordinate
						$ymin = min($ymin, $p[$key]);
						$ymax = max($ymax, $p[$key]);
					}
				}
				$x = $xmin;
				$y = $ymin;
				$w = ($xmax - $xmin);
				$h = ($ymax - $ymin);
				if ($name == 'polyline') {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
					if (!empty($obstyle)) {
						$this->PolyLine($p, $obstyle, array(), array());
					}
					$this->StopTransform();
				} else { // polygon
					if ($clipping) {
						$this->SVGTransform($tm);
						$this->Polygon($p, 'CNZ', array(), array(), true);
					} else {
						$this->StartTransform();
						$this->SVGTransform($tm);
						$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Polygon', array($p, 'CNZ'));
						if (!empty($obstyle)) {
							$this->Polygon($p, $obstyle, array(), array(), true);
						}
						$this->StopTransform();
					}
				}
				break;
			}
			// image
			case 'image': {
				if ($invisible) {
					break;
				}
				if (!isset($attribs['xlink:href']) OR empty($attribs['xlink:href'])) {
					break;
				}
				$x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
				$y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
				$w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
				$h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):0);
				$img = $attribs['xlink:href'];
				if (!$clipping) {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h);
					if (preg_match('/^data:image\/[^;]+;base64,/', $img, $m) > 0) {
						// embedded image encoded as base64
						$img = '@'.base64_decode(substr($img, strlen($m[0])));
					} else {
						// fix image path
						if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) {
							// replace relative path with full server path
							$img = $this->svgdir.'/'.$img;
						}
						if (($img[0] == '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
							$findroot = strpos($img, $_SERVER['DOCUMENT_ROOT']);
							if (($findroot === false) OR ($findroot > 1)) {
								if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
									$img = substr($_SERVER['DOCUMENT_ROOT'], 0, -1).$img;
								} else {
									$img = $_SERVER['DOCUMENT_ROOT'].$img;
								}
							}
						}
						$img = urldecode($img);
						$testscrtype = @parse_url($img);
						if (!isset($testscrtype['query']) OR empty($testscrtype['query'])) {
							// convert URL to server path
							$img = str_replace(K_PATH_URL, K_PATH_MAIN, $img);
						}
					}
					// get image type
					$imgtype = TCPDF_IMAGES::getImageFileType($img);
					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);
					}
					$this->StopTransform();
				}
				break;
			}
			// text
			case 'text':
			case 'tspan': {
				if (isset($this->svgtextmode['text-anchor']) AND !empty($this->svgtext)) {
					// @TODO: unsupported feature
				}
				// only basic support - advanced features must be implemented
				$this->svgtextmode['invisible'] = $invisible;
				if ($invisible) {
					break;
				}
				array_push($this->svgstyles, $svgstyle);
				if (isset($attribs['x'])) {
					$x = $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false);
				} elseif ($name == 'tspan') {
					$x = $this->x;
				} else {
					$x = 0;
				}
				if (isset($attribs['dx'])) {
					$x += $this->getHTMLUnitToUnits($attribs['dx'], 0, $this->svgunit, false);
				}
				if (isset($attribs['y'])) {
					$y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
				} elseif ($name == 'tspan') {
					$y = $this->y;
				} else {
					$y = 0;
				}
				if (isset($attribs['dy'])) {
					$y += $this->getHTMLUnitToUnits($attribs['dy'], 0, $this->svgunit, false);
				}
				$svgstyle['text-color'] = $svgstyle['fill'];
				$this->svgtext = '';
				if (isset($svgstyle['text-anchor'])) {
					$this->svgtextmode['text-anchor'] = $svgstyle['text-anchor'];
				} else {
					$this->svgtextmode['text-anchor'] = 'start';
				}
				if (isset($svgstyle['direction'])) {
					if ($svgstyle['direction'] == 'rtl') {
						$this->svgtextmode['rtl'] = true;
					} else {
						$this->svgtextmode['rtl'] = false;
					}
				} else {
					$this->svgtextmode['rtl'] = false;
				}
				if (isset($svgstyle['stroke']) AND ($svgstyle['stroke'] != 'none') AND isset($svgstyle['stroke-width']) AND ($svgstyle['stroke-width'] > 0)) {
					$this->svgtextmode['stroke'] = $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false);
				} else {
					$this->svgtextmode['stroke'] = false;
				}
				$this->StartTransform();
				$this->SVGTransform($tm);
				$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, 1, 1);
				$this->x = $x;
				$this->y = $y;
				break;
			}
			// use
			case 'use': {
				if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
					$svgdefid = substr($attribs['xlink:href'], 1);
					if (isset($this->svgdefs[$svgdefid])) {
						$use = $this->svgdefs[$svgdefid];
						if (isset($attribs['xlink:href'])) {
							unset($attribs['xlink:href']);
						}
						if (isset($attribs['id'])) {
							unset($attribs['id']);
						}
						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($parser, $use['name'], $attribs);
						return;
					}
				}
				break;
			}
			default: {
				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']);
				}
			}
		}
	}