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.c128
1 files changed, 96 insertions, 32 deletions
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index b6e56e17..5945b82d 100644
--- a/editor/pamfunc.c
+++ b/editor/pamfunc.c
@@ -13,8 +13,8 @@
   multiply/divide where possible.  Especially when multiplying by an 
   integer.
 
-  2) For multiply/divide, give option of simply changing the maxval and
-  leaving the raster alone.
+  2) speed up by not transforming the raster in the idempotent cases
+  (e.g. multiply by one).
 
 ******************************************************************************/
 
@@ -23,7 +23,7 @@
 #include "shhopt.h"
 #include "pam.h"
 
-enum function {
+enum Function {
     FN_MULTIPLY,
     FN_DIVIDE,
     FN_ADD,
@@ -42,22 +42,23 @@ enum function {
    a "max" function.
 */
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespec of input file */
-    enum function function;
+    const char * inputFileName;
+    enum Function function;
     union {
-        float multiplier;
-        float divisor;
-        int adder;
-        int subtractor;
+        float        multiplier;
+        float        divisor;
+        int          adder;
+        int          subtractor;
         unsigned int max;
         unsigned int min;
         unsigned int mask;
         unsigned int shiftCount;
     } u;
+    unsigned int changemaxval;
     unsigned int verbose;
 };
 
@@ -80,8 +81,8 @@ parseHex(const char * const hexString) {
          
 
 static void
-parseCommandLine(int argc, char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -126,13 +127,16 @@ parseCommandLine(int argc, char ** const argv,
             &shiftleftSpec,  0);
     OPTENT3(0,   "shiftright", OPT_UINT,   &cmdlineP->u.shiftCount,
             &shiftrightSpec, 0);
-    OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
+    OPTENT3(0,   "verbose",      OPT_FLAG,   NULL, &cmdlineP->verbose,
+            0);
+    OPTENT3(0,   "changemaxval", OPT_FLAG,   NULL, &cmdlineP->changemaxval,
+            0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (multiplierSpec + divisorSpec + adderSpec + subtractorSpec +
@@ -186,16 +190,17 @@ parseCommandLine(int argc, char ** const argv,
                  argc-1);
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else 
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
     
+    free(option_def);
 }
 
 
 
 static bool
-isDyadicMaskFunction(enum function const fn) {
+isDyadicMaskFunction(enum Function const fn) {
 
     return (fn == FN_AND || fn == FN_OR || fn == FN_XOR);
 }
@@ -203,7 +208,7 @@ isDyadicMaskFunction(enum function const fn) {
 
 
 static bool
-isMaskFunction(enum function const fn) {
+isMaskFunction(enum Function const fn) {
 
     return (isDyadicMaskFunction(fn) || fn == FN_NOT);
 }
@@ -211,7 +216,7 @@ isMaskFunction(enum function const fn) {
 
 
 static bool
-isShiftFunction(enum function const fn) {
+isShiftFunction(enum Function const fn) {
 
     return (fn == FN_SHIFTLEFT || fn == FN_SHIFTRIGHT);
 }
@@ -219,7 +224,7 @@ isShiftFunction(enum function const fn) {
 
 
 static bool
-isBitstringFunction(enum function const fn) {
+isBitstringFunction(enum Function const fn) {
 
     return isMaskFunction(fn) || isShiftFunction(fn);
 }
@@ -227,7 +232,7 @@ isBitstringFunction(enum function const fn) {
 
 
 static void
-validateFunction(struct cmdlineInfo const cmdline,
+validateFunction(struct CmdlineInfo const cmdline,
                  const struct pam * const pamP) {
 
     if (isBitstringFunction(cmdline.function)) {
@@ -259,7 +264,58 @@ validateFunction(struct cmdlineInfo const cmdline,
 
 
 static void
-applyFunction(struct cmdlineInfo const cmdline,
+planTransform(struct CmdlineInfo const cmdline,
+              sample             const inputMaxval,
+              sample *           const outputMaxvalP,
+              bool *             const mustChangeRasterP) {
+/*----------------------------------------------------------------------------
+   Plan the transform described by 'cmdline', given the maxval of the input
+   image is 'inputMaxval.
+
+   The plan just consists of whether to change the maxval or the raster.
+   Some multiplications and divisions can be achieved just by changing the
+   maxval and leaving the samples in the raster alone.
+-----------------------------------------------------------------------------*/
+    if (cmdline.changemaxval) {
+        /* User allows us to change the maxval, if that makes it easier */
+        if (cmdline.function == FN_MULTIPLY || cmdline.function == FN_DIVIDE) {
+            float const multiplier =
+                cmdline.function == FN_MULTIPLY ? cmdline.u.multiplier :
+                (1/cmdline.u.divisor);
+
+            float const neededMaxval = inputMaxval / multiplier;
+
+            if (neededMaxval + 0.5 < inputMaxval) {
+                /* Lowering the maxval might make some of the sample values
+                   higher than the maxval, so we'd have to modify the raster
+                   to clip them.
+                */
+                *outputMaxvalP     = inputMaxval;
+                *mustChangeRasterP = true;
+            } else if (neededMaxval > PAM_OVERALL_MAXVAL) {
+                *outputMaxvalP     = inputMaxval;
+                *mustChangeRasterP = true;
+            } else {
+                *outputMaxvalP     = ROUNDU(neededMaxval);
+                *mustChangeRasterP = false;
+            }
+        } else {
+            *outputMaxvalP     = inputMaxval;
+            *mustChangeRasterP = true;
+        }
+    } else {
+        *outputMaxvalP     = inputMaxval;
+        *mustChangeRasterP = true;
+    }
+    if (*outputMaxvalP != inputMaxval)
+        pm_message("Changing maxval to %u because of -changemaxval",
+                   (unsigned)*outputMaxvalP);
+}
+
+
+
+static void
+applyFunction(struct CmdlineInfo const cmdline,
               struct pam         const inpam,
               struct pam         const outpam,
               tuple *            const inputRow,
@@ -275,10 +331,10 @@ applyFunction(struct cmdlineInfo const cmdline,
            divide, both cmdline.u.divisor and oneOverDivisor are
            meaningless.  
         */
-    int col;
+    unsigned int col;
 
     for (col = 0; col < inpam.width; ++col) {
-        int plane;
+        unsigned int plane;
         for (plane = 0; plane < inpam.depth; ++plane) {
             sample const inSample = inputRow[col][plane];
             sample outSample;  /* Could be > maxval  */
@@ -330,21 +386,22 @@ applyFunction(struct cmdlineInfo const cmdline,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     FILE * ifP;
     tuple * inputRow;   /* Row from input image */
     tuple * outputRow;  /* Row of output image */
-    int row;
-    struct cmdlineInfo cmdline;
+    unsigned int row;
+    struct CmdlineInfo cmdline;
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
+    bool mustChangeRaster;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -355,16 +412,21 @@ main(int argc, char *argv[]) {
     outpam = inpam;    /* Initial value -- most fields should be same */
     outpam.file = stdout;
 
+    planTransform(cmdline, inpam.maxval, &outpam.maxval, &mustChangeRaster);
+
     pnm_writepaminit(&outpam);
 
     outputRow = pnm_allocpamrow(&outpam);
 
-    for (row = 0; row < inpam.height; row++) {
+    for (row = 0; row < inpam.height; ++row) {
         pnm_readpamrow(&inpam, inputRow);
 
-        applyFunction(cmdline, inpam, outpam, inputRow, outputRow);
+        if (mustChangeRaster) {
+            applyFunction(cmdline, inpam, outpam, inputRow, outputRow);
 
-        pnm_writepamrow(&outpam, outputRow);
+            pnm_writepamrow(&outpam, outputRow);
+        } else
+            pnm_writepamrow(&outpam, inputRow);
     }
     pnm_freepamrow(outputRow);
     pnm_freepamrow(inputRow);
@@ -374,3 +436,5 @@ main(int argc, char *argv[]) {
     return 0;
 }
 
+
+