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