PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/phenx/php-svg-lib/src/Svg/Style.php

https://bitbucket.org/openemr/openemr
PHP | 485 lines | 396 code | 55 blank | 34 comment | 34 complexity | 14ae890241ac59494b25dbe136286837 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-1.0, GPL-2.0, LGPL-3.0, BSD-3-Clause, Unlicense, MPL-2.0, GPL-3.0, LGPL-2.1
  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 http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  7. */
  8. namespace Svg;
  9. use Svg\Tag\AbstractTag;
  10. class Style
  11. {
  12. const TYPE_COLOR = 1;
  13. const TYPE_LENGTH = 2;
  14. const TYPE_NAME = 3;
  15. const TYPE_ANGLE = 4;
  16. const TYPE_NUMBER = 5;
  17. public $color;
  18. public $opacity;
  19. public $fill;
  20. public $fillOpacity;
  21. public $fillRule;
  22. public $stroke;
  23. public $strokeOpacity;
  24. public $strokeLinecap;
  25. public $strokeLinejoin;
  26. public $strokeMiterlimit;
  27. public $strokeWidth;
  28. public $strokeDasharray;
  29. public $strokeDashoffset;
  30. public $fontFamily = 'serif';
  31. public $fontSize = 12;
  32. public $fontWeight = 'normal';
  33. public $fontStyle = 'normal';
  34. public $textAnchor = 'start';
  35. protected function getStyleMap()
  36. {
  37. return array(
  38. 'color' => array('color', self::TYPE_COLOR),
  39. 'opacity' => array('opacity', self::TYPE_NUMBER),
  40. 'fill' => array('fill', self::TYPE_COLOR),
  41. 'fill-opacity' => array('fillOpacity', self::TYPE_NUMBER),
  42. 'fill-rule' => array('fillRule', self::TYPE_NAME),
  43. 'stroke' => array('stroke', self::TYPE_COLOR),
  44. 'stroke-dasharray' => array('strokeDasharray', self::TYPE_NAME),
  45. 'stroke-dashoffset' => array('strokeDashoffset', self::TYPE_NUMBER),
  46. 'stroke-linecap' => array('strokeLinecap', self::TYPE_NAME),
  47. 'stroke-linejoin' => array('strokeLinejoin', self::TYPE_NAME),
  48. 'stroke-miterlimit' => array('strokeMiterlimit', self::TYPE_NUMBER),
  49. 'stroke-opacity' => array('strokeOpacity', self::TYPE_NUMBER),
  50. 'stroke-width' => array('strokeWidth', self::TYPE_NUMBER),
  51. 'font-family' => array('fontFamily', self::TYPE_NAME),
  52. 'font-size' => array('fontSize', self::TYPE_NUMBER),
  53. 'font-weight' => array('fontWeight', self::TYPE_NUMBER),
  54. 'font-style' => array('fontStyle', self::TYPE_NAME),
  55. 'text-anchor' => array('textAnchor', self::TYPE_NAME),
  56. );
  57. }
  58. /**
  59. * @param $attributes
  60. *
  61. * @return Style
  62. */
  63. public function fromAttributes($attributes)
  64. {
  65. $this->fillStyles($attributes);
  66. if (isset($attributes["style"])) {
  67. $styles = self::parseCssStyle($attributes["style"]);
  68. $this->fillStyles($styles);
  69. }
  70. }
  71. public function inherit(AbstractTag $tag) {
  72. $group = $tag->getParentGroup();
  73. if ($group) {
  74. $parent_style = $group->getStyle();
  75. foreach ($parent_style as $_key => $_value) {
  76. if ($_value !== null) {
  77. $this->$_key = $_value;
  78. }
  79. }
  80. }
  81. }
  82. protected function fillStyles($styles)
  83. {
  84. foreach ($this->getStyleMap() as $from => $spec) {
  85. if (isset($styles[$from])) {
  86. list($to, $type) = $spec;
  87. $value = null;
  88. switch ($type) {
  89. case self::TYPE_COLOR:
  90. $value = self::parseColor($styles[$from]);
  91. break;
  92. case self::TYPE_NUMBER:
  93. $value = ($styles[$from] === null) ? null : (float)$styles[$from];
  94. break;
  95. default:
  96. $value = $styles[$from];
  97. }
  98. if ($value !== null) {
  99. $this->$to = $value;
  100. }
  101. }
  102. }
  103. }
  104. static function parseColor($color)
  105. {
  106. $color = strtolower(trim($color));
  107. $parts = preg_split('/\s+/', $color, 2);
  108. if (count($parts) == 2) {
  109. $color = $parts[1];
  110. }
  111. else {
  112. $color = $parts[0];
  113. }
  114. if ($color === "none") {
  115. return "none";
  116. }
  117. // SVG color name
  118. if (isset(self::$colorNames[$color])) {
  119. return self::parseHexColor(self::$colorNames[$color]);
  120. }
  121. // Hex color
  122. if ($color[0] === "#") {
  123. return self::parseHexColor($color);
  124. }
  125. // RGB color
  126. if (strpos($color, "rgb") !== false) {
  127. return self::getTriplet($color);
  128. }
  129. // RGB color
  130. if (strpos($color, "hsl") !== false) {
  131. $triplet = self::getTriplet($color, true);
  132. if ($triplet == null) {
  133. return null;
  134. }
  135. list($h, $s, $l) = $triplet;
  136. $r = $l;
  137. $g = $l;
  138. $b = $l;
  139. $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
  140. if ($v > 0) {
  141. $m = $l + $l - $v;
  142. $sv = ($v - $m) / $v;
  143. $h *= 6.0;
  144. $sextant = floor($h);
  145. $fract = $h - $sextant;
  146. $vsf = $v * $sv * $fract;
  147. $mid1 = $m + $vsf;
  148. $mid2 = $v - $vsf;
  149. switch ($sextant) {
  150. case 0:
  151. $r = $v;
  152. $g = $mid1;
  153. $b = $m;
  154. break;
  155. case 1:
  156. $r = $mid2;
  157. $g = $v;
  158. $b = $m;
  159. break;
  160. case 2:
  161. $r = $m;
  162. $g = $v;
  163. $b = $mid1;
  164. break;
  165. case 3:
  166. $r = $m;
  167. $g = $mid2;
  168. $b = $v;
  169. break;
  170. case 4:
  171. $r = $mid1;
  172. $g = $m;
  173. $b = $v;
  174. break;
  175. case 5:
  176. $r = $v;
  177. $g = $m;
  178. $b = $mid2;
  179. break;
  180. }
  181. }
  182. return array(
  183. $r * 255.0,
  184. $g * 255.0,
  185. $b * 255.0,
  186. );
  187. }
  188. return null;
  189. }
  190. static function getTriplet($color, $percent = false) {
  191. $i = strpos($color, "(");
  192. $j = strpos($color, ")");
  193. // Bad color value
  194. if ($i === false || $j === false) {
  195. return null;
  196. }
  197. $triplet = preg_split("/\\s*,\\s*/", trim(substr($color, $i + 1, $j - $i - 1)));
  198. if (count($triplet) != 3) {
  199. return null;
  200. }
  201. foreach (array_keys($triplet) as $c) {
  202. $triplet[$c] = trim($triplet[$c]);
  203. if ($percent) {
  204. if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
  205. $triplet[$c] = $triplet[$c] / 100;
  206. }
  207. else {
  208. $triplet[$c] = $triplet[$c] / 255;
  209. }
  210. }
  211. else {
  212. if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
  213. $triplet[$c] = round($triplet[$c] * 2.55);
  214. }
  215. }
  216. }
  217. return $triplet;
  218. }
  219. static function parseHexColor($hex)
  220. {
  221. $c = array(0, 0, 0);
  222. // #FFFFFF
  223. if (isset($hex[6])) {
  224. $c[0] = hexdec(substr($hex, 1, 2));
  225. $c[1] = hexdec(substr($hex, 3, 2));
  226. $c[2] = hexdec(substr($hex, 5, 2));
  227. } else {
  228. $c[0] = hexdec($hex[1] . $hex[1]);
  229. $c[1] = hexdec($hex[2] . $hex[2]);
  230. $c[2] = hexdec($hex[3] . $hex[3]);
  231. }
  232. return $c;
  233. }
  234. /**
  235. * Simple CSS parser
  236. *
  237. * @param $style
  238. *
  239. * @return array
  240. */
  241. static function parseCssStyle($style)
  242. {
  243. $matches = array();
  244. preg_match_all("/([a-z-]+)\\s*:\\s*([^;$]+)/si", $style, $matches, PREG_SET_ORDER);
  245. $styles = array();
  246. foreach ($matches as $match) {
  247. $styles[$match[1]] = $match[2];
  248. }
  249. return $styles;
  250. }
  251. /**
  252. * Convert a size to a float
  253. *
  254. * @param string $size SVG size
  255. * @param float $dpi DPI
  256. * @param float $fontsize Reference font size
  257. *
  258. * @return float|null
  259. */
  260. static function convertSize($size, $dpi = 72.0, $fontsize = 11.0) {
  261. $size = trim(strtolower($size));
  262. if (is_numeric($size)) {
  263. return $size;
  264. }
  265. if ($pos = strpos($size, "px")) {
  266. return floatval(substr($size, 0, $pos));
  267. }
  268. if ($pos = strpos($size, "pt")) {
  269. return floatval(substr($size, 0, $pos));
  270. }
  271. if ($pos = strpos($size, "%")) {
  272. return $fontsize * substr($size, 0, $pos) / 100;
  273. }
  274. if ($pos = strpos($size, "em")) {
  275. return $fontsize * substr($size, 0, $pos);
  276. }
  277. // TODO cm, mm, pc, in, etc
  278. return null;
  279. }
  280. static $colorNames = array(
  281. 'antiquewhite' => '#FAEBD7',
  282. 'aqua' => '#00FFFF',
  283. 'aquamarine' => '#7FFFD4',
  284. 'beige' => '#F5F5DC',
  285. 'black' => '#000000',
  286. 'blue' => '#0000FF',
  287. 'brown' => '#A52A2A',
  288. 'cadetblue' => '#5F9EA0',
  289. 'chocolate' => '#D2691E',
  290. 'cornflowerblue' => '#6495ED',
  291. 'crimson' => '#DC143C',
  292. 'darkblue' => '#00008B',
  293. 'darkgoldenrod' => '#B8860B',
  294. 'darkgreen' => '#006400',
  295. 'darkmagenta' => '#8B008B',
  296. 'darkorange' => '#FF8C00',
  297. 'darkred' => '#8B0000',
  298. 'darkseagreen' => '#8FBC8F',
  299. 'darkslategray' => '#2F4F4F',
  300. 'darkviolet' => '#9400D3',
  301. 'deepskyblue' => '#00BFFF',
  302. 'dodgerblue' => '#1E90FF',
  303. 'firebrick' => '#B22222',
  304. 'forestgreen' => '#228B22',
  305. 'fuchsia' => '#FF00FF',
  306. 'gainsboro' => '#DCDCDC',
  307. 'gold' => '#FFD700',
  308. 'gray' => '#808080',
  309. 'green' => '#008000',
  310. 'greenyellow' => '#ADFF2F',
  311. 'hotpink' => '#FF69B4',
  312. 'indigo' => '#4B0082',
  313. 'khaki' => '#F0E68C',
  314. 'lavenderblush' => '#FFF0F5',
  315. 'lemonchiffon' => '#FFFACD',
  316. 'lightcoral' => '#F08080',
  317. 'lightgoldenrodyellow' => '#FAFAD2',
  318. 'lightgreen' => '#90EE90',
  319. 'lightsalmon' => '#FFA07A',
  320. 'lightskyblue' => '#87CEFA',
  321. 'lightslategray' => '#778899',
  322. 'lightyellow' => '#FFFFE0',
  323. 'lime' => '#00FF00',
  324. 'limegreen' => '#32CD32',
  325. 'magenta' => '#FF00FF',
  326. 'maroon' => '#800000',
  327. 'mediumaquamarine' => '#66CDAA',
  328. 'mediumorchid' => '#BA55D3',
  329. 'mediumseagreen' => '#3CB371',
  330. 'mediumspringgreen' => '#00FA9A',
  331. 'mediumvioletred' => '#C71585',
  332. 'midnightblue' => '#191970',
  333. 'mintcream' => '#F5FFFA',
  334. 'moccasin' => '#FFE4B5',
  335. 'navy' => '#000080',
  336. 'olive' => '#808000',
  337. 'orange' => '#FFA500',
  338. 'orchid' => '#DA70D6',
  339. 'palegreen' => '#98FB98',
  340. 'palevioletred' => '#D87093',
  341. 'peachpuff' => '#FFDAB9',
  342. 'pink' => '#FFC0CB',
  343. 'powderblue' => '#B0E0E6',
  344. 'purple' => '#800080',
  345. 'red' => '#FF0000',
  346. 'royalblue' => '#4169E1',
  347. 'salmon' => '#FA8072',
  348. 'seagreen' => '#2E8B57',
  349. 'sienna' => '#A0522D',
  350. 'silver' => '#C0C0C0',
  351. 'skyblue' => '#87CEEB',
  352. 'slategray' => '#708090',
  353. 'springgreen' => '#00FF7F',
  354. 'steelblue' => '#4682B4',
  355. 'tan' => '#D2B48C',
  356. 'teal' => '#008080',
  357. 'thistle' => '#D8BFD8',
  358. 'turquoise' => '#40E0D0',
  359. 'violetred' => '#D02090',
  360. 'white' => '#FFFFFF',
  361. 'yellow' => '#FFFF00',
  362. 'aliceblue' => '#f0f8ff',
  363. 'azure' => '#f0ffff',
  364. 'bisque' => '#ffe4c4',
  365. 'blanchedalmond' => '#ffebcd',
  366. 'blueviolet' => '#8a2be2',
  367. 'burlywood' => '#deb887',
  368. 'chartreuse' => '#7fff00',
  369. 'coral' => '#ff7f50',
  370. 'cornsilk' => '#fff8dc',
  371. 'cyan' => '#00ffff',
  372. 'darkcyan' => '#008b8b',
  373. 'darkgray' => '#a9a9a9',
  374. 'darkgrey' => '#a9a9a9',
  375. 'darkkhaki' => '#bdb76b',
  376. 'darkolivegreen' => '#556b2f',
  377. 'darkorchid' => '#9932cc',
  378. 'darksalmon' => '#e9967a',
  379. 'darkslateblue' => '#483d8b',
  380. 'darkslategrey' => '#2f4f4f',
  381. 'darkturquoise' => '#00ced1',
  382. 'deeppink' => '#ff1493',
  383. 'dimgray' => '#696969',
  384. 'dimgrey' => '#696969',
  385. 'floralwhite' => '#fffaf0',
  386. 'ghostwhite' => '#f8f8ff',
  387. 'goldenrod' => '#daa520',
  388. 'grey' => '#808080',
  389. 'honeydew' => '#f0fff0',
  390. 'indianred' => '#cd5c5c',
  391. 'ivory' => '#fffff0',
  392. 'lavender' => '#e6e6fa',
  393. 'lawngreen' => '#7cfc00',
  394. 'lightblue' => '#add8e6',
  395. 'lightcyan' => '#e0ffff',
  396. 'lightgray' => '#d3d3d3',
  397. 'lightgrey' => '#d3d3d3',
  398. 'lightpink' => '#ffb6c1',
  399. 'lightseagreen' => '#20b2aa',
  400. 'lightslategrey' => '#778899',
  401. 'lightsteelblue' => '#b0c4de',
  402. 'linen' => '#faf0e6',
  403. 'mediumblue' => '#0000cd',
  404. 'mediumpurple' => '#9370db',
  405. 'mediumslateblue' => '#7b68ee',
  406. 'mediumturquoise' => '#48d1cc',
  407. 'mistyrose' => '#ffe4e1',
  408. 'navajowhite' => '#ffdead',
  409. 'oldlace' => '#fdf5e6',
  410. 'olivedrab' => '#6b8e23',
  411. 'orangered' => '#ff4500',
  412. 'palegoldenrod' => '#eee8aa',
  413. 'paleturquoise' => '#afeeee',
  414. 'papayawhip' => '#ffefd5',
  415. 'peru' => '#cd853f',
  416. 'plum' => '#dda0dd',
  417. 'rosybrown' => '#bc8f8f',
  418. 'saddlebrown' => '#8b4513',
  419. 'sandybrown' => '#f4a460',
  420. 'seashell' => '#fff5ee',
  421. 'slateblue' => '#6a5acd',
  422. 'slategrey' => '#708090',
  423. 'snow' => '#fffafa',
  424. 'tomato' => '#ff6347',
  425. 'violet' => '#ee82ee',
  426. 'wheat' => '#f5deb3',
  427. 'whitesmoke' => '#f5f5f5',
  428. 'yellowgreen' => '#9acd32',
  429. );
  430. }