/* pnmarith.c - perform arithmetic on two portable anymaps ** ** slightly modified by Marcel Wijkstra ** ** ** Copyright (C) 1989, 1991 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pam.h" #include "shhopt.h" enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIFFERENCE, FN_MINIMUM, FN_MAXIMUM, FN_MEAN, FN_COMPARE}; struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ char *input1Filespec; char *input2Filespec; enum function function; }; 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 addSpec, subtractSpec, multiplySpec, differenceSpec, minimumSpec, maximumSpec, meanSpec, compareSpec; option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "add", OPT_FLAG, NULL, &addSpec, 0); OPTENT3(0, "subtract", OPT_FLAG, NULL, &subtractSpec, 0); OPTENT3(0, "multiply", OPT_FLAG, NULL, &multiplySpec, 0); OPTENT3(0, "difference", OPT_FLAG, NULL, &differenceSpec, 0); OPTENT3(0, "minimum", OPT_FLAG, NULL, &minimumSpec, 0); OPTENT3(0, "maximum", OPT_FLAG, NULL, &maximumSpec, 0); OPTENT3(0, "mean", OPT_FLAG, NULL, &meanSpec, 0); OPTENT3(0, "compare", OPT_FLAG, NULL, &compareSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (addSpec + subtractSpec + multiplySpec + differenceSpec + minimumSpec + maximumSpec + meanSpec + compareSpec > 1) pm_error("You may specify only one function"); if (argc-1 != 2) pm_error("You must specify two arguments: the files which are " "the operands of the " "dyadic function. You specified %d", argc-1); else { cmdlineP->input1Filespec = argv[1]; cmdlineP->input2Filespec = argv[2]; } if (addSpec) cmdlineP->function = FN_ADD; else if (subtractSpec) cmdlineP->function = FN_SUBTRACT; else if (multiplySpec) cmdlineP->function = FN_MULTIPLY; else if (differenceSpec) cmdlineP->function = FN_DIFFERENCE; else if (minimumSpec) cmdlineP->function = FN_MINIMUM; else if (maximumSpec) cmdlineP->function = FN_MAXIMUM; else if (meanSpec) cmdlineP->function = FN_MEAN; else if (compareSpec) cmdlineP->function = FN_COMPARE; else pm_error("You must specify a function (e.g. '-add')"); } static void computeOutputType(struct pam * const outpamP, struct pam const inpam1, struct pam const inpam2, enum function const function) { outpamP->size = sizeof(struct pam); outpamP->len = sizeof(struct pam); outpamP->file = stdout; outpamP->format = MAX(inpam1.format, inpam2.format); outpamP->plainformat = FALSE; outpamP->height = inpam1.height; outpamP->width = inpam1.width; outpamP->depth = MAX(inpam1.depth, inpam2.depth); outpamP->maxval = MAX(inpam1.maxval, inpam2.maxval); if (function == FN_COMPARE) outpamP->maxval = MAX(outpamP->maxval, 2); outpamP->bytes_per_sample = (pm_maxvaltobits(outpamP->maxval)+7)/8; strcpy(outpamP->tuple_type, inpam1.tuple_type); } int main(int argc, char *argv[]) { struct cmdlineInfo cmdline; struct pam inpam1; struct pam inpam2; struct pam outpam; FILE* if1P; FILE* if2P; tuple* tuplerow1; tuple* tuplerow2; tuple* tuplerowOut; unsigned int row; pnm_init( &argc, argv ); parseCommandLine(argc, argv, &cmdline); if1P = pm_openr(cmdline.input1Filespec); if2P = pm_openr(cmdline.input2Filespec); pnm_readpaminit(if1P, &inpam1, sizeof(inpam1)); pnm_readpaminit(if2P, &inpam2, sizeof(inpam2)); if (inpam1.width != inpam2.width || inpam1.height != inpam1.height) pm_error("The two images must be the same dimensions. " "The first is %dx%dx%d, but the second is %dx%dx%d", inpam1.width, inpam1.height, inpam1.depth, inpam2.width, inpam2.height, inpam2.depth); if (inpam1.depth != 1 && inpam2.depth != 1 && inpam1.depth != inpam2.depth) pm_error("The two images must have the same depth or one of them " "must have depth 1. The first has depth %d and the second " "has depth %d", inpam1.depth, inpam2.depth); computeOutputType(&outpam, inpam1, inpam2, cmdline.function); tuplerow1 = pnm_allocpamrow(&inpam1); tuplerow2 = pnm_allocpamrow(&inpam2); tuplerowOut = pnm_allocpamrow(&outpam); pnm_writepaminit(&outpam); for (row = 0; row < outpam.height; ++row) { unsigned int col; pnm_readpamrow(&inpam1, tuplerow1); pnm_readpamrow(&inpam2, tuplerow2); if (outpam.maxval != inpam1.maxval) pnm_scaletuplerow(&inpam1, tuplerow1, tuplerow1, outpam.maxval); if (outpam.maxval != inpam2.maxval) pnm_scaletuplerow(&inpam2, tuplerow2, tuplerow2, outpam.maxval); for (col = 0; col < outpam.width; ++col) { unsigned int outplane; for (outplane = 0; outplane < outpam.depth; ++outplane) { unsigned int const plane1 = MIN(outplane, inpam1.depth-1); unsigned int const plane2 = MIN(outplane, inpam2.depth-1); double result; switch (cmdline.function) { case FN_ADD: result = tuplerow1[col][plane1] + tuplerow2[col][plane2]; break; case FN_SUBTRACT: result = (int)tuplerow1[col][plane1] - (int)tuplerow2[col][plane2]; break; case FN_MULTIPLY: result = tuplerow1[col][plane1] * tuplerow2[col][plane2] / outpam.maxval; break; case FN_DIFFERENCE: result = tuplerow1[col][plane1] > tuplerow2[col][plane2] ? tuplerow1[col][plane1] - tuplerow2[col][plane2] : tuplerow2[col][plane2] - tuplerow1[col][plane1]; break; case FN_MINIMUM: result = MIN(tuplerow1[col][plane1], tuplerow2[col][plane2]); break; case FN_MAXIMUM: result = MAX(tuplerow1[col][plane1], tuplerow2[col][plane2]); break; case FN_MEAN: result = (tuplerow1[col][plane1] + tuplerow2[col][plane2])/2.0; break; case FN_COMPARE: result = tuplerow1[col][plane1] > tuplerow2[col][plane2] ? 2 : tuplerow1[col][plane1] < tuplerow2[col][plane2] ? 0 : 1; break; } result = MAX(0, result); result = MIN(outpam.maxval, result); tuplerowOut[col][outplane] = (unsigned int) (result + 0.5); } } pnm_writepamrow(&outpam, tuplerowOut); } pm_close(if1P); pm_close(if2P); pnm_freepamrow(tuplerow1); pnm_freepamrow(tuplerow2); pnm_freepamrow(tuplerowOut); exit(0); }