1 |
|
2 |
|
3 | #include "color.h"
|
4 |
|
5 | #include <algorithm>
|
6 | #include <cmath>
|
7 | #include <cstdlib>
|
8 | #include <cstring>
|
9 | #include <limits>
|
10 | #include <map>
|
11 | #include <string>
|
12 |
|
13 |
|
14 | #if defined(_MSC_VER) && _MSC_VER < 1900
|
15 | #define snprintf _snprintf
|
16 | #endif
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | template <typename parsed_t>
|
23 | static bool
|
24 | parse_integer(const char** pStr, parsed_t *pParsed) {
|
25 | parsed_t& c = *pParsed;
|
26 | const char*& str = *pStr;
|
27 | int8_t sign=1;
|
28 |
|
29 | c = 0;
|
30 | if (*str == '-') {
|
31 | sign=-1;
|
32 | ++str;
|
33 | }
|
34 | else if (*str == '+')
|
35 | ++str;
|
36 |
|
37 | if (*str >= '0' && *str <= '9') {
|
38 | do {
|
39 | c *= 10;
|
40 | c += *str++ - '0';
|
41 | } while (*str >= '0' && *str <= '9');
|
42 | } else {
|
43 | return false;
|
44 | }
|
45 | if (sign<0)
|
46 | c=-c;
|
47 | return true;
|
48 | }
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 | template <typename parsed_t>
|
57 | static bool
|
58 | parse_css_number(const char** pStr, parsed_t *pParsed) {
|
59 | parsed_t &parsed = *pParsed;
|
60 | const char*& str = *pStr;
|
61 | const char* startStr = str;
|
62 | if (!str || !*str)
|
63 | return false;
|
64 | parsed_t integerPart = 0;
|
65 | parsed_t fractionPart = 0;
|
66 | int divisorForFraction = 1;
|
67 | int sign = 1;
|
68 | int exponent = 0;
|
69 | int digits = 0;
|
70 | bool inFraction = false;
|
71 |
|
72 | if (*str == '-') {
|
73 | ++str;
|
74 | sign = -1;
|
75 | }
|
76 | else if (*str == '+')
|
77 | ++str;
|
78 | while (*str != '\0') {
|
79 | if (*str >= '0' && *str <= '9') {
|
80 | if (digits>=std::numeric_limits<parsed_t>::digits10) {
|
81 | if (!inFraction)
|
82 | return false;
|
83 | }
|
84 | else {
|
85 | ++digits;
|
86 |
|
87 | if (inFraction) {
|
88 | fractionPart = fractionPart*10 + (*str - '0');
|
89 | divisorForFraction *= 10;
|
90 | }
|
91 | else {
|
92 | integerPart = integerPart*10 + (*str - '0');
|
93 | }
|
94 | }
|
95 | }
|
96 | else if (*str == '.') {
|
97 | if (inFraction)
|
98 | break;
|
99 | else
|
100 | inFraction = true;
|
101 | }
|
102 | else if (*str == 'e') {
|
103 | ++str;
|
104 | if (!parse_integer(&str, &exponent))
|
105 | return false;
|
106 | break;
|
107 | }
|
108 | else
|
109 | break;
|
110 | ++str;
|
111 | }
|
112 | if (str != startStr) {
|
113 | parsed = sign * (integerPart + fractionPart/divisorForFraction);
|
114 | for (;exponent>0;--exponent)
|
115 | parsed *= 10;
|
116 | for (;exponent<0;++exponent)
|
117 | parsed /= 10;
|
118 | return true;
|
119 | }
|
120 | return false;
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | template <typename T>
|
128 | static T
|
129 | clip(T value, T minValue, T maxValue) {
|
130 | if (value > maxValue)
|
131 | value = maxValue;
|
132 | if (value < minValue)
|
133 | value = minValue;
|
134 | return value;
|
135 | }
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 | template <typename T>
|
142 | static T
|
143 | wrap_float(T value, T limit) {
|
144 | return fmod(fmod(value, limit) + limit, limit);
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 | static bool
|
161 | parse_rgb_channel(const char** pStr, uint8_t *pChannel) {
|
162 | int channel;
|
163 | if (parse_integer(pStr, &channel)) {
|
164 | *pChannel = clip(channel, 0, 255);
|
165 | return true;
|
166 | }
|
167 | return false;
|
168 | }
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 | static bool
|
175 | parse_degrees(const char** pStr, float *pDegrees) {
|
176 | float degrees;
|
177 | if (parse_css_number(pStr, °rees)) {
|
178 | *pDegrees = wrap_float(degrees, 360.0f);
|
179 | return true;
|
180 | }
|
181 | return false;
|
182 | }
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | static bool
|
189 | parse_clipped_percentage(const char** pStr, float *pFraction) {
|
190 | float percentage;
|
191 | bool result = parse_css_number(pStr,&percentage);
|
192 | const char*& str = *pStr;
|
193 | if (result) {
|
194 | if (*str == '%') {
|
195 | ++str;
|
196 | *pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
|
197 | return result;
|
198 | }
|
199 | }
|
200 | return false;
|
201 | }
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 | #define WHITESPACE \
|
208 | while (' ' == *str) ++str;
|
209 |
|
210 | #define WHITESPACE_OR_COMMA \
|
211 | while (' ' == *str || ',' == *str) ++str;
|
212 |
|
213 | #define CHANNEL(NAME) \
|
214 | if (!parse_rgb_channel(&str, &NAME)) \
|
215 | return 0; \
|
216 |
|
217 | #define HUE(NAME) \
|
218 | if (!parse_degrees(&str, &NAME)) \
|
219 | return 0;
|
220 |
|
221 | #define SATURATION(NAME) \
|
222 | if (!parse_clipped_percentage(&str, &NAME)) \
|
223 | return 0;
|
224 |
|
225 | #define LIGHTNESS(NAME) SATURATION(NAME)
|
226 |
|
227 | #define ALPHA(NAME) \
|
228 | if (*str >= '1' && *str <= '9') { \
|
229 | NAME = 1; \
|
230 | } else { \
|
231 | if ('0' == *str) ++str; \
|
232 | if ('.' == *str) { \
|
233 | ++str; \
|
234 | float n = .1f; \
|
235 | while (*str >= '0' && *str <= '9') { \
|
236 | NAME += (*str++ - '0') * n; \
|
237 | n *= .1f; \
|
238 | } \
|
239 | } \
|
240 | } \
|
241 | do {} while (0)
|
242 |
|
243 |
|
244 |
|
245 |
|
246 | static const std::map<std::string, uint32_t> named_colors = {
|
247 | { "transparent", 0xFFFFFF00}
|
248 | , { "aliceblue", 0xF0F8FFFF }
|
249 | , { "antiquewhite", 0xFAEBD7FF }
|
250 | , { "aqua", 0x00FFFFFF }
|
251 | , { "aquamarine", 0x7FFFD4FF }
|
252 | , { "azure", 0xF0FFFFFF }
|
253 | , { "beige", 0xF5F5DCFF }
|
254 | , { "bisque", 0xFFE4C4FF }
|
255 | , { "black", 0x000000FF }
|
256 | , { "blanchedalmond", 0xFFEBCDFF }
|
257 | , { "blue", 0x0000FFFF }
|
258 | , { "blueviolet", 0x8A2BE2FF }
|
259 | , { "brown", 0xA52A2AFF }
|
260 | , { "burlywood", 0xDEB887FF }
|
261 | , { "cadetblue", 0x5F9EA0FF }
|
262 | , { "chartreuse", 0x7FFF00FF }
|
263 | , { "chocolate", 0xD2691EFF }
|
264 | , { "coral", 0xFF7F50FF }
|
265 | , { "cornflowerblue", 0x6495EDFF }
|
266 | , { "cornsilk", 0xFFF8DCFF }
|
267 | , { "crimson", 0xDC143CFF }
|
268 | , { "cyan", 0x00FFFFFF }
|
269 | , { "darkblue", 0x00008BFF }
|
270 | , { "darkcyan", 0x008B8BFF }
|
271 | , { "darkgoldenrod", 0xB8860BFF }
|
272 | , { "darkgray", 0xA9A9A9FF }
|
273 | , { "darkgreen", 0x006400FF }
|
274 | , { "darkgrey", 0xA9A9A9FF }
|
275 | , { "darkkhaki", 0xBDB76BFF }
|
276 | , { "darkmagenta", 0x8B008BFF }
|
277 | , { "darkolivegreen", 0x556B2FFF }
|
278 | , { "darkorange", 0xFF8C00FF }
|
279 | , { "darkorchid", 0x9932CCFF }
|
280 | , { "darkred", 0x8B0000FF }
|
281 | , { "darksalmon", 0xE9967AFF }
|
282 | , { "darkseagreen", 0x8FBC8FFF }
|
283 | , { "darkslateblue", 0x483D8BFF }
|
284 | , { "darkslategray", 0x2F4F4FFF }
|
285 | , { "darkslategrey", 0x2F4F4FFF }
|
286 | , { "darkturquoise", 0x00CED1FF }
|
287 | , { "darkviolet", 0x9400D3FF }
|
288 | , { "deeppink", 0xFF1493FF }
|
289 | , { "deepskyblue", 0x00BFFFFF }
|
290 | , { "dimgray", 0x696969FF }
|
291 | , { "dimgrey", 0x696969FF }
|
292 | , { "dodgerblue", 0x1E90FFFF }
|
293 | , { "firebrick", 0xB22222FF }
|
294 | , { "floralwhite", 0xFFFAF0FF }
|
295 | , { "forestgreen", 0x228B22FF }
|
296 | , { "fuchsia", 0xFF00FFFF }
|
297 | , { "gainsboro", 0xDCDCDCFF }
|
298 | , { "ghostwhite", 0xF8F8FFFF }
|
299 | , { "gold", 0xFFD700FF }
|
300 | , { "goldenrod", 0xDAA520FF }
|
301 | , { "gray", 0x808080FF }
|
302 | , { "green", 0x008000FF }
|
303 | , { "greenyellow", 0xADFF2FFF }
|
304 | , { "grey", 0x808080FF }
|
305 | , { "honeydew", 0xF0FFF0FF }
|
306 | , { "hotpink", 0xFF69B4FF }
|
307 | , { "indianred", 0xCD5C5CFF }
|
308 | , { "indigo", 0x4B0082FF }
|
309 | , { "ivory", 0xFFFFF0FF }
|
310 | , { "khaki", 0xF0E68CFF }
|
311 | , { "lavender", 0xE6E6FAFF }
|
312 | , { "lavenderblush", 0xFFF0F5FF }
|
313 | , { "lawngreen", 0x7CFC00FF }
|
314 | , { "lemonchiffon", 0xFFFACDFF }
|
315 | , { "lightblue", 0xADD8E6FF }
|
316 | , { "lightcoral", 0xF08080FF }
|
317 | , { "lightcyan", 0xE0FFFFFF }
|
318 | , { "lightgoldenrodyellow", 0xFAFAD2FF }
|
319 | , { "lightgray", 0xD3D3D3FF }
|
320 | , { "lightgreen", 0x90EE90FF }
|
321 | , { "lightgrey", 0xD3D3D3FF }
|
322 | , { "lightpink", 0xFFB6C1FF }
|
323 | , { "lightsalmon", 0xFFA07AFF }
|
324 | , { "lightseagreen", 0x20B2AAFF }
|
325 | , { "lightskyblue", 0x87CEFAFF }
|
326 | , { "lightslategray", 0x778899FF }
|
327 | , { "lightslategrey", 0x778899FF }
|
328 | , { "lightsteelblue", 0xB0C4DEFF }
|
329 | , { "lightyellow", 0xFFFFE0FF }
|
330 | , { "lime", 0x00FF00FF }
|
331 | , { "limegreen", 0x32CD32FF }
|
332 | , { "linen", 0xFAF0E6FF }
|
333 | , { "magenta", 0xFF00FFFF }
|
334 | , { "maroon", 0x800000FF }
|
335 | , { "mediumaquamarine", 0x66CDAAFF }
|
336 | , { "mediumblue", 0x0000CDFF }
|
337 | , { "mediumorchid", 0xBA55D3FF }
|
338 | , { "mediumpurple", 0x9370DBFF }
|
339 | , { "mediumseagreen", 0x3CB371FF }
|
340 | , { "mediumslateblue", 0x7B68EEFF }
|
341 | , { "mediumspringgreen", 0x00FA9AFF }
|
342 | , { "mediumturquoise", 0x48D1CCFF }
|
343 | , { "mediumvioletred", 0xC71585FF }
|
344 | , { "midnightblue", 0x191970FF }
|
345 | , { "mintcream", 0xF5FFFAFF }
|
346 | , { "mistyrose", 0xFFE4E1FF }
|
347 | , { "moccasin", 0xFFE4B5FF }
|
348 | , { "navajowhite", 0xFFDEADFF }
|
349 | , { "navy", 0x000080FF }
|
350 | , { "oldlace", 0xFDF5E6FF }
|
351 | , { "olive", 0x808000FF }
|
352 | , { "olivedrab", 0x6B8E23FF }
|
353 | , { "orange", 0xFFA500FF }
|
354 | , { "orangered", 0xFF4500FF }
|
355 | , { "orchid", 0xDA70D6FF }
|
356 | , { "palegoldenrod", 0xEEE8AAFF }
|
357 | , { "palegreen", 0x98FB98FF }
|
358 | , { "paleturquoise", 0xAFEEEEFF }
|
359 | , { "palevioletred", 0xDB7093FF }
|
360 | , { "papayawhip", 0xFFEFD5FF }
|
361 | , { "peachpuff", 0xFFDAB9FF }
|
362 | , { "peru", 0xCD853FFF }
|
363 | , { "pink", 0xFFC0CBFF }
|
364 | , { "plum", 0xDDA0DDFF }
|
365 | , { "powderblue", 0xB0E0E6FF }
|
366 | , { "purple", 0x800080FF }
|
367 | , { "rebeccapurple", 0x663399FF }
|
368 | , { "red", 0xFF0000FF }
|
369 | , { "rosybrown", 0xBC8F8FFF }
|
370 | , { "royalblue", 0x4169E1FF }
|
371 | , { "saddlebrown", 0x8B4513FF }
|
372 | , { "salmon", 0xFA8072FF }
|
373 | , { "sandybrown", 0xF4A460FF }
|
374 | , { "seagreen", 0x2E8B57FF }
|
375 | , { "seashell", 0xFFF5EEFF }
|
376 | , { "sienna", 0xA0522DFF }
|
377 | , { "silver", 0xC0C0C0FF }
|
378 | , { "skyblue", 0x87CEEBFF }
|
379 | , { "slateblue", 0x6A5ACDFF }
|
380 | , { "slategray", 0x708090FF }
|
381 | , { "slategrey", 0x708090FF }
|
382 | , { "snow", 0xFFFAFAFF }
|
383 | , { "springgreen", 0x00FF7FFF }
|
384 | , { "steelblue", 0x4682B4FF }
|
385 | , { "tan", 0xD2B48CFF }
|
386 | , { "teal", 0x008080FF }
|
387 | , { "thistle", 0xD8BFD8FF }
|
388 | , { "tomato", 0xFF6347FF }
|
389 | , { "turquoise", 0x40E0D0FF }
|
390 | , { "violet", 0xEE82EEFF }
|
391 | , { "wheat", 0xF5DEB3FF }
|
392 | , { "white", 0xFFFFFFFF }
|
393 | , { "whitesmoke", 0xF5F5F5FF }
|
394 | , { "yellow", 0xFFFF00FF }
|
395 | , { "yellowgreen", 0x9ACD32FF }
|
396 | };
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 | static int
|
403 | h(char c) {
|
404 | switch (c) {
|
405 | case '0':
|
406 | case '1':
|
407 | case '2':
|
408 | case '3':
|
409 | case '4':
|
410 | case '5':
|
411 | case '6':
|
412 | case '7':
|
413 | case '8':
|
414 | case '9':
|
415 | return c - '0';
|
416 | case 'a':
|
417 | case 'b':
|
418 | case 'c':
|
419 | case 'd':
|
420 | case 'e':
|
421 | case 'f':
|
422 | return (c - 'a') + 10;
|
423 | case 'A':
|
424 | case 'B':
|
425 | case 'C':
|
426 | case 'D':
|
427 | case 'E':
|
428 | case 'F':
|
429 | return (c - 'A') + 10;
|
430 | }
|
431 | return 0;
|
432 | }
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 | rgba_t
|
439 | rgba_create(uint32_t rgba) {
|
440 | rgba_t color;
|
441 | color.r = (double) (rgba >> 24) / 255;
|
442 | color.g = (double) (rgba >> 16 & 0xff) / 255;
|
443 | color.b = (double) (rgba >> 8 & 0xff) / 255;
|
444 | color.a = (double) (rgba & 0xff) / 255;
|
445 | return color;
|
446 | }
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 | void
|
453 | rgba_to_string(rgba_t rgba, char *buf, size_t len) {
|
454 | if (1 == rgba.a) {
|
455 | snprintf(buf, len, "#%.2x%.2x%.2x",
|
456 | static_cast<int>(round(rgba.r * 255)),
|
457 | static_cast<int>(round(rgba.g * 255)),
|
458 | static_cast<int>(round(rgba.b * 255)));
|
459 | } else {
|
460 | snprintf(buf, len, "rgba(%d, %d, %d, %.2f)",
|
461 | static_cast<int>(round(rgba.r * 255)),
|
462 | static_cast<int>(round(rgba.g * 255)),
|
463 | static_cast<int>(round(rgba.b * 255)),
|
464 | rgba.a);
|
465 | }
|
466 | }
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 | static inline int32_t
|
473 | rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
474 | return
|
475 | r << 24
|
476 | | g << 16
|
477 | | b << 8
|
478 | | a;
|
479 | }
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 | static float
|
487 | hue_to_rgb(float t1, float t2, float hue) {
|
488 | if (hue < 0)
|
489 | hue += 6;
|
490 | if (hue >= 6)
|
491 | hue -= 6;
|
492 |
|
493 | if (hue < 1)
|
494 | return (t2 - t1) * hue + t1;
|
495 | else if (hue < 3)
|
496 | return t2;
|
497 | else if (hue < 4)
|
498 | return (t2 - t1) * (4 - hue) + t1;
|
499 | else
|
500 | return t1;
|
501 | }
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 | static inline int32_t
|
510 | rgba_from_hsla(float h_deg, float s, float l, float a) {
|
511 | uint8_t r, g, b;
|
512 | float h = (6 * h_deg) / 360.0f, m1, m2;
|
513 |
|
514 | if (l<=0.5)
|
515 | m2=l*(s+1);
|
516 | else
|
517 | m2=l+s-l*s;
|
518 | m1 = l*2 - m2;
|
519 |
|
520 |
|
521 | r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5);
|
522 | g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5);
|
523 | b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5);
|
524 |
|
525 | return rgba_from_rgba(r, g, b, (uint8_t) (a * 255));
|
526 | }
|
527 |
|
528 |
|
529 |
|
530 |
|
531 |
|
532 |
|
533 | static inline int32_t
|
534 | rgba_from_hsl(float h_deg, float s, float l) {
|
535 | return rgba_from_hsla(h_deg, s, l, 1.0);
|
536 | }
|
537 |
|
538 |
|
539 |
|
540 |
|
541 |
|
542 |
|
543 | static int32_t
|
544 | rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
545 | return rgba_from_rgba(r, g, b, 255);
|
546 | }
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 | static int32_t
|
553 | rgba_from_hex8_string(const char *str) {
|
554 | return rgba_from_rgba(
|
555 | (h(str[0]) << 4) + h(str[1]),
|
556 | (h(str[2]) << 4) + h(str[3]),
|
557 | (h(str[4]) << 4) + h(str[5]),
|
558 | (h(str[6]) << 4) + h(str[7])
|
559 | );
|
560 | }
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 | static int32_t
|
567 | rgba_from_hex6_string(const char *str) {
|
568 | return rgba_from_rgb(
|
569 | (h(str[0]) << 4) + h(str[1])
|
570 | , (h(str[2]) << 4) + h(str[3])
|
571 | , (h(str[4]) << 4) + h(str[5])
|
572 | );
|
573 | }
|
574 |
|
575 |
|
576 |
|
577 |
|
578 |
|
579 | static int32_t
|
580 | rgba_from_hex4_string(const char *str) {
|
581 | return rgba_from_rgba(
|
582 | (h(str[0]) << 4) + h(str[0]),
|
583 | (h(str[1]) << 4) + h(str[1]),
|
584 | (h(str[2]) << 4) + h(str[2]),
|
585 | (h(str[3]) << 4) + h(str[3])
|
586 | );
|
587 | }
|
588 |
|
589 |
|
590 |
|
591 |
|
592 |
|
593 | static int32_t
|
594 | rgba_from_hex3_string(const char *str) {
|
595 | return rgba_from_rgb(
|
596 | (h(str[0]) << 4) + h(str[0])
|
597 | , (h(str[1]) << 4) + h(str[1])
|
598 | , (h(str[2]) << 4) + h(str[2])
|
599 | );
|
600 | }
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 | static int32_t
|
607 | rgba_from_rgb_string(const char *str, short *ok) {
|
608 | if (str == strstr(str, "rgb(")) {
|
609 | str += 4;
|
610 | WHITESPACE;
|
611 | uint8_t r = 0, g = 0, b = 0;
|
612 | CHANNEL(r);
|
613 | WHITESPACE_OR_COMMA;
|
614 | CHANNEL(g);
|
615 | WHITESPACE_OR_COMMA;
|
616 | CHANNEL(b);
|
617 | WHITESPACE;
|
618 | return *ok = 1, rgba_from_rgb(r, g, b);
|
619 | }
|
620 | return *ok = 0;
|
621 | }
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 | static int32_t
|
628 | rgba_from_rgba_string(const char *str, short *ok) {
|
629 | if (str == strstr(str, "rgba(")) {
|
630 | str += 5;
|
631 | WHITESPACE;
|
632 | uint8_t r = 0, g = 0, b = 0;
|
633 | float a = 0;
|
634 | CHANNEL(r);
|
635 | WHITESPACE_OR_COMMA;
|
636 | CHANNEL(g);
|
637 | WHITESPACE_OR_COMMA;
|
638 | CHANNEL(b);
|
639 | WHITESPACE_OR_COMMA;
|
640 | ALPHA(a);
|
641 | WHITESPACE;
|
642 | return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255));
|
643 | }
|
644 | return *ok = 0;
|
645 | }
|
646 |
|
647 |
|
648 |
|
649 |
|
650 |
|
651 | static int32_t
|
652 | rgba_from_hsla_string(const char *str, short *ok) {
|
653 | if (str == strstr(str, "hsla(")) {
|
654 | str += 5;
|
655 | WHITESPACE;
|
656 | float h_deg = 0;
|
657 | float s = 0, l = 0;
|
658 | float a = 0;
|
659 | HUE(h_deg);
|
660 | WHITESPACE_OR_COMMA;
|
661 | SATURATION(s);
|
662 | WHITESPACE_OR_COMMA;
|
663 | LIGHTNESS(l);
|
664 | WHITESPACE_OR_COMMA;
|
665 | ALPHA(a);
|
666 | WHITESPACE;
|
667 | return *ok = 1, rgba_from_hsla(h_deg, s, l, a);
|
668 | }
|
669 | return *ok = 0;
|
670 | }
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 | static int32_t
|
677 | rgba_from_hsl_string(const char *str, short *ok) {
|
678 | if (str == strstr(str, "hsl(")) {
|
679 | str += 4;
|
680 | WHITESPACE;
|
681 | float h_deg = 0;
|
682 | float s = 0, l = 0;
|
683 | HUE(h_deg);
|
684 | WHITESPACE_OR_COMMA;
|
685 | SATURATION(s);
|
686 | WHITESPACE_OR_COMMA;
|
687 | LIGHTNESS(l);
|
688 | WHITESPACE;
|
689 | return *ok = 1, rgba_from_hsl(h_deg, s, l);
|
690 | }
|
691 | return *ok = 0;
|
692 | }
|
693 |
|
694 |
|
695 |
|
696 |
|
697 |
|
698 |
|
699 |
|
700 |
|
701 |
|
702 |
|
703 |
|
704 |
|
705 | static int32_t
|
706 | rgba_from_hex_string(const char *str, short *ok) {
|
707 | size_t len = strlen(str);
|
708 | *ok = 1;
|
709 | switch (len) {
|
710 | case 8: return rgba_from_hex8_string(str);
|
711 | case 6: return rgba_from_hex6_string(str);
|
712 | case 4: return rgba_from_hex4_string(str);
|
713 | case 3: return rgba_from_hex3_string(str);
|
714 | }
|
715 | return *ok = 0;
|
716 | }
|
717 |
|
718 |
|
719 |
|
720 |
|
721 |
|
722 | static int32_t
|
723 | rgba_from_name_string(const char *str, short *ok) {
|
724 | std::string lowered(str);
|
725 | std::transform(lowered.begin(), lowered.end(), lowered.begin(), tolower);
|
726 | auto color = named_colors.find(lowered);
|
727 | if (color != named_colors.end()) {
|
728 | return *ok = 1, color->second;
|
729 | }
|
730 | return *ok = 0;
|
731 | }
|
732 |
|
733 |
|
734 |
|
735 |
|
736 |
|
737 |
|
738 |
|
739 |
|
740 |
|
741 |
|
742 |
|
743 |
|
744 |
|
745 |
|
746 |
|
747 |
|
748 | int32_t
|
749 | rgba_from_string(const char *str, short *ok) {
|
750 | if ('#' == str[0])
|
751 | return rgba_from_hex_string(++str, ok);
|
752 | if (str == strstr(str, "rgba"))
|
753 | return rgba_from_rgba_string(str, ok);
|
754 | if (str == strstr(str, "rgb"))
|
755 | return rgba_from_rgb_string(str, ok);
|
756 | if (str == strstr(str, "hsla"))
|
757 | return rgba_from_hsla_string(str, ok);
|
758 | if (str == strstr(str, "hsl"))
|
759 | return rgba_from_hsl_string(str, ok);
|
760 | return rgba_from_name_string(str, ok);
|
761 | }
|
762 |
|
763 |
|
764 |
|
765 |
|
766 |
|
767 | void
|
768 | rgba_inspect(int32_t rgba) {
|
769 | printf("rgba(%d,%d,%d,%d)\n"
|
770 | , rgba >> 24 & 0xff
|
771 | , rgba >> 16 & 0xff
|
772 | , rgba >> 8 & 0xff
|
773 | , rgba & 0xff
|
774 | );
|
775 | }
|