diff options
Diffstat (limited to 'editor/pamfunc.c')
-rw-r--r-- | editor/pamfunc.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/editor/pamfunc.c b/editor/pamfunc.c new file mode 100644 index 00000000..dbb1ca70 --- /dev/null +++ b/editor/pamfunc.c @@ -0,0 +1,221 @@ +/****************************************************************************** + pamfunc +******************************************************************************* + Apply one of various functions to each sample in a PAM image + + By Bryan Henderson, San Jose CA 2002.06.16. + + Contributed to the public domain + + ENHANCEMENT IDEAS: + + 1) speed up by doing integer arithmetic instead of floating point for + 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. + +******************************************************************************/ + +#include "pam.h" +#include "shhopt.h" + +enum function {FN_MULTIPLY, FN_DIVIDE, FN_ADD, FN_SUBTRACT, FN_MIN, FN_MAX}; + +/* Note that when the user specifies a minimum, that means he's requesting + a "max" function. +*/ + +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; + union { + float multiplier; + float divisor; + int adder; + int subtractor; + unsigned int max; + unsigned int min; + } u; + unsigned int verbose; +}; + + +static void +parseCommandLine(int argc, 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. +-----------------------------------------------------------------------------*/ + optEntry *option_def = malloc(100*sizeof(optEntry)); + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int multiplierSpec, divisorSpec, adderSpec, subtractorSpec; + unsigned int maxSpec, minSpec; + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "multiplier", OPT_FLOAT, &cmdlineP->u.multiplier, + &multiplierSpec, 0); + OPTENT3(0, "divisor", OPT_FLOAT, &cmdlineP->u.divisor, + &divisorSpec, 0); + OPTENT3(0, "adder", OPT_INT, &cmdlineP->u.adder, + &adderSpec, 0); + OPTENT3(0, "subtractor", OPT_INT, &cmdlineP->u.subtractor, + &subtractorSpec, 0); + OPTENT3(0, "min", OPT_UINT, &cmdlineP->u.min, + &minSpec, 0); + OPTENT3(0, "max", OPT_UINT, &cmdlineP->u.max, + &maxSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (multiplierSpec + divisorSpec + adderSpec + subtractorSpec + + minSpec + maxSpec > 1) + pm_error("You may specify at most one of -multiplier, -divisor," + "-adder, -subtractor, -min, and -max"); + + if (multiplierSpec) { + cmdlineP->function = FN_MULTIPLY; + if (cmdlineP->u.multiplier < 0) + pm_error("Multiplier must be nonnegative. You specified %f", + cmdlineP->u.multiplier); + } else if (divisorSpec) { + cmdlineP->function = FN_DIVIDE; + if (cmdlineP->u.divisor < 0) + pm_error("Divisor must be nonnegative. You specified %f", + cmdlineP->u.divisor); + } else if (adderSpec) { + cmdlineP->function = FN_ADD; + } else if (subtractorSpec) { + cmdlineP->function = FN_SUBTRACT; + } else if (minSpec) { + cmdlineP->function = FN_MAX; + } else if (maxSpec) { + cmdlineP->function = FN_MIN; + } else + pm_error("You must specify one of -multiplier, -divisor, " + "-adder, -subtractor, -min, or -max"); + + if (argc-1 > 1) + pm_error("Too many arguments (%d). File spec is the only argument.", + argc-1); + + if (argc-1 < 1) + cmdlineP->inputFilespec = "-"; + else + cmdlineP->inputFilespec = argv[1]; + +} + + + +static void +applyFunction(struct cmdlineInfo const cmdline, + struct pam const inpam, + struct pam const outpam, + tuple * const inputRow, + tuple * const outputRow) { + + float const oneOverDivisor = 1/cmdline.u.divisor; + /* In my experiments, the compiler couldn't figure out that + 1/cmdline.u.divisor is a constant and instead recomputed it + for each and every pixel. division is slower than + multiplication, so we want to multiply by + 1/cmdline.u.divisor instead of divide by cmdline.u.divisor, + so we compute that here. Note that if the function isn't + divide, both cmdline.u.divisor and oneOverDivisor are + meaningless. + */ + int col; + + for (col = 0; col < inpam.width; ++col) { + int plane; + for (plane = 0; plane < inpam.depth; ++plane) { + sample const inSample = inputRow[col][plane]; + sample outSample; /* Could be > maxval */ + + switch (cmdline.function) { + case FN_MULTIPLY: + outSample = ROUNDU(inSample * cmdline.u.multiplier); + break; + case FN_DIVIDE: + outSample = ROUNDU(inSample * oneOverDivisor); + break; + case FN_ADD: + outSample = MAX(0, (long)inSample + cmdline.u.adder); + break; + case FN_SUBTRACT: + outSample = MAX(0, (long)inSample - cmdline.u.subtractor); + break; + case FN_MAX: + outSample = MAX(inSample, cmdline.u.min); + break; + case FN_MIN: + outSample = MIN(inSample, cmdline.u.max); + break; + } + outputRow[col][plane] = MIN(outpam.maxval, outSample); + } + } +} + + + +int +main(int argc, char *argv[]) { + + FILE* ifP; + tuple* inputRow; /* Row from input image */ + tuple* outputRow; /* Row of output image */ + int row; + struct cmdlineInfo cmdline; + struct pam inpam; /* Input PAM image */ + struct pam outpam; /* Output PAM image */ + + pnm_init( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + inputRow = pnm_allocpamrow(&inpam); + + outpam = inpam; /* Initial value -- most fields should be same */ + outpam.file = stdout; + + pnm_writepaminit(&outpam); + + outputRow = pnm_allocpamrow(&outpam); + + for (row = 0; row < inpam.height; row++) { + pnm_readpamrow(&inpam, inputRow); + + applyFunction(cmdline, inpam, outpam, inputRow, outputRow); + + pnm_writepamrow(&outpam, outputRow); + } + pnm_freepamrow(outputRow); + pnm_freepamrow(inputRow); + pm_close(inpam.file); + pm_close(outpam.file); + + exit(0); +} + |