1 #define __SP_SVG_COLOR_C__
3 /**
4 * \file
5 * Reading \& writing of SVG/CSS colors.
6 */
7 /*
8 * Authors:
9 * Lauris Kaplinski <lauris@kaplinski.com>
10 *
11 * Copyright (C) 1999-2002 Lauris Kaplinski
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #include <math.h>
21 #include <glib/gstrfuncs.h>
22 #include <glib/ghash.h>
23 #include <glib/gutils.h>
25 #include "svg.h"
27 struct SPSVGColor {
28 unsigned long rgb;
29 char const *name;
30 };
32 /*
33 * These are the colors defined in the SVG standard
34 */
35 static SPSVGColor const sp_svg_color_named[] = {
36 { 0xF0F8FF, "aliceblue" },
37 { 0xFAEBD7, "antiquewhite" },
38 { 0x00FFFF, "aqua" },
39 { 0x7FFFD4, "aquamarine" },
40 { 0xF0FFFF, "azure" },
41 { 0xF5F5DC, "beige" },
42 { 0xFFE4C4, "bisque" },
43 { 0x000000, "black" },
44 { 0xFFEBCD, "blanchedalmond" },
45 { 0x0000FF, "blue" },
46 { 0x8A2BE2, "blueviolet" },
47 { 0xA52A2A, "brown" },
48 { 0xDEB887, "burlywood" },
49 { 0x5F9EA0, "cadetblue" },
50 { 0x7FFF00, "chartreuse" },
51 { 0xD2691E, "chocolate" },
52 { 0xFF7F50, "coral" },
53 { 0x6495ED, "cornflowerblue" },
54 { 0xFFF8DC, "cornsilk" },
55 { 0xDC143C, "crimson" },
56 { 0x00FFFF, "cyan" },
57 { 0x00008B, "darkblue" },
58 { 0x008B8B, "darkcyan" },
59 { 0xB8860B, "darkgoldenrod" },
60 { 0xA9A9A9, "darkgray" },
61 { 0x006400, "darkgreen" },
62 { 0xA9A9A9, "darkgrey" },
63 { 0xBDB76B, "darkkhaki" },
64 { 0x8B008B, "darkmagenta" },
65 { 0x556B2F, "darkolivegreen" },
66 { 0xFF8C00, "darkorange" },
67 { 0x9932CC, "darkorchid" },
68 { 0x8B0000, "darkred" },
69 { 0xE9967A, "darksalmon" },
70 { 0x8FBC8F, "darkseagreen" },
71 { 0x483D8B, "darkslateblue" },
72 { 0x2F4F4F, "darkslategray" },
73 { 0x2F4F4F, "darkslategrey" },
74 { 0x00CED1, "darkturquoise" },
75 { 0x9400D3, "darkviolet" },
76 { 0xFF1493, "deeppink" },
77 { 0x00BFFF, "deepskyblue" },
78 { 0x696969, "dimgray" },
79 { 0x696969, "dimgrey" },
80 { 0x1E90FF, "dodgerblue" },
81 { 0xB22222, "firebrick" },
82 { 0xFFFAF0, "floralwhite" },
83 { 0x228B22, "forestgreen" },
84 { 0xFF00FF, "fuchsia" },
85 { 0xDCDCDC, "gainsboro" },
86 { 0xF8F8FF, "ghostwhite" },
87 { 0xFFD700, "gold" },
88 { 0xDAA520, "goldenrod" },
89 { 0x808080, "gray" },
90 { 0x808080, "grey" },
91 { 0x008000, "green" },
92 { 0xADFF2F, "greenyellow" },
93 { 0xF0FFF0, "honeydew" },
94 { 0xFF69B4, "hotpink" },
95 { 0xCD5C5C, "indianred" },
96 { 0x4B0082, "indigo" },
97 { 0xFFFFF0, "ivory" },
98 { 0xF0E68C, "khaki" },
99 { 0xE6E6FA, "lavender" },
100 { 0xFFF0F5, "lavenderblush" },
101 { 0x7CFC00, "lawngreen" },
102 { 0xFFFACD, "lemonchiffon" },
103 { 0xADD8E6, "lightblue" },
104 { 0xF08080, "lightcoral" },
105 { 0xE0FFFF, "lightcyan" },
106 { 0xFAFAD2, "lightgoldenrodyellow" },
107 { 0xD3D3D3, "lightgray" },
108 { 0x90EE90, "lightgreen" },
109 { 0xD3D3D3, "lightgrey" },
110 { 0xFFB6C1, "lightpink" },
111 { 0xFFA07A, "lightsalmon" },
112 { 0x20B2AA, "lightseagreen" },
113 { 0x87CEFA, "lightskyblue" },
114 { 0x778899, "lightslategray" },
115 { 0x778899, "lightslategrey" },
116 { 0xB0C4DE, "lightsteelblue" },
117 { 0xFFFFE0, "lightyellow" },
118 { 0x00FF00, "lime" },
119 { 0x32CD32, "limegreen" },
120 { 0xFAF0E6, "linen" },
121 { 0xFF00FF, "magenta" },
122 { 0x800000, "maroon" },
123 { 0x66CDAA, "mediumaquamarine" },
124 { 0x0000CD, "mediumblue" },
125 { 0xBA55D3, "mediumorchid" },
126 { 0x9370DB, "mediumpurple" },
127 { 0x3CB371, "mediumseagreen" },
128 { 0x7B68EE, "mediumslateblue" },
129 { 0x00FA9A, "mediumspringgreen" },
130 { 0x48D1CC, "mediumturquoise" },
131 { 0xC71585, "mediumvioletred" },
132 { 0x191970, "midnightblue" },
133 { 0xF5FFFA, "mintcream" },
134 { 0xFFE4E1, "mistyrose" },
135 { 0xFFE4B5, "moccasin" },
136 { 0xFFDEAD, "navajowhite" },
137 { 0x000080, "navy" },
138 { 0xFDF5E6, "oldlace" },
139 { 0x808000, "olive" },
140 { 0x6B8E23, "olivedrab" },
141 { 0xFFA500, "orange" },
142 { 0xFF4500, "orangered" },
143 { 0xDA70D6, "orchid" },
144 { 0xEEE8AA, "palegoldenrod" },
145 { 0x98FB98, "palegreen" },
146 { 0xAFEEEE, "paleturquoise" },
147 { 0xDB7093, "palevioletred" },
148 { 0xFFEFD5, "papayawhip" },
149 { 0xFFDAB9, "peachpuff" },
150 { 0xCD853F, "peru" },
151 { 0xFFC0CB, "pink" },
152 { 0xDDA0DD, "plum" },
153 { 0xB0E0E6, "powderblue" },
154 { 0x800080, "purple" },
155 { 0xFF0000, "red" },
156 { 0xBC8F8F, "rosybrown" },
157 { 0x4169E1, "royalblue" },
158 { 0x8B4513, "saddlebrown" },
159 { 0xFA8072, "salmon" },
160 { 0xF4A460, "sandybrown" },
161 { 0x2E8B57, "seagreen" },
162 { 0xFFF5EE, "seashell" },
163 { 0xA0522D, "sienna" },
164 { 0xC0C0C0, "silver" },
165 { 0x87CEEB, "skyblue" },
166 { 0x6A5ACD, "slateblue" },
167 { 0x708090, "slategray" },
168 { 0x708090, "slategrey" },
169 { 0xFFFAFA, "snow" },
170 { 0x00FF7F, "springgreen" },
171 { 0x4682B4, "steelblue" },
172 { 0xD2B48C, "tan" },
173 { 0x008080, "teal" },
174 { 0xD8BFD8, "thistle" },
175 { 0xFF6347, "tomato" },
176 { 0x40E0D0, "turquoise" },
177 { 0xEE82EE, "violet" },
178 { 0xF5DEB3, "wheat" },
179 { 0xFFFFFF, "white" },
180 { 0xF5F5F5, "whitesmoke" },
181 { 0xFFFF00, "yellow" },
182 { 0x9ACD32, "yellowgreen" }
183 };
185 #define SP_SVG_NUMCOLORS (sizeof(sp_svg_color_named) / sizeof(sp_svg_color_named[0]))
187 static GHashTable *sp_svg_create_color_hash();
189 guint32
190 sp_svg_read_color(gchar const *str, guint32 def)
191 {
192 static GHashTable *colors = NULL;
193 gchar c[32];
194 guint32 val = 0;
196 /*
197 * todo: handle the rgb (r, g, b) and rgb ( r%, g%, b%), syntax
198 * defined in http://www.w3.org/TR/REC-CSS2/syndata.html#color-units
199 */
201 if (str == NULL) return def;
202 while ((*str <= ' ') && *str) str++;
203 if (!*str) return def;
205 if (str[0] == '#') {
206 gint i;
207 for (i = 1; str[i]; i++) {
208 int hexval;
209 if (str[i] >= '0' && str[i] <= '9')
210 hexval = str[i] - '0';
211 else if (str[i] >= 'A' && str[i] <= 'F')
212 hexval = str[i] - 'A' + 10;
213 else if (str[i] >= 'a' && str[i] <= 'f')
214 hexval = str[i] - 'a' + 10;
215 else
216 break;
217 val = (val << 4) + hexval;
218 }
219 /* handle #rgb case */
220 if (i == 1 + 3) {
221 val = ((val & 0xf00) << 8) |
222 ((val & 0x0f0) << 4) |
223 (val & 0x00f);
224 val |= val << 4;
225 } else if (i != 1 + 6) {
226 /* must be either 3 or 6 digits. */
227 return def;
228 }
229 } else if (!strncmp(str, "rgb(", 4)) {
230 gboolean hasp, hasd;
231 gchar *s, *e;
232 gdouble r, g, b;
234 s = (gchar *) str + 4;
235 hasp = FALSE;
236 hasd = FALSE;
238 r = g_ascii_strtod(s, &e);
239 if (s == e) return def;
240 s = e;
241 if (*s == '%') {
242 hasp = TRUE;
243 s += 1;
244 } else {
245 hasd = TRUE;
246 }
247 while (*s && g_ascii_isspace(*s)) s += 1;
248 if (*s != ',') return def;
249 s += 1;
250 while (*s && g_ascii_isspace(*s)) s += 1;
251 g = g_ascii_strtod(s, &e);
252 if (s == e) return def;
253 s = e;
254 if (*s == '%') {
255 hasp = TRUE;
256 s += 1;
257 } else {
258 hasd = TRUE;
259 }
260 while (*s && g_ascii_isspace(*s)) s += 1;
261 if (*s != ',') return def;
262 s += 1;
263 while (*s && g_ascii_isspace(*s)) s += 1;
264 b = g_ascii_strtod(s, &e);
265 if (s == e) return def;
266 s = e;
267 if (*s == '%') {
268 hasp = TRUE;
269 } else {
270 hasd = TRUE;
271 }
272 if (hasp && hasd) return def;
273 if (hasp) {
274 val = (guint) floor(CLAMP(r, 0.0, 100.0) * 2.559999) << 24;
275 val |= ((guint) floor(CLAMP(g, 0.0, 100.0) * 2.559999) << 16);
276 val |= ((guint) floor(CLAMP(b, 0.0, 100.0) * 2.559999) << 8);
277 } else {
278 val = (guint) CLAMP(r, 0, 255) << 24;
279 val |= ((guint) CLAMP(g, 0, 255) << 16);
280 val |= ((guint) CLAMP(b, 0, 255) << 8);
281 }
282 return val;
283 } else {
284 gint i;
285 if (!colors) {
286 colors = sp_svg_create_color_hash();
287 }
288 for (i = 0; i < 31; i++) {
289 if (str[i] == ';') {
290 c[i] = '\0';
291 break;
292 }
293 c[i] = g_ascii_tolower(str[i]);
294 if (!str[i]) break;
295 }
296 c[31] = '\0';
298 gpointer const rgb_ptr = g_hash_table_lookup(colors, c);
299 if (rgb_ptr) {
300 val = *(static_cast<unsigned long *>(rgb_ptr));
301 } else {
302 return def;
303 }
304 }
306 return (val << 8);
307 }
309 gint
310 sp_svg_write_color(gchar *buf, gint buflen, guint32 color)
311 {
312 return g_snprintf(buf, buflen, "#%06x", color >> 8);
313 }
315 static GHashTable *
316 sp_svg_create_color_hash()
317 {
318 GHashTable *colors = g_hash_table_new(g_str_hash, g_str_equal);
320 for (unsigned i = 0 ; i < SP_SVG_NUMCOLORS ; i++) {
321 g_hash_table_insert(colors,
322 (gpointer)(sp_svg_color_named[i].name),
323 (gpointer)(&sp_svg_color_named[i].rgb));
324 }
326 return colors;
327 }
329 /*
330 Local Variables:
331 mode:c++
332 c-file-style:"stroustrup"
333 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
334 indent-tabs-mode:nil
335 fill-column:99
336 End:
337 */
338 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :