blendish: cosmetix
[iv.d.git] / sdpy / color.d
blob65c5da746bc7c4614bb371b6c0fb210f7f97083f
1 /*
2 * Pixel Graphics Library
3 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
4 * Understanding is not required. Only obedience.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 module iv.sdpy.color /*is aliced*/;
21 import iv.alice;
22 import iv.sdpy.compat;
25 // ////////////////////////////////////////////////////////////////////////// //
26 @gcc_inline ubyte clampToByte(T) (T n) @safe pure nothrow @nogc if (__traits(isIntegral, T)) {
27 //static assert(!__traits(isUnsigned, T), "clampToByte can't process unsigned types");
28 static if (__VERSION__ > 2067) pragma(inline, true);
29 static if (T.sizeof == 2 || T.sizeof == 4) {
30 static if (__traits(isUnsigned, T)) {
31 return cast(ubyte)(n&0xff|(255-((-cast(int)(n < 256))>>24)));
32 } else {
33 n &= -cast(int)(n >= 0);
34 return cast(ubyte)(n|((255-cast(int)n)>>31));
36 } else static if (T.sizeof == 1) {
37 static assert(__traits(isUnsigned, T), "clampToByte: signed byte? no, really?");
38 return cast(ubyte)n;
39 } else {
40 static assert(false, "clampToByte: integer too big");
44 static assert(clampToByte(666) == 255);
45 static assert(clampToByte(-666) == 0);
46 static assert(clampToByte(250) == 250);
47 static assert(clampToByte(-250) == 0);
48 static assert(clampToByte(cast(uint)250) == 250);
49 static assert(clampToByte(cast(uint)1000) == 255);
50 static assert(clampToByte(cast(uint)0xfffffff0) == 255);
54 private @gcc_inline T absInternal(T) (T a) {
55 static if (__VERSION__ > 2067) pragma(inline, true);
56 return (a < 0 ? -a : a);
59 private @gcc_inline TT minInternal(TT, T...) (T args) if (T.length > 0) {
60 static if (__VERSION__ > 2067) pragma(inline, true);
61 TT res = cast(TT)args[0];
62 foreach (immutable n; args[1..$]) if (n < res) res = cast(TT)n;
63 return res;
66 private @gcc_inline TT maxInternal(TT, T...) (T args) if (T.length > 0) {
67 static if (__VERSION__ > 2067) pragma(inline, true);
68 TT res = cast(TT)args[0];
69 foreach (immutable n; args[1..$]) if (n > res) res = cast(TT)n;
70 return res;
74 // ////////////////////////////////////////////////////////////////////////// //
75 align(1) struct VColor {
76 align(1):
77 union {
78 uint u32;
79 /// struct to ease color components extraction/replacing
80 version(LittleEndian) {
81 align(1) struct {
82 align(1):
83 ubyte b, g, r, a;
85 } else version(BigEndian) {
86 align(1) struct {
87 align(1):
88 ubyte a, r, g, b;
90 } else {
91 static assert(0, "WTF?!");
94 // consts
95 enum {
96 AShift = 24,
97 RShift = 16,
98 GShift = 8,
99 BShift = 0,
101 enum : uint {
102 AMask = cast(uint)(0xffu<<AShift),
103 RMask = cast(uint)(0xffu<<RShift),
104 GMask = cast(uint)(0xffu<<GShift),
105 BMask = cast(uint)(0xffu<<BShift),
107 static if (__VERSION__ >= 2067) {
108 enum : VColor {
109 transparent = VColor(AMask), /// completely transparent pixel color
110 black = VColor(0), /// completely black pixel color
111 white = VColor(RMask|GMask|BMask), /// completely white pixel color
112 red = VColor(RMask), /// completely red pixel color
113 green = VColor(GMask), /// completely green pixel color
114 blue = VColor(BMask), /// completely blue pixel color
116 } else {
117 // alas, old DMDFE sux
118 static @property pure nothrow @safe @nogc {
119 @gcc_inline VColor transparent () { return VColor(AMask); }
120 @gcc_inline VColor black () { return VColor(0); }
121 @gcc_inline VColor white () { return VColor(RMask|GMask|BMask); }
122 @gcc_inline VColor red () { return VColor(RMask); }
123 @gcc_inline VColor green () { return VColor(GMask); }
124 @gcc_inline VColor blue () { return VColor(BMask); }
128 // this mixin can be used to alphablend two `uint` colors
129 // `colu32name` is variable that holds color to blend,
130 // `destu32name` is variable that holds "current" color (from surface, for example)
131 // alpha value of `destu32name` doesn't matter
132 // alpha value of `colu32name` means: 0 for replace color, 255 for keep `destu32name`
133 enum ColorBlendMixinStr(string colu32name, string destu32name) = "{
134 static if (VColor.AShift == 24) {
135 immutable uint a_tmp_ = (256-(("~colu32name~")>>24))&(-(1-(((("~colu32name~")>>24)+1)>>8))); // to not loose bits, but 255 should become 0
136 immutable uint dc_tmp_ = ("~destu32name~")&0xffffff;
137 immutable uint srb_tmp_ = (("~colu32name~")&0xff00ff);
138 immutable uint sg_tmp_ = (("~colu32name~")&0x00ff00);
139 } else static if (VColor.AShift == 0) {
140 immutable uint a_tmp_ = (256-(("~colu32name~")&0xff))&(-(1-(((("~colu32name~")&0xff)+1)>>8))); // to not loose bits, but 255 should become 0
141 immutable uint dc_tmp_ = (("~destu32name~")>>8)&0xffffff;
142 immutable uint srb_tmp_ = ((("~colu32name~")>>8)&0xff00ff);
143 immutable uint sg_tmp_ = ((("~colu32name~")>>8)&0x00ff00);
144 } else {
145 static assert(0, `unsupported VColor.AMask value (only 0 and 24 are allowed)`);
147 immutable uint drb_tmp_ = (dc_tmp_&0xff00ff);
148 immutable uint dg_tmp_ = (dc_tmp_&0x00ff00);
149 immutable uint orb_tmp_ = (drb_tmp_+(((srb_tmp_-drb_tmp_)*a_tmp_+0x800080)>>8))&0xff00ff;
150 immutable uint og_tmp_ = (dg_tmp_+(((sg_tmp_-dg_tmp_)*a_tmp_+0x008000)>>8))&0x00ff00;
151 static if (VColor.AShift == 24) {
152 ("~destu32name~") = (orb_tmp_|og_tmp_)&~VColor.AMask;
153 } else {
154 // move colors to highest bits
155 ("~destu32name~") = (orb_tmp_|og_tmp_)<<8;
159 // methods
160 string toString () const nothrow @safe {
161 static usize b2s() (char[] dest, ubyte b) {
162 if (b >= 100) {
163 dest[0] = cast(char)(b/100%10+'0');
164 dest[1] = cast(char)(b/10%10+'0');
165 dest[2] = cast(char)(b%10+'0');
166 return 3;
167 } else if (b >= 10) {
168 dest[0] = cast(char)(b/10%10+'0');
169 dest[1] = cast(char)(b%10+'0');
170 return 2;
171 } else {
172 dest[0] = cast(char)(b%10+'0');
173 return 1;
176 char[32] buf;
177 usize pos = 0;
178 switch (u32) {
179 case AMask: return "transparent";
180 case 0: return "black";
181 case RMask: return "red";
182 case GMask: return "green";
183 case BMask: return "blue";
184 case RMask|GMask|BMask: return "white";
185 default:
187 buf[pos++] = 'r';
188 buf[pos++] = 'g';
189 buf[pos++] = 'b';
190 if (a != 0) buf[pos++] = 'a';
191 buf[pos++] = '(';
192 pos += b2s(buf[pos..$], r);
193 buf[pos++] = ',';
194 pos += b2s(buf[pos..$], g);
195 buf[pos++] = ',';
196 pos += b2s(buf[pos..$], b);
197 if (a != 0) {
198 buf[pos++] = ',';
199 pos += b2s(buf[pos..$], a);
201 buf[pos++] = ')';
202 return buf[0..pos].idup;
204 @safe nothrow @nogc:
205 this (uint v) pure { u32 = v; }
206 this (const(char)[] s) { u32 = parseColorName(s).u32; }
207 this (string s) { u32 = parseColorName(s).u32; }
209 // `to!` support
210 //static auto opCast(T) (const(char)[] s) if (is(T == VColor)) { return parseColorName(s); }
211 //auto opCast(T) (const(char)[] s) if (is(T == uint)) { return u32; }
213 /// Is color completely transparent?
214 @gcc_inline @property bool isTransparent() () const pure {
215 static if (__VERSION__ > 2067) pragma(inline, true);
216 return (a == 255);
219 /// Is color completely opaque?
220 @gcc_inline @property bool isOpaque() () const pure {
221 static if (__VERSION__ > 2067) pragma(inline, true);
222 return (a == 0);
225 @gcc_inline @property VColor setAlpha(T) (T a) const pure if (__traits(isIntegral, T)) {
226 static if (__VERSION__ > 2067) pragma(inline, true);
227 return VColor((u32&~AMask)|(clampToByte(a)<<AShift));
231 * Build rgba color from components.
233 * Params:
234 * r = red component [0..255]
235 * g = green component [0..255]
236 * b = blue component [0..255]
237 * a = transparency [0..255] (0: completely opaque; 255: completely transparent)
239 * Returns:
240 * VColor
242 @gcc_inline static VColor rgba(TR, TG, TB, TA) (TR r, TG g, TB b, TA a) pure
243 if (__traits(isIntegral, TR) && __traits(isIntegral, TG) && __traits(isIntegral, TB) && __traits(isIntegral, TA))
245 static if (__VERSION__ > 2067) pragma(inline, true);
246 return VColor(
247 (clampToByte(a)<<AShift)|
248 (clampToByte(r)<<RShift)|
249 (clampToByte(g)<<GShift)|
250 (clampToByte(b)<<BShift));
253 * Build opaque non-transparent rgb color from components.
255 * Params:
256 * r = red component [0..255]
257 * g = green component [0..255]
258 * b = blue component [0..255]
260 * Returns:
261 * VColor
263 @gcc_inline static VColor rgb(TR, TG, TB) (TR r, TG g, TB b) pure
264 if (__traits(isIntegral, TR) && __traits(isIntegral, TG) && __traits(isIntegral, TB))
266 static if (__VERSION__ > 2067) pragma(inline, true);
267 return VColor(
268 (clampToByte(r)<<RShift)|
269 (clampToByte(g)<<GShift)|
270 (clampToByte(b)<<BShift));
273 // HSL functions were taken from arsd.color, written by Adam D. Ruppe, modified by Ketmar
274 // Converts hsl to rgb
275 static VColor hsl(T) (T h, T s, T l, T a=0) pure if (__traits(isFloating, T)) {
276 h %= 360;
277 immutable real C = (1-absInternal(2*l-1))*s;
278 immutable real hPrime = h/60;
279 immutable real X = C*(1-absInternal(hPrime%2-1));
280 real r, g, b;
281 if (h is real.nan) {
282 r = g = b = 0;
283 } else if (hPrime >= 0 && hPrime < 1) {
284 r = C;
285 g = X;
286 b = 0;
287 } else if (hPrime >= 1 && hPrime < 2) {
288 r = X;
289 g = C;
290 b = 0;
291 } else if (hPrime >= 2 && hPrime < 3) {
292 r = 0;
293 g = C;
294 b = X;
295 } else if (hPrime >= 3 && hPrime < 4) {
296 r = 0;
297 g = X;
298 b = C;
299 } else if (hPrime >= 4 && hPrime < 5) {
300 r = X;
301 g = 0;
302 b = C;
303 } else if (hPrime >= 5 && hPrime < 6) {
304 r = C;
305 g = 0;
306 b = X;
309 immutable real m = l-C/2;
310 r += m;
311 g += m;
312 b += m;
314 return VColor.rgba(cast(ubyte)(r*255), cast(ubyte)(g*255), cast(ubyte)(b*255), cast(ubyte)(a));
318 // Converts an RGB color into an HSL triplet.
319 // useWeightedLightness will try to get a better value for luminosity for the human eye,
320 // which is more sensitive to green than red and more to red than blue.
321 // If it is false, it just does average of the rgb.
322 void toHsl(T=real) (out T Ho, out T So, out T Lo, bool useWeightedLightness=false) pure if (__traits(isFloating, T)) {
323 // use bitops for CTFE
324 immutable real r1 = cast(real)((this.u32>>RShift)&0xff)/255;
325 immutable real g1 = cast(real)((this.u32>>GShift)&0xff)/255;
326 immutable real b1 = cast(real)((this.u32>>BShift)&0xff)/255;
328 immutable real maxColor = maxInternal!real(r1, g1, b1);
329 immutable real minColor = minInternal!real(r1, g1, b1);
331 real L = (maxColor+minColor)/2;
332 if (useWeightedLightness) {
333 // the colors don't affect the eye equally
334 // this is a little more accurate than plain HSL numbers
335 L = 0.2126*r1+0.7152*g1+0.0722*b1;
337 real S = 0;
338 real H = 0;
339 if (maxColor != minColor) {
340 if (L < 0.5) {
341 S = (maxColor-minColor)/(maxColor+minColor);
342 } else {
343 S = (maxColor-minColor)/(2.0-maxColor-minColor);
345 if (r1 == maxColor) {
346 H = (g1-b1)/(maxColor-minColor);
347 } else if(g1 == maxColor) {
348 H = 2.0+(b1-r1)/(maxColor-minColor);
349 } else {
350 H = 4.0+(r1-g1)/(maxColor-minColor);
354 H = H*60;
355 if (H < 0) H += 360;
357 //return [H, S, L];
358 Ho = cast(T)H;
359 So = cast(T)S;
360 Lo = cast(T)L;
363 VColor lighten(T) (T percentage) pure if (__traits(isFloating, T)) {
364 real h, s, l;
365 toHsl(h, s, l);
366 l *= (1+percentage);
367 if (l > 1) l = 1;
368 else if (l < 0) l = 0; //k8:???
369 return hsl(h, s, l, cast(real)this.a);
372 VColor darken(T) (T percentage) pure if (__traits(isFloating, T)) {
373 real h, s, l;
374 toHsl(h, s, l);
375 l *= (1-percentage);
376 if (l > 1) l = 1;
377 else if (l < 0) l = 0; //k8:???
378 return hsl(h, s, l, cast(real)this.a);
381 // for light colors, call darken. for dark colors, call lighten.
382 // The goal: get toward center grey.
383 VColor moderate(T) (T percentage) pure if (__traits(isFloating, T)) {
384 real h, s, l;
385 toHsl(h, s, l);
386 if (l > 0.5) l *= (1-percentage);
387 else if (l <= 0.01) l = percentage; // if we are given black, moderating it means getting *something* out
388 else l *= (1+percentage);
389 if (l > 1) l = 1;
390 else if (l < 0) l = 0; //k8:???
391 return hsl(h, s, l, cast(real)this.a);
394 /// the opposite of moderate. Make darks darker and lights lighter
395 VColor extremify(T) (T percentage) pure if (__traits(isFloating, T)) {
396 real h, s, l;
397 toHsl(h, s, l);
398 if (l < 0.5) l *= (1-percentage); else l *= (1+percentage);
399 if (l > 1) l = 1;
400 else if (l < 0) l = 0; //k8:???
401 return hsl(h, s, l, cast(real)this.a);
404 /// Move around the lightness wheel, trying not to break on moderate things
405 VColor oppositeLightness() () pure {
406 real h, s, l;
407 toHsl(h, s, l);
408 auto original = l;
409 if (original > 0.4 && original < 0.6) {
410 l = 0.8-original; // so it isn't quite the same
411 } else {
412 l = 1-original;
414 return hsl(h, s, l, cast(real)this.a);
417 /// Try to determine a text color - either white or black - based on the input
418 VColor textColor() () pure {
419 real h, s, l;
420 toHsl(h, s, l, true); // give green a bonus for contrast
421 return (l > 0.71 ? VColor.black : VColor.white);
424 static assert(VColor.sizeof == uint.sizeof);
426 static assert(VColor.black.textColor == VColor.white);
427 static assert(VColor.hsl(1.0, 1.0, 1.0) == VColor.white);
428 static assert(VColor.hsl(1.0, 1.0, 0.0) == VColor.black);
429 //pragma(msg, VColor.hsl(1.0, 1.0, 0.0));
433 // ////////////////////////////////////////////////////////////////////////// //
434 private int digit (char ch, int base) pure @safe nothrow @nogc {
435 static if (__VERSION__ > 2067) pragma(inline, true);
436 if (ch >= '0' && ch <= '9') ch -= '0';
437 else if (ch >= 'A' && ch <= 'Z') ch -= 'A'-10;
438 else if (ch >= 'a' && ch <= 'z') ch -= 'a'-10;
439 else ch = '\xff';
440 return (ch < base ? ch : -1);
444 // ////////////////////////////////////////////////////////////////////////// //
445 private __gshared VColor[string] knownColors;
448 private void loadColors (string srctext) {
449 ubyte[3] rgb;
450 usize pos;
451 mainloop: while (srctext.length) {
452 pos = 0;
453 while (pos < srctext.length && srctext[pos] != '\n') ++pos;
454 if (pos < srctext.length) ++pos;
455 auto ln = srctext[0..pos];
456 srctext = srctext[pos..$];
457 while (ln.length && ln[$-1] <= ' ') ln = ln[0..$-1];
458 pos = 0;
459 while (pos < ln.length && ln[pos] != '#') ++pos;
460 ln = ln[0..pos];
461 //{ import std.stdio; writeln("*[", ln, "]"); }
462 foreach (immutable idx; 0..3) {
463 while (ln.length && ln[0] <= ' ') ln = ln[1..$];
464 if (ln.length == 0 || ln[0] < '0' || ln[0] > '9') continue mainloop;
465 uint num = 0;
466 while (ln.length && ln[0] >= '0' && ln[0] <= '9') {
467 num = num*10+(ln[0]-'0');
468 if (num > 255) continue mainloop;
469 ln = ln[1..$];
471 rgb[idx] = cast(ubyte)num;
472 //{ import std.stdio; writeln("**[", ln, "]"); }
474 while (ln.length && ln[0] <= ' ') ln = ln[1..$];
475 if (ln.length == 0) continue mainloop;
476 //{ import std.stdio; writeln("[", ln, "] = (", rgb[0], ", ", rgb[1], ", ", rgb[2], ")"); }
477 knownColors[ln.idup] = VColor.rgb(rgb[0], rgb[1], rgb[2]);
482 shared static this () {
484 try {
485 loadColors("/usr/share/X11/rgb.txt");
486 } catch (Exception) {
487 knownColors["red"] = VColor.rgb(255, 0, 0);
488 knownColors["green"] = VColor.rgb(0, 255, 0);
489 knownColors["blue"] = VColor.rgb(0, 0, 255);
490 knownColors["black"] = VColor.rgb(0, 0, 0);
491 knownColors["white"] = VColor.rgb(255, 255, 255);
492 knownColors["silver"] = VColor.rgb(192, 192, 192);
495 loadColors(colorList_);
499 // ////////////////////////////////////////////////////////////////////////// //
500 public VColor parseColorName (const(char)[] cname, bool* ok=null) @trusted nothrow @nogc {
501 bool parseNum (out ubyte v) @safe nothrow @nogc {
502 int base = 10;
503 while (cname.length && (cname[0] <= ' ' || cname[0] == '_')) cname = cname[1..$];
504 if (cname.length == 0 || cname[0] < '0' || cname[0] > '9') return false;
505 if (cname.length > 2 && cname[0] == '0' && (cname[1] == 'x' || cname[1] == 'X')) {
506 // hex number
507 cname = cname[2..$];
508 base = 16;
509 } else if (cname.length > 2 && cname[0] == '0' && (cname[1] == 'o' || cname[1] == 'O')) {
510 // octal number
511 cname = cname[2..$];
512 base = 8;
513 } else if (cname.length > 2 && cname[0] == '0' && (cname[1] == 'b' || cname[1] == 'B')) {
514 // binary number
515 cname = cname[2..$];
516 base = 2;
517 } else if (cname.length > 2 && cname[0] == '0' && (cname[1] == 'd' || cname[1] == 'D')) {
518 // decimal number
519 cname = cname[2..$];
521 if (cname.length == 0 || digit(cname[0], base) < 0) return false;
522 int n = 0;
523 while (cname.length) {
524 int d = digit(cname[0], base);
525 if (d < 0) {
526 if (cname[0] != '_') {
527 while (cname.length && cname[0] <= ' ') cname = cname[1..$];
528 break;
530 } else {
531 n = n*base+d;
532 if (n > 255) return false;
534 cname = cname[1..$];
536 v = cast(ubyte)n;
537 return true;
540 if (ok !is null) *ok = false;
541 while (cname.length && cname[0] <= ' ') cname = cname[1..$];
542 while (cname.length && cname[$-1] <= ' ') cname = cname[0..$-1];
543 if (cname.length == 0) return VColor.transparent;
544 if (cname[0] == '#') {
545 cname = cname[1..$];
546 ubyte[6] hd;
547 uint hdpos = 0;
548 // collect hex digits
549 foreach (char ch; cname) {
550 if (ch <= ' ' || ch == '_') continue;
551 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
552 if (hdpos >= hd.length) return VColor.transparent;
553 if (ch >= 'a') ch -= 'a'-10;
554 else if (ch >= 'A') ch -= 'A'-10;
555 else ch -= '0';
556 hd[hdpos++] = cast(ubyte)ch;
557 } else if (ch > ' ' && ch != '_') {
558 return VColor.transparent;
561 if (hdpos == 3) {
562 if (ok !is null) *ok = true;
563 //return VColor.rgb(hd[0]*16+hd[0], hd[1]*16+hd[1], hd[2]*16+hd[2]);
564 return VColor.rgb(hd[0]*17, hd[1]*17, hd[2]*17);
565 } else if (hdpos == 6) {
566 if (ok !is null) *ok = true;
567 return VColor.rgb(hd[0]*16+hd[1], hd[2]*16+hd[3], hd[4]*16+hd[5]);
568 } else {
569 return VColor.transparent;
572 if (cname.length > 3 && cname[0..3] == "rgb") {
573 cname = cname[3..$];
574 if (cname[0] == 'a') cname = cname[1..$];
575 while (cname.length && cname[0] <= ' ') cname = cname[1..$];
576 if (cname.length < 2 || cname[0] != '(' || cname[$-1] != ')') return VColor.transparent;
577 cname = cname[1..$];
578 ubyte[4] rgba;
579 uint cidx = 0;
580 for (;;) {
581 while (cname.length && (cname[0] <= ' ' || cname[0] == '_')) cname = cname[1..$];
582 if (cidx >= rgba.length) return VColor.transparent;
583 if (cname[0] != ',') {
584 if (!parseNum(rgba[cidx])) return VColor.transparent;
586 ++cidx;
587 if (cname[0] == ')') break;
588 if (cname[0] != ',') return VColor.transparent;
589 cname = cname[1..$];
591 if (cidx < 3) return VColor.transparent;
592 if (ok !is null) *ok = true;
593 return VColor.rgba(rgba[0], rgba[1], rgba[2], rgba[3]);
595 // try predefined colors
597 char[64] nbuf;
598 usize pos = 0;
599 foreach (char ch; cname) {
600 if (ch <= ' ') continue;
601 if (ch >= 'A' && ch <= 'Z') ch += 32; // poor man's `toLower()`
602 if (pos >= nbuf.length) return VColor.transparent;
603 nbuf[pos++] = ch;
605 if (pos == 0) return VColor.transparent;
606 if (auto cl = nbuf[0..pos] in knownColors) {
607 if (ok !is null) *ok = true;
608 return *cl;
610 if (nbuf[0..pos] == "transparent") {
611 if (ok !is null) *ok = true;
612 return VColor.transparent;
615 return VColor.transparent;
618 unittest {
619 import iv.writer;
620 version(test_color_parser) {
621 void dumpColor (string cname) {
622 bool ok;
623 auto clr = parseColorName(cname, &ok);
624 writefln!"0x%08x; ok=%s; [%s]"(clr, ok, cname);
627 dumpColor("#f00");
628 dumpColor("#e00");
629 dumpColor("#00_ff_00");
630 dumpColor("#00fe0_0");
631 dumpColor("rgb(1, 2, 3 )");
632 dumpColor("rgba(1, 2, 3 )");
633 dumpColor("rgba(1, 2, 3 , 4)");
634 dumpColor("rgba(1,,, 4)");
635 dumpColor("green");
636 dumpColor("gray");
637 dumpColor("orange");
638 dumpColor("dark orange");
639 dumpColor("olive");
640 dumpColor("yellow");
641 dumpColor("gold");
646 // ////////////////////////////////////////////////////////////////////////// //
647 private immutable string colorList_ = `
648 255 250 250 snow
649 248 248 255 ghostwhite
650 245 245 245 whitesmoke
651 220 220 220 gainsboro
652 255 250 240 floralwhite
653 253 245 230 oldlace
654 250 240 230 linen
655 250 235 215 antiquewhite
656 255 239 213 papayawhip
657 255 235 205 blanchedalmond
658 255 228 196 bisque
659 255 218 185 peachpuff
660 255 222 173 navajowhite
661 255 228 181 moccasin
662 255 248 220 cornsilk
663 255 255 240 ivory
664 255 250 205 lemonchiffon
665 255 245 238 seashell
666 240 255 240 honeydew
667 245 255 250 mintcream
668 240 255 255 azure
669 240 248 255 aliceblue
670 230 230 250 lavender
671 255 240 245 lavenderblush
672 255 228 225 mistyrose
673 255 255 255 white
674 0 0 0 black
675 47 79 79 darkslategray
676 47 79 79 darkslategrey
677 105 105 105 dimgray
678 105 105 105 dimgrey
679 112 128 144 slategray
680 112 128 144 slategrey
681 119 136 153 lightslategray
682 119 136 153 lightslategrey
683 190 190 190 gray
684 190 190 190 grey
685 190 190 190 x11gray
686 190 190 190 x11grey
687 128 128 128 webgray
688 128 128 128 webgrey
689 211 211 211 lightgrey
690 211 211 211 lightgray
691 25 25 112 midnightblue
692 0 0 128 navy
693 0 0 128 navyblue
694 100 149 237 cornflowerblue
695 72 61 139 darkslateblue
696 106 90 205 slateblue
697 123 104 238 mediumslateblue
698 132 112 255 lightslateblue
699 0 0 205 mediumblue
700 65 105 225 royalblue
701 0 0 255 blue
702 30 144 255 dodgerblue
703 0 191 255 deepskyblue
704 135 206 235 skyblue
705 135 206 250 lightskyblue
706 70 130 180 steelblue
707 176 196 222 lightsteelblue
708 173 216 230 lightblue
709 176 224 230 powderblue
710 175 238 238 paleturquoise
711 0 206 209 darkturquoise
712 72 209 204 mediumturquoise
713 64 224 208 turquoise
714 0 255 255 cyan
715 0 255 255 aqua
716 224 255 255 lightcyan
717 95 158 160 cadetblue
718 102 205 170 mediumaquamarine
719 127 255 212 aquamarine
720 0 100 0 darkgreen
721 85 107 47 darkolivegreen
722 143 188 143 darkseagreen
723 46 139 87 seagreen
724 60 179 113 mediumseagreen
725 32 178 170 lightseagreen
726 152 251 152 palegreen
727 0 255 127 springgreen
728 124 252 0 lawngreen
729 0 255 0 green
730 0 255 0 lime
731 0 255 0 x11green
732 0 128 0 webgreen
733 127 255 0 chartreuse
734 0 250 154 mediumspringgreen
735 173 255 47 greenyellow
736 50 205 50 limegreen
737 154 205 50 yellowgreen
738 34 139 34 forestgreen
739 107 142 35 olivedrab
740 189 183 107 darkkhaki
741 240 230 140 khaki
742 238 232 170 palegoldenrod
743 250 250 210 lightgoldenrodyellow
744 255 255 224 lightyellow
745 255 255 0 yellow
746 255 215 0 gold
747 238 221 130 lightgoldenrod
748 218 165 32 goldenrod
749 184 134 11 darkgoldenrod
750 188 143 143 rosybrown
751 205 92 92 indianred
752 139 69 19 saddlebrown
753 160 82 45 sienna
754 205 133 63 peru
755 222 184 135 burlywood
756 245 245 220 beige
757 245 222 179 wheat
758 244 164 96 sandybrown
759 210 180 140 tan
760 210 105 30 chocolate
761 178 34 34 firebrick
762 165 42 42 brown
763 233 150 122 darksalmon
764 250 128 114 salmon
765 255 160 122 lightsalmon
766 255 165 0 orange
767 255 140 0 darkorange
768 255 127 80 coral
769 240 128 128 lightcoral
770 255 99 71 tomato
771 255 69 0 orangered
772 255 0 0 red
773 255 105 180 hotpink
774 255 20 147 deeppink
775 255 192 203 pink
776 255 182 193 lightpink
777 219 112 147 palevioletred
778 176 48 96 maroon
779 176 48 96 x11maroon
780 128 0 0 webmaroon
781 199 21 133 mediumvioletred
782 208 32 144 violetred
783 255 0 255 magenta
784 255 0 255 fuchsia
785 238 130 238 violet
786 221 160 221 plum
787 218 112 214 orchid
788 186 85 211 mediumorchid
789 153 50 204 darkorchid
790 148 0 211 darkviolet
791 138 43 226 blueviolet
792 160 32 240 purple
793 160 32 240 x11purple
794 128 0 128 webpurple
795 147 112 219 mediumpurple
796 216 191 216 thistle
797 255 250 250 snow1
798 238 233 233 snow2
799 205 201 201 snow3
800 139 137 137 snow4
801 255 245 238 seashell1
802 238 229 222 seashell2
803 205 197 191 seashell3
804 139 134 130 seashell4
805 255 239 219 antiquewhite1
806 238 223 204 antiquewhite2
807 205 192 176 antiquewhite3
808 139 131 120 antiquewhite4
809 255 228 196 bisque1
810 238 213 183 bisque2
811 205 183 158 bisque3
812 139 125 107 bisque4
813 255 218 185 peachpuff1
814 238 203 173 peachpuff2
815 205 175 149 peachpuff3
816 139 119 101 peachpuff4
817 255 222 173 navajowhite1
818 238 207 161 navajowhite2
819 205 179 139 navajowhite3
820 139 121 94 navajowhite4
821 255 250 205 lemonchiffon1
822 238 233 191 lemonchiffon2
823 205 201 165 lemonchiffon3
824 139 137 112 lemonchiffon4
825 255 248 220 cornsilk1
826 238 232 205 cornsilk2
827 205 200 177 cornsilk3
828 139 136 120 cornsilk4
829 255 255 240 ivory1
830 238 238 224 ivory2
831 205 205 193 ivory3
832 139 139 131 ivory4
833 240 255 240 honeydew1
834 224 238 224 honeydew2
835 193 205 193 honeydew3
836 131 139 131 honeydew4
837 255 240 245 lavenderblush1
838 238 224 229 lavenderblush2
839 205 193 197 lavenderblush3
840 139 131 134 lavenderblush4
841 255 228 225 mistyrose1
842 238 213 210 mistyrose2
843 205 183 181 mistyrose3
844 139 125 123 mistyrose4
845 240 255 255 azure1
846 224 238 238 azure2
847 193 205 205 azure3
848 131 139 139 azure4
849 131 111 255 slateblue1
850 122 103 238 slateblue2
851 105 89 205 slateblue3
852 71 60 139 slateblue4
853 72 118 255 royalblue1
854 67 110 238 royalblue2
855 58 95 205 royalblue3
856 39 64 139 royalblue4
857 0 0 255 blue1
858 0 0 238 blue2
859 0 0 205 blue3
860 0 0 139 blue4
861 30 144 255 dodgerblue1
862 28 134 238 dodgerblue2
863 24 116 205 dodgerblue3
864 16 78 139 dodgerblue4
865 99 184 255 steelblue1
866 92 172 238 steelblue2
867 79 148 205 steelblue3
868 54 100 139 steelblue4
869 0 191 255 deepskyblue1
870 0 178 238 deepskyblue2
871 0 154 205 deepskyblue3
872 0 104 139 deepskyblue4
873 135 206 255 skyblue1
874 126 192 238 skyblue2
875 108 166 205 skyblue3
876 74 112 139 skyblue4
877 176 226 255 lightskyblue1
878 164 211 238 lightskyblue2
879 141 182 205 lightskyblue3
880 96 123 139 lightskyblue4
881 198 226 255 slategray1
882 185 211 238 slategray2
883 159 182 205 slategray3
884 108 123 139 slategray4
885 202 225 255 lightsteelblue1
886 188 210 238 lightsteelblue2
887 162 181 205 lightsteelblue3
888 110 123 139 lightsteelblue4
889 191 239 255 lightblue1
890 178 223 238 lightblue2
891 154 192 205 lightblue3
892 104 131 139 lightblue4
893 224 255 255 lightcyan1
894 209 238 238 lightcyan2
895 180 205 205 lightcyan3
896 122 139 139 lightcyan4
897 187 255 255 paleturquoise1
898 174 238 238 paleturquoise2
899 150 205 205 paleturquoise3
900 102 139 139 paleturquoise4
901 152 245 255 cadetblue1
902 142 229 238 cadetblue2
903 122 197 205 cadetblue3
904 83 134 139 cadetblue4
905 0 245 255 turquoise1
906 0 229 238 turquoise2
907 0 197 205 turquoise3
908 0 134 139 turquoise4
909 0 255 255 cyan1
910 0 238 238 cyan2
911 0 205 205 cyan3
912 0 139 139 cyan4
913 151 255 255 darkslategray1
914 141 238 238 darkslategray2
915 121 205 205 darkslategray3
916 82 139 139 darkslategray4
917 127 255 212 aquamarine1
918 118 238 198 aquamarine2
919 102 205 170 aquamarine3
920 69 139 116 aquamarine4
921 193 255 193 darkseagreen1
922 180 238 180 darkseagreen2
923 155 205 155 darkseagreen3
924 105 139 105 darkseagreen4
925 84 255 159 seagreen1
926 78 238 148 seagreen2
927 67 205 128 seagreen3
928 46 139 87 seagreen4
929 154 255 154 palegreen1
930 144 238 144 palegreen2
931 124 205 124 palegreen3
932 84 139 84 palegreen4
933 0 255 127 springgreen1
934 0 238 118 springgreen2
935 0 205 102 springgreen3
936 0 139 69 springgreen4
937 0 255 0 green1
938 0 238 0 green2
939 0 205 0 green3
940 0 139 0 green4
941 127 255 0 chartreuse1
942 118 238 0 chartreuse2
943 102 205 0 chartreuse3
944 69 139 0 chartreuse4
945 192 255 62 olivedrab1
946 179 238 58 olivedrab2
947 154 205 50 olivedrab3
948 105 139 34 olivedrab4
949 202 255 112 darkolivegreen1
950 188 238 104 darkolivegreen2
951 162 205 90 darkolivegreen3
952 110 139 61 darkolivegreen4
953 255 246 143 khaki1
954 238 230 133 khaki2
955 205 198 115 khaki3
956 139 134 78 khaki4
957 255 236 139 lightgoldenrod1
958 238 220 130 lightgoldenrod2
959 205 190 112 lightgoldenrod3
960 139 129 76 lightgoldenrod4
961 255 255 224 lightyellow1
962 238 238 209 lightyellow2
963 205 205 180 lightyellow3
964 139 139 122 lightyellow4
965 255 255 0 yellow1
966 238 238 0 yellow2
967 205 205 0 yellow3
968 139 139 0 yellow4
969 255 215 0 gold1
970 238 201 0 gold2
971 205 173 0 gold3
972 139 117 0 gold4
973 255 193 37 goldenrod1
974 238 180 34 goldenrod2
975 205 155 29 goldenrod3
976 139 105 20 goldenrod4
977 255 185 15 darkgoldenrod1
978 238 173 14 darkgoldenrod2
979 205 149 12 darkgoldenrod3
980 139 101 8 darkgoldenrod4
981 255 193 193 rosybrown1
982 238 180 180 rosybrown2
983 205 155 155 rosybrown3
984 139 105 105 rosybrown4
985 255 106 106 indianred1
986 238 99 99 indianred2
987 205 85 85 indianred3
988 139 58 58 indianred4
989 255 130 71 sienna1
990 238 121 66 sienna2
991 205 104 57 sienna3
992 139 71 38 sienna4
993 255 211 155 burlywood1
994 238 197 145 burlywood2
995 205 170 125 burlywood3
996 139 115 85 burlywood4
997 255 231 186 wheat1
998 238 216 174 wheat2
999 205 186 150 wheat3
1000 139 126 102 wheat4
1001 255 165 79 tan1
1002 238 154 73 tan2
1003 205 133 63 tan3
1004 139 90 43 tan4
1005 255 127 36 chocolate1
1006 238 118 33 chocolate2
1007 205 102 29 chocolate3
1008 139 69 19 chocolate4
1009 255 48 48 firebrick1
1010 238 44 44 firebrick2
1011 205 38 38 firebrick3
1012 139 26 26 firebrick4
1013 255 64 64 brown1
1014 238 59 59 brown2
1015 205 51 51 brown3
1016 139 35 35 brown4
1017 255 140 105 salmon1
1018 238 130 98 salmon2
1019 205 112 84 salmon3
1020 139 76 57 salmon4
1021 255 160 122 lightsalmon1
1022 238 149 114 lightsalmon2
1023 205 129 98 lightsalmon3
1024 139 87 66 lightsalmon4
1025 255 165 0 orange1
1026 238 154 0 orange2
1027 205 133 0 orange3
1028 139 90 0 orange4
1029 255 127 0 darkorange1
1030 238 118 0 darkorange2
1031 205 102 0 darkorange3
1032 139 69 0 darkorange4
1033 255 114 86 coral1
1034 238 106 80 coral2
1035 205 91 69 coral3
1036 139 62 47 coral4
1037 255 99 71 tomato1
1038 238 92 66 tomato2
1039 205 79 57 tomato3
1040 139 54 38 tomato4
1041 255 69 0 orangered1
1042 238 64 0 orangered2
1043 205 55 0 orangered3
1044 139 37 0 orangered4
1045 255 0 0 red1
1046 238 0 0 red2
1047 205 0 0 red3
1048 139 0 0 red4
1049 255 20 147 deeppink1
1050 238 18 137 deeppink2
1051 205 16 118 deeppink3
1052 139 10 80 deeppink4
1053 255 110 180 hotpink1
1054 238 106 167 hotpink2
1055 205 96 144 hotpink3
1056 139 58 98 hotpink4
1057 255 181 197 pink1
1058 238 169 184 pink2
1059 205 145 158 pink3
1060 139 99 108 pink4
1061 255 174 185 lightpink1
1062 238 162 173 lightpink2
1063 205 140 149 lightpink3
1064 139 95 101 lightpink4
1065 255 130 171 palevioletred1
1066 238 121 159 palevioletred2
1067 205 104 137 palevioletred3
1068 139 71 93 palevioletred4
1069 255 52 179 maroon1
1070 238 48 167 maroon2
1071 205 41 144 maroon3
1072 139 28 98 maroon4
1073 255 62 150 violetred1
1074 238 58 140 violetred2
1075 205 50 120 violetred3
1076 139 34 82 violetred4
1077 255 0 255 magenta1
1078 238 0 238 magenta2
1079 205 0 205 magenta3
1080 139 0 139 magenta4
1081 255 131 250 orchid1
1082 238 122 233 orchid2
1083 205 105 201 orchid3
1084 139 71 137 orchid4
1085 255 187 255 plum1
1086 238 174 238 plum2
1087 205 150 205 plum3
1088 139 102 139 plum4
1089 224 102 255 mediumorchid1
1090 209 95 238 mediumorchid2
1091 180 82 205 mediumorchid3
1092 122 55 139 mediumorchid4
1093 191 62 255 darkorchid1
1094 178 58 238 darkorchid2
1095 154 50 205 darkorchid3
1096 104 34 139 darkorchid4
1097 155 48 255 purple1
1098 145 44 238 purple2
1099 125 38 205 purple3
1100 85 26 139 purple4
1101 171 130 255 mediumpurple1
1102 159 121 238 mediumpurple2
1103 137 104 205 mediumpurple3
1104 93 71 139 mediumpurple4
1105 255 225 255 thistle1
1106 238 210 238 thistle2
1107 205 181 205 thistle3
1108 139 123 139 thistle4
1109 0 0 0 gray0
1110 0 0 0 grey0
1111 3 3 3 gray1
1112 3 3 3 grey1
1113 5 5 5 gray2
1114 5 5 5 grey2
1115 8 8 8 gray3
1116 8 8 8 grey3
1117 10 10 10 gray4
1118 10 10 10 grey4
1119 13 13 13 gray5
1120 13 13 13 grey5
1121 15 15 15 gray6
1122 15 15 15 grey6
1123 18 18 18 gray7
1124 18 18 18 grey7
1125 20 20 20 gray8
1126 20 20 20 grey8
1127 23 23 23 gray9
1128 23 23 23 grey9
1129 26 26 26 gray10
1130 26 26 26 grey10
1131 28 28 28 gray11
1132 28 28 28 grey11
1133 31 31 31 gray12
1134 31 31 31 grey12
1135 33 33 33 gray13
1136 33 33 33 grey13
1137 36 36 36 gray14
1138 36 36 36 grey14
1139 38 38 38 gray15
1140 38 38 38 grey15
1141 41 41 41 gray16
1142 41 41 41 grey16
1143 43 43 43 gray17
1144 43 43 43 grey17
1145 46 46 46 gray18
1146 46 46 46 grey18
1147 48 48 48 gray19
1148 48 48 48 grey19
1149 51 51 51 gray20
1150 51 51 51 grey20
1151 54 54 54 gray21
1152 54 54 54 grey21
1153 56 56 56 gray22
1154 56 56 56 grey22
1155 59 59 59 gray23
1156 59 59 59 grey23
1157 61 61 61 gray24
1158 61 61 61 grey24
1159 64 64 64 gray25
1160 64 64 64 grey25
1161 66 66 66 gray26
1162 66 66 66 grey26
1163 69 69 69 gray27
1164 69 69 69 grey27
1165 71 71 71 gray28
1166 71 71 71 grey28
1167 74 74 74 gray29
1168 74 74 74 grey29
1169 77 77 77 gray30
1170 77 77 77 grey30
1171 79 79 79 gray31
1172 79 79 79 grey31
1173 82 82 82 gray32
1174 82 82 82 grey32
1175 84 84 84 gray33
1176 84 84 84 grey33
1177 87 87 87 gray34
1178 87 87 87 grey34
1179 89 89 89 gray35
1180 89 89 89 grey35
1181 92 92 92 gray36
1182 92 92 92 grey36
1183 94 94 94 gray37
1184 94 94 94 grey37
1185 97 97 97 gray38
1186 97 97 97 grey38
1187 99 99 99 gray39
1188 99 99 99 grey39
1189 102 102 102 gray40
1190 102 102 102 grey40
1191 105 105 105 gray41
1192 105 105 105 grey41
1193 107 107 107 gray42
1194 107 107 107 grey42
1195 110 110 110 gray43
1196 110 110 110 grey43
1197 112 112 112 gray44
1198 112 112 112 grey44
1199 115 115 115 gray45
1200 115 115 115 grey45
1201 117 117 117 gray46
1202 117 117 117 grey46
1203 120 120 120 gray47
1204 120 120 120 grey47
1205 122 122 122 gray48
1206 122 122 122 grey48
1207 125 125 125 gray49
1208 125 125 125 grey49
1209 127 127 127 gray50
1210 127 127 127 grey50
1211 130 130 130 gray51
1212 130 130 130 grey51
1213 133 133 133 gray52
1214 133 133 133 grey52
1215 135 135 135 gray53
1216 135 135 135 grey53
1217 138 138 138 gray54
1218 138 138 138 grey54
1219 140 140 140 gray55
1220 140 140 140 grey55
1221 143 143 143 gray56
1222 143 143 143 grey56
1223 145 145 145 gray57
1224 145 145 145 grey57
1225 148 148 148 gray58
1226 148 148 148 grey58
1227 150 150 150 gray59
1228 150 150 150 grey59
1229 153 153 153 gray60
1230 153 153 153 grey60
1231 156 156 156 gray61
1232 156 156 156 grey61
1233 158 158 158 gray62
1234 158 158 158 grey62
1235 161 161 161 gray63
1236 161 161 161 grey63
1237 163 163 163 gray64
1238 163 163 163 grey64
1239 166 166 166 gray65
1240 166 166 166 grey65
1241 168 168 168 gray66
1242 168 168 168 grey66
1243 171 171 171 gray67
1244 171 171 171 grey67
1245 173 173 173 gray68
1246 173 173 173 grey68
1247 176 176 176 gray69
1248 176 176 176 grey69
1249 179 179 179 gray70
1250 179 179 179 grey70
1251 181 181 181 gray71
1252 181 181 181 grey71
1253 184 184 184 gray72
1254 184 184 184 grey72
1255 186 186 186 gray73
1256 186 186 186 grey73
1257 189 189 189 gray74
1258 189 189 189 grey74
1259 191 191 191 gray75
1260 191 191 191 grey75
1261 194 194 194 gray76
1262 194 194 194 grey76
1263 196 196 196 gray77
1264 196 196 196 grey77
1265 199 199 199 gray78
1266 199 199 199 grey78
1267 201 201 201 gray79
1268 201 201 201 grey79
1269 204 204 204 gray80
1270 204 204 204 grey80
1271 207 207 207 gray81
1272 207 207 207 grey81
1273 209 209 209 gray82
1274 209 209 209 grey82
1275 212 212 212 gray83
1276 212 212 212 grey83
1277 214 214 214 gray84
1278 214 214 214 grey84
1279 217 217 217 gray85
1280 217 217 217 grey85
1281 219 219 219 gray86
1282 219 219 219 grey86
1283 222 222 222 gray87
1284 222 222 222 grey87
1285 224 224 224 gray88
1286 224 224 224 grey88
1287 227 227 227 gray89
1288 227 227 227 grey89
1289 229 229 229 gray90
1290 229 229 229 grey90
1291 232 232 232 gray91
1292 232 232 232 grey91
1293 235 235 235 gray92
1294 235 235 235 grey92
1295 237 237 237 gray93
1296 237 237 237 grey93
1297 240 240 240 gray94
1298 240 240 240 grey94
1299 242 242 242 gray95
1300 242 242 242 grey95
1301 245 245 245 gray96
1302 245 245 245 grey96
1303 247 247 247 gray97
1304 247 247 247 grey97
1305 250 250 250 gray98
1306 250 250 250 grey98
1307 252 252 252 gray99
1308 252 252 252 grey99
1309 255 255 255 gray100
1310 255 255 255 grey100
1311 169 169 169 darkgrey
1312 169 169 169 darkgray
1313 0 0 139 darkblue
1314 0 139 139 darkcyan
1315 139 0 139 darkmagenta
1316 139 0 0 darkred
1317 144 238 144 lightgreen
1318 220 20 60 crimson
1319 75 0 130 indigo
1320 128 128 0 olive
1321 102 51 153 rebeccapurple
1322 192 192 192 silver
1323 0 128 128 teal
1324 # css differences
1325 128 128 128 css-gray
1326 128 128 128 css-grey
1327 0 128 0 css-green
1328 128 0 0 css-maroon
1329 128 0 128 css-purple