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; } } ?>