#include "pm_c_util.h" #include "mallocvar.h" #include "shhopt.h" #include "pam.h" struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFilespec; const char * maskFilespec; unsigned int verbose; float sharpness; float threshold; }; static void parseCommandLine(int argc, const 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; /* Instructions to OptParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; unsigned int sharpSpec, thresholdSpec; MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "sharpness", OPT_FLOAT, &cmdlineP->sharpness, &sharpSpec, 0); OPTENT3(0, "threshold", OPT_FLOAT, &cmdlineP->threshold, &thresholdSpec, 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 */ pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (sharpSpec) { if (cmdlineP->sharpness < 0) pm_error("-sharpness less than zero doesn't make sense. " "You specified %f", cmdlineP->sharpness); } else cmdlineP->sharpness = 1.0; if (thresholdSpec) { if (cmdlineP->threshold < 0) pm_error("-threshold less than zero doesn't make sense. " "You specified %f", cmdlineP->threshold); if (cmdlineP->threshold > 1.0) pm_error("-threshold greater than unity doesn't make sense. " "You specified %f", cmdlineP->threshold); } else cmdlineP->threshold = 0.0; if (argc-1 < 1) pm_error("You must specify at least one argument: The name " "of the mask image file"); else { cmdlineP->maskFilespec = argv[1]; if (argc-1 < 2) cmdlineP->inputFilespec = "-"; else { cmdlineP->inputFilespec = argv[2]; if (argc-1 > 2) pm_error("There are at most two arguments: mask file name " "and input file name. You specified %d", argc-1); } } } static sample sharpened(sample const inputSample, sample const maskSample, float const sharpness, sample const threshold, sample const maxval) { int const edgeness = inputSample - maskSample; sample retval; if (abs(edgeness) > threshold) { float const rawResult = inputSample + edgeness * sharpness; retval = MIN(maxval, (unsigned)MAX(0, (int)(rawResult+0.5))); } else retval = inputSample; return retval; } int main(int argc, const char * *argv) { struct cmdlineInfo cmdline; struct pam inpam; struct pam maskpam; struct pam outpam; FILE * ifP; FILE * maskfP; tuple * inputTuplerow; tuple * maskTuplerow; tuple * outputTuplerow; unsigned int row; sample threshold; /* Magnitude of difference between image and unsharp mask below which they will be considered identical. */ pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); maskfP = pm_openr(cmdline.maskFilespec); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); pnm_readpaminit(maskfP, &maskpam, PAM_STRUCT_SIZE(tuple_type)); if (inpam.width != maskpam.width || inpam.height != maskpam.height || inpam.depth != maskpam.depth) pm_error("The mask image must be the same dimensions as the " "input image. The mask is %dx%dx%d, but the input is " "%dx%dx%d.", maskpam.width, maskpam.height, maskpam.depth, inpam.width, inpam.height, inpam.depth); if (inpam.maxval != maskpam.maxval) pm_error("The mask image must have the same maxval as the " "input image. The input image has maxval %u, " "but the mask image has maxval %u", (unsigned)inpam.maxval, (unsigned)maskpam.maxval); threshold = (float)cmdline.threshold / inpam.maxval; outpam = inpam; outpam.file = stdout; inputTuplerow = pnm_allocpamrow(&inpam); maskTuplerow = pnm_allocpamrow(&maskpam); outputTuplerow = pnm_allocpamrow(&outpam); pnm_writepaminit(&outpam); for (row = 0; row < outpam.height; ++row) { unsigned int col; pnm_readpamrow(&inpam, inputTuplerow); pnm_readpamrow(&maskpam, maskTuplerow); for (col = 0; col < outpam.width; ++col) { unsigned int plane; for (plane = 0; plane < outpam.depth; ++plane) { outputTuplerow[col][plane] = sharpened(inputTuplerow[col][plane], maskTuplerow[col][plane], cmdline.sharpness, threshold, outpam.maxval); } } pnm_writepamrow(&outpam, outputTuplerow); } pm_close(ifP); pm_close(maskfP); pnm_freepamrow(inputTuplerow); pnm_freepamrow(maskTuplerow); pnm_freepamrow(outputTuplerow); return 0; }