1 /**
2  * Color module for dcell.
3  *
4  * Copyright: Copyright 2025 Garrett D'Amore
5  * Authors: Garrett D'Amore
6  * License:
7  *   Distributed under the Boost Software License, Version 1.0.
8  *   (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt)
9  *   SPDX-License-Identifier: BSL-1.0
10  */
11 module dcell.color;
12 
13 import std.format;
14 import std.typecons;
15 
16 /**
17  * Color is a what you think, almost.
18  * However, the upper bits of the color are used to indicate special behaviors.
19  * If the value upper 24-bits are clear, then the value is an index into a
20  * palette (typically it should be less than 256).  If the isRGB bit is
21  * set, then the lower 24 bits are a 24-bit direct color (RGB).
22  */
23 enum Color : uint
24 {
25     invalid = 1 << 24, /// not a color (also means do not change color)
26     reset = invalid + 1, /// reset color to terminal defaults
27     isRGB = 1 << 31, /// indicates that the low 24-bits are red, green blue
28     black = 0,
29     maroon = 1,
30     green = 2,
31     olive = 3,
32     navy = 4,
33     purple = 5,
34     teal = 6,
35     silver = 7,
36     gray = 8,
37     red = 9,
38     lime = 10,
39     yellow = 11,
40     blue = 12,
41     fuchsia = 13,
42     aqua = 14,
43     white = 15,
44     // following colors are web named colors
45     aliceBlue = isRGB | 0xF0F8FF,
46     antiqueWhite = isRGB | 0xFAEBD7,
47     aquamarine = isRGB | 0x7FFFD4,
48     azure = isRGB | 0xF0FFFF,
49     beige = isRGB | 0xF5F5DC,
50     bisque = isRGB | 0xFFE4C4,
51     blanchedAlmond = isRGB | 0xFFEBCD,
52     blueViolet = isRGB | 0x8A2BE2,
53     brown = isRGB | 0xA52A2A,
54     burlyWood = isRGB | 0xDEB887,
55     cadetBlue = isRGB | 0x5F9EA0,
56     chartreuse = isRGB | 0x7FFF00,
57     chocolate = isRGB | 0xD2691E,
58     coral = isRGB | 0xFF7F50,
59     cornflowerBlue = isRGB | 0x6495ED,
60     cornsilk = isRGB | 0xFFF8DC,
61     crimson = isRGB | 0xDC143C,
62     darkBlue = isRGB | 0x00008B,
63     darkCyan = isRGB | 0x008B8B,
64     darkGoldenrod = isRGB | 0xB8860B,
65     darkGray = isRGB | 0xA9A9A9,
66     darkGreen = isRGB | 0x006400,
67     darkKhaki = isRGB | 0xBDB76B,
68     darkMagenta = isRGB | 0x8B008B,
69     darkOliveGreen = isRGB | 0x556B2F,
70     darkOrange = isRGB | 0xFF8C00,
71     darkOrchid = isRGB | 0x9932CC,
72     darkRed = isRGB | 0x8B0000,
73     darkSalmon = isRGB | 0xE9967A,
74     darkSeaGreen = isRGB | 0x8FBC8F,
75     darkSlateBlue = isRGB | 0x483D8B,
76     darkSlateGray = isRGB | 0x2F4F4F,
77     darkTurquoise = isRGB | 0x00CED1,
78     darkViolet = isRGB | 0x9400D3,
79     deepPink = isRGB | 0xFF1493,
80     deepSkyBlue = isRGB | 0x00BFFF,
81     dimGray = isRGB | 0x696969,
82     dodgerBlue = isRGB | 0x1E90FF,
83     fireBrick = isRGB | 0xB22222,
84     floralWhite = isRGB | 0xFFFAF0,
85     forestGreen = isRGB | 0x228B22,
86     gainsboro = isRGB | 0xDCDCDC,
87     ghostWhite = isRGB | 0xF8F8FF,
88     gold = isRGB | 0xFFD700,
89     goldenrod = isRGB | 0xDAA520,
90     greenYellow = isRGB | 0xADFF2F,
91     honeydew = isRGB | 0xF0FFF0,
92     hotPink = isRGB | 0xFF69B4,
93     indianRed = isRGB | 0xCD5C5C,
94     indigo = isRGB | 0x4B0082,
95     ivory = isRGB | 0xFFFFF0,
96     khaki = isRGB | 0xF0E68C,
97     lavender = isRGB | 0xE6E6FA,
98     lavenderBlush = isRGB | 0xFFF0F5,
99     lawnGreen = isRGB | 0x7CFC00,
100     lemonChiffon = isRGB | 0xFFFACD,
101     lightBlue = isRGB | 0xADD8E6,
102     lightCoral = isRGB | 0xF08080,
103     lightCyan = isRGB | 0xE0FFFF,
104     lightGoldenrodYellow = isRGB | 0xFAFAD2,
105     lightGray = isRGB | 0xD3D3D3,
106     lightGreen = isRGB | 0x90EE90,
107     lightPink = isRGB | 0xFFB6C1,
108     lightSalmon = isRGB | 0xFFA07A,
109     lightSeaGreen = isRGB | 0x20B2AA,
110     lightSkyBlue = isRGB | 0x87CEFA,
111     lightSlateGray = isRGB | 0x778899,
112     lightSteelBlue = isRGB | 0xB0C4DE,
113     lightYellow = isRGB | 0xFFFFE0,
114     limeGreen = isRGB | 0x32CD32,
115     linen = isRGB | 0xFAF0E6,
116     mediumAquamarine = isRGB | 0x66CDAA,
117     mediumBlue = isRGB | 0x0000CD,
118     mediumOrchid = isRGB | 0xBA55D3,
119     mediumPurple = isRGB | 0x9370DB,
120     mediumSeaGreen = isRGB | 0x3CB371,
121     mediumSlateBlue = isRGB | 0x7B68EE,
122     mediumSpringGreen = isRGB | 0x00FA9A,
123     mediumTurquoise = isRGB | 0x48D1CC,
124     mediumVioletRed = isRGB | 0xC71585,
125     midnightBlue = isRGB | 0x191970,
126     mintCream = isRGB | 0xF5FFFA,
127     mistyRose = isRGB | 0xFFE4E1,
128     moccasin = isRGB | 0xFFE4B5,
129     navajoWhite = isRGB | 0xFFDEAD,
130     oldLace = isRGB | 0xFDF5E6,
131     oliveDrab = isRGB | 0x6B8E23,
132     orange = isRGB | 0xFFA500,
133     orangeRed = isRGB | 0xFF4500,
134     orchid = isRGB | 0xDA70D6,
135     paleGoldenrod = isRGB | 0xEEE8AA,
136     paleGreen = isRGB | 0x98FB98,
137     paleTurquoise = isRGB | 0xAFEEEE,
138     paleVioletRed = isRGB | 0xDB7093,
139     papayaWhip = isRGB | 0xFFEFD5,
140     peachPuff = isRGB | 0xFFDAB9,
141     peru = isRGB | 0xCD853F,
142     pink = isRGB | 0xFFC0CB,
143     plum = isRGB | 0xDDA0DD,
144     powderBlue = isRGB | 0xB0E0E6,
145     rebeccaPurple = isRGB | 0x663399,
146     rosyBrown = isRGB | 0xBC8F8F,
147     royalBlue = isRGB | 0x4169E1,
148     saddleBrown = isRGB | 0x8B4513,
149     salmon = isRGB | 0xFA8072,
150     sandyBrown = isRGB | 0xF4A460,
151     seaGreen = isRGB | 0x2E8B57,
152     seashell = isRGB | 0xFFF5EE,
153     sienna = isRGB | 0xA0522D,
154     skyBlue = isRGB | 0x87CEEB,
155     slateBlue = isRGB | 0x6A5ACD,
156     slateGray = isRGB | 0x708090,
157     snow = isRGB | 0xFFFAFA,
158     springGreen = isRGB | 0x00FF7F,
159     steelBlue = isRGB | 0x4682B4,
160     tan = isRGB | 0xD2B48C,
161     thistle = isRGB | 0xD8BFD8,
162     tomato = isRGB | 0xFF6347,
163     turquoise = isRGB | 0x40E0D0,
164     violet = isRGB | 0xEE82EE,
165     wheat = isRGB | 0xF5DEB3,
166     whiteSmoke = isRGB | 0xF5F5F5,
167     yellowGreen = isRGB | 0x9ACD32,
168     init = invalid,
169 }
170 
171 private static immutable uint[Color] rgbValues;
172 private static immutable Color[uint] palValues;
173 
174 shared static this() @safe
175 {
176     rgbValues[Color.black] = 0x000000;
177     rgbValues[Color.maroon] = 0x800000;
178     rgbValues[Color.green] = 0x008000;
179     rgbValues[Color.olive] = 0x808000;
180     rgbValues[Color.navy] = 0x000080;
181     rgbValues[Color.purple] = 0x800080;
182     rgbValues[Color.teal] = 0x008080;
183     rgbValues[Color.silver] = 0xC0C0C0;
184     rgbValues[Color.gray] = 0x808080;
185     rgbValues[Color.red] = 0xFF0000;
186     rgbValues[Color.lime] = 0x00FF00;
187     rgbValues[Color.yellow] = 0xFFFF00;
188     rgbValues[Color.blue] = 0x0000FF;
189     rgbValues[Color.fuchsia] = 0xFF00FF;
190     rgbValues[Color.aqua] = 0x00FFFF;
191     rgbValues[Color.white] = 0xFFFFFF;
192     // 256 color extended palette
193     rgbValues[cast(Color) 16] = 0x000000; // black
194     rgbValues[cast(Color) 17] = 0x00005F;
195     rgbValues[cast(Color) 18] = 0x000087;
196     rgbValues[cast(Color) 19] = 0x0000AF;
197     rgbValues[cast(Color) 20] = 0x0000D7;
198     rgbValues[cast(Color) 21] = 0x0000FF; // blue
199     rgbValues[cast(Color) 22] = 0x005F00;
200     rgbValues[cast(Color) 23] = 0x005F5F;
201     rgbValues[cast(Color) 24] = 0x005F87;
202     rgbValues[cast(Color) 25] = 0x005FAF;
203     rgbValues[cast(Color) 26] = 0x005FD7;
204     rgbValues[cast(Color) 27] = 0x005FFF;
205     rgbValues[cast(Color) 28] = 0x008700;
206     rgbValues[cast(Color) 29] = 0x00875F;
207     rgbValues[cast(Color) 30] = 0x008787;
208     rgbValues[cast(Color) 31] = 0x0087Af;
209     rgbValues[cast(Color) 32] = 0x0087D7;
210     rgbValues[cast(Color) 33] = 0x0087FF;
211     rgbValues[cast(Color) 34] = 0x00AF00;
212     rgbValues[cast(Color) 35] = 0x00AF5F;
213     rgbValues[cast(Color) 36] = 0x00AF87;
214     rgbValues[cast(Color) 37] = 0x00AFAF;
215     rgbValues[cast(Color) 38] = 0x00AFD7;
216     rgbValues[cast(Color) 39] = 0x00AFFF;
217     rgbValues[cast(Color) 40] = 0x00D700;
218     rgbValues[cast(Color) 41] = 0x00D75F;
219     rgbValues[cast(Color) 42] = 0x00D787;
220     rgbValues[cast(Color) 43] = 0x00D7AF;
221     rgbValues[cast(Color) 44] = 0x00D7D7;
222     rgbValues[cast(Color) 45] = 0x00D7FF;
223     rgbValues[cast(Color) 46] = 0x00FF00; // lime
224     rgbValues[cast(Color) 47] = 0x00FF5F;
225     rgbValues[cast(Color) 48] = 0x00FF87;
226     rgbValues[cast(Color) 49] = 0x00FFAF;
227     rgbValues[cast(Color) 50] = 0x00FFd7;
228     rgbValues[cast(Color) 51] = 0x00FFFF; // aqua
229     rgbValues[cast(Color) 52] = 0x5F0000;
230     rgbValues[cast(Color) 53] = 0x5F005F;
231     rgbValues[cast(Color) 54] = 0x5F0087;
232     rgbValues[cast(Color) 55] = 0x5F00AF;
233     rgbValues[cast(Color) 56] = 0x5F00D7;
234     rgbValues[cast(Color) 57] = 0x5F00FF;
235     rgbValues[cast(Color) 58] = 0x5F5F00;
236     rgbValues[cast(Color) 59] = 0x5F5F5F;
237     rgbValues[cast(Color) 60] = 0x5F5F87;
238     rgbValues[cast(Color) 61] = 0x5F5FAF;
239     rgbValues[cast(Color) 62] = 0x5F5FD7;
240     rgbValues[cast(Color) 63] = 0x5F5FFF;
241     rgbValues[cast(Color) 64] = 0x5F8700;
242     rgbValues[cast(Color) 65] = 0x5F875F;
243     rgbValues[cast(Color) 66] = 0x5F8787;
244     rgbValues[cast(Color) 67] = 0x5F87AF;
245     rgbValues[cast(Color) 68] = 0x5F87D7;
246     rgbValues[cast(Color) 69] = 0x5F87FF;
247     rgbValues[cast(Color) 70] = 0x5FAF00;
248     rgbValues[cast(Color) 71] = 0x5FAF5F;
249     rgbValues[cast(Color) 72] = 0x5FAF87;
250     rgbValues[cast(Color) 73] = 0x5FAFAF;
251     rgbValues[cast(Color) 74] = 0x5FAFD7;
252     rgbValues[cast(Color) 75] = 0x5FAFFF;
253     rgbValues[cast(Color) 76] = 0x5FD700;
254     rgbValues[cast(Color) 77] = 0x5FD75F;
255     rgbValues[cast(Color) 78] = 0x5FD787;
256     rgbValues[cast(Color) 79] = 0x5FD7AF;
257     rgbValues[cast(Color) 80] = 0x5FD7D7;
258     rgbValues[cast(Color) 81] = 0x5FD7FF;
259     rgbValues[cast(Color) 82] = 0x5FFF00;
260     rgbValues[cast(Color) 83] = 0x5FFF5F;
261     rgbValues[cast(Color) 84] = 0x5FFF87;
262     rgbValues[cast(Color) 85] = 0x5FFFAF;
263     rgbValues[cast(Color) 86] = 0x5FFFD7;
264     rgbValues[cast(Color) 87] = 0x5FFFFF;
265     rgbValues[cast(Color) 88] = 0x870000;
266     rgbValues[cast(Color) 89] = 0x87005F;
267     rgbValues[cast(Color) 90] = 0x870087;
268     rgbValues[cast(Color) 91] = 0x8700AF;
269     rgbValues[cast(Color) 92] = 0x8700D7;
270     rgbValues[cast(Color) 93] = 0x8700FF;
271     rgbValues[cast(Color) 94] = 0x875F00;
272     rgbValues[cast(Color) 95] = 0x875F5F;
273     rgbValues[cast(Color) 96] = 0x875F87;
274     rgbValues[cast(Color) 97] = 0x875FAF;
275     rgbValues[cast(Color) 98] = 0x875FD7;
276     rgbValues[cast(Color) 99] = 0x875FFF;
277     rgbValues[cast(Color) 100] = 0x878700;
278     rgbValues[cast(Color) 101] = 0x87875F;
279     rgbValues[cast(Color) 102] = 0x878787;
280     rgbValues[cast(Color) 103] = 0x8787AF;
281     rgbValues[cast(Color) 104] = 0x8787D7;
282     rgbValues[cast(Color) 105] = 0x8787FF;
283     rgbValues[cast(Color) 106] = 0x87AF00;
284     rgbValues[cast(Color) 107] = 0x87AF5F;
285     rgbValues[cast(Color) 108] = 0x87AF87;
286     rgbValues[cast(Color) 109] = 0x87AFAF;
287     rgbValues[cast(Color) 110] = 0x87AFD7;
288     rgbValues[cast(Color) 111] = 0x87AFFF;
289     rgbValues[cast(Color) 112] = 0x87D700;
290     rgbValues[cast(Color) 113] = 0x87D75F;
291     rgbValues[cast(Color) 114] = 0x87D787;
292     rgbValues[cast(Color) 115] = 0x87D7AF;
293     rgbValues[cast(Color) 116] = 0x87D7D7;
294     rgbValues[cast(Color) 117] = 0x87D7FF;
295     rgbValues[cast(Color) 118] = 0x87FF00;
296     rgbValues[cast(Color) 119] = 0x87FF5F;
297     rgbValues[cast(Color) 120] = 0x87FF87;
298     rgbValues[cast(Color) 121] = 0x87FFAF;
299     rgbValues[cast(Color) 122] = 0x87FFD7;
300     rgbValues[cast(Color) 123] = 0x87FFFF;
301     rgbValues[cast(Color) 124] = 0xAF0000;
302     rgbValues[cast(Color) 125] = 0xAF005F;
303     rgbValues[cast(Color) 126] = 0xAF0087;
304     rgbValues[cast(Color) 127] = 0xAF00AF;
305     rgbValues[cast(Color) 128] = 0xAF00D7;
306     rgbValues[cast(Color) 129] = 0xAF00FF;
307     rgbValues[cast(Color) 130] = 0xAF5F00;
308     rgbValues[cast(Color) 131] = 0xAF5F5F;
309     rgbValues[cast(Color) 132] = 0xAF5F87;
310     rgbValues[cast(Color) 133] = 0xAF5FAF;
311     rgbValues[cast(Color) 134] = 0xAF5FD7;
312     rgbValues[cast(Color) 135] = 0xAF5FFF;
313     rgbValues[cast(Color) 136] = 0xAF8700;
314     rgbValues[cast(Color) 137] = 0xAF875F;
315     rgbValues[cast(Color) 138] = 0xAF8787;
316     rgbValues[cast(Color) 139] = 0xAF87AF;
317     rgbValues[cast(Color) 140] = 0xAF87D7;
318     rgbValues[cast(Color) 141] = 0xAF87FF;
319     rgbValues[cast(Color) 142] = 0xAFAF00;
320     rgbValues[cast(Color) 143] = 0xAFAF5F;
321     rgbValues[cast(Color) 144] = 0xAFAF87;
322     rgbValues[cast(Color) 145] = 0xAFAFAF;
323     rgbValues[cast(Color) 146] = 0xAFAFD7;
324     rgbValues[cast(Color) 147] = 0xAFAFFF;
325     rgbValues[cast(Color) 148] = 0xAFD700;
326     rgbValues[cast(Color) 149] = 0xAFD75F;
327     rgbValues[cast(Color) 150] = 0xAFD787;
328     rgbValues[cast(Color) 151] = 0xAFD7AF;
329     rgbValues[cast(Color) 152] = 0xAFD7D7;
330     rgbValues[cast(Color) 153] = 0xAFD7FF;
331     rgbValues[cast(Color) 154] = 0xAFFF00;
332     rgbValues[cast(Color) 155] = 0xAFFF5F;
333     rgbValues[cast(Color) 156] = 0xAFFF87;
334     rgbValues[cast(Color) 157] = 0xAFFFAF;
335     rgbValues[cast(Color) 158] = 0xAFFFD7;
336     rgbValues[cast(Color) 159] = 0xAFFFFF;
337     rgbValues[cast(Color) 160] = 0xD70000;
338     rgbValues[cast(Color) 161] = 0xD7005F;
339     rgbValues[cast(Color) 162] = 0xD70087;
340     rgbValues[cast(Color) 163] = 0xD700AF;
341     rgbValues[cast(Color) 164] = 0xD700D7;
342     rgbValues[cast(Color) 165] = 0xD700FF;
343     rgbValues[cast(Color) 166] = 0xD75F00;
344     rgbValues[cast(Color) 167] = 0xD75F5F;
345     rgbValues[cast(Color) 168] = 0xD75F87;
346     rgbValues[cast(Color) 169] = 0xD75FAF;
347     rgbValues[cast(Color) 170] = 0xD75FD7;
348     rgbValues[cast(Color) 171] = 0xD75FFF;
349     rgbValues[cast(Color) 172] = 0xD78700;
350     rgbValues[cast(Color) 173] = 0xD7875F;
351     rgbValues[cast(Color) 174] = 0xD78787;
352     rgbValues[cast(Color) 175] = 0xD787AF;
353     rgbValues[cast(Color) 176] = 0xD787D7;
354     rgbValues[cast(Color) 177] = 0xD787FF;
355     rgbValues[cast(Color) 178] = 0xD7AF00;
356     rgbValues[cast(Color) 179] = 0xD7AF5F;
357     rgbValues[cast(Color) 180] = 0xD7AF87;
358     rgbValues[cast(Color) 181] = 0xD7AFAF;
359     rgbValues[cast(Color) 182] = 0xD7AFD7;
360     rgbValues[cast(Color) 183] = 0xD7AFFF;
361     rgbValues[cast(Color) 184] = 0xD7D700;
362     rgbValues[cast(Color) 185] = 0xD7D75F;
363     rgbValues[cast(Color) 186] = 0xD7D787;
364     rgbValues[cast(Color) 187] = 0xD7D7AF;
365     rgbValues[cast(Color) 188] = 0xD7D7D7;
366     rgbValues[cast(Color) 189] = 0xD7D7FF;
367     rgbValues[cast(Color) 190] = 0xD7FF00;
368     rgbValues[cast(Color) 191] = 0xD7FF5F;
369     rgbValues[cast(Color) 192] = 0xD7FF87;
370     rgbValues[cast(Color) 193] = 0xD7FFAF;
371     rgbValues[cast(Color) 194] = 0xD7FFD7;
372     rgbValues[cast(Color) 195] = 0xD7FFFF;
373     rgbValues[cast(Color) 196] = 0xFF0000; // red
374     rgbValues[cast(Color) 197] = 0xFF005F;
375     rgbValues[cast(Color) 198] = 0xFF0087;
376     rgbValues[cast(Color) 199] = 0xFF00AF;
377     rgbValues[cast(Color) 200] = 0xFF00D7;
378     rgbValues[cast(Color) 201] = 0xFF00FF; // fuchsia
379     rgbValues[cast(Color) 202] = 0xFF5F00;
380     rgbValues[cast(Color) 203] = 0xFF5F5F;
381     rgbValues[cast(Color) 204] = 0xFF5F87;
382     rgbValues[cast(Color) 205] = 0xFF5FAF;
383     rgbValues[cast(Color) 206] = 0xFF5FD7;
384     rgbValues[cast(Color) 207] = 0xFF5FFF;
385     rgbValues[cast(Color) 208] = 0xFF8700;
386     rgbValues[cast(Color) 209] = 0xFF875F;
387     rgbValues[cast(Color) 210] = 0xFF8787;
388     rgbValues[cast(Color) 211] = 0xFF87AF;
389     rgbValues[cast(Color) 212] = 0xFF87D7;
390     rgbValues[cast(Color) 213] = 0xFF87FF;
391     rgbValues[cast(Color) 214] = 0xFFAF00;
392     rgbValues[cast(Color) 215] = 0xFFAF5F;
393     rgbValues[cast(Color) 216] = 0xFFAF87;
394     rgbValues[cast(Color) 217] = 0xFFAFAF;
395     rgbValues[cast(Color) 218] = 0xFFAFD7;
396     rgbValues[cast(Color) 219] = 0xFFAFFF;
397     rgbValues[cast(Color) 220] = 0xFFD700;
398     rgbValues[cast(Color) 221] = 0xFFD75F;
399     rgbValues[cast(Color) 222] = 0xFFD787;
400     rgbValues[cast(Color) 223] = 0xFFD7AF;
401     rgbValues[cast(Color) 224] = 0xFFD7D7;
402     rgbValues[cast(Color) 225] = 0xFFD7FF;
403     rgbValues[cast(Color) 226] = 0xFFFF00; // yellow
404     rgbValues[cast(Color) 227] = 0xFFFF5F;
405     rgbValues[cast(Color) 228] = 0xFFFF87;
406     rgbValues[cast(Color) 229] = 0xFFFFAF;
407     rgbValues[cast(Color) 230] = 0xFFFFD7;
408     rgbValues[cast(Color) 231] = 0xFFFFFF; // white
409     rgbValues[cast(Color) 232] = 0x080808;
410     rgbValues[cast(Color) 233] = 0x121212;
411     rgbValues[cast(Color) 234] = 0x1C1C1C;
412     rgbValues[cast(Color) 235] = 0x262626;
413     rgbValues[cast(Color) 236] = 0x303030;
414     rgbValues[cast(Color) 237] = 0x3A3A3A;
415     rgbValues[cast(Color) 238] = 0x444444;
416     rgbValues[cast(Color) 239] = 0x4E4E4E;
417     rgbValues[cast(Color) 240] = 0x585858;
418     rgbValues[cast(Color) 241] = 0x626262;
419     rgbValues[cast(Color) 242] = 0x6C6C6C;
420     rgbValues[cast(Color) 243] = 0x767676;
421     rgbValues[cast(Color) 244] = 0x808080; // grey
422     rgbValues[cast(Color) 245] = 0x8A8A8A;
423     rgbValues[cast(Color) 246] = 0x949494;
424     rgbValues[cast(Color) 247] = 0x9E9E9E;
425     rgbValues[cast(Color) 248] = 0xA8A8A8;
426     rgbValues[cast(Color) 249] = 0xB2B2B2;
427     rgbValues[cast(Color) 250] = 0xBCBCBC;
428     rgbValues[cast(Color) 251] = 0xC6C6C6;
429     rgbValues[cast(Color) 252] = 0xD0D0D0;
430     rgbValues[cast(Color) 253] = 0xDADADA;
431     rgbValues[cast(Color) 254] = 0xE4E4E4;
432     rgbValues[cast(Color) 255] = 0xEEEEEE;
433 
434     palValues[0x000000] = Color.black;
435     palValues[0x800000] = Color.maroon;
436     palValues[0x008000] = Color.green;
437     palValues[0x808000] = Color.olive;
438     palValues[0x000080] = Color.navy;
439     palValues[0x800080] = Color.purple;
440     palValues[0x008080] = Color.teal;
441     palValues[0xC0C0C0] = Color.silver;
442     palValues[0x808080] = Color.gray;
443     palValues[0xFF0000] = Color.red;
444     palValues[0x00FF00] = Color.lime;
445     palValues[0xFFFF00] = Color.yellow;
446     palValues[0x0000FF] = Color.blue;
447     palValues[0xFF00FF] = Color.fuchsia;
448     palValues[0x00FFFF] = Color.aqua;
449     palValues[0xFFFFFF] = Color.white;
450     // palValues[0x000000] = cast(Color) 16; // black
451     palValues[0x00005F] = cast(Color) 17;
452     palValues[0x000087] = cast(Color) 18;
453     palValues[0x0000AF] = cast(Color) 19;
454     palValues[0x0000D7] = cast(Color) 20;
455     // palValues[0x0000FF] = cast(Color) 21; // blue
456     palValues[0x005F00] = cast(Color) 22;
457     palValues[0x005F5F] = cast(Color) 23;
458     palValues[0x005F87] = cast(Color) 24;
459     palValues[0x005FAF] = cast(Color) 25;
460     palValues[0x005FD7] = cast(Color) 26;
461     palValues[0x005FFF] = cast(Color) 27;
462     palValues[0x008700] = cast(Color) 28;
463     palValues[0x00875F] = cast(Color) 29;
464     palValues[0x008787] = cast(Color) 30;
465     palValues[0x0087Af] = cast(Color) 31;
466     palValues[0x0087D7] = cast(Color) 32;
467     palValues[0x0087FF] = cast(Color) 33;
468     palValues[0x00AF00] = cast(Color) 34;
469     palValues[0x00AF5F] = cast(Color) 35;
470     palValues[0x00AF87] = cast(Color) 36;
471     palValues[0x00AFAF] = cast(Color) 37;
472     palValues[0x00AFD7] = cast(Color) 38;
473     palValues[0x00AFFF] = cast(Color) 39;
474     palValues[0x00D700] = cast(Color) 40;
475     palValues[0x00D75F] = cast(Color) 41;
476     palValues[0x00D787] = cast(Color) 42;
477     palValues[0x00D7AF] = cast(Color) 43;
478     palValues[0x00D7D7] = cast(Color) 44;
479     palValues[0x00D7FF] = cast(Color) 45;
480     // palValues[0x00FF00] = cast(Color) 46; // lime
481     palValues[0x00FF5F] = cast(Color) 47;
482     palValues[0x00FF87] = cast(Color) 48;
483     palValues[0x00FFAF] = cast(Color) 49;
484     palValues[0x00FFd7] = cast(Color) 50;
485     // palValues[0x00FFFF] = cast(Color) 51; // aqua
486     palValues[0x5F0000] = cast(Color) 52;
487     palValues[0x5F005F] = cast(Color) 53;
488     palValues[0x5F0087] = cast(Color) 54;
489     palValues[0x5F00AF] = cast(Color) 55;
490     palValues[0x5F00D7] = cast(Color) 56;
491     palValues[0x5F00FF] = cast(Color) 57;
492     palValues[0x5F5F00] = cast(Color) 58;
493     palValues[0x5F5F5F] = cast(Color) 59;
494     palValues[0x5F5F87] = cast(Color) 60;
495     palValues[0x5F5FAF] = cast(Color) 61;
496     palValues[0x5F5FD7] = cast(Color) 62;
497     palValues[0x5F5FFF] = cast(Color) 63;
498     palValues[0x5F8700] = cast(Color) 64;
499     palValues[0x5F875F] = cast(Color) 65;
500     palValues[0x5F8787] = cast(Color) 66;
501     palValues[0x5F87AF] = cast(Color) 67;
502     palValues[0x5F87D7] = cast(Color) 68;
503     palValues[0x5F87FF] = cast(Color) 69;
504     palValues[0x5FAF00] = cast(Color) 70;
505     palValues[0x5FAF5F] = cast(Color) 71;
506     palValues[0x5FAF87] = cast(Color) 72;
507     palValues[0x5FAFAF] = cast(Color) 73;
508     palValues[0x5FAFD7] = cast(Color) 74;
509     palValues[0x5FAFFF] = cast(Color) 75;
510     palValues[0x5FD700] = cast(Color) 76;
511     palValues[0x5FD75F] = cast(Color) 77;
512     palValues[0x5FD787] = cast(Color) 78;
513     palValues[0x5FD7AF] = cast(Color) 79;
514     palValues[0x5FD7D7] = cast(Color) 80;
515     palValues[0x5FD7FF] = cast(Color) 81;
516     palValues[0x5FFF00] = cast(Color) 82;
517     palValues[0x5FFF5F] = cast(Color) 83;
518     palValues[0x5FFF87] = cast(Color) 84;
519     palValues[0x5FFFAF] = cast(Color) 85;
520     palValues[0x5FFFD7] = cast(Color) 86;
521     palValues[0x5FFFFF] = cast(Color) 87;
522     palValues[0x870000] = cast(Color) 88;
523     palValues[0x87005F] = cast(Color) 89;
524     palValues[0x870087] = cast(Color) 90;
525     palValues[0x8700AF] = cast(Color) 91;
526     palValues[0x8700D7] = cast(Color) 92;
527     palValues[0x8700FF] = cast(Color) 93;
528     palValues[0x875F00] = cast(Color) 94;
529     palValues[0x875F5F] = cast(Color) 95;
530     palValues[0x875F87] = cast(Color) 96;
531     palValues[0x875FAF] = cast(Color) 97;
532     palValues[0x875FD7] = cast(Color) 98;
533     palValues[0x875FFF] = cast(Color) 99;
534     palValues[0x878700] = cast(Color) 100;
535     palValues[0x87875F] = cast(Color) 101;
536     palValues[0x878787] = cast(Color) 102;
537     palValues[0x8787AF] = cast(Color) 103;
538     palValues[0x8787D7] = cast(Color) 104;
539     palValues[0x8787FF] = cast(Color) 105;
540     palValues[0x87AF00] = cast(Color) 106;
541     palValues[0x87AF5F] = cast(Color) 107;
542     palValues[0x87AF87] = cast(Color) 108;
543     palValues[0x87AFAF] = cast(Color) 109;
544     palValues[0x87AFD7] = cast(Color) 110;
545     palValues[0x87AFFF] = cast(Color) 111;
546     palValues[0x87D700] = cast(Color) 112;
547     palValues[0x87D75F] = cast(Color) 113;
548     palValues[0x87D787] = cast(Color) 114;
549     palValues[0x87D7AF] = cast(Color) 115;
550     palValues[0x87D7D7] = cast(Color) 116;
551     palValues[0x87D7FF] = cast(Color) 117;
552     palValues[0x87FF00] = cast(Color) 118;
553     palValues[0x87FF5F] = cast(Color) 119;
554     palValues[0x87FF87] = cast(Color) 120;
555     palValues[0x87FFAF] = cast(Color) 121;
556     palValues[0x87FFD7] = cast(Color) 122;
557     palValues[0x87FFFF] = cast(Color) 123;
558     palValues[0xAF0000] = cast(Color) 124;
559     palValues[0xAF005F] = cast(Color) 125;
560     palValues[0xAF0087] = cast(Color) 126;
561     palValues[0xAF00AF] = cast(Color) 127;
562     palValues[0xAF00D7] = cast(Color) 128;
563     palValues[0xAF00FF] = cast(Color) 129;
564     palValues[0xAF5F00] = cast(Color) 130;
565     palValues[0xAF5F5F] = cast(Color) 131;
566     palValues[0xAF5F87] = cast(Color) 132;
567     palValues[0xAF5FAF] = cast(Color) 133;
568     palValues[0xAF5FD7] = cast(Color) 134;
569     palValues[0xAF5FFF] = cast(Color) 135;
570     palValues[0xAF8700] = cast(Color) 136;
571     palValues[0xAF875F] = cast(Color) 137;
572     palValues[0xAF8787] = cast(Color) 138;
573     palValues[0xAF87AF] = cast(Color) 139;
574     palValues[0xAF87D7] = cast(Color) 140;
575     palValues[0xAF87FF] = cast(Color) 141;
576     palValues[0xAFAF00] = cast(Color) 142;
577     palValues[0xAFAF5F] = cast(Color) 143;
578     palValues[0xAFAF87] = cast(Color) 144;
579     palValues[0xAFAFAF] = cast(Color) 145;
580     palValues[0xAFAFD7] = cast(Color) 146;
581     palValues[0xAFAFFF] = cast(Color) 147;
582     palValues[0xAFD700] = cast(Color) 148;
583     palValues[0xAFD75F] = cast(Color) 149;
584     palValues[0xAFD787] = cast(Color) 150;
585     palValues[0xAFD7AF] = cast(Color) 151;
586     palValues[0xAFD7D7] = cast(Color) 152;
587     palValues[0xAFD7FF] = cast(Color) 153;
588     palValues[0xAFFF00] = cast(Color) 154;
589     palValues[0xAFFF5F] = cast(Color) 155;
590     palValues[0xAFFF87] = cast(Color) 156;
591     palValues[0xAFFFAF] = cast(Color) 157;
592     palValues[0xAFFFD7] = cast(Color) 158;
593     palValues[0xAFFFFF] = cast(Color) 159;
594     palValues[0xD70000] = cast(Color) 160;
595     palValues[0xD7005F] = cast(Color) 161;
596     palValues[0xD70087] = cast(Color) 162;
597     palValues[0xD700AF] = cast(Color) 163;
598     palValues[0xD700D7] = cast(Color) 164;
599     palValues[0xD700FF] = cast(Color) 165;
600     palValues[0xD75F00] = cast(Color) 166;
601     palValues[0xD75F5F] = cast(Color) 167;
602     palValues[0xD75F87] = cast(Color) 168;
603     palValues[0xD75FAF] = cast(Color) 169;
604     palValues[0xD75FD7] = cast(Color) 170;
605     palValues[0xD75FFF] = cast(Color) 171;
606     palValues[0xD78700] = cast(Color) 172;
607     palValues[0xD7875F] = cast(Color) 173;
608     palValues[0xD78787] = cast(Color) 174;
609     palValues[0xD787AF] = cast(Color) 175;
610     palValues[0xD787D7] = cast(Color) 176;
611     palValues[0xD787FF] = cast(Color) 177;
612     palValues[0xD7AF00] = cast(Color) 178;
613     palValues[0xD7AF5F] = cast(Color) 179;
614     palValues[0xD7AF87] = cast(Color) 180;
615     palValues[0xD7AFAF] = cast(Color) 181;
616     palValues[0xD7AFD7] = cast(Color) 182;
617     palValues[0xD7AFFF] = cast(Color) 183;
618     palValues[0xD7D700] = cast(Color) 184;
619     palValues[0xD7D75F] = cast(Color) 185;
620     palValues[0xD7D787] = cast(Color) 186;
621     palValues[0xD7D7AF] = cast(Color) 187;
622     palValues[0xD7D7D7] = cast(Color) 188;
623     palValues[0xD7D7FF] = cast(Color) 189;
624     palValues[0xD7FF00] = cast(Color) 190;
625     palValues[0xD7FF5F] = cast(Color) 191;
626     palValues[0xD7FF87] = cast(Color) 192;
627     palValues[0xD7FFAF] = cast(Color) 193;
628     palValues[0xD7FFD7] = cast(Color) 194;
629     palValues[0xD7FFFF] = cast(Color) 195;
630     // palValues[0xFF0000] = cast(Color) 196; // red
631     palValues[0xFF005F] = cast(Color) 197;
632     palValues[0xFF0087] = cast(Color) 198;
633     palValues[0xFF00AF] = cast(Color) 199;
634     palValues[0xFF00D7] = cast(Color) 200;
635     // palValues[0xFF00FF] = cast(Color) 201; // fuchsia
636     palValues[0xFF5F00] = cast(Color) 202;
637     palValues[0xFF5F5F] = cast(Color) 203;
638     palValues[0xFF5F87] = cast(Color) 204;
639     palValues[0xFF5FAF] = cast(Color) 205;
640     palValues[0xFF5FD7] = cast(Color) 206;
641     palValues[0xFF5FFF] = cast(Color) 207;
642     palValues[0xFF8700] = cast(Color) 208;
643     palValues[0xFF875F] = cast(Color) 209;
644     palValues[0xFF8787] = cast(Color) 210;
645     palValues[0xFF87AF] = cast(Color) 211;
646     palValues[0xFF87D7] = cast(Color) 212;
647     palValues[0xFF87FF] = cast(Color) 213;
648     palValues[0xFFAF00] = cast(Color) 214;
649     palValues[0xFFAF5F] = cast(Color) 215;
650     palValues[0xFFAF87] = cast(Color) 216;
651     palValues[0xFFAFAF] = cast(Color) 217;
652     palValues[0xFFAFD7] = cast(Color) 218;
653     palValues[0xFFAFFF] = cast(Color) 219;
654     palValues[0xFFD700] = cast(Color) 220;
655     palValues[0xFFD75F] = cast(Color) 221;
656     palValues[0xFFD787] = cast(Color) 222;
657     palValues[0xFFD7AF] = cast(Color) 223;
658     palValues[0xFFD7D7] = cast(Color) 224;
659     palValues[0xFFD7FF] = cast(Color) 225;
660     // palValues[0xFFFF00] = cast(Color) 226; // yellow
661     palValues[0xFFFF5F] = cast(Color) 227;
662     palValues[0xFFFF87] = cast(Color) 228;
663     palValues[0xFFFFAF] = cast(Color) 229;
664     palValues[0xFFFFD7] = cast(Color) 230;
665     // palValues[0xFFFFFF] = cast(Color) 231; // white
666     palValues[0x080808] = cast(Color) 232;
667     palValues[0x121212] = cast(Color) 233;
668     palValues[0x1C1C1C] = cast(Color) 234;
669     palValues[0x262626] = cast(Color) 235;
670     palValues[0x303030] = cast(Color) 236;
671     palValues[0x3A3A3A] = cast(Color) 237;
672     palValues[0x444444] = cast(Color) 238;
673     palValues[0x4E4E4E] = cast(Color) 239;
674     palValues[0x585858] = cast(Color) 240;
675     palValues[0x626262] = cast(Color) 241;
676     palValues[0x6C6C6C] = cast(Color) 242;
677     palValues[0x767676] = cast(Color) 243;
678     // palValues[0x808080] = cast(Color) 244; // grey
679     palValues[0x8A8A8A] = cast(Color) 245;
680     palValues[0x949494] = cast(Color) 246;
681     palValues[0x9E9E9E] = cast(Color) 247;
682     palValues[0xA8A8A8] = cast(Color) 248;
683     palValues[0xB2B2B2] = cast(Color) 249;
684     palValues[0xBCBCBC] = cast(Color) 250;
685     palValues[0xC6C6C6] = cast(Color) 251;
686     palValues[0xD0D0D0] = cast(Color) 252;
687     palValues[0xDADADA] = cast(Color) 253;
688     palValues[0xE4E4E4] = cast(Color) 254;
689     palValues[0xEEEEEE] = cast(Color) 255;
690 }
691 
692 /**
693  * Obtain the numeric value of the RGB for the color.
694  *
695  * Params:
696  *  c = a Color
697  * Returns: Numeric RGB value for color, or -1 if it cannot be represented.
698  */
699 int toHex(Color c) pure @safe
700 {
701     if ((c & Color.isRGB) != 0)
702     {
703         return (c & 0xffffff);
704     }
705     if (c in rgbValues)
706     {
707         return rgbValues[c];
708     }
709     return (-1);
710 }
711 
712 /**
713  * Create a color from RGB values.
714  *
715  * Params:
716  *   rgb = hex value, red << 16 | green << 8 | blue
717  * Returns: The associated Color, or Color.invalid if a bad value for rgb was supplied.
718  */
719 Color fromHex(int rgb) pure @safe
720 {
721     if (rgb < 1 << 24)
722     {
723         return cast(Color) rgb | Color.isRGB;
724     }
725     return Color.invalid;
726 }
727 
728 /**
729  * Convert a color to RGB form.  This is useful to convert
730  * palette based colors to their full RGB values, which will provide
731  * fidelity when the terminal supports it, but consequently does not
732  * honor terminal preferences for color palettes.
733  *
734  * Params:
735  *   c = a valid Color
736  * Returns: An RGB format Color, Color.invalid if it cannot be determined.
737  */
738 Color toRGB(Color c) pure @safe
739 {
740     if ((c & Color.isRGB) != 0)
741     {
742         return c;
743     }
744     if (c in rgbValues)
745     {
746         return cast(Color) rgbValues[c] | Color.isRGB;
747     }
748     return Color.invalid;
749 }
750 
751 /**
752  * Is the color in RGB format? RGB format colors will try to be accurate
753  * on the terminal, and will not honor user preferences.
754  * Params:
755  *   c = a valid color
756  * Returns: true if the color is an RGB format color
757  */
758 bool isRGB(Color c) pure @safe
759 {
760     return (c & Color.isRGB) != 0;
761 }
762 
763 /// Return true if the color is valid.
764 bool isValid(Color c) pure @safe
765 {
766     return (c != Color.invalid);
767 }
768 
769 /**
770  * Given a color, try to find an associated palette entry for it.
771  * This will try to find the lowest numbered palette entry.
772  * The palette entry might be a higher numbered color than the
773  * terminal can support, if it does not support a 256 color palette.
774  *
775  * Params:
776  *   c = a valid Color
777  *   numColors = the size of the palette
778  *
779  * Returns: the palette Color closest matching c
780  */
781 Color toPalette(Color c, int numColors) @safe
782 {
783     import std.functional;
784 
785     switch (c)
786     {
787     case Color.reset, Color.invalid:
788         return c;
789     default:
790         return memoize!bestColor(c, numColors);
791     }
792 }
793 
794 /// Return true if c1 is darker than c2.
795 bool darker(Color c1, Color c2) @safe
796 {
797     import std.functional;
798 
799     auto d1 = memoize!redMean(c1, Color.black);
800     auto d2 = memoize!redMean(c2, Color.black);
801     return (d1 < d2);
802 }
803 
804 /**
805  * decompose a color into red, green, and blue values.
806  */
807 auto decompose(Color c) pure @safe
808 {
809     c = toRGB(c);
810     return Tuple!(int, int, int)((c & 0xff0000) >> 16, ((c & 0xff00) >> 8), (c & 0xff));
811 }
812 
813 /**
814  * decompose a color into red, green, and blue values.
815  */
816 void decompose(Color c, ref int r, ref int g, ref int b) pure @safe
817 {
818     c = toRGB(c);
819     r = int(c & 0xff0000) >> 16;
820     g = int(c & 0xff00) >> 8;
821     b = int(c & 0xff);
822 }
823 
824 /**
825  * Name returns W3C name or an empty string if no arguments
826  * if passed true as an argument it will falls back to
827  * the CSS hex string if no W3C name found '#ABCDEF'
828  */
829 string name(Color c, bool css = false) pure @safe
830 {
831     foreach (name, color; colorsByName)
832     {
833         if (c == color)
834         {
835             return name;
836         }
837     }
838     if (css)
839     {
840         return c.css();
841     }
842     return "";
843 }
844 
845 string css(Color c) pure @safe
846 {
847     if (!c.isValid)
848     {
849         return "";
850     }
851     return format("#%06X", c.toHex());
852 }
853 
854 unittest
855 {
856     assert(toPalette(Color.red, 16) == Color.red);
857     assert(toPalette(cast(Color) 0x00FF00 | Color.isRGB, 16) == Color.lime);
858     assert(toHex(Color.invalid) == -1);
859     assert(toRGB(cast(Color) 512) == Color.invalid);
860     assert(toRGB(Color.reset) == Color.invalid);
861     assert(fromHex(cast(int) Color.reset) == Color.invalid);
862     for (int i = 0; i < 256; i++)
863     {
864         auto r = toHex(cast(Color) i);
865         assert(r >= 0);
866         auto c = fromHex(r);
867         assert(toRGB(c) == c);
868         assert(c != Color.invalid);
869         auto p = toPalette(c, 256);
870         assert(p != Color.invalid);
871         if (i < 16)
872         {
873             assert(p == i);
874         }
875         else
876         {
877             assert(p < 256);
878             if (p > 15) // sometimes we map to a lower palette color
879             {
880                 assert(p == i);
881             }
882         }
883     }
884     for (Color c = Color.black; c <= Color.white; c++)
885     {
886         assert(toPalette(toRGB(c), 256) == c);
887     }
888     assert(decompose(Color.yellowGreen)[0] == 0x9a);
889     assert(decompose(Color.yellowGreen)[1] == 0xcd);
890     assert(decompose(Color.yellowGreen)[2] == 0x32);
891     assert(decompose(Color.red)[0] == 0xff);
892     assert(decompose(Color.red)[1] == 0);
893     assert(decompose(Color.red)[2] == 0);
894 
895     assert(Color.red.name == "red");
896     assert(Color.darkKhaki.name == "darkkhaki");
897     assert(Color.red.css == "#FF0000");
898     assert(Color.red.toRGB.name(true) == "#FF0000");
899 }
900 
901 private long redMean(Color c1, Color c2) pure @safe
902 {
903     int r1, r2, g1, g2, b1, b2;
904     decompose(c1, r1, g1, b1);
905     decompose(c2, r2, g2, b2);
906     long ar = (r1 + r2) / 2;
907     long dr = (r1 - r2);
908     long dg = (g1 - g2);
909     long db = (b1 - b2);
910 
911     long dist;
912 
913     // see https://en.wikipedia.org/wiki/Color_difference
914     dist = ((2 + ar / 256) * dr * dr) + (4 * dg * dg) + ((2 + ((255 - ar) / 256)) * db * db);
915 
916     // not bothering with the square root, since we are just comparing values
917     return dist;
918 }
919 
920 private Color bestColor(Color c, int numColors) pure @safe
921 {
922     // this is an expensive operation, so you really want
923     // to memoize it.
924     long abs(long a) pure
925     {
926         return a >= 0 ? a : -a;
927     }
928 
929     c = toRGB(c);
930     if (c == Color.invalid)
931     {
932         return c;
933     }
934 
935     // look for a perfect fit first before we start doing hard math
936     auto hex = toHex(c);
937     if ((hex in palValues) && (palValues[hex] <= numColors))
938     {
939         return (palValues[hex]);
940     }
941 
942     if (numColors == 0)
943     {
944         auto d1 = redMean(c, Color.black);
945         auto d2 = redMean(c, Color.white);
946         return abs(d1) < abs(d2) ? Color.black : Color.white;
947     }
948     if (numColors > 256)
949     {
950         numColors = 256;
951     }
952     auto bestDist = long.max;
953     auto bestColor = Color.invalid;
954     for (Color pal = Color.black; pal < numColors; pal++)
955     {
956         auto d = redMean(c, toRGB(pal));
957         if (d < bestDist)
958         {
959             bestDist = d;
960             bestColor = pal;
961         }
962     }
963 
964     return (bestColor);
965 }
966 
967 unittest
968 {
969     import std.stdio;
970 
971     Color v;
972     assert(v == Color.invalid);
973     assert(bestColor(Color.red, 16) == Color.red);
974     assert(bestColor(Color.red, 256) == Color.red);
975     assert(bestColor(Color.paleGreen, 256) == cast(Color) 120);
976     assert(bestColor(Color.darkSlateBlue, 256) == cast(Color) 60);
977     assert(bestColor(fromHex(0xfe0000), 16) == Color.red);
978 }
979 
980 unittest
981 {
982     import std.stdio;
983 
984     assert(toPalette(Color.red, 16) == Color.red);
985     assert(toPalette(Color.red, 256) == Color.red);
986     assert(toPalette(Color.paleGreen, 256) == cast(Color) 120);
987     assert(toPalette(Color.darkSlateBlue, 256) == cast(Color) 60);
988     assert(toPalette(fromHex(0xfe0000), 16) == Color.red);
989 }
990 
991 // ColorNames holds the written names of colors. Useful to present a list of
992 // recognized named colors.
993 static immutable Color[string] colorsByName;
994 
995 shared static this() @safe
996 {
997     colorsByName = [
998         "black": Color.black,
999         "maroon": Color.maroon,
1000         "green": Color.green,
1001         "olive": Color.olive,
1002         "navy": Color.navy,
1003         "purple": Color.purple,
1004         "teal": Color.teal,
1005         "silver": Color.silver,
1006         "gray": Color.gray,
1007         "red": Color.red,
1008         "lime": Color.lime,
1009         "yellow": Color.yellow,
1010         "blue": Color.blue,
1011         "fuchsia": Color.fuchsia,
1012         "aqua": Color.aqua,
1013         "white": Color.white,
1014         "aliceblue": Color.aliceBlue,
1015         "antiquewhite": Color.antiqueWhite,
1016         "aquamarine": Color.aquamarine,
1017         "azure": Color.azure,
1018         "beige": Color.beige,
1019         "bisque": Color.bisque,
1020         "blanchedalmond": Color.blanchedAlmond,
1021         "blueviolet": Color.blueViolet,
1022         "brown": Color.brown,
1023         "burlywood": Color.burlyWood,
1024         "cadetblue": Color.cadetBlue,
1025         "chartreuse": Color.chartreuse,
1026         "chocolate": Color.chocolate,
1027         "coral": Color.coral,
1028         "cornflowerblue": Color.cornflowerBlue,
1029         "cornsilk": Color.cornsilk,
1030         "crimson": Color.crimson,
1031         "darkblue": Color.darkBlue,
1032         "darkcyan": Color.darkCyan,
1033         "darkgoldenrod": Color.darkGoldenrod,
1034         "darkgray": Color.darkGray,
1035         "darkgreen": Color.darkGreen,
1036         "darkkhaki": Color.darkKhaki,
1037         "darkmagenta": Color.darkMagenta,
1038         "darkolivegreen": Color.darkOliveGreen,
1039         "darkorange": Color.darkOrange,
1040         "darkorchid": Color.darkOrchid,
1041         "darkred": Color.darkRed,
1042         "darksalmon": Color.darkSalmon,
1043         "darkseagreen": Color.darkSeaGreen,
1044         "darkslateblue": Color.darkSlateBlue,
1045         "darkslategray": Color.darkSlateGray,
1046         "darkturquoise": Color.darkTurquoise,
1047         "darkviolet": Color.darkViolet,
1048         "deeppink": Color.deepPink,
1049         "deepskyblue": Color.deepSkyBlue,
1050         "dimgray": Color.dimGray,
1051         "dodgerblue": Color.dodgerBlue,
1052         "firebrick": Color.fireBrick,
1053         "floralwhite": Color.floralWhite,
1054         "forestgreen": Color.forestGreen,
1055         "gainsboro": Color.gainsboro,
1056         "ghostwhite": Color.ghostWhite,
1057         "gold": Color.gold,
1058         "goldenrod": Color.goldenrod,
1059         "greenyellow": Color.greenYellow,
1060         "honeydew": Color.honeydew,
1061         "hotpink": Color.hotPink,
1062         "indianred": Color.indianRed,
1063         "indigo": Color.indigo,
1064         "ivory": Color.ivory,
1065         "khaki": Color.khaki,
1066         "lavender": Color.lavender,
1067         "lavenderblush": Color.lavenderBlush,
1068         "lawngreen": Color.lawnGreen,
1069         "lemonchiffon": Color.lemonChiffon,
1070         "lightblue": Color.lightBlue,
1071         "lightcoral": Color.lightCoral,
1072         "lightcyan": Color.lightCyan,
1073         "lightgoldenrodyellow": Color.lightGoldenrodYellow,
1074         "lightgray": Color.lightGray,
1075         "lightgreen": Color.lightGreen,
1076         "lightpink": Color.lightPink,
1077         "lightsalmon": Color.lightSalmon,
1078         "lightseagreen": Color.lightSeaGreen,
1079         "lightskyblue": Color.lightSkyBlue,
1080         "lightslategray": Color.lightSlateGray,
1081         "lightsteelblue": Color.lightSteelBlue,
1082         "lightyellow": Color.lightYellow,
1083         "limegreen": Color.limeGreen,
1084         "linen": Color.linen,
1085         "mediumaquamarine": Color.mediumAquamarine,
1086         "mediumblue": Color.mediumBlue,
1087         "mediumorchid": Color.mediumOrchid,
1088         "mediumpurple": Color.mediumPurple,
1089         "mediumseagreen": Color.mediumSeaGreen,
1090         "mediumslateblue": Color.mediumSlateBlue,
1091         "mediumspringgreen": Color.mediumSpringGreen,
1092         "mediumturquoise": Color.mediumTurquoise,
1093         "mediumvioletred": Color.mediumVioletRed,
1094         "midnightblue": Color.midnightBlue,
1095         "mintcream": Color.mintCream,
1096         "mistyrose": Color.mistyRose,
1097         "moccasin": Color.moccasin,
1098         "navajowhite": Color.navajoWhite,
1099         "oldlace": Color.oldLace,
1100         "olivedrab": Color.oliveDrab,
1101         "orange": Color.orange,
1102         "orangered": Color.orangeRed,
1103         "orchid": Color.orchid,
1104         "palegoldenrod": Color.paleGoldenrod,
1105         "palegreen": Color.paleGreen,
1106         "paleturquoise": Color.paleTurquoise,
1107         "palevioletred": Color.paleVioletRed,
1108         "papayawhip": Color.papayaWhip,
1109         "peachpuff": Color.peachPuff,
1110         "peru": Color.peru,
1111         "pink": Color.pink,
1112         "plum": Color.plum,
1113         "powderblue": Color.powderBlue,
1114         "rebeccapurple": Color.rebeccaPurple,
1115         "rosybrown": Color.rosyBrown,
1116         "royalblue": Color.royalBlue,
1117         "saddlebrown": Color.saddleBrown,
1118         "salmon": Color.salmon,
1119         "sandybrown": Color.sandyBrown,
1120         "seagreen": Color.seaGreen,
1121         "seashell": Color.seashell,
1122         "sienna": Color.sienna,
1123         "skyblue": Color.skyBlue,
1124         "slateblue": Color.slateBlue,
1125         "slategray": Color.slateGray,
1126         "snow": Color.snow,
1127         "springgreen": Color.springGreen,
1128         "steelblue": Color.steelBlue,
1129         "tan": Color.tan,
1130         "thistle": Color.thistle,
1131         "tomato": Color.tomato,
1132         "turquoise": Color.turquoise,
1133         "violet": Color.violet,
1134         "wheat": Color.wheat,
1135         "whitesmoke": Color.whiteSmoke,
1136         "yellowgreen": Color.yellowGreen,
1137         "grey": Color.gray,
1138         "dimgrey": Color.dimGray,
1139         "darkgrey": Color.darkGray,
1140         "darkslategrey": Color.darkSlateGray,
1141         "lightgrey": Color.lightGray,
1142         "lightslategrey": Color.lightSlateGray,
1143         "slategrey": Color.slateGray,
1144 
1145         "reset": Color.reset, // actually the terminal default
1146     ];
1147 }