@shqld/canvas 2.11.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/Readme.md +600 -0
  2. package/binding.gyp +230 -0
  3. package/browser.js +35 -0
  4. package/index.js +94 -0
  5. package/lib/DOMMatrix.js +620 -0
  6. package/lib/bindings.js +80 -0
  7. package/lib/canvas.js +113 -0
  8. package/lib/context2d.js +14 -0
  9. package/lib/image.js +96 -0
  10. package/lib/jpegstream.js +41 -0
  11. package/lib/parse-font.js +101 -0
  12. package/lib/pattern.js +17 -0
  13. package/lib/pdfstream.js +35 -0
  14. package/lib/pngstream.js +42 -0
  15. package/package.json +71 -0
  16. package/scripts/install.js +24 -0
  17. package/src/Backends.cc +18 -0
  18. package/src/Backends.h +10 -0
  19. package/src/Canvas.cc +965 -0
  20. package/src/Canvas.h +96 -0
  21. package/src/CanvasError.h +23 -0
  22. package/src/CanvasGradient.cc +123 -0
  23. package/src/CanvasGradient.h +22 -0
  24. package/src/CanvasPattern.cc +136 -0
  25. package/src/CanvasPattern.h +37 -0
  26. package/src/CanvasRenderingContext2d.cc +3360 -0
  27. package/src/CanvasRenderingContext2d.h +225 -0
  28. package/src/Image.cc +1434 -0
  29. package/src/Image.h +127 -0
  30. package/src/ImageData.cc +146 -0
  31. package/src/ImageData.h +27 -0
  32. package/src/JPEGStream.h +167 -0
  33. package/src/PNG.h +292 -0
  34. package/src/Point.h +11 -0
  35. package/src/Util.h +9 -0
  36. package/src/backend/Backend.cc +112 -0
  37. package/src/backend/Backend.h +69 -0
  38. package/src/backend/ImageBackend.cc +74 -0
  39. package/src/backend/ImageBackend.h +26 -0
  40. package/src/backend/PdfBackend.cc +53 -0
  41. package/src/backend/PdfBackend.h +24 -0
  42. package/src/backend/SvgBackend.cc +61 -0
  43. package/src/backend/SvgBackend.h +24 -0
  44. package/src/bmp/BMPParser.cc +457 -0
  45. package/src/bmp/BMPParser.h +60 -0
  46. package/src/bmp/LICENSE.md +24 -0
  47. package/src/closure.cc +26 -0
  48. package/src/closure.h +81 -0
  49. package/src/color.cc +779 -0
  50. package/src/color.h +30 -0
  51. package/src/dll_visibility.h +20 -0
  52. package/src/init.cc +94 -0
  53. package/src/register_font.cc +408 -0
  54. package/src/register_font.h +7 -0
  55. package/types/index.d.ts +484 -0
  56. package/util/has_lib.js +119 -0
  57. package/util/win_jpeg_lookup.js +21 -0
package/src/color.cc ADDED
@@ -0,0 +1,779 @@
1
+ // Copyright (c) 2010 LearnBoost <tj@learnboost.com>
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
+ // Compatibility with Visual Studio versions prior to VS2015
14
+ #if defined(_MSC_VER) && _MSC_VER < 1900
15
+ #define snprintf _snprintf
16
+ #endif
17
+
18
+ /*
19
+ * Parse integer value
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
+ * Parse CSS <number> value
53
+ * Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html
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
+ * Clip value to the range [minValue, maxValue]
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
+ * Wrap value to the range [0, limit]
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
+ * Wrap value to the range [0, limit] - currently-unused integer version of wrap_float
149
+ */
150
+
151
+ // template <typename T>
152
+ // static T wrap_int(T value, T limit) {
153
+ // return (value % limit + limit) % limit;
154
+ // }
155
+
156
+ /*
157
+ * Parse color channel value
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
+ * Parse a value in degrees
172
+ */
173
+
174
+ static bool
175
+ parse_degrees(const char** pStr, float *pDegrees) {
176
+ float degrees;
177
+ if (parse_css_number(pStr, &degrees)) {
178
+ *pDegrees = wrap_float(degrees, 360.0f);
179
+ return true;
180
+ }
181
+ return false;
182
+ }
183
+
184
+ /*
185
+ * Parse and clip a percentage value. Returns a float in the range [0, 1].
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
+ * Macros to help with parsing inside rgba_from_*_string
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) { \
232
+ NAME = 0; \
233
+ ++str; \
234
+ } \
235
+ if ('.' == *str) { \
236
+ ++str; \
237
+ NAME = 0; \
238
+ float n = .1f; \
239
+ while (*str >= '0' && *str <= '9') { \
240
+ NAME += (*str++ - '0') * n; \
241
+ n *= .1f; \
242
+ } \
243
+ } \
244
+ } \
245
+ do {} while (0) // require trailing semicolon
246
+
247
+ /*
248
+ * Named colors.
249
+ */
250
+ static const std::map<std::string, uint32_t> named_colors = {
251
+ { "transparent", 0xFFFFFF00}
252
+ , { "aliceblue", 0xF0F8FFFF }
253
+ , { "antiquewhite", 0xFAEBD7FF }
254
+ , { "aqua", 0x00FFFFFF }
255
+ , { "aquamarine", 0x7FFFD4FF }
256
+ , { "azure", 0xF0FFFFFF }
257
+ , { "beige", 0xF5F5DCFF }
258
+ , { "bisque", 0xFFE4C4FF }
259
+ , { "black", 0x000000FF }
260
+ , { "blanchedalmond", 0xFFEBCDFF }
261
+ , { "blue", 0x0000FFFF }
262
+ , { "blueviolet", 0x8A2BE2FF }
263
+ , { "brown", 0xA52A2AFF }
264
+ , { "burlywood", 0xDEB887FF }
265
+ , { "cadetblue", 0x5F9EA0FF }
266
+ , { "chartreuse", 0x7FFF00FF }
267
+ , { "chocolate", 0xD2691EFF }
268
+ , { "coral", 0xFF7F50FF }
269
+ , { "cornflowerblue", 0x6495EDFF }
270
+ , { "cornsilk", 0xFFF8DCFF }
271
+ , { "crimson", 0xDC143CFF }
272
+ , { "cyan", 0x00FFFFFF }
273
+ , { "darkblue", 0x00008BFF }
274
+ , { "darkcyan", 0x008B8BFF }
275
+ , { "darkgoldenrod", 0xB8860BFF }
276
+ , { "darkgray", 0xA9A9A9FF }
277
+ , { "darkgreen", 0x006400FF }
278
+ , { "darkgrey", 0xA9A9A9FF }
279
+ , { "darkkhaki", 0xBDB76BFF }
280
+ , { "darkmagenta", 0x8B008BFF }
281
+ , { "darkolivegreen", 0x556B2FFF }
282
+ , { "darkorange", 0xFF8C00FF }
283
+ , { "darkorchid", 0x9932CCFF }
284
+ , { "darkred", 0x8B0000FF }
285
+ , { "darksalmon", 0xE9967AFF }
286
+ , { "darkseagreen", 0x8FBC8FFF }
287
+ , { "darkslateblue", 0x483D8BFF }
288
+ , { "darkslategray", 0x2F4F4FFF }
289
+ , { "darkslategrey", 0x2F4F4FFF }
290
+ , { "darkturquoise", 0x00CED1FF }
291
+ , { "darkviolet", 0x9400D3FF }
292
+ , { "deeppink", 0xFF1493FF }
293
+ , { "deepskyblue", 0x00BFFFFF }
294
+ , { "dimgray", 0x696969FF }
295
+ , { "dimgrey", 0x696969FF }
296
+ , { "dodgerblue", 0x1E90FFFF }
297
+ , { "firebrick", 0xB22222FF }
298
+ , { "floralwhite", 0xFFFAF0FF }
299
+ , { "forestgreen", 0x228B22FF }
300
+ , { "fuchsia", 0xFF00FFFF }
301
+ , { "gainsboro", 0xDCDCDCFF }
302
+ , { "ghostwhite", 0xF8F8FFFF }
303
+ , { "gold", 0xFFD700FF }
304
+ , { "goldenrod", 0xDAA520FF }
305
+ , { "gray", 0x808080FF }
306
+ , { "green", 0x008000FF }
307
+ , { "greenyellow", 0xADFF2FFF }
308
+ , { "grey", 0x808080FF }
309
+ , { "honeydew", 0xF0FFF0FF }
310
+ , { "hotpink", 0xFF69B4FF }
311
+ , { "indianred", 0xCD5C5CFF }
312
+ , { "indigo", 0x4B0082FF }
313
+ , { "ivory", 0xFFFFF0FF }
314
+ , { "khaki", 0xF0E68CFF }
315
+ , { "lavender", 0xE6E6FAFF }
316
+ , { "lavenderblush", 0xFFF0F5FF }
317
+ , { "lawngreen", 0x7CFC00FF }
318
+ , { "lemonchiffon", 0xFFFACDFF }
319
+ , { "lightblue", 0xADD8E6FF }
320
+ , { "lightcoral", 0xF08080FF }
321
+ , { "lightcyan", 0xE0FFFFFF }
322
+ , { "lightgoldenrodyellow", 0xFAFAD2FF }
323
+ , { "lightgray", 0xD3D3D3FF }
324
+ , { "lightgreen", 0x90EE90FF }
325
+ , { "lightgrey", 0xD3D3D3FF }
326
+ , { "lightpink", 0xFFB6C1FF }
327
+ , { "lightsalmon", 0xFFA07AFF }
328
+ , { "lightseagreen", 0x20B2AAFF }
329
+ , { "lightskyblue", 0x87CEFAFF }
330
+ , { "lightslategray", 0x778899FF }
331
+ , { "lightslategrey", 0x778899FF }
332
+ , { "lightsteelblue", 0xB0C4DEFF }
333
+ , { "lightyellow", 0xFFFFE0FF }
334
+ , { "lime", 0x00FF00FF }
335
+ , { "limegreen", 0x32CD32FF }
336
+ , { "linen", 0xFAF0E6FF }
337
+ , { "magenta", 0xFF00FFFF }
338
+ , { "maroon", 0x800000FF }
339
+ , { "mediumaquamarine", 0x66CDAAFF }
340
+ , { "mediumblue", 0x0000CDFF }
341
+ , { "mediumorchid", 0xBA55D3FF }
342
+ , { "mediumpurple", 0x9370DBFF }
343
+ , { "mediumseagreen", 0x3CB371FF }
344
+ , { "mediumslateblue", 0x7B68EEFF }
345
+ , { "mediumspringgreen", 0x00FA9AFF }
346
+ , { "mediumturquoise", 0x48D1CCFF }
347
+ , { "mediumvioletred", 0xC71585FF }
348
+ , { "midnightblue", 0x191970FF }
349
+ , { "mintcream", 0xF5FFFAFF }
350
+ , { "mistyrose", 0xFFE4E1FF }
351
+ , { "moccasin", 0xFFE4B5FF }
352
+ , { "navajowhite", 0xFFDEADFF }
353
+ , { "navy", 0x000080FF }
354
+ , { "oldlace", 0xFDF5E6FF }
355
+ , { "olive", 0x808000FF }
356
+ , { "olivedrab", 0x6B8E23FF }
357
+ , { "orange", 0xFFA500FF }
358
+ , { "orangered", 0xFF4500FF }
359
+ , { "orchid", 0xDA70D6FF }
360
+ , { "palegoldenrod", 0xEEE8AAFF }
361
+ , { "palegreen", 0x98FB98FF }
362
+ , { "paleturquoise", 0xAFEEEEFF }
363
+ , { "palevioletred", 0xDB7093FF }
364
+ , { "papayawhip", 0xFFEFD5FF }
365
+ , { "peachpuff", 0xFFDAB9FF }
366
+ , { "peru", 0xCD853FFF }
367
+ , { "pink", 0xFFC0CBFF }
368
+ , { "plum", 0xDDA0DDFF }
369
+ , { "powderblue", 0xB0E0E6FF }
370
+ , { "purple", 0x800080FF }
371
+ , { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft
372
+ , { "red", 0xFF0000FF }
373
+ , { "rosybrown", 0xBC8F8FFF }
374
+ , { "royalblue", 0x4169E1FF }
375
+ , { "saddlebrown", 0x8B4513FF }
376
+ , { "salmon", 0xFA8072FF }
377
+ , { "sandybrown", 0xF4A460FF }
378
+ , { "seagreen", 0x2E8B57FF }
379
+ , { "seashell", 0xFFF5EEFF }
380
+ , { "sienna", 0xA0522DFF }
381
+ , { "silver", 0xC0C0C0FF }
382
+ , { "skyblue", 0x87CEEBFF }
383
+ , { "slateblue", 0x6A5ACDFF }
384
+ , { "slategray", 0x708090FF }
385
+ , { "slategrey", 0x708090FF }
386
+ , { "snow", 0xFFFAFAFF }
387
+ , { "springgreen", 0x00FF7FFF }
388
+ , { "steelblue", 0x4682B4FF }
389
+ , { "tan", 0xD2B48CFF }
390
+ , { "teal", 0x008080FF }
391
+ , { "thistle", 0xD8BFD8FF }
392
+ , { "tomato", 0xFF6347FF }
393
+ , { "turquoise", 0x40E0D0FF }
394
+ , { "violet", 0xEE82EEFF }
395
+ , { "wheat", 0xF5DEB3FF }
396
+ , { "white", 0xFFFFFFFF }
397
+ , { "whitesmoke", 0xF5F5F5FF }
398
+ , { "yellow", 0xFFFF00FF }
399
+ , { "yellowgreen", 0x9ACD32FF }
400
+ };
401
+
402
+ /*
403
+ * Hex digit int val.
404
+ */
405
+
406
+ static int
407
+ h(char c) {
408
+ switch (c) {
409
+ case '0':
410
+ case '1':
411
+ case '2':
412
+ case '3':
413
+ case '4':
414
+ case '5':
415
+ case '6':
416
+ case '7':
417
+ case '8':
418
+ case '9':
419
+ return c - '0';
420
+ case 'a':
421
+ case 'b':
422
+ case 'c':
423
+ case 'd':
424
+ case 'e':
425
+ case 'f':
426
+ return (c - 'a') + 10;
427
+ case 'A':
428
+ case 'B':
429
+ case 'C':
430
+ case 'D':
431
+ case 'E':
432
+ case 'F':
433
+ return (c - 'A') + 10;
434
+ }
435
+ return 0;
436
+ }
437
+
438
+ /*
439
+ * Return rgba_t from rgba.
440
+ */
441
+
442
+ rgba_t
443
+ rgba_create(uint32_t rgba) {
444
+ rgba_t color;
445
+ color.r = (double) (rgba >> 24) / 255;
446
+ color.g = (double) (rgba >> 16 & 0xff) / 255;
447
+ color.b = (double) (rgba >> 8 & 0xff) / 255;
448
+ color.a = (double) (rgba & 0xff) / 255;
449
+ return color;
450
+ }
451
+
452
+ /*
453
+ * Return a string representation of the color.
454
+ */
455
+
456
+ void
457
+ rgba_to_string(rgba_t rgba, char *buf, size_t len) {
458
+ if (1 == rgba.a) {
459
+ snprintf(buf, len, "#%.2x%.2x%.2x",
460
+ static_cast<int>(round(rgba.r * 255)),
461
+ static_cast<int>(round(rgba.g * 255)),
462
+ static_cast<int>(round(rgba.b * 255)));
463
+ } else {
464
+ snprintf(buf, len, "rgba(%d, %d, %d, %.2f)",
465
+ static_cast<int>(round(rgba.r * 255)),
466
+ static_cast<int>(round(rgba.g * 255)),
467
+ static_cast<int>(round(rgba.b * 255)),
468
+ rgba.a);
469
+ }
470
+ }
471
+
472
+ /*
473
+ * Return rgba from (r,g,b,a).
474
+ */
475
+
476
+ static inline int32_t
477
+ rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
478
+ return
479
+ r << 24
480
+ | g << 16
481
+ | b << 8
482
+ | a;
483
+ }
484
+
485
+ /*
486
+ * Helper function used in rgba_from_hsla().
487
+ * Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
488
+ */
489
+
490
+ static float
491
+ hue_to_rgb(float t1, float t2, float hue) {
492
+ if (hue < 0)
493
+ hue += 6;
494
+ if (hue >= 6)
495
+ hue -= 6;
496
+
497
+ if (hue < 1)
498
+ return (t2 - t1) * hue + t1;
499
+ else if (hue < 3)
500
+ return t2;
501
+ else if (hue < 4)
502
+ return (t2 - t1) * (4 - hue) + t1;
503
+ else
504
+ return t1;
505
+ }
506
+
507
+ /*
508
+ * Return rgba from (h,s,l,a).
509
+ * Expects h values in the range [0, 360), and s, l, a in the range [0, 1].
510
+ * Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
511
+ */
512
+
513
+ static inline int32_t
514
+ rgba_from_hsla(float h_deg, float s, float l, float a) {
515
+ uint8_t r, g, b;
516
+ float h = (6 * h_deg) / 360.0f, m1, m2;
517
+
518
+ if (l<=0.5)
519
+ m2=l*(s+1);
520
+ else
521
+ m2=l+s-l*s;
522
+ m1 = l*2 - m2;
523
+
524
+ // Scale and round the RGB components
525
+ r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5);
526
+ g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5);
527
+ b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5);
528
+
529
+ return rgba_from_rgba(r, g, b, (uint8_t) (a * 255));
530
+ }
531
+
532
+ /*
533
+ * Return rgba from (h,s,l).
534
+ * Expects h values in the range [0, 360), and s, l in the range [0, 1].
535
+ */
536
+
537
+ static inline int32_t
538
+ rgba_from_hsl(float h_deg, float s, float l) {
539
+ return rgba_from_hsla(h_deg, s, l, 1.0);
540
+ }
541
+
542
+
543
+ /*
544
+ * Return rgba from (r,g,b).
545
+ */
546
+
547
+ static int32_t
548
+ rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) {
549
+ return rgba_from_rgba(r, g, b, 255);
550
+ }
551
+
552
+ /*
553
+ * Return rgba from #RRGGBBAA
554
+ */
555
+
556
+ static int32_t
557
+ rgba_from_hex8_string(const char *str) {
558
+ return rgba_from_rgba(
559
+ (h(str[0]) << 4) + h(str[1]),
560
+ (h(str[2]) << 4) + h(str[3]),
561
+ (h(str[4]) << 4) + h(str[5]),
562
+ (h(str[6]) << 4) + h(str[7])
563
+ );
564
+ }
565
+
566
+ /*
567
+ * Return rgb from "#RRGGBB".
568
+ */
569
+
570
+ static int32_t
571
+ rgba_from_hex6_string(const char *str) {
572
+ return rgba_from_rgb(
573
+ (h(str[0]) << 4) + h(str[1])
574
+ , (h(str[2]) << 4) + h(str[3])
575
+ , (h(str[4]) << 4) + h(str[5])
576
+ );
577
+ }
578
+
579
+ /*
580
+ * Return rgba from #RGBA
581
+ */
582
+
583
+ static int32_t
584
+ rgba_from_hex4_string(const char *str) {
585
+ return rgba_from_rgba(
586
+ (h(str[0]) << 4) + h(str[0]),
587
+ (h(str[1]) << 4) + h(str[1]),
588
+ (h(str[2]) << 4) + h(str[2]),
589
+ (h(str[3]) << 4) + h(str[3])
590
+ );
591
+ }
592
+
593
+ /*
594
+ * Return rgb from "#RGB"
595
+ */
596
+
597
+ static int32_t
598
+ rgba_from_hex3_string(const char *str) {
599
+ return rgba_from_rgb(
600
+ (h(str[0]) << 4) + h(str[0])
601
+ , (h(str[1]) << 4) + h(str[1])
602
+ , (h(str[2]) << 4) + h(str[2])
603
+ );
604
+ }
605
+
606
+ /*
607
+ * Return rgb from "rgb()"
608
+ */
609
+
610
+ static int32_t
611
+ rgba_from_rgb_string(const char *str, short *ok) {
612
+ if (str == strstr(str, "rgb(")) {
613
+ str += 4;
614
+ WHITESPACE;
615
+ uint8_t r = 0, g = 0, b = 0;
616
+ CHANNEL(r);
617
+ WHITESPACE_OR_COMMA;
618
+ CHANNEL(g);
619
+ WHITESPACE_OR_COMMA;
620
+ CHANNEL(b);
621
+ WHITESPACE;
622
+ return *ok = 1, rgba_from_rgb(r, g, b);
623
+ }
624
+ return *ok = 0;
625
+ }
626
+
627
+ /*
628
+ * Return rgb from "rgba()"
629
+ */
630
+
631
+ static int32_t
632
+ rgba_from_rgba_string(const char *str, short *ok) {
633
+ if (str == strstr(str, "rgba(")) {
634
+ str += 5;
635
+ WHITESPACE;
636
+ uint8_t r = 0, g = 0, b = 0;
637
+ float a = 1.f;
638
+ CHANNEL(r);
639
+ WHITESPACE_OR_COMMA;
640
+ CHANNEL(g);
641
+ WHITESPACE_OR_COMMA;
642
+ CHANNEL(b);
643
+ WHITESPACE_OR_COMMA;
644
+ ALPHA(a);
645
+ WHITESPACE;
646
+ return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255));
647
+ }
648
+ return *ok = 0;
649
+ }
650
+
651
+ /*
652
+ * Return rgb from "hsla()"
653
+ */
654
+
655
+ static int32_t
656
+ rgba_from_hsla_string(const char *str, short *ok) {
657
+ if (str == strstr(str, "hsla(")) {
658
+ str += 5;
659
+ WHITESPACE;
660
+ float h_deg = 0;
661
+ float s = 0, l = 0;
662
+ float a = 0;
663
+ HUE(h_deg);
664
+ WHITESPACE_OR_COMMA;
665
+ SATURATION(s);
666
+ WHITESPACE_OR_COMMA;
667
+ LIGHTNESS(l);
668
+ WHITESPACE_OR_COMMA;
669
+ ALPHA(a);
670
+ WHITESPACE;
671
+ return *ok = 1, rgba_from_hsla(h_deg, s, l, a);
672
+ }
673
+ return *ok = 0;
674
+ }
675
+
676
+ /*
677
+ * Return rgb from "hsl()"
678
+ */
679
+
680
+ static int32_t
681
+ rgba_from_hsl_string(const char *str, short *ok) {
682
+ if (str == strstr(str, "hsl(")) {
683
+ str += 4;
684
+ WHITESPACE;
685
+ float h_deg = 0;
686
+ float s = 0, l = 0;
687
+ HUE(h_deg);
688
+ WHITESPACE_OR_COMMA;
689
+ SATURATION(s);
690
+ WHITESPACE_OR_COMMA;
691
+ LIGHTNESS(l);
692
+ WHITESPACE;
693
+ return *ok = 1, rgba_from_hsl(h_deg, s, l);
694
+ }
695
+ return *ok = 0;
696
+ }
697
+
698
+
699
+ /*
700
+ * Return rgb from:
701
+ *
702
+ * - "#RGB"
703
+ * - "#RGBA"
704
+ * - "#RRGGBB"
705
+ * - "#RRGGBBAA"
706
+ *
707
+ */
708
+
709
+ static int32_t
710
+ rgba_from_hex_string(const char *str, short *ok) {
711
+ size_t len = strlen(str);
712
+ *ok = 1;
713
+ switch (len) {
714
+ case 8: return rgba_from_hex8_string(str);
715
+ case 6: return rgba_from_hex6_string(str);
716
+ case 4: return rgba_from_hex4_string(str);
717
+ case 3: return rgba_from_hex3_string(str);
718
+ }
719
+ return *ok = 0;
720
+ }
721
+
722
+ /*
723
+ * Return named color value.
724
+ */
725
+
726
+ static int32_t
727
+ rgba_from_name_string(const char *str, short *ok) {
728
+ std::string lowered(str);
729
+ std::transform(lowered.begin(), lowered.end(), lowered.begin(), tolower);
730
+ auto color = named_colors.find(lowered);
731
+ if (color != named_colors.end()) {
732
+ return *ok = 1, color->second;
733
+ }
734
+ return *ok = 0;
735
+ }
736
+
737
+ /*
738
+ * Return rgb from:
739
+ *
740
+ * - #RGB
741
+ * - #RGBA
742
+ * - #RRGGBB
743
+ * - #RRGGBBAA
744
+ * - rgb(r,g,b)
745
+ * - rgba(r,g,b,a)
746
+ * - hsl(h,s,l)
747
+ * - hsla(h,s,l,a)
748
+ * - name
749
+ *
750
+ */
751
+
752
+ int32_t
753
+ rgba_from_string(const char *str, short *ok) {
754
+ if ('#' == str[0])
755
+ return rgba_from_hex_string(++str, ok);
756
+ if (str == strstr(str, "rgba"))
757
+ return rgba_from_rgba_string(str, ok);
758
+ if (str == strstr(str, "rgb"))
759
+ return rgba_from_rgb_string(str, ok);
760
+ if (str == strstr(str, "hsla"))
761
+ return rgba_from_hsla_string(str, ok);
762
+ if (str == strstr(str, "hsl"))
763
+ return rgba_from_hsl_string(str, ok);
764
+ return rgba_from_name_string(str, ok);
765
+ }
766
+
767
+ /*
768
+ * Inspect the given rgba color.
769
+ */
770
+
771
+ void
772
+ rgba_inspect(int32_t rgba) {
773
+ printf("rgba(%d,%d,%d,%d)\n"
774
+ , rgba >> 24 & 0xff
775
+ , rgba >> 16 & 0xff
776
+ , rgba >> 8 & 0xff
777
+ , rgba & 0xff
778
+ );
779
+ }