1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include <stdio.h>
15 
16 
17 #include <stdlib.h>
18 #ifdef _WIN32
19 #include <string.h>
20 #include <ctype.h>
21 #include "compat.h"
22 #endif
23 #include <string.h>
24 #include <ctype.h>
25 
26 #include "arith.h"
27 #include "color.h"
28 #include "colorprocs.h"
29 #include "colortbl.h"
30 #include "memory.h"
31 
32 static char* colorscheme;
33 
34 #ifdef _MSC_VER
35 extern int strcasecmp(const char *s1, const char *s2);
36 extern int strncasecmp(const char *s1, const char *s2, unsigned int n);
37 #endif
38 
39 
hsv2rgb(double h,double s,double v,double * r,double * g,double * b)40 static void hsv2rgb(double h, double s, double v,
41 			double *r, double *g, double *b)
42 {
43     int i;
44     double f, p, q, t;
45 
46     if (s <= 0.0) {		/* achromatic */
47 	*r = v;
48 	*g = v;
49 	*b = v;
50     } else {
51 	if (h >= 1.0)
52 	    h = 0.0;
53 	h = 6.0 * h;
54 	i = (int) h;
55 	f = h - (double) i;
56 	p = v * (1 - s);
57 	q = v * (1 - (s * f));
58 	t = v * (1 - (s * (1 - f)));
59 	switch (i) {
60 	case 0:
61 	    *r = v;
62 	    *g = t;
63 	    *b = p;
64 	    break;
65 	case 1:
66 	    *r = q;
67 	    *g = v;
68 	    *b = p;
69 	    break;
70 	case 2:
71 	    *r = p;
72 	    *g = v;
73 	    *b = t;
74 	    break;
75 	case 3:
76 	    *r = p;
77 	    *g = q;
78 	    *b = v;
79 	    break;
80 	case 4:
81 	    *r = t;
82 	    *g = p;
83 	    *b = v;
84 	    break;
85 	case 5:
86 	    *r = v;
87 	    *g = p;
88 	    *b = q;
89 	    break;
90 	}
91     }
92 }
93 
rgb2hsv(double r,double g,double b,double * h,double * s,double * v)94 static void rgb2hsv(double r, double g, double b,
95 		double *h, double *s, double *v)
96 {
97 
98     double rgbmin, rgbmax;
99     double rc, bc, gc;
100     double ht = 0.0, st = 0.0;
101 
102     rgbmin = MIN(r, MIN(g, b));
103     rgbmax = MAX(r, MAX(g, b));
104 
105     if (rgbmax > 0.0)
106 	st = (rgbmax - rgbmin) / rgbmax;
107 
108     if (st > 0.0) {
109 	rc = (rgbmax - r) / (rgbmax - rgbmin);
110 	gc = (rgbmax - g) / (rgbmax - rgbmin);
111 	bc = (rgbmax - b) / (rgbmax - rgbmin);
112 	if (r == rgbmax)
113 	    ht = bc - gc;
114 	else if (g == rgbmax)
115 	    ht = 2 + rc - bc;
116 	else if (b == rgbmax)
117 	    ht = 4 + gc - rc;
118 	ht = ht * 60.0;
119 	if (ht < 0.0)
120 	    ht += 360.0;
121     }
122     *h = ht / 360.0;
123     *v = rgbmax;
124     *s = st;
125 }
126 
rgb2cmyk(double r,double g,double b,double * c,double * m,double * y,double * k)127 static void rgb2cmyk(double r, double g, double b, double *c, double *m,
128 		     double *y, double *k)
129 {
130     *c = 1.0 - r;
131     *m = 1.0 - g;
132     *y = 1.0 - b;
133     *k = *c < *m ? *c : *m;
134     *k = *y < *k ? *y : *k;
135     *c -= *k;
136     *m -= *k;
137     *y -= *k;
138 }
139 
colorcmpf(const void * p0,const void * p1)140 static int colorcmpf(const void *p0, const void *p1)
141 {
142     return strcasecmp(((hsvrgbacolor_t *) p0)->name, ((hsvrgbacolor_t *) p1)->name);
143 }
144 
canontoken(char * str)145 char *canontoken(char *str)
146 {
147     static unsigned char *canon;
148     static size_t allocated;
149     unsigned char c, *p, *q;
150     size_t len;
151 
152     p = (unsigned char *) str;
153     len = strlen(str);
154     if (len >= allocated) {
155 	allocated = len + 1 + 10;
156 	canon = grealloc(canon, allocated);
157 	if (!canon)
158 	    return NULL;
159     }
160     q = (unsigned char *) canon;
161     while ((c = *p++)) {
162 	/* if (isalnum(c) == FALSE) */
163 	    /* continue; */
164 	if (isupper(c))
165 	    c = (unsigned char) tolower(c);
166 	*q++ = c;
167     }
168     *q = '\0';
169     return (char*)canon;
170 }
171 
172 /* fullColor:
173  * Return "/prefix/str"
174  */
fullColor(char * prefix,char * str)175 static char* fullColor (char* prefix, char* str)
176 {
177     static char *fulls;
178     static size_t allocated;
179     size_t len = strlen(prefix) + strlen(str) + 3;
180 
181     if (len >= allocated) {
182 	allocated = len + 10;
183 	fulls = grealloc(fulls, allocated);
184     }
185     sprintf (fulls, "/%s/%s", prefix, str);
186     return fulls;
187 }
188 
189 /* resolveColor:
190  * Resolve input color str allowing color scheme namespaces.
191  *  0) "black" => "black"
192  *     "white" => "white"
193  *     "lightgrey" => "lightgrey"
194  *    NB: This is something of a hack due to the remaining codegen.
195  *        Once these are gone, this case could be removed and all references
196  *        to "black" could be replaced by "/X11/black".
197  *  1) No initial / =>
198  *          if colorscheme is defined and no "X11", return /colorscheme/str
199  *          else return str
200  *  2) One initial / => return str+1
201  *  3) Two initial /'s =>
202  *       a) If colorscheme is defined and not "X11", return /colorscheme/(str+2)
203  *       b) else return (str+2)
204  *  4) Two /'s, not both initial => return str.
205  *
206  * Note that 1), 2), and 3b) allow the default X11 color scheme.
207  *
208  * In other words,
209  *   xxx => /colorscheme/xxx     if colorscheme is defined and not "X11"
210  *   xxx => xxx                  otherwise
211  *   /xxx => xxx
212  *   /X11/yyy => yyy
213  *   /xxx/yyy => /xxx/yyy
214  *   //yyy => /colorscheme/yyy   if colorscheme is defined and not "X11"
215  *   //yyy => yyy                otherwise
216  *
217  * At present, no other error checking is done. For example,
218  * yyy could be "". This will be caught later.
219  */
220 
221 #define DFLT_SCHEME "X11/"      /* Must have final '/' */
222 #define DFLT_SCHEME_LEN ((sizeof(DFLT_SCHEME)-1)/sizeof(char))
223 #define ISNONDFLT(s) ((s) && *(s) && strncasecmp(DFLT_SCHEME, s, DFLT_SCHEME_LEN-1))
224 
resolveColor(char * str)225 static char* resolveColor (char* str)
226 {
227     char* s;
228     char* ss;   /* second slash */
229     char* c2;   /* second char */
230 
231     if (!strcmp(str, "black")) return str;
232     if (!strcmp(str, "white")) return str;
233     if (!strcmp(str, "lightgrey")) return str;
234     if (*str == '/') {   /* if begins with '/' */
235 	c2 = str+1;
236         if ((ss = strchr(c2, '/'))) {  /* if has second '/' */
237 	    if (*c2 == '/') {    /* if second '/' is second character */
238 		    /* Do not compare against final '/' */
239 		if (ISNONDFLT(colorscheme))
240 		    s = fullColor (colorscheme, c2+1);
241 		else
242 		    s = c2+1;
243 	    }
244 	    else if (strncasecmp(DFLT_SCHEME, c2, DFLT_SCHEME_LEN)) s = str;
245 	    else s = ss + 1;
246 	}
247 	else s = c2;
248     }
249     else if (ISNONDFLT(colorscheme)) s = fullColor (colorscheme, str);
250     else s = str;
251     return canontoken(s);
252 }
253 
colorxlate(char * str,gvcolor_t * color,color_type_t target_type)254 int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
255 {
256     static hsvrgbacolor_t *last;
257     static unsigned char *canon;
258     static size_t allocated;
259     unsigned char *p, *q;
260     hsvrgbacolor_t fake;
261     unsigned char c;
262     double H, S, V, A, R, G, B;
263     double C, M, Y, K;
264     unsigned int r, g, b, a;
265     size_t len;
266     int rc;
267 
268     color->type = target_type;
269 
270     rc = COLOR_OK;
271     for (; *str == ' '; str++);	/* skip over any leading whitespace */
272     p = (unsigned char *) str;
273 
274     /* test for rgb value such as: "#ff0000"
275        or rgba value such as "#ff000080" */
276     a = 255;			/* default alpha channel value=opaque in case not supplied */
277     if ((*p == '#')
278 	&& (sscanf((char *) p, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3)) {
279 	switch (target_type) {
280 	case HSVA_DOUBLE:
281 	    R = (double) r / 255.0;
282 	    G = (double) g / 255.0;
283 	    B = (double) b / 255.0;
284 	    A = (double) a / 255.0;
285 	    rgb2hsv(R, G, B, &H, &S, &V);
286 	    color->u.HSVA[0] = H;
287 	    color->u.HSVA[1] = S;
288 	    color->u.HSVA[2] = V;
289 	    color->u.HSVA[3] = A;
290 	    break;
291 	case RGBA_BYTE:
292 	    color->u.rgba[0] = r;
293 	    color->u.rgba[1] = g;
294 	    color->u.rgba[2] = b;
295 	    color->u.rgba[3] = a;
296 	    break;
297 	case CMYK_BYTE:
298 	    R = (double) r / 255.0;
299 	    G = (double) g / 255.0;
300 	    B = (double) b / 255.0;
301 	    rgb2cmyk(R, G, B, &C, &M, &Y, &K);
302 	    color->u.cmyk[0] = (int) C *255;
303 	    color->u.cmyk[1] = (int) M *255;
304 	    color->u.cmyk[2] = (int) Y *255;
305 	    color->u.cmyk[3] = (int) K *255;
306 	    break;
307 	case RGBA_WORD:
308 	    color->u.rrggbbaa[0] = r * 65535 / 255;
309 	    color->u.rrggbbaa[1] = g * 65535 / 255;
310 	    color->u.rrggbbaa[2] = b * 65535 / 255;
311 	    color->u.rrggbbaa[3] = a * 65535 / 255;
312 	    break;
313 	case RGBA_DOUBLE:
314 	    color->u.RGBA[0] = (double) r / 255.0;
315 	    color->u.RGBA[1] = (double) g / 255.0;
316 	    color->u.RGBA[2] = (double) b / 255.0;
317 	    color->u.RGBA[3] = (double) a / 255.0;
318 	    break;
319 	case COLOR_STRING:
320 	    break;
321 	case COLOR_INDEX:
322 	    break;
323 	}
324 	return rc;
325     }
326 
327     /* test for hsv value such as: ".6,.5,.3" */
328     if (((c = *p) == '.') || isdigit(c)) {
329 	len = strlen((char*)p);
330 	if (len >= allocated) {
331 	    allocated = len + 1 + 10;
332 	    canon = grealloc(canon, allocated);
333 	    if (! canon) {
334 		rc = COLOR_MALLOC_FAIL;
335 		return rc;
336 	    }
337 	}
338 	q = canon;
339 	while ((c = *p++)) {
340 	    if (c == ',')
341 		c = ' ';
342 	    *q++ = c;
343 	}
344 	*q = '\0';
345 
346 	if (sscanf((char *) canon, "%lf%lf%lf", &H, &S, &V) == 3) {
347 	    /* clip to reasonable values */
348 	    H = MAX(MIN(H, 1.0), 0.0);
349 	    S = MAX(MIN(S, 1.0), 0.0);
350 	    V = MAX(MIN(V, 1.0), 0.0);
351 	    switch (target_type) {
352 	    case HSVA_DOUBLE:
353 		color->u.HSVA[0] = H;
354 		color->u.HSVA[1] = S;
355 		color->u.HSVA[2] = V;
356 		color->u.HSVA[3] = 1.0; /* opaque */
357 		break;
358 	    case RGBA_BYTE:
359 		hsv2rgb(H, S, V, &R, &G, &B);
360 		color->u.rgba[0] = (int) (R * 255);
361 		color->u.rgba[1] = (int) (G * 255);
362 		color->u.rgba[2] = (int) (B * 255);
363 		color->u.rgba[3] = 255;	/* opaque */
364 		break;
365 	    case CMYK_BYTE:
366 		hsv2rgb(H, S, V, &R, &G, &B);
367 		rgb2cmyk(R, G, B, &C, &M, &Y, &K);
368 		color->u.cmyk[0] = (int) C *255;
369 		color->u.cmyk[1] = (int) M *255;
370 		color->u.cmyk[2] = (int) Y *255;
371 		color->u.cmyk[3] = (int) K *255;
372 		break;
373 	    case RGBA_WORD:
374 		hsv2rgb(H, S, V, &R, &G, &B);
375 		color->u.rrggbbaa[0] = (int) (R * 65535);
376 		color->u.rrggbbaa[1] = (int) (G * 65535);
377 		color->u.rrggbbaa[2] = (int) (B * 65535);
378 		color->u.rrggbbaa[3] = 65535;	/* opaque */
379 		break;
380 	    case RGBA_DOUBLE:
381 		hsv2rgb(H, S, V, &R, &G, &B);
382 		color->u.RGBA[0] = R;
383 		color->u.RGBA[1] = G;
384 		color->u.RGBA[2] = B;
385 		color->u.RGBA[3] = 1.0;	/* opaque */
386 		break;
387 	    case COLOR_STRING:
388 		break;
389 	    case COLOR_INDEX:
390 		break;
391 	    }
392 	    return rc;
393 	}
394     }
395 
396     /* test for known color name (generic, not renderer specific known names) */
397     fake.name = resolveColor(str);
398     if (!fake.name)
399 	return COLOR_MALLOC_FAIL;
400     if ((last == NULL)
401 	|| (last->name[0] != fake.name[0])
402 	|| (strcmp(last->name, fake.name))) {
403 	last = (hsvrgbacolor_t *) bsearch((void *) &fake,
404 				      (void *) color_lib,
405 				      sizeof(color_lib) /
406 				      sizeof(hsvrgbacolor_t), sizeof(fake),
407 				      colorcmpf);
408     }
409     if (last != NULL) {
410 	switch (target_type) {
411 	case HSVA_DOUBLE:
412 	    color->u.HSVA[0] = ((double) last->h) / 255.0;
413 	    color->u.HSVA[1] = ((double) last->s) / 255.0;
414 	    color->u.HSVA[2] = ((double) last->v) / 255.0;
415 	    color->u.HSVA[3] = ((double) last->a) / 255.0;
416 	    break;
417 	case RGBA_BYTE:
418 	    color->u.rgba[0] = last->r;
419 	    color->u.rgba[1] = last->g;
420 	    color->u.rgba[2] = last->b;
421 	    color->u.rgba[3] = last->a;
422 	    break;
423 	case CMYK_BYTE:
424 	    R = (last->r) / 255.0;
425 	    G = (last->g) / 255.0;
426 	    B = (last->b) / 255.0;
427 	    rgb2cmyk(R, G, B, &C, &M, &Y, &K);
428 	    color->u.cmyk[0] = (int) C * 255;
429 	    color->u.cmyk[1] = (int) M * 255;
430 	    color->u.cmyk[2] = (int) Y * 255;
431 	    color->u.cmyk[3] = (int) K * 255;
432 	    break;
433 	case RGBA_WORD:
434 	    color->u.rrggbbaa[0] = last->r * 65535 / 255;
435 	    color->u.rrggbbaa[1] = last->g * 65535 / 255;
436 	    color->u.rrggbbaa[2] = last->b * 65535 / 255;
437 	    color->u.rrggbbaa[3] = last->a * 65535 / 255;
438 	    break;
439 	case RGBA_DOUBLE:
440 	    color->u.RGBA[0] = last->r / 255.0;
441 	    color->u.RGBA[1] = last->g / 255.0;
442 	    color->u.RGBA[2] = last->b / 255.0;
443 	    color->u.RGBA[3] = last->a / 255.0;
444 	    break;
445 	case COLOR_STRING:
446 	    break;
447 	case COLOR_INDEX:
448 	    break;
449 	}
450 	return rc;
451     }
452 
453     /* if we're still here then we failed to find a valid color spec */
454     rc = COLOR_UNKNOWN;
455     switch (target_type) {
456     case HSVA_DOUBLE:
457 	color->u.HSVA[0] = color->u.HSVA[1] = color->u.HSVA[2] = 0.0;
458 	color->u.HSVA[3] = 1.0; /* opaque */
459 	break;
460     case RGBA_BYTE:
461 	color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = 0;
462 	color->u.rgba[3] = 255;	/* opaque */
463 	break;
464     case CMYK_BYTE:
465 	color->u.cmyk[0] =
466 	    color->u.cmyk[1] = color->u.cmyk[2] = color->u.cmyk[3] = 0;
467 	break;
468     case RGBA_WORD:
469 	color->u.rrggbbaa[0] = color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = 0;
470 	color->u.rrggbbaa[3] = 65535;	/* opaque */
471 	break;
472     case RGBA_DOUBLE:
473 	color->u.RGBA[0] = color->u.RGBA[1] = color->u.RGBA[2] = 0.0;
474 	color->u.RGBA[3] = 1.0;	/* opaque */
475 	break;
476     case COLOR_STRING:
477 	break;
478     case COLOR_INDEX:
479 	break;
480     }
481     return rc;
482 }
483 
rgba_wordToByte(int * rrggbbaa,unsigned char * rgba)484 static void rgba_wordToByte (int* rrggbbaa, unsigned char* rgba)
485 {
486     int i;
487 
488     for (i = 0; i < 4; i++) {
489 	rgba[i] = rrggbbaa[i] * 255 / 65535;
490     }
491 }
492 
rgba_dblToByte(double * RGBA,unsigned char * rgba)493 static void rgba_dblToByte (double* RGBA, unsigned char* rgba)
494 {
495     int i;
496 
497     for (i = 0; i < 4; i++) {
498 	rgba[i] = (unsigned char)(RGBA[i] * 255);
499     }
500 }
501 
502 /* colorCvt:
503  * Color format converter.
504  * Except for the trivial case, it converts the input color to a string
505  * representation and then calls colorxlate.
506  * ncolor must point to a gvcolor_t struct with type specifying the desired
507  * output type.
508  */
colorCvt(gvcolor_t * ocolor,gvcolor_t * ncolor)509 int colorCvt(gvcolor_t *ocolor, gvcolor_t *ncolor)
510 {
511     int rc;
512     char buf[BUFSIZ];
513     char* s;
514     unsigned char rgba[4];
515 
516     if (ocolor->type == ncolor->type) {
517 	memcpy (&ncolor->u, &ocolor->u, sizeof(ocolor->u));
518 	return COLOR_OK;
519     }
520     s = buf;
521     switch (ocolor->type) {
522     case HSVA_DOUBLE :
523 	sprintf (buf, "%.03f %.03f %.03f %.03f",
524 	    ocolor->u.HSVA[0], ocolor->u.HSVA[1], ocolor->u.HSVA[2], ocolor->u.HSVA[3]);
525 	break;
526     case RGBA_BYTE :
527 	sprintf (buf, "#%02x%02x%02x%02x",
528 	    ocolor->u.rgba[0], ocolor->u.rgba[1], ocolor->u.rgba[2], ocolor->u.rgba[3]);
529 	break;
530     case RGBA_WORD:
531 	rgba_wordToByte (ocolor->u.rrggbbaa, rgba);
532 	sprintf (buf, "#%02x%02x%02x%02x", rgba[0], rgba[1], rgba[2], rgba[3]);
533 	break;
534     case RGBA_DOUBLE:
535 	rgba_dblToByte (ocolor->u.RGBA, rgba);
536 	sprintf (buf, "#%02x%02x%02x%02x", rgba[0], rgba[1], rgba[2], rgba[3]);
537 	break;
538     case COLOR_STRING:
539 	s = ocolor->u.string;
540 	break;
541     case CMYK_BYTE :
542 	/* agerr (AGWARN, "Input color type 'CMYK_BYTE' not supported for conversion\n"); */
543 	return COLOR_UNKNOWN;
544 	break;
545     case COLOR_INDEX:
546 	/* agerr (AGWARN, "Input color type 'COLOR_INDEX' not supported for conversion\n"); */
547 	return COLOR_UNKNOWN;
548 	break;
549     default:
550 	/* agerr (AGWARN, "Unknown input color type value '%u'\n", ncolor->type); */
551 	return COLOR_UNKNOWN;
552 	break;
553     }
554     rc = colorxlate (s, ncolor, ncolor->type);
555     return rc;
556 }
557 
558 /* setColorScheme:
559  * Set current color scheme for resolving names.
560  */
setColorScheme(char * s)561 void setColorScheme (char* s)
562 {
563     colorscheme = s;
564 }
565 
566 
567 
568