comparison mupdf-source/source/svg/svg-color.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2021 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24 #include "svg-imp.h"
25
26 #include <string.h>
27
28 /* Color keywords (white, blue, fuchsia)
29 * System color keywords (ActiveBorder, ButtonFace -- need to find reasonable defaults)
30 * #fb0 (expand to #ffbb00)
31 * #ffbb00
32 * rgb(255,255,255)
33 * rgb(100%,100%,100%)
34 *
35 * "red icc-color(profileName,255,0,0)" (not going to support for now)
36 */
37
38 struct
39 {
40 const char *name;
41 float red, green, blue;
42 }
43 svg_predefined_colors[] =
44 {
45 { "aliceblue", 240, 248, 255 },
46 { "antiquewhite", 250, 235, 215 },
47 { "aqua", 0, 255, 255 },
48 { "aquamarine", 127, 255, 212 },
49 { "azure", 240, 255, 255 },
50 { "beige", 245, 245, 220 },
51 { "bisque", 255, 228, 196 },
52 { "black", 0, 0, 0 },
53 { "blanchedalmond", 255, 235, 205 },
54 { "blue", 0, 0, 255 },
55 { "blueviolet", 138, 43, 226 },
56 { "brown", 165, 42, 42 },
57 { "burlywood", 222, 184, 135 },
58 { "cadetblue", 95, 158, 160 },
59 { "chartreuse", 127, 255, 0 },
60 { "chocolate", 210, 105, 30 },
61 { "coral", 255, 127, 80 },
62 { "cornflowerblue", 100, 149, 237 },
63 { "cornsilk", 255, 248, 220 },
64 { "crimson", 220, 20, 60 },
65 { "cyan", 0, 255, 255 },
66 { "darkblue", 0, 0, 139 },
67 { "darkcyan", 0, 139, 139 },
68 { "darkgoldenrod", 184, 134, 11 },
69 { "darkgray", 169, 169, 169 },
70 { "darkgreen", 0, 100, 0 },
71 { "darkgrey", 169, 169, 169 },
72 { "darkkhaki", 189, 183, 107 },
73 { "darkmagenta", 139, 0, 139 },
74 { "darkolivegreen", 85, 107, 47 },
75 { "darkorange", 255, 140, 0 },
76 { "darkorchid", 153, 50, 204 },
77 { "darkred", 139, 0, 0 },
78 { "darksalmon", 233, 150, 122 },
79 { "darkseagreen", 143, 188, 143 },
80 { "darkslateblue", 72, 61, 139 },
81 { "darkslategray", 47, 79, 79 },
82 { "darkslategrey", 47, 79, 79 },
83 { "darkturquoise", 0, 206, 209 },
84 { "darkviolet", 148, 0, 211 },
85 { "deeppink", 255, 20, 147 },
86 { "deepskyblue", 0, 191, 255 },
87 { "dimgray", 105, 105, 105 },
88 { "dimgrey", 105, 105, 105 },
89 { "dodgerblue", 30, 144, 255 },
90 { "firebrick", 178, 34, 34 },
91 { "floralwhite", 255, 250, 240 },
92 { "forestgreen", 34, 139, 34 },
93 { "fuchsia", 255, 0, 255 },
94 { "gainsboro", 220, 220, 220 },
95 { "ghostwhite", 248, 248, 255 },
96 { "gold", 255, 215, 0 },
97 { "goldenrod", 218, 165, 32 },
98 { "gray", 128, 128, 128 },
99 { "green", 0, 128, 0 },
100 { "greenyellow", 173, 255, 47 },
101 { "grey", 128, 128, 128 },
102 { "honeydew", 240, 255, 240 },
103 { "hotpink", 255, 105, 180 },
104 { "indianred", 205, 92, 92 },
105 { "indigo", 75, 0, 130 },
106 { "ivory", 255, 255, 240 },
107 { "khaki", 240, 230, 140 },
108 { "lavender", 230, 230, 250 },
109 { "lavenderblush", 255, 240, 245 },
110 { "lawngreen", 124, 252, 0 },
111 { "lemonchiffon", 255, 250, 205 },
112 { "lightblue", 173, 216, 230 },
113 { "lightcoral", 240, 128, 128 },
114 { "lightcyan", 224, 255, 255 },
115 { "lightgoldenrodyellow", 250, 250, 210 },
116 { "lightgray", 211, 211, 211 },
117 { "lightgreen", 144, 238, 144 },
118 { "lightgrey", 211, 211, 211 },
119 { "lightpink", 255, 182, 193 },
120 { "lightsalmon", 255, 160, 122 },
121 { "lightseagreen", 32, 178, 170 },
122 { "lightskyblue", 135, 206, 250 },
123 { "lightslategray", 119, 136, 153 },
124 { "lightslategrey", 119, 136, 153 },
125 { "lightsteelblue", 176, 196, 222 },
126 { "lightyellow", 255, 255, 224 },
127 { "lime", 0, 255, 0 },
128 { "limegreen", 50, 205, 50 },
129 { "linen", 250, 240, 230 },
130 { "magenta", 255, 0, 255 },
131 { "maroon", 128, 0, 0 },
132 { "mediumaquamarine", 102, 205, 170 },
133 { "mediumblue", 0, 0, 205 },
134 { "mediumorchid", 186, 85, 211 },
135 { "mediumpurple", 147, 112, 219 },
136 { "mediumseagreen", 60, 179, 113 },
137 { "mediumslateblue", 123, 104, 238 },
138 { "mediumspringgreen", 0, 250, 154 },
139 { "mediumturquoise", 72, 209, 204 },
140 { "mediumvioletred", 199, 21, 133 },
141 { "midnightblue", 25, 25, 112 },
142 { "mintcream", 245, 255, 250 },
143 { "mistyrose", 255, 228, 225 },
144 { "moccasin", 255, 228, 181 },
145 { "navajowhite", 255, 222, 173 },
146 { "navy", 0, 0, 128 },
147 { "oldlace", 253, 245, 230 },
148 { "olive", 128, 128, 0 },
149 { "olivedrab", 107, 142, 35 },
150 { "orange", 255, 165, 0 },
151 { "orangered", 255, 69, 0 },
152 { "orchid", 218, 112, 214 },
153 { "palegoldenrod", 238, 232, 170 },
154 { "palegreen", 152, 251, 152 },
155 { "paleturquoise", 175, 238, 238 },
156 { "palevioletred", 219, 112, 147 },
157 { "papayawhip", 255, 239, 213 },
158 { "peachpuff", 255, 218, 185 },
159 { "peru", 205, 133, 63 },
160 { "pink", 255, 192, 203 },
161 { "plum", 221, 160, 221 },
162 { "powderblue", 176, 224, 230 },
163 { "purple", 128, 0, 128 },
164 { "red", 255, 0, 0 },
165 { "rosybrown", 188, 143, 143 },
166 { "royalblue", 65, 105, 225 },
167 { "saddlebrown", 139, 69, 19 },
168 { "salmon", 250, 128, 114 },
169 { "sandybrown", 244, 164, 96 },
170 { "seagreen", 46, 139, 87 },
171 { "seashell", 255, 245, 238 },
172 { "sienna", 160, 82, 45 },
173 { "silver", 192, 192, 192 },
174 { "skyblue", 135, 206, 235 },
175 { "slateblue", 106, 90, 205 },
176 { "slategray", 112, 128, 144 },
177 { "slategrey", 112, 128, 144 },
178 { "snow", 255, 250, 250 },
179 { "springgreen", 0, 255, 127 },
180 { "steelblue", 70, 130, 180 },
181 { "tan", 210, 180, 140 },
182 { "teal", 0, 128, 128 },
183 { "thistle", 216, 191, 216 },
184 { "tomato", 255, 99, 71 },
185 { "turquoise", 64, 224, 208 },
186 { "violet", 238, 130, 238 },
187 { "wheat", 245, 222, 179 },
188 { "white", 255, 255, 255 },
189 { "whitesmoke", 245, 245, 245 },
190 { "yellow", 255, 255, 0 },
191 { "yellowgreen", 154, 205, 50 },
192 };
193
194 static int unhex(int chr)
195 {
196 const char *hextable = "0123456789abcdef";
197 return strchr(hextable, (chr|32)) - hextable;
198 }
199
200 static int ishex(int chr)
201 {
202 if (chr >= '0' && chr <= '9') return 1;
203 if (chr >= 'A' && chr <= 'F') return 1;
204 if (chr >= 'a' && chr <= 'f') return 1;
205 return 0;
206 }
207
208 void
209 svg_parse_color(fz_context *ctx, svg_document *doc, const char *str, float *rgb)
210 {
211 int i, l, m, r, cmp;
212 size_t n;
213
214 rgb[0] = 0.0f;
215 rgb[1] = 0.0f;
216 rgb[2] = 0.0f;
217
218 /* Crack hex-coded RGB */
219
220 if (str[0] == '#')
221 {
222 str ++;
223
224 n = strlen(str);
225 if (n == 3 || (n > 3 && !ishex(str[3])))
226 {
227 rgb[0] = (unhex(str[0]) * 16 + unhex(str[0])) / 255.0f;
228 rgb[1] = (unhex(str[1]) * 16 + unhex(str[1])) / 255.0f;
229 rgb[2] = (unhex(str[2]) * 16 + unhex(str[2])) / 255.0f;
230 return;
231 }
232
233 if (n >= 6)
234 {
235 rgb[0] = (unhex(str[0]) * 16 + unhex(str[1])) / 255.0f;
236 rgb[1] = (unhex(str[2]) * 16 + unhex(str[3])) / 255.0f;
237 rgb[2] = (unhex(str[4]) * 16 + unhex(str[5])) / 255.0f;
238 return;
239 }
240
241 return;
242 }
243
244 /* rgb(X,Y,Z) -- whitespace allowed around numbers */
245
246 else if (strstr(str, "rgb("))
247 {
248 int numberlen = 0;
249 char numberbuf[50];
250
251 str = str + 4;
252
253 for (i = 0; i < 3; i++)
254 {
255 while (svg_is_whitespace_or_comma(*str))
256 str ++;
257
258 if (svg_is_digit(*str))
259 {
260 numberlen = 0;
261 while (svg_is_digit(*str) && numberlen < (int)sizeof(numberbuf) - 1)
262 numberbuf[numberlen++] = *str++;
263 numberbuf[numberlen] = 0;
264
265 if (*str == '%')
266 {
267 str ++;
268 rgb[i] = fz_atof(numberbuf) / 100.0f;
269 }
270 else
271 {
272 rgb[i] = fz_atof(numberbuf) / 255.0f;
273 }
274 }
275 }
276
277 return;
278 }
279
280 /* TODO: parse icc-profile(X,Y,Z,W) syntax */
281
282 /* Search for a pre-defined color */
283
284 else
285 {
286 char keyword[50], *p;
287 fz_strlcpy(keyword, str, sizeof keyword);
288 p = keyword;
289 while (*p && *p >= 'a' && *p <= 'z')
290 ++p;
291 *p = 0;
292
293 l = 0;
294 r = nelem(svg_predefined_colors) - 1;
295
296 while (l <= r)
297 {
298 m = (l + r) / 2;
299 cmp = strcmp(svg_predefined_colors[m].name, keyword);
300 if (cmp > 0)
301 r = m - 1;
302 else if (cmp < 0)
303 l = m + 1;
304 else
305 {
306 rgb[0] = svg_predefined_colors[m].red / 255.0f;
307 rgb[1] = svg_predefined_colors[m].green / 255.0f;
308 rgb[2] = svg_predefined_colors[m].blue / 255.0f;
309 return;
310 }
311 }
312 }
313 }
314
315 static int
316 svg_parse_color_from_style_string(fz_context *ctx, svg_document *doc, const char *p, float color[3])
317 {
318 char buf[100], *e;
319 while (*p && svg_is_whitespace(*p))
320 ++p;
321 fz_strlcpy(buf, p, sizeof buf);
322 e = strchr(buf, ';');
323 if (e)
324 *e = 0;
325 if (!strcmp(buf, "none"))
326 return 0;
327 svg_parse_color(ctx, doc, buf, color);
328 return 1;
329 }
330
331 void
332 svg_parse_color_from_style(fz_context *ctx, svg_document *doc, const char *str,
333 int *fill_is_set, float fill[3],
334 int *stroke_is_set, float stroke[3])
335 {
336 const char *p;
337
338 p = strstr(str, "fill:");
339 if (p)
340 *fill_is_set = svg_parse_color_from_style_string(ctx, doc, p+5, fill);
341
342 p = strstr(str, "stroke:");
343 if (p)
344 *stroke_is_set = svg_parse_color_from_style_string(ctx, doc, p+7, stroke);
345 }