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