4 * @link http://github.com/PhenX/php-svg-lib
5 * @author Fabien M�nager <fabien.menager@gmail.com>
6 * @license GNU LGPLv3+ http://www.gnu.org/copyleft/lesser.html
11 use Svg\Tag\AbstractTag
;
16 const TYPE_LENGTH
= 2;
19 const TYPE_NUMBER
= 5;
30 public $strokeOpacity;
31 public $strokeLinecap;
32 public $strokeLinejoin;
33 public $strokeMiterlimit;
35 public $strokeDasharray;
36 public $strokeDashoffset;
38 public $fontFamily = 'serif';
39 public $fontSize = 12;
40 public $fontWeight = 'normal';
41 public $fontStyle = 'normal';
42 public $textAnchor = 'start';
44 protected function getStyleMap()
47 'color' => array('color', self
::TYPE_COLOR
),
48 'opacity' => array('opacity', self
::TYPE_NUMBER
),
49 'display' => array('display', self
::TYPE_NAME
),
51 'fill' => array('fill', self
::TYPE_COLOR
),
52 'fill-opacity' => array('fillOpacity', self
::TYPE_NUMBER
),
53 'fill-rule' => array('fillRule', self
::TYPE_NAME
),
55 'stroke' => array('stroke', self
::TYPE_COLOR
),
56 'stroke-dasharray' => array('strokeDasharray', self
::TYPE_NAME
),
57 'stroke-dashoffset' => array('strokeDashoffset', self
::TYPE_NUMBER
),
58 'stroke-linecap' => array('strokeLinecap', self
::TYPE_NAME
),
59 'stroke-linejoin' => array('strokeLinejoin', self
::TYPE_NAME
),
60 'stroke-miterlimit' => array('strokeMiterlimit', self
::TYPE_NUMBER
),
61 'stroke-opacity' => array('strokeOpacity', self
::TYPE_NUMBER
),
62 'stroke-width' => array('strokeWidth', self
::TYPE_NUMBER
),
64 'font-family' => array('fontFamily', self
::TYPE_NAME
),
65 'font-size' => array('fontSize', self
::TYPE_NUMBER
),
66 'font-weight' => array('fontWeight', self
::TYPE_NAME
),
67 'font-style' => array('fontStyle', self
::TYPE_NAME
),
68 'text-anchor' => array('textAnchor', self
::TYPE_NAME
),
77 public function fromAttributes($attributes)
79 $this->fillStyles($attributes);
81 if (isset($attributes["style"])) {
82 $styles = self
::parseCssStyle($attributes["style"]);
83 $this->fillStyles($styles);
87 public function inherit(AbstractTag
$tag) {
88 $group = $tag->getParentGroup();
90 $parent_style = $group->getStyle();
92 foreach ($parent_style as $_key => $_value) {
93 if ($_value !== null) {
94 $this->$_key = $_value;
100 public function fromStyleSheets(AbstractTag
$tag, $attributes) {
101 $class = isset($attributes["class"]) ?
preg_split('/\s+/', trim($attributes["class"])) : null;
103 $stylesheets = $tag->getDocument()->getStyleSheets();
107 foreach ($stylesheets as $_sc) {
109 /** @var \Sabberworm\CSS\RuleSet\DeclarationBlock $_decl */
110 foreach ($_sc->getAllDeclarationBlocks() as $_decl) {
112 /** @var \Sabberworm\CSS\Property\Selector $_selector */
113 foreach ($_decl->getSelectors() as $_selector) {
114 $_selector = $_selector->getSelector();
117 if ($class !== null) {
118 foreach ($class as $_class) {
119 if ($_selector === ".$_class") {
120 /** @var \Sabberworm\CSS\Rule\Rule $_rule */
121 foreach ($_decl->getRules() as $_rule) {
122 $styles[$_rule->getRule()] = $_rule->getValue() . "";
131 if ($_selector === $tag->tagName
) {
132 /** @var \Sabberworm\CSS\Rule\Rule $_rule */
133 foreach ($_decl->getRules() as $_rule) {
134 $styles[$_rule->getRule()] = $_rule->getValue() . "";
143 $this->fillStyles($styles);
146 protected function fillStyles($styles)
148 foreach ($this->getStyleMap() as $from => $spec) {
149 if (isset($styles[$from])) {
150 list($to, $type) = $spec;
153 case self
::TYPE_COLOR
:
154 $value = self
::parseColor($styles[$from]);
157 case self
::TYPE_NUMBER
:
158 $value = ($styles[$from] === null) ?
null : (float)$styles[$from];
162 $value = $styles[$from];
165 if ($value !== null) {
172 static function parseColor($color)
174 $color = strtolower(trim($color));
176 $parts = preg_split('/[^,]\s+/', $color, 2);
178 if (count($parts) == 2) {
185 if ($color === "none") {
190 if (isset(self
::$colorNames[$color])) {
191 return self
::parseHexColor(self
::$colorNames[$color]);
195 if ($color[0] === "#") {
196 return self
::parseHexColor($color);
200 if (strpos($color, "rgb") !== false) {
201 return self
::getTriplet($color);
205 if (strpos($color, "hsl") !== false) {
206 $triplet = self
::getTriplet($color, true);
208 if ($triplet == null) {
212 list($h, $s, $l) = $triplet;
217 $v = ($l <= 0.5) ?
($l * (1.0 +
$s)) : ($l +
$s - $l * $s);
220 $sv = ($v - $m) / $v;
222 $sextant = floor($h);
223 $fract = $h - $sextant;
224 $vsf = $v * $sv * $fract;
270 if (strpos($color, "url(#") !== false) {
271 $i = strpos($color, "(");
272 $j = strpos($color, ")");
275 if ($i === false ||
$j === false) {
279 return trim(substr($color, $i +
1, $j - $i - 1));
285 static function getTriplet($color, $percent = false) {
286 $i = strpos($color, "(");
287 $j = strpos($color, ")");
290 if ($i === false ||
$j === false) {
294 $triplet = preg_split("/\\s*,\\s*/", trim(substr($color, $i +
1, $j - $i - 1)));
296 if (count($triplet) != 3) {
300 foreach (array_keys($triplet) as $c) {
301 $triplet[$c] = trim($triplet[$c]);
304 if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
305 $triplet[$c] = $triplet[$c] / 100;
308 $triplet[$c] = $triplet[$c] / 255;
312 if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
313 $triplet[$c] = round($triplet[$c] * 2.55);
321 static function parseHexColor($hex)
326 if (isset($hex[6])) {
327 $c[0] = hexdec(substr($hex, 1, 2));
328 $c[1] = hexdec(substr($hex, 3, 2));
329 $c[2] = hexdec(substr($hex, 5, 2));
331 $c[0] = hexdec($hex[1] . $hex[1]);
332 $c[1] = hexdec($hex[2] . $hex[2]);
333 $c[2] = hexdec($hex[3] . $hex[3]);
346 static function parseCssStyle($style)
349 preg_match_all("/([a-z-]+)\\s*:\\s*([^;$]+)/si", $style, $matches, PREG_SET_ORDER
);
352 foreach ($matches as $match) {
353 $styles[$match[1]] = $match[2];
360 * Convert a size to a float
362 * @param string $size SVG size
363 * @param float $dpi DPI
364 * @param float $referenceSize Reference size
368 static function convertSize($size, $referenceSize = 11.0, $dpi = 96.0) {
369 $size = trim(strtolower($size));
371 if (is_numeric($size)) {
375 if ($pos = strpos($size, "px")) {
376 return floatval(substr($size, 0, $pos));
379 if ($pos = strpos($size, "pt")) {
380 return floatval(substr($size, 0, $pos));
383 if ($pos = strpos($size, "cm")) {
384 return floatval(substr($size, 0, $pos)) * $dpi;
387 if ($pos = strpos($size, "%")) {
388 return $referenceSize * substr($size, 0, $pos) / 100;
391 if ($pos = strpos($size, "em")) {
392 return $referenceSize * substr($size, 0, $pos);
395 // TODO cm, mm, pc, in, etc
400 static $colorNames = array(
401 'antiquewhite' => '#FAEBD7',
403 'aquamarine' => '#7FFFD4',
404 'beige' => '#F5F5DC',
405 'black' => '#000000',
407 'brown' => '#A52A2A',
408 'cadetblue' => '#5F9EA0',
409 'chocolate' => '#D2691E',
410 'cornflowerblue' => '#6495ED',
411 'crimson' => '#DC143C',
412 'darkblue' => '#00008B',
413 'darkgoldenrod' => '#B8860B',
414 'darkgreen' => '#006400',
415 'darkmagenta' => '#8B008B',
416 'darkorange' => '#FF8C00',
417 'darkred' => '#8B0000',
418 'darkseagreen' => '#8FBC8F',
419 'darkslategray' => '#2F4F4F',
420 'darkviolet' => '#9400D3',
421 'deepskyblue' => '#00BFFF',
422 'dodgerblue' => '#1E90FF',
423 'firebrick' => '#B22222',
424 'forestgreen' => '#228B22',
425 'fuchsia' => '#FF00FF',
426 'gainsboro' => '#DCDCDC',
429 'green' => '#008000',
430 'greenyellow' => '#ADFF2F',
431 'hotpink' => '#FF69B4',
432 'indigo' => '#4B0082',
433 'khaki' => '#F0E68C',
434 'lavenderblush' => '#FFF0F5',
435 'lemonchiffon' => '#FFFACD',
436 'lightcoral' => '#F08080',
437 'lightgoldenrodyellow' => '#FAFAD2',
438 'lightgreen' => '#90EE90',
439 'lightsalmon' => '#FFA07A',
440 'lightskyblue' => '#87CEFA',
441 'lightslategray' => '#778899',
442 'lightyellow' => '#FFFFE0',
444 'limegreen' => '#32CD32',
445 'magenta' => '#FF00FF',
446 'maroon' => '#800000',
447 'mediumaquamarine' => '#66CDAA',
448 'mediumorchid' => '#BA55D3',
449 'mediumseagreen' => '#3CB371',
450 'mediumspringgreen' => '#00FA9A',
451 'mediumvioletred' => '#C71585',
452 'midnightblue' => '#191970',
453 'mintcream' => '#F5FFFA',
454 'moccasin' => '#FFE4B5',
456 'olive' => '#808000',
457 'orange' => '#FFA500',
458 'orchid' => '#DA70D6',
459 'palegreen' => '#98FB98',
460 'palevioletred' => '#D87093',
461 'peachpuff' => '#FFDAB9',
463 'powderblue' => '#B0E0E6',
464 'purple' => '#800080',
466 'royalblue' => '#4169E1',
467 'salmon' => '#FA8072',
468 'seagreen' => '#2E8B57',
469 'sienna' => '#A0522D',
470 'silver' => '#C0C0C0',
471 'skyblue' => '#87CEEB',
472 'slategray' => '#708090',
473 'springgreen' => '#00FF7F',
474 'steelblue' => '#4682B4',
477 'thistle' => '#D8BFD8',
478 'turquoise' => '#40E0D0',
479 'violetred' => '#D02090',
480 'white' => '#FFFFFF',
481 'yellow' => '#FFFF00',
482 'aliceblue' => '#f0f8ff',
483 'azure' => '#f0ffff',
484 'bisque' => '#ffe4c4',
485 'blanchedalmond' => '#ffebcd',
486 'blueviolet' => '#8a2be2',
487 'burlywood' => '#deb887',
488 'chartreuse' => '#7fff00',
489 'coral' => '#ff7f50',
490 'cornsilk' => '#fff8dc',
492 'darkcyan' => '#008b8b',
493 'darkgray' => '#a9a9a9',
494 'darkgrey' => '#a9a9a9',
495 'darkkhaki' => '#bdb76b',
496 'darkolivegreen' => '#556b2f',
497 'darkorchid' => '#9932cc',
498 'darksalmon' => '#e9967a',
499 'darkslateblue' => '#483d8b',
500 'darkslategrey' => '#2f4f4f',
501 'darkturquoise' => '#00ced1',
502 'deeppink' => '#ff1493',
503 'dimgray' => '#696969',
504 'dimgrey' => '#696969',
505 'floralwhite' => '#fffaf0',
506 'ghostwhite' => '#f8f8ff',
507 'goldenrod' => '#daa520',
509 'honeydew' => '#f0fff0',
510 'indianred' => '#cd5c5c',
511 'ivory' => '#fffff0',
512 'lavender' => '#e6e6fa',
513 'lawngreen' => '#7cfc00',
514 'lightblue' => '#add8e6',
515 'lightcyan' => '#e0ffff',
516 'lightgray' => '#d3d3d3',
517 'lightgrey' => '#d3d3d3',
518 'lightpink' => '#ffb6c1',
519 'lightseagreen' => '#20b2aa',
520 'lightslategrey' => '#778899',
521 'lightsteelblue' => '#b0c4de',
522 'linen' => '#faf0e6',
523 'mediumblue' => '#0000cd',
524 'mediumpurple' => '#9370db',
525 'mediumslateblue' => '#7b68ee',
526 'mediumturquoise' => '#48d1cc',
527 'mistyrose' => '#ffe4e1',
528 'navajowhite' => '#ffdead',
529 'oldlace' => '#fdf5e6',
530 'olivedrab' => '#6b8e23',
531 'orangered' => '#ff4500',
532 'palegoldenrod' => '#eee8aa',
533 'paleturquoise' => '#afeeee',
534 'papayawhip' => '#ffefd5',
537 'rosybrown' => '#bc8f8f',
538 'saddlebrown' => '#8b4513',
539 'sandybrown' => '#f4a460',
540 'seashell' => '#fff5ee',
541 'slateblue' => '#6a5acd',
542 'slategrey' => '#708090',
544 'tomato' => '#ff6347',
545 'violet' => '#ee82ee',
546 'wheat' => '#f5deb3',
547 'whitesmoke' => '#f5f5f5',
548 'yellowgreen' => '#9acd32',