diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/pamscale.c | 3 | ||||
-rw-r--r-- | editor/pamthreshold.c | 37 | ||||
-rw-r--r-- | editor/pnmnorm.c | 185 |
3 files changed, 170 insertions, 55 deletions
diff --git a/editor/pamscale.c b/editor/pamscale.c index af7ab612..4f205064 100644 --- a/editor/pamscale.c +++ b/editor/pamscale.c @@ -2049,6 +2049,9 @@ scaleWithoutMixing(const struct pam * const inpamP, int row; int rowInInput; + assert(outpamP->maxval == inpamP->maxval); + assert(outpamP->depth == inpamP->depth); + tuplerow = pnm_allocpamrow(inpamP); rowInInput = -1; diff --git a/editor/pamthreshold.c b/editor/pamthreshold.c index e6eed864..428b819d 100644 --- a/editor/pamthreshold.c +++ b/editor/pamthreshold.c @@ -222,6 +222,21 @@ parseCommandLine(int argc, +static void +thresholdPixel(struct pam * const outpamP, + tuplen const inTuplen, + tuple const outTuple, + float const threshold) { + + outTuple[0] = inTuplen[0] >= threshold ? PAM_BW_WHITE : PAM_BLACK; + if (outpamP->depth > 1) { + /* Do alpha */ + outTuple[1] = inTuplen[1] > 0.5 ? 1 : 0; + } +} + + + /* simple thresholding (the same as in pamditherbw) */ static void @@ -240,9 +255,9 @@ thresholdSimple(struct pam * const inpamP, for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrown(inpamP, inrow); - for (col = 0; col < inpamP->width; ++col) - outrow[col][0] = - inrow[col][0] >= threshold ? PAM_BW_WHITE : PAM_BLACK; + for (col = 0; col < inpamP->width; ++col) { + thresholdPixel(outpamP, inrow[col], outrow[col], threshold); + } pnm_writepamrow(outpamP, outrow); } @@ -489,6 +504,7 @@ thresholdLocalRow(struct pam * const inpamP, struct cmdlineInfo const cmdline, struct range const globalRange, samplen const globalThreshold, + struct pam * const outpamP, tuple * const outrow) { tuplen * const inrow = inrows[row % windowHeight]; @@ -508,7 +524,7 @@ thresholdLocalRow(struct pam * const inpamP, cmdline.threshold, minSpread, globalThreshold, &threshold); - outrow[col][0] = inrow[col][0] >= threshold ? PAM_BW_WHITE : PAM_BLACK; + thresholdPixel(outpamP, inrow[col], outrow[col], threshold); } } @@ -595,7 +611,8 @@ thresholdLocal(struct pam * const inpamP, for (row = 0; row < inpamP->height; ++row) { thresholdLocalRow(inpamP, inrows, oddLocalWidth, windowHeight, row, - cmdline, globalRange, globalThreshold, outrow); + cmdline, globalRange, globalThreshold, + outpamP, outrow); pnm_writepamrow(outpamP, outrow); @@ -664,10 +681,16 @@ main(int argc, char **argv) { outpam.plainformat = 0; outpam.height = inpam.height; outpam.width = inpam.width; - outpam.depth = 1; outpam.maxval = 1; outpam.bytes_per_sample = 1; - strcpy(outpam.tuple_type, "BLACKANDWHITE"); + + if (inpam.depth > 1) { + strcpy(outpam.tuple_type, "BLACKANDWHITE_ALPHA"); + outpam.depth = 2; + } else { + strcpy(outpam.tuple_type, "BLACKANDWHITE"); + outpam.depth = 1; + } pnm_writepaminit(&outpam); diff --git a/editor/pnmnorm.c b/editor/pnmnorm.c index b36ad462..27d51115 100644 --- a/editor/pnmnorm.c +++ b/editor/pnmnorm.c @@ -29,9 +29,10 @@ #include <assert.h> -#include "pnm.h" -#include "shhopt.h" +#include "pm_c_util.h" #include "mallocvar.h" +#include "shhopt.h" +#include "pnm.h" enum brightMethod {BRIGHT_LUMINOSITY, BRIGHT_COLORVALUE, BRIGHT_SATURATION}; @@ -60,8 +61,8 @@ struct cmdlineInfo { static void -parseCommandLine (int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -116,7 +117,7 @@ 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 ); + optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (!cmdlineP->wpercentSpec) @@ -354,21 +355,85 @@ computeAdjustmentForExpansionLimit(xelval const maxval, static void -computeEndValues(FILE * const ifp, - int const cols, - int const rows, - xelval const maxval, - int const format, - struct cmdlineInfo const cmdline, - xelval * const bvalueP, - xelval * const wvalueP) { +disOverlap(xelval const reqBvalue, + xelval const reqWvalue, + bool const bIsFixed, + bool const wIsFixed, + xelval const maxval, + xelval * const nonOlapBvalueP, + xelval * const nonOlapWvalueP) { /*---------------------------------------------------------------------------- - Figure out what original values will be translated to full white and - full black -- thus defining to what all the other values get translated. + Compute black and white end values that don't overlap, i.e. the + black value is darker than the white, from an initial attempt that + might overlap. - This may involve looking at the image. The image is in the file - 'ifp', which is positioned just past the header (at the raster). - Leave it positioned arbitrarily. + 'req{B|W}value' is that initial attempt. We return the + nonoverlapping version as *nonOlap{B|W}valueP. + + '{b|w}IsFixed' means we cannot change that endpoint. + + If both ends are fixed 'reqBvalue' and 'reqWvalue' overlap, we just + fail the program -- the user asked for the impossible. + + Where one end is fixed and the other is not, we move the unfixed end + to be one unit above or below the fixed end, as appropriate. + + Where both ends are free, we move them to the point halfway between them, + the white end being one more than the black end. +-----------------------------------------------------------------------------*/ + assert(maxval > 0); + + if (reqBvalue < reqWvalue) { + /* No overlap; initial attempt is fine. */ + *nonOlapBvalueP = reqBvalue; + *nonOlapWvalueP = reqWvalue; + } else { + if (bIsFixed && wIsFixed) + pm_error("The colors which become black (value <= %u) " + "would overlap the " + "colors which become white (value >= %u).", + reqBvalue, reqWvalue); + else if (bIsFixed) { + if (reqBvalue >= maxval) + pm_error("The black value must be less than the maxval"); + else { + *nonOlapBvalueP = reqBvalue; + *nonOlapWvalueP = reqBvalue + 1; + } + } else if (wIsFixed) { + if (reqWvalue == 0) + pm_error("The white value must be greater than 0"); + else { + *nonOlapBvalueP = reqWvalue - 1; + *nonOlapWvalueP = reqWvalue; + } + } else { + /* Both ends are free; use the point halfway between them. */ + xelval const midPoint = (reqWvalue + reqBvalue + maxval/2)/2; + *nonOlapBvalueP = MIN(midPoint, maxval-1); + *nonOlapWvalueP = *nonOlapBvalueP + 1; + } + } +} + + + +static void +resolvePercentParams(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + struct cmdlineInfo const cmdline, + xelval * const bvalueP, + xelval * const wvalueP) { +/*---------------------------------------------------------------------------- + Figure out the endpoint of the stretch (the value that is to be stretched + to black and the one that is to be stretched to white) as requested + by the -bvalue, -bpercent, -wvalue, and -wpercent options. + + These values may be invalid due to overlapping, and they may exceed + the maximum allowed stretch; Caller must deal with that. -----------------------------------------------------------------------------*/ unsigned int * hist; /* malloc'ed */ @@ -377,45 +442,71 @@ computeEndValues(FILE * const ifp, if (hist == NULL) pm_error("Unable to allocate storage for intensity histogram."); else { - xelval unlimitedBvalue, unlimitedWvalue; - unsigned int bLower, wRaise; - - buildHistogram(ifp, cols, rows, maxval, format, hist, + buildHistogram(ifP, cols, rows, maxval, format, hist, cmdline.brightMethod); if (cmdline.bvalueSpec && !cmdline.bpercentSpec) { - unlimitedBvalue = cmdline.bvalue; + *bvalueP = cmdline.bvalue; } else { xelval percentBvalue; computeBottomPercentile(hist, maxval, cols*rows, cmdline.bpercent, &percentBvalue); if (cmdline.bvalueSpec) - unlimitedBvalue = MIN(percentBvalue, cmdline.bvalue); + *bvalueP = MIN(percentBvalue, cmdline.bvalue); else - unlimitedBvalue = percentBvalue; + *bvalueP = percentBvalue; } if (cmdline.wvalueSpec && !cmdline.wpercentSpec) { - unlimitedWvalue = cmdline.wvalue; + *wvalueP = cmdline.wvalue; } else { xelval percentWvalue; computeTopPercentile(hist, maxval, cols*rows, cmdline.wpercent, &percentWvalue); if (cmdline.wvalueSpec) - unlimitedWvalue = MAX(percentWvalue, cmdline.wvalue); + *wvalueP = MAX(percentWvalue, cmdline.wvalue); else - unlimitedWvalue = percentWvalue; + *wvalueP = percentWvalue; } + free(hist); + } +} - computeAdjustmentForExpansionLimit( - maxval, unlimitedBvalue, unlimitedWvalue, cmdline.maxExpansion, - &bLower, &wRaise); - *bvalueP = unlimitedBvalue - bLower; - *wvalueP = unlimitedWvalue + wRaise; - free(hist); - } +static void +computeEndValues(FILE * const ifP, + int const cols, + int const rows, + xelval const maxval, + int const format, + struct cmdlineInfo const cmdline, + xelval * const bvalueP, + xelval * const wvalueP) { +/*---------------------------------------------------------------------------- + Figure out what original values will be translated to full white and + full black -- thus defining to what all the other values get translated. + + This may involve looking at the image. The image is in the file + 'ifp', which is positioned just past the header (at the raster). + Leave it positioned arbitrarily. +-----------------------------------------------------------------------------*/ + xelval reqBvalue, reqWvalue, nonOlapBvalue, nonOlapWvalue; + unsigned int bLower, wRaise; + + resolvePercentParams(ifP, cols, rows, maxval, format, cmdline, + &reqBvalue, &reqWvalue); + + disOverlap(reqBvalue, reqWvalue, + cmdline.bvalueSpec, cmdline.wvalueSpec, maxval, + &nonOlapBvalue, &nonOlapWvalue); + + computeAdjustmentForExpansionLimit( + maxval, nonOlapBvalue, nonOlapWvalue, cmdline.maxExpansion, + &bLower, &wRaise); + + *bvalueP = nonOlapBvalue - bLower; + *wvalueP = nonOlapWvalue + wRaise; } @@ -545,9 +636,9 @@ writeRowNormalized(xel * const xelrow, float const scaler = brightScaler(p, maxval, newBrightness, brightMethod); - xelval const r = MIN((int)(PPM_GETR(p)*scaler+0.5), maxval); - xelval const g = MIN((int)(PPM_GETG(p)*scaler+0.5), maxval); - xelval const b = MIN((int)(PPM_GETB(p)*scaler+0.5), maxval); + xelval const r = MIN(ROUNDU(PPM_GETR(p)*scaler), maxval); + xelval const g = MIN(ROUNDU(PPM_GETG(p)*scaler), maxval); + xelval const b = MIN(ROUNDU(PPM_GETB(p)*scaler), maxval); PNM_ASSIGN(outrow[col], r, g, b); } else PNM_ASSIGN(outrow[col], @@ -563,7 +654,7 @@ writeRowNormalized(xel * const xelrow, int -main(int argc, char *argv[]) { +main(int argc, const char *argv[]) { struct cmdlineInfo cmdline; FILE *ifP; @@ -572,7 +663,7 @@ main(int argc, char *argv[]) { int rows, cols, format; xelval bvalue, wvalue; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -584,19 +675,17 @@ main(int argc, char *argv[]) { computeEndValues(ifP, cols, rows, maxval, format, cmdline, &bvalue, &wvalue); - - if (wvalue <= bvalue) - pm_error("The colors which become black would overlap the " - "colors which become white."); - else { + { xelval * newBrightness; int row; xel * xelrow; xel * rowbuf; + assert(wvalue > bvalue); + xelrow = pnm_allocrow(cols); - pm_message("remapping %d..%d to %d..%d", bvalue, wvalue, 0, maxval); + pm_message("remapping %u..%u to %u..%u", bvalue, wvalue, 0, maxval); computeTransferFunction(bvalue, wvalue, maxval, &newBrightness); @@ -614,7 +703,7 @@ main(int argc, char *argv[]) { free(newBrightness); pnm_freerow(rowbuf); pnm_freerow(xelrow); - } - pm_close(ifP); + } + pm_close(ifP); return 0; } |