about summary refs log tree commit diff
path: root/editor/pamfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'editor/pamfunc.c')
-rw-r--r--editor/pamfunc.c190
1 files changed, 172 insertions, 18 deletions
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index dbb1ca70..d380303a 100644
--- a/editor/pamfunc.c
+++ b/editor/pamfunc.c
@@ -18,10 +18,24 @@
 
 ******************************************************************************/
 
-#include "pam.h"
+#include "mallocvar.h"
 #include "shhopt.h"
+#include "pam.h"
 
-enum function {FN_MULTIPLY, FN_DIVIDE, FN_ADD, FN_SUBTRACT, FN_MIN, FN_MAX};
+enum function {
+    FN_MULTIPLY,
+    FN_DIVIDE,
+    FN_ADD,
+    FN_SUBTRACT,
+    FN_MIN,
+    FN_MAX,
+    FN_AND,
+    FN_OR,
+    FN_XOR,
+    FN_NOT,
+    FN_SHIFTLEFT,
+    FN_SHIFTRIGHT
+};
 
 /* Note that when the user specifies a minimum, that means he's requesting
    a "max" function.
@@ -40,11 +54,30 @@ struct cmdlineInfo {
         int subtractor;
         unsigned int max;
         unsigned int min;
+        unsigned int mask;
+        unsigned int shiftCount;
     } u;
     unsigned int verbose;
 };
 
 
+
+static unsigned int
+parseHex(const char * const hexString) {
+
+    unsigned int retval;
+    char * tail;
+
+    retval = strtol(hexString, &tail, 16);
+
+    if (*tail != '\0')
+        pm_error("Invalid hex string '%s'.  Junk: '%s'", hexString, tail);
+
+    return retval;
+}
+
+         
+
 static void
 parseCommandLine(int argc, char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
@@ -52,29 +85,46 @@ parseCommandLine(int argc, char ** const argv,
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
-        /* Instructions to OptParseOptions2 on how to parse our options.
-         */
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
     unsigned int multiplierSpec, divisorSpec, adderSpec, subtractorSpec;
     unsigned int maxSpec, minSpec;
+    unsigned int andmaskSpec, ormaskSpec, xormaskSpec, notSpec;
+    unsigned int shiftleftSpec, shiftrightSpec;
+
+    const char * mask;
+
+    MALLOCARRAY(option_def, 100);
 
-    option_def_index = 0;   /* incremented by OPTENTRY */
+    option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0,   "multiplier", OPT_FLOAT,  &cmdlineP->u.multiplier, 
             &multiplierSpec, 0);
     OPTENT3(0,   "divisor",    OPT_FLOAT,  &cmdlineP->u.divisor,
-            &divisorSpec, 0);
+            &divisorSpec,    0);
     OPTENT3(0,   "adder",      OPT_INT,    &cmdlineP->u.adder,
-            &adderSpec, 0);
+            &adderSpec,      0);
     OPTENT3(0,   "subtractor", OPT_INT,    &cmdlineP->u.subtractor,
             &subtractorSpec, 0);
     OPTENT3(0,   "min",        OPT_UINT,   &cmdlineP->u.min,
-            &minSpec, 0);
+            &minSpec,        0);
     OPTENT3(0,   "max",        OPT_UINT,   &cmdlineP->u.max,
-            &maxSpec, 0);
+            &maxSpec,        0);
+    OPTENT3(0,   "andmask",    OPT_STRING, &mask,
+            &andmaskSpec,    0);
+    OPTENT3(0,   "ormask",     OPT_STRING, &mask,
+            &ormaskSpec,     0);
+    OPTENT3(0,   "xormask",    OPT_STRING, &mask,
+            &xormaskSpec,    0);
+    OPTENT3(0,   "not",        OPT_FLAG,   NULL,
+            &notSpec,        0);
+    OPTENT3(0,   "shiftleft",  OPT_UINT,   &cmdlineP->u.shiftCount,
+            &shiftleftSpec,  0);
+    OPTENT3(0,   "shiftright", OPT_UINT,   &cmdlineP->u.shiftCount,
+            &shiftrightSpec, 0);
     OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
 
     opt.opt_table = option_def;
@@ -85,9 +135,12 @@ parseCommandLine(int argc, char ** const argv,
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (multiplierSpec + divisorSpec + adderSpec + subtractorSpec +
-        minSpec + maxSpec > 1)
+        minSpec + maxSpec + andmaskSpec + ormaskSpec + xormaskSpec + notSpec +
+        shiftleftSpec + shiftrightSpec > 1)
         pm_error("You may specify at most one of -multiplier, -divisor,"
-                 "-adder, -subtractor, -min, and -max");
+                 "-adder, -subtractor, -min, -max, "
+                 "-andmask, -ormask, -xormask, -not, "
+                 "-shiftleft, and -shiftright");
 
     if (multiplierSpec) {
         cmdlineP->function = FN_MULTIPLY;
@@ -107,9 +160,25 @@ parseCommandLine(int argc, char ** const argv,
         cmdlineP->function = FN_MAX;
     } else if (maxSpec) {
         cmdlineP->function = FN_MIN;
+    } else if (andmaskSpec) {
+        cmdlineP->function = FN_AND;
+        cmdlineP->u.mask = parseHex(mask);
+    } else if (ormaskSpec) {
+        cmdlineP->function = FN_OR;
+        cmdlineP->u.mask = parseHex(mask);
+    } else if (xormaskSpec) {
+        cmdlineP->function = FN_XOR;
+        cmdlineP->u.mask = parseHex(mask);
+    } else if (notSpec) {
+        cmdlineP->function = FN_NOT;
+    } else if (shiftleftSpec) {
+        cmdlineP->function = FN_SHIFTLEFT;
+    } else if (shiftrightSpec) {
+        cmdlineP->function = FN_SHIFTRIGHT;
     } else 
         pm_error("You must specify one of -multiplier, -divisor, "
-                 "-adder, -subtractor, -min, or -max");
+                 "-adder, -subtractor, -min, -max, "
+                 "-and, -or, -xor, -not, -shiftleft, or -shiftright");
         
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  File spec is the only argument.",
@@ -124,6 +193,70 @@ parseCommandLine(int argc, char ** const argv,
 
 
 
+static bool
+isDyadicMaskFunction(enum function const fn) {
+
+    return (fn == FN_AND || fn == FN_OR || fn == FN_XOR);
+}
+
+
+
+static bool
+isMaskFunction(enum function const fn) {
+
+    return (isDyadicMaskFunction(fn) || fn == FN_NOT);
+}
+
+
+
+static bool
+isShiftFunction(enum function const fn) {
+
+    return (fn == FN_SHIFTLEFT || fn == FN_SHIFTRIGHT);
+}
+
+
+
+static bool
+isBitstringFunction(enum function const fn) {
+
+    return isMaskFunction(fn) || isShiftFunction(fn);
+}
+
+
+
+static void
+validateFunction(struct cmdlineInfo const cmdline,
+                 const struct pam * const pamP) {
+
+    if (isBitstringFunction(cmdline.function)) {
+        if (pm_bitstomaxval(pm_maxvaltobits(pamP->maxval)) != pamP->maxval)
+            pm_error("For a bit string function, the maxval must be a full "
+                     "binary count, i.e. a power of two minus one such as "
+                     "0xff or 0x1.  You have 0x%x",
+                     (unsigned)pamP->maxval);
+
+        if (isDyadicMaskFunction(cmdline.function)) {
+            if ((cmdline.u.mask & pamP->maxval) != cmdline.u.mask)
+                pm_error("Your bit string mask 0x%x is wider than the samples "
+                         "of the image (%u bits, according to the maxval %lu",
+                         cmdline.u.mask, pm_maxvaltobits(pamP->maxval),
+                         pamP->maxval);
+        }
+
+        if (isShiftFunction(cmdline.function)) {
+            if (cmdline.u.shiftCount > pm_maxvaltobits(pamP->maxval))
+                pm_error("Your shift count (%u) is greater than the width "
+                         "of the samples of the image (%u bits, according "
+                         "to the maxval %lu)",
+                         cmdline.u.shiftCount, pm_maxvaltobits(pamP->maxval),
+                         pamP->maxval);
+        }
+    }
+}
+
+
+
 static void
 applyFunction(struct cmdlineInfo const cmdline,
               struct pam         const inpam,
@@ -168,6 +301,25 @@ applyFunction(struct cmdlineInfo const cmdline,
             case FN_MIN:
                 outSample = MIN(inSample, cmdline.u.max);
                 break;
+            case FN_AND:
+                outSample = inSample & cmdline.u.mask;
+                break;
+            case FN_OR:
+                outSample = inSample | cmdline.u.mask;
+                break;
+            case FN_XOR:
+                outSample = inSample ^ cmdline.u.mask;
+                break;
+            case FN_NOT:
+                outSample = ~inSample;
+                break;
+            case FN_SHIFTLEFT:
+                outSample =
+                    (inSample << cmdline.u.shiftCount) & outpam.maxval;
+                break;
+            case FN_SHIFTRIGHT:
+                outSample = inSample >> cmdline.u.shiftCount;
+                break;
             }
             outputRow[col][plane] = MIN(outpam.maxval, outSample);
         }
@@ -179,15 +331,15 @@ applyFunction(struct cmdlineInfo const cmdline,
 int
 main(int argc, char *argv[]) {
 
-    FILE* ifP;
-    tuple* inputRow;   /* Row from input image */
-    tuple* outputRow;  /* Row of output image */
+    FILE * ifP;
+    tuple * inputRow;   /* Row from input image */
+    tuple * outputRow;  /* Row of output image */
     int row;
     struct cmdlineInfo cmdline;
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
 
-    pnm_init( &argc, argv );
+    pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -195,6 +347,8 @@ main(int argc, char *argv[]) {
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
+    validateFunction(cmdline, &inpam);
+
     inputRow = pnm_allocpamrow(&inpam);
 
     outpam = inpam;    /* Initial value -- most fields should be same */
@@ -216,6 +370,6 @@ main(int argc, char *argv[]) {
     pm_close(inpam.file);
     pm_close(outpam.file);
     
-    exit(0);
+    return 0;
 }