/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/common/colxlate.c

Go to the documentation of this file.
00001 /* $Id: colxlate.c,v 1.18 2008/03/04 17:54:53 arif Exp $ $Revision: 1.18 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #include <stdio.h>
00018 
00019 
00020 #include <stdlib.h>
00021 #ifdef WIN32
00022 #include <string.h>
00023 #include <ctype.h>
00024 #include "compat.h"
00025 #endif
00026 #include <string.h>
00027 #include <ctype.h>
00028 
00029 #include "arith.h"
00030 #include "color.h"
00031 #include "colorprocs.h"
00032 #include "colortbl.h"
00033 #include "memory.h"
00034 
00035 static char* colorscheme;
00036 
00037 #ifdef WIN32
00038 extern int strcasecmp(const char *s1, const char *s2);
00039 extern int strncasecmp(const char *s1, const char *s2, unsigned int n);
00040 #endif
00041 
00042 
00043 static void hsv2rgb(double h, double s, double v,
00044                         double *r, double *g, double *b)
00045 {
00046     int i;
00047     double f, p, q, t;
00048 
00049     if (s <= 0.0) {             /* achromatic */
00050         *r = v;
00051         *g = v;
00052         *b = v;
00053     } else {
00054         if (h >= 1.0)
00055             h = 0.0;
00056         h = 6.0 * h;
00057         i = (int) h;
00058         f = h - (double) i;
00059         p = v * (1 - s);
00060         q = v * (1 - (s * f));
00061         t = v * (1 - (s * (1 - f)));
00062         switch (i) {
00063         case 0:
00064             *r = v;
00065             *g = t;
00066             *b = p;
00067             break;
00068         case 1:
00069             *r = q;
00070             *g = v;
00071             *b = p;
00072             break;
00073         case 2:
00074             *r = p;
00075             *g = v;
00076             *b = t;
00077             break;
00078         case 3:
00079             *r = p;
00080             *g = q;
00081             *b = v;
00082             break;
00083         case 4:
00084             *r = t;
00085             *g = p;
00086             *b = v;
00087             break;
00088         case 5:
00089             *r = v;
00090             *g = p;
00091             *b = q;
00092             break;
00093         }
00094     }
00095 }
00096 
00097 static void rgb2hsv(double r, double g, double b,
00098                 double *h, double *s, double *v)
00099 {
00100 
00101     double rgbmin, rgbmax;
00102     double rc, bc, gc;
00103     double ht = 0.0, st = 0.0;
00104 
00105     rgbmin = MIN(r, MIN(g, b));
00106     rgbmax = MAX(r, MAX(g, b));
00107 
00108     if (rgbmax > 0.0)
00109         st = (rgbmax - rgbmin) / rgbmax;
00110 
00111     if (st > 0.0) {
00112         rc = (rgbmax - r) / (rgbmax - rgbmin);
00113         gc = (rgbmax - g) / (rgbmax - rgbmin);
00114         bc = (rgbmax - b) / (rgbmax - rgbmin);
00115         if (r == rgbmax)
00116             ht = bc - gc;
00117         else if (g == rgbmax)
00118             ht = 2 + rc - bc;
00119         else if (b == rgbmax)
00120             ht = 4 + gc - rc;
00121         ht = ht * 60.0;
00122         if (ht < 0.0)
00123             ht += 360.0;
00124     }
00125     *h = ht / 360.0;
00126     *v = rgbmax;
00127     *s = st;
00128 }
00129 
00130 static void rgb2cmyk(double r, double g, double b, double *c, double *m,
00131                      double *y, double *k)
00132 {
00133     *c = 1.0 - r;
00134     *m = 1.0 - g;
00135     *y = 1.0 - b;
00136     *k = *c < *m ? *c : *m;
00137     *k = *y < *k ? *y : *k;
00138     *c -= *k;
00139     *m -= *k;
00140     *y -= *k;
00141 }
00142 
00143 static int colorcmpf(const void *p0, const void *p1)
00144 {
00145     return strcasecmp(((hsvrgbacolor_t *) p0)->name, ((hsvrgbacolor_t *) p1)->name);
00146 }
00147 
00148 char *canontoken(char *str)
00149 {
00150     static unsigned char *canon;
00151     static int allocated;
00152     unsigned char c, *p, *q;
00153     int len;
00154 
00155     p = (unsigned char *) str;
00156     len = strlen(str);
00157     if (len >= allocated) {
00158         allocated = len + 1 + 10;
00159         canon = grealloc(canon, allocated);
00160         if (!canon)
00161             return NULL;
00162     }
00163     q = (unsigned char *) canon;
00164     while ((c = *p++)) {
00165         /* if (isalnum(c) == FALSE) */
00166             /* continue; */
00167         if (isupper(c))
00168             c = tolower(c);
00169         *q++ = c;
00170     }
00171     *q = '\0';
00172     return (char*)canon;
00173 }
00174 
00175 /* fullColor:
00176  * Return "/prefix/str"
00177  */
00178 static char* fullColor (char* prefix, char* str)
00179 {
00180     static char *fulls;
00181     static int allocated;
00182     int len = strlen (prefix) + strlen (str) + 3;
00183 
00184     if (len >= allocated) {
00185         allocated = len + 10;
00186         fulls = grealloc(fulls, allocated);
00187     }
00188     sprintf (fulls, "/%s/%s", prefix, str);
00189     return fulls;
00190 }
00191 
00192 /* resolveColor:
00193  * Resolve input color str allowing color scheme namespaces.
00194  *  0) "black" => "black" 
00195  *    NB: This is something of a hack due to the remaining codegen.
00196  *        Once these are gone, this case could be removed and all references
00197  *        to "black" could be replaced by "/X11/black".
00198  *  1) No initial / => 
00199  *          if colorscheme is defined and no "X11", return /colorscheme/str
00200  *          else return str
00201  *  2) One initial / => return str+1
00202  *  3) Two initial /'s =>
00203  *       a) If colorscheme is defined and not "X11", return /colorscheme/(str+2)
00204  *       b) else return (str+2)
00205  *  4) Two /'s, not both initial => return str.
00206  *
00207  * Note that 1), 2), and 3b) allow the default X11 color scheme. 
00208  *
00209  * In other words,
00210  *   xxx => /colorscheme/xxx     if colorscheme is defined and not "X11"
00211  *   xxx => xxx                  otherwise
00212  *   /xxx => xxx
00213  *   /X11/yyy => yyy
00214  *   /xxx/yyy => /xxx/yyy
00215  *   //yyy => /colorscheme/yyy   if colorscheme is defined and not "X11"
00216  *   //yyy => yyy                otherwise
00217  * 
00218  * At present, no other error checking is done. For example, 
00219  * yyy could be "". This will be caught later.
00220  */
00221 
00222 #define DFLT_SCHEME "X11/"      /* Must have final '/' */
00223 #define DFLT_SCHEME_LEN ((sizeof(DFLT_SCHEME)-1)/sizeof(char))
00224 #define ISNONDFLT(s) ((s) && *(s) && strncasecmp(DFLT_SCHEME, s, DFLT_SCHEME_LEN-1))
00225 
00226 static char* resolveColor (char* str)
00227 {
00228     char* s;
00229     char* ss;   /* second slash */
00230     char* c2;   /* second char */
00231 
00232     if ((*str == 'b') || !strncmp(str+1,"lack",4)) return str;
00233     else if (*str == '/') {   /* if begins with '/' */
00234         c2 = str+1;
00235         if ((ss = strchr(c2, '/'))) {  /* if has second '/' */
00236             if (*c2 == '/') {    /* if second '/' is second character */
00237                     /* Do not compare against final '/' */
00238                 if (ISNONDFLT(colorscheme))
00239                     s = fullColor (colorscheme, c2+1);
00240                 else
00241                     s = c2+1;
00242             }
00243             else if (strncasecmp(DFLT_SCHEME, c2, DFLT_SCHEME_LEN)) s = str;
00244             else s = ss + 1;
00245         }
00246         else s = c2;
00247     }
00248     else if (ISNONDFLT(colorscheme)) s = fullColor (colorscheme, str);
00249     else s = str;
00250     return canontoken(s);
00251 }
00252 
00253 int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
00254 {
00255     static hsvrgbacolor_t *last;
00256     static unsigned char *canon;
00257     static int allocated;
00258     unsigned char *p, *q;
00259     hsvrgbacolor_t fake;
00260     unsigned char c;
00261     double H, S, V, A, R, G, B;
00262     double C, M, Y, K;
00263     unsigned int r, g, b, a;
00264     int len, rc;
00265 
00266     color->type = target_type;
00267 
00268     rc = COLOR_OK;
00269     for (; *str == ' '; str++); /* skip over any leading whitespace */
00270     p = (unsigned char *) str;
00271 
00272     /* test for rgb value such as: "#ff0000"
00273        or rgba value such as "#ff000080" */
00274     a = 255;                    /* default alpha channel value=opaque in case not supplied */
00275     if ((*p == '#')
00276         && (sscanf((char *) p, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3)) {
00277         switch (target_type) {
00278         case HSVA_DOUBLE:
00279             R = (double) r / 255.0;
00280             G = (double) g / 255.0;
00281             B = (double) b / 255.0;
00282             A = (double) a / 255.0;
00283             rgb2hsv(R, G, B, &H, &S, &V);
00284             color->u.HSVA[0] = H;
00285             color->u.HSVA[1] = S;
00286             color->u.HSVA[2] = V;
00287             color->u.HSVA[3] = A;
00288             break;
00289         case RGBA_BYTE:
00290             color->u.rgba[0] = r;
00291             color->u.rgba[1] = g;
00292             color->u.rgba[2] = b;
00293             color->u.rgba[3] = a;
00294             break;
00295         case CMYK_BYTE:
00296             R = (double) r / 255.0;
00297             G = (double) g / 255.0;
00298             B = (double) b / 255.0;
00299             rgb2cmyk(R, G, B, &C, &M, &Y, &K);
00300             color->u.cmyk[0] = (int) C *255;
00301             color->u.cmyk[1] = (int) M *255;
00302             color->u.cmyk[2] = (int) Y *255;
00303             color->u.cmyk[3] = (int) K *255;
00304             break;
00305         case RGBA_WORD:
00306             color->u.rrggbbaa[0] = r * 65535 / 255;
00307             color->u.rrggbbaa[1] = g * 65535 / 255;
00308             color->u.rrggbbaa[2] = b * 65535 / 255;
00309             color->u.rrggbbaa[3] = a * 65535 / 255;
00310             break;
00311         case RGBA_DOUBLE:
00312             color->u.RGBA[0] = (double) r / 255.0;
00313             color->u.RGBA[1] = (double) g / 255.0;
00314             color->u.RGBA[2] = (double) b / 255.0;
00315             color->u.RGBA[3] = (double) a / 255.0;
00316             break;
00317         case COLOR_STRING:
00318             break;
00319         case COLOR_INDEX:
00320             break;
00321         }
00322         return rc;
00323     }
00324 
00325     /* test for hsv value such as: ".6,.5,.3" */
00326     if (((c = *p) == '.') || isdigit(c)) {
00327         len = strlen((char*)p);
00328         if (len >= allocated) {
00329             allocated = len + 1 + 10;
00330             canon = grealloc(canon, allocated);
00331             if (! canon) {
00332                 rc = COLOR_MALLOC_FAIL;
00333                 return rc;
00334             }
00335         }
00336         q = canon;
00337         while ((c = *p++)) {
00338             if (c == ',')
00339                 c = ' ';
00340             *q++ = c;
00341         }
00342         *q = '\0';
00343 
00344         if (sscanf((char *) canon, "%lf%lf%lf", &H, &S, &V) == 3) {
00345             /* clip to reasonable values */
00346             H = MAX(MIN(H, 1.0), 0.0);
00347             S = MAX(MIN(S, 1.0), 0.0);
00348             V = MAX(MIN(V, 1.0), 0.0);
00349             switch (target_type) {
00350             case HSVA_DOUBLE:
00351                 color->u.HSVA[0] = H;
00352                 color->u.HSVA[1] = S;
00353                 color->u.HSVA[2] = V;
00354                 color->u.HSVA[3] = 1.0; /* opaque */
00355                 break;
00356             case RGBA_BYTE:
00357                 hsv2rgb(H, S, V, &R, &G, &B);
00358                 color->u.rgba[0] = (int) (R * 255);
00359                 color->u.rgba[1] = (int) (G * 255);
00360                 color->u.rgba[2] = (int) (B * 255);
00361                 color->u.rgba[3] = 255; /* opaque */
00362                 break;
00363             case CMYK_BYTE:
00364                 hsv2rgb(H, S, V, &R, &G, &B);
00365                 rgb2cmyk(R, G, B, &C, &M, &Y, &K);
00366                 color->u.cmyk[0] = (int) C *255;
00367                 color->u.cmyk[1] = (int) M *255;
00368                 color->u.cmyk[2] = (int) Y *255;
00369                 color->u.cmyk[3] = (int) K *255;
00370                 break;
00371             case RGBA_WORD:
00372                 hsv2rgb(H, S, V, &R, &G, &B);
00373                 color->u.rrggbbaa[0] = (int) (R * 65535);
00374                 color->u.rrggbbaa[1] = (int) (G * 65535);
00375                 color->u.rrggbbaa[2] = (int) (B * 65535);
00376                 color->u.rrggbbaa[3] = 65535;   /* opaque */
00377                 break;
00378             case RGBA_DOUBLE:
00379                 hsv2rgb(H, S, V, &R, &G, &B);
00380                 color->u.RGBA[0] = R;
00381                 color->u.RGBA[1] = G;
00382                 color->u.RGBA[2] = B;
00383                 color->u.RGBA[3] = 1.0; /* opaque */
00384                 break;
00385             case COLOR_STRING:
00386                 break;
00387             case COLOR_INDEX:
00388                 break;
00389             }
00390             return rc;
00391         }
00392     }
00393 
00394     /* test for known color name (generic, not renderer specific known names) */
00395     fake.name = resolveColor(str);
00396     if (!fake.name)
00397         return COLOR_MALLOC_FAIL;
00398     if ((last == NULL)
00399         || (last->name[0] != fake.name[0])
00400         || (strcmp(last->name, fake.name))) {
00401         last = (hsvrgbacolor_t *) bsearch((void *) &fake,
00402                                       (void *) color_lib,
00403                                       sizeof(color_lib) /
00404                                       sizeof(hsvrgbacolor_t), sizeof(fake),
00405                                       colorcmpf);
00406     }
00407     if (last != NULL) {
00408         switch (target_type) {
00409         case HSVA_DOUBLE:
00410             color->u.HSVA[0] = ((double) last->h) / 255.0;
00411             color->u.HSVA[1] = ((double) last->s) / 255.0;
00412             color->u.HSVA[2] = ((double) last->v) / 255.0;
00413             color->u.HSVA[3] = ((double) last->a) / 255.0;
00414             break;
00415         case RGBA_BYTE:
00416             color->u.rgba[0] = last->r;
00417             color->u.rgba[1] = last->g;
00418             color->u.rgba[2] = last->b;
00419             color->u.rgba[3] = last->a;
00420             break;
00421         case CMYK_BYTE:
00422             R = (last->r) / 255.0;
00423             G = (last->g) / 255.0;
00424             B = (last->b) / 255.0;
00425             rgb2cmyk(R, G, B, &C, &M, &Y, &K);
00426             color->u.cmyk[0] = (int) C * 255;
00427             color->u.cmyk[1] = (int) M * 255;
00428             color->u.cmyk[2] = (int) Y * 255;
00429             color->u.cmyk[3] = (int) K * 255;
00430             break;
00431         case RGBA_WORD:
00432             color->u.rrggbbaa[0] = last->r * 65535 / 255;
00433             color->u.rrggbbaa[1] = last->g * 65535 / 255;
00434             color->u.rrggbbaa[2] = last->b * 65535 / 255;
00435             color->u.rrggbbaa[3] = last->a * 65535 / 255;
00436             break;
00437         case RGBA_DOUBLE:
00438             color->u.RGBA[0] = last->r / 255.0;
00439             color->u.RGBA[1] = last->g / 255.0;
00440             color->u.RGBA[2] = last->b / 255.0;
00441             color->u.RGBA[3] = last->a / 255.0;
00442             break;
00443         case COLOR_STRING:
00444             break;
00445         case COLOR_INDEX:
00446             break;
00447         }
00448         return rc;
00449     }
00450 
00451     /* if we're still here then we failed to find a valid color spec */
00452     rc = COLOR_UNKNOWN;
00453     switch (target_type) {
00454     case HSVA_DOUBLE:
00455         color->u.HSVA[0] = color->u.HSVA[1] = color->u.HSVA[2] = 0.0;
00456         color->u.HSVA[3] = 1.0; /* opaque */
00457         break;
00458     case RGBA_BYTE:
00459         color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = 0;
00460         color->u.rgba[3] = 255; /* opaque */
00461         break;
00462     case CMYK_BYTE:
00463         color->u.cmyk[0] =
00464             color->u.cmyk[1] = color->u.cmyk[2] = color->u.cmyk[3] = 0;
00465         break;
00466     case RGBA_WORD:
00467         color->u.rrggbbaa[0] = color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = 0;
00468         color->u.rrggbbaa[3] = 65535;   /* opaque */
00469         break;
00470     case RGBA_DOUBLE:
00471         color->u.RGBA[0] = color->u.RGBA[1] = color->u.RGBA[2] = 0.0;
00472         color->u.RGBA[3] = 1.0; /* opaque */
00473         break;
00474     case COLOR_STRING:
00475         break;
00476     case COLOR_INDEX:
00477         break;
00478     }
00479     return rc;
00480 }
00481 
00482 /* setColorScheme:
00483  * Set current color scheme for resolving names.
00484  */
00485 void setColorScheme (char* s)
00486 {
00487     colorscheme = s;
00488 }
00489 
00490 
00491 

Generated on Mon Mar 31 19:03:24 2008 for Graphviz by  doxygen 1.5.1