398 lines
15 KiB
PHP
398 lines
15 KiB
PHP
<?php
|
|
/*
|
|
SVG to dojox.gfx Parser
|
|
Copyright (C) 2009 Aaron Lindsay <aclindsay@aclindsay.com>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
require_once("objects/SVG.php");
|
|
|
|
require_once("objects/Path.php");
|
|
require_once("objects/Rectangle.php");
|
|
require_once("objects/Circle.php");
|
|
require_once("objects/Ellipse.php");
|
|
require_once("objects/Line.php");
|
|
require_once("objects/Polyline.php");
|
|
require_once("objects/Line.php");
|
|
require_once("objects/Text.php");
|
|
|
|
require_once("objects/Gradient.php");
|
|
require_once("objects/RadialGradient.php");
|
|
require_once("objects/LinearGradient.php");
|
|
require_once("objects/GradientStop.php");
|
|
|
|
require_once("objects/Transform.php");
|
|
|
|
class Parser {
|
|
private $elementStack;
|
|
private $svg;
|
|
private $transformStack;
|
|
private $characterDataStack;
|
|
|
|
public function parse($SVGstring) {
|
|
//reset the stack of elements in case someone already ran this
|
|
unset($this->elementStack);
|
|
$this->elementStack = array();
|
|
|
|
//reset the stack of transforms in case someone already ran this
|
|
unset($this->transformStack);
|
|
$this->transformStack = array();
|
|
|
|
//reset the stack of character data (this is used for the text fields)
|
|
$this->characterDataStack = array();
|
|
|
|
$this->svg = new SVG();
|
|
|
|
//create the parser object
|
|
$parser = xml_parser_create();
|
|
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); //set to 0 so all the elements don't get converted to upper case
|
|
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); //we don't like extra white-space so skip it
|
|
|
|
//set the handlers
|
|
xml_set_element_handler($parser, array($this, "startElementHandler"), array($this,"endElementHandler"));
|
|
xml_set_character_data_handler($parser, array($this, "characterDataHandler"));
|
|
|
|
xml_parse($parser, $SVGstring);
|
|
xml_parser_free($parser); //parser... be free!!!
|
|
|
|
return $this->svg;
|
|
}
|
|
|
|
private function startElementHandler($parser, $name, $attribs) {
|
|
$currentTransform = new Transform();
|
|
|
|
switch ($name) {
|
|
case "path":
|
|
$path = new Path();
|
|
if (array_key_exists("id", $attribs))
|
|
$path->setId($attribs["id"]);
|
|
if (array_key_exists("d", $attribs))
|
|
$path->setPath($attribs["d"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$path->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$path->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$path->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$path->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("fill", $attribs))
|
|
$path->setFill($attribs["fill"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$path->setTransforms($attribs["transform"]);
|
|
$currentTransform = $path->getTransform();
|
|
}
|
|
$this->elementStack[] = $path;
|
|
break;
|
|
case "rect":
|
|
$rect = new Rectangle();
|
|
if (array_key_exists("id", $attribs))
|
|
$rect->setId($attribs["id"]);
|
|
if (array_key_exists("x", $attribs))
|
|
$rect->setX($attribs["x"]);
|
|
if (array_key_exists("y", $attribs))
|
|
$rect->setY($attribs["y"]);
|
|
if (array_key_exists("height", $attribs))
|
|
$rect->setHeight($attribs["height"]);
|
|
if (array_key_exists("width", $attribs))
|
|
$rect->setWidth($attribs["width"]);
|
|
if (array_key_exists("rx", $attribs))
|
|
$rect->setRx($attribs["rx"]);
|
|
if (array_key_exists("ry", $attribs))
|
|
$rect->setRy($attribs["ry"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$rect->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$rect->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$rect->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$rect->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("fill", $attribs))
|
|
$rect->setFill($attribs["fill"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$rect->setTransforms($attribs["transform"]);
|
|
$currentTransform = $rect->getTransform();
|
|
}
|
|
$this->elementStack[] = $rect;
|
|
break;
|
|
case "circle":
|
|
$circle = new Circle();
|
|
if (array_key_exists("id", $attribs))
|
|
$circle->setId($attribs["id"]);
|
|
if (array_key_exists("cx", $attribs))
|
|
$circle->setCx($attribs["cx"]);
|
|
if (array_key_exists("cy", $attribs))
|
|
$circle->setCy($attribs["cy"]);
|
|
if (array_key_exists("r", $attribs))
|
|
$circle->setR($attribs["r"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$circle->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$circle->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$circle->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$circle->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("fill", $attribs))
|
|
$circle->setFill($attribs["fill"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$circle->setTransforms($attribs["transform"]);
|
|
$currentTransform = $circle->getTransform();
|
|
}
|
|
$this->elementStack[] = $circle;
|
|
break;
|
|
case "ellipse":
|
|
$ellipse = new Ellipse();
|
|
if (array_key_exists("id", $attribs))
|
|
$ellipse->setId($attribs["id"]);
|
|
if (array_key_exists("cx", $attribs))
|
|
$ellipse->setCx($attribs["cx"]);
|
|
if (array_key_exists("cy", $attribs))
|
|
$ellipse->setCy($attribs["cy"]);
|
|
if (array_key_exists("rx", $attribs))
|
|
$ellipse->setRx($attribs["rx"]);
|
|
if (array_key_exists("ry", $attribs))
|
|
$ellipse->setRy($attribs["ry"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$ellipse->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$ellipse->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$ellipse->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$ellipse->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("fill", $attribs))
|
|
$ellipse->setFill($attribs["fill"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$ellipse->setTransforms($attribs["transform"]);
|
|
$currentTransform = $ellipse->getTransform();
|
|
}
|
|
$this->elementStack[] = $ellipse;
|
|
break;
|
|
case "line":
|
|
$line = new Line();
|
|
if (array_key_exists("id", $attribs))
|
|
$line->setId($attribs["id"]);
|
|
if (array_key_exists("x1", $attribs))
|
|
$line->setX1($attribs["x1"]);
|
|
if (array_key_exists("y1", $attribs))
|
|
$line->setY1($attribs["y1"]);
|
|
if (array_key_exists("x2", $attribs))
|
|
$line->setX2($attribs["x2"]);
|
|
if (array_key_exists("y2", $attribs))
|
|
$line->setY2($attribs["y2"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$line->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$line->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$line->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$line->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$line->setTransforms($attribs["transform"]);
|
|
$currentTransform = $line->getTransform();
|
|
}
|
|
$this->elementStack[] = $line;
|
|
break;
|
|
case "polyline":
|
|
$polyline = new Polyline();
|
|
if (array_key_exists("id", $attribs))
|
|
$polyline->setId($attribs["id"]);
|
|
if (array_key_exists("points", $attribs))
|
|
$polyline->setPoints($attribs["points"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$polyline->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$polyline->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$polyline->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$polyline->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$polyline->setTransforms($attribs["transform"]);
|
|
$currentTransform = $polyline->getTransform();
|
|
}
|
|
$this->elementStack[] = $polyline;
|
|
break;
|
|
case "text":
|
|
case "tspan":
|
|
$text = new Text();
|
|
if (array_key_exists("id", $attribs))
|
|
$text->setId($attribs["id"]);
|
|
if (array_key_exists("x", $attribs))
|
|
$text->setX($attribs["x"]);
|
|
if (array_key_exists("y", $attribs))
|
|
$text->setY($attribs["y"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$text->setStyles($attribs["style"]);
|
|
if (array_key_exists("stroke", $attribs))
|
|
$text->setStroke($attribs["stroke"]);
|
|
if (array_key_exists("stroke-width", $attribs))
|
|
$text->setStrokeWidth($attribs["stroke-width"]);
|
|
if (array_key_exists("stroke-linecap", $attribs))
|
|
$text->setStrokeLinecap($attribs["stroke-linecap"]);
|
|
if (array_key_exists("fill", $attribs))
|
|
$text->setFill($attribs["fill"]);
|
|
if (array_key_exists("text-anchor", $attribs))
|
|
$text->setTextAnchor($attribs["text-anchor"]);
|
|
if (array_key_exists("text-decoration", $attribs))
|
|
$text->setTextDecoration($attribs["text-decoration"]);
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$text->setTransforms($attribs["transform"]);
|
|
$currentTransform = $text->getTransform();
|
|
}
|
|
$this->elementStack[] = $text;
|
|
break;
|
|
case "linearGradient":
|
|
$linearGradient = new LinearGradient();
|
|
if (array_key_exists("id", $attribs))
|
|
$linearGradient->setId($attribs["id"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$linearGradient->setStyles($attribs["style"]);
|
|
if (array_key_exists("gradientTransform", $attribs))
|
|
$linearGradient->setTransforms($attribs["gradientTransform"]);
|
|
if (array_key_exists("xlink:href", $attribs))
|
|
$linearGradient->setLink($attribs["xlink:href"]);
|
|
if (array_key_exists("x1", $attribs))
|
|
$linearGradient->setX1($attribs["x1"]);
|
|
if (array_key_exists("y1", $attribs))
|
|
$linearGradient->setY1($attribs["y1"]);
|
|
if (array_key_exists("x2", $attribs))
|
|
$linearGradient->setX2($attribs["x2"]);
|
|
if (array_key_exists("y2", $attribs))
|
|
$linearGradient->setY2($attribs["y2"]);
|
|
$this->elementStack[] = $linearGradient;
|
|
break;
|
|
case "stop":
|
|
$stop = new GradientStop();
|
|
if (array_key_exists("id", $attribs))
|
|
$stop->setId($attribs["id"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$stop->setStyles($attribs["style"]);
|
|
if (array_key_exists("offset", $attribs))
|
|
$stop->setOffset($attribs["offset"]);
|
|
$this->elementStack[] = $stop;
|
|
break;
|
|
case "radialGradient":
|
|
$radialGradient = new RadialGradient();
|
|
if (array_key_exists("id", $attribs))
|
|
$radialGradient->setId($attribs["id"]);
|
|
if (array_key_exists("style", $attribs))
|
|
$radialGradient->setStyles($attribs["style"]);
|
|
if (array_key_exists("gradientTransform", $attribs))
|
|
$radialGradient->setTransforms($attribs["gradientTransform"]);
|
|
if (array_key_exists("xlink:href", $attribs))
|
|
$radialGradient->setLink($attribs["xlink:href"]);
|
|
if (array_key_exists("cx", $attribs))
|
|
$radialGradient->setCx($attribs["cx"]);
|
|
if (array_key_exists("cy", $attribs))
|
|
$radialGradient->setCy($attribs["cy"]);
|
|
if (array_key_exists("r", $attribs))
|
|
$radialGradient->setR($attribs["r"]);
|
|
if (array_key_exists("fx", $attribs))
|
|
$radialGradient->setFx($attribs["fx"]);
|
|
if (array_key_exists("fy", $attribs))
|
|
$radialGradient->setFy($attribs["fy"]);
|
|
$this->elementStack[] = $radialGradient;
|
|
break;
|
|
case "g":
|
|
if (array_key_exists("transform", $attribs)) {
|
|
$element = new Element();
|
|
$element->setTransforms($attribs["transform"]);
|
|
$currentTransform = $element->getTransform();
|
|
}
|
|
break;
|
|
}
|
|
//dump the transforms on the stack of them so if there are any nested elements, they can access them
|
|
$this->transformStack[] = $currentTransform;
|
|
}
|
|
|
|
private function characterDataHandler($parser, $data) {
|
|
$this->characterDataStack[] = $data;
|
|
}
|
|
|
|
private function endElementHandler($parser, $name) {
|
|
//as well as the last text data
|
|
$lastText = array_pop($this->characterDataStack);
|
|
|
|
switch ($name) {
|
|
case "path":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addPath($element);
|
|
break;
|
|
case "rect":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addRectangle($element);
|
|
break;
|
|
case "circle":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addCircle($element);
|
|
break;
|
|
case "ellipse":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addEllipse($element);
|
|
break;
|
|
case "line":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addLine($element);
|
|
break;
|
|
case "polyline":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$this->svg->addPolyline($element);
|
|
break;
|
|
case "text":
|
|
case "tspan":
|
|
$element = array_pop($this->elementStack);
|
|
$element->setTransform($this->getFullCurrentTransform());
|
|
$element->setText($lastText);
|
|
//add the element only if the text has at least some non-whitespace
|
|
if (trim($lastText) != "")
|
|
$this->svg->addText($element);
|
|
break;
|
|
case "linearGradient":
|
|
$this->svg->addLinearGradient(array_pop($this->elementStack));
|
|
break;
|
|
case "stop":
|
|
$stop = array_pop($this->elementStack);
|
|
if ($this->elementStack[count($this->elementStack)-1] instanceof Gradient)
|
|
$this->elementStack[count($this->elementStack)-1]->addStop($stop);
|
|
break;
|
|
case "radialGradient":
|
|
$this->svg->addRadialGradient(array_pop($this->elementStack));
|
|
break;
|
|
}
|
|
|
|
//pop the last transform off the stack
|
|
array_pop($this->transformStack);
|
|
}
|
|
|
|
private function getFullCurrentTransform() {
|
|
$one = new Transform();
|
|
foreach ($this->transformStack as $transform)
|
|
$one->multiplyBy($transform);
|
|
return $one;
|
|
}
|
|
}
|
|
?>
|