/* This software may only be used by you under license from AT&T Corp. ("AT&T"). A copy of AT&T's Source Code Agreement is available at AT&T's Internet website having the URL: If you received this software without first entering into a license with AT&T, you have an infringing copy of this software and cannot use it without violating AT&T's intellectual property rights. */ #pragma prototyped #include "render.h" #include "colortbl.h" static void hsv2rgb(double h, double s, double v, double *r, double *g, double *b) { int i; double f,p,q,t; if (s <= 0.0) { /* achromatic */ *r = v; *g = v; *b = v; } else { if (h >= 1.0) h = 0.0; h = 6.0 * h; i = (int)h; f = h - (double)i; p = v * (1 - s); q = v * (1 - (s * f)); t = v * ( 1 - (s * (1 - f))); switch (i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } } } static void rgb2hsv(double r, double g, double b, double *h, double *s, double *v) { double rgbmin,rgbmax; double rc,bc,gc; double ht=0.0,st=0.0; rgbmin = MIN(r,MIN(g,b)); rgbmax = MAX(r,MAX(g,b)); if (rgbmax > 0.0) st = (rgbmax - rgbmin) / rgbmax; if (st > 0.0) { rc = (rgbmax - r) / (rgbmax - rgbmin); gc = (rgbmax - g) / (rgbmax - rgbmin); bc = (rgbmax - b) / (rgbmax - rgbmin); if (r == rgbmax) ht = bc - gc; else if (g == rgbmax) ht = 2 + rc - bc; else if (b == rgbmax) ht = 4 + gc - rc; ht = ht * 60.0; if (ht < 0.0) ht += 360.0; } *h = ht / 360.0; *v = rgbmax; *s = st; } static void rgb2cmyk(double r, double g, double b, double *c, double *m, double *y, double *k) { *c = 1.0 - r; *m = 1.0 - g; *y = 1.0 - b; *k = *c < *m ? *c : *m; *k = *y < *k ? *y : *k; *c -= *k; *m -= *k; *y -= *k; } static int colorcmpf(void *p0, void *p1) { /* fast comparison of first character */ int i = (((hsbcolor_t*)p0)->name[0] - ((hsbcolor_t*)p1)->name[0]); /* if first character matches then compare full color string */ return (i ? i : strcmp(((hsbcolor_t*)p0)->name,((hsbcolor_t*)p1)->name)); } char *canontoken(char *str) { static char canon[SMALLBUF]; char c; char *p=str; char *q=canon; int i=SMALLBUF; while ((c = *p++) && (--i)) { if (isalnum(c) == FALSE) continue; if (isupper(c)) c = tolower(c); *q++ = c; } if (c) agerr (AGWARN, "color value '%s' truncated\n", str); *q = '\0'; return canon; } void colorxlate(char *str, color_t *color, color_type target_type) { static hsbcolor_t *last; hsbcolor_t fake; char canon[SMALLBUF]; char *p, *q, ch; double H,S,V,R,G,B; double C,M,Y,K; int r,g,b,a; int i; color->type = target_type; /* skip over any leading whitespace */ for (; *str == ' '; str++); p = str; /* test for rgb value such as: "#ff0000" or rgba value such as "#ff000080" */ a = 0; /* default alpha channel value in case not supplied */ if ((*p == '#') && (sscanf(p,"#%2x%2x%2x%2x",&r,&g,&b,&a) >= 3)) { switch (target_type) { case HSV_DOUBLE: R = (double)r/255.0; G = (double)g/255.0; B = (double)b/255.0; rgb2hsv(R,G,B,&H,&S,&V); color->u.HSV[0] = H; color->u.HSV[1] = S; color->u.HSV[2] = V; break; case RGBA_BYTE: color->u.rgba[0] = r; color->u.rgba[1] = g; color->u.rgba[2] = b; color->u.rgba[3] = a; break; case CMYK_BYTE: R = (double)r/255.0; G = (double)g/255.0; B = (double)b/255.0; rgb2cmyk(R,G,B,&C,&M,&Y,&K); color->u.cmyk[0] = (int)C*255; color->u.cmyk[1] = (int)M*255; color->u.cmyk[2] = (int)Y*255; color->u.cmyk[3] = (int)K*255; break; case RGBA_WORD: color->u.rrggbbaa[0] = r*65535/255; color->u.rrggbbaa[1] = g*65535/255; color->u.rrggbbaa[2] = b*65535/255; color->u.rrggbbaa[3] = a*65535/255; break; } /* color->type = target_type; */ return; } /* test for hsv value such as: ".6,.5,.3" */ if (((ch = *p) == '.') || isdigit(ch)) { q = canon; i = SMALLBUF; while ((ch = *p++) && (--i)) { if (ch == ',') ch = ' '; *q++ = ch; } if (ch) agerr (AGWARN, "color value '%s' truncated\n", str); *q = '\0'; if (sscanf(canon,"%lf%lf%lf",&H,&S,&V) == 3) { /* clip to reasonable values */ H = MAX(MIN(H,1.0),0.0); S = MAX(MIN(S,1.0),0.0); V = MAX(MIN(V,1.0),0.0); switch (target_type) { case HSV_DOUBLE: color->u.HSV[0] = H; color->u.HSV[1] = S; color->u.HSV[2] = V; break; case RGBA_BYTE: hsv2rgb(H,S,V,&R,&G,&B); color->u.rgba[0] = (int)(R*255); color->u.rgba[1] = (int)(G*255); color->u.rgba[2] = (int)(B*255); color->u.rgba[3] = 0; break; case CMYK_BYTE: hsv2rgb(H,S,V,&R,&G,&B); rgb2cmyk(R,G,B,&C,&M,&Y,&K); color->u.cmyk[0] = (int)C*255; color->u.cmyk[1] = (int)M*255; color->u.cmyk[2] = (int)Y*255; color->u.cmyk[3] = (int)K*255; break; case RGBA_WORD: hsv2rgb(H,S,V,&R,&G,&B); color->u.rrggbbaa[0] = (int)(R*65535); color->u.rrggbbaa[1] = (int)(G*65535); color->u.rrggbbaa[2] = (int)(B*65535); color->u.rrggbbaa[3] = 0; break; } /* color->type = target_type; */ return; } } /* test for known color name */ fake.name = canontoken(str); if ((last == NULL) ||(last->name[0] != fake.name[0]) ||(strcmp(last->name,fake.name))) { last = (hsbcolor_t*) bsearch((void*)&fake, (void*)color_lib, sizeof(color_lib)/sizeof(hsbcolor_t), sizeof(fake),(bsearch_cmpf)colorcmpf); } if (last != NULL) { switch (target_type) { case HSV_DOUBLE: color->u.HSV[0] = ((double)last->h)/255.0; color->u.HSV[1] = ((double)last->s)/255.0; color->u.HSV[2] = ((double)last->b)/255.0; break; case RGBA_BYTE: H = (last->h)/255.0; S = (last->s)/255.0; V = (last->b)/255.0; hsv2rgb(H,S,V,&R,&G,&B); color->u.rgba[0] = (int)(R*255); color->u.rgba[1] = (int)(G*255); color->u.rgba[2] = (int)(B*255); color->u.rgba[3] = 0; break; case CMYK_BYTE: H = (last->h)/255.0; S = (last->s)/255.0; V = (last->b)/255.0; hsv2rgb(H,S,V,&R,&G,&B); rgb2cmyk(R,G,B,&C,&M,&Y,&K); color->u.cmyk[0] = (int)C*255; color->u.cmyk[1] = (int)M*255; color->u.cmyk[2] = (int)Y*255; color->u.cmyk[3] = (int)K*255; break; case RGBA_WORD: H = (last->h)/255.0; S = (last->s)/255.0; V = (last->b)/255.0; hsv2rgb(H,S,V,&R,&G,&B); color->u.rrggbbaa[0] = (int)(R*65535); color->u.rrggbbaa[1] = (int)(G*65535); color->u.rrggbbaa[2] = (int)(B*65535); color->u.rrggbbaa[3] = 0; break; } /* color->type = target_type; */ return; } /* if we're still here then we failed to find a valid color spec */ agerr (AGWARN, "%s is not a known color. Using black.\n",str); switch (target_type) { case HSV_DOUBLE: color->u.HSV[0] = color->u.HSV[1] = color->u.HSV[2] = 0.0; break; case RGBA_BYTE: color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = color->u.rgba[3] = 0; break; case CMYK_BYTE: color->u.cmyk[0] = color->u.cmyk[1] = color->u.cmyk[2] = color->u.cmyk[3] = 0; break; case RGBA_WORD: color->u.rrggbbaa[0] = color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = color->u.rrggbbaa[3] = 0; break; } /* color->type = target_type; */ return; }