68619e3561c248776430a7adc1cba59269ed56b3
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / Color.js
1 /*
2  * Copyright (C) 2009, 2013 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009 Joseph Pecoraro
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 WebInspector.Color = class Color
31 {
32     constructor(format, components)
33     {
34         this.format = format;
35
36         if (format === WebInspector.Color.Format.HSL || format === WebInspector.Color.Format.HSLA)
37             this._hsla = components;
38         else
39             this._rgba = components;
40
41         this.valid = !components.some(isNaN);
42     }
43
44     // Static
45
46     static fromString(colorString)
47     {
48         var value = colorString.toLowerCase().replace(/%|\s+/g, "");
49         var transparentNicknames = ["transparent", "rgba(0,0,0,0)", "hsla(0,0,0,0)"];
50         if (transparentNicknames.includes(value)) {
51             var color = new WebInspector.Color(WebInspector.Color.Format.Nickname, [0, 0, 0, 0]);
52             color.nickname = "transparent";
53             color.original = colorString;
54             return color;
55         }
56
57         // Simple - #hex, rgb(), nickname, hsl()
58         var simple = /^(?:#([0-9a-f]{3,8})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
59         var match = colorString.match(simple);
60         if (match) {
61             if (match[1]) { // hex
62                 var hex = match[1].toUpperCase();
63                 var len = hex.length;
64                 if (len === 3) {
65                     return new WebInspector.Color(WebInspector.Color.Format.ShortHEX, [
66                         parseInt(hex.charAt(0) + hex.charAt(0), 16),
67                         parseInt(hex.charAt(1) + hex.charAt(1), 16),
68                         parseInt(hex.charAt(2) + hex.charAt(2), 16),
69                         1
70                     ]);
71                 } else if (len === 6) {
72                     return new WebInspector.Color(WebInspector.Color.Format.HEX, [
73                         parseInt(hex.substring(0, 2), 16),
74                         parseInt(hex.substring(2, 4), 16),
75                         parseInt(hex.substring(4, 6), 16),
76                         1
77                     ]);
78                 } else if (len === 4) {
79                     return new WebInspector.Color(WebInspector.Color.Format.ShortHEXAlpha, [
80                         parseInt(hex.charAt(0) + hex.charAt(0), 16),
81                         parseInt(hex.charAt(1) + hex.charAt(1), 16),
82                         parseInt(hex.charAt(2) + hex.charAt(2), 16),
83                         parseInt(hex.charAt(3) + hex.charAt(3), 16) / 255
84                     ]);
85                 } else if (len === 8) {
86                     return new WebInspector.Color(WebInspector.Color.Format.HEXAlpha, [
87                         parseInt(hex.substring(0, 2), 16),
88                         parseInt(hex.substring(2, 4), 16),
89                         parseInt(hex.substring(4, 6), 16),
90                         parseInt(hex.substring(6, 8), 16) / 255
91                     ]);
92                 } else
93                     return null;
94             } else if (match[2]) { // rgb
95                 var rgb = match[2].split(/\s*,\s*/);
96                 if (rgb.length !== 3)
97                     return null;
98                 return new WebInspector.Color(WebInspector.Color.Format.RGB, [
99                     parseInt(rgb[0]),
100                     parseInt(rgb[1]),
101                     parseInt(rgb[2]),
102                     1
103                 ]);
104             } else if (match[3]) { // nickname
105                 var nickname = match[3].toLowerCase();
106                 if (WebInspector.Color.Nicknames.hasOwnProperty(nickname)) {
107                     var color = new WebInspector.Color(WebInspector.Color.Format.Nickname, WebInspector.Color.Nicknames[nickname].concat(1));
108                     color.nickname = nickname;
109                     color.original = colorString;
110                     return color;
111                 } else
112                     return null;
113             } else if (match[4]) { // hsl
114                 var hsl = match[4].replace(/%/g, "").split(/\s*,\s*/);
115                 if (hsl.length !== 3)
116                     return null;
117                 return new WebInspector.Color(WebInspector.Color.Format.HSL, [
118                     parseInt(hsl[0]),
119                     parseInt(hsl[1]),
120                     parseInt(hsl[2]),
121                     1
122                 ]);
123             }
124         }
125
126         // Advanced - rgba(), hsla()
127         var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/i;
128         match = colorString.match(advanced);
129         if (match) {
130             if (match[1]) { // rgba
131                 var rgba = match[1].split(/\s*,\s*/);
132                 if (rgba.length !== 4)
133                     return null;
134                 return new WebInspector.Color(WebInspector.Color.Format.RGBA, [
135                     parseInt(rgba[0]),
136                     parseInt(rgba[1]),
137                     parseInt(rgba[2]),
138                     Number.constrain(parseFloat(rgba[3]), 0, 1)
139                 ]);
140             } else if (match[2]) { // hsla
141                 var hsla = match[2].replace(/%/g, "").split(/\s*,\s*/);
142                 if (hsla.length !== 4)
143                     return null;
144                 return new WebInspector.Color(WebInspector.Color.Format.HSLA, [
145                     parseInt(hsla[0]),
146                     parseInt(hsla[1]),
147                     parseInt(hsla[2]),
148                     Number.constrain(parseFloat(hsla[3]), 0, 1)
149                 ]);
150             }
151         }
152
153         return null;
154     }
155
156     static rgb2hsv(r, g, b)
157     {
158         r /= 255;
159         g /= 255;
160         b /= 255;
161
162         var min = Math.min(Math.min(r, g), b);
163         var max = Math.max(Math.max(r, g), b);
164         var delta = max - min;
165
166         var v = max;
167         var s, h;
168
169         if (max === min)
170             h = 0;
171         else if (max === r)
172             h = (60 * ((g - b) / delta)) % 360;
173         else if (max === g)
174             h = 60 * ((b - r) / delta) + 120;
175         else if (max === b)
176             h = 60 * ((r - g) / delta) + 240;
177
178         if (h < 0)
179             h += 360;
180
181         // Saturation
182         if (max === 0)
183             s = 0;
184         else
185             s = 1 - (min / max);
186
187         return [h, s, v];
188     }
189
190     static hsv2rgb(h, s, v)
191     {
192         if (s === 0)
193             return [v, v, v];
194
195         h /= 60;
196         var i = Math.floor(h);
197         var data = [
198             v * (1 - s),
199             v * (1 - s * (h - i)),
200             v * (1 - s * (1 - (h - i)))
201         ];
202         var rgb;
203
204         switch (i) {
205         case 0:
206             rgb = [v, data[2], data[0]];
207             break;
208         case 1:
209             rgb = [data[1], v, data[0]];
210             break;
211         case 2:
212             rgb = [data[0], v, data[2]];
213             break;
214         case 3:
215             rgb = [data[0], data[1], v];
216             break;
217         case 4:
218             rgb = [data[2], data[0], v];
219             break;
220         default:
221             rgb = [v, data[0], data[1]];
222             break;
223         }
224
225         return rgb;
226     }
227
228
229     // Public
230
231     nextFormat(format)
232     {
233         format = format || this.format;
234
235         switch (format) {
236         case WebInspector.Color.Format.Original:
237             return this.simple ? WebInspector.Color.Format.RGB : WebInspector.Color.Format.RGBA;
238
239         case WebInspector.Color.Format.RGB:
240         case WebInspector.Color.Format.RGBA:
241             return this.simple ? WebInspector.Color.Format.HSL : WebInspector.Color.Format.HSLA;
242
243         case WebInspector.Color.Format.HSL:
244         case WebInspector.Color.Format.HSLA:
245             if (this.nickname)
246                 return WebInspector.Color.Format.Nickname;
247             if (this.simple)
248                 return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
249             return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
250
251         case WebInspector.Color.Format.ShortHEX:
252             return WebInspector.Color.Format.HEX;
253
254         case WebInspector.Color.Format.ShortHEXAlpha:
255             return WebInspector.Color.Format.HEXAlpha;
256
257         case WebInspector.Color.Format.HEX:
258         case WebInspector.Color.Format.HEXAlpha:
259             return WebInspector.Color.Format.Original;
260
261         case WebInspector.Color.Format.Nickname:
262             if (this.simple)
263                 return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
264             return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
265
266         default:
267             console.error("Unknown color format.");
268             return null;
269         }
270     }
271
272     get alpha()
273     {
274         return this._rgba ? this._rgba[3] : this._hsla[3];
275     }
276
277     get simple()
278     {
279         return this.alpha === 1;
280     }
281
282     get rgb()
283     {
284         var rgb = this.rgba.slice();
285         rgb.pop();
286         return rgb;
287     }
288
289     get hsl()
290     {
291         var hsl = this.hsla.slice();
292         hsl.pop();
293         return hsl;
294     }
295
296     get rgba()
297     {
298         if (!this._rgba)
299             this._rgba = this._hslaToRGBA(this._hsla);
300         return this._rgba;
301     }
302
303     get hsla()
304     {
305         if (!this._hsla)
306             this._hsla = this._rgbaToHSLA(this.rgba);
307         return this._hsla;
308     }
309
310     copy()
311     {
312         switch (this.format) {
313         case WebInspector.Color.Format.RGB:
314         case WebInspector.Color.Format.HEX:
315         case WebInspector.Color.Format.ShortHEX:
316         case WebInspector.Color.Format.HEXAlpha:
317         case WebInspector.Color.Format.ShortHEXAlpha:
318         case WebInspector.Color.Format.Nickname:
319         case WebInspector.Color.Format.RGBA:
320             return new WebInspector.Color(this.format, this.rgba);
321         case WebInspector.Color.Format.HSL:
322         case WebInspector.Color.Format.HSLA:
323             return new WebInspector.Color(this.format, this.hsla);
324         }
325     }
326
327     toString(format)
328     {
329         if (!format)
330             format = this.format;
331
332         switch (format) {
333         case WebInspector.Color.Format.Original:
334             return this._toOriginalString();
335         case WebInspector.Color.Format.RGB:
336             return this._toRGBString();
337         case WebInspector.Color.Format.RGBA:
338             return this._toRGBAString();
339         case WebInspector.Color.Format.HSL:
340             return this._toHSLString();
341         case WebInspector.Color.Format.HSLA:
342             return this._toHSLAString();
343         case WebInspector.Color.Format.HEX:
344             return this._toHEXString();
345         case WebInspector.Color.Format.ShortHEX:
346             return this._toShortHEXString();
347         case WebInspector.Color.Format.HEXAlpha:
348             return this._toHEXAlphaString();
349         case WebInspector.Color.Format.ShortHEXAlpha:
350             return this._toShortHEXAlphaString();
351         case WebInspector.Color.Format.Nickname:
352             return this._toNicknameString();
353         }
354
355         throw "invalid color format";
356     }
357
358     // Private
359
360     _toOriginalString()
361     {
362         return this.original || this._toNicknameString();
363     }
364
365     _toNicknameString()
366     {
367         if (this.nickname)
368             return this.nickname;
369
370         var rgba = this.rgba;
371         if (!this.simple) {
372             if (rgba[0] === 0 && rgba[1] === 0 && rgba[2] === 0 && rgba[3] === 0)
373                 return "transparent";
374             return this._toRGBAString();
375         }
376
377         var nicknames = WebInspector.Color.Nicknames;
378         for (var nickname in nicknames) {
379             if (!nicknames.hasOwnProperty(nickname))
380                 continue;
381
382             var nicknameRGB = nicknames[nickname];
383             if (nicknameRGB[0] === rgba[0] && nicknameRGB[1] === rgba[1] && nicknameRGB[2] === rgba[2])
384                 return nickname;
385         }
386
387         return this._toRGBString();
388     }
389
390     _toShortHEXString()
391     {
392         if (!this.simple)
393             return this._toRGBAString();
394
395         var rgba = this.rgba;
396         var r = this._componentToHexValue(rgba[0]);
397         var g = this._componentToHexValue(rgba[1]);
398         var b = this._componentToHexValue(rgba[2]);
399
400         if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1])
401             return "#" + r[0] + g[0] + b[0];
402         else
403             return "#" + r + g + b;
404     }
405
406     _toHEXString()
407     {
408         if (!this.simple)
409             return this._toRGBAString();
410
411         var rgba = this.rgba;
412         var r = this._componentToHexValue(rgba[0]);
413         var g = this._componentToHexValue(rgba[1]);
414         var b = this._componentToHexValue(rgba[2]);
415
416         return "#" + r + g + b;
417     }
418
419     _toShortHEXAlphaString()
420     {
421         let rgba = this.rgba;
422         let r = this._componentToHexValue(rgba[0]);
423         let g = this._componentToHexValue(rgba[1]);
424         let b = this._componentToHexValue(rgba[2]);
425         let a = this._componentToHexValue(Math.round(rgba[3] * 255));
426
427         if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1] && a[0] === a[1])
428             return "#" + r[0] + g[0] + b[0] + a[0];
429         else
430             return "#" + r + g + b + a;
431     }
432
433     _toHEXAlphaString()
434     {
435         let rgba = this.rgba;
436         let r = this._componentToHexValue(rgba[0]);
437         let g = this._componentToHexValue(rgba[1]);
438         let b = this._componentToHexValue(rgba[2]);
439         let a = this._componentToHexValue(Math.round(rgba[3] * 255));
440
441         return "#" + r + g + b + a;
442     }
443
444     _toRGBString()
445     {
446         if (!this.simple)
447             return this._toRGBAString();
448
449         var rgba = this.rgba;
450         return "rgb(" + [rgba[0], rgba[1], rgba[2]].join(", ") + ")";
451     }
452
453     _toRGBAString()
454     {
455         return "rgba(" + this.rgba.join(", ") + ")";
456     }
457
458     _toHSLString()
459     {
460         if (!this.simple)
461             return this._toHSLAString();
462
463         var hsla = this.hsla;
464         return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
465     }
466
467     _toHSLAString()
468     {
469         var hsla = this.hsla;
470         return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")";
471     }
472
473     _canBeSerializedAsShortHEX()
474     {
475         var rgba = this.rgba;
476
477         var r = this._componentToHexValue(rgba[0]);
478         if (r[0] !== r[1])
479             return false;
480
481         var g = this._componentToHexValue(rgba[1]);
482         if (g[0] !== g[1])
483             return false;
484
485         var b = this._componentToHexValue(rgba[2]);
486         if (b[0] !== b[1])
487             return false;
488
489         return true;
490     }
491
492     _componentToNumber(value)
493     {
494         return Number.constrain(value, 0, 255);
495     }
496
497     _componentToHexValue(value)
498     {
499         var hex = this._componentToNumber(value).toString(16);
500         if (hex.length === 1)
501             hex = "0" + hex;
502         return hex;
503     }
504
505     _rgbToHSL(rgb)
506     {
507         var r = this._componentToNumber(rgb[0]) / 255;
508         var g = this._componentToNumber(rgb[1]) / 255;
509         var b = this._componentToNumber(rgb[2]) / 255;
510         var max = Math.max(r, g, b);
511         var min = Math.min(r, g, b);
512         var diff = max - min;
513         var add = max + min;
514
515         if (min === max)
516             var h = 0;
517         else if (r === max)
518             var h = ((60 * (g - b) / diff) + 360) % 360;
519         else if (g === max)
520             var h = (60 * (b - r) / diff) + 120;
521         else
522             var h = (60 * (r - g) / diff) + 240;
523
524         var l = 0.5 * add;
525
526         if (l === 0)
527             var s = 0;
528         else if (l === 1)
529             var s = 1;
530         else if (l <= 0.5)
531             var s = diff / add;
532         else
533             var s = diff / (2 - add);
534
535         h = Math.round(h);
536         s = Math.round(s * 100);
537         l = Math.round(l * 100);
538
539         return [h, s, l];
540     }
541
542     _hslToRGB(hsl)
543     {
544         var h = parseFloat(hsl[0]) / 360;
545         var s = parseFloat(hsl[1]) / 100;
546         var l = parseFloat(hsl[2]) / 100;
547
548         h *= 6;
549         var sArray = [
550             l += s *= l < .5 ? l : 1 - l,
551             l - h % 1 * s * 2,
552             l -= s *= 2,
553             l,
554             l + h % 1 * s,
555             l + s
556         ];
557         return [
558             Math.round(sArray[ ~~h      % 6 ] * 255),
559             Math.round(sArray[ (h | 16) % 6 ] * 255),
560             Math.round(sArray[ (h | 8)  % 6 ] * 255)
561         ];
562     }
563
564     _rgbaToHSLA(rgba)
565     {
566         var hsl = this._rgbToHSL(rgba);
567         hsl.push(rgba[3]);
568         return hsl;
569     }
570
571     _hslaToRGBA(hsla)
572     {
573         var rgba = this._hslToRGB(hsla);
574         rgba.push(hsla[3]);
575         return rgba;
576     }
577 };
578
579 WebInspector.Color.Format = {
580     Original: "color-format-original",
581     Nickname: "color-format-nickname",
582     HEX: "color-format-hex",
583     ShortHEX: "color-format-short-hex",
584     HEXAlpha: "color-format-hex-alpha",
585     ShortHEXAlpha: "color-format-short-hex-alpha",
586     RGB: "color-format-rgb",
587     RGBA: "color-format-rgba",
588     HSL: "color-format-hsl",
589     HSLA: "color-format-hsla"
590 };
591
592 WebInspector.Color.Nicknames = {
593     "aliceblue": [240, 248, 255],
594     "antiquewhite": [250, 235, 215],
595     "aquamarine": [127, 255, 212],
596     "azure": [240, 255, 255],
597     "beige": [245, 245, 220],
598     "bisque": [255, 228, 196],
599     "black": [0, 0, 0],
600     "blanchedalmond": [255, 235, 205],
601     "blue": [0, 0, 255],
602     "blueviolet": [138, 43, 226],
603     "brown": [165, 42, 42],
604     "burlywood": [222, 184, 135],
605     "cadetblue": [95, 158, 160],
606     "chartreuse": [127, 255, 0],
607     "chocolate": [210, 105, 30],
608     "coral": [255, 127, 80],
609     "cornflowerblue": [100, 149, 237],
610     "cornsilk": [255, 248, 220],
611     "crimson": [237, 164, 61],
612     "cyan": [0, 255, 255],
613     "darkblue": [0, 0, 139],
614     "darkcyan": [0, 139, 139],
615     "darkgoldenrod": [184, 134, 11],
616     "darkgray": [169, 169, 169],
617     "darkgreen": [0, 100, 0],
618     "darkkhaki": [189, 183, 107],
619     "darkmagenta": [139, 0, 139],
620     "darkolivegreen": [85, 107, 47],
621     "darkorange": [255, 140, 0],
622     "darkorchid": [153, 50, 204],
623     "darkred": [139, 0, 0],
624     "darksalmon": [233, 150, 122],
625     "darkseagreen": [143, 188, 143],
626     "darkslateblue": [72, 61, 139],
627     "darkslategray": [47, 79, 79],
628     "darkturquoise": [0, 206, 209],
629     "darkviolet": [148, 0, 211],
630     "deeppink": [255, 20, 147],
631     "deepskyblue": [0, 191, 255],
632     "dimgray": [105, 105, 105],
633     "dodgerblue": [30, 144, 255],
634     "firebrick": [178, 34, 34],
635     "floralwhite": [255, 250, 240],
636     "forestgreen": [34, 139, 34],
637     "gainsboro": [220, 220, 220],
638     "ghostwhite": [248, 248, 255],
639     "gold": [255, 215, 0],
640     "goldenrod": [218, 165, 32],
641     "gray": [128, 128, 128],
642     "green": [0, 128, 0],
643     "greenyellow": [173, 255, 47],
644     "honeydew": [240, 255, 240],
645     "hotpink": [255, 105, 180],
646     "indianred": [205, 92, 92],
647     "indigo": [75, 0, 130],
648     "ivory": [255, 255, 240],
649     "khaki": [240, 230, 140],
650     "lavender": [230, 230, 250],
651     "lavenderblush": [255, 240, 245],
652     "lawngreen": [124, 252, 0],
653     "lemonchiffon": [255, 250, 205],
654     "lightblue": [173, 216, 230],
655     "lightcoral": [240, 128, 128],
656     "lightcyan": [224, 255, 255],
657     "lightgoldenrodyellow": [250, 250, 210],
658     "lightgreen": [144, 238, 144],
659     "lightgrey": [211, 211, 211],
660     "lightpink": [255, 182, 193],
661     "lightsalmon": [255, 160, 122],
662     "lightseagreen": [32, 178, 170],
663     "lightskyblue": [135, 206, 250],
664     "lightslategray": [119, 136, 153],
665     "lightsteelblue": [176, 196, 222],
666     "lightyellow": [255, 255, 224],
667     "lime": [0, 255, 0],
668     "limegreen": [50, 205, 50],
669     "linen": [250, 240, 230],
670     "magenta": [255, 0, 255],
671     "maroon": [128, 0, 0],
672     "mediumaquamarine": [102, 205, 170],
673     "mediumblue": [0, 0, 205],
674     "mediumorchid": [186, 85, 211],
675     "mediumpurple": [147, 112, 219],
676     "mediumseagreen": [60, 179, 113],
677     "mediumslateblue": [123, 104, 238],
678     "mediumspringgreen": [0, 250, 154],
679     "mediumturquoise": [72, 209, 204],
680     "mediumvioletred": [199, 21, 133],
681     "midnightblue": [25, 25, 112],
682     "mintcream": [245, 255, 250],
683     "mistyrose": [255, 228, 225],
684     "moccasin": [255, 228, 181],
685     "navajowhite": [255, 222, 173],
686     "navy": [0, 0, 128],
687     "oldlace": [253, 245, 230],
688     "olive": [128, 128, 0],
689     "olivedrab": [107, 142, 35],
690     "orange": [255, 165, 0],
691     "orangered": [255, 69, 0],
692     "orchid": [218, 112, 214],
693     "palegoldenrod": [238, 232, 170],
694     "palegreen": [152, 251, 152],
695     "paleturquoise": [175, 238, 238],
696     "palevioletred": [219, 112, 147],
697     "papayawhip": [255, 239, 213],
698     "peachpuff": [255, 218, 185],
699     "peru": [205, 133, 63],
700     "pink": [255, 192, 203],
701     "plum": [221, 160, 221],
702     "powderblue": [176, 224, 230],
703     "purple": [128, 0, 128],
704     "rebeccapurple": [102, 51, 153],
705     "red": [255, 0, 0],
706     "rosybrown": [188, 143, 143],
707     "royalblue": [65, 105, 225],
708     "saddlebrown": [139, 69, 19],
709     "salmon": [250, 128, 114],
710     "sandybrown": [244, 164, 96],
711     "seagreen": [46, 139, 87],
712     "seashell": [255, 245, 238],
713     "sienna": [160, 82, 45],
714     "silver": [192, 192, 192],
715     "skyblue": [135, 206, 235],
716     "slateblue": [106, 90, 205],
717     "slategray": [112, 128, 144],
718     "snow": [255, 250, 250],
719     "springgreen": [0, 255, 127],
720     "steelblue": [70, 130, 180],
721     "tan": [210, 180, 140],
722     "teal": [0, 128, 128],
723     "thistle": [216, 191, 216],
724     "tomato": [255, 99, 71],
725     "turquoise": [64, 224, 208],
726     "violet": [238, 130, 238],
727     "wheat": [245, 222, 179],
728     "white": [255, 255, 255],
729     "whitesmoke": [245, 245, 245],
730     "yellow": [255, 255, 0],
731     "yellowgreen": [154, 205, 50]
732 };