diff options
Diffstat (limited to 'editor/pnmsmooth.c')
-rw-r--r-- | editor/pnmsmooth.c | 162 |
1 files changed, 108 insertions, 54 deletions
diff --git a/editor/pnmsmooth.c b/editor/pnmsmooth.c index 16d8ec33..a76bd42b 100644 --- a/editor/pnmsmooth.c +++ b/editor/pnmsmooth.c @@ -21,6 +21,7 @@ #include <unistd.h> +#include <assert.h> #include <string.h> #include <errno.h> @@ -28,6 +29,7 @@ #include "mallocvar.h" #include "shhopt.h" #include "nstring.h" +#include "pm.h" /* For pm_plain_output */ #include "pm_system.h" #include "pnm.h" @@ -39,13 +41,13 @@ struct cmdlineInfo { const char * inputFilespec; /* Filespec of input file */ unsigned int width; unsigned int height; - const char * dump; + unsigned int dump; }; static void -parseCommandLine (int argc, char ** argv, +parseCommandLine (int argc, const char ** argv, struct cmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc @@ -58,19 +60,19 @@ parseCommandLine (int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; - unsigned int widthSpec, heightSpec, dumpSpec, sizeSpec; + unsigned int widthSpec, heightSpec, sizeSpec; MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "dump", OPT_STRING, - &cmdlineP->dump, &dumpSpec, 0); + OPTENT3(0, "dump", OPT_FLAG, + NULL, &cmdlineP->dump, 0); OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, &widthSpec, 0); OPTENT3(0, "height", OPT_UINT, @@ -82,18 +84,17 @@ parseCommandLine (int argc, char ** argv, 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 *cmdline_p and others. */ + free(option_def); + if (!widthSpec) cmdlineP->width = 3; if (!heightSpec) cmdlineP->height = 3; - if (!dumpSpec) - cmdlineP->dump = NULL; - if (sizeSpec) { /* -size is strictly for backward compatibility. This program used to use a different command line processor and had @@ -142,69 +143,122 @@ parseCommandLine (int argc, char ** argv, } - static void -writeConvolutionImage(FILE * const cofp, - unsigned int const cols, - unsigned int const rows, - int const format) { - - xelval const convmaxval = rows * cols * 2; - /* normalizing factor for our convolution matrix */ - xelval const g = rows * cols + 1; - /* weight of all pixels in our convolution matrix */ - int row; - xel *outputrow; - - if (convmaxval > PNM_OVERALLMAXVAL) - pm_error("The convolution matrix is too large. " - "Width x Height x 2\n" - "must not exceed %d and it is %d.", - PNM_OVERALLMAXVAL, convmaxval); - - pnm_writepnminit(cofp, cols, rows, convmaxval, format, 0); - outputrow = pnm_allocrow(cols); - - for (row = 0; row < rows; ++row) { - unsigned int col; - for (col = 0; col < cols; ++col) - PNM_ASSIGN1(outputrow[col], g); - pnm_writepnmrow(cofp, outputrow, cols, convmaxval, format, 0); +validateComputableDimensions(unsigned int const cols, + unsigned int const rows){ +/*---------------------------------------------------------------------------- + Make sure that convolution matrix dimensions are small enough to + represent in a string. +-----------------------------------------------------------------------------*/ + unsigned int const maxStringLength = INT_MAX - 2 -6; + + if (cols > maxStringLength / rows / 2 ) + pm_error("The convolution matrix size %u x %u is too large.", + cols, rows); +} + + + +static const char * +makeConvolutionKernel(unsigned int const cols, + unsigned int const rows) { +/*---------------------------------------------------------------------------- + Return a value for a Pnmconvol '-matrix' option that specifies a + convolution kernel with with dimensions 'cols' by 'rows' with 1 + for every weight. Caller can use this with Pnmconvol -normalize. +-----------------------------------------------------------------------------*/ + unsigned int const maxOptSize = cols * rows * 2; + + char * matrix; + + MALLOCARRAY(matrix, maxOptSize); + + if (matrix == NULL) + pm_error("Could not get memory for a %u x %u convolution matrix", + rows, cols); + else { + unsigned int row; + unsigned int cursor; + + for (row = 0, cursor = 0; row < rows; ++row) { + unsigned int col; + + if (row > 0) + matrix[cursor++] = ';'; + + for (col = 0; col < cols; ++col) { + if (col > 0) + matrix[cursor++] = ','; + + matrix[cursor++] = '1'; + } + } + assert(cursor < maxOptSize); + matrix[cursor] = '\0'; } - pnm_freerow(outputrow); + + return matrix; +} + + + +static void +validateMatrixOptSize(unsigned int const rows, + unsigned int const cols) { + + /* If the user accidentally specifies absurdly large values for the + convolution matrix size, the failure mode can be a confusing message + resulting from the 'pnmconvol' arguments being too large. To try + to be more polite in that case, we apply an arbitrary limit on the + size of the option here. + */ + + if (rows * cols > 5000) + pm_error("Convolution matrix dimensions %u x %u are too large " + "to be useful, so we assume you made a mistake. " + "We refuse to use numbers this large because they might " + "cause excessive resource use that would cause failures " + "whose cause would not be obvious to you", cols, rows); } int -main(int argc, char ** argv) { +main(int argc, const char ** argv) { struct cmdlineInfo cmdline; - FILE * convFileP; - const char * tempfileName; + const char * matrixOptValue; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - if (cmdline.dump) - convFileP = pm_openw(cmdline.dump); - else - pm_make_tmpfile(&convFileP, &tempfileName); - - writeConvolutionImage(convFileP, cmdline.width, cmdline.height, - PGM_FORMAT); + validateComputableDimensions(cmdline.width, cmdline.height); + validateMatrixOptSize(cmdline.width, cmdline.height); - pm_close(convFileP); + matrixOptValue = makeConvolutionKernel(cmdline.width, cmdline.height); if (cmdline.dump) { - /* We're done. Convolution image is in user's file */ + pm_error("-dump option no longer exists. " + "You don't need it because you can now do uniform " + "convolution easily with the -matrix and -normalize " + "options of 'pnmconvol'."); } else { + const char * const plainOpt = pm_plain_output ? "-plain" : NULL; + + const char * matrixOpt; + + pm_asprintf(&matrixOpt, "-matrix=%s", matrixOptValue); + + pm_message("Running Pnmconvol -normalize %s", matrixOpt); + pm_system_lp("pnmconvol", NULL, NULL, NULL, NULL, - "pnmconvol", tempfileName, cmdline.inputFilespec, NULL); + "pnmconvol", matrixOpt, cmdline.inputFilespec, + "-normalize", "-quiet", plainOpt, NULL); - unlink(tempfileName); - strfree(tempfileName); + pm_strfree(matrixOpt); } + pm_strfree(matrixOptValue); + return 0; } |