From 1d04a0bbd3d269ce351b6a1ec6f30608ce5d6dd6 Mon Sep 17 00:00:00 2001 From: ellson Date: Wed, 24 Sep 2008 17:16:08 +0000 Subject: [PATCH] renaming color -> inkpot --- lib/inkpot/inkpot.h | 90 +++++++ lib/inkpot/inkpot_scheme.c | 479 ++++++++++++++++++++++++++++++++++++ lib/inkpot/inkpot_xlate.c | 480 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1049 insertions(+) create mode 100644 lib/inkpot/inkpot.h create mode 100644 lib/inkpot/inkpot_scheme.c create mode 100644 lib/inkpot/inkpot_xlate.c diff --git a/lib/inkpot/inkpot.h b/lib/inkpot/inkpot.h new file mode 100644 index 000000000..5879e9db2 --- /dev/null +++ b/lib/inkpot/inkpot.h @@ -0,0 +1,90 @@ +/* $Id$ $Revision$ */ +/* vim:set shiftwidth=4 ts=8: */ + +/********************************************************** +* This software is part of the graphviz package * +* http://www.graphviz.org/ * +* * +* Copyright (c) 1994-2004 AT&T Corp. * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Corp. * +* * +* Information and Software Systems Research * +* AT&T Research, Florham Park NJ * +**********************************************************/ + +#ifndef COLOR_H +#define COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +typedef enum { + INKPOT_SUCCESS=0, + INKPOT_MALLOC_FAIL, + INKPOT_COLOR_UNKNOWN, + INKPOT_SCHEME_UNKNOWN, + INKPOT_MAX_ONE_INDEXED_SCHEME +} inkpot_status_t; + +typedef struct inkpot_s inkpot_t; + +/* possible representations of color in gvcolor_t */ +typedef enum { + HSVA_DOUBLE, + RGBA_DOUBLE, + RGBA_WORD, + RGBA_BYTE, + CMYK_BYTE, + COLOR_STRING, + COLOR_INDEX +} color_type_t; + +/* gvcolor_t can hold a color spec in a choice or representations */ +typedef struct gvcolor_s { + union { + double HSVA[4]; + double RGBA[4]; + int rrggbbaa[4]; + unsigned char rgba[4]; + unsigned char cmyk[4]; + char *string; + int index; + } u; + color_type_t type; +} gvcolor_t; + +extern inkpot_status_t inkpot_init( inkpot_t **inkpot ); +extern inkpot_status_t inkpot_clear( inkpot_t *inkpot ); +extern inkpot_status_t inkpot_add( inkpot_t *inkpot, const char *scheme ); + +extern inkpot_status_t inkpot_find( inkpot_t *inkpot, const char *color ); +extern inkpot_status_t inkpot_find_default( inkpot_t *inkpot); +extern void inkpot_get_rgba( inkpot_t *inkpot, + unsigned int *r, unsigned int *g, unsigned int *b, unsigned int *a); +extern void inkpot_get_hsva( inkpot_t *inkpot, + unsigned int *h, unsigned int *s, unsigned int *v, unsigned int *a); + +extern void inkpot_print_schemes( inkpot_t *inkpot ); +extern void inkpot_print_names( inkpot_t *inkpot ); +extern void inkpot_print_values( inkpot_t *inkpot ); +extern void inkpot_print_rgba( inkpot_t *inkpot ); + +extern int setColorScheme (const char* s); +extern inkpot_status_t colorxlate(const char *str, gvcolor_t * color, color_type_t target_type); +extern char *canontoken(const char *str); + +#ifdef __cplusplus +} +#endif +#endif /* COLOR_H */ diff --git a/lib/inkpot/inkpot_scheme.c b/lib/inkpot/inkpot_scheme.c new file mode 100644 index 000000000..7e396b27a --- /dev/null +++ b/lib/inkpot/inkpot_scheme.c @@ -0,0 +1,479 @@ +/* $Id$ $Revision$ */ +/* vim:set shiftwidth=4 ts=8: */ + +/********************************************************** + * This software is part of the graphviz package * + * http://www.graphviz.org/ * + * * + * Copyright (c) 1994-2004 AT&T Corp. * + * and is licensed under the * + * Common Public License, Version 1.0 * + * by AT&T Corp. * + * * + * Information and Software Systems Research * + * AT&T Research, Florham Park NJ * + **********************************************************/ + +#include +#include +#include +#include + +#include "inkpot.h" +#include "inkpot_tables.h" + +static int string_cmpf (const char *k, const char *b) +{ + for ( ; *k && *b; k++, b++) { + if (*k > *b) return 1; + if (*k < *b) return -1; + } + if (*k) return 1; /* if the next char in key is not '\0', then key is longer */ + if (*b) return -1; /* if the next char in base is not '\0', then base is longer */ + return 0; +} + +static int inkpot_scheme_name_cmpf ( const void *key, const void *base) +{ + const char *k = (const char*)key; + const char *b = &TAB_STRINGS[((inkpot_scheme_name_t *)base)->string_idx]; + + return string_cmpf(k, b); +} + +static inkpot_scheme_name_t *inkpot_find_scheme_name ( const char *scheme ) +{ + if (scheme == NULL) + return NULL; + return (inkpot_scheme_name_t *) bsearch( + (void*)scheme, (void*)TAB_SCHEMES_NAME, + SZT_SCHEMES_NAME, sizeof(inkpot_scheme_name_t), + inkpot_scheme_name_cmpf); +} + +static int inkpot_scheme_index_cmpf ( const void *key, const void *base) +{ + const char *k = (const char*)key; + const char *b = &TAB_STRINGS[((inkpot_scheme_index_t *)base)->string_idx]; + + return string_cmpf(k, b); +} + +static inkpot_scheme_index_t *inkpot_find_scheme_index ( const char *scheme ) +{ + if (scheme == NULL) + return NULL; + return (inkpot_scheme_index_t *) bsearch( + (void*)scheme, (void*)TAB_SCHEMES_INDEX, + SZT_SCHEMES_INDEX, sizeof(inkpot_scheme_index_t), + inkpot_scheme_index_cmpf); +} + +inkpot_status_t inkpot_clear ( inkpot_t *inkpot) +{ + inkpot->scheme_bits = 0; /* clear schemes */ + inkpot->scheme_index = NULL; + inkpot->name = NULL; /* clear cached value */ + return INKPOT_SUCCESS; +} + +inkpot_status_t inkpot_init ( inkpot_t **inkpot) +{ + *inkpot = malloc(sizeof(inkpot_t)); + if (*inkpot == NULL) + return INKPOT_MALLOC_FAIL; + return inkpot_clear ( *inkpot ); +} + +inkpot_status_t inkpot_add ( inkpot_t *inkpot, const char *scheme ) +{ + inkpot_scheme_name_t *inkpot_scheme_name; + inkpot_scheme_index_t *inkpot_scheme_index; + IDX_SCHEMES_NAME idx; + + if (scheme == NULL) + return INKPOT_SCHEME_UNKNOWN; + inkpot_scheme_name = inkpot_find_scheme_name(scheme); + if (inkpot_scheme_name) { + idx = inkpot_scheme_name - TAB_SCHEMES_NAME; + if (! inkpot->scheme_bits) { + inkpot->default_scheme_name_idx = idx; /* first scheme is default */ + inkpot->default_value_idx = TAB_NAMES[inkpot_scheme_name->default_name_idx].value_idx; + inkpot->first_name_idx = inkpot_scheme_name->first_name_idx; + inkpot->last_name_idx = inkpot_scheme_name->last_name_idx; + } + else { + inkpot->first_name_idx = MIN(inkpot->first_name_idx, inkpot_scheme_name->first_name_idx); + inkpot->last_name_idx = MAX(inkpot->last_name_idx, inkpot_scheme_name->last_name_idx); + } + if (! (inkpot->scheme_bits & (1 << idx))) { + inkpot->scheme_bits |= 1 << idx; + inkpot->name = NULL; /* clear cached value */ + } + } + else { + inkpot_scheme_index = inkpot_find_scheme_index(scheme); + if (! inkpot_scheme_index) + return INKPOT_SCHEME_UNKNOWN; + if (inkpot->scheme_index != inkpot_scheme_index) { + if (inkpot->scheme_index) + return INKPOT_MAX_ONE_INDEXED_SCHEME; + inkpot->scheme_index = inkpot_scheme_index; + if (! inkpot->scheme_bits ) { + /* Set a default color from an index scheme only if no named schemes + * have been specified yet. Will be overwritten by the default of the + * first name scheme if given later */ + inkpot->default_value_idx = TAB_IXVALUES[inkpot_scheme_index->first_value_idx]; + } + inkpot->name = NULL; /* clear cached value */ + } + } + return INKPOT_SUCCESS; +} + +static int inkpot_name_cmpf ( const void *key, const void *base) +{ + const char *k = (const char*)key; + const char *b = &TAB_STRINGS[((inkpot_name_t *)base)->string_idx]; + + return string_cmpf(k, b); +} + +static inkpot_status_t inkpot_find_name ( inkpot_t *inkpot, const char *color ) +{ + inkpot_name_t *name; + const char *last_name; + IDX_NAMES j; + IDX_STRINGS k; + + if (inkpot == NULL) + return INKPOT_SCHEME_UNKNOWN; + if (name == NULL) + return INKPOT_COLOR_UNKNOWN; + if (! inkpot->name /* if we can't use the last result */ + || ! ((last_name = &TAB_STRINGS[inkpot->name->string_idx])) + || ( last_name[0] != color[0] ) + || ( strcmp(last_name, color) != 0)) { + name = (inkpot_name_t *) bsearch( /* then do a fresh search */ + (void*)color, (void*)(&TAB_NAMES[inkpot->first_name_idx]), + inkpot->last_name_idx + 1 - inkpot->first_name_idx, + sizeof(inkpot_name_t), inkpot_name_cmpf); + if (name == NULL) + return INKPOT_COLOR_UNKNOWN; + + j = name - TAB_NAMES; + k = TAB_NAMES[j].string_idx; + while ( j < SZT_NAMES && k == TAB_NAMES[j].string_idx && ! (inkpot->scheme_bits & TAB_NAMES[j].scheme_bits)) { + /* There can be multiple entries for the same + * color string with different values. Linearly search + * through them for the first one in the requested scheme(s) */ + j++; + } + if (k != TAB_NAMES[j].string_idx || j == SZT_NAMES) + return INKPOT_COLOR_UNKNOWN; + inkpot->name = &TAB_NAMES[j]; /* cache name resolution */ + } + inkpot->value = &TAB_VALUES[inkpot->name->value_idx]; + return INKPOT_SUCCESS; +} + +static inkpot_status_t inkpot_find_index ( inkpot_t *inkpot, int index ) +{ + inkpot_scheme_index_t *scheme_index; + IDX_SCHEMES_INDEX j; + IDX_IXVALUES first, last; + + scheme_index = inkpot->scheme_index; + if (!scheme_index) + return INKPOT_SCHEME_UNKNOWN; + + first = scheme_index->first_value_idx; + j = scheme_index - TAB_SCHEMES_INDEX; + if (++j >= SZT_SCHEMES_INDEX) + last = SZT_IXVALUES; + else + last = TAB_SCHEMES_INDEX[j].first_value_idx; + + /* clip user-provided index to fit available range */ + index = MAX(index, 0); + index = MIN(index, (last-1-first)); + index += first; + + assert(index < SZT_IXVALUES); + assert(TAB_IXVALUES[index] < SZT_VALUES); + inkpot->value = &TAB_VALUES[TAB_IXVALUES[index]]; + return INKPOT_SUCCESS; +} + +inkpot_status_t inkpot_find( inkpot_t *inkpot, const char *color ) +{ + int index; + inkpot_status_t rc = INKPOT_COLOR_UNKNOWN; + + if (color && sscanf(color, "%d", &index) == 1) + rc = inkpot_find_index(inkpot, index); + + if (rc != INKPOT_SUCCESS) + rc = inkpot_find_name(inkpot, color); + + return rc; +} + +inkpot_status_t inkpot_find_default( inkpot_t *inkpot ) +{ + inkpot->value = &TAB_VALUES[inkpot->default_value_idx]; + return INKPOT_SUCCESS; +} + +static int inkpot_value_cmpf ( const void *key, const void *base) +{ + inkpot_value_t *cv_key = (inkpot_value_t*)key; + inkpot_value_t *cv_base = (inkpot_value_t*)base; + + if (cv_key->r > cv_base->r) return 1; + if (cv_key->r < cv_base->r) return -1; + if (cv_key->g > cv_base->g) return 1; + if (cv_key->g < cv_base->g) return -1; + if (cv_key->b > cv_base->b) return 1; + if (cv_key->b < cv_base->b) return -1; + if (cv_key->a > cv_base->a) return 1; + if (cv_key->a < cv_base->a) return -1; + return 0; +} + +static int inkpot_find_value ( inkpot_t *inkpot ) +{ + inkpot_value_t *rc, *value = inkpot->value; + inkpot_name_t *name; + inkpot_scheme_index_t *scheme_index; + IDX_VALUES value_idx; + IDX_NAMES i; + IDX_IXVALUES k, first, last; + IDX_SCHEMES_INDEX j; + + if (! inkpot->value->is_named) { + rc = (inkpot_value_t *) bsearch( + (void*)(value), (void*)TAB_VALUES, + SZT_VALUES, sizeof(inkpot_value_t), + inkpot_value_cmpf); + if (rc) + inkpot->value->is_named = 1; + } + if (inkpot->value->is_named) { + value_idx = value - TAB_VALUES; + for (i = value->toname_idx; i < SZT_NAMES; i++) { + name = &TAB_NAMES[TAB_NAMES[i].toname_idx]; + if (name->value_idx != value_idx) + break; + if (name->scheme_bits & inkpot->scheme_bits) { + inkpot->name = name; + return INKPOT_SUCCESS; + } + } + scheme_index = inkpot->scheme_index; + if (scheme_index) { + + first = scheme_index->first_value_idx; + j = scheme_index - TAB_SCHEMES_INDEX; + if (++j >= SZT_SCHEMES_INDEX) + last = SZT_IXVALUES; + else + last = TAB_SCHEMES_INDEX[j].first_value_idx; + + for (k = first; k < last; k++) { + if (TAB_IXVALUES[k] == value_idx) { + inkpot->name = NULL; + inkpot->index = k - first; + return INKPOT_SUCCESS; + } + } + } + } + return INKPOT_COLOR_UNKNOWN; +} + +void inkpot_get_rgba ( inkpot_t *inkpot, unsigned int *r, unsigned int *g, unsigned int *b, unsigned int *a) +{ + unsigned char *t = &(inkpot->value->r); + + if (r) *r = *t; t++; + if (g) *g = *t; t++; + if (b) *b = *t; t++; + if (a) *a = *t; t++; +} + +void inkpot_get_hsva ( inkpot_t *inkpot, unsigned int *h, unsigned int *s, unsigned int *v, unsigned int *a) +{ + unsigned char *t = &(inkpot->value->a); + + if (a) *a = *t; t++; + if (h) *h = *t; t++; + if (s) *s = *t; t++; + if (v) *v = *t; t++; +} + +inkpot_status_t inkpot_xlate(inkpot_t *from_scheme, inkpot_t *to_scheme) +{ + return inkpot_find_value(to_scheme); +} + +void inkpot_print_schemes( inkpot_t *inkpot ) +{ + IDX_SCHEMES_NAME i; + + fprintf(stderr, "schemes:\n"); + for (i = 0; i < SZT_SCHEMES_NAME; i++) { + if ((1<scheme_bits) { + fprintf (stderr, "%s", &TAB_STRINGS[TAB_SCHEMES_NAME[i].string_idx]); + if (i == inkpot->default_scheme_name_idx) + fprintf (stderr, " (default)"); + fprintf (stderr, "\n"); + } + } + if (inkpot->scheme_index) + fprintf (stderr, "%s (indexed)\n", &TAB_STRINGS[inkpot->scheme_index->string_idx]); + fprintf(stderr, "\n"); +} + +static void inkpot_print_scheme_names( inkpot_t *inkpot, int scheme_bits) +{ + IDX_SCHEMES_NAME i; + int found = 0; + + fprintf(stderr, "("); + for (i = 0; i < SZT_SCHEMES_NAME; i++) { + if ((1 << i) & scheme_bits) { + if (found++) + fprintf(stderr, " "); + fprintf (stderr, "%s", &TAB_STRINGS[TAB_SCHEMES_NAME[i].string_idx]); + } + } + fprintf(stderr, ")"); +} + +static void inkpot_print_rgba_value( inkpot_value_t *value ) +{ + fprintf (stderr, "%d,%d,%d,%d", + value->r, value->g, value->b, value->a); +} + +void inkpot_print_rgba( inkpot_t *inkpot ) +{ + inkpot_print_rgba_value( inkpot->value ); +} + +static void inkpot_print_hsva_value(inkpot_value_t *value ) +{ + fprintf (stderr, " %d,%d,%d,%d\n", + value->h, value->s, value->v, value->a); +} + +void inkpot_print_hsva( inkpot_t *inkpot ) +{ + inkpot_print_hsva_value( inkpot->value ); +} + +void inkpot_print_names( inkpot_t *inkpot ) +{ + inkpot_name_t *name; + inkpot_value_t *value; + inkpot_scheme_index_t *scheme_index; + IDX_NAMES i; + IDX_SCHEMES_INDEX j; + BIT_SCHEMES_NAME inkpot_scheme_bits, scheme_bits; + IDX_IXVALUES k, first, last; + + fprintf(stderr, "names:\n"); + inkpot_scheme_bits = inkpot->scheme_bits; + if (inkpot_scheme_bits) { + for (i = 0; i < SZT_NAMES; i++) { + name = &TAB_NAMES[i]; + scheme_bits = name->scheme_bits & inkpot_scheme_bits; + if (scheme_bits) { + value = &TAB_VALUES[name->value_idx]; + fprintf(stderr, "%s", &TAB_STRINGS[TAB_NAMES[i].string_idx]); + inkpot_print_scheme_names(inkpot, scheme_bits); + fprintf(stderr, " "); + inkpot_print_rgba_value(value); + fprintf(stderr, "\n"); + } + } + } + scheme_index = inkpot->scheme_index; + if (scheme_index) { + + first = scheme_index->first_value_idx; + j = scheme_index - TAB_SCHEMES_INDEX; + if (++j >= SZT_SCHEMES_INDEX) + last = SZT_IXVALUES; + else + last = TAB_SCHEMES_INDEX[j].first_value_idx; + + for (k = first; k < last; k++) { + value = &TAB_VALUES[TAB_IXVALUES[j]]; + fprintf (stderr, "%d(%s) ", k - first , &TAB_STRINGS[scheme_index->string_idx]); + inkpot_print_rgba_value(value); + fprintf(stderr, "\n"); + } + } + fprintf(stderr, "\n"); +} + +void inkpot_print_values( inkpot_t *inkpot ) +{ + inkpot_value_t *value; + inkpot_name_t *name; + inkpot_scheme_index_t *scheme_index; + IDX_VALUES i; + IDX_NAMES t; + BIT_SCHEMES_NAME scheme_bits; + IDX_SCHEMES_INDEX j; + IDX_IXVALUES k, first, last; + int found; + + fprintf(stderr, "values:\n"); + for (i = 0; i < SZT_VALUES; i++) { + value = &TAB_VALUES[i]; + found = 0; + for (t = value->toname_idx; t < SZT_NAMES; t++) { + name = &TAB_NAMES[TAB_NAMES[t].toname_idx]; + if (name->value_idx != i) + break; + scheme_bits = name->scheme_bits & inkpot->scheme_bits; + if (scheme_bits) { + if (found++) + fprintf(stderr, " "); + else + inkpot_print_rgba_value(value); + fprintf(stderr, " %s", &TAB_STRINGS[name->string_idx]); + inkpot_print_scheme_names(inkpot, scheme_bits); + } + } + scheme_index = inkpot->scheme_index; + if (scheme_index) { + + first = scheme_index->first_value_idx; + j = scheme_index - TAB_SCHEMES_INDEX; + if (++j >= SZT_SCHEMES_INDEX) + last = SZT_IXVALUES; + else + last = TAB_SCHEMES_INDEX[j].first_value_idx; + + for (k = first; k < last; k++) { + if (TAB_IXVALUES[k] == i) { + if (found++) + fprintf(stderr, " "); + else { + inkpot_print_rgba_value(value); + fprintf(stderr, " "); + } + fprintf(stderr, "%d(%s)", k - first, &TAB_STRINGS[scheme_index->string_idx]); + break; + } + } + } + if (found) + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); +} diff --git a/lib/inkpot/inkpot_xlate.c b/lib/inkpot/inkpot_xlate.c new file mode 100644 index 000000000..9f9068f0d --- /dev/null +++ b/lib/inkpot/inkpot_xlate.c @@ -0,0 +1,480 @@ +/* $Id$ $Revision$ */ +/* vim:set shiftwidth=4 ts=8: */ + +/********************************************************** +* This software is part of the graphviz package * +* http://www.graphviz.org/ * +* * +* Copyright (c) 1994-2004 AT&T Corp. * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Corp. * +* * +* Information and Software Systems Research * +* AT&T Research, Florham Park NJ * +**********************************************************/ + +#include +#include +#include +#include +#ifdef WIN32 +#include "compat.h" +#endif + +#include "inkpot.h" + +static inkpot_t *inkpot; +static const char *colorscheme; + +#ifdef WIN32 +extern int strcasecmp(const char *s1, const char *s2); +extern int strncasecmp(const char *s1, const char *s2, unsigned int n); +#endif + +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; +} + +char *canontoken(const char *str) +{ + static char *canon; + static int allocated; + const char *p; + char *q, c; + int len; + + p = str; + len = strlen(str); + if (len >= allocated) { + allocated = len + 1 + 10; + canon = realloc(canon, allocated); + if (!canon) + return NULL; + } + q = canon; + while ((c = *p++)) { + /* if (isalnum(c) == FALSE) */ + /* continue; */ + if (isupper(c)) + c = tolower(c); + *q++ = c; + } + *q = '\0'; + return canon; +} + +/* fullColor: + * Return "/prefix/str" + */ +static char* fullColor (const char* prefix, const char* str) +{ + static char *fulls; + static int allocated; + int len = strlen (prefix) + strlen (str) + 3; + + if (len >= allocated) { + allocated = len + 10; + fulls = realloc(fulls, allocated); + } + sprintf (fulls, "/%s/%s", prefix, str); + return fulls; +} + +/* resolveColor: + * Resolve input color str allowing color scheme namespaces. + * 0) "black" => "black" + * NB: This is something of a hack due to the remaining codegen. + * Once these are gone, this case could be removed and all references + * to "black" could be replaced by "/x11/black". + * 1) No initial / => + * if colorscheme is defined and no "x11", return /colorscheme/str + * else return str + * 2) One initial / => return str+1 + * 3) Two initial /'s => + * a) If colorscheme is defined and not "x11", return /colorscheme/(str+2) + * b) else return (str+2) + * 4) Two /'s, not both initial => return str. + * + * Note that 1), 2), and 3b) allow the default x11 color scheme. + * + * In other words, + * xxx => /colorscheme/xxx if colorscheme is defined and not "x11" + * xxx => xxx otherwise + * /xxx => xxx + * /x11/yyy => yyy + * /xxx/yyy => /xxx/yyy + * //yyy => /colorscheme/yyy if colorscheme is defined and not "x11" + * //yyy => yyy otherwise + * + * At present, no other error checking is done. For example, + * yyy could be "". This will be caught later. + */ + +#define DFLT_SCHEME "x11/" /* Must have final '/' */ +#define DFLT_SCHEME_LEN ((sizeof(DFLT_SCHEME)-1)/sizeof(char)) +#define ISNONDFLT(s) ((s) && *(s) && strncasecmp(DFLT_SCHEME, s, DFLT_SCHEME_LEN-1)) + +static char* resolveColor (const char* str) +{ + const char* s; + const char* ss; /* second slash */ + const char* c2; /* second char */ + + if ((*str == 'b') || !strncmp(str+1,"lack",4)) return (char*)str; + else if (*str == '/') { /* if begins with '/' */ + c2 = str+1; + if ((ss = strchr(c2, '/'))) { /* if has second '/' */ + if (*c2 == '/') { /* if second '/' is second character */ + /* Do not compare against final '/' */ + if (ISNONDFLT(colorscheme)) + s = fullColor (colorscheme, c2+1); + else + s = c2+1; + } + else if (strncasecmp(DFLT_SCHEME, c2, DFLT_SCHEME_LEN)) s = str; + else s = ss + 1; + } + else s = c2; + } + else if (ISNONDFLT(colorscheme)) s = fullColor (colorscheme, str); + else s = str; + return canontoken(s); +} + +inkpot_status_t colorxlate(const char *str, gvcolor_t * color, color_type_t target_type) +{ + static unsigned char *canon; + static int allocated; + unsigned char *p, *q; + unsigned char c; + double H, S, V, A, R, G, B; + double C, M, Y, K; + unsigned int r, g, b, a, h, s, v; + int len; + inkpot_status_t rc; + const char *key; + + color->type = target_type; + + rc = INKPOT_SUCCESS; + for (; *str == ' '; str++); /* skip over any leading whitespace */ + p = (unsigned char *) str; + + /* test for rgb value such as: "#ff0000" + * or rgba value such as "#ff000080" */ + a = 255; /* default alpha channel value=opaque in case not supplied */ + if ((*p == '#') + && (sscanf((char *) p, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3)) { + switch (target_type) { + case HSVA_DOUBLE: + R = r / 255.0; + G = g / 255.0; + B = b / 255.0; + A = a / 255.0; + rgb2hsv(R, G, B, &H, &S, &V); + color->u.HSVA[0] = H; + color->u.HSVA[1] = S; + color->u.HSVA[2] = V; + color->u.HSVA[3] = A; + 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 = r / 255.0; + G = g / 255.0; + B = 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; + case RGBA_DOUBLE: + color->u.RGBA[0] = r / 255.0; + color->u.RGBA[1] = g / 255.0; + color->u.RGBA[2] = b / 255.0; + color->u.RGBA[3] = a / 255.0; + break; + case COLOR_STRING: + break; + case COLOR_INDEX: + break; + } + return rc; + } + + /* test for hsv value such as: ".6,.5,.3" */ + if (((c = *p) == '.') || isdigit(c)) { + len = strlen((char*)p); + if (len >= allocated) { + allocated = len + 1 + 10; + canon = realloc(canon, allocated); + if (! canon) { + rc = INKPOT_MALLOC_FAIL; + return rc; + } + } + q = canon; + while ((c = *p++)) { + if (c == ',') + c = ' '; + *q++ = c; + } + *q = '\0'; + + A = 1.0; /* default alpha channel value=opaque in case not supplied */ + if (sscanf((char *) canon, "%lf%lf%lf%lf", &H, &S, &V, &A) >= 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); + A = MAX(MIN(A, 1.0), 0.0); + switch (target_type) { + case HSVA_DOUBLE: + color->u.HSVA[0] = H; + color->u.HSVA[1] = S; + color->u.HSVA[2] = V; + color->u.HSVA[3] = A; + 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] = (int) (A * 255); + 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] = (int) (A * 65535); + break; + case RGBA_DOUBLE: + hsv2rgb(H, S, V, &R, &G, &B); + color->u.RGBA[0] = R; + color->u.RGBA[1] = G; + color->u.RGBA[2] = B; + color->u.RGBA[3] = A; + break; + case COLOR_STRING: + break; + case COLOR_INDEX: + break; + } + return rc; + } + } + + /* test for known color name */ +// key = resolveColor(str); + key = str; + rc = inkpot_find(inkpot, key); + if (rc == INKPOT_SUCCESS) { + switch (target_type) { + case HSVA_DOUBLE: + inkpot_get_hsva(inkpot, &h, &s, &v, &a); + color->u.HSVA[0] = h / 255.0; + color->u.HSVA[1] = s / 255.0; + color->u.HSVA[2] = v / 255.0; + color->u.HSVA[3] = a / 255.0; + break; + case RGBA_BYTE: + inkpot_get_rgba(inkpot, &r, &g, &b, &a); + color->u.rgba[0] = r; + color->u.rgba[1] = g; + color->u.rgba[2] = b; + color->u.rgba[3] = a; + break; + case CMYK_BYTE: + inkpot_get_rgba(inkpot, &r, &g, &b, &a); + R = r / 255.0; + G = g / 255.0; + B = 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: + inkpot_get_rgba(inkpot, &r, &g, &b, &a); + 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; + case RGBA_DOUBLE: + inkpot_get_rgba(inkpot, &r, &g, &b, &a); + color->u.RGBA[0] = r / 255.0; + color->u.RGBA[1] = g / 255.0; + color->u.RGBA[2] = b / 255.0; + color->u.RGBA[3] = a / 255.0; + break; + case COLOR_STRING: + break; + case COLOR_INDEX: + break; + } + return rc; + } + + /* if we're still here then we failed to find a valid color spec */ + rc = INKPOT_COLOR_UNKNOWN; + switch (target_type) { + case HSVA_DOUBLE: + color->u.HSVA[0] = color->u.HSVA[1] = color->u.HSVA[2] = 0.0; + color->u.HSVA[3] = 1.0; /* opaque */ + break; + case RGBA_BYTE: + color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = 0; + color->u.rgba[3] = 255; /* opaque */ + 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] = 0; + color->u.rrggbbaa[3] = 65535; /* opaque */ + break; + case RGBA_DOUBLE: + color->u.RGBA[0] = color->u.RGBA[1] = color->u.RGBA[2] = 0.0; + color->u.RGBA[3] = 1.0; /* opaque */ + break; + case COLOR_STRING: + break; + case COLOR_INDEX: + break; + } + return rc; +} + +/* setColorScheme: + * Set current color scheme for resolving names. + */ +int setColorScheme (const char* scheme) +{ + inkpot_status_t rc; + + colorscheme = scheme; + rc = inkpot_init(&inkpot); + if (rc != INKPOT_SUCCESS) + return rc; + return inkpot_add(inkpot, scheme); +} + + + -- 2.40.0