about summary refs log tree commit diff
path: root/lib/libpamcolor.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2017-06-28 22:04:00 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2017-06-28 22:04:00 +0000
commit04f0382f7f28e6456f23b150b60ce2b9fe7f0d98 (patch)
tree89241e451eef86014bc524db0a8630b3c033d5c8 /lib/libpamcolor.c
parent6f62629842614ba3cd807d9eaad722a7d7653969 (diff)
downloadnetpbm-mirror-04f0382f7f28e6456f23b150b60ce2b9fe7f0d98.tar.gz
netpbm-mirror-04f0382f7f28e6456f23b150b60ce2b9fe7f0d98.tar.xz
netpbm-mirror-04f0382f7f28e6456f23b150b60ce2b9fe7f0d98.zip
Add pnm_parsecolorn
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3007 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libpamcolor.c')
-rw-r--r--lib/libpamcolor.c281
1 files changed, 274 insertions, 7 deletions
diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c
index 06dd2493..120a82cf 100644
--- a/lib/libpamcolor.c
+++ b/lib/libpamcolor.c
@@ -22,9 +22,274 @@
 #include <limits.h>
 
 #include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/colorname.h"
+
+#include "netpbm/pam.h"
+#include "netpbm/ppm.h"
+
+
+
+static void
+computeHexTable(int * const hexit) {
+
+    unsigned int i;
+
+    for (i = 0; i < 256; ++i)
+        hexit[i] = -1;
+
+    hexit['0'] = 0;
+    hexit['1'] = 1;
+    hexit['2'] = 2;
+    hexit['3'] = 3;
+    hexit['4'] = 4;
+    hexit['5'] = 5;
+    hexit['6'] = 6;
+    hexit['7'] = 7;
+    hexit['8'] = 8;
+    hexit['9'] = 9;
+    hexit['a'] = hexit['A'] = 10;
+    hexit['b'] = hexit['B'] = 11;
+    hexit['c'] = hexit['C'] = 12;
+    hexit['d'] = hexit['D'] = 13;
+    hexit['e'] = hexit['E'] = 14;
+    hexit['f'] = hexit['F'] = 15;
+}
+
+
+
+static void
+parseHexDigits(const char *   const string,
+               char           const delim,
+               const int *    const hexit,
+               samplen *      const nP,
+               unsigned int * const digitCtP) {
+
+    unsigned int digitCt;
+    unsigned long n;
+    unsigned long maxval;
+
+    for (digitCt = 0, n = 0, maxval = 1; string[digitCt] != delim; ) {
+        char const digit = string[digitCt];
+        if (digit == '\0')
+            pm_error("rgb: color spec ends prematurely");
+        else {
+            int const hexval = hexit[(unsigned int)digit];
+            if (hexval == -1)
+                pm_error("Invalid hex digit in rgb: color spec: 0x%02x",
+                         digit);
+            n = n * 16 + hexval;
+            maxval *= 16;
+            ++digitCt;
+        }
+    }
+    *nP = (samplen) n / maxval;
+    *digitCtP = digitCt;
+}
+
+
+
+static void
+parseNewHexX11(char   const colorname[], 
+               tuplen const color) {
+/*----------------------------------------------------------------------------
+   Determine what color colorname[] specifies in the new style hex
+   color specification format (e.g. rgb:55/40/55).
+
+   Return that color as *colorP.
+
+   Assume colorname[] starts with "rgb:", but otherwise it might be
+   gibberish.
+-----------------------------------------------------------------------------*/
+    int hexit[256];
+
+    const char * cp;
+    unsigned int digitCt;
+
+    computeHexTable(hexit);
+
+    cp = &colorname[4];
+
+    parseHexDigits(cp, '/', hexit, &color[PAM_RED_PLANE], &digitCt);
+
+    cp += digitCt;
+    ++cp;  /* Skip the slash */
+
+    parseHexDigits(cp, '/', hexit, &color[PAM_GRN_PLANE], &digitCt);
+
+    cp += digitCt;
+    ++cp;  /* Skip the slash */
+
+    parseHexDigits(cp, '\0', hexit, &color[PAM_BLU_PLANE], &digitCt);
+}
+
+
+
+static bool
+isNormal(samplen const arg) {
+
+    return arg >= 0.0 && arg <= 1.0;
+}
+
+
+
+static void
+parseNewDecX11(const char * const colorname, 
+               tuplen       const color) {
 
-#include "pam.h"
-#include "ppm.h"
+    int rc;
+    
+    rc = sscanf(colorname, "rgbi:%f/%f/%f",
+                &color[PAM_RED_PLANE],
+                &color[PAM_GRN_PLANE],
+                &color[PAM_BLU_PLANE]);
+
+    if (rc != 3)
+        pm_error("invalid color specifier '%s'", colorname);
+
+    if (!(isNormal(color[PAM_RED_PLANE]) &&
+          isNormal(color[PAM_GRN_PLANE]) &&
+          isNormal(color[PAM_BLU_PLANE]))) {
+        pm_error("invalid color specifier '%s' - "
+                 "values must be between 0.0 and 1.0", colorname);
+    }
+}
+
+
+
+static void
+parseOldX11(const char * const colorname, 
+            tuplen       const color) {
+/*----------------------------------------------------------------------------
+   Return as *colorP the color specified by the old X11 style color
+   specififier colorname[] (e.g. #554055).
+-----------------------------------------------------------------------------*/
+    int hexit[256];
+    
+    computeHexTable(hexit);
+
+    if (!pm_strishex(&colorname[1]))
+        pm_error("Non-hexadecimal characters in #-type color specification");
+
+    switch (strlen(colorname) - 1 /* (Number of hex digits) */) {
+    case 3:
+        color[PAM_RED_PLANE] = (samplen)hexit[(unsigned int)colorname[1]]/15;
+        color[PAM_GRN_PLANE] = (samplen)hexit[(unsigned int)colorname[2]]/15;
+        color[PAM_BLU_PLANE] = (samplen)hexit[(unsigned int)colorname[3]]/15;
+        break;
+
+    case 6:
+        color[PAM_RED_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[1]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[2]] << 0))
+             / 255;
+        color[PAM_GRN_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[3]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[4]] << 0))
+             / 255;
+        color[PAM_BLU_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[5]] << 4) + 
+             (samplen)(hexit[(unsigned int)colorname[6]] << 0))
+             / 255;
+        break;
+
+    case 9:
+        color[PAM_RED_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[1]] << 8) +
+             (samplen)(hexit[(unsigned int)colorname[2]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[3]] << 0))
+            / 4095;
+        color[PAM_GRN_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[4]] << 8) + 
+             (samplen)(hexit[(unsigned int)colorname[5]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[6]] << 0))
+            / 4095;
+        color[PAM_BLU_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[7]] << 8) + 
+             (samplen)(hexit[(unsigned int)colorname[8]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[9]] << 0))
+            / 4095;
+        break;
+
+    case 12:
+        color[PAM_RED_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[1]] << 12) + 
+             (samplen)(hexit[(unsigned int)colorname[2]] <<  8) +
+             (samplen)(hexit[(unsigned int)colorname[3]] <<  4) + 
+             (samplen)(hexit[(unsigned int)colorname[4]] <<  0))
+            / 65535;
+        color[PAM_GRN_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[5]] << 12) + 
+             (samplen)(hexit[(unsigned int)colorname[6]] <<  8) +
+             (samplen)(hexit[(unsigned int)colorname[7]] <<  4) +
+             (samplen)(hexit[(unsigned int)colorname[8]] <<  0))
+            / 65535;
+        color[PAM_BLU_PLANE] =
+            ((samplen)(hexit[(unsigned int)colorname[9]] << 12) + 
+             (samplen)(hexit[(unsigned int)colorname[10]] << 8) +
+             (samplen)(hexit[(unsigned int)colorname[11]] << 4) +
+             (samplen)(hexit[(unsigned int)colorname[12]] << 0))
+            / 65535;
+        break;
+
+    default:
+        pm_error("invalid color specifier '%s'", colorname);
+    }
+}
+
+
+
+static void
+parseOldX11Dec(const char* const colorname, 
+               tuplen      const color) {
+
+    int rc;
+
+    rc = sscanf(colorname, "%f,%f,%f",
+                &color[PAM_RED_PLANE],
+                &color[PAM_GRN_PLANE],
+                &color[PAM_BLU_PLANE]);
+
+    if (rc != 3)
+        pm_error("invalid color specifier '%s'", colorname);
+
+    if (!(isNormal(color[PAM_RED_PLANE]) &&
+          isNormal(color[PAM_GRN_PLANE]) &&
+          isNormal(color[PAM_BLU_PLANE]))) {
+        pm_error("invalid color specifier '%s' - "
+                 "values must be between 0.0 and 1.0", colorname);
+    }
+}
+
+
+
+tuplen
+pnm_parsecolorn(const char * const colorname) {
+
+    tuplen retval;
+    
+    MALLOCARRAY_NOFAIL(retval, 3);
+
+    if (strncmp(colorname, "rgb:", 4) == 0)
+        /* It's a new-X11-style hexadecimal rgb specifier. */
+        parseNewHexX11(colorname, retval);
+    else if (strncmp(colorname, "rgbi:", 5) == 0)
+        /* It's a new-X11-style decimal/float rgb specifier. */
+        parseNewDecX11(colorname, retval);
+    else if (colorname[0] == '#')
+        /* It's an old-X11-style hexadecimal rgb specifier. */
+        parseOldX11(colorname, retval);
+    else if ((colorname[0] >= '0' && colorname[0] <= '9') ||
+             colorname[0] == '.')
+        /* It's an old-style decimal/float rgb specifier. */
+        parseOldX11Dec(colorname, retval);
+    else 
+        /* Must be a name from the X-style rgb file. */
+        pm_parse_dictionary_namen(colorname, retval);
+
+    return retval;
+}
 
 
 
@@ -33,7 +298,7 @@ pnm_parsecolor(const char * const colorname,
                sample       const maxval) {
 
     tuple retval;
-    pixel color;
+    tuplen color;
     struct pam pam;
 
     pam.len = PAM_STRUCT_SIZE(bytes_per_sample);
@@ -43,11 +308,13 @@ pnm_parsecolor(const char * const colorname,
 
     retval = pnm_allocpamtuple(&pam);
 
-    color = ppm_parsecolor(colorname, maxval);
+    color = pnm_parsecolorn(colorname);
+
+    retval[PAM_RED_PLANE] = ROUNDU(color[PAM_RED_PLANE] * maxval);
+    retval[PAM_GRN_PLANE] = ROUNDU(color[PAM_GRN_PLANE] * maxval);
+    retval[PAM_BLU_PLANE] = ROUNDU(color[PAM_BLU_PLANE] * maxval);
 
-    retval[PAM_RED_PLANE] = PPM_GETR(color);
-    retval[PAM_GRN_PLANE] = PPM_GETG(color);
-    retval[PAM_BLU_PLANE] = PPM_GETB(color);
+    free(color);
 
     return retval;
 }