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