composer package updates
[openemr.git] / vendor / phenx / php-svg-lib / src / Svg / Style.php
blob9e7f6dba0605d255272ede0fa2888bcac778ccea
1 <?php
2 /**
3 * @package php-svg-lib
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
7 */
9 namespace Svg;
11 use Svg\Tag\AbstractTag;
13 class Style
15 const TYPE_COLOR = 1;
16 const TYPE_LENGTH = 2;
17 const TYPE_NAME = 3;
18 const TYPE_ANGLE = 4;
19 const TYPE_NUMBER = 5;
21 public $color;
22 public $opacity;
23 public $display;
25 public $fill;
26 public $fillOpacity;
27 public $fillRule;
29 public $stroke;
30 public $strokeOpacity;
31 public $strokeLinecap;
32 public $strokeLinejoin;
33 public $strokeMiterlimit;
34 public $strokeWidth;
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()
46 return array(
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),
72 /**
73 * @param $attributes
75 * @return Style
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();
89 if ($group) {
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();
105 $styles = array();
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();
116 // Match class name
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() . "";
125 break 2;
130 // Match tag name
131 if ($_selector === $tag->tagName) {
132 /** @var \Sabberworm\CSS\Rule\Rule $_rule */
133 foreach ($_decl->getRules() as $_rule) {
134 $styles[$_rule->getRule()] = $_rule->getValue() . "";
137 break;
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;
151 $value = null;
152 switch ($type) {
153 case self::TYPE_COLOR:
154 $value = self::parseColor($styles[$from]);
155 break;
157 case self::TYPE_NUMBER:
158 $value = ($styles[$from] === null) ? null : (float)$styles[$from];
159 break;
161 default:
162 $value = $styles[$from];
165 if ($value !== null) {
166 $this->$to = $value;
172 static function parseColor($color)
174 $color = strtolower(trim($color));
176 $parts = preg_split('/[^,]\s+/', $color, 2);
178 if (count($parts) == 2) {
179 $color = $parts[1];
181 else {
182 $color = $parts[0];
185 if ($color === "none") {
186 return "none";
189 // SVG color name
190 if (isset(self::$colorNames[$color])) {
191 return self::parseHexColor(self::$colorNames[$color]);
194 // Hex color
195 if ($color[0] === "#") {
196 return self::parseHexColor($color);
199 // RGB color
200 if (strpos($color, "rgb") !== false) {
201 return self::getTriplet($color);
204 // RGB color
205 if (strpos($color, "hsl") !== false) {
206 $triplet = self::getTriplet($color, true);
208 if ($triplet == null) {
209 return null;
212 list($h, $s, $l) = $triplet;
214 $r = $l;
215 $g = $l;
216 $b = $l;
217 $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
218 if ($v > 0) {
219 $m = $l + $l - $v;
220 $sv = ($v - $m) / $v;
221 $h *= 6.0;
222 $sextant = floor($h);
223 $fract = $h - $sextant;
224 $vsf = $v * $sv * $fract;
225 $mid1 = $m + $vsf;
226 $mid2 = $v - $vsf;
228 switch ($sextant) {
229 case 0:
230 $r = $v;
231 $g = $mid1;
232 $b = $m;
233 break;
234 case 1:
235 $r = $mid2;
236 $g = $v;
237 $b = $m;
238 break;
239 case 2:
240 $r = $m;
241 $g = $v;
242 $b = $mid1;
243 break;
244 case 3:
245 $r = $m;
246 $g = $mid2;
247 $b = $v;
248 break;
249 case 4:
250 $r = $mid1;
251 $g = $m;
252 $b = $v;
253 break;
254 case 5:
255 $r = $v;
256 $g = $m;
257 $b = $mid2;
258 break;
262 return array(
263 $r * 255.0,
264 $g * 255.0,
265 $b * 255.0,
269 // Gradient
270 if (strpos($color, "url(#") !== false) {
271 $i = strpos($color, "(");
272 $j = strpos($color, ")");
274 // Bad url format
275 if ($i === false || $j === false) {
276 return null;
279 return trim(substr($color, $i + 1, $j - $i - 1));
282 return null;
285 static function getTriplet($color, $percent = false) {
286 $i = strpos($color, "(");
287 $j = strpos($color, ")");
289 // Bad color value
290 if ($i === false || $j === false) {
291 return null;
294 $triplet = preg_split("/\\s*,\\s*/", trim(substr($color, $i + 1, $j - $i - 1)));
296 if (count($triplet) != 3) {
297 return null;
300 foreach (array_keys($triplet) as $c) {
301 $triplet[$c] = trim($triplet[$c]);
303 if ($percent) {
304 if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
305 $triplet[$c] = $triplet[$c] / 100;
307 else {
308 $triplet[$c] = $triplet[$c] / 255;
311 else {
312 if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
313 $triplet[$c] = round($triplet[$c] * 2.55);
318 return $triplet;
321 static function parseHexColor($hex)
323 $c = array(0, 0, 0);
325 // #FFFFFF
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));
330 } else {
331 $c[0] = hexdec($hex[1] . $hex[1]);
332 $c[1] = hexdec($hex[2] . $hex[2]);
333 $c[2] = hexdec($hex[3] . $hex[3]);
336 return $c;
340 * Simple CSS parser
342 * @param $style
344 * @return array
346 static function parseCssStyle($style)
348 $matches = array();
349 preg_match_all("/([a-z-]+)\\s*:\\s*([^;$]+)/si", $style, $matches, PREG_SET_ORDER);
351 $styles = array();
352 foreach ($matches as $match) {
353 $styles[$match[1]] = $match[2];
356 return $styles;
360 * Convert a size to a float
362 * @param string $size SVG size
363 * @param float $dpi DPI
364 * @param float $referenceSize Reference size
366 * @return float|null
368 static function convertSize($size, $referenceSize = 11.0, $dpi = 96.0) {
369 $size = trim(strtolower($size));
371 if (is_numeric($size)) {
372 return $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
397 return null;
400 static $colorNames = array(
401 'antiquewhite' => '#FAEBD7',
402 'aqua' => '#00FFFF',
403 'aquamarine' => '#7FFFD4',
404 'beige' => '#F5F5DC',
405 'black' => '#000000',
406 'blue' => '#0000FF',
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',
427 'gold' => '#FFD700',
428 'gray' => '#808080',
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',
443 'lime' => '#00FF00',
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',
455 'navy' => '#000080',
456 'olive' => '#808000',
457 'orange' => '#FFA500',
458 'orchid' => '#DA70D6',
459 'palegreen' => '#98FB98',
460 'palevioletred' => '#D87093',
461 'peachpuff' => '#FFDAB9',
462 'pink' => '#FFC0CB',
463 'powderblue' => '#B0E0E6',
464 'purple' => '#800080',
465 'red' => '#FF0000',
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',
475 'tan' => '#D2B48C',
476 'teal' => '#008080',
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',
491 'cyan' => '#00ffff',
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',
508 'grey' => '#808080',
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',
535 'peru' => '#cd853f',
536 'plum' => '#dda0dd',
537 'rosybrown' => '#bc8f8f',
538 'saddlebrown' => '#8b4513',
539 'sandybrown' => '#f4a460',
540 'seashell' => '#fff5ee',
541 'slateblue' => '#6a5acd',
542 'slategrey' => '#708090',
543 'snow' => '#fffafa',
544 'tomato' => '#ff6347',
545 'violet' => '#ee82ee',
546 'wheat' => '#f5deb3',
547 'whitesmoke' => '#f5f5f5',
548 'yellowgreen' => '#9acd32',