diff options
Diffstat (limited to 'editor/pnmscalefixed.c')
-rw-r--r-- | editor/pnmscalefixed.c | 113 |
1 files changed, 59 insertions, 54 deletions
diff --git a/editor/pnmscalefixed.c b/editor/pnmscalefixed.c index 884ca315..1a89a2e5 100644 --- a/editor/pnmscalefixed.c +++ b/editor/pnmscalefixed.c @@ -15,10 +15,11 @@ ** - added -reduce N to allow scaling by integer value ** in this case, scale_comp becomes 1/N and x/yscale ** get set as they should -** +** ** */ - + +#include <limits.h> #include <math.h> #include "pm_c_util.h" @@ -27,12 +28,12 @@ #include "pnm.h" /* The pnm library allows us to code this program without branching cases - for PGM and PPM, but we do the branch anyway to speed up processing of + for PGM and PPM, but we do the branch anyway to speed up processing of PGM images. */ /* We do all our arithmetic in integers. In order not to get killed by the - rounding, we scale every number up by the factor SCALE, do the + rounding, we scale every number up by the factor SCALE, do the arithmetic, then scale it back down. */ #define SCALE 4096 @@ -118,16 +119,16 @@ parse_command_line(int argc, char ** argv, pm_error("Cannot specify both -xsize/width and -xscale."); if (ysize != -1 && yscale != -1) pm_error("Cannot specify both -ysize/height and -yscale."); - - if (xysize && - (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1 || + + if (xysize && + (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1 || reduce != -1 || pixels != -1) ) pm_error("Cannot specify -xysize with other dimension options."); - if (pixels != -1 && + if (pixels != -1 && (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1 || reduce != -1) ) pm_error("Cannot specify -pixels with other dimension options."); - if (reduce != -1 && + if (reduce != -1 && (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1) ) pm_error("Cannot specify -reduce with other dimension options."); @@ -148,7 +149,7 @@ parse_command_line(int argc, char ** argv, else { cmdline_p->xbox = atoi(argv[1]); cmdline_p->ybox = atoi(argv[2]); - + if (argc-1 < 3) cmdline_p->input_filespec = "-"; else @@ -157,7 +158,7 @@ parse_command_line(int argc, char ** argv, } else { cmdline_p->xbox = 0; cmdline_p->ybox = 0; - + if (xsize == -1 && xscale == -1 && ysize == -1 && yscale == -1 && pixels == -1 && reduce == -1) { /* parameters are scale factor and optional filespec */ @@ -187,7 +188,7 @@ parse_command_line(int argc, char ** argv, if (reduce != -1) { scale_parm = ((double) 1.0) / ((double) reduce); - pm_message("reducing by %d gives scale factor of %f.", + pm_message("reducing by %d gives scale factor of %f.", reduce, scale_parm); } else scale_parm = 0.0; @@ -210,12 +211,12 @@ parse_command_line(int argc, char ** argv, static void -compute_output_dimensions(const struct cmdline_info cmdline, +compute_output_dimensions(const struct cmdline_info cmdline, const int rows, const int cols, int * newrowsP, int * newcolsP) { if (cmdline.pixels) { - if (rows * cols <= cmdline.pixels) { + if (rows <= cmdline.pixels / cols) { *newrowsP = rows; *newcolsP = cols; } else { @@ -226,9 +227,9 @@ compute_output_dimensions(const struct cmdline_info cmdline, } } else if (cmdline.xbox) { const double aspect_ratio = (float) cols / (float) rows; - const double box_aspect_ratio = + const double box_aspect_ratio = (float) cmdline.xbox / (float) cmdline.ybox; - + if (box_aspect_ratio > aspect_ratio) { *newrowsP = cmdline.ybox; *newcolsP = *newrowsP * aspect_ratio + 0.5; @@ -254,24 +255,24 @@ compute_output_dimensions(const struct cmdline_info cmdline, *newrowsP = rows * ((float) cmdline.xsize/cols) +.5; else *newrowsP = rows; - } + } - /* If the calculations above yielded (because of rounding) a zero + /* If the calculations above yielded (because of 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 + 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; -} +} static void -horizontal_scale(const xel inputxelrow[], xel newxelrow[], - const int cols, const int newcols, const long sxscale, +horizontal_scale(const xel inputxelrow[], xel newxelrow[], + const int cols, const int newcols, const long sxscale, const int format, const xelval maxval, int * stretchP) { /*---------------------------------------------------------------------------- @@ -282,14 +283,14 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], 'format' and 'maxval' describe the Netpbm format of the both input and output rows. - *stretchP is the number of columns (could be fractional) on the right + *stretchP is the number of columns (could be fractional) on the right that we had to fill by stretching because of rounding problems. -----------------------------------------------------------------------------*/ long r, g, b; long fraccoltofill, fraccolleft; unsigned int col; unsigned int newcol; - + newcol = 0; fraccoltofill = SCALE; /* Output column is "empty" now */ r = g = b = 0; /* initial value */ @@ -302,7 +303,7 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], */ while (fraccolleft >= fraccoltofill) { /* Generate one output pixel in 'newxelrow'. It will consist - of anything accumulated from prior input pixels in 'r','g', + of anything accumulated from prior input pixels in 'r','g', and 'b', plus a fraction of the current input pixel. */ switch (PNM_FORMAT_TYPE(format)) { @@ -332,7 +333,7 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], fraccoltofill = SCALE; r = g = b = 0; } - /* There's not enough left in the current input pixel to fill up + /* There's not enough left in the current input pixel to fill up a whole output column, so just accumulate the remainder of the pixel into the current output column. */ @@ -343,7 +344,7 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], g += fraccolleft * PPM_GETG(inputxelrow[col]); b += fraccolleft * PPM_GETB(inputxelrow[col]); break; - + default: g += fraccolleft * PNM_GET1(inputxelrow[col]); break; @@ -356,7 +357,7 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], while (newcol < newcols) { /* We ran out of input columns before we filled up the output columns. This would be because of rounding down. For small - images, we're probably missing only a tiny fraction of a column, + images, we're probably missing only a tiny fraction of a column, but for large images, it could be multiple columns. So we fake the remaining output columns by copying the rightmost @@ -382,7 +383,7 @@ horizontal_scale(const xel inputxelrow[], xel newxelrow[], if ( b > maxval ) b = maxval; PPM_ASSIGN(newxelrow[newcol], r, g, b ); break; - + default: g += fraccoltofill * PNM_GET1(inputxelrow[cols-1]); g += HALFSCALE; /* for rounding */ @@ -416,7 +417,7 @@ main(int argc, char **argv ) { long* gs; long* bs; int vertical_stretch; - /* The number of rows we had to fill by stretching because of + /* The number of rows we had to fill by stretching because of rounding error, which made us run out of input rows before we had filled up the output rows. */ @@ -434,7 +435,7 @@ main(int argc, char **argv ) { newformat = PGM_TYPE; newmaxval = PGM_MAXMAXVAL; pm_message( "promoting from PBM to PGM" ); - } else { + } else { newformat = format; newmaxval = maxval; } @@ -446,18 +447,22 @@ main(int argc, char **argv ) { unfilled. We can address that by stretching, whereas the other case would require throwing away some of the input. */ + if (newcols > INT_MAX / SCALE) + pm_error("New image width (%d) is uncomputably large", newcols); + if (newrows > INT_MAX / SCALE) + pm_error("New image height (%d) is uncomputably large", newrows); sxscale = SCALE * newcols / cols; syscale = SCALE * newrows / rows; if (cmdline.verbose) { - pm_message("Scaling by %ld/%d = %f horizontally to %d columns.", + pm_message("Scaling by %ld/%d = %f horizontally to %d columns.", sxscale, SCALE, (float) sxscale/SCALE, newcols ); - pm_message("Scaling by %ld/%d = %f vertically to %d rows.", + pm_message("Scaling by %ld/%d = %f vertically to %d rows.", syscale, SCALE, (float) syscale/SCALE, newrows); } xelrow = pnm_allocrow(cols); - if (newrows == rows) /* shortcut Y scaling if possible */ + if (newrows == rows) /* shortcut Y scaling if possible */ tempxelrow = xelrow; else tempxelrow = pnm_allocrow( cols ); @@ -468,18 +473,18 @@ main(int argc, char **argv ) { fracrowleft = syscale; needtoreadrow = 1; for ( col = 0; col < cols; ++col ) - rs[col] = gs[col] = bs[col] = HALFSCALE; + rs[col] = gs[col] = bs[col] = HALFSCALE; fracrowtofill = SCALE; vertical_stretch = 0; - + pnm_writepnminit( stdout, newcols, newrows, newmaxval, newformat, 0 ); newxelrow = pnm_allocrow( newcols ); - + for ( row = 0; row < newrows; ++row ) { /* First scale vertically from xelrow into tempxelrow. */ if ( newrows == rows ) { /* shortcut vertical scaling if possible */ pnm_readpnmrow( ifp, xelrow, cols, newmaxval, format ); - } else { + } else { while ( fracrowleft < fracrowtofill ) { if ( needtoreadrow ) if ( rowsread < rows ) { @@ -513,8 +518,8 @@ main(int argc, char **argv ) { } else { /* We need another input row to fill up this output row, but there aren't any more. That's because of rounding - down on our scaling arithmetic. So we go ahead with - the data from the last row we read, which amounts to + down on our scaling arithmetic. So we go ahead with + the data from the last row we read, which amounts to stretching out the last output row. */ vertical_stretch += fracrowtofill; @@ -544,7 +549,7 @@ main(int argc, char **argv ) { for ( col = 0, xP = xelrow, nxP = tempxelrow; col < cols; ++col, ++xP, ++nxP ) { register long g; - + g = gs[col] + fracrowtofill * PNM_GET1( *xP ); g /= SCALE; if ( g > newmaxval ) g = newmaxval; @@ -559,37 +564,37 @@ main(int argc, char **argv ) { needtoreadrow = 1; } fracrowtofill = SCALE; - } + } /* Now scale tempxelrow horizontally into newxelrow & write it out. */ - if (newcols == cols) /* shortcut X scaling if possible */ - pnm_writepnmrow(stdout, tempxelrow, newcols, + if (newcols == cols) /* shortcut X scaling if possible */ + pnm_writepnmrow(stdout, tempxelrow, newcols, newmaxval, newformat, 0); else { int stretch; - horizontal_scale(tempxelrow, newxelrow, cols, newcols, sxscale, + horizontal_scale(tempxelrow, newxelrow, cols, newcols, sxscale, format, newmaxval, &stretch); - + if (cmdline.verbose && row == 0 && stretch != 0) pm_message("%d/%d = %f right columns filled by stretching " - "because of arithmetic imprecision", + "because of arithmetic imprecision", stretch, SCALE, (float) stretch/SCALE); - - pnm_writepnmrow(stdout, newxelrow, newcols, + + pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0 ); } - } + } if (cmdline.verbose && vertical_stretch != 0) pm_message("%d/%d = %f bottom rows filled by stretching due to " - "arithmetic imprecision", - vertical_stretch, SCALE, + "arithmetic imprecision", + vertical_stretch, SCALE, (float) vertical_stretch/SCALE); - + pm_close( ifp ); pm_close( stdout ); - + exit( 0 ); } |