Graphviz  2.41.20171026.1811
colxlate.c
Go to the documentation of this file.
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 
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 
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 
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 
140 static int colorcmpf(const void *p0, const void *p1)
141 {
142  return strcasecmp(((hsvrgbacolor_t *) p0)->name, ((hsvrgbacolor_t *) p1)->name);
143 }
144 
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  */
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 
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 
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 
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 
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  */
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  */
561 void setColorScheme (char* s)
562 {
563  colorscheme = s;
564 }
565 
566 
567 
void s1(graph_t *, node_t *)
Definition: stuff.c:686
#define MAX(a, b)
Definition: agerror.c:17
unsigned char b
Definition: color.h:26
union color_s::@10 u
void * grealloc(void *ptr, size_t size)
Definition: memory.c:54
#define MIN(a, b)
Definition: arith.h:35
#define C
Definition: pack.c:29
#define ISNONDFLT(s)
Definition: colxlate.c:223
Definition: color.h:34
#define COLOR_MALLOC_FAIL
Definition: color.h:47
char * name
Definition: color.h:24
#define DFLT_SCHEME
Definition: colxlate.c:221
double RGBA[4]
Definition: color.h:36
color_type_t type
Definition: color.h:44
int
Definition: grammar.c:1264
int rrggbbaa[4]
Definition: color.h:40
unsigned char s
Definition: color.h:25
#define DFLT_SCHEME_LEN
Definition: colxlate.c:222
int strncasecmp(const char *s1, const char *s2, unsigned int n)
Definition: strncasecmp.c:20
char * string
Definition: color.h:41
unsigned char cmyk[4]
Definition: color.h:39
unsigned char a
Definition: color.h:26
Definition: grammar.c:79
color_type_t
Definition: color.h:30
unsigned char g
Definition: color.h:26
int colorxlate(char *str, gvcolor_t *color, color_type_t target_type)
Definition: colxlate.c:254
char * canontoken(char *str)
Definition: colxlate.c:145
double HSVA[4]
Definition: color.h:37
#define NULL
Definition: logic.h:39
int colorCvt(gvcolor_t *ocolor, gvcolor_t *ncolor)
Definition: colxlate.c:509
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:21
unsigned char v
Definition: color.h:25
#define COLOR_UNKNOWN
Definition: color.h:48
#define COLOR_OK
Definition: color.h:49
void setColorScheme(char *s)
Definition: colxlate.c:561
agxbuf * str
Definition: htmlparse.c:85
struct hsvrgbacolor_t hsvrgbacolor_t
unsigned char h
Definition: color.h:25
unsigned char rgba[4]
Definition: color.h:38
unsigned char r
Definition: color.h:26