about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--editor/pamscale.c79
1 files changed, 47 insertions, 32 deletions
diff --git a/editor/pamscale.c b/editor/pamscale.c
index 82f4209f..09b61ed0 100644
--- a/editor/pamscale.c
+++ b/editor/pamscale.c
@@ -751,21 +751,28 @@ parseCommandLine(int argc,
 
 static void 
 computeOutputDimensions(struct cmdlineInfo  const cmdline, 
-                        unsigned int        const rows, 
                         unsigned int        const cols, 
-                        int *               const newrowsP, 
-                        int *               const newcolsP) {
+                        unsigned int        const rows, 
+                        int *               const newcolsP,
+                        int *               const newrowsP) { 
+
+    double newcolsD, newrowsD;
+        /* Intermediate calculation of the output dimensions, in double
+           precision floating point to avoid arithmetic overflow.
+        */
+    unsigned int newcols, newrows;
+        /* The output dimensions we return */
 
     switch(cmdline.scaleType) {
     case SCALE_PIXELMAX: {
         if (rows * cols <= cmdline.pixels) {
-            *newrowsP = rows;
-            *newcolsP = cols;
+            newrowsD = rows;
+            newcolsD = cols;
         } else {
             const double scale =
                 sqrt( (float) cmdline.pixels / ((float) cols * (float) rows));
-            *newrowsP = rows * scale;
-            *newcolsP = cols * scale;
+            newrowsD = rows * scale;
+            newcolsD = cols * scale;
         }
     } break;
     case SCALE_BOXFIT:
@@ -778,48 +785,56 @@ computeOutputDimensions(struct cmdlineInfo  const cmdline,
              cmdline.scaleType == SCALE_BOXFIT) ||
             (box_aspect_ratio < aspect_ratio &&
              cmdline.scaleType == SCALE_BOXFILL)) {
-            *newrowsP = cmdline.ysize;
-            *newcolsP = *newrowsP * aspect_ratio + 0.5;
+            newrowsD = cmdline.ysize;
+            newcolsD = newrowsD * aspect_ratio;
         } else {
-            *newcolsP = cmdline.xsize;
-            *newrowsP = *newcolsP / aspect_ratio + 0.5;
+            newcolsD = cmdline.xsize;
+            newrowsD = newcolsD / aspect_ratio;
         }
     } break;
     case SCALE_SEPARATE: {
         if (cmdline.xsize)
-            *newcolsP = cmdline.xsize;
+            newcolsD = cmdline.xsize;
         else if (cmdline.xscale)
-            *newcolsP = cmdline.xscale * cols + .5;
+            newcolsD = cmdline.xscale * cols;
         else if (cmdline.ysize)
-            *newcolsP = cols * ((float) cmdline.ysize/rows) +.5;
+            newcolsD = cols * ((float) cmdline.ysize/rows);
         else
-            *newcolsP = cols;
+            newcolsD = cols;
 
         if (cmdline.ysize)
-            *newrowsP = cmdline.ysize;
+            newrowsD = cmdline.ysize;
         else if (cmdline.yscale)
-            *newrowsP = cmdline.yscale * rows +.5;
+            newrowsD = cmdline.yscale * rows;
         else if (cmdline.xsize)
-            *newrowsP = rows * ((float) cmdline.xsize/cols) +.5;
+            newrowsD = rows * ((float) cmdline.xsize/cols);
         else
-            *newrowsP = rows;
+            newrowsD = rows;
     }
     }
-
-    /* If the calculations above yielded (due to rounding) a zero 
-     * dimension, we fudge it up to 1.  We do this rather than considering
-     * it a specification error (and dying) because it's friendlier to 
-     * automated processes that work on arbitrary input.  It saves them
-     * having to check their numbers to avoid catastrophe.
-     */
-  
-    if (*newcolsP < 1) *newcolsP = 1;
-    if (*newrowsP < 1) *newrowsP = 1;
+    
+    /* If the rounding yields a zero dimension, we fudge it up to 1.  We do
+       this rather than considering it a specification error (and dying)
+       because it's friendlier to automated processes that work on arbitrary
+       input.  It saves them having to check their numbers to avoid
+       catastrophe.
+    */
+    newcols = MAX(1, ROUNDU(newcolsD));
+    newrows = MAX(1, ROUNDU(newrowsD));
+
+    if (newcols > INT_MAX - 2)
+        pm_error("output image width (%u) too large for computations",
+                 newcols);
+    if (newrows > INT_MAX - 2)
+        pm_error("output image height (%u) too large for computation",
+                 newrows);
+
+    *newcolsP = newcols;
+    *newrowsP = newrows;
 }
 
 
 
-
 /****************************/
 /****************************/
 /******* resampling *********/
@@ -2142,8 +2157,8 @@ pamscale(FILE *             const ifP,
         outpam.maxval = inpam.maxval;
     }
 
-    computeOutputDimensions(cmdline, inpam.height, inpam.width,
-                            &outpam.height, &outpam.width);
+    computeOutputDimensions(cmdline, inpam.width, inpam.height, 
+                            &outpam.width, &outpam.height);
 
     xscale = (float) outpam.width / inpam.width;
     yscale = (float) outpam.height / inpam.height;