@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.
- package/Readme.md +600 -0
- package/binding.gyp +230 -0
- package/browser.js +35 -0
- package/index.js +94 -0
- package/lib/DOMMatrix.js +620 -0
- package/lib/bindings.js +80 -0
- package/lib/canvas.js +113 -0
- package/lib/context2d.js +14 -0
- package/lib/image.js +96 -0
- package/lib/jpegstream.js +41 -0
- package/lib/parse-font.js +101 -0
- package/lib/pattern.js +17 -0
- package/lib/pdfstream.js +35 -0
- package/lib/pngstream.js +42 -0
- package/package.json +71 -0
- package/scripts/install.js +24 -0
- package/src/Backends.cc +18 -0
- package/src/Backends.h +10 -0
- package/src/Canvas.cc +965 -0
- package/src/Canvas.h +96 -0
- package/src/CanvasError.h +23 -0
- package/src/CanvasGradient.cc +123 -0
- package/src/CanvasGradient.h +22 -0
- package/src/CanvasPattern.cc +136 -0
- package/src/CanvasPattern.h +37 -0
- package/src/CanvasRenderingContext2d.cc +3360 -0
- package/src/CanvasRenderingContext2d.h +225 -0
- package/src/Image.cc +1434 -0
- package/src/Image.h +127 -0
- package/src/ImageData.cc +146 -0
- package/src/ImageData.h +27 -0
- package/src/JPEGStream.h +167 -0
- package/src/PNG.h +292 -0
- package/src/Point.h +11 -0
- package/src/Util.h +9 -0
- package/src/backend/Backend.cc +112 -0
- package/src/backend/Backend.h +69 -0
- package/src/backend/ImageBackend.cc +74 -0
- package/src/backend/ImageBackend.h +26 -0
- package/src/backend/PdfBackend.cc +53 -0
- package/src/backend/PdfBackend.h +24 -0
- package/src/backend/SvgBackend.cc +61 -0
- package/src/backend/SvgBackend.h +24 -0
- package/src/bmp/BMPParser.cc +457 -0
- package/src/bmp/BMPParser.h +60 -0
- package/src/bmp/LICENSE.md +24 -0
- package/src/closure.cc +26 -0
- package/src/closure.h +81 -0
- package/src/color.cc +779 -0
- package/src/color.h +30 -0
- package/src/dll_visibility.h +20 -0
- package/src/init.cc +94 -0
- package/src/register_font.cc +408 -0
- package/src/register_font.h +7 -0
- package/types/index.d.ts +484 -0
- package/util/has_lib.js +119 -0
- 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, °rees)) {
|
|
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
|
+
}
|