1 /* css3_color.c -- Routines for handling css3 colors
2  *
3  * Copyright (c) 1994-2018 Carnegie Mellon University.  All rights reserved.
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  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name "Carnegie Mellon University" must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission. For permission or any legal
20  *    details, please contact
21  *      Carnegie Mellon University
22  *      Center for Technology Transfer and Enterprise Creation
23  *      4615 Forbes Avenue
24  *      Suite 302
25  *      Pittsburgh, PA  15213
26  *      (412) 268-7393, fax: (412) 268-7395
27  *      innovation@andrew.cmu.edu
28  *
29  * 4. Redistributions of any form whatsoever must retain the following
30  *    acknowledgment:
31  *    "This product includes software developed by Computing Services
32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33  *
34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41  *
42  */
43 
44 #include <limits.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 struct css3_color_t {
50     const char *name;
51     unsigned char r;
52     unsigned char g;
53     unsigned char b;
54 };
55 
56 static const struct css3_color_t css3_colors[] = {
57     { "aliceblue",            240, 248, 255 },
58     { "antiquewhite",         250, 235, 215 },
59     { "aqua",                   0, 255, 255 },
60     { "aquamarine",           127, 255, 212 },
61     { "azure",                240, 255, 255 },
62     { "beige",                245, 245, 220 },
63     { "bisque",               255, 228, 196 },
64     { "black",                  0,   0,   0 },
65     { "blanchedalmond",       255, 235, 205 },
66     { "blue",                   0,   0, 255 },
67     { "blueviolet",           138,  43, 226 },
68     { "brown",                165,  42,  42 },
69     { "burlywood",            222, 184, 135 },
70     { "cadetblue",             95, 158, 160 },
71     { "chartreuse",           127, 255,   0 },
72     { "chocolate",            210, 105,  30 },
73     { "coral",                255, 127,  80 },
74     { "cornflowerblue",       100, 149, 237 },
75     { "cornsilk",             255, 248, 220 },
76     { "crimson",              220,  20,  60 },
77     { "cyan",                   0, 255, 255 },
78     { "darkblue",               0,   0, 139 },
79     { "darkcyan",               0, 139, 139 },
80     { "darkgoldenrod",        184, 134,  11 },
81     { "darkgray",             169, 169, 169 },
82     { "darkgreen",              0, 100,   0 },
83     { "darkgrey",             169, 169, 169 },
84     { "darkkhaki",            189, 183, 107 },
85     { "darkmagenta",          139,   0, 139 },
86     { "darkolivegreen",        85, 107,  47 },
87     { "darkorange",           255, 140,   0 },
88     { "darkorchid",           153,  50, 204 },
89     { "darkred",              139,   0,   0 },
90     { "darksalmon",           233, 150, 122 },
91     { "darkseagreen",         143, 188, 143 },
92     { "darkslateblue",         72 , 61, 139 },
93     { "darkslategray",         47,  79,  79 },
94     { "darkslategrey",         47,  79,  79 },
95     { "darkturquoise",          0, 206, 209 },
96     { "darkviolet",           148,   0, 211 },
97     { "deeppink",             255,  20, 147 },
98     { "deepskyblue",            0, 191, 255 },
99     { "dimgray",              105, 105, 105 },
100     { "dimgrey",              105, 105, 105 },
101     { "dodgerblue",            30, 144, 255 },
102     { "firebrick",            178,  34,  34 },
103     { "floralwhite",          255, 250, 240 },
104     { "forestgreen",           34, 139,  34 },
105     { "fuchsia",              255,   0, 255 },
106     { "gainsboro",            220, 220, 220 },
107     { "ghostwhite",           248, 248, 255 },
108     { "gold",                 255, 215,   0 },
109     { "goldenrod",            218, 165,  32 },
110     { "gray",                 128, 128, 128 },
111     { "green",                  0, 128,   0 },
112     { "greenyellow",          173, 255,  47 },
113     { "grey",                 128, 128, 128 },
114     { "honeydew",             240, 255, 240 },
115     { "hotpink",              255, 105, 180 },
116     { "indianred",            205,  92,  92 },
117     { "indigo",                75,   0, 130 },
118     { "ivory",                255, 255, 240 },
119     { "khaki",                240, 230, 140 },
120     { "lavender",             230, 230, 250 },
121     { "lavenderblush",        255, 240, 245 },
122     { "lawngreen",            124, 252,   0 },
123     { "lemonchiffon",         255, 250, 205 },
124     { "lightblue",            173, 216, 230 },
125     { "lightcoral",           240, 128, 128 },
126     { "lightcyan",            224, 255, 255 },
127     { "lightgoldenrodyellow", 250, 250, 210 },
128     { "lightgray",            211, 211, 211 },
129     { "lightgreen",           144, 238, 144 },
130     { "lightgrey",            211, 211, 211 },
131     { "lightpink",            255, 182, 193 },
132     { "lightsalmon",          255, 160, 122 },
133     { "lightseagreen",         32, 178, 170 },
134     { "lightskyblue",         135, 206, 250 },
135     { "lightslategray",       119, 136, 153 },
136     { "lightslategrey",       119, 136, 153 },
137     { "lightsteelblue",       176, 196, 222 },
138     { "lightyellow",          255, 255, 224 },
139     { "lime",                   0, 255,   0 },
140     { "limegreen",             50, 205,  50 },
141     { "linen",                250, 240, 230 },
142     { "magenta",              255,   0, 255 },
143     { "maroon",               128,   0,   0 },
144     { "mediumaquamarine",     102, 205, 170 },
145     { "mediumblue",             0,   0, 205 },
146     { "mediumorchid",         186,  85, 211 },
147     { "mediumpurple",         147, 112, 219 },
148     { "mediumseagreen",        60, 179, 113 },
149     { "mediumslateblue",      123, 104, 238 },
150     { "mediumspringgreen",      0, 250, 154 },
151     { "mediumturquoise",       72, 209, 204 },
152     { "mediumvioletred",      199,  21, 133 },
153     { "midnightblue",          25,  25, 112 },
154     { "mintcream",            245, 255, 250 },
155     { "mistyrose",            255, 228, 225 },
156     { "moccasin",             255, 228, 181 },
157     { "navajowhite",          255, 222, 173 },
158     { "navy",                   0,   0, 128 },
159     { "oldlace",              253, 245, 230 },
160     { "olive",                128, 128,   0 },
161     { "olivedrab",            107, 142,  35 },
162     { "orange",               255, 165,   0 },
163     { "orangered",            255,  69,   0 },
164     { "orchid",               218, 112, 214 },
165     { "palegoldenrod",        238, 232, 170 },
166     { "palegreen",            152, 251, 152 },
167     { "paleturquoise",        175, 238, 238 },
168     { "palevioletred",        219, 112, 147 },
169     { "papayawhip",           255, 239, 213 },
170     { "peachpuff",            255, 218, 185 },
171     { "peru",                 205, 133, 63 },
172     { "pink",                 255, 192, 203 },
173     { "plum",                 221, 160, 221 },
174     { "powderblue",           176, 224, 230 },
175     { "purple",               128,   0, 128 },
176     { "red",                  255,   0,   0 },
177     { "rosybrown",            188, 143, 143 },
178     { "royalblue",             65, 105, 225 },
179     { "saddlebrown",          139,  69,  19 },
180     { "salmon",               250, 128, 114 },
181     { "sandybrown",           244, 164,  96 },
182     { "seagreen",              46, 139,  87 },
183     { "seashell",             255, 245, 238 },
184     { "sienna",               160,  82,  45 },
185     { "silver",               192, 192, 192 },
186     { "skyblue",              135, 206, 235 },
187     { "slateblue",            106,  90, 205 },
188     { "slategray",            112, 128, 144 },
189     { "slategrey",            112, 128, 144 },
190     { "snow",                 255, 250, 250 },
191     { "springgreen",            0, 255, 127 },
192     { "steelblue",             70, 130, 180 },
193     { "tan",                  210, 180, 140 },
194     { "teal",                   0, 128, 128 },
195     { "thistle",              216, 191, 216 },
196     { "tomato",               255,  99,  71 },
197     { "turquoise",             64, 224, 208 },
198     { "violet",               238, 130, 238 },
199     { "wheat",                245, 222, 179 },
200     { "white",                255, 255, 255 },
201     { "whitesmoke",           245, 245, 245 },
202     { "yellow",               255, 255,   0 },
203     { "yellowgreen",          154, 205,  50 },
204     { NULL,                     0,   0,   0 }
205 };
206 
207 /* Take a hex value for a color and find best matching css3 color name using:
208    https://en.wikipedia.org/wiki/Color_difference */
css3_color_hex_to_name(const char * hexstr)209 const char *css3_color_hex_to_name(const char *hexstr)
210 {
211     if (!hexstr || hexstr[0] != '#') return NULL;
212 
213     size_t hexlen = strlen(hexstr);
214 
215     if (hexlen != 7 && hexlen != 9) return NULL;
216 
217     /* Convert hex encoded color into separate RGB */
218     long hex = strtol(hexstr+1, NULL, 16);
219     if (hexlen == 9) hex >>= 8;  /* drop last 2 digits */
220 
221     struct {
222         unsigned char r, g, b;
223     } C;
224 
225     C.b = (hex & 0x0000ff);
226     hex >>= 8;
227     C.g = (hex & 0x00ff);
228     hex >>= 8;
229     C.r = (hex & 0xff);
230 
231     const struct css3_color_t *css;
232     unsigned long best = ULONG_MAX;
233     const char *name = NULL;
234 
235     for (css = css3_colors; css->name; css++) {
236         int dR = css->r - C.r;
237         int dG = css->g - C.g;
238         int dB = css->b - C.b;
239 
240         if (dR == 0 && dG == 0 && dB == 0) return css->name;
241 
242         unsigned dR2 = dR * dR;
243         unsigned dG2 = dG * dG;
244         unsigned dB2 = dB * dB;
245         unsigned long dC = 2*dR2 + 4*dG2 + 3*dB2;
246 
247         unsigned r = (css->r + C.r) / 2;
248         dC += (r * (dR2 - dB2)) / 256;
249 
250         if (dC < best) {
251             best = dC;
252             name = css->name;
253         }
254     }
255 
256     return name;
257 }
258