diff --git a/Log.php b/Log.php new file mode 100644 index 0000000..15f0bac --- /dev/null +++ b/Log.php @@ -0,0 +1,71 @@ +logfile = fopen($file, 'ab+'); + $this->message('Starting log'); + } + + /** + * @param $message + * @return false|int + */ + public function message($message) + { + $message = '[' . date('Y-m-d / H:i:s') . '] @MESSAGE' . ' - ' . $message; + $message .= "\n"; + return fwrite($this->logfile, $message); + } + + /** + * @param $message + * @return false|int + */ + public function error($message) + { + $message = '[' . date('Y-m-d / H:i:s') . '] @ERROR' . ' - ' . $message; + $message .= "\n"; + return fwrite($this->logfile, $message); + } + + /** + * + */ + public function __destruct() + { + $this->message("Finishing log\n-----------------------"); + fclose($this->logfile); + } + + /** + * @param mixed $message + * @return string + */ + public static function decode($message) + { + if (is_string($message)) { + return $message; + } + + if (is_array($message)) { + return implode('|', $message); + } + + if ($message instanceof SimpleXMLElement) { + return (string) $message; + } + + return ''; + } +} + diff --git a/SvgToImage.php b/SvgToImage.php new file mode 100644 index 0000000..6eb8cb1 --- /dev/null +++ b/SvgToImage.php @@ -0,0 +1,1350 @@ +0 + +include 'Log.php'; + +class SvgToImage +{ + protected $_svgXML; + protected $_image; + protected $_log; + protected $_x; + protected $_y; + protected $_width; + protected $_height; + protected $_showDesc = false; + protected $_desc; + protected $_currentOptions = []; + private $transparentColor = [0, 0, 255]; + public $_debug = true; // change to false to stop debug mode + + /** + * array of path type + */ + private $pathType = [ + 'm' => 'MoveTo', + 'l' => 'LineTo', + 'h' => 'HorizontalLineTo', + 'v' => 'VerticalLineTo', + 'c' => 'CurveTo', + 'z' => 'EndingLine', + ]; + + /** + * array of color names => rgb color + * because some svg creator uses them + * used http://www.yoyodesign.org/doc/w3c/svg1/types.html#ColorKeywords + */ + private $colors = [ + 'aliceblue' => [240, 248, 255], + 'antiquewhite' => [250, 235, 215], + 'aqua' => [0, 255, 255], + 'aquamarine' => [127, 255, 212], + 'azure' => [240, 255, 255], + 'beige' => [245, 245, 220], + 'bisque' => [255, 228, 196], + 'black' => [0, 0, 0], + 'blanchedalmond' => [255, 235, 205], + 'blue' => [0, 0, 255], + 'blueviolet' => [138, 43, 226], + 'brown' => [165, 42, 42], + 'burlywood' => [222, 184, 135], + 'cadetblue' => [95, 158, 160], + 'chartreuse' => [127, 255, 0], + 'chocolate' => [210, 105, 30], + 'coral' => [255, 127, 80], + 'cornflowerblue' => [100, 149, 237], + 'cornsilk' => [255, 248, 220], + 'crimson' => [220, 20, 60], + 'cyan' => [0, 255, 255], + 'darkblue' => [0, 0, 139], + 'darkcyan' => [0, 139, 139], + 'darkgoldenrod' => [184, 134, 11], + 'darkgray' => [169, 169, 169], + 'darkgreen' => [0, 100, 0], + 'darkgrey' => [169, 169, 169], + 'darkkhaki' => [189, 183, 107], + 'darkmagenta' => [139, 0, 139], + 'darkolivegreen' => [85, 107, 47], + 'darkorange' => [255, 140, 0], + 'darkorchid' => [153, 50, 204], + 'darkred' => [139, 0, 0], + 'darksalmon' => [233, 150, 122], + 'darkseagreen' => [143, 188, 143], + 'darkslateblue' => [72, 61, 139], + 'darkslategray' => [47, 79, 79], + 'darkslategrey' => [47, 79, 79], + 'darkturquoise' => [0, 206, 209], + 'darkviolet' => [148, 0, 211], + 'deeppink' => [255, 20, 147], + 'deepskyblue' => [0, 191, 255], + 'dimgray' => [105, 105, 105], + 'dimgrey' => [105, 105, 105], + 'dodgerblue' => [30, 144, 255], + 'firebrick' => [178, 34, 34], + 'floralwhite' => [255, 250, 240], + 'forestgreen' => [34, 139, 34], + 'fuchsia' => [255, 0, 255], + 'gainsboro' => [220, 220, 220], + 'ghostwhite' => [248, 248, 255], + 'gold' => [255, 215, 0], + 'goldenrod' => [218, 165, 32], + 'gray' => [128, 128, 128], + 'grey' => [128, 128, 128], + 'green' => [0, 128, 0], + 'greenyellow' => [173, 255, 47], + 'honeydew' => [240, 255, 240], + 'hotpink' => [255, 105, 180], + 'indianred' => [205, 92, 92], + 'indigo' => [75, 0, 130], + 'ivory' => [255, 255, 240], + 'khaki' => [240, 230, 140], + 'lavender' => [230, 230, 250], + 'lavenderblush' => [255, 240, 245], + 'lawngreen' => [124, 252, 0], + 'lemonchiffon' => [255, 250, 205], + 'lightblue' => [173, 216, 230], + 'lightcoral' => [240, 128, 128], + 'lightcyan' => [224, 255, 255], + 'lightgoldenrodyellow' => [250, 250, 210], + 'lightgray' => [211, 211, 211], + 'lightgreen' => [144, 238, 144], + 'lightgrey' => [211, 211, 211], + 'lightpink' => [255, 182, 193], + 'lightsalmon' => [255, 160, 122], + 'lightseagreen' => [32, 178, 170], + 'lightskyblue' => [135, 206, 250], + 'lightslategray' => [119, 136, 153], + 'lightslategrey' => [119, 136, 153], + 'lightsteelblue' => [176, 196, 222], + 'lightyellow' => [255, 255, 224], + 'lime' => [0, 255, 0], + 'limegreen' => [50, 205, 50], + 'linen' => [250, 240, 230], + 'magenta' => [255, 0, 255], + 'maroon' => [128, 0, 0], + 'mediumaquamarine' => [102, 205, 170], + 'mediumblue' => [0, 0, 205], + 'mediumorchid' => [186, 85, 211], + 'mediumpurple' => [147, 112, 219], + 'mediumseagreen' => [60, 179, 113], + 'mediumslateblue' => [123, 104, 238], + 'mediumspringgreen' => [0, 250, 154], + 'mediumturquoise' => [72, 209, 204], + 'mediumvioletred' => [199, 21, 133], + 'midnightblue' => [25, 25, 112], + 'mintcream' => [245, 255, 250], + 'mistyrose' => [255, 228, 225], + 'moccasin' => [255, 228, 181], + 'navajowhite' => [255, 222, 173], + 'navy' => [0, 0, 128], + 'oldlace' => [253, 245, 230], + 'olive' => [128, 128, 0], + 'olivedrab' => [107, 142, 35], + 'orange' => [255, 165, 0], + 'orangered' => [255, 69, 0], + 'orchid' => [218, 112, 214], + 'palegoldenrod' => [238, 232, 170], + 'palegreen' => [152, 251, 152], + 'paleturquoise' => [175, 238, 238], + 'palevioletred' => [219, 112, 147], + 'papayawhip' => [255, 239, 213], + 'peachpuff' => [255, 218, 185], + 'peru' => [205, 133, 63], + 'pink' => [255, 192, 203], + 'plum' => [221, 160, 221], + 'powderblue' => [176, 224, 230], + 'purple' => [128, 0, 128], + 'red' => [255, 0, 0], + 'rosybrown' => [188, 143, 143], + 'royalblue' => [65, 105, 225], + 'saddlebrown' => [139, 69, 19], + 'salmon' => [250, 128, 114], + 'sandybrown' => [244, 164, 96], + 'seagreen' => [46, 139, 87], + 'seashell' => [255, 245, 238], + 'sienna' => [160, 82, 45], + 'silver' => [192, 192, 192], + 'skyblue' => [135, 206, 235], + 'slateblue' => [106, 90, 205], + 'slategray' => [112, 128, 144], + 'slategrey' => [112, 128, 144], + 'snow' => [255, 250, 250], + 'springgreen' => [0, 255, 127], + 'steelblue' => [70, 130, 180], + 'tan' => [210, 180, 140], + 'teal' => [0, 128, 128], + 'thistle' => [216, 191, 216], + 'tomato' => [255, 99, 71], + 'turquoise' => [64, 224, 208], + 'violet' => [238, 130, 238], + 'wheat' => [245, 222, 179], + 'white' => [255, 255, 255], + 'whitesmoke' => [245, 245, 245], + 'yellow' => [255, 255, 0], + 'yellowgreen' => [154, 205, 50] + ]; + + /** + * constructor + * parse the svg with simplexml + * @param string $svg SVG as string + */ + public function __construct($svg) + { + if ($this->_debug) { + $this->_log = new Log('log.dat'); + } + $this->_svgXML = simplexml_load_string($svg); + } + + /** + * Construct with a file + * @param string path to the file + * @return SVGTOIMAGE instance of this class + */ + public static function load($file) + { + $svg = file_get_contents($file); + return new SVGTOIMAGE($svg); + } + + /** + * Construct with a string + * @param string ... + * @return SVGTOIMAGE instance of this class + */ + public static function parse($xml) + { + return new SVGTOIMAGE($xml); + } + + /** + * Destroy the GD Image when finished + */ + public function __destruct() + { + imagedestroy($this->_image); + } + + /** + * setter - option : show the description from the svg into the image if present + * @param boolean + */ + public function setShowDesc($showDesc = true) + { + if (is_bool($showDesc)) { + //if($this->_debug) $this->_log->message('Passage de showDesc en '.$showDesc); + $this->_showDesc = $showDesc; + } else if ($this->_debug) { + $this->_log->error('Erreur dans la fonction showDesc, doit recevoir booléen, a reçu : ' . $showDesc); + } + } + + /** + * setter - option : origin of the final image from the svg (default : 0) + * @param int + */ + public function setX($x) + { + if (is_int($x)) { + //if($this->_debug) $this->_log->message('Passage de x en '.$x); + $this->_x = $x; + } elseif ($this->_debug) { + $this->_log->error('Erreur dans la fonction setX, doit recevoir int, a reçu : ' . $x); + } + } + + /** + * setter - option : origin of the final image from the svg (default : 0) + * @param int + */ + public function setY($y) + { + if (is_int($y)) { + //if($this->_debug) $this->_log->message('Passage de y en '.$y); + $this->_y = $y; + } elseif ($this->_debug) { + $this->_log->error('Erreur dans la fonction setY, doit recevoir int, a reçu : ' . $y); + } + } + + /** + * setter - option : width of the final image (default : svg width) + * @param int + */ + public function setWidth($width) + { + if (is_int($width)) { + //if($this->_debug) $this->_log->message('Passage de width en '.$width); + $this->_width = $width; + } elseif ($this->_debug) { + $this->_log->error('Erreur dans la fonction setWidth, doit recevoir int, a reçu : ' . $width); + } + } + + /** + * setter - option : height of the final image (default : svg height) + * @param int + */ + public function setHeight($height) + { + if (is_int($height)) { + //if($this->_debug) $this->_log->message('Passage de height en '.$height); + $this->_height = $height; + } elseif ($this->_debug) { + $this->_log->error('Erreur dans la fonction setHeight, doit recevoir int, a reçu : ' . $height); + } + } + + /** + * @param string $size size of picture or element + * @return int "real" size of element. To eliminate SVG with centimeters + */ + private function _getSizeType($size) + { + $size = rtrim($size); + $unit = substr($size, -2, 2); + $value = (int)substr($size, 0, -2); + switch ($unit) { + case 'cm': + return $value * 30; // approximatively + break; + case 'in': + return $value * 12; // approximatively + break; + case 'px': + case 'pt': + return $value; + default: + return (int) $size; + } + } + + /** + * @return int final image width + */ + private function _getImageWidth() + { + return isset($this->_width) ? $this->_width : $this->_getSizeType($this->_svgXML->attributes()->width); + } + + /** + * @return int final image height + */ + private function _getImageHeight() + { + return isset($this->_height) ? $this->_height : $this->_getSizeType($this->_svgXML->attributes()->height); + } + + /** + * @param string Color code (ie: #CCC , #FE4323, etc...) + * @return array with R | G | B + */ + private function _parseColor($colorCode) + { + if ($colorCode instanceof SimpleXMLElement) { + $colorCode = (string) $colorCode; + } + if (is_string($colorCode) && strlen($colorCode) === 7) { + return [ + base_convert(substr($colorCode, 1, 2), 16, 10), + base_convert(substr($colorCode, 3, 2), 16, 10), + base_convert(substr($colorCode, 5, 2), 16, 10), + ]; + } + if (is_string($colorCode) && strlen($colorCode) === 4) { + return [ + base_convert($colorCode[1] . $colorCode[1], 16, 10), + base_convert($colorCode[2] . $colorCode[2], 16, 10), + base_convert($colorCode[3] . $colorCode[3], 16, 10), + ]; + } + if (is_array($colorCode) && count($colorCode) === 3) { + return $colorCode; + } + if ($this->_debug) { + $this->_log->error('Couleur mal indiquée ' . Log::decode($colorCode)); + } + return [0, 0, 0]; // !#FFF || !#FFFFFF || !array(255,255,255) then black + } + + /** + * Allocate color to the final image thanks to _parseColor (check if the color isn't spelled directly 'black') + * @param string color code + * @return false|int|void on the image + */ + private function _allocateColor($color) + { + if ($color !== '') { + if (array_key_exists(strtolower($color), $this->colors)) { + $arrayColor = $this->_parseColor($this->colors[strtolower($color)]); + } else { + $arrayColor = $this->_parseColor($color); + } + return imagecolorallocate($this->_image, $arrayColor[0], $arrayColor[1], $arrayColor[2]); + } + + return null; + } + + /** + * return an array to use with imagesetstyle + * @param int $full + * @param int $empty + * @param $color + * @return array + */ + private function _getDashedStroke($full, $empty, $color) + { + $tiret = []; + for ($i = 0; $i < $full; $i++) { + $tiret[] = $color; + } + for ($i = 0; $i < $empty; $i++) { + $tiret[] = IMG_COLOR_TRANSPARENT; + } + //if($this->_debug) $this->_log->message('nouveaux tirets : '.Log::decode($tiret)); + return $tiret; + } + + /** + * @param $paramName + * @return mixed|null + */ + private function _getParam($paramName) + { + $currentOptions = $this->_getAllParams(); + return isset($currentOptions[$paramName]) ? $currentOptions[$paramName] : null; + } + + /** + * @return array + */ + private function _getAllParams() + { + $newarr = []; + foreach ($this->_currentOptions as $array) { + $newarr = array_merge($newarr, $array); + } + return $newarr; + } + + /** + * @param SimpleXMLElement $element + * @return array options + */ + private function _getParams($element) + { + $options = $this->_getAllParams(); + foreach ($element->attributes() as $name => $value) { + switch ($name) { + case 'x': + case 'y': + case 'r': + case 'width': + case 'height': + $options[$name] = $this->_getSizeType($value); + break; + case 'cx': + $options['x'] = $this->_getSizeType($value); + break; + case 'cy': + $options['y'] = $this->_getSizeType($value); + break; + case 'xlink:href': + $options['href'] = $value; + break; + case 'd': + case 'points': + $options['path'] = (string)$value; + break; + case 'fill': + $options['fill'] = ($value == 'none') ? '' : $value; + break; + case 'stroke-width' : + $options['strokeWidth'] = $value; + break; + case 'stroke-dasharray' : + $options['strokeDasharray'] = $value; + break; + case 'font-size': + $options['fontSize'] = $value; + break; + case 'font-family': + $options['fontFamily'] = $value; + break; + case 'font-style': + $options['fontStyle'] = $value; + break; + case 'font-weight': + $options['fontWeight'] = $value; + break; + case 'transform': // transform="matrix(1.006896,0,0,1.006896,0.3043,-0.708342)" + $transform = preg_split('/[()]/', $value); + if (count($transform) === 3) { + $typeTransform = $transform[0]; + switch ($typeTransform) { + case 'translate': + list($options['originX'], $options['originY']) = explode(',', $transform[1]); + break; + case 'rotate': + $options['rotate'] = $transform[1]; + break; + case 'scale': + $options['scale'] = $transform[1]; + break; + default: + break; + } + } + break; + case 'style' : + $allStyle = preg_split('/[;:]/', $value); + $i = 0; + while ($i < count($allStyle)) { + if ($allStyle[$i] === 'display' && $allStyle[$i + 1] === 'none') { + // display:none? Stop looking for info + return null; + } + if ($allStyle[$i] === 'fill') { + $options['fill'] = $allStyle[$i + 1]; + } + if ($allStyle[$i] === 'stroke') { + $options['stroke'] = $allStyle[$i + 1]; + } + if ($allStyle[$i] === 'stroke-width') { + $options['strokeWidth'] = $allStyle[$i + 1]; + } + $i += 2; + } + break; + default: + $options[$name] = $value; + break; + } + } + return $options; + } + + /** + * add the given image from svg to the final image + * @param simpleXMLElement + * @return bool + */ + private function _parseImage($imageNode) + { + $x = 0; + $y = 0; + $width = 0; + $height = 0; + $href = ''; + $transform = ''; + $r = 0; + extract($this->_getParams($imageNode), EXTR_OVERWRITE); + //case translate + if ($this->_getParam('originX') !== null) { + $x += $this->_getParam('originX'); + } + if ($this->_getParam('originY') !== null) { + $y += $this->_getParam('originY'); + } + //end translate + if ($transform !== '') { + $transforms = preg_split('/[()]/', $transform); + foreach ($transforms as $i => $iValue) { + // rotation + if ($iValue === 'rotate') { + $rotinfo = $transforms[$i + 1]; + $rotinfo = explode(' ', $rotinfo); + $r = $rotinfo[0]; + } + } + } + if ($width === 0 || $height === 0 || $href === '') { + return null; + } + + $imageTypeArray = explode('.', $href); + $lastElementFromImageType = count($imageTypeArray); + $imageType = $imageTypeArray[$lastElementFromImageType - 1]; + if ($imageType === 'jpg' || $imageType === 'jpeg') { + $newImage = imagecreatefromjpeg((string)$href); + } elseif ($imageType === 'png') { + $newImage = imagecreatefrompng((string)$href); + } elseif ($imageType === 'gif') { + $newImage = imagecreatefromgif((string)$href); + } else { + return null; + } + if (false === $newImage) { + return null; + } + + imagealphablending($newImage, true); + + //rotating the image if needed + if ($r !== 0) { + if ($this->_debug) { + if ($newImage = imagerotate($newImage, -(float)$r, -1)) { + $this->_log->message('Rotating image'); + } else { + $this->_log->error('Rotating image'); + } + } else { + $newImage = imagerotate($newImage, -(float)$r, -1); + } + if (false === $newImage) { + return null; + } + $blue = imagecolorallocate($newImage, $this->transparentColor[0], $this->transparentColor[1], $this->transparentColor[2]); + imagecolortransparent($newImage, $blue); + } + $newWidth = imagesx($newImage); + $newHeight = imagesy($newImage); + + return imagecopy($this->_image, $newImage, ($newWidth === $width) ? $x : $x - ($newWidth - $width) / 2, ($newHeight === $height) ? $y : $y - ($newHeight - $height) / 2, 0, 0, imagesx($newImage), imagesy($newImage)); // Thanks Raphael & GD for saying things wrong. + } + + /** + * small function to find int into a string - works like java parseint + * @param string containing numbers + * @return int + */ + private function _parseInt($string) + { + if (preg_match('/[-]?(\d+)/', $string, $array)) { + return $array[0]; + } + + return 0; + } + + /** + * add a line to the final image + * @param $x1 int position of segment + * @param $y1 int + * @param $x2 int + * @param $y2 int + * @param $color + * @return bool + */ + private function _drawLine($x1, $y1, $x2, $y2, $color) + { + if (!imageline($this->_image, $x1, $y1, $x2, $y2, $color)) { + if ($this->_debug) { + $this->_log->error('Chemin erroné : ' . $x1 . ' - ' . $y1 . ' - ' . $x2 . ' - ' . $y2); + } + return false; + } + + if ($this->_debug) { + $this->_log->message('Chemin : ' . $x1 . ' - ' . $y1 . ' - ' . $x2 . ' - ' . $y2); + } + + return true; + } + + /** + * add a curve to the final image + * @param $startX int position of start, controls and end points + * @param $startY int + * @param $control1X int + * @param $control1Y int + * @param $control2X int + * @param $control2Y int + * @param $endX int + * @param $endY int + * @param $color + */ + private function _drawCurve($startX, $startY, $control1X, $control1Y, $control2X, $control2Y, $endX, $endY, $color) + { + $cx = 3 * ($control1X - $startX); + $bx = 3 * ($control2X - $control1X) - $cx; + $ax = $endX - $startX - $cx - $bx; + + $cy = 3 * ($control1Y - $startY); + $by = 3 * ($control2Y - $control1Y) - $cy; + $ay = $endY - $startY - $cy - $by; + //if($this->_debug) $this->_log->message('ax : '.$ax.', ay : '.$ay); + for ($t = 0; $t < 1; $t += .01) { + $xt = $ax * $t * $t * $t + $bx * $t * $t + $cx * $t + $startX; + $yt = $ay * $t * $t * $t + $by * $t * $t + $cy * $t + $startY; + imagesetpixel($this->_image, $xt, $yt, $color); + } + } + + + /*EXPERIMENTS*/ + + /** + * Calculate the coordinate of the Bezier curve at $t = 0..1 + * + * @param $p1 + * @param $p2 + * @param $p3 + * @param $p4 + * @param $t + * @return array + */ + private function _Bezier_eval($p1, $p2, $p3, $p4, $t) + { + // lines between successive pairs of points (degree 1) + $q1 = array((1 - $t) * $p1[0] + $t * $p2[0], (1 - $t) * $p1[1] + $t * $p2[1]); + $q2 = array((1 - $t) * $p2[0] + $t * $p3[0], (1 - $t) * $p2[1] + $t * $p3[1]); + $q3 = array((1 - $t) * $p3[0] + $t * $p4[0], (1 - $t) * $p3[1] + $t * $p4[1]); + // curves between successive pairs of lines. (degree 2) + $r1 = array((1 - $t) * $q1[0] + $t * $q2[0], (1 - $t) * $q1[1] + $t * $q2[1]); + $r2 = array((1 - $t) * $q2[0] + $t * $q3[0], (1 - $t) * $q2[1] + $t * $q3[1]); + // final curve between the two 2-degree curves. (degree 3) + return array((1 - $t) * $r1[0] + $t * $r2[0], (1 - $t) * $r1[1] + $t * $r2[1]); + } + + /** + * Calculate the squared distance between two points + * + * @param $p1 + * @param $p2 + * @return float|int + */ + private function _Point_distance2($p1, $p2) + { + $dx = $p2[0] - $p1[0]; + $dy = $p2[1] - $p1[1]; + return $dx * $dx + $dy * $dy; + } + + /** + * Convert the curve to a polyline + * + * @param $p1 + * @param $p2 + * @param $p3 + * @param $p4 + * @param $tolerance + * @return array + */ + private function _Bezier_convert($p1, $p2, $p3, $p4, $tolerance) + { + $t1 = 0.0; + $prev = $p1; + $t2 = 0.1; + $tol2 = $tolerance * $tolerance; + $result [] = $prev[0]; + $result [] = $prev[1]; + while ($t1 < 1.0) { + if ($t2 > 1.0) { + $t2 = 1.0; + } + $next = $this->_Bezier_eval($p1, $p2, $p3, $p4, $t2); + $dist = $this->_Point_distance2($prev, $next); + while ($dist > $tol2) { + // Halve the distance until small enough + $t2 = $t1 + ($t2 - $t1) * 0.5; + $next = $this->_Bezier_eval($p1, $p2, $p3, $p4, $t2); + $dist = $this->_Point_distance2($prev, $next); + } + // the image*polygon functions expect a flattened array of coordiantes + $result [] = $next[0]; + $result [] = $next[1]; + $t1 = $t2; + $prev = $next; + $t2 = $t1 + 0.1; + } + return $result; + } + + /** + * Draw a Bezier curve on an image + * + * @param $p1 + * @param $p2 + * @param $p3 + * @param $p4 + * @param $color + * @return array + */ + private function _Bezier_drawfilled($p1, $p2, $p3, $p4, $color) + { + return $this->_Bezier_convert($p1, $p2, $p3, $p4, 0.1); + } + + /*END OF EXPERIMENT*/ + + /** + * @param $polygon + * @param string $stroke + * @param string $fill + */ + private function _drawPolygon($polygon, $stroke = '', $fill = '') + { + //if($this->_debug) $this->_log->message('_drawPolygon : fill : '.$fill.' stroke:'.$stroke); + if ($fill !== '' && count($polygon) >= 6) { + //if($this->_debug) $this->_log->message('polygon rempli : '.$fill); + imagefilledpolygon($this->_image, $polygon, count($polygon) / 2, $fill); + if ($stroke !== '') { + imagepolygon($this->_image, $polygon, count($polygon) / 2, $stroke); + } + } elseif (count($polygon) >= 6) { + //if($this->_debug) $this->_log->message('polygon non rempli : '.$stroke); + imagepolygon($this->_image, $polygon, count($polygon) / 2, $stroke); + //imagepolygon($this->_image, $polygon, count($polygon)/2, IMG_COLOR_STYLED); + } elseif (count($polygon) === 4) { + //if($this->_debug) $this->_log->message('ligne via polygon : '.$stroke); + $this->_drawLine($polygon[0], $polygon[1], $polygon[2], $polygon[3], $stroke); + } + } + + + /** + * add path/lineS/polyline whatever you name it. + * @param simpleXMLElement + * @return null + */ + private function _parsePath($pathNode) + { + $path = ''; + $strokeWidth = 1; + $fill = ''; + $stroke = ''; + $strokeDasharray = ''; + + extract($this->_getParams($pathNode), EXTR_OVERWRITE); + + if (stripos($path, 'm') !== 0 && !is_numeric($path[0])) { + if ($this->_debug) { + $this->_log->error('Mauvais path rencontré : ' . $path); + } + return null; + } + + $thickness = imagesetthickness($this->_image, $this->_parseInt($strokeWidth)); + if ($this->_debug && !$thickness) { + $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); + } else { + $this->_log->message('épaisseur du trait à : ' . $this->_parseInt($strokeWidth)); + } + + $colorStroke = $stroke !== '' ? $this->_allocateColor($stroke) : ($fill === '' ? $this->_allocateColor('black') : ''); + $colorFill = $fill !== '' ? $this->_allocateColor($fill) : ''; + + if ($this->_debug) { + $this->_log->message('colors ! fill:' . $colorFill . 'stroke:' . $colorStroke); + } + + if ($strokeDasharray !== '') { + $strokeDasharray = explode(',', $strokeDasharray); + imagesetstyle($this->_image, $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke)); + } else { + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + } + + $lastOpe = ''; + + $pathArray = preg_split('/[ ,]/', $path); + + // Si le path est de format 'm 100 100 l 100 100 z' il faut recoller les morceaux + if (array_key_exists(strtolower($pathArray[0]), $this->pathType)) { + $j = 0; + do { + if (array_key_exists(strtolower($pathArray[$j]), $this->pathType)) { + $pathArray[$j] .= $pathArray[$j + 1]; + $pathArray[$j + 1] = '~'; + $j++; + $newNb = count($pathArray); + for ($k = $j; $k <= $newNb; $k++) { + $pathArray[$k] = $pathArray[$k + 1]; + } + } else { + if ($pathArray[$j] === '' || $pathArray[$j] === null) { + unset($pathArray[$j]); + } + $j++; + } + } while (isset($pathArray[$j])); + //if($this->_debug) $this->_log->message('Path reconstruit ! '.implode(', ',$pathArray)); + } + + $nbArray = count($pathArray); + $polyPoints = []; + $i = 0; + $lastX = 0; + $lastY = 0; + $lastMX = 0; + $lastMY = 0; + while ($i < $nbArray) { + // Changement de départ + if (stripos($pathArray[$i], 'm') === 0) { + if (isset($pathArray[$i - 1])) { + $this->_drawPolygon($polyPoints, $colorStroke, $colorFill); + $polyPoints = []; + } + $lastX = $this->_parseInt($pathArray[$i]); + $lastMX = $this->_parseInt($pathArray[$i]); + $lastY = $this->_parseInt($pathArray[$i + 1]); + $lastMY = $this->_parseInt($pathArray[$i + 1]); + $lastOpe = 'm'; + $i += 2; + // Ligne + } elseif (stripos($pathArray[$i], 'l') === 0 || (is_numeric($pathArray[$i]) && strtolower($lastOpe) === 'l')) { +// if (stripos($pathArray[$i], 'l') === 0) { + $newX = $this->_parseInt($pathArray[$i]); + $newY = $this->_parseInt($pathArray[$i + 1]); +// } else { +// $newX = $lastX + $this->_parseInt($pathArray[$i]); +// $newY = $lastY + $this->_parseInt($pathArray[$i + 1]); +// } + $polyPoints = array_merge($polyPoints, [$lastX, $lastY, $newX, $newY]); + //$this->_drawLine($lastX , $lastY , $newX , $newY , IMG_COLOR_STYLED); + $lastOpe = 'l'; + $lastX = $newX; + $lastY = $newY; + $i += 2; + // Ligne horizontale + } elseif (stripos($pathArray[$i], 'h') === 0 || (is_numeric($pathArray[$i]) && (strtolower($lastOpe) === 'h'))) { + if (strpos($pathArray[$i], 'H') === 0) { + $newX = $this->_parseInt($pathArray[$i]); + } else { + $newX = $lastX + $this->_parseInt($pathArray[$i]); + } + //$this->_drawLine($lastX , $lastY , $newX , $lastY , IMG_COLOR_STYLED); + $polyPoints = array_merge($polyPoints, array($lastX, $lastY, $newX, $newY)); + $lastOpe = 'h'; + $lastX = $newX; + $i++; + // Ligne verticale + } elseif (stripos($pathArray[$i], 'v') === 0 || (is_numeric($pathArray[$i]) && strtolower($lastOpe) === 'v')) { + if (strpos($pathArray[$i], 'V') === 0) { + $newY = $this->_parseInt($pathArray[$i]); + } else { + $newY = $lastY + $this->_parseInt($pathArray[$i]); + } + if (!isset($newX)) { + $newX = $lastX; + } + //$this->_drawLine($lastX , $lastY , $lastX , $newY , IMG_COLOR_STYLED); + $polyPoints = array_merge($polyPoints, [$lastX, $lastY, $newX, $newY]); + $lastY = $newY; + $lastOpe = 'v'; + $i++; + // Courbe + } elseif (stripos($pathArray[$i], 'c') === 0 || (is_numeric($pathArray[$i]) && strtolower($lastOpe) === 'c')) { + /*SPECIF !!! http://www.w3.org/TR/SVG/paths.html*/ + if (strpos($pathArray[$i], 'C') === 0) { + $control1x = $this->_parseInt($pathArray[$i]); + $control1y = $this->_parseInt($pathArray[$i + 1]); + $control2x = $this->_parseInt($pathArray[$i + 2]); + $control2y = $this->_parseInt($pathArray[$i + 3]); + $newX = $this->_parseInt($pathArray[$i + 4]); + $newY = $this->_parseInt($pathArray[$i + 5]); + } else { + $control1x = $lastX + $this->_parseInt($pathArray[$i]); + $control1y = $lastY + $this->_parseInt($pathArray[$i + 1]); + $control2x = $lastX + $this->_parseInt($pathArray[$i + 2]); + $control2y = $lastY + $this->_parseInt($pathArray[$i + 3]); + $newX = $lastX + $this->_parseInt($pathArray[$i + 4]); + $newY = $lastY + $this->_parseInt($pathArray[$i + 5]); + } + + $polyPoints = array_merge($polyPoints, $this->_Bezier_drawfilled(array($lastX, $lastY), array($control1x, $control1y), array($control2x, $control2y), array($newX, $newY), $colorFill)); + + $lastX = $newX; + $lastY = $newY; + $lastOpe = 'c'; + $i += 6; + // Dernière ligne droite + } elseif (stripos($pathArray[$i], 'z') === 0 || (is_numeric(substr($pathArray[$i], 0, 1)) && strtolower($lastOpe) === 'z')) { + if ($lastOpe === 'z' && $this->_debug) { + $this->_log->error('2 bouclages dans une boucle'); + } + $polyPoints = array_merge($polyPoints, array($lastX, $lastY, $lastMX, $lastMY)); + $lastMX = $lastX; + $lastMY = $lastY; + //$this->_drawLine($lastX , $lastY , $lastMX , $lastMY , IMG_COLOR_STYLED); + $lastOpe = 'z'; + $i++; + // Polyline + } else { + $lastX = $this->_parseInt($pathArray[$i]); +// $lastX = $this->_parseInt($pathArray[$i + 2]); +// $lastY = $this->_parseInt($pathArray[$i + 3]); + $lastY = $this->_parseInt($pathArray[$i + 1]); + $lastOpe = 'l'; // s'il n'a aucune lettre, c'est une polyline, donc des... lignes. + $i += 2; + } + //if($this->_debug) $this->_log->message('counter :'.$i); + } + + $this->_drawPolygon($polyPoints, $colorStroke, $colorFill); + + imagecolordeallocate($this->_image, $colorStroke); + if ($colorFill !== '') { + imagecolordeallocate($this->_image, $colorFill); + } + imagesetthickness($this->_image, 1); + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + + return null; + } + + /** + * add a circle in the final image + * @param SimpleXMLElement + * @return + */ + private function _parseCircle($circleNode) + { + $x = 0; + $y = 0; + $r = 0; + $strokeWidth = 1; + $fill = ''; + $stroke = ''; + extract($this->_getParams($circleNode), EXTR_OVERWRITE); + if ($this->_getParam('originX') !== null) { + $x += $this->_getParam('originX'); + } + if ($this->_getParam('originY') !== null) { + $y += $this->_getParam('originY'); + } + if ($r === 0) { + return; + } + if ($this->_debug) { + $this->_log->message('Cercle - x : ' . $x . ' - y : ' . $y . ' - rayon : ' . $r . '-' . ' - épaisseur : ' . $strokeWidth); + } + + $thickness = imagesetthickness($this->_image, (int)$strokeWidth); + if ($this->_debug && !$thickness) { + $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); + } + + $colorStroke = $this->_allocateColor((string)$stroke); + $colorFill = $this->_allocateColor((string)$fill); + + if ($fill !== '' || ($fill === '' && $stroke === '')) { + imagefilledarc($this->_image, $x, $y, $r * 2, $r * 2, 0, 359.9, $colorFill, IMG_ARC_PIE); + //imageellipse ($this->_image , $x , $y , $r*2 , $r*2, $colorStroke ); + } + if ($stroke !== '') { + imagearc($this->_image, $x, $y, $r * 2, $r * 2, 0, 359.9, $colorStroke); + } + imagecolordeallocate($this->_image, $colorStroke); + imagecolordeallocate($this->_image, $colorFill); + imagesetthickness($this->_image, 1); + + return null; + } + + /** + * add text in the final image 0 + * @param SimpleXMLElement + * @return + */ + private function _parseText($textNode) + { + $x = 0; + $y = 0; + $r = 0; + $strokeWidth = 1; + $fill = ''; + $fontSize = 10; + $fontFamily = 'SansSerif'; + $fontStyle = 'normal'; + $fontWeight = 'normal'; + + extract($this->_getParams($textNode), EXTR_OVERWRITE); + + //case translation + if ($this->_getParam('originX') !== null) { + $x += $this->_getParam('originX'); + } + if ($this->_getParam('originY') !== null) { + $y += $this->_getParam('originY'); + } + //end translation + //case rotation + if ($this->_getParam('rotate') !== null) { + $r = $this->_getParam('rotate'); + } + //end rotation + //case scale + if ($this->_getParam('scale') !== null) { + $fontSize *= ($this->_getParam('scale') - 1); + } + //end scale + + if ($textNode === '') { + return; + } + $colorStroke = $this->_allocateColor((string)$fill); + + $fontfile = './fonts/arial.ttf'; + if (is_readable('./fonts/' . strtolower($fontFamily) . '.ttf')) { + $fontfile = './fonts/' . strtolower($fontFamily) . '.ttf'; + } + + if ($this->_debug) { + $this->_log->message('text ' . rtrim($textNode) . ' avec typo :' . $fontfile . ' de taille ' . $fontSize); + } + if ($this->_debug) { + $this->_log->message('text avec rotation : ' . $r); + } + //imagestring ( $this->_image , 2 , $x , $y , rtrim($textNode) , $fill ); +// imagefttext($this->_image, (double)$fontSize, $r, $x, $y, $colorStroke, $fontfile, rtrim($textNode)); + imagettftext($this->_image, (double)$fontSize, $r, $x, $y, $colorStroke, $fontfile, rtrim($textNode)); + imagecolordeallocate($this->_image, $colorStroke); + + return null; + } + + /* + * add a rectangle to the final image + * @param simpleXMLElement + * @return a nice rectangle ! + */ + private function _parseRectangle($rectNode) + { + $x = 0; + $y = 0; + $width = 0; + $height = 0; + $r = 0; + $fill = ''; + $stroke = ''; + $strokeWidth = 1; + $strokeDasharray = ''; + extract($this->_getParams($rectNode), EXTR_OVERWRITE); + //case translate + if ($this->_getParam('originX') !== null) { + $x += $this->_getParam('originX'); + } + if ($this->_getParam('originY') !== null) { + $y += $this->_getParam('originY'); + } + //end translate + if ($width === 0 || $height === 0) { + return; + } + $colorStroke = $this->_allocateColor((string)$stroke); + $colorFill = $this->_allocateColor((string)$fill); + $thickness = imagesetthickness($this->_image, (int)$strokeWidth); + if ($strokeDasharray !== '') { + $strokeDasharray = explode(',', $strokeDasharray); + imagesetstyle($this->_image, $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke)); + } else { + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + } + + if ($this->_debug && !$thickness) { + $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); + } + + if ($fill !== '' || ($fill === '' && $stroke === '')) { + imagefilledrectangle($this->_image, $x, $y, $x + $width, $y + $height, $colorFill); + imagerectangle($this->_image, $x, $y, $x + $width, $y + $height, IMG_COLOR_STYLED); + } + if ($stroke !== '') { + imagerectangle($this->_image, $x, $y, $x + $width, $y + $height, IMG_COLOR_STYLED); + } + imagecolordeallocate($this->_image, $colorStroke); + imagecolordeallocate($this->_image, $colorFill); + imagesetthickness($this->_image, 1); + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + } + + /** + * @param $lineNode + */ + private function _parseLine($lineNode) + { + $x1 = 0; + $y1 = 0; + $x2 = 0; + $y2 = 0; + $stroke = ''; + $strokeWidth = 1; + $strokeDasharray = ''; + extract($this->_getParams($lineNode), EXTR_OVERWRITE); + //case translate + if ($this->_getParam('originX') !== null) { + $x1 += $this->_getParam('originX'); + $x2 += $this->_getParam('originX'); + } + if ($this->_getParam('originY') !== null) { + $y1 += $this->_getParam('originY'); + $y2 += $this->_getParam('originY'); + } + //end translate + //case rotation + if ($this->_getParam('rotate') !== null) { + // TODO + } + //end rotation + //case scale + if ($this->_getParam('scale') !== null) { + $xrapport = ($x2 - $x1) * ($this->_getParam('scale') - 1); + $x2 += $xrapport; + $yrapport = ($y2 - $y1) * ($this->_getParam('scale') - 1); + $y2 += $yrapport; + if ($this->_debug) { + $this->_log->message('scale by ' . Log::decode($this->_getParam('scale')) . ':' . Log::decode($xrapport) . ' - ' . Log::decode($yrapport)); + } + } + //end scale + $colorStroke = $this->_allocateColor((string)$stroke); + imagesetthickness($this->_image, (int)$strokeWidth); + if ($strokeDasharray !== '') { + $strokeDasharray = explode(',', $strokeDasharray); + imagesetstyle($this->_image, $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke)); + } else { + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + } + + //if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); + $this->_drawLine($x1, $y1, $x2, $y2, $colorStroke); + imagecolordeallocate($this->_image, $colorStroke); + imagesetthickness($this->_image, 1); + imagesetstyle($this->_image, $this->_getDashedStroke(10, 0, $colorStroke)); + } + + /** + * add a polygon in the final image + * @param simpleXMLElement + * @return po-po-po-polygon ! + */ + private function _parsePolygon($polyNode) + { + $path = ''; + $fill = ''; + $stroke = ''; + $strokeWidth = 1; + extract($this->_getParams($polyNode), EXTR_OVERWRITE); + if ($path === '') { + return; + } + $pointArray = preg_split('/[ ,]/', $path); + $colorStroke = $this->_allocateColor((string)$stroke); + $colorFill = $this->_allocateColor((string)$fill); + $thickness = imagesetthickness($this->_image, (int)$strokeWidth); + if ($this->_debug && !$thickness) { + $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); + } + + if ($fill !== '') { + imagefilledpolygon($this->_image, $pointArray, count($pointArray) / 2, $colorFill); + } + if ($stroke !== '') { + imagepolygon($this->_image, $pointArray, count($pointArray) / 2, $colorStroke); + } + imagecolordeallocate($this->_image, $colorStroke); + imagecolordeallocate($this->_image, $colorFill); + imagesetthickness($this->_image, 1); + return null; + } + + /** + * add the description text in the final image + * @param string the description + * @return boolean + */ + private function _parseDescription($desc) + { + if ($this->_debug) $this->_log->message('Ajout de la description : ' . $desc); + return imagestring($this->_image, 2, 10, $this->_getImageHeight() - 20, $desc, imagecolorallocate($this->_image, 255, 255, 255)); + } + + /** + * @param SimpleXMLIterator|SimpleXMLElement $groupNode + * get group attributes to pass it to children + * parse children + */ + private function _parseGroup($groupNode) + { + $this->_currentOptions[] = $this->_getParams($groupNode); + foreach ($groupNode->children() as $element) { + $this->_chooseParse($element); + } + unset($this->_currentOptions[count($this->_currentOptions) - 1]); + } + + /** + * select what to parse + * @param simpleXMLElement $element + */ + private function _chooseParse($element) + { + if ($element->getName() === 'image') { + $this->_parseImage($element); + } + if ($element->getName() === 'circle') { + $this->_parseCircle($element); + } + if ($element->getName() === 'rect') { + $this->_parseRectangle($element); + } + if ($element->getName() === 'path') { + $this->_parsePath($element); + } + if ($element->getName() === 'polygon') { + $this->_parsePolygon($element); + } + if ($element->getName() === 'polyline') { + $this->_parsePath($element); + } + if ($element->getName() === 'g') { + $this->_parseGroup($element); + } + if ($element->getName() === 'text') { + $this->_parseText($element); + } + if ($element->getName() === 'line') { + $this->_parseLine($element); + } + //if($element->getName() == 'defs') + // $this->_parseDefs($element); + //if($element->getName() == 'title') + // $this->_parseTitle($element); + if ($this->_showDesc && $element->getName() === 'desc') { + $this->_desc = $element; + } + } + + /** + * parse everything, main function + * @param string format of the ouput 'png' 'gif' jpg' + * @param string path where you want to save the file (with the final name), null will just show the image but not saved on server + * @return bool + */ + public function toImage($format = 'png', $path = null) + { + $writeDesc = null; + $this->_image = imagecreatetruecolor($this->_getImageWidth(), $this->_getImageHeight()); + imagefilledrectangle($this->_image, 0, 0, $this->_getImageWidth(), $this->_getImageHeight(), $this->_allocateColor('white')); + imagealphablending($this->_image, true); + //imageantialias($this->_image, true); // On ne peut pas gérer l'épaisseur des traits si l'antialiasing est activé... lol ? + foreach ($this->_svgXML->children() as $element) { + $this->_chooseParse($element); + $this->_currentOptions = array(); + } + if ($this->_showDesc && $this->_desc !== null) { + $this->_parseDescription($this->_desc); + } + //imagefilter ( $this->_image , IMG_FILTER_SMOOTH, 6); + switch ($format) { + case 'gif' : + header('Content-type: ' . image_type_to_mime_type(IMAGETYPE_GIF)); + return imagegif($this->_image, $path); + case 'jpg': + header('Content-type: ' . image_type_to_mime_type(IMAGETYPE_JPEG)); + return imagejpeg($this->_image, $path); + case 'png' : + default : + header('Content-type: ' . image_type_to_mime_type(IMAGETYPE_PNG)); + return imagepng($this->_image, $path); + } + } +} diff --git a/log.php b/log.php deleted file mode 100644 index b4e2121..0000000 --- a/log.php +++ /dev/null @@ -1,29 +0,0 @@ -logfile = fopen($file, 'a+'); - $this->message('Starting log'); - } - - function message($message) { - $message = '['. date("Y-m-d / H:i:s") . '] @MESSAGE'.' - '.$message; - $message .= "\n"; - return fwrite( $this->logfile, $message ); - } - - function error($message) { - $message = '['. date("Y-m-d / H:i:s") . '] @ERROR'.' - '.$message; - $message .= "\n"; - return fwrite( $this->logfile, $message ); - } - - function __destruct(){ - $this->message("Finishing log\n-----------------------"); - return fclose( $this->logfile ); - } -} - diff --git a/svgtoimage.php b/svgtoimage.php deleted file mode 100644 index cbbb4a2..0000000 --- a/svgtoimage.php +++ /dev/null @@ -1,1184 +0,0 @@ -0 - -include 'log.php'; - -class SVGTOIMAGE{ - - protected $_svgXML; - protected $_image; - protected $_log; - protected $_x; - protected $_y; - protected $_width; - protected $_height; - protected $_showDesc = false; - protected $_desc; - protected $_currentOptions = array(); - private $transparentColor = array(0,0,255); - public $_debug = true; // change to false to stop debug mode - - /* - * array of path type - */ - private $pathType = array( - 'm' => 'MoveTo', - 'l' => 'LineTo', - 'h' => 'HorizontalLineTo', - 'v' => 'VerticalLineTo', - 'c' => 'CurveTo', - 'z' => 'EndingLine', - ); - - /* array of color names => rgb color - because some svg creator uses them - used http://www.yoyodesign.org/doc/w3c/svg1/types.html#ColorKeywords - */ - private $colors = array( - 'aliceblue'=>array(240, 248, 255), - 'antiquewhite'=>array(250, 235, 215), - 'aqua'=>array( 0, 255, 255), - 'aquamarine'=>array(127, 255, 212), - 'azure'=>array(240, 255, 255), - 'beige'=>array(245, 245, 220), - 'bisque'=>array(255, 228, 196), - 'black'=>array( 0, 0, 0), - 'blanchedalmond'=>array(255, 235, 205), - 'blue'=>array( 0, 0, 255), - 'blueviolet'=>array(138, 43, 226), - 'brown'=>array(165, 42, 42), - 'burlywood'=>array(222, 184, 135), - 'cadetblue'=>array( 95, 158, 160), - 'chartreuse'=>array(127, 255, 0), - 'chocolate'=>array(210, 105, 30), - 'coral'=>array(255, 127, 80), - 'cornflowerblue'=>array(100, 149, 237), - 'cornsilk'=>array(255, 248, 220), - 'crimson'=>array(220, 20, 60), - 'cyan'=>array( 0, 255, 255), - 'darkblue'=>array( 0, 0, 139), - 'darkcyan'=>array( 0, 139, 139), - 'darkgoldenrod'=>array(184, 134, 11), - 'darkgray'=>array(169, 169, 169), - 'darkgreen'=>array( 0, 100, 0), - 'darkgrey'=>array(169, 169, 169), - 'darkkhaki'=>array(189, 183, 107), - 'darkmagenta'=>array(139, 0, 139), - 'darkolivegreen'=>array( 85, 107, 47), - 'darkorange'=>array(255, 140, 0), - 'darkorchid'=>array(153, 50, 204), - 'darkred'=>array(139, 0, 0), - 'darksalmon'=>array(233, 150, 122), - 'darkseagreen'=>array(143, 188, 143), - 'darkslateblue'=>array( 72, 61, 139), - 'darkslategray'=>array( 47, 79, 79), - 'darkslategrey'=>array( 47, 79, 79), - 'darkturquoise'=>array( 0, 206, 209), - 'darkviolet'=>array(148, 0, 211), - 'deeppink'=>array(255, 20, 147), - 'deepskyblue'=>array( 0, 191, 255), - 'dimgray'=>array(105, 105, 105), - 'dimgrey'=>array(105, 105, 105), - 'dodgerblue'=>array( 30, 144, 255), - 'firebrick'=>array(178, 34, 34), - 'floralwhite'=>array(255, 250, 240), - 'forestgreen'=>array( 34, 139, 34), - 'fuchsia'=>array(255, 0, 255), - 'gainsboro'=>array(220, 220, 220), - 'ghostwhite'=>array(248, 248, 255), - 'gold'=>array(255, 215, 0), - 'goldenrod'=>array(218, 165, 32), - 'gray'=>array(128, 128, 128), - 'grey'=>array(128, 128, 128), - 'green'=>array( 0, 128, 0), - 'greenyellow'=>array(173, 255, 47), - 'honeydew'=>array(240, 255, 240), - 'hotpink'=>array(255, 105, 180), - 'indianred'=>array(205, 92, 92), - 'indigo'=>array( 75, 0, 130), - 'ivory'=>array(255, 255, 240), - 'khaki'=>array(240, 230, 140), - 'lavender'=>array(230, 230, 250), - 'lavenderblush'=>array(255, 240, 245), - 'lawngreen'=>array(124, 252, 0), - 'lemonchiffon'=>array(255, 250, 205), - 'lightblue'=>array(173, 216, 230), - 'lightcoral'=>array(240, 128, 128), - 'lightcyan'=>array(224, 255, 255), - 'lightgoldenrodyellow'=>array(250, 250, 210), - 'lightgray'=>array(211, 211, 211), - 'lightgreen'=>array(144, 238, 144), - 'lightgrey'=>array(211, 211, 211), - 'lightpink'=>array(255, 182, 193), - 'lightsalmon'=>array(255, 160, 122), - 'lightseagreen'=>array( 32, 178, 170), - 'lightskyblue'=>array(135, 206, 250), - 'lightslategray'=>array(119, 136, 153), - 'lightslategrey'=>array(119, 136, 153), - 'lightsteelblue'=>array(176, 196, 222), - 'lightyellow'=>array(255, 255, 224), - 'lime'=>array( 0, 255, 0), - 'limegreen'=>array( 50, 205, 50), - 'linen'=>array(250, 240, 230), - 'magenta'=>array(255, 0, 255), - 'maroon'=>array(128, 0, 0), - 'mediumaquamarine'=>array(102, 205, 170), - 'mediumblue'=>array( 0, 0, 205), - 'mediumorchid'=>array(186, 85, 211), - 'mediumpurple'=>array(147, 112, 219), - 'mediumseagreen'=>array( 60, 179, 113), - 'mediumslateblue'=>array(123, 104, 238), - 'mediumspringgreen'=>array( 0, 250, 154), - 'mediumturquoise'=>array( 72, 209, 204), - 'mediumvioletred'=>array(199, 21, 133), - 'midnightblue'=>array( 25, 25, 112), - 'mintcream'=>array(245, 255, 250), - 'mistyrose'=>array(255, 228, 225), - 'moccasin'=>array(255, 228, 181), - 'navajowhite'=>array(255, 222, 173), - 'navy'=>array( 0, 0, 128), - 'oldlace'=>array(253, 245, 230), - 'olive'=>array(128, 128, 0), - 'olivedrab'=>array(107, 142, 35), - 'orange'=>array(255, 165, 0), - 'orangered'=>array(255, 69, 0), - 'orchid'=>array(218, 112, 214), - 'palegoldenrod'=>array(238, 232, 170), - 'palegreen'=>array(152, 251, 152), - 'paleturquoise'=>array(175, 238, 238), - 'palevioletred'=>array(219, 112, 147), - 'papayawhip'=>array(255, 239, 213), - 'peachpuff'=>array(255, 218, 185), - 'peru'=>array(205, 133, 63), - 'pink'=>array(255, 192, 203), - 'plum'=>array(221, 160, 221), - 'powderblue'=>array(176, 224, 230), - 'purple'=>array(128, 0, 128), - 'red'=>array(255, 0, 0), - 'rosybrown'=>array(188, 143, 143), - 'royalblue'=>array( 65, 105, 225), - 'saddlebrown'=>array(139, 69, 19), - 'salmon'=>array(250, 128, 114), - 'sandybrown'=>array(244, 164, 96), - 'seagreen'=>array( 46, 139, 87), - 'seashell'=>array(255, 245, 238), - 'sienna'=>array(160, 82, 45), - 'silver'=>array(192, 192, 192), - 'skyblue'=>array(135, 206, 235), - 'slateblue'=>array(106, 90, 205), - 'slategray'=>array(112, 128, 144), - 'slategrey'=>array(112, 128, 144), - 'snow'=>array(255, 250, 250), - 'springgreen'=>array( 0, 255, 127), - 'steelblue'=>array( 70, 130, 180), - 'tan'=>array(210, 180, 140), - 'teal'=>array( 0, 128, 128), - 'thistle'=>array(216, 191, 216), - 'tomato'=>array(255, 99, 71), - 'turquoise'=>array( 64, 224, 208), - 'violet'=>array(238, 130, 238), - 'wheat'=>array(245, 222, 179), - 'white'=>array(255, 255, 255), - 'whitesmoke'=>array(245, 245, 245), - 'yellow'=>array(255, 255, 0), - 'yellowgreen'=>array(154, 205, 50) - ); - - /** - * constructor - * parse the svg with simplexml - */ - public function __construct($svg){ - if($this->_debug) $this->_log = new Log('log.dat'); - $this->_svgXML = simplexml_load_string($svg); - } - - /** - * Construct with a file - * @param : string path to the file - * @return : instance of this class - */ - public static function load($file){ - $svg = file_get_contents($file); - return new SVGTOIMAGE($svg); - } - - /** - * Construct with a string - * @param : string ... - * @return : instance of this class - */ - public static function parse($xml){ - return new SVGTOIMAGE($xml); - } - - /** - * Destroy the GD Image when finished - */ - public function __destruct(){ - imagedestroy($this->_image); - } - - /** - * setter - option : show the description from the svg into the image if present - * @param boolean - */ - public function setShowDesc($showDesc = true){ - if(is_bool($showDesc)){ - //if($this->_debug) $this->_log->message('Passage de showDesc en '.$showDesc); - $this->_showDesc = $showDesc; - }else{ - if($this->_debug) $this->_log->error('Erreur dans la fonction showDesc, doit recevoir booléen, a reçu : '.$showDesc); - } - } - - /** - * setter - option : origin of the final image from the svg (default : 0) - * @param int - */ - public function setX($x){ - if(is_int($x)){ - //if($this->_debug) $this->_log->message('Passage de x en '.$x); - $this->_x = $x; - }else{ - if($this->_debug) $this->_log->error('Erreur dans la fonction setX, doit recevoir int, a reçu : '.$x); - } - } - - /* - * setter - option : origin of the final image from the svg (default : 0) - * @param int - */ - public function setY($y){ - if(is_int($y)){ - //if($this->_debug) $this->_log->message('Passage de y en '.$y); - $this->_y = $y; - }else{ - if($this->_debug) $this->_log->error('Erreur dans la fonction setY, doit recevoir int, a reçu : '.$y); - } - } - - /* - * setter - option : width of the final image (default : svg width) - * @param int - */ - public function setWidth($width){ - if(is_int($width)){ - //if($this->_debug) $this->_log->message('Passage de width en '.$width); - $this->_width = $width; - }else{ - if($this->_debug) $this->_log->error('Erreur dans la fonction setWidth, doit recevoir int, a reçu : '.$width); - } - } - - /* - * setter - option : height of the final image (default : svg height) - * @param int - */ - public function setHeight($height){ - if(is_int($height)){ - //if($this->_debug) $this->_log->message('Passage de height en '.$height); - $this->_height = $height; - }else{ - if($this->_debug) $this->_log->error('Erreur dans la fonction setHeight, doit recevoir int, a reçu : '.$height); - } - } - - /* - * DEPRECATED - * return width and height from the SVG - */ - private function _getImageSize(){ - $imageSize = array(); - $imageSize['width'] = $this->_svgXML->attributes()->width; - $imageSize['height'] = $this->_svgXML->attributes()->height; - if($this->_debug) $this->_log->message('taille de l\'image : '.Log::decode($imageSize)); - return $imageSize; - } - - /** - * @param string size of picture or element - * @return int "real" size of element. To eliminate SVG with centimeters - */ - private function _getSizeType($value){ - $value = rtrim($value); - switch(substr($value,-2,2)){ - case 'cm': - return $value * 30; // approximatively - break; - case 'in': - return $value * 12; // approximatively - break; - case 'px': - case 'pt': - default: - return $value; - } - } - - /** - * @return int final image width - */ - private function _getImageWidth(){ - return isset($this->_width) ? $this->_width : $this->_getSizeType($this->_svgXML->attributes()->width); - } - - /** - * @return int final image height - */ - private function _getImageHeight(){ - return isset($this->_height) ? $this->_height : $this->_getSizeType($this->_svgXML->attributes()->height); - } - - /* - * @param string Color code (ie: #CCC , #FE4323, etc...) - * @return array with R | G | B - */ - private function _parseColor($colorCode){ - if(is_string($colorCode) && strlen($colorCode) == 7){ - $convert = array( - base_convert(substr($colorCode, 1, 2), 16, 10), - base_convert(substr($colorCode, 3, 2), 16, 10), - base_convert(substr($colorCode, 5, 2), 16, 10), - ); - return $convert; - } - if(is_string($colorCode) && strlen($colorCode) == 4){ - return array( - base_convert(substr($colorCode, 1, 1).substr($colorCode, 1, 1), 16, 10), - base_convert(substr($colorCode, 2, 1).substr($colorCode, 2, 1), 16, 10), - base_convert(substr($colorCode, 3, 1).substr($colorCode, 3, 1), 16, 10), - ); - } - if(is_array($colorCode) && count($colorCode) == 3){ - return $colorCode; - } - if($this->_debug) $this->_log->error('Couleur mal indiquée '.Log::decode($colorCode)); - return array(0,0,0); // !#FFF || !#FFFFFF || !array(255,255,255) then black - } - - /** - * Allocate color to the final image thanks to _parseColor (check if the color isn't spelled directly 'black') - * @param string color code - * @return imageallocate on the image - */ - private function _allocateColor($color){ - if($color != '' && array_key_exists(strtolower($color), $this->colors)){ - $arrayColor = $this->_parseColor($this->colors[strtolower($color)]); - }elseif($color != ''){ - $arrayColor = $this->_parseColor($color); - }else return; - return imagecolorallocate( $this->_image, $arrayColor[0], $arrayColor[1], $arrayColor[2] ); - } - - /** - * return an array to use with imagesetstyle - * @param allocatecolorimage - * @return array - */ - private function _getDashedStroke($full, $empty, $color){ - $tiret = array(); - for($i=0;$i<$full;$i++){ - $tiret[] = $color; - } - for($i=0;$i<$empty;$i++){ - $tiret[] = IMG_COLOR_TRANSPARENT; - } - //if($this->_debug) $this->_log->message('nouveaux tirets : '.Log::decode($tiret)); - return $tiret; - } - - private function _getParam($paramName){ - $currentOptions = $this->_getAllParams(); - return isset($currentOptions[$paramName]) ? $currentOptions[$paramName] : null; - } - - private function _getAllParams(){ - $newarr = array(); - foreach($this->_currentOptions as $array) - $newarr = array_merge($newarr, $array); - return $newarr; - } - - /** - * @param node $element - * @return array options - */ - private function _getParams($element){ - $options = $this->_getAllParams(); - foreach($element->attributes() as $name => $value){ - switch($name){ - case 'x': - case 'y': - case 'r': - case 'width': - case 'height': - $options[$name] = $this->_getSizeType($value); - break; - case 'cx': - $options['x'] = $this->_getSizeType($value); - break; - case 'cy': - $options['y'] = $this->_getSizeType($value); - break; - case 'xlink:href': - $options['href'] = $value; - break; - case 'd': - case 'points': - $options['path'] = $value; - break; - case 'fill': - $options['fill'] = ($value == 'none') ? '' : $value; - break; - case 'stroke-width' : - $options['strokeWidth'] = $value; - break; - case 'stroke-dasharray' : - $options['strokeDasharray'] = $value; - break; - case 'font-size': - $options['fontSize'] = $value; - break; - case 'font-family': - $options['fontFamily'] = $value; - break; - case 'font-style': - $options['fontStyle'] = $value; - break; - case 'font-weight': - $options['fontWeight'] = $value; - break; - case 'transform': // transform="matrix(1.006896,0,0,1.006896,0.3043,-0.708342)" - $transform = split('[()]', $value); - if(count($transform) == 3){ - $typeTransform = $transform[0]; - switch($typeTransform){ - case 'translate': - list($options['originX'], $options['originY']) = explode(',', $transform[1]); - break; - case 'rotate': - $options['rotate'] = $transform[1]; - break; - case 'scale': - $options['scale'] = $transform[1]; - break; - default: - break; - } - } - break; - case 'style' : - $allStyle = split('[;:]', $value); - $i = 0; - while ($i < count($allStyle)) { - if($allStyle[$i] == 'display' && $allStyle[$i+1] == 'none') return; // display:none? Stop looking for info - if($allStyle[$i] == 'fill') $options['fill'] = $allStyle[$i+1]; - if($allStyle[$i] == 'stroke') $options['stroke'] = $allStyle[$i+1]; - if($allStyle[$i] == 'stroke-width') $options['strokeWidth'] = $allStyle[$i+1]; - $i=$i+2; - } - break; - default: - $options[$name] = $value; - break; - } - } - /*if($this->_debug){ - $this->_log->message('-------- option ---------'); - foreach($options as $key => $value){ - $this->_log->message('option : '.(string)$key.' -> '.(string)$value); - } - $this->_log->message('------- /option/ --------'); - }*/ - //if($this->_debug) $this->_log->message('options : '.Log::decode($options)); - return $options; - } - - /** - * add the given image from svg to the final image - * @param simpleXMLElement - * @return imagecopy - */ - private function _parseImage($imageNode){ - $x = 0; - $y = 0; - $width = 0; - $height = 0; - $href = ''; - $transform = ''; - $r = 0; - extract($this->_getParams($imageNode)); - //case translate - if($this->_getParam('originX') !== null) - $x += $this->_getParam('originX'); - if($this->_getParam('originY') !== null) - $y += $this->_getParam('originY'); - //end translate - if($transform != ''){ - $transforms = split('[()]', $transform); - $nb = count($transforms); - for($i = 0; $i < $nb; $i++){ - // rotation - if($transforms[$i] == 'rotate'){ - $rotinfo = $transforms[$i+1]; - $rotinfo = explode(' ', $rotinfo); - $r = $rotinfo[0]; - } - } - } - if($width == 0 || $height == 0 || $href == '') - return; - $imageTypeArray = explode('.', $href); - $lastElementFromImageType = count($imageTypeArray); - $imageType = $imageTypeArray[$lastElementFromImageType-1]; - if($imageType == 'jpg' || $imageType == 'jpeg') - $newImage = imagecreatefromjpeg($href); - else if($imageType == 'png') - $newImage = imagecreatefrompng($href); - else if($imageType == 'gif') - $newImage = imagecreatefromgif($href); - else return; - - imagealphablending($newImage, true); - - //rotating the image if needed - if($r != 0){ - if($this->_debug){ - if($newImage = imagerotate($newImage, - floatval($r), -1)){ - $this->_log->message('Rotating image'); - }else - $this->_log->error('Rotating image'); - }else{ - $newImage = imagerotate($newImage, - floatval($r), -1); - } - $blue = imagecolorallocate($newImage, $this->transparentColor[0], $this->transparentColor[1],$this->transparentColor[2]); - imagecolortransparent($newImage, $blue); - } - $newWidth = imagesx($newImage); - $newHeight = imagesy($newImage); - - imagecopy($this->_image,$newImage,($newWidth == $width) ? $x : $x-($newWidth-$width)/2,($newHeight == $height) ? $y : $y-($newHeight-$height)/2,0,0,imagesx($newImage) , imagesy($newImage)); // Thanks Raphael & GD for saying things wrong. - } - - /** - * Check if the given SVG xml is W3C valid - * DEPRECATED and unused anymore - * @param string ... - * @return boolean - */ - private function _pathIsW3C($path){ - if(strripos($path, ',')) - return true; - return false; - } - - - - /** - * small function to find int into a string - works like java parseint - * @param string containing numbers - * @return int - */ - private function _parseInt($string){ - if(preg_match('/[-]?(\d+)/', $string, $array)) return $array[0]; - else return 0; - } - - /** - * add a line to the final image - * @param $x1, $y1, $x2, $y2 int position of segment - * @param imagecolorallocate color (via _allocatecolor !) - * @return imageline - */ - private function _drawLine($x1, $y1, $x2, $y2, $color){ - if(!imageline( $this->_image , $x1, $y1, $x2, $y2, $color )){ - if($this->_debug) $this->_log->error('Chemin erroné : '.$x1.' - '.$y1.' - '.$x2.' - '.$y2); - }else{ - if($this->_debug) $this->_log->message('Chemin : '.$x1.' - '.$y1.' - '.$x2.' - '.$y2); - } - } - - /** - * add a curve to the final image - * @param $startX, $startY, $control1X, $control1Y, $control2X, $control2Y, $endX, $endY int position of start, controls and end points - * @param imagecolorallocate color (via _allocatecolor !) - * @return lots of imagesetpixel - * Algorithme de http://www.dreamstube.com/post/Bezier-Curves-In-PHP!.aspx - */ - private function _drawCurve($startX, $startY, $control1X, $control1Y, $control2X, $control2Y, $endX, $endY, $color){ - $cx=3*($control1X-$startX); - $bx=3*($control2X-$control1X)-$cx; - $ax=$endX-$startX-$cx-$bx; - - $cy=3*($control1Y-$startY); - $by=3*($control2Y-$control1Y)-$cy; - $ay=$endY-$startY-$cy-$by; - //if($this->_debug) $this->_log->message('ax : '.$ax.', ay : '.$ay); - for($t=0; $t<1; $t+=.01) - { - $xt = $ax * $t * $t * $t + $bx * $t * $t + $cx * $t + $startX; - $yt = $ay * $t * $t * $t + $by * $t * $t + $cy * $t + $startY; - imagesetpixel ( $this->_image , $xt , $yt , $color ); - } - } - - - /*EXPERIMENT*/ - - // Calculate the coordinate of the Bezier curve at $t = 0..1 - private function _Bezier_eval($p1,$p2,$p3,$p4,$t) { - // lines between successive pairs of points (degree 1) - $q1 = array((1-$t) * $p1[0] + $t * $p2[0],(1-$t) * $p1[1] + $t * $p2[1]); - $q2 = array((1-$t) * $p2[0] + $t * $p3[0],(1-$t) * $p2[1] + $t * $p3[1]); - $q3 = array((1-$t) * $p3[0] + $t * $p4[0],(1-$t) * $p3[1] + $t * $p4[1]); - // curves between successive pairs of lines. (degree 2) - $r1 = array((1-$t) * $q1[0] + $t * $q2[0],(1-$t) * $q1[1] + $t * $q2[1]); - $r2 = array((1-$t) * $q2[0] + $t * $q3[0],(1-$t) * $q2[1] + $t * $q3[1]); - // final curve between the two 2-degree curves. (degree 3) - return array((1-$t) * $r1[0] + $t * $r2[0],(1-$t) * $r1[1] + $t * $r2[1]); - } - - // Calculate the squared distance between two points - private function _Point_distance2($p1,$p2) { - $dx = $p2[0] - $p1[0]; - $dy = $p2[1] - $p1[1]; - return $dx * $dx + $dy * $dy; - } - - // Convert the curve to a polyline - private function _Bezier_convert($p1,$p2,$p3,$p4,$tolerance) { - $t1 = 0.0; - $prev = $p1; - $t2 = 0.1; - $tol2 = $tolerance * $tolerance; - $result []= $prev[0]; - $result []= $prev[1]; - while ($t1 < 1.0) { - if ($t2 > 1.0) { - $t2 = 1.0; - } - $next = $this->_Bezier_eval($p1,$p2,$p3,$p4,$t2); - $dist = $this->_Point_distance2($prev,$next); - while ($dist > $tol2) { - // Halve the distance until small enough - $t2 = $t1 + ($t2 - $t1) * 0.5; - $next = $this->_Bezier_eval($p1,$p2,$p3,$p4,$t2); - $dist = $this->_Point_distance2($prev,$next); - } - // the image*polygon functions expect a flattened array of coordiantes - $result []= $next[0]; - $result []= $next[1]; - $t1 = $t2; - $prev = $next; - $t2 = $t1 + 0.1; - } - return $result; - } - - // Draw a Bezier curve on an image - private function _Bezier_drawfilled($p1,$p2,$p3,$p4,$color) { - $polygon = $this->_Bezier_convert($p1,$p2,$p3,$p4,0.1); - return $polygon; - } - /*END OF EXPERIMENT*/ - - private function _drawPolygon($polygon, $stroke = '', $fill = ''){ - //if($this->_debug) $this->_log->message('_drawPolygon : fill : '.$fill.' stroke:'.$stroke); - if($fill !== '' && count($polygon) >= 6){ - //if($this->_debug) $this->_log->message('polygon rempli : '.$fill); - imagefilledpolygon($this->_image,$polygon,count($polygon)/2,$fill); - if($stroke != '') imagepolygon($this->_image, $polygon, count($polygon)/2, $stroke); - }elseif(count($polygon) >= 6){ - //if($this->_debug) $this->_log->message('polygon non rempli : '.$stroke); - imagepolygon($this->_image, $polygon, count($polygon)/2, $stroke); - //imagepolygon($this->_image, $polygon, count($polygon)/2, IMG_COLOR_STYLED); - }elseif(count($polygon) == 4){ - //if($this->_debug) $this->_log->message('ligne via polygon : '.$stroke); - $this->_drawLine($polygon[0],$polygon[1], $polygon[2],$polygon[3], $stroke); - } - } - - - /** - * add path/lineS/polyline whatever you name it. - * @param simpleXMLElement - * @return lines on the final image via _drawLine - */ - private function _parsePath($pathNode){ - $path = ''; - $strokeWidth = 1; - $fill = ''; - $stroke = ''; - $strokeDasharray = ''; - - extract($this->_getParams($pathNode)); - - if(strtolower(substr($path, 0,1)) != 'm' && !is_numeric(substr($path, 0,1))){ - if($this->_debug) $this->_log->error('Mauvais path rencontré : '.$path); - return; - } - - $thickness = imagesetthickness( $this->_image , $this->_parseInt($strokeWidth) ); - if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); - else $this->_log->message('épaisseur du trait à : '.$this->_parseInt($strokeWidth)); - - $colorStroke = $stroke != '' ? $this->_allocateColor($stroke) : $fill === '' ? $this->_allocateColor('black') : ''; - $colorFill = $fill != '' ? $this->_allocateColor($fill) : ''; - - if($this->_debug) $this->_log->message('colors ! fill:'.$colorFill.'stroke:'.$colorStroke); - - if($strokeDasharray != ''){ - $strokeDasharray = explode(',', $strokeDasharray); - imagesetstyle ( $this->_image , $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke )); - }else - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - - $lastOpe = ''; - - $pathArray = split('[ ,]', $path); - - // Si le path est de format 'm 100 100 l 100 100 z' il faut recoller les morceaux - if(array_key_exists(strtolower($pathArray[0]), $this->pathType)){ - $j = 0; - do{ - if(array_key_exists(strtolower($pathArray[$j]), $this->pathType)){ - $pathArray[$j] = $pathArray[$j].$pathArray[$j+1]; - $pathArray[$j+1] = '~'; - $j++; - $newNb = count($pathArray); - for($k = $j; $k<=$newNb; $k++){ - $pathArray[$k] = $pathArray[$k+1]; - } - }else{ - if($pathArray[$j] == '' || $pathArray[$j] == null) - unset($pathArray[$j]); - $j++; - } - }while(isset($pathArray[$j])); - //if($this->_debug) $this->_log->message('Path reconstruit ! '.implode(', ',$pathArray)); - } - - - $nbArray = count($pathArray); - - $polyPoints = array(); - $i = 0; - $lastX = 0; - $lastY = 0; - $lastMX = 0; - $lastMY = 0; - while ($i < $nbArray) { - // Changement de départ - if(strtolower(substr($pathArray[$i], 0, 1)) == 'm'){ - if(isset($pathArray[$i-1])){ - $this->_drawPolygon($polyPoints, $colorStroke, $colorFill); - $polyPoints = array(); - $lastX = 0; - $lastY = 0; - $lastMX = 0; - $lastMY = 0; - } - $lastX = $this->_parseInt($pathArray[$i]); - $lastMX = $this->_parseInt($pathArray[$i]); - $lastY = $this->_parseInt($pathArray[$i+1]); - $lastMY = $this->_parseInt($pathArray[$i+1]); - $lastOpe = 'm'; - $i=$i+2; - // Ligne - }elseif(strtolower(substr($pathArray[$i], 0, 1)) == 'l' || (is_numeric($pathArray[$i]) && strtolower($lastOpe) == 'l')){ - if(substr($pathArray[$i], 0, 1) == 'L'){ - $newX = $this->_parseInt($pathArray[$i]); - $newY = $this->_parseInt($pathArray[$i+1]); - }else{ - $newX = $lastX + $this->_parseInt($pathArray[$i]); - $newY = $lastY + $this->_parseInt($pathArray[$i+1]); - } - $polyPoints = array_merge($polyPoints,array($lastX, $lastY, $newX, $newY)); - //$this->_drawLine($lastX , $lastY , $newX , $newY , IMG_COLOR_STYLED); - $lastOpe = 'l'; - $lastX = $newX; - $lastY = $newY; - $i=$i+2; - // Ligne horizontale - }elseif(strtolower(substr($pathArray[$i], 0, 1)) == 'h' || (is_numeric($pathArray[$i]) && strtolower($lastOpe) == 'h')){ - if(substr($pathArray[$i], 0, 1) == 'H'){ - $newX = $this->_parseInt($pathArray[$i]); - }else{ - $newX = $lastX + $this->_parseInt($pathArray[$i]); - } - //$this->_drawLine($lastX , $lastY , $newX , $lastY , IMG_COLOR_STYLED); - $polyPoints = array_merge($polyPoints,array($lastX, $lastY, $newX, $newY)); - $lastOpe = 'h'; - $lastX = $newX; - $i++; - // Ligne verticale - }elseif(strtolower(substr($pathArray[$i], 0, 1)) == 'v' || (is_numeric($pathArray[$i]) && strtolower($lastOpe) == 'v')){ - if(substr($pathArray[$i], 0, 1) == 'V'){ - $newY = $this->_parseInt($pathArray[$i]); - }else{ - $newY = $lastY + $this->_parseInt($pathArray[$i]); - } - //$this->_drawLine($lastX , $lastY , $lastX , $newY , IMG_COLOR_STYLED); - $polyPoints = array_merge($polyPoints,array($lastX, $lastY, $newX, $newY)); - $lastY = $newY; - $lastOpe = 'v'; - $i++; - // Courbe - }elseif(strtolower(substr($pathArray[$i], 0, 1)) == 'c' || (is_numeric($pathArray[$i]) && strtolower($lastOpe) == 'c')){ - /*SPECIF !!! http://www.w3.org/TR/SVG/paths.html*/ - if(substr($pathArray[$i], 0, 1) == 'C'){ - $control1x = $this->_parseInt($pathArray[$i]); - $control1y = $this->_parseInt($pathArray[$i+1]); - $control2x = $this->_parseInt($pathArray[$i+2]); - $control2y = $this->_parseInt($pathArray[$i+3]); - $newX = $this->_parseInt($pathArray[$i+4]); - $newY = $this->_parseInt($pathArray[$i+5]); - }else{ - $control1x = $lastX + $this->_parseInt($pathArray[$i]); - $control1y = $lastY + $this->_parseInt($pathArray[$i+1]); - $control2x = $lastX + $this->_parseInt($pathArray[$i+2]); - $control2y = $lastY + $this->_parseInt($pathArray[$i+3]); - $newX = $lastX + $this->_parseInt($pathArray[$i+4]); - $newY = $lastY + $this->_parseInt($pathArray[$i+5]); - } - - $polyPoints = array_merge($polyPoints,$this->_Bezier_drawfilled(array($lastX, $lastY),array($control1x, $control1y),array($control2x, $control2y),array($newX, $newY),$colorFill)); - - $lastX = $newX; - $lastY = $newY; - $lastOpe = 'c'; - $i=$i+6; - // Dernière ligne droite - }elseif(strtolower(substr($pathArray[$i], 0, 1)) == 'z' || (is_numeric(substr($pathArray[$i], 0, 1)) && strtolower($lastOpe) == 'z')){ - if($lastOpe == 'z' && $this->_debug) $this->_log->error('2 bouclages dans une boucle'); - $polyPoints = array_merge($polyPoints,array($lastX, $lastY, $lastMX, $lastMY)); - $lastMX = $lastX; - $lastMY = $lastY; - //$this->_drawLine($lastX , $lastY , $lastMX , $lastMY , IMG_COLOR_STYLED); - $lastOpe = 'z'; - $i++; - // Polyline - }else{ - $lastX = $this->_parseInt($pathArray[$i+2]); - $lastY = $this->_parseInt($pathArray[$i+3]); - $lastOpe = 'l'; // s'il n'a aucune lettre, c'est une polyline, donc des... lignes. - $i=$i+2; - } - //if($this->_debug) $this->_log->message('counter :'.$i); - } - - $this->_drawPolygon($polyPoints, $colorStroke, $colorFill); - - imagecolordeallocate( $this->_image, $colorStroke); - imagecolordeallocate( $this->_image, $colorFill); - imagesetthickness ( $this->_image , 1 ); - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - } - - /** - * add a circle in the final image - * @param SimpleXMLElement - * @return - */ - private function _parseCircle($circleNode){ - $x = 0; - $y = 0; - $r = 0; - $strokeWidth = 1; - $fill = ''; - $stroke = ''; - extract($this->_getParams($circleNode)); - if($this->_getParam('originX') !== null){ - $x += $this->_getParam('originX'); - } - if($this->_getParam('originY') !== null){ - $y += $this->_getParam('originY'); - } - if($r == 0) - return; - if($this->_debug) $this->_log->message('Cercle - x : '.$x.' - y : '.$y.' - rayon : '.$r.'-'.$colorStroke[2].' - épaisseur : '.$strokeWidth); - - $thickness = imagesetthickness( $this->_image , (int)$strokeWidth ); - if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); - - $colorStroke = $this->_allocateColor((string)$stroke); - $colorFill = $this->_allocateColor((string)$fill); - - if($fill != '' || ($fill=='' && $stroke=='')){ - imagefilledarc($this->_image , $x , $y , $r*2 , $r*2 ,0,359.9, $colorFill, IMG_ARC_PIE ); - //imageellipse ($this->_image , $x , $y , $r*2 , $r*2, $colorStroke ); - } - if($stroke !=''){ - imagearc($this->_image , $x , $y , $r*2 , $r*2,0,359.9, $colorStroke ); - } - imagecolordeallocate( $this->_image, $colorStroke); - imagecolordeallocate( $this->_image, $colorFill); - imagesetthickness ( $this->_image , 1 ); - } - - /** - * add text in the final image 0 - * @param SimpleXMLElement - * @return - */ - private function _parseText($textNode){ - $x = 0; - $y = 0; - $r = 0; - $strokeWidth = 1; - $fill = ''; - $fontSize = 10; - $fontFamily = 'SansSerif'; - $fontStyle = 'normal'; - $fontWeight = 'normal'; - - extract($this->_getParams($textNode)); - - //case translation - if($this->_getParam('originX') !== null){ - $x += $this->_getParam('originX'); - } - if($this->_getParam('originY') !== null){ - $y += $this->_getParam('originY'); - } - //end translation - //case rotation - if($this->_getParam('rotate') !== null){ - $r = $this->_getParam('rotate'); - } - //end rotation - //case scale - if($this->_getParam('scale') !== null) $fontSize *= ($this->_getParam('scale') -1); - //end scale - - if($textNode == '') - return; - $colorStroke = $this->_allocateColor((string)$fill); - - $fontfile = file_exists('fonts/'.strtolower($fontFamily).'.ttf') ? 'fonts/'.strtolower($fontFamily).'.ttf' : 'fonts/arial.ttf'; - - if($this->_debug) $this->_log->message('text '.rtrim($textNode).' avec typo :'.$fontfile.' de taille '.$fontSize); - if($this->_debug) $this->_log->message('text avec rotation : '.$r); - //imagestring ( $this->_image , 2 , $x , $y , rtrim($textNode) , $fill ); - imagettftext ( $this->_image , (double)$fontSize , $r , $x , $y , $colorStroke , $fontfile , rtrim($textNode) ); - imagecolordeallocate( $this->_image, $colorStroke); - } - - /* - * add a rectangle to the final image - * @param simpleXMLElement - * @return a nice rectangle ! - */ - private function _parseRectangle($rectNode){ - $x = 0; - $y = 0; - $width = 0; - $height = 0; - $r = 0; - $fill = ''; - $stroke = ''; - $strokeWidth = 1; - $strokeDasharray = ''; - extract($this->_getParams($rectNode)); - //case translate - if($this->_getParam('originX') !== null) - $x += $this->_getParam('originX'); - if($this->_getParam('originY') !== null) - $y += $this->_getParam('originY'); - //end translate - if($width == 0 || $height == 0) - return; - $colorStroke = $this->_allocateColor((string)$stroke); - $colorFill = $this->_allocateColor((string)$fill); - $thickness = imagesetthickness( $this->_image , (int)$strokeWidth ); - if($strokeDasharray != ''){ - $strokeDasharray = explode(',', $strokeDasharray); - imagesetstyle ( $this->_image , $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke )); - }else - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - - if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); - - if($fill != '' || ($fill=='' && $stroke=='')){ - imagefilledrectangle ($this->_image , $x , $y , $x+$width , $y+$height, $colorFill ); - imagerectangle($this->_image , $x , $y , $x+$width , $y+$height, IMG_COLOR_STYLED); - } - if($stroke != ''){ - imagerectangle($this->_image , $x , $y , $x+$width , $y+$height, IMG_COLOR_STYLED); - } - imagecolordeallocate($this->_image,$colorStroke); - imagecolordeallocate($this->_image,$colorFill); - imagesetthickness ( $this->_image , 1 ); - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - } - - private function _parseLine($lineNode){ - $x1 = 0; - $y1 = 0; - $x2 = 0; - $y2 = 0; - $stroke = ''; - $strokeWidth = 1; - $strokeDasharray = ''; - extract($this->_getParams($lineNode)); - //case translate - if($this->_getParam('originX') !== null){ - $x1 += $this->_getParam('originX'); - $x2 += $this->_getParam('originX'); - } - if($this->_getParam('originY') !== null){ - $y1 += $this->_getParam('originY'); - $y2 += $this->_getParam('originY'); - } - //end translate - //case rotation - if($this->_getParam('rotate') !== null){ - - } - //end rotation - //case scale - if($this->_getParam('scale') !== null){ - $xrapport = ($x2 - $x1) * ($this->_getParam('scale') -1); - $x2 += $xrapport; - $yrapport = ($y2 - $y1) * ($this->_getParam('scale') -1); - $y2 += $yrapport; - if($this->_debug) $this->_log->message('scale by '.Log::decode($this->_getParam('scale')).':'.Log::decode($xrapport).' - '.Log::decode($yrapport)); - } - //end scale - $colorStroke = $this->_allocateColor((string)$stroke); - $thickness = imagesetthickness( $this->_image , (int)$strokeWidth ); - if($strokeDasharray != ''){ - $strokeDasharray = explode(',', $strokeDasharray); - imagesetstyle ( $this->_image , $this->_getDashedStroke($strokeDasharray[0], $strokeDasharray[1], $colorStroke )); - }else - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - - //if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); - $this->_drawLine($x1, $y1, $x2, $y2, $colorStroke); - imagecolordeallocate($this->_image,$colorStroke); - imagesetthickness ( $this->_image , 1 ); - imagesetstyle ( $this->_image , $this->_getDashedStroke(10, 0, $colorStroke )); - } - - /** - * add a polygon in the final image - * @param simpleXMLElement - * @return po-po-po-polygon ! - */ - private function _parsePolygon($polyNode){ - $points = ''; - $fill = ''; - $stroke = ''; - $strokeWidth = 1; - extract($this->_getParams($polyNode)); - if($points == '') - return; - $pointArray = split('[ ,]', $points); - $colorStroke = $this->_allocateColor((string)$stroke); - $colorFill = $this->_allocateColor((string)$fill); - $thickness = imagesetthickness( $this->_image , (int)$strokeWidth ); - if($this->_debug && !$thickness) $this->_log->error('Erreur dans la mise en place de l\'épaisseur du trait'); - - if($fill != ''){ - imagefilledpolygon ($this->_image , $pointArray , count($pointArray)/2 , $colorFill ); - } - if($stroke != ''){ - imagepolygon ( $this->_image , $pointArray , count($pointArray)/2 , $colorStroke ); - } - imagecolordeallocate($this->_image,$colorStroke); - imagecolordeallocate($this->_image,$colorFill); - imagesetthickness ( $this->_image , 1 ); - } - - /** - * add the description text in the final image - * @param string the description - * @return boolean - */ - private function _parseDescription($desc){ - if($this->_debug) $this->_log->message('Ajout de la description : '.$desc); - return imagestring ( $this->_image , 2, 10, $this->_getImageHeight()-20, $desc , imagecolorallocate($this->_image, 255, 255, 255)); - } - - /** - * @param node - * get group attributes to pass it to children - * parse children - */ - private function _parseGroup($groupNode){ - $this->_currentOptions[] = $this->_getParams($groupNode); - foreach($groupNode->children() as $element){ - $this->_chooseParse($element); - } - unset($this->_currentOptions[count($this->_currentOptions) -1]); - } - - /** - * select what to parse - * @param simpleXMLElement - * @return the selected function - */ - private function _chooseParse($element){ - if($element->getName() == 'image') - $this->_parseImage($element); - if($element->getName() == 'circle') - $this->_parseCircle($element); - if($element->getName() == 'rect') - $this->_parseRectangle($element); - if($element->getName() == 'path') - $this->_parsePath($element); - if($element->getName() == 'polygon') - $this->_parsePolygon($element); - if($element->getName() == 'polyline') - $this->_parsePath($element); - if($element->getName() == 'g') - $this->_parseGroup($element); - if($element->getName() == 'text') - $this->_parseText($element); - if($element->getName() == 'line') - $this->_parseLine($element); - //if($element->getName() == 'defs') - // $this->_parseDefs($element); - //if($element->getName() == 'title') - // $this->_parseTitle($element); - if($element->getName() == 'desc' && $this->_showDesc) - $this->_desc = $element; - } - - /** - * parse everything, main function - * @param string format of the ouput 'png' 'gif' jpg' - * @param string path where you want to save the file (with the final name), null will just show the image but not saved on server - * @return the image - */ - public function toImage($format = 'png', $path = null){ - $writeDesc = null; - $this->_image = imagecreatetruecolor($this->_getImageWidth(), $this->_getImageHeight()); - imagefilledrectangle($this->_image, 0, 0 , $this->_getImageWidth(), $this->_getImageHeight(), $this->_allocateColor('white')); - imagealphablending($this->_image, true); - //imageantialias($this->_image, true); // On ne peut pas gérer l'épaisseur des traits si l'antialiasing est activé... lol ? - foreach($this->_svgXML->children() as $element){ - $this->_chooseParse($element); - $this->_currentOptions = array(); - } - if($this->_showDesc && $this->_desc != null) $this->_parseDescription($this->_desc); - //imagefilter ( $this->_image , IMG_FILTER_SMOOTH, 6); - switch($format){ - case 'gif' : - header("Content-type: " . image_type_to_mime_type(IMAGETYPE_GIF)); - return imagegif($this->_image, $path); - case 'jpg': - header("Content-type: " . image_type_to_mime_type(IMAGETYPE_JPEG)); - return imagejpeg($this->_image, $path); - case 'png' : - default : - header("Content-type: " . image_type_to_mime_type(IMAGETYPE_PNG)); - return imagepng($this->_image, $path); - } - } - -} \ No newline at end of file diff --git a/test.php b/test.php index eaa30ee..82d500b 100644 --- a/test.php +++ b/test.php @@ -1,5 +1,5 @@ - @@ -21,11 +21,11 @@ style="fill:white;stroke:red;stroke-width:2"/> $svg = ' Created with Raphael - + - +