1 module sily.color; 2 3 import std.algorithm : canFind; 4 import std.algorithm.comparison; 5 import std.algorithm.comparison: compclamp = clamp; 6 import std.array : replace; 7 import std.conv; 8 import std.math; 9 import std.regex; 10 import std.stdio; 11 import std.string; 12 import std.uni : toLower; 13 import std.traits: isNumeric; 14 15 import sily.vector; 16 import sily.meta; 17 import sily.array; 18 19 alias col = Color; 20 alias Color8 = (R, G, B) => Color(R / 255.0f, G / 255.0f, B / 255.0f); 21 22 struct Color { 23 public float[4] data = fill!float(1, 4); 24 25 alias data this; 26 alias arrayof = data; 27 28 this(in float val) { 29 foreach (i; 0 .. 3) { data[i] = val; } 30 data[3] = 1.0f; 31 } 32 33 this(in float val, in float a) { 34 foreach (i; 0 .. 3) { data[i] = val; } 35 data[3] = a; 36 } 37 38 this(in float[3] vals...) { 39 data = vals ~ [1.0f]; 40 } 41 42 this(in float[4] vals...) { 43 data = vals; 44 } 45 46 ubyte r8() { return cast(ubyte) (data[0] * 255u); } 47 ubyte g8() { return cast(ubyte) (data[1] * 255u); } 48 ubyte b8() { return cast(ubyte) (data[2] * 255u); } 49 ubyte a8() { return cast(ubyte) (data[3] * 255u); } 50 51 /* -------------------------------------------------------------------------- */ 52 /* UNARY OPERATIONS OVERRIDES */ 53 /* -------------------------------------------------------------------------- */ 54 55 // opBinary x [+, -, *, /, %] y 56 auto opBinary(string op, R)(in Color!(R, N) b) const if ( isNumeric!R ) { 57 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 58 VecType ret = VecType(); 59 foreach (i; 0 .. 4) { mixin( "ret.data[i] = data[i] " ~ op ~ " b.data[i];" ); } 60 return ret; 61 } 62 63 // opBinaryRight y [+, -, *, /, %] x 64 auto opBinaryRight(string op, R)(in Color!(R, N) b) const if ( isNumeric!R ) { 65 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 66 VecType ret = VecType(); 67 foreach (i; 0 .. 4) { mixin( "ret[i] = b.data[i] " ~ op ~ " data[i];" ); } 68 return ret; 69 } 70 71 auto opBinary(string op, R)(in R b) const if ( isNumeric!R ) { 72 // assert(this !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 73 VecType ret = VecType(); 74 foreach (i; 0 .. 4) { mixin( "ret.data[i] = data[i] " ~ op ~ " b;" ); } 75 return ret; 76 } 77 78 auto opBinaryRight(string op, R)(in R b) const if ( isNumeric!R ) { 79 // assert(this !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 80 VecType ret = VecType(); 81 foreach (i; 0 .. 4) { mixin( "ret[i] = b " ~ op ~ " data[i];" ); } 82 return ret; 83 } 84 85 // opEquals x == y 86 bool opEquals(R)(in Color!(R, 4) b) const if ( isNumeric!R ) { 87 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 88 bool eq = true; 89 foreach (i; 0 .. 4) { eq = eq && data[i] == b.data[i]; } 90 return eq; 91 } 92 93 // opCmp x [< > ==] y 94 int opCmp(R)(in Color!(R, N) b) const if ( isNumeric!R ) { 95 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 96 float al = length; 97 float bl = b.length; 98 if (al == bl) return 0; 99 if (al < bl) return -1; 100 return 1; 101 } 102 103 // opUnary [-, +, --, ++] x 104 auto opUnary(string op)() if(op == "-"){ 105 // assert(this !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 106 VecType ret = VecType(); 107 if (op == "-") 108 foreach (i; 0 .. 4) { ret.data[i] = -data[i]; } 109 return ret; 110 } 111 112 // opOpAssign x [+, -, *, /, %]= y 113 auto opOpAssign(string op, R)( in Color!(R, N) b ) if ( isNumeric!R ) { 114 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 115 foreach (i; 0 .. 4) { mixin( "data[i] = data[i] " ~ op ~ " b.data[i];" ); } 116 return this; 117 } 118 119 auto opOpAssign(string op, R)( in R b ) if ( isNumeric!R ) { 120 // assert(this !is null, "\nOP::ERROR nullptr Color!" ~ 4.to!string ~ "."); 121 foreach (i; 0 .. 4) { mixin( "data[i] = data[i] " ~ op ~ " b;" ); } 122 return this; 123 } 124 125 size_t toHash() const @nogc @safe pure nothrow { 126 float s = 0; 127 foreach (i; 0 .. 4) { s += data[i]; } 128 return cast(size_t) s; 129 } 130 131 // incredible magic from terramatter.meta.meta 132 // idk how it works but it works awesome 133 // and im not going to touch it at all 134 enum AccessString = "r g b a"; 135 mixin accessByString!(float, 4, "data", AccessString); 136 137 138 public Vector4f asVector4f() { 139 return Vector4f(data); 140 } 141 142 public Vector3f asVector3f() { 143 return Vector3f(data[0..3]); 144 } 145 146 public Color copyof() { 147 return Color(data); 148 } 149 150 public string toString() const { 151 import std.conv : to; 152 string s; 153 s ~= "["; 154 foreach (i; 0 .. 4) { 155 s ~= format("%.2f", data[i]); 156 if (i != 4 - 1) s ~= ", "; 157 } 158 s ~= "]"; 159 return s; 160 } 161 162 /* -------------------------------------------------------------------------- */ 163 /* PROPERTIES */ 164 /* -------------------------------------------------------------------------- */ 165 166 /** 167 * Inverts color 168 */ 169 public void invert() { 170 data[0] = 1.0f - data[0]; 171 data[1] = 1.0f - data[1]; 172 data[2] = 1.0f - data[2]; 173 data[3] = 1.0f - data[3]; 174 } 175 176 /** 177 * Returns the luminance of the color in the [0.0, 1.0] range 178 */ 179 public float luminance() { 180 return compclamp(0.2126f * data[0] + 0.7152f * data[1] + 0.0722f * data[2], 0.0f, 1.0f); 181 } 182 183 /** 184 * Returns the linear interpolation with another color 185 * Params: 186 * p_to = Color to interpolate with 187 * p_weight = Interpolation factor in [0.0, 1.0] range 188 */ 189 public void lerp(const Color p_to, float p_weight) { 190 data[0] += (p_weight * (p_to.data[0] - data[0])); 191 data[1] += (p_weight * (p_to.data[1] - data[1])); 192 data[2] += (p_weight * (p_to.data[2] - data[2])); 193 data[3] += (p_weight * (p_to.data[3] - data[3])); 194 } 195 196 /** 197 * Darkens color by `p_amount` 198 * Params: 199 * p_amount = Amount to darken 200 */ 201 public void darken(float p_amount) { 202 data[0] = data[0] * (1.0f - p_amount); 203 data[1] = data[1] * (1.0f - p_amount); 204 data[2] = data[2] * (1.0f - p_amount); 205 } 206 207 /** 208 * Lightens color by `p_amount` 209 * Params: 210 * p_amount = Amount to lighten 211 */ 212 public void lighten(float p_amount) { 213 data[0] = data[0] + (1.0f - data[0]) * p_amount; 214 data[1] = data[1] + (1.0f - data[1]) * p_amount; 215 data[2] = data[2] + (1.0f - data[2]) * p_amount; 216 } 217 218 /** 219 * Clamps color values between `min` and `max` 220 * Params: 221 * min = Minimal allowed value 222 * max = Maximal allowed value 223 */ 224 void clamp(float min = 0.0f, float max = 1.0f) { 225 data[0] = compclamp(data[0], min, max); 226 data[1] = compclamp(data[1], min, max); 227 data[2] = compclamp(data[2], min, max); 228 data[3] = compclamp(data[3], min, max); 229 } 230 231 /* -------------------------------------------------------------------------- */ 232 /* HTML */ 233 /* -------------------------------------------------------------------------- */ 234 235 private uint tocolbit(uint c_bits, int[4] c_order ...) { 236 uint c_size = 2.pow(c_bits) - 1; 237 uint c_shift = c_bits; 238 uint c = (data[c_order[0]] * c_size).round.to!uint; 239 c <<= c_shift; 240 c |= (data[c_order[1]] * c_size).round.to!uint; 241 c <<= c_shift; 242 c |= (data[c_order[2]] * c_size).round.to!uint; 243 c <<= c_shift; 244 c |= (data[c_order[3]] * c_size).round.to!uint; 245 return c; 246 } 247 248 // public uint toargb32() { return tocolbit(8, 3, 0, 1, 2); } 249 // public uint toabgr32() { return tocolbit(8, 3, 2, 1, 0); } 250 // public uint torgba32() { return tocolbit(8, 0, 1, 2, 3); } 251 // public uint toargb64() { return tocolbit(16, 3, 0, 1, 2); } 252 // public uint toabgr64() { return tocolbit(16, 3, 2, 1, 0); } 253 // public uint torgba64() { return tocolbit(16, 0, 1, 2, 3); } 254 255 private string _to_hex(float p_val) const { 256 int v = (p_val * 255).round.to!int; 257 v = v.clamp(0, 255); 258 string ret; 259 260 for (int i = 0; i < 2; i++) { 261 char[2] c = [ 0, 0 ]; 262 int lv = v & 0xF; 263 if (lv < 10) { 264 c[0] = ('0' + lv).to!char; 265 } else { 266 c[0] = ('a' + lv - 10).to!char; 267 } 268 269 v >>= 4; 270 string cs = c.to!string; 271 ret = cs ~ ret; 272 } 273 274 return ret; 275 } 276 277 /** 278 * Returns html representation of color in format `#RRGGBB` 279 * 280 * If `p_alpha` is true returns color in format `#RRGGBBAA` 281 * Params: 282 * p_alpha = Include alpha? 283 * Returns: Html string 284 */ 285 public string toHtml(bool p_alpha = false) const { 286 string txt; 287 txt ~= _to_hex(data[0]); 288 txt ~= _to_hex(data[1]); 289 txt ~= _to_hex(data[2]); 290 if (p_alpha) { 291 txt ~= _to_hex(data[3]); 292 } 293 return txt; 294 } 295 296 /** 297 * Returns hex representation of color in format `0xrrggbb` 298 * Returns: uint hex 299 */ 300 public uint toHex() { 301 int r = rint(data[0] * 255); 302 int g = rint(data[1] * 255); 303 int b = rint(data[2] * 255); 304 return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff); 305 } 306 307 /* -------------------------------------------------------------------------- */ 308 /* SETTERS */ 309 /* -------------------------------------------------------------------------- */ 310 311 private void setHex(uint p_hex, uint c_mask, uint c_bits, bool c_hasAlpha) { 312 float c_size = (2.pow(c_bits) - 1).to!float; 313 uint c_shift = c_bits; 314 float a = 0; 315 if (c_hasAlpha) { 316 a = (p_hex & c_mask) / c_size; 317 p_hex >>= c_shift; 318 } 319 float b = (p_hex & c_mask) / c_size; 320 p_hex >>= c_shift; 321 float g = (p_hex & c_mask) / c_size; 322 p_hex >>= c_shift; 323 float r = (p_hex & c_mask) / c_size; 324 325 data = [r, g, b, a]; 326 } 327 328 /** 329 * Sets color to hexadecimal value 330 * Params: 331 * p_hex = uint hex value to set color to 332 * p_hasAlpha = Does p_hex include alpha 333 */ 334 public void setHex(uint p_hex, bool p_hasAlpha = false) { setHex(p_hex, 0xFF, 8, p_hasAlpha); } 335 // public void setHex64(uint p_hex, bool p_hasAlpha = false) { setHex(p_hex, 0xFFFF, 16, p_hasAlpha); } 336 337 /** 338 * Sets color from hsv 339 * Params: 340 * p_h = hue 341 * p_s = saturation 342 * p_v = value 343 * p_alpha = alpha 344 */ 345 public void setHsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f) { 346 int i; 347 float f, p, q, t; 348 data[3] = p_alpha; 349 350 if (p_s == 0) { 351 // Achromatic (grey) 352 data[0] = data[1] = data[2] = p_v; 353 return; 354 } 355 356 p_h *= 6.0f; 357 p_h = p_h.fmod(6); 358 i = p_h.floor().to!int; 359 360 f = p_h - i; 361 p = p_v * (1 - p_s); 362 q = p_v * (1 - p_s * f); 363 t = p_v * (1 - p_s * (1 - f)); 364 365 switch (i) { 366 case 0: // Red is the dominant color 367 data[0] = p_v; 368 data[1] = t; 369 data[2] = p; 370 break; 371 case 1: // Green is the dominant color 372 data[0] = q; 373 data[1] = p_v; 374 data[2] = p; 375 break; 376 case 2: 377 data[0] = p; 378 data[1] = p_v; 379 data[2] = t; 380 break; 381 case 3: // Blue is the dominant color 382 data[0] = p; 383 data[1] = q; 384 data[2] = p_v; 385 break; 386 case 4: 387 data[0] = t; 388 data[1] = p; 389 data[2] = p_v; 390 break; 391 default: // (5) Red is the dominant color 392 data[0] = p_v; 393 data[1] = p; 394 data[2] = q; 395 break; 396 } 397 } 398 399 /++ 400 + Sets color from html string in format `#RRGGBB` 401 + Params: 402 + html = Color string 403 +/ 404 public void setHtml(string html) { 405 auto rg = regex(r"/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i"); 406 auto m = matchAll(html, rg); 407 m.popFront(); 408 float _r = to!int(m.front.hit, 16) / 255; m.popFront(); 409 float _g = to!int(m.front.hit, 16) / 255; m.popFront(); 410 float _b = to!int(m.front.hit, 16) / 255; m.popFront(); 411 data = [to!float(_r), to!float(_g), to!float(_b), 1.0f]; 412 } 413 414 /* -------------------------------------------------------------------------- */ 415 /* HSV PROPERTIES */ 416 /* -------------------------------------------------------------------------- */ 417 418 /** 419 * Returns `h` component of hsv 420 */ 421 public float hue() const { 422 float cmin = data[0].min(data[1]); 423 cmin = cmin.min(data[2]); 424 float cmax = data[0].max(data[1]); 425 cmax = cmax.min(data[2]); 426 427 float delta = cmax - cmin; 428 if (delta == 0) { return 0; } 429 430 float h; 431 if (data[0] == cmax) { 432 h = (data[1] - data[2]) / delta; 433 } else 434 if (data[1] == cmax) { 435 h = 2 + (data[2] - data[0]) / delta; 436 } else { 437 h = 4 + (data[2] - data[0]) / delta; 438 } 439 440 h /= 6.0f; 441 if (h < 0) { 442 h += 1.0f; 443 } 444 return h; 445 } 446 447 /** 448 * Returns `s` component of hsv 449 */ 450 public float saturation() const { 451 float cmin = data[0].min(data[1]); 452 cmin = cmin.min(data[2]); 453 float cmax = data[0].max(data[1]); 454 cmax = cmax.min(data[2]); 455 456 float delta = cmax - cmin; 457 458 return (cmax != 0) ? (delta / cmax) : 0; 459 } 460 461 /** 462 * Returns `v` component of hsv 463 */ 464 public float value() const { 465 float cmax = data[0].max(data[1]); 466 cmax = cmax.max(data[2]); 467 return cmax; 468 } 469 470 /* -------------------------------------------------------------------------- */ 471 /* BASH GETTERS */ 472 /* -------------------------------------------------------------------------- */ 473 474 /** 475 * Sets color from ANSI index 476 * Params: 477 * ansi = Color index 478 */ 479 void setAnsi8(int ansi) { 480 if (ansi > 100) ansi -= 92; 481 if (ansi > 90) ansi -= 82; 482 if (ansi > 40) ansi -= 40; 483 if (ansi > 30) ansi -= 30; 484 if (ansi >= lowHEX.length) ansi = lowHEX.length.to!int - 1; 485 if (ansi < 0) ansi = 0; 486 // write(ansi); 487 setHex(lowHEX[ansi]); 488 } 489 490 /** 491 * Sets color from ANSI256 index 492 * Params: 493 * ansi = Color index 494 */ 495 void setAnsi(int ansi) { 496 if (ansi < 0 || ansi > 255) { 497 data = [0, 0, 0, 0]; 498 return; 499 } 500 if (ansi < 16) { 501 setHex(Color.lowHEX[ansi]); 502 return; 503 } 504 505 if (ansi > 231) { 506 const int s = (ansi - 232) * 10 + 8; 507 data = [s / 255.0f, s / 255.0f, s / 255.0f, 1]; 508 return; 509 } 510 511 const int n = ansi - 16; 512 int _b = n % 6; 513 int _g = (n - _b) / 6 % 6; 514 int _r = (n - _b - _g * 6) / 36 % 6; 515 _b = _b ? _b * 40 + 55 : 0; 516 _r = _r ? _r * 40 + 55 : 0; 517 _g = _g ? _g * 40 + 55 : 0; 518 519 data = [_r / 255.0, _g / 255.0, _b / 255.0, 1]; 520 } 521 522 /* -------------------------------------------------------------------------- */ 523 /* BASH SETTERS */ 524 /* -------------------------------------------------------------------------- */ 525 526 private alias rint = (a) => to!int(round(a)); 527 528 529 private float colorDistance(Color e1, Color e2) { 530 int rmean = ( cast(int) e1.r + cast(int) e2.r ) / 2; 531 int r = cast(int) e1.r - cast(int) e2.r; 532 int g = cast(int) e1.g - cast(int) e2.g; 533 int b = cast(int) e1.b - cast(int) e2.b; 534 // return sqrt( 535 // (((512 + rmean) * r * r) >> 8) + 536 // 4.0f * g * g + 537 // (((767 - rmean) * b * b) >> 8) 538 // ); 539 return sqrt((2 + rmean / 255) * r * r + 4 * g * g + (2 + (255 - rmean) / 255) * b * b + 0.0f); 540 } 541 542 /** 543 * Returns closest ANSI8 color index 544 * Params: 545 * isBackground = Is color a background 546 * Returns: ANSI8 color 547 */ 548 int toAnsi8(bool isBackground = false) { 549 /* 550 * 39 - default foreground, 49 - default backgound 551 * Main colors are from 30 - 39, light variant is 90 - 97. 552 * 97 is white, 30 is black. to get background - add 10 to color code 553 * goes like: 554 * black, red, green, yellow, blue, magenta, cyan, lgray 555 * then repeat with lighter variation 556 */ 557 558 int ri = rint(data[0] * 255); 559 int gi = rint(data[1] * 255); 560 int bi = rint(data[2] * 255); 561 562 if (ri / 64 == gi / 64 && gi / 64 == bi / 64) { 563 // 0 128 192 255 564 if (ri <= 64) return 30 + (isBackground ? 10 : 0); 565 if (ri <= 160) return 90 + (isBackground ? 10 : 0); 566 if (ri <= 224) return 37 + (isBackground ? 10 : 0); 567 if (ri <= 255) return 97 + (isBackground ? 10 : 0); 568 } 569 570 // int diff = 255 * 3; 571 float diff = 255 * 3; 572 int pos = 0; 573 // writeln(lowHEX[15] - hex); 574 for (int i = 0; i < 16; i ++) { 575 if (i == 0 || i == 7 || i == 8 || i == 15) continue; 576 int rh = lowRGB[i * 3]; 577 int gh = lowRGB[i * 3 + 1]; 578 int bh = lowRGB[i * 3 + 2]; 579 // int rd = abs(rh - ri); 580 // int gd = abs(gh - gi); 581 // int bd = abs(bh - bi); 582 // int udiff = rd + gd + bd; 583 float udiff = colorDistance(col(ri, gi, bi), col(rh, gh, bh)); 584 if (udiff < diff) { 585 diff = udiff; 586 pos = i; 587 } 588 } 589 // write(pos); 590 591 int ansi = pos + 30; 592 if (pos >= 8) ansi += 60 - 8; 593 return ansi + (isBackground ? 10 : 0); 594 } 595 596 /** 597 * Returns closest ANSI256 color index 598 * Returns: ANSI256 color 599 */ 600 int toAnsi() { 601 /* 602 * 256 ANSI color coding is: 603 * 0 - 14 Special colors, probably check by hand 604 * goes like: 605 * black, red, green, yellow, blue, magenta, cyan, lgray 606 * then repeat with lighter variation 607 * 16 - 231 RGB colors with color coding like this: 608 * Pure R component is on 16, 52, 88, 124, 160, 196. Aka map(r, comp) 609 * B component is r +0..5 610 * G component is rb +0,6,12,18,24,30 (but not 36 coz it's next red) 611 * in end rgb coding, considering mcol = floor(col*5) 612 * rgbansi = 16 + (16 * r) + (6 * g) + b; 613 * 232 - 255 Grayscale from dark to light 614 * refer to https://misc.flogisoft.com/_media/bash/colors_format/256-colors.sh-v2.png 615 */ 616 617 float r = data[0]; 618 float g = data[1]; 619 float b = data[2]; 620 621 int ri = rint(data[0] * 255); 622 int gi = rint(data[1] * 255); 623 int bi = rint(data[2] * 255); 624 625 if (ri / 16 == gi / 16 && gi / 16 == bi / 16) { 626 // handles grayscale 627 if (ri < 8) { 628 return 16; 629 } 630 631 if (ri > 248) { 632 return 231; 633 } 634 635 return rint(((ri - 8.0) / 247.0) * 24.0) + 232; 636 } 637 638 int ansi = 16 639 + ( 36 * rint(r * 5)) 640 + ( 6 * rint(g * 5)) 641 + rint(b * 5); 642 643 return ansi; 644 } 645 646 /** 647 * Returns closest bash ANSI8 color string 648 * Params: 649 * isBackground = Is color a background 650 * Returns: Bash ANSI8 color string 651 */ 652 string toAnsi8String(bool isBackground = false) { 653 return "\033[" ~ toAnsi8(isBackground).to!string ~ "m"; 654 } 655 656 /** 657 * Returns closest bash ANSI256 color string 658 * Params: 659 * isBackground = Is color a background 660 * Returns: Bash ANSI256 color string 661 */ 662 string toAnsiString(bool isBackground = false) { 663 return (isBackground ? "\033[48;5;" : "\033[38;5;") ~ 664 toAnsi().to!string ~ "m"; 665 } 666 667 /** 668 * Returns bash truecolor string 669 * Params: 670 * isBackground = Is color a background 671 * Returns: Bash truecolor string 672 */ 673 string toTrueColorString(bool isBackground = false) { 674 return (isBackground ? "\033[48;2;" : "\033[38;2;") ~ 675 rint(data[0] * 255).to!string ~ ";" ~ 676 rint(data[1] * 255).to!string ~ ";" ~ 677 rint(data[2] * 255).to!string ~ "m"; 678 679 } 680 681 682 // TODO add colours from godot 683 // LINK https://github.com/godotengine/godot/blob/master/core/math/color.cpp 684 685 private static const uint[] lowHEX = [ 686 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, 687 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff 688 ]; 689 690 private static const ushort[] lowRGB = [ 691 0, 0, 0, 128, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 128, 128, 0, 128, 0, 128, 128, 192, 192, 192, 692 128, 128, 128, 255, 0, 0, 0, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 0, 255, 255, 255, 255, 255 693 ]; 694 } 695 696 697 enum Colors 698 { 699 aliceBlue = Color8(240,248,255), /// <font color=aliceBlue>◼</font> 700 antiqueWhite = Color8(250,235,215), /// <font color=antiqueWhite>◼</font> 701 aqua = Color8(0,255,255), /// <font color=aqua>◼</font> 702 aquamarine = Color8(127,255,212), /// <font color=aquamarine>◼</font> 703 azure = Color8(240,255,255), /// <font color=azure>◼</font> 704 beige = Color8(245,245,220), /// <font color=beige>◼</font> 705 bisque = Color8(255,228,196), /// <font color=bisque>◼</font> 706 black = Color8(0,0,0), /// <font color=black>◼</font> 707 blanchedAlmond = Color8(255,235,205), /// <font color=blanchedAlmond>◼</font> 708 blue = Color8(0,0,255), /// <font color=blue>◼</font> 709 blueViolet = Color8(138,43,226), /// <font color=blueViolet>◼</font> 710 brown = Color8(165,42,42), /// <font color=brown>◼</font> 711 burlyWood = Color8(222,184,135), /// <font color=burlyWood>◼</font> 712 cadetBlue = Color8(95,158,160), /// <font color=cadetBlue>◼</font> 713 chartreuse = Color8(127,255,0), /// <font color=chartreuse>◼</font> 714 chocolate = Color8(210,105,30), /// <font color=chocolate>◼</font> 715 coral = Color8(255,127,80), /// <font color=coral>◼</font> 716 cornflowerBlue = Color8(100,149,237), /// <font color=cornflowerBlue>◼</font> 717 cornsilk = Color8(255,248,220), /// <font color=cornsilk>◼</font> 718 crimson = Color8(220,20,60), /// <font color=crimson>◼</font> 719 cyan = Color8(0,255,255), /// <font color=cyan>◼</font> 720 darkBlue = Color8(0,0,139), /// <font color=darkBlue>◼</font> 721 darkCyan = Color8(0,139,139), /// <font color=darkCyan>◼</font> 722 darkGoldenrod = Color8(184,134,11), /// <font color=darkGoldenrod>◼</font> 723 darkGray = Color8(169,169,169), /// <font color=darkGray>◼</font> 724 darkGrey = Color8(169,169,169), /// <font color=darkGrey>◼</font> 725 darkGreen = Color8(0,100,0), /// <font color=darkGreen>◼</font> 726 darkKhaki = Color8(189,183,107), /// <font color=darkKhaki>◼</font> 727 darkMagenta = Color8(139,0,139), /// <font color=darkMagenta>◼</font> 728 darkOliveGreen = Color8(85,107,47), /// <font color=darkOliveGreen>◼</font> 729 darkOrange = Color8(255,140,0), /// <font color=darkOrange>◼</font> 730 darkOrchid = Color8(153,50,204), /// <font color=darkOrchid>◼</font> 731 darkRed = Color8(139,0,0), /// <font color=darkRed>◼</font> 732 darkSalmon = Color8(233,150,122), /// <font color=darkSalmon>◼</font> 733 darkSeaGreen = Color8(143,188,143), /// <font color=darkSeaGreen>◼</font> 734 darkSlateBlue = Color8(72,61,139), /// <font color=darkSlateBlue>◼</font> 735 darkSlateGray = Color8(47,79,79), /// <font color=darkSlateGray>◼</font> 736 darkSlateGrey = Color8(47,79,79), /// <font color=darkSlateGrey>◼</font> 737 darkTurquoise = Color8(0,206,209), /// <font color=darkTurquoise>◼</font> 738 darkViolet = Color8(148,0,211), /// <font color=darkViolet>◼</font> 739 deepPink = Color8(255,20,147), /// <font color=deepPink>◼</font> 740 deepSkyBlue = Color8(0,191,255), /// <font color=deepSkyBlue>◼</font> 741 dimGray = Color8(105,105,105), /// <font color=dimGray>◼</font> 742 dimGrey = Color8(105,105,105), /// <font color=dimGrey>◼</font> 743 dodgerBlue = Color8(30,144,255), /// <font color=dodgerBlue>◼</font> 744 fireBrick = Color8(178,34,34), /// <font color=fireBrick>◼</font> 745 floralWhite = Color8(255,250,240), /// <font color=floralWhite>◼</font> 746 forestGreen = Color8(34,139,34), /// <font color=forestGreen>◼</font> 747 fuchsia = Color8(255,0,255), /// <font color=fuchsia>◼</font> 748 gainsboro = Color8(220,220,220), /// <font color=gainsboro>◼</font> 749 ghostWhite = Color8(248,248,255), /// <font color=ghostWhite>◼</font> 750 gold = Color8(255,215,0), /// <font color=gold>◼</font> 751 goldenrod = Color8(218,165,32), /// <font color=goldenrod>◼</font> 752 gray = Color8(128,128,128), /// <font color=gray>◼</font> 753 grey = Color8(128,128,128), /// <font color=grey>◼</font> 754 green = Color8(0,128,0), /// <font color=green>◼</font> 755 greenYellow = Color8(173,255,47), /// <font color=greenYellow>◼</font> 756 honeydew = Color8(240,255,240), /// <font color=honeydew>◼</font> 757 hotPink = Color8(255,105,180), /// <font color=hotPink>◼</font> 758 indianRed = Color8(205,92,92), /// <font color=indianRed>◼</font> 759 indigo = Color8(75,0,130), /// <font color=indigo>◼</font> 760 ivory = Color8(255,255,240), /// <font color=ivory>◼</font> 761 khaki = Color8(240,230,140), /// <font color=khaki>◼</font> 762 lavender = Color8(230,230,250), /// <font color=lavender>◼</font> 763 lavenderBlush = Color8(255,240,245), /// <font color=lavenderBlush>◼</font> 764 lawnGreen = Color8(124,252,0), /// <font color=lawnGreen>◼</font> 765 lemonChiffon = Color8(255,250,205), /// <font color=lemonChiffon>◼</font> 766 lightBlue = Color8(173,216,230), /// <font color=lightBlue>◼</font> 767 lightCoral = Color8(240,128,128), /// <font color=lightCoral>◼</font> 768 lightCyan = Color8(224,255,255), /// <font color=lightCyan>◼</font> 769 lightGoldenrodYellow = Color8(250,250,210), /// <font color=lightGoldenrodYellow>◼</font> 770 lightGray = Color8(211,211,211), /// <font color=lightGray>◼</font> 771 lightGrey = Color8(211,211,211), /// <font color=lightGrey>◼</font> 772 lightGreen = Color8(144,238,144), /// <font color=lightGreen>◼</font> 773 lightPink = Color8(255,182,193), /// <font color=lightPink>◼</font> 774 lightSalmon = Color8(255,160,122), /// <font color=lightSalmon>◼</font> 775 lightSeaGreen = Color8(32,178,170), /// <font color=lightSeaGreen>◼</font> 776 lightSkyBlue = Color8(135,206,250), /// <font color=lightSkyBlue>◼</font> 777 lightSlateGray = Color8(119,136,153), /// <font color=lightSlateGray>◼</font> 778 lightSlateGrey = Color8(119,136,153), /// <font color=lightSlateGrey>◼</font> 779 lightSteelBlue = Color8(176,196,222), /// <font color=lightSteelBlue>◼</font> 780 lightYellow = Color8(255,255,224), /// <font color=lightYellow>◼</font> 781 lime = Color8(0,255,0), /// <font color=lime>◼</font> 782 limeGreen = Color8(50,205,50), /// <font color=limeGreen>◼</font> 783 linen = Color8(250,240,230), /// <font color=linen>◼</font> 784 magenta = Color8(255,0,255), /// <font color=magenta>◼</font> 785 maroon = Color8(128,0,0), /// <font color=maroon>◼</font> 786 mediumAquamarine = Color8(102,205,170), /// <font color=mediumAquamarine>◼</font> 787 mediumBlue = Color8(0,0,205), /// <font color=mediumBlue>◼</font> 788 mediumOrchid = Color8(186,85,211), /// <font color=mediumOrchid>◼</font> 789 mediumPurple = Color8(147,112,219), /// <font color=mediumPurple>◼</font> 790 mediumSeaGreen = Color8(60,179,113), /// <font color=mediumSeaGreen>◼</font> 791 mediumSlateBlue = Color8(123,104,238), /// <font color=mediumSlateBlue>◼</font> 792 mediumSpringGreen = Color8(0,250,154), /// <font color=mediumSpringGreen>◼</font> 793 mediumTurquoise = Color8(72,209,204), /// <font color=mediumTurquoise>◼</font> 794 mediumVioletRed = Color8(199,21,133), /// <font color=mediumVioletRed>◼</font> 795 midnightBlue = Color8(25,25,112), /// <font color=midnightBlue>◼</font> 796 mintCream = Color8(245,255,250), /// <font color=mintCream>◼</font> 797 mistyRose = Color8(255,228,225), /// <font color=mistyRose>◼</font> 798 moccasin = Color8(255,228,181), /// <font color=moccasin>◼</font> 799 navajoWhite = Color8(255,222,173), /// <font color=navajoWhite>◼</font> 800 navy = Color8(0,0,128), /// <font color=navy>◼</font> 801 oldLace = Color8(253,245,230), /// <font color=oldLace>◼</font> 802 olive = Color8(128,128,0), /// <font color=olive>◼</font> 803 oliveDrab = Color8(107,142,35), /// <font color=oliveDrab>◼</font> 804 orange = Color8(255,165,0), /// <font color=orange>◼</font> 805 orangeRed = Color8(255,69,0), /// <font color=orangeRed>◼</font> 806 orchid = Color8(218,112,214), /// <font color=orchid>◼</font> 807 paleGoldenrod = Color8(238,232,170), /// <font color=paleGoldenrod>◼</font> 808 paleGreen = Color8(152,251,152), /// <font color=paleGreen>◼</font> 809 paleTurquoise = Color8(175,238,238), /// <font color=paleTurquoise>◼</font> 810 paleVioletRed = Color8(219,112,147), /// <font color=paleVioletRed>◼</font> 811 papayaWhip = Color8(255,239,213), /// <font color=papayaWhip>◼</font> 812 peachPuff = Color8(255,218,185), /// <font color=peachPuff>◼</font> 813 peru = Color8(205,133,63), /// <font color=peru>◼</font> 814 pink = Color8(255,192,203), /// <font color=pink>◼</font> 815 plum = Color8(221,160,221), /// <font color=plum>◼</font> 816 powderBlue = Color8(176,224,230), /// <font color=powderBlue>◼</font> 817 purple = Color8(128,0,128), /// <font color=purple>◼</font> 818 red = Color8(255,0,0), /// <font color=red>◼</font> 819 rosyBrown = Color8(188,143,143), /// <font color=rosyBrown>◼</font> 820 royalBlue = Color8(65,105,225), /// <font color=royalBlue>◼</font> 821 saddleBrown = Color8(139,69,19), /// <font color=saddleBrown>◼</font> 822 salmon = Color8(250,128,114), /// <font color=salmon>◼</font> 823 sandyBrown = Color8(244,164,96), /// <font color=sandyBrown>◼</font> 824 seaGreen = Color8(46,139,87), /// <font color=seaGreen>◼</font> 825 seashell = Color8(255,245,238), /// <font color=seashell>◼</font> 826 sienna = Color8(160,82,45), /// <font color=sienna>◼</font> 827 silver = Color8(192,192,192), /// <font color=silver>◼</font> 828 skyBlue = Color8(135,206,235), /// <font color=skyBlue>◼</font> 829 slateBlue = Color8(106,90,205), /// <font color=slateBlue>◼</font> 830 slateGray = Color8(112,128,144), /// <font color=slateGray>◼</font> 831 slateGrey = Color8(112,128,144), /// <font color=slateGrey>◼</font> 832 snow = Color8(255,250,250), /// <font color=snow>◼</font> 833 springGreen = Color8(0,255,127), /// <font color=springGreen>◼</font> 834 steelBlue = Color8(70,130,180), /// <font color=steelBlue>◼</font> 835 tan = Color8(210,180,140), /// <font color=tan>◼</font> 836 teal = Color8(0,128,128), /// <font color=teal>◼</font> 837 thistle = Color8(216,191,216), /// <font color=thistle>◼</font> 838 tomato = Color8(255,99,71), /// <font color=tomato>◼</font> 839 turquoise = Color8(64,224,208), /// <font color=turquoise>◼</font> 840 violet = Color8(238,130,238), /// <font color=violet>◼</font> 841 wheat = Color8(245,222,179), /// <font color=wheat>◼</font> 842 white = Color8(255,255,255), /// <font color=white>◼</font> 843 whiteSmoke = Color8(245,245,245), /// <font color=whiteSmoke>◼</font> 844 yellow = Color8(255,255,0), /// <font color=yellow>◼</font> 845 yellowGreen = Color8(154,205,50) /// <font color=yellowGreen>◼</font> 846 }