From 40a120115a9201d590d90d7a62f31dbcb006bdb0 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 12 May 2018 20:00:11 +0000 Subject: Add pnm_colorspec_*, pnm_parsecolor2, pnm_allocpamtuplen, pnm_freepamtuplen. Make normalized tuple functions respect pam.allocation_depth git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3250 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- doc/HISTORY | 15 ++++ lib/libpamcolor.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/libpamn.c | 42 ++++++++- lib/libppmcolor.c | 8 +- lib/pam.h | 28 ++++++ 5 files changed, 344 insertions(+), 6 deletions(-) diff --git a/doc/HISTORY b/doc/HISTORY index e5ced971..4ef73227 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -8,6 +8,21 @@ not yet BJH Release 10.83.00 Add pamlevels. Thanks Anton Shepelev . + Add rgb-:r/g/b color specification format. + + libnetpbm: Add pnm_colorspec_rgb_integer, + pnm_colorspec_rgb_norm, pnm_colorspec_rgb_x11, + pnm_colorspec_dict, pnm_colorspec_dict_close. + + libnetpbm: Add pnm_parsecolor2. + + libnetpbm: Add pnm_allocpamtuplen, pnm_freepamtuplen. + + libnetpbm: Make the normalized tuple functions respect the + allocation depth specified in struct pam (member + 'allocation_depth') instead of using the actual tuple depth + (member 'depth'). + ilbmtoppm: Fix bug: may fail with bogus error message about an invalid CLUT chunk if image has a CLUT chunk. Introduced after Netpbm 10.26 (January 2005) and at or before Netpbm 10.35 diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c index 3cef5e2d..b6a09d26 100644 --- a/lib/libpamcolor.c +++ b/lib/libpamcolor.c @@ -424,6 +424,263 @@ pnm_colorname(struct pam * const pamP, +static tuple +scaledRgb(struct pam * const pamP, + tuple const color, + sample const maxval) { + + tuple scaledColor; + + struct pam pam; + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(allocation_depth); + pam.maxval = pamP->maxval; + pam.depth = pamP->depth; + pam.allocation_depth = 3; + + scaledColor = pnm_allocpamtuple(&pam); + + pnm_scaletuple(&pam, scaledColor, color, maxval); + + pnm_maketuplergb(&pam, scaledColor); + + return scaledColor; +} + + + +const char * +pnm_colorspec_rgb_integer(struct pam * const pamP, + tuple const color, + sample const maxval) { + + const char * retval; + + tuple scaledColor = scaledRgb(pamP, color, maxval); + + pm_asprintf(&retval, "rgb-%lu:%lu/%lu/%lu", + maxval, + scaledColor[PAM_RED_PLANE], + scaledColor[PAM_GRN_PLANE], + scaledColor[PAM_BLU_PLANE] + ); + + pnm_freepamtuple(scaledColor); + + return retval; +} + + + +const char * +pnm_colorspec_rgb_norm(struct pam * const pamP, + tuple const color, + unsigned int const digitCt) { + + const char * retval; + + tuple rgbColor; + + tuplen normColor; + + struct pam rgbPam; + + rgbPam.size = sizeof(rgbPam); + rgbPam.len = PAM_STRUCT_SIZE(allocation_depth); + rgbPam.maxval = pamP->maxval; + rgbPam.depth = pamP->depth; + rgbPam.allocation_depth = 3; + + rgbColor = pnm_allocpamtuple(&rgbPam); + + pnm_assigntuple(&rgbPam, rgbColor, color); /* initial value */ + + pnm_maketuplergb(&rgbPam, rgbColor); + + normColor = pnm_allocpamtuplen(&rgbPam); + + rgbPam.depth = 3; + + pnm_normalizetuple(&rgbPam, rgbColor, normColor); + + { + const char * format; + pm_asprintf(&format, "rgbi:%%.%uf/%%.%uf/%%.%uf", + digitCt, digitCt, digitCt); + + pm_asprintf(&retval, format, + normColor[PAM_RED_PLANE], + normColor[PAM_GRN_PLANE], + normColor[PAM_BLU_PLANE] + ); + } + + pnm_freepamtuplen(normColor); + pnm_freepamtuple(rgbColor); + + return retval; +} + + + +const char * +pnm_colorspec_rgb_x11(struct pam * const pamP, + tuple const color, + unsigned int const hexDigitCt) { + + const char * retval; + + sample maxval; + const char * format; + + switch(hexDigitCt) { + case 1: + maxval = 15; + format = "rgb:%01x:%01x:%01x"; + break; + case 2: + maxval = 255; + format = "rgb:%02x:%02x:%02x"; + break; + case 3: + maxval = 4095; + format = "rgb:%03x:%03x:%03x"; + break; + case 4: + maxval = 65535; + format = "rgb:%04x:%04x:%04x"; + break; + default: + pm_error("Invalid number of hex digits " + "for X11 color specification: %u. " + "Must be 1, 2, 3, or 4", hexDigitCt); + } + + { + tuple const scaledColor = scaledRgb(pamP, color, maxval); + + pm_asprintf(&retval, format, + scaledColor[PAM_RED_PLANE], + scaledColor[PAM_GRN_PLANE], + scaledColor[PAM_BLU_PLANE] + ); + + pnm_freepamtuple(scaledColor); + } + return retval; +} + + + +const char * +pnm_colorspec_dict(struct pam * const pamP, + tuple const color) { +/*---------------------------------------------------------------------------- + Return the name from the color dictionary of color 'color'. + + Return it in newly allocated pm_strdrup storage. + + If the color is not in the dictionary, or the dictionary doesn't even + exist (file not found in any of the possible places), return NULL. + + The color dictionary uses maxval 255, so we match to that precision. + E.g. if a component of 'color' is 1000 out of maxval 65535 (which would be + 3.9 out of maxval 255), we consider it a match to a component value of 4 + in the color dictionary. +-----------------------------------------------------------------------------*/ + tuple scaledColor = scaledRgb(pamP, color, PAM_COLORFILE_MAXVAL); + + FILE * dictFileP; + const char * colorname; + + dictFileP = pm_openColornameFile(NULL, false); + + if (dictFileP) { + bool eof; + for (colorname = NULL, eof = false; !colorname && !eof; ) { + struct colorfile_entry const ce = pm_colorget(dictFileP); + + if (ce.colorname) { + if (scaledColor[PAM_RED_PLANE] == (sample)ce.r && + scaledColor[PAM_GRN_PLANE] == (sample)ce.g && + scaledColor[PAM_BLU_PLANE] == (sample)ce.b) { + colorname = pm_strdup(ce.colorname); + } + } else + eof = TRUE; + } + + fclose(dictFileP); + } else + colorname = NULL; + + pnm_freepamtuple(scaledColor); + + return colorname; +} + + + +const char * +pnm_colorspec_dict_close(struct pam * const pamP, + tuple const color) { +/*---------------------------------------------------------------------------- + Return the name from the color dictionary of the color closst to 'color'. + + Return it in newly allocated pm_strdrup storage. + + If the color dictionary is empty, or the dictionary doesn't even exist + (file not found in any of the possible places), return a null string. + This is the only case in which we would return a null string, as the + color dictionary cannot define a null string color name. +-----------------------------------------------------------------------------*/ + tuple scaledColor = scaledRgb(pamP, color, PAM_COLORFILE_MAXVAL); + + FILE * dictFileP; + static char colorname[200]; + + dictFileP = pm_openColornameFile(NULL, false); + + if (dictFileP) { + unsigned int bestDiff; + bool eof; + + for (bestDiff = 32767, eof = FALSE; !eof && bestDiff > 0; ) { + struct colorfile_entry const ce = pm_colorget(dictFileP); + + if (ce.colorname) { + unsigned int const thisDiff = + abs((int)scaledColor[PAM_RED_PLANE] - (int)ce.r) + + abs((int)scaledColor[PAM_GRN_PLANE] - (int)ce.g) + + abs((int)scaledColor[PAM_BLU_PLANE] - (int)ce.b); + + if (thisDiff < bestDiff) { + bestDiff = thisDiff; + STRSCPY(colorname, ce.colorname); + } + } else + eof = TRUE; + } + + fclose(dictFileP); + + if (bestDiff == 32767) { + /* Color file contain no entries, so we can't even pick a close + one + */ + STRSCPY(colorname, ""); + } + } else + STRSCPY(colorname, ""); + + pnm_freepamtuple(scaledColor); + + return pm_strdup(colorname); +} + + + double pnm_lumin_factor[3] = {PPM_LUMINR, PPM_LUMING, PPM_LUMINB}; void diff --git a/lib/libpamn.c b/lib/libpamn.c index ce844c7f..65c8979f 100644 --- a/lib/libpamn.c +++ b/lib/libpamn.c @@ -23,6 +23,43 @@ +static unsigned int +allocationDepth(const struct pam * const pamP) { + + unsigned int retval; + + if (pamP->len >= PAM_STRUCT_SIZE(allocation_depth)) { + if (pamP->allocation_depth == 0) + retval = pamP->depth; + else { + if (pamP->depth > pamP->allocation_depth) + pm_error("'allocationDepth' (%u) is smaller than 'depth' (%u)", + pamP->allocation_depth, pamP->depth); + retval = pamP->allocation_depth; + } + } else + retval = pamP->depth; + return retval; +} + + + +tuplen +pnm_allocpamtuplen(const struct pam * const pamP) { + + tuplen retval; + + retval = malloc(allocationDepth(pamP) * sizeof(retval[0])); + + if (retval == NULL) + pm_error("Out of memory allocating %u-plane normalized tuple", + allocationDepth(pamP)); + + return retval; +} + + + static void allocpamrown(const struct pam * const pamP, tuplen ** const tuplerownP, @@ -32,7 +69,7 @@ allocpamrown(const struct pam * const pamP, overflow will not occur in our calculations. NOTE: pnm_readpaminit() ensures this assumption is valid. -----------------------------------------------------------------------------*/ - int const bytes_per_tuple = pamP->depth * sizeof(samplen); + int const bytes_per_tuple = allocationDepth(pamP) * sizeof(samplen); tuplen * tuplerown; const char * error; @@ -47,7 +84,8 @@ allocpamrown(const struct pam * const pamP, pm_asprintf(&error, "Out of memory allocating space for a tuple row of" "%u tuples by %u samples per tuple " "by %u bytes per sample.", - pamP->width, pamP->depth, (unsigned)sizeof(samplen)); + pamP->width, allocationDepth(pamP), + (unsigned)sizeof(samplen)); else { /* Now we initialize the pointers to the individual tuples to make this a regulation C two dimensional array. diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c index df9e5295..27340d5f 100644 --- a/lib/libppmcolor.c +++ b/lib/libppmcolor.c @@ -78,7 +78,7 @@ ppm_colorname(const pixel * const colorP, f = pm_openColornameFile(NULL, !hexok); if (!f) - strcpy(colorname, ""); + STRSCPY(colorname, ""); else { int bestDiff; bool eof; @@ -94,7 +94,7 @@ ppm_colorname(const pixel * const colorP, if (thisDiff < bestDiff) { bestDiff = thisDiff; - strcpy(colorname, ce.colorname); + STRSCPY(colorname, ce.colorname); } } else eof = TRUE; @@ -105,12 +105,12 @@ ppm_colorname(const pixel * const colorP, /* Color file contain no entries, so we can't even pick a close one */ - strcpy(colorname, ""); + STRSCPY(colorname, ""); } else if (bestDiff > 0 && hexok) { /* We didn't find an exact match and user is willing to accept hex, so we don't have to use an approximate match. */ - strcpy(colorname, ""); + STRSCPY(colorname, ""); } } diff --git a/lib/pam.h b/lib/pam.h index 9f999e93..c2cfb4c7 100644 --- a/lib/pam.h +++ b/lib/pam.h @@ -401,6 +401,11 @@ typedef float samplen; typedef samplen *tuplen; /* Same as 'tuple', except using normalized samples. */ +tuplen +pnm_allocpamtuplen(const struct pam * const pamP); + +#define pnm_freepamtuplen(tuplen) pm_freerow((char*) tuplen) + tuplen * pnm_allocpamrown(const struct pam * const pamP); @@ -506,6 +511,29 @@ pnm_colorname(struct pam * const pamP, tuple const color, int const hexok); +const char * +pnm_colorspec_rgb_integer(struct pam * const pamP, + tuple const color, + sample const maxval); + +const char * +pnm_colorspec_rgb_norm(struct pam * const pamP, + tuple const color, + unsigned int const digitCt); + +const char * +pnm_colorspec_rgb_x11(struct pam * const pamP, + tuple const color, + unsigned int const hexDigitCt); + +const char * +pnm_colorspec_dict(struct pam * const pamP, + tuple const color); + +const char * +pnm_colorspec_dict_close(struct pam * const pamP, + tuple const color); + extern double pnm_lumin_factor[3]; -- cgit 1.4.1