Skip to content

Commit 0d3ca5e

Browse files
committed
Improve color parsing
- use correct format for default fill color - set default color to black for better currentcolor support - add support for alpha (hex, rgba, hsla) fixes #24 fixes #68
1 parent 6fd8b90 commit 0d3ca5e

File tree

3 files changed

+79
-38
lines changed

3 files changed

+79
-38
lines changed

src/Svg/DefaultStyle.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
class DefaultStyle extends Style
1212
{
13-
public $color = '';
13+
public $color = [0, 0, 0, 1];
1414
public $opacity = 1.0;
1515
public $display = 'inline';
1616

17-
public $fill = 'black';
17+
public $fill = [0, 0, 0, 1];
1818
public $fillOpacity = 1.0;
1919
public $fillRule = 'nonzero';
2020

src/Svg/Style.php

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class Style
1818
const TYPE_ANGLE = 4;
1919
const TYPE_NUMBER = 5;
2020

21+
private $_parentStyle;
22+
2123
public $color;
2224
public $opacity;
2325
public $display;
@@ -88,7 +90,7 @@ public function inherit(AbstractTag $tag) {
8890
$group = $tag->getParentGroup();
8991
if ($group) {
9092
$parent_style = $group->getStyle();
91-
93+
$this->_parentStyle = $parent_style;
9294
foreach ($parent_style as $_key => $_value) {
9395
if ($_value !== null) {
9496
$this->$_key = $_value;
@@ -145,13 +147,24 @@ public function fromStyleSheets(AbstractTag $tag, $attributes) {
145147

146148
protected function fillStyles($styles)
147149
{
148-
foreach ($this->getStyleMap() as $from => $spec) {
150+
$style_map = $this->getStyleMap();
151+
foreach ($style_map as $from => $spec) {
149152
if (isset($styles[$from])) {
150153
list($to, $type) = $spec;
151154
$value = null;
152155
switch ($type) {
153156
case self::TYPE_COLOR:
154157
$value = self::parseColor($styles[$from]);
158+
if ($value === "currentcolor") {
159+
if ($type === "color") {
160+
$value = $this->_parentStyle->color;
161+
} else {
162+
$value = $this->color;
163+
}
164+
}
165+
if ($value !== null && $value[3] !== 1 && array_key_exists("{$from}-opacity", $style_map) === true) {
166+
$styles["{$from}-opacity"] = $value[3];
167+
}
155168
break;
156169

157170
case self::TYPE_NUMBER:
@@ -177,15 +190,18 @@ static function parseColor($color)
177190

178191
if (count($parts) == 2) {
179192
$color = $parts[1];
180-
}
181-
else {
193+
} else {
182194
$color = $parts[0];
183195
}
184196

185197
if ($color === "none") {
186198
return "none";
187199
}
188200

201+
if ($color === "currentcolor") {
202+
return "currentcolor";
203+
}
204+
189205
// SVG color name
190206
if (isset(self::$colorNames[$color])) {
191207
return self::parseHexColor(self::$colorNames[$color]);
@@ -198,18 +214,18 @@ static function parseColor($color)
198214

199215
// RGB color
200216
if (strpos($color, "rgb") !== false) {
201-
return self::getTriplet($color);
217+
return self::getQuad($color);
202218
}
203219

204220
// RGB color
205221
if (strpos($color, "hsl") !== false) {
206-
$triplet = self::getTriplet($color, true);
222+
$quad = self::getQuad($color, true);
207223

208-
if ($triplet == null) {
224+
if ($quad == null) {
209225
return null;
210226
}
211227

212-
list($h, $s, $l) = $triplet;
228+
list($h, $s, $l, $a) = $quad;
213229

214230
$r = $l;
215231
$g = $l;
@@ -258,11 +274,13 @@ static function parseColor($color)
258274
break;
259275
}
260276
}
277+
$a = $a * 255;
261278

262279
return array(
263280
$r * 255.0,
264281
$g * 255.0,
265282
$b * 255.0,
283+
$a
266284
);
267285
}
268286

@@ -282,7 +300,7 @@ static function parseColor($color)
282300
return null;
283301
}
284302

285-
static function getTriplet($color, $percent = false) {
303+
static function getQuad($color, $percent = false) {
286304
$i = strpos($color, "(");
287305
$j = strpos($color, ")");
288306

@@ -291,46 +309,60 @@ static function getTriplet($color, $percent = false) {
291309
return null;
292310
}
293311

294-
$triplet = preg_split("/\\s*,\\s*/", trim(substr($color, $i + 1, $j - $i - 1)));
312+
$quad = preg_split("/\\s*[,\\/]\\s*/", trim(substr($color, $i + 1, $j - $i - 1)));
313+
if (!isset($quad[3])) {
314+
$quad[3] = 1;
315+
}
295316

296-
if (count($triplet) != 3) {
317+
if (count($quad) != 3 && count($quad) != 4) {
297318
return null;
298319
}
299320

300-
foreach (array_keys($triplet) as $c) {
301-
$triplet[$c] = trim($triplet[$c]);
321+
foreach (array_keys($quad) as $c) {
322+
$quad[$c] = trim($quad[$c]);
302323

303324
if ($percent) {
304-
if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
305-
$triplet[$c] = floatval($triplet[$c]) / 100;
306-
}
307-
else {
308-
$triplet[$c] = $triplet[$c] / 255;
325+
if ($quad[$c][strlen($quad[$c]) - 1] === "%") {
326+
$quad[$c] = floatval($quad[$c]) / 100;
327+
} else {
328+
$quad[$c] = $quad[$c] / 255;
309329
}
310-
}
311-
else {
312-
if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") {
313-
$triplet[$c] = round(floatval($triplet[$c]) * 2.55);
330+
} else {
331+
if ($quad[$c][strlen($quad[$c]) - 1] === "%") {
332+
$quad[$c] = round(floatval($quad[$c]) * 2.55);
314333
}
315334
}
316335
}
317336

318-
return $triplet;
337+
return $quad;
319338
}
320339

321340
static function parseHexColor($hex)
322341
{
323-
$c = array(0, 0, 0);
342+
$c = array(0, 0, 0, 1);
324343

325344
// #FFFFFF
326345
if (isset($hex[6])) {
327346
$c[0] = hexdec(substr($hex, 1, 2));
328347
$c[1] = hexdec(substr($hex, 3, 2));
329348
$c[2] = hexdec(substr($hex, 5, 2));
349+
350+
if (isset($hex[7])) {
351+
$alpha = substr($hex, 7, 2);
352+
if (ctype_xdigit($alpha)) {
353+
$c[3] = round(hexdec($alpha)/255, 2);
354+
}
355+
}
330356
} else {
331357
$c[0] = hexdec($hex[1] . $hex[1]);
332358
$c[1] = hexdec($hex[2] . $hex[2]);
333359
$c[2] = hexdec($hex[3] . $hex[3]);
360+
361+
if (isset($hex[4])) {
362+
if (ctype_xdigit($hex[4])) {
363+
$c[3] = round(hexdec($hex[4] . $hex[4])/255, 2);
364+
}
365+
}
334366
}
335367

336368
return $c;

tests/Svg/StyleTest.php

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,26 @@ class StyleTest extends TestCase
1717
public function test_parseColor()
1818
{
1919
$this->assertEquals("none", Style::parseColor("none"));
20-
$this->assertEquals(array(255, 0, 0), Style::parseColor("RED"));
21-
$this->assertEquals(array(0, 0, 255), Style::parseColor("blue"));
20+
$this->assertEquals("currentcolor", Style::parseColor("currentcolor"));
21+
$this->assertEquals(array(255, 0, 0, 1), Style::parseColor("RED"));
22+
$this->assertEquals(array(0, 0, 255, 1), Style::parseColor("blue"));
23+
$this->assertEquals(array(0, 0, 0, 1), Style::parseColor("black"));
24+
$this->assertEquals(array(255, 255, 255, 1), Style::parseColor("white"));
25+
2226
$this->assertEquals(null, Style::parseColor("foo"));
23-
$this->assertEquals(array(0, 0, 0), Style::parseColor("black"));
24-
$this->assertEquals(array(255, 255, 255), Style::parseColor("white"));
25-
$this->assertEquals(array(0, 0, 0), Style::parseColor("#000000"));
26-
$this->assertEquals(array(255, 255, 255), Style::parseColor("#ffffff"));
27-
$this->assertEquals(array(0, 0, 0), Style::parseColor("rgb(0,0,0)"));
28-
$this->assertEquals(array(255, 255, 255), Style::parseColor("rgb(255,255,255)"));
29-
$this->assertEquals(array(0, 0, 0), Style::parseColor("rgb(0, 0, 0)"));
30-
$this->assertEquals(array(255, 255, 255), Style::parseColor("rgb(255, 255, 255)"));
27+
28+
$this->assertEquals(array(0, 0, 0, 1), Style::parseColor("#000000"));
29+
$this->assertEquals(array(255, 255, 255, 1), Style::parseColor("#ffffff"));
30+
$this->assertEquals(array(0, 0, 0, .5), Style::parseColor("#00000080"));
31+
32+
$this->assertEquals(array(0, 0, 0, 1), Style::parseColor("rgb(0,0,0)"));
33+
$this->assertEquals(array(255, 255, 255, 1), Style::parseColor("rgb(255,255,255)"));
34+
$this->assertEquals(array(0, 0, 0, 1), Style::parseColor("rgb(0, 0, 0)"));
35+
$this->assertEquals(array(255, 255, 255, 1), Style::parseColor("rgb(255, 255, 255)"));
36+
$this->assertEquals(array(255, 255, 255, .5), Style::parseColor("rgb(255, 255, 255, .5)"));
37+
38+
$this->assertEquals(array(255, 0, 0, 1), Style::parseColor("hsl(0, 100%, 50%)"));
39+
$this->assertEquals(array(255, 0, 0, .5), Style::parseColor("hsl(0, 100%, 50%, .5)"));
3140
}
3241

3342
public function test_fromAttributes()
@@ -42,8 +51,8 @@ public function test_fromAttributes()
4251

4352
$style->fromAttributes($attributes);
4453

45-
$this->assertEquals(array(0, 0, 255), $style->color);
46-
$this->assertEquals(array(255, 255, 255), $style->fill);
54+
$this->assertEquals(array(0, 0, 255, 1), $style->color);
55+
$this->assertEquals(array(255, 255, 255, 1), $style->fill);
4756
$this->assertEquals("none", $style->stroke);
4857
}
4958

0 commit comments

Comments
 (0)