about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-12-22 19:10:25 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-12-22 19:10:25 +0000
commit00b5c554ee6d2ec2f1f8b29ebd7b4bbaa8581cb9 (patch)
treed8f29fe03a11046ccdf0a33246e31d2d41ca9172
parent8796566268e8f7469f8dc6ccc41cf03d135c4d74 (diff)
downloadnetpbm-mirror-00b5c554ee6d2ec2f1f8b29ebd7b4bbaa8581cb9.tar.gz
netpbm-mirror-00b5c554ee6d2ec2f1f8b29ebd7b4bbaa8581cb9.tar.xz
netpbm-mirror-00b5c554ee6d2ec2f1f8b29ebd7b4bbaa8581cb9.zip
Add -changemaxval
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2075 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--doc/HISTORY2
-rw-r--r--editor/pamfunc.c79
2 files changed, 72 insertions, 9 deletions
diff --git a/doc/HISTORY b/doc/HISTORY
index 27e58d86..5c4067df 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -6,6 +6,8 @@ CHANGE HISTORY
 
 not yet  BJH  Release 10.65.00
 
+              pamfunc: add -changemaxval.
+
               pgmkernel: add -maxval.
 
               Recognize SIGPWR on systems that have it in messages
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index bcec22f3..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).
 
 ******************************************************************************/
 
@@ -58,6 +58,7 @@ struct CmdlineInfo {
         unsigned int mask;
         unsigned int shiftCount;
     } u;
+    unsigned int changemaxval;
     unsigned int verbose;
 };
 
@@ -126,7 +127,10 @@ parseCommandLine(int argc, const 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 */
@@ -260,6 +264,57 @@ validateFunction(struct CmdlineInfo const cmdline,
 
 
 static void
+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,
@@ -276,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  */
@@ -336,10 +391,11 @@ main(int argc, const char *argv[]) {
     FILE * ifP;
     tuple * inputRow;   /* Row from input image */
     tuple * outputRow;  /* Row of output image */
-    int row;
+    unsigned int row;
     struct CmdlineInfo cmdline;
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
+    bool mustChangeRaster;
 
     pm_proginit(&argc, argv);
 
@@ -356,16 +412,21 @@ main(int argc, const 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);