diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/Makefile | 2 | ||||
-rw-r--r-- | editor/pamcomp.c | 118 | ||||
-rw-r--r-- | editor/pamflip/flip.h | 2 | ||||
-rw-r--r-- | editor/pamflip/pamflip.c | 222 | ||||
-rw-r--r-- | editor/pamflip/pamflip_sse.c | 44 | ||||
-rw-r--r-- | editor/pamflip/pamflip_sse.h | 2 | ||||
-rw-r--r-- | editor/pamlevels.c | 515 | ||||
-rw-r--r-- | editor/pamrecolor.c | 2 | ||||
-rw-r--r-- | editor/pamscale.c | 314 | ||||
-rw-r--r-- | editor/pbmclean.c | 55 | ||||
-rw-r--r-- | editor/pbmmask.c | 394 | ||||
-rw-r--r-- | editor/pnmremap.c | 8 | ||||
-rw-r--r-- | editor/specialty/pammixinterlace.c | 61 |
13 files changed, 1187 insertions, 552 deletions
diff --git a/editor/Makefile b/editor/Makefile index 39329f00..d7d71bf6 100644 --- a/editor/Makefile +++ b/editor/Makefile @@ -19,7 +19,7 @@ SUBDIRS = pamflip specialty PORTBINARIES = pamaddnoise pambackground pamcomp pamcut \ pamdice pamditherbw pamedge \ pamenlarge \ - pamfunc pammasksharpen \ + pamfunc pamlevels pammasksharpen \ pamperspective pamrecolor pamrubber \ pamscale pamsistoaglyph pamstretch pamthreshold pamundice \ pamwipeout \ diff --git a/editor/pamcomp.c b/editor/pamcomp.c index 332acac3..0732b92f 100644 --- a/editor/pamcomp.c +++ b/editor/pamcomp.c @@ -6,13 +6,13 @@ This program is derived from (and replaces) Pnmcomp, whose origin is as follows: - Copyright 1992, David Koblas. - Permission to use, copy, modify, and distribute this software + Copyright 1992, David Koblas. + 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. + 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. No code from the original remains in the present version. The January 2004 version was coded entirely by Bryan Henderson. @@ -40,11 +40,11 @@ enum vertPos {ABOVE, TOP, MIDDLE, BOTTOM, BELOW}; enum sampleScale {INTENSITY_SAMPLE, GAMMA_SAMPLE}; /* This indicates a scale for a PAM sample value. INTENSITY_SAMPLE means - the value is proportional to light intensity; GAMMA_SAMPLE means the + the value is proportional to light intensity; GAMMA_SAMPLE means the value is gamma-adjusted as defined in the PGM/PPM spec. In both scales, the values are continuous and normalized to the range 0..1. - - This scale has no meaning if the PAM is not a visual image. + + This scale has no meaning if the PAM is not a visual image. */ enum alphaMix {AM_KEEPUNDER, AM_OVERLAY}; @@ -84,12 +84,12 @@ struct cmdlineInfo { static void -parseCommandLine(int argc, +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. + and argv. Return the information in the options as *cmdlineP. If command line is internally inconsistent (invalid options, etc.), issue error message to stderr and abort program. @@ -111,11 +111,11 @@ parseCommandLine(int argc, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "invert", OPT_FLAG, NULL, + OPTENT3(0, "invert", OPT_FLAG, NULL, &cmdlineP->alphaInvert, 0); - OPTENT3(0, "xoff", OPT_INT, &cmdlineP->xoff, + OPTENT3(0, "xoff", OPT_INT, &cmdlineP->xoff, &xoffSpec, 0); - OPTENT3(0, "yoff", OPT_INT, &cmdlineP->yoff, + OPTENT3(0, "yoff", OPT_INT, &cmdlineP->yoff, &yoffSpec, 0); OPTENT3(0, "opacity", OPT_FLOAT, &cmdlineP->opacity, &opacitySpec, 0); @@ -125,9 +125,9 @@ parseCommandLine(int argc, &alignSpec, 0); OPTENT3(0, "valign", OPT_STRING, &valign, &valignSpec, 0); - OPTENT3(0, "linear", OPT_FLAG, NULL, + OPTENT3(0, "linear", OPT_FLAG, NULL, &cmdlineP->linear, 0); - OPTENT3(0, "mixtransparency", OPT_FLAG, NULL, + OPTENT3(0, "mixtransparency", OPT_FLAG, NULL, &cmdlineP->mixtransparency, 0); opt.opt_table = option_def; @@ -158,9 +158,9 @@ parseCommandLine(int argc, cmdlineP->align = BEYONDRIGHT; else pm_error("Invalid value for align option: '%s'. Only LEFT, " - "RIGHT, CENTER, BEYONDLEFT, and BEYONDRIGHT are valid.", + "RIGHT, CENTER, BEYONDLEFT, and BEYONDRIGHT are valid.", align); - } else + } else cmdlineP->align = LEFT; if (valignSpec) { @@ -176,12 +176,12 @@ parseCommandLine(int argc, cmdlineP->valign = BELOW; else pm_error("Invalid value for valign option: '%s'. Only TOP, " - "BOTTOM, MIDDLE, ABOVE, and BELOW are valid.", + "BOTTOM, MIDDLE, ABOVE, and BELOW are valid.", align); - } else + } else cmdlineP->valign = TOP; - if (!opacitySpec) + if (!opacitySpec) cmdlineP->opacity = 1.0; if (argc-1 < 1) @@ -219,7 +219,7 @@ commonFormat(int const formatA, int const typeA = PAM_FORMAT_TYPE(formatA); int const typeB = PAM_FORMAT_TYPE(formatB); - + if (typeA == PAM_TYPE || typeB == PAM_TYPE) retval = PAM_FORMAT; else if (typeA == PPM_TYPE || typeB == PPM_TYPE) @@ -242,7 +242,7 @@ typedef enum { TT_BLACKANDWHITE, TT_GRAYSCALE, TT_RGB } BaseTupletype; static BaseTupletype -commonTupletype(const char * const tupletypeA, +commonTupletype(const char * const tupletypeA, const char * const tupletypeB) { if (strneq(tupletypeA, "RGB", 3) || @@ -300,11 +300,11 @@ determineOutputType(const struct pam * const underlayPamP, composedPamP->height = underlayPamP->height; composedPamP->width = underlayPamP->width; - composedPamP->format = commonFormat(underlayPamP->format, + composedPamP->format = commonFormat(underlayPamP->format, overlayPamP->format); composedPamP->plainformat = FALSE; - composedPamP->maxval = pm_lcm(underlayPamP->maxval, overlayPamP->maxval, + composedPamP->maxval = pm_lcm(underlayPamP->maxval, overlayPamP->maxval, 1, PNM_OVERALLMAXVAL); composedPamP->visual = true; @@ -325,7 +325,7 @@ determineOutputType(const struct pam * const underlayPamP, static void warnOutOfFrame(int const originLeft, - int const originTop, + int const originTop, int const overCols, int const overRows, int const underCols, @@ -362,7 +362,7 @@ warnOutOfFrame(int const originLeft, static void -validateComputableHeight(int const originTop, +validateComputableHeight(int const originTop, int const overRows) { if (originTop < 0) { @@ -381,11 +381,11 @@ validateComputableHeight(int const originTop, static void -computeOverlayPosition(int const underCols, +computeOverlayPosition(int const underCols, int const underRows, - int const overCols, + int const overCols, int const overRows, - struct cmdlineInfo const cmdline, + struct cmdlineInfo const cmdline, int * const originLeftP, int * const originTopP) { /*---------------------------------------------------------------------------- @@ -421,8 +421,8 @@ computeOverlayPosition(int const underCols, validateComputableHeight(*originTopP, overRows); - warnOutOfFrame(*originLeftP, *originTopP, - overCols, overRows, underCols, underRows); + warnOutOfFrame(*originLeftP, *originTopP, + overCols, overRows, underCols, underRows); } @@ -484,7 +484,7 @@ computeOverlayPosition(int const underCols, static sample -composeComponents(sample const compA, +composeComponents(sample const compA, sample const compB, float const distrib, float const bFactor, @@ -508,7 +508,7 @@ composeComponents(sample const compA, useful. The inputs and result are based on a maxval of 'maxval'. - + Note that while 'distrib' in the straightforward case is always in [0,1], it can in fact be negative or greater than 1. We clip the result as required to return a legal sample value. @@ -520,7 +520,7 @@ composeComponents(sample const compA, retval = compA; else { if (sampleScale == INTENSITY_SAMPLE) { - sample const mix = + sample const mix = ROUNDU(compA * distrib + compB * bFactor *(1.0 - distrib)); retval = MIN(maxval, MAX(0, mix)); } else { @@ -529,7 +529,7 @@ composeComponents(sample const compA, float const compALinear = pm_ungamma709(compANormalized); float const compBLinear = pm_ungamma709(compBNormalized); float const compBLinearAdj = compBLinear * bFactor; - float const mix = + float const mix = compALinear * distrib + compBLinearAdj * (1.0 - distrib) * composedFactor; sample const sampleValue = ROUNDU(pm_gamma709(mix) * maxval); @@ -624,13 +624,13 @@ overlayPixel(tuple const overlayTuple, /* Part of formula for AM_OVERLAY -- see explanation above */ overlayWeight = masterOpacity; /* initial value */ - + if (overlayPamP->have_opacity) overlayWeight *= (float) overlayTuple[overlayPamP->opacity_plane] / overlayPamP->maxval; - + if (alphaTuplen) { - float const alphaval = + float const alphaval = invertAlpha ? (1.0 - alphaTuplen[0]) : alphaTuplen[0]; overlayWeight *= alphaval; } @@ -645,7 +645,7 @@ overlayPixel(tuple const overlayTuple, float const uOpacityN = uOpacity / uMaxval; float const oOpacityN = oOpacity / oMaxval; float const composedTrans = (1.0 - uOpacityN) * (1.0 * oOpacityN); - + if (composedTrans > .999) { underlayWeight = 1.0; composedWeight = 1.0; @@ -659,10 +659,10 @@ overlayPixel(tuple const overlayTuple, } { unsigned int plane; - + for (plane = 0; plane < composedPamP->color_depth; ++plane) - composedTuple[plane] = - composeComponents(overlayTuple[plane], underlayTuple[plane], + composedTuple[plane] = + composeComponents(overlayTuple[plane], underlayTuple[plane], overlayWeight, underlayWeight, composedWeight, composedPamP->maxval, @@ -707,7 +707,7 @@ adaptRowFormat(struct pam * const inpamP, static void -composeRow(int const originleft, +composeRow(int const originleft, struct pam * const underlayPamP, struct pam * const overlayPamP, bool const invertAlpha, @@ -732,7 +732,7 @@ composeRow(int const originleft, int const ovlcol = col - originleft; if (ovlcol >= 0 && ovlcol < overlayPamP->width) { - tuplen const alphaTuplen = + tuplen const alphaTuplen = alphaTuplerown ? alphaTuplerown[ovlcol] : NULL; overlayPixel(overlayTuplerow[ovlcol], overlayPamP, @@ -799,8 +799,8 @@ determineInputAdaptations(const struct pam * const underlayPamP, static void -composite(int const originleft, - int const origintop, +composite(int const originleft, + int const origintop, struct pam * const underlayPamP, struct pam * const overlayPamP, struct pam * const alphaPamP, @@ -829,7 +829,7 @@ composite(int const originleft, We assume that the span from the topmost row of the two images to the bottommost row is less than INT_MAX. -----------------------------------------------------------------------------*/ - enum sampleScale const sampleScale = + enum sampleScale const sampleScale = assumeLinear ? INTENSITY_SAMPLE : GAMMA_SAMPLE; enum alphaMix const alphaMix = mixTransparency ? AM_OVERLAY : AM_KEEPUNDER; @@ -859,7 +859,7 @@ composite(int const originleft, assert(INT_MAX - overlayPamP->height > origintop); /* arg constraint */ for (underlayRow = MIN(0, origintop), overlayRow = MIN(0, -origintop); - underlayRow < MAX(underlayPamP->height, + underlayRow < MAX(underlayPamP->height, origintop + overlayPamP->height); ++underlayRow, ++overlayRow) { @@ -872,19 +872,19 @@ composite(int const originleft, if (underlayRow >= 0 && underlayRow < underlayPamP->height) { pnm_readpamrow(underlayPamP, underlayTuplerow); adaptRowFormat(underlayPamP, &adaptUnderlayPam, underlayTuplerow); - if (underlayRow < origintop || + if (underlayRow < origintop || underlayRow >= origintop + overlayPamP->height) { - + /* Overlay image does not touch this underlay row. */ pnm_writepamrow(composedPamP, underlayTuplerow); } else { composeRow(originleft, &adaptUnderlayPam, &adaptOverlayPam, - invertAlpha, masterOpacity, + invertAlpha, masterOpacity, composedPamP, sampleScale, alphaMix, underlayTuplerow, overlayTuplerow, alphaTuplerown, composedTuplerow); - + pnm_writepamrow(composedPamP, composedTuplerow); } } @@ -905,13 +905,13 @@ initAlphaFile(struct cmdlineInfo const cmdline, struct pam * const pamP) { FILE * fileP; - + if (cmdline.alphaFilespec) { fileP = pm_openr(cmdline.alphaFilespec); pamP->comment_p = NULL; pnm_readpaminit(fileP, pamP, PAM_STRUCT_SIZE(opacity_plane)); - if (overlayPamP->width != pamP->width || + if (overlayPamP->width != pamP->width || overlayPamP->height != pamP->height) pm_error("Opacity map and overlay image are not the same size"); } else @@ -942,7 +942,7 @@ main(int argc, const char *argv[]) { overlayFileP = pm_openr(cmdline.overlayFilespec); overlayPam.comment_p = NULL; - pnm_readpaminit(overlayFileP, &overlayPam, + pnm_readpaminit(overlayFileP, &overlayPam, PAM_STRUCT_SIZE(opacity_plane)); if (overlayPam.len < PAM_STRUCT_SIZE(opacity_plane)) @@ -959,7 +959,7 @@ main(int argc, const char *argv[]) { underlayFileP = pm_openr(cmdline.underlyingFilespec); underlayPam.comment_p = NULL; - pnm_readpaminit(underlayFileP, &underlayPam, + pnm_readpaminit(underlayFileP, &underlayPam, PAM_STRUCT_SIZE(opacity_plane)); assert(underlayPam.len >= PAM_STRUCT_SIZE(opacity_plane)); @@ -968,8 +968,8 @@ main(int argc, const char *argv[]) { pm_error("Overlay image has tuple type '%s', which is not a " "standard visual type. We don't know how to compose.", overlayPam.tuple_type); - - computeOverlayPosition(underlayPam.width, underlayPam.height, + + computeOverlayPosition(underlayPam.width, underlayPam.height, overlayPam.width, overlayPam.height, cmdline, &originLeft, &originTop); @@ -983,7 +983,7 @@ main(int argc, const char *argv[]) { pnm_setminallocationdepth(&underlayPam, composedPam.depth); pnm_setminallocationdepth(&overlayPam, composedPam.depth); - + composite(originLeft, originTop, &underlayPam, &overlayPam, alphaFileP ? &alphaPam : NULL, cmdline.alphaInvert, cmdline.opacity, diff --git a/editor/pamflip/flip.h b/editor/pamflip/flip.h index 612a7f84..ace93044 100644 --- a/editor/pamflip/flip.h +++ b/editor/pamflip/flip.h @@ -1,7 +1,7 @@ #ifndef FLIP_H_INCLUDED #define FLIP_H_INCLUDED -struct xformCore { +struct XformCore { /* a b c d */ diff --git a/editor/pamflip/pamflip.c b/editor/pamflip/pamflip.c index e6f1d6ed..bc752208 100644 --- a/editor/pamflip/pamflip.c +++ b/editor/pamflip/pamflip.c @@ -13,9 +13,9 @@ /* transformNonPbmChunk() is the general transformation function. It can transform anything, albeit slowly and expensively. - + The following are enhancements for specific cases: - + transformRowByRowPbm(): PBM image with left-right or null transformation transformRowsBottomTopPbm() @@ -77,12 +77,12 @@ #include "flip.h" #include "pamflip_sse.h" -enum xformType {LEFTRIGHT, TOPBOTTOM, TRANSPOSE}; +enum XformType {LEFTRIGHT, TOPBOTTOM, TRANSPOSE}; static void parseXformOpt(const char * const xformOpt, unsigned int * const xformCountP, - enum xformType * const xformList) { + enum XformType * const xformList) { /*---------------------------------------------------------------------------- Translate the -xform option string into an array of transform types. @@ -93,10 +93,10 @@ parseXformOpt(const char * const xformOpt, char * xformOptWork; char * cursor; bool eol; - + xformOptWork = strdup(xformOpt); cursor = &xformOptWork[0]; - + eol = FALSE; /* initial value */ xformCount = 0; /* initial value */ while (!eol && xformCount < 10) { @@ -125,13 +125,13 @@ parseXformOpt(const char * const xformOpt, /* See transformPoint() for an explanation of the transform matrix types. The - difference between xformCore and xformMatrix is that 'xformCore' is + difference between XformCore and XformMatrix is that 'XformCore' is particular to the source image dimensions and can be used to do the - transformation, while 'xformCore' is independent of the source image and + transformation, while 'XformCore' is independent of the source image and just tells what kind of transformation. */ -struct xformMatrix { +struct XformMatrix { /* a b 0 c d 0 e f 1 @@ -147,7 +147,7 @@ struct xformMatrix { static void -leftright(struct xformCore * const xformP) { +leftright(struct XformCore * const xformP) { xformP->a = - xformP->a; xformP->c = - xformP->c; } @@ -155,7 +155,7 @@ leftright(struct xformCore * const xformP) { static void -topbottom(struct xformCore * const xformP) { +topbottom(struct XformCore * const xformP) { xformP->b = - xformP->b; xformP->d = - xformP->d; } @@ -174,7 +174,7 @@ swap(int * const xP, int * const yP) { static void -transpose(struct xformCore * const xformP) { +transpose(struct XformCore * const xformP) { swap(&xformP->a, &xformP->b); swap(&xformP->c, &xformP->d); } @@ -183,18 +183,18 @@ transpose(struct xformCore * const xformP) { static void computeXformCore(unsigned int const xformCount, - enum xformType const xformType[], - struct xformCore * const xformP) { - - struct xformCore const nullTransform = {1, 0, 0, 1}; + enum XformType const XformType[], + struct XformCore * const xformP) { + + struct XformCore const nullTransform = {1, 0, 0, 1}; unsigned int i; *xformP = nullTransform; /* initial value */ for (i = 0; i < xformCount; ++i) { - switch (xformType[i]) { - case LEFTRIGHT: + switch (XformType[i]) { + case LEFTRIGHT: leftright(xformP); break; case TOPBOTTOM: @@ -210,7 +210,7 @@ computeXformCore(unsigned int const xformCount, static void -xformDimensions(struct xformCore const xform, +xformDimensions(struct XformCore const xform, unsigned int const inCols, unsigned int const inRows, unsigned int * const outColsP, @@ -222,25 +222,25 @@ xformDimensions(struct xformCore const xform, E.g. if it's a 90 degree rotation of a 10 x 20 image, the output is a 20 x 10 image. -----------------------------------------------------------------------------*/ - *outColsP = abs(xform.a * inCols + xform.c * inRows); - *outRowsP = abs(xform.b * inCols + xform.d * inRows); + *outColsP = abs(xform.a * (int)inCols + xform.c * (int)inRows); + *outRowsP = abs(xform.b * (int)inCols + xform.d * (int)inRows); } static void -computeXformMatrix(struct xformMatrix * const xformP, +computeXformMatrix(struct XformMatrix * const xformP, unsigned int const sourceCols, unsigned int const sourceRows, - struct xformCore const xformCore) { + struct XformCore const XformCore) { - int colMax = xformCore.a * (sourceCols-1) + xformCore.c * (sourceRows-1); - int rowMax = xformCore.b * (sourceCols-1) + xformCore.d * (sourceRows-1); + int colMax = XformCore.a * (sourceCols-1) + XformCore.c * (sourceRows-1); + int rowMax = XformCore.b * (sourceCols-1) + XformCore.d * (sourceRows-1); - xformP->a = xformCore.a; - xformP->b = xformCore.b; - xformP->c = xformCore.c; - xformP->d = xformCore.d; + xformP->a = XformCore.a; + xformP->b = XformCore.b; + xformP->c = XformCore.c; + xformP->d = XformCore.d; xformP->e = colMax < 0 ? -colMax : 0; xformP->f = rowMax < 0 ? -rowMax : 0; } @@ -252,7 +252,7 @@ struct cmdlineInfo { in a form easy for the program to use. */ const char * inputFilespec; /* Filespec of input file */ - struct xformCore xform; + struct XformCore xform; /* Handy mathematical representation of all of transform options */ size_t availableMemory; unsigned int pageSize; @@ -272,7 +272,7 @@ interpretMemorySize(unsigned int const memsizeSpec, if (memsizeSpec) { if (memsizeOpt > sizeMax / Meg) pm_error("-memsize value too large: %u MiB. Maximum this program " - "can handle is %u MiB", + "can handle is %u MiB", memsizeOpt, (unsigned)sizeMax / Meg); *availableMemoryP = memsizeOpt * Meg; } else @@ -300,8 +300,8 @@ parseCommandLine(int argc, char ** const argv, unsigned int memsizeOpt; const char * xformOpt; unsigned int xformCount; - /* Number of transforms in the 'xformType' array */ - enum xformType xformList[10]; + /* Number of transforms in the 'XformType' array */ + enum XformType xformList[10]; /* Array of transforms to be applied, in order */ MALLOCARRAY(option_def, 100); @@ -323,11 +323,11 @@ parseCommandLine(int argc, char ** const argv, OPTENT3(0, "cw", OPT_FLAG, NULL, &r270, 0); OPTENT3(0, "null", OPT_FLAG, NULL, &null, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - OPTENT3(0, "memsize", OPT_UINT, &memsizeOpt, + OPTENT3(0, "memsize", OPT_UINT, &memsizeOpt, &memsizeSpec, 0); OPTENT3(0, "pagesize", OPT_UINT, &cmdlineP->pageSize, &pagesizeSpec, 0); - OPTENT3(0, "xform", OPT_STRING, &xformOpt, + OPTENT3(0, "xform", OPT_STRING, &xformOpt, &xformSpec, 0); opt.opt_table = option_def; @@ -364,20 +364,20 @@ parseCommandLine(int argc, char ** const argv, } else if (null) { xformCount = 0; } - } else if (xformSpec) + } else if (xformSpec) parseXformOpt(xformOpt, &xformCount, xformList); else pm_error("You must specify an option such as -topbottom to indicate " "what kind of flip you want."); computeXformCore(xformCount, xformList, &cmdlineP->xform); - + interpretMemorySize(memsizeSpec, memsizeOpt, &cmdlineP->availableMemory); if (!pagesizeSpec) - cmdlineP->pageSize = 4*1024; + cmdlineP->pageSize = 4*1024; - if (argc-1 == 0) + if (argc-1 == 0) cmdlineP->inputFilespec = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " @@ -391,7 +391,7 @@ parseCommandLine(int argc, char ** const argv, static void -bitOrderReverse(unsigned char * const bitrow, +bitOrderReverse(unsigned char * const bitrow, unsigned int const cols) { /*---------------------------------------------------------------------------- Reverse the bits in a packed pbm row (1 bit per pixel). I.e. the leftmost @@ -413,12 +413,12 @@ bitOrderReverse(unsigned char * const bitrow, if ((bitrow[j] | bitrow[i]) == 0) { /* Both are 0x00 - skip */ } else { - unsigned char const t = bitreverse[bitrow[j]]; + unsigned char const t = bitreverse[bitrow[j]]; bitrow[j] = bitreverse[bitrow[i]]; bitrow[i] = t; } } else { - unsigned int const m = cols % 8; + unsigned int const m = cols % 8; unsigned int i, j; /* Cursors into bitrow[]. i moves from left to center; @@ -431,7 +431,7 @@ bitOrderReverse(unsigned char * const bitrow, /* Skip if both are 0x00 */ th = bitreverse[bitrow[i]]; bitrow[i] = - bitreverse[0xff & ((bitrow[j-1] << 8 + bitreverse[0xff & ((bitrow[j-1] << 8 | bitrow[j]) >> (8-m))]; bitrow[j] = 0xff & ((th << 8 | tl) >> m); tl = th; @@ -450,7 +450,7 @@ bitOrderReverse(unsigned char * const bitrow, static void -transformRowByRowPbm(struct pam * const inpamP, +transformRowByRowPbm(struct pam * const inpamP, struct pam * const outpamP, bool const reverse) { /*---------------------------------------------------------------------------- @@ -464,7 +464,7 @@ transformRowByRowPbm(struct pam * const inpamP, unsigned char * bitrow; unsigned int row; - bitrow = pbm_allocrow_packed(outpamP->width); + bitrow = pbm_allocrow_packed(outpamP->width); for (row = 0; row < inpamP->height; ++row) { pbm_readpbmrow_packed(inpamP->file, bitrow, inpamP->width, @@ -481,7 +481,7 @@ transformRowByRowPbm(struct pam * const inpamP, static void -transformRowByRowNonPbm(struct pam * const inpamP, +transformRowByRowNonPbm(struct pam * const inpamP, struct pam * const outpamP, bool const reverse) { /*---------------------------------------------------------------------------- @@ -500,20 +500,20 @@ transformRowByRowNonPbm(struct pam * const inpamP, itself. */ tuple * scratchTuplerow; - + unsigned int row; - + tuplerow = pnm_allocpamrow(inpamP); - + if (reverse) { /* Set up newtuplerow[] to point to the tuples of tuplerow[] in reverse order. */ unsigned int col; - + MALLOCARRAY_NOFAIL(scratchTuplerow, inpamP->width); - for (col = 0; col < inpamP->width; ++col) + for (col = 0; col < inpamP->width; ++col) scratchTuplerow[col] = tuplerow[inpamP->width - col - 1]; newtuplerow = scratchTuplerow; } else { @@ -524,7 +524,7 @@ transformRowByRowNonPbm(struct pam * const inpamP, pnm_readpamrow(inpamP, tuplerow); pnm_writepamrow(outpamP, newtuplerow); } - + if (scratchTuplerow) free(scratchTuplerow); pnm_freepamrow(tuplerow); @@ -535,7 +535,7 @@ transformRowByRowNonPbm(struct pam * const inpamP, static void transformRowsBottomTopPbm(struct pam * const inpamP, struct pam * const outpamP, - bool const reverse) { + bool const reverse) { /*---------------------------------------------------------------------------- Flip a PBM raster top for bottom; read the raster from *inpamP; write the flipped raster to *outpamP. @@ -547,15 +547,15 @@ transformRowsBottomTopPbm(struct pam * const inpamP, unsigned char ** bitrow; unsigned int row; - + bitrow = pbm_allocarray_packed(outpamP->width, outpamP->height); - + for (row = 0; row < rows; ++row) - pbm_readpbmrow_packed(inpamP->file, bitrow[row], + pbm_readpbmrow_packed(inpamP->file, bitrow[row], inpamP->width, inpamP->format); for (row = 0; row < rows; ++row) { - if (reverse) + if (reverse) bitOrderReverse(bitrow[rows-row-1], inpamP->width); pbm_writepbmrow_packed(outpamP->file, bitrow[rows - row - 1], @@ -567,7 +567,7 @@ transformRowsBottomTopPbm(struct pam * const inpamP, static void -transformRowsBottomTopNonPbm(struct pam * const inpamP, +transformRowsBottomTopNonPbm(struct pam * const inpamP, struct pam * const outpamP) { /*---------------------------------------------------------------------------- Do a simple vertical flip. Read the raster from *inpamP; write the @@ -593,17 +593,17 @@ transformRowsBottomTopNonPbm(struct pam * const inpamP, pnm_writepamrow(outpamP, tuplerow); } - + pnm_freepamarray(tuplerows, outpamP); } static void __inline__ -transformPoint(int const col, - int const row, - struct xformMatrix const xform, - unsigned int * const newcolP, +transformPoint(int const col, + int const row, + struct XformMatrix const xform, + unsigned int * const newcolP, unsigned int * const newrowP ) { /*---------------------------------------------------------------------------- Compute the location in the output of a pixel that is at row 'row', @@ -613,7 +613,7 @@ transformPoint(int const col, Return the output image location of the pixel as *newcolP and *newrowP. -----------------------------------------------------------------------------*/ /* The transformation is: - + [ a b 0 ] [ x y 1 ] [ c d 0 ] = [ x2 y2 1 ] [ e f 1 ] @@ -653,9 +653,9 @@ writeRaster(struct pam * const pamP, static void transformPbmGen(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xformCore) { + struct XformCore const XformCore) { /*---------------------------------------------------------------------------- - This is the same as transformGen, except that it uses less + This is the same as transformGen, except that it uses less memory, since the PBM buffer format uses one bit per pixel instead of twelve bytes + pointer space @@ -665,28 +665,28 @@ transformPbmGen(struct pam * const inpamP, -----------------------------------------------------------------------------*/ bit * bitrow; bit ** newbits; - struct xformMatrix xform; + struct XformMatrix xform; unsigned int row; - - computeXformMatrix(&xform, inpamP->width, inpamP->height, xformCore); - + + computeXformMatrix(&xform, inpamP->width, inpamP->height, XformCore); + bitrow = pbm_allocrow_packed(inpamP->width); newbits = pbm_allocarray_packed( outpamP->width, outpamP->height ); - + /* Initialize entire array to zeroes. One bits will be or'ed in later */ for (row = 0; row < outpamP->height; ++row) { unsigned int col; - for (col = 0; col < pbm_packed_bytes(outpamP->width); ++col) - newbits[row][col] = 0; + for (col = 0; col < pbm_packed_bytes(outpamP->width); ++col) + newbits[row][col] = 0; } - + for (row = 0; row < inpamP->height; ++row) { unsigned int col; pbm_readpbmrow_packed(inpamP->file, bitrow, inpamP->width, inpamP->format); for (col = 0; col < inpamP->width; ) { - if (bitrow[col/8] == 0x00) + if (bitrow[col/8] == 0x00) col += 8; /* Blank. Skip to next byte. */ else { /* Examine each pixel. */ unsigned int const colLimit = MIN(col+8, inpamP->width); @@ -695,7 +695,7 @@ transformPbmGen(struct pam * const inpamP, for (i = 0; col < colLimit; ++i, ++col) { bool const bitIsOne = (bitrow[col/8] >> (7-i)) & 0x01; if (bitIsOne) { - /* Write in only the one bits. */ + /* Write in only the one bits. */ unsigned int newcol, newrow; transformPoint(col, row, xform, &newcol, &newrow); newbits[newrow][newcol/8] |= 0x01 << (7 - newcol % 8); @@ -710,7 +710,7 @@ transformPbmGen(struct pam * const inpamP, for (row = 0; row < outpamP->height; ++row) pbm_writepbmrow_packed(outpamP->file, newbits[row], outpamP->width, 0); - + pbm_freearray(newbits, outpamP->height); pbm_freerow(bitrow); } @@ -720,7 +720,7 @@ transformPbmGen(struct pam * const inpamP, static void transformNonPbmWhole(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xformCore, + struct XformCore const XformCore, bool const verbose) { /*---------------------------------------------------------------------------- Do the transform using "pam" library functions, as opposed to "pbm" @@ -738,18 +738,18 @@ transformNonPbmWhole(struct pam * const inpamP, -----------------------------------------------------------------------------*/ tuple * tuplerow; tuple ** newtuples; - struct xformMatrix xform; + struct XformMatrix xform; unsigned int row; - computeXformMatrix(&xform, inpamP->width, inpamP->height, xformCore); - + computeXformMatrix(&xform, inpamP->width, inpamP->height, XformCore); + tuplerow = pnm_allocpamrow(inpamP); newtuples = pnm_allocpamarray(outpamP); - + for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrow(inpamP, tuplerow); - + for (col = 0; col < inpamP->width; ++col) { unsigned int newcol, newrow; @@ -762,9 +762,9 @@ transformNonPbmWhole(struct pam * const inpamP, tuplerow[col]); } } - + writeRaster(outpamP, newtuples); - + pnm_freepamarray(newtuples, outpamP); pnm_freepamrow(tuplerow); } @@ -798,7 +798,7 @@ initOutCell(struct pam * const outCellPamP, unsigned int const inCellWidth, unsigned int const inCellHeight, struct pam * const inpamP, - struct xformCore const xformCore) { + struct XformCore const XformCore) { /*---------------------------------------------------------------------------- Set up an output cell. Create and open a temporary file to hold its raster. Figure out the dimensions of the cell. Return a PAM structure @@ -812,7 +812,7 @@ initOutCell(struct pam * const outCellPamP, outCellPamP->file = pm_tmpfile(); - xformDimensions(xformCore, inCellWidth, inCellHeight, + xformDimensions(XformCore, inCellWidth, inCellHeight, &outCellFileCt, &outCellRankCt); outCellPamP->width = outCellFileCt; @@ -824,8 +824,8 @@ initOutCell(struct pam * const outCellPamP, static outputMap * createOutputMap(struct pam * const inpamP, unsigned int const maxRows, - struct xformMatrix const cellXform, - struct xformCore const xformCore) { + struct XformMatrix const cellXform, + struct XformCore const XformCore) { /*---------------------------------------------------------------------------- Create and return the output map. That's a map of all the output cells (from which the output image can be assembled, once those cells are filled @@ -853,7 +853,7 @@ createOutputMap(struct pam * const inpamP, MALLOCVAR_NOFAIL(mapP); - xformDimensions(xformCore, inCellFileCt, inCellRankCt, + xformDimensions(XformCore, inCellFileCt, inCellRankCt, &mapP->fileCt, &mapP->rankCt); MALLOCARRAY(mapP->pam, mapP->rankCt); @@ -879,14 +879,14 @@ createOutputMap(struct pam * const inpamP, unsigned int outCellFile, outCellRank; transformPoint(inCellFile, inCellRank, cellXform, &outCellFile, &outCellRank); - + initOutCell(&mapP->pam[outCellRank][outCellFile], inpamP->width, inCellRowCt, - inpamP, xformCore); + inpamP, XformCore); } return mapP; } - + static void @@ -935,14 +935,14 @@ closeCellFiles(outputMap * const outputMapP) { static void transformCell(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xformCore) { + struct XformCore const XformCore) { - struct xformMatrix xform; + struct XformMatrix xform; tuple * inTupleRow; tuple ** outTuples; unsigned int inRow; - computeXformMatrix(&xform, inpamP->width, inpamP->height, xformCore); + computeXformMatrix(&xform, inpamP->width, inpamP->height, XformCore); inTupleRow = pnm_allocpamrow(inpamP); @@ -952,7 +952,7 @@ transformCell(struct pam * const inpamP, unsigned int inCol; pnm_readpamrow(inpamP, inTupleRow); - + for (inCol = 0; inCol < inpamP->width; ++inCol) { unsigned int outCol, outRow; @@ -996,7 +996,7 @@ stitchCellsToOutput(outputMap * const outputMapP, outCol = 0; for (outFile = 0; outFile < outputMapP->fileCt; ++outFile) { - struct pam * const outCellPamP = + struct pam * const outCellPamP = &outputMapP->pam[outRank][outFile]; assert(outCellPamP->height == cellRows); @@ -1020,7 +1020,7 @@ stitchCellsToOutput(outputMap * const outputMapP, static void transformNonPbmChunk(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xformCore, + struct XformCore const XformCore, unsigned int const maxRows, bool const verbose) { /*---------------------------------------------------------------------------- @@ -1032,11 +1032,11 @@ transformNonPbmChunk(struct pam * const inpamP, header). We call the strip of 'maxRows' rows that we read a source cell. We - transform that cell according to 'xformCore' to create a + transform that cell according to 'XformCore' to create a target cell. We store all the target cells in temporary files. We consider the target cells to be arranged in a column matrix the same as the source cells within the source image; we transform that - matrix according to 'xformCore'. The resulting cell matrix is the + matrix according to 'XformCore'. The resulting cell matrix is the target image. -----------------------------------------------------------------------------*/ /* The cells of the source image ("inCell") are in a 1-column matrix. @@ -1046,7 +1046,7 @@ transformNonPbmChunk(struct pam * const inpamP, unsigned int const inCellFileCt = 1; unsigned int const inCellRankCt = (inpamP->height + maxRows - 1) / maxRows; - struct xformMatrix cellXform; + struct XformMatrix cellXform; unsigned int inCellRank; outputMap * outputMapP; @@ -1054,9 +1054,9 @@ transformNonPbmChunk(struct pam * const inpamP, pm_message("Transforming in %u chunks, using temp files", inCellRankCt); - computeXformMatrix(&cellXform, inCellFileCt, inCellRankCt, xformCore); + computeXformMatrix(&cellXform, inCellFileCt, inCellRankCt, XformCore); - outputMapP = createOutputMap(inpamP, maxRows, cellXform, xformCore); + outputMapP = createOutputMap(inpamP, maxRows, cellXform, XformCore); for (inCellRank = 0; inCellRank < inCellRankCt; ++inCellRank) { unsigned int const inCellFile = 0; @@ -1070,15 +1070,15 @@ transformNonPbmChunk(struct pam * const inpamP, transformPoint(inCellFile, inCellRank, cellXform, &outCellFile, &outCellRank); - + outCellPamP = &outputMapP->pam[outCellRank][outCellFile]; /* Input cell is just the next 'inCellRows' rows of input image */ inCellPam = *inpamP; inCellPam.height = inCellRows; - transformCell(&inCellPam, outCellPamP, xformCore); - } + transformCell(&inCellPam, outCellPamP, XformCore); + } rewindCellFiles(outputMapP); @@ -1122,7 +1122,7 @@ maxRowsThatFit(struct pam * const pamP, static void transformPbm(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xform, + struct XformCore const xform, bool const verbose) { if (xform.b == 0 && xform.c == 0) { @@ -1155,7 +1155,7 @@ transformPbm(struct pam * const inpamP, static void transformNonPbm(struct pam * const inpamP, struct pam * const outpamP, - struct xformCore const xform, + struct XformCore const xform, unsigned int const availableMemory, bool const verbose) { @@ -1212,7 +1212,7 @@ main(int argc, char * argv[]) { ifP = pm_openr_seekable(cmdline.inputFilespec); else ifP = pm_openr(cmdline.inputFilespec); - + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); outpam = inpam; /* initial value */ @@ -1233,6 +1233,6 @@ main(int argc, char * argv[]) { } pm_close(inpam.file); pm_close(outpam.file); - + return 0; } diff --git a/editor/pamflip/pamflip_sse.c b/editor/pamflip/pamflip_sse.c index e0929f65..c4e51751 100644 --- a/editor/pamflip/pamflip_sse.c +++ b/editor/pamflip/pamflip_sse.c @@ -37,7 +37,7 @@ /*---------------------------------------------------------------------------- This is a specialized routine for row-for-column PBM transformations. - (-cw, -ccw, -xy). It requires GCC (>= v. 4.2.0) and SSE2. + (-cw, -ccw, -xy). It requires GCC (>= v. 4.2.0) and SSE2. In each cycle, we read sixteen rows from the input. We process this band left to right in blocks 8 pixels wide. We use the SSE2 instruction @@ -70,7 +70,7 @@ It is possible to write a non-SSE version by providing a generic version of transpose16Bitrows() or one tuned for a specific architecture. Use 8x8 blocks to avoid endian issues. - + Further enhancement should be possible by employing wider bands, larger blocks as wider SIMD registers become available. Clearing the white parts after instead of before transposition is also a @@ -149,7 +149,7 @@ transpose16Bitrows(unsigned int const cols, register v16qi vReg = { block[0][col8], block[1][col8], - block[2][col8], block[3][col8], + block[2][col8], block[3][col8], block[4][col8], block[5][col8], block[6][col8], block[7][col8], block[8][col8], block[9][col8], @@ -163,14 +163,14 @@ transpose16Bitrows(unsigned int const cols, if (_mm_movemask_epi8(compare) != 0xffff) { /* There is some black content in this block; write to outplane */ - + unsigned int outrow; unsigned int i; outrow = col; /* initial value */ for (i = 0; i < 7; ++i) { - /* GCC (>=4.2) automatically unrolls this loop */ + /* GCC (>=4.2) automatically unrolls this loop */ outplane[outrow++][outcol16] = _mm_movemask_epi8((__m128i)vReg); vReg = (v16qi)_mm_slli_epi32((__m128i)vReg, 1); @@ -197,7 +197,7 @@ analyzeBlock(const struct pam * const inpamP, "twists" brought about by Intel byte ordering which occur when: (1) 16 bytes are loaded to a SSE register (2) 16 bits are written to memory. - + If 'rows' is not a multiple of 8, a partial input band appears at one edge. Set *topOfFullBlockP accordingly. blockPartial[] is an adjusted "block" for this partial band, brought up to a size of 8 rows. The extra pointers point @@ -227,7 +227,7 @@ analyzeBlock(const struct pam * const inpamP, : block[i]; } *topOfFullBlockP = inpamP->height % 16; - + if (inpamP->height >= 16) { *outcol16P = inpamP->height/16 - 1; } else @@ -243,7 +243,7 @@ doPartialBlockTop(const struct pam * const inpamP, const bit * const blockPartial[16], unsigned int const topOfFullBlock, uint16_t ** const outplane) { - + if (topOfFullBlock > 0) { unsigned int colChar, row; unsigned int pad = 16 - topOfFullBlock; @@ -267,7 +267,7 @@ doPartialBlockTop(const struct pam * const inpamP, outplane, inpamP->height /16); /* Transpose partial rows on top of input. Place on right edge of output. - */ + */ } } @@ -303,7 +303,7 @@ doFullBlocks(const struct pam * const inpamP, ++modrow; if (modrow == 16) { /* 16 row buffer is full. Transpose. */ - modrow = 0; + modrow = 0; transpose16Bitrows(inpamP->width, inpamP->height, block, outplane, outcol16); @@ -320,7 +320,7 @@ doPartialBlockBottom(const struct pam * const inpamP, int const xdir, const bit * const blockPartial[16], uint16_t ** const outplane) { - + if (xdir > 0 && inpamP->height % 16 > 0) { unsigned int colChar; @@ -331,7 +331,7 @@ doPartialBlockBottom(const struct pam * const inpamP, outplane, inpamP->height/16); /* Transpose partial rows on bottom of input. Place on right edge of output. - */ + */ } } @@ -341,7 +341,7 @@ static void writeOut(const struct pam * const outpamP, uint16_t ** const outplane, int const ydir) { - + unsigned int row; for (row = 0; row < outpamP->height; ++row) { @@ -357,23 +357,23 @@ writeOut(const struct pam * const outpamP, static void clearOutplane(const struct pam * const outpamP, - uint16_t ** const outplane) { - + uint16_t ** const outplane) { + unsigned int row; - + for (row = 0; row < outpamP->height; ++row) { unsigned int col16; /* column divided by 16 */ for (col16 = 0; col16 < (outpamP->width + 15)/16; ++col16) outplane[row][col16] = 0x0000; } -} +} void pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, const struct pam * const outpamP, - struct xformCore const xformCore) { + struct XformCore const xformCore) { /*---------------------------------------------------------------------------- This is a specialized routine for row-for-column PBM transformations. (-cw, -ccw, -xy). @@ -397,11 +397,11 @@ pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, pm_error("Could not allocate %u x %u array of 16 bit units", blocksPerRow, outpamP->height + 7); - /* We write to the output array in 16 bit units. Add margin. */ + /* We write to the output array in 16 bit units. Add margin. */ clearOutplane(outpamP, outplane); - analyzeBlock(inpamP, inrow, xdir, block, blockPartial, + analyzeBlock(inpamP, inrow, xdir, block, blockPartial, &topOfFullBlock, &outcol16); doPartialBlockTop(inpamP, inrow, blockPartial, topOfFullBlock, outplane); @@ -421,9 +421,9 @@ pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, void pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, const struct pam * const outpamP, - struct xformCore const xformCore) { + struct XformCore const xformCore) { /* Nobody is supposed to call this */ assert(false); } -#endif +#endif diff --git a/editor/pamflip/pamflip_sse.h b/editor/pamflip/pamflip_sse.h index 59e7c026..cd1267b7 100644 --- a/editor/pamflip/pamflip_sse.h +++ b/editor/pamflip/pamflip_sse.h @@ -7,6 +7,6 @@ struct pam; void pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, const struct pam * const outpamP, - struct xformCore const xformCore); + struct XformCore const xformCore); #endif diff --git a/editor/pamlevels.c b/editor/pamlevels.c new file mode 100644 index 00000000..fbbb2c0b --- /dev/null +++ b/editor/pamlevels.c @@ -0,0 +1,515 @@ +#include <stdbool.h> +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "netpbm/pam.h" +#include "netpbm/pm_system.h" +#include "netpbm/pm_gamma.h" +#include "netpbm/nstring.h" +#include "netpbm/ppm.h" + +#include "shhopt.h" +#include "mallocvar.h" + +/* ----------------------------- Type aliases ------------------------------ */ + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef struct pam pam; + +typedef struct { +/*---------------------------------------------------------------------------- + An RGB triple, in linear intensity or linear brightness; user's choice. +-----------------------------------------------------------------------------*/ + double _[3]; +} Rgb; + +typedef struct { +/*---------------------------------------------------------------------------- + A quadratic polynomial +-----------------------------------------------------------------------------*/ + double coeff[3]; +} Polynomial; + +typedef struct { +/*---------------------------------------------------------------------------- + A set of source or target sample values, in some plane. + + These are either intensity-linear or brightness-linear; user's choice. + + There could be two or three values; user must know which. +-----------------------------------------------------------------------------*/ + double _[3]; +} SampleSet; + +/* ------------------------- Parse transformations ------------------------- */ + +typedef struct { +/*---------------------------------------------------------------------------- + A mapping of one source color to one target color, encoded in linear RGB +-----------------------------------------------------------------------------*/ + tuplen from; + tuplen to; +} Trans; + +typedef struct { + const char * from; /* color specifications */ + const char * to; /* as they appear on commandline */ + unsigned int hasFrom; /* "from" part is present */ + unsigned int hasTo; /* "to" part is present */ + char nameFromS[3]; /* short option name */ + char nameToS [3]; + char nameFromL[6]; /* long option name */ + char nameToL [6]; +} TransArg; + +typedef struct { + TransArg _[3]; +} TransArgSet; + +typedef struct { + unsigned int n; + /* Number of elements in 't', 2 for linear transformation; 3 for + quadratic. + */ + Trans t[3]; +} TransSet; + +typedef struct { + unsigned int linear; + unsigned int fitbrightness; + TransSet xlats; /* color mappings (-from1, -to1, etc.) */ + const char * inputFileName; /* the input file name, "-" for stdin */ +} CmdlineInfo; + + + +static void +optAddTrans (optEntry * const option_def, + unsigned int * const option_def_indexP, + TransArg * const xP, + char const index) { + + char indexc; + uint option_def_index; + + option_def_index = *option_def_indexP; + + indexc = '0' + index; + + STRSCPY(xP->nameFromL, "from "); xP->nameFromL[4] = indexc; + STRSCPY(xP->nameToL, "to " ); xP->nameToL [2] = indexc; + STRSCPY(xP->nameFromS, "f " ); xP->nameFromS[1] = indexc; + STRSCPY(xP->nameToS, "t " ); xP->nameToS [1] = indexc; + + OPTENT3(0, xP->nameFromL, OPT_STRING, &xP->from, &xP->hasFrom, 0); + OPTENT3(0, xP->nameFromS, OPT_STRING, &xP->from, &xP->hasFrom, 0); + OPTENT3(0, xP->nameToL, OPT_STRING, &xP->to, &xP->hasTo, 0); + OPTENT3(0, xP->nameToS, OPT_STRING, &xP->to, &xP->hasTo, 0); + + *option_def_indexP = option_def_index; +} + + + +static void +parseColor(const char * const text, + tuplen * const colorP) { +/*---------------------------------------------------------------------------- + Parses color secification in <text>, converts it into linear RGB, + and stores the result in <colorP>. +-----------------------------------------------------------------------------*/ + const char * const lastsc = strrchr(text, ':'); + + const char * colorname; + double mul; + tuplen unmultipliedColor; + tuplen color; + + if (lastsc) { + /* Specification contains a colon. It might be the colon that + introduces the optional multiplier, or it might just be the colon + after the type specifier, e.g. "rgbi:...". + */ + + if (strstr(text, "rgb") == text && strchr(text, ':') == lastsc) { + /* The only colon present is the one on the type specifier. + So there is no multiplier. + */ + mul = 1.0; + colorname = pm_strdup(text); + } else { + /* There is a multiplier (possibly invalid, though). */ + const char * const mulstart = lastsc + 1; + + char * endP; + char colorbuf[50]; + + errno = 0; + mul = strtod(mulstart, &endP); + if (errno != 0 || endP == mulstart) + pm_error("Invalid sample multiplier: '%s'", mulstart); + + strncpy(colorbuf, text, lastsc - text); + colorbuf[lastsc - text] = '\0'; + colorname = pm_strdup(colorbuf); + } + } else { + mul = 1.0; + colorname = pm_strdup(text); + } + + unmultipliedColor = pnm_parsecolorn(colorname); + + pm_strfree(colorname); + + MALLOCARRAY_NOFAIL(color, 3); + + { + /* Linearize and apply multiplier */ + unsigned int i; + for (i = 0; i < 3; ++i) + color[i] = pm_ungamma709(unmultipliedColor[i]) * mul; + } + free(unmultipliedColor); + + *colorP = color; +} + + + +static void +parseTran (TransArg const transArg, + Trans * const rP) { + + parseColor(transArg.from, &rP->from); + parseColor(transArg.to, &rP->to); +} + + + +static void +calcTrans(TransArgSet const transArgs, + TransSet * const transP) { +/*---------------------------------------------------------------------------- + Interpret transformation option (-from1, etc.) values 'transArg' + as transformations, *transP. +-----------------------------------------------------------------------------*/ + unsigned int xi; + + for (transP->n = 0, xi = 0; xi < 3; ++xi) { + const TransArg * const xformP = &transArgs._[xi]; + + if (xformP->hasFrom || xformP->hasTo) { + if (!xformP->hasFrom || !xformP->hasTo) + pm_error("Mapping %u incompletely specified - " + "you specified -fromN or -toN but not the other", + xi + 1); + parseTran(*xformP, &transP->t[transP->n++]); + } + } + if (transP->n < 2) + pm_error("You must specify at least two mappings with " + "-from1, -to1, etc. You specified %u", transP->n); +} + + + +static void +parseCommandLine(int argc, + const char ** argv, + CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + TransArgSet xlations; /* color mapping as read from command line */ + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + + OPTENT3(0, "fitbrightness", OPT_FLAG, NULL, + &cmdlineP->fitbrightness, 0); + OPTENT3(0, "linear", OPT_FLAG, NULL, + &cmdlineP->linear, 0); + + { + unsigned int i; + for (i = 0; i < 3; ++i) + optAddTrans(option_def, &option_def_index, + &xlations._[i], i + 1); + } + + opt.opt_table = option_def; + opt.short_allowed = 0; + opt.allowNegNum = 0; + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + + if (cmdlineP->linear && cmdlineP->fitbrightness) { + pm_error("You cannot use -linear and -fitbrightness together"); + /* Note: It actually makes sense to use them together; we're just not + willing to put the effort into something it's unlikely anyone will + want. + */ + } + + calcTrans(xlations, &cmdlineP->xlats); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. " + "The only possible non-option argument " + "is the input file name"); + } + + free(option_def); +} + + + +static void +errResolve(void) { + pm_error( "Cannot resolve the transformations"); +} + + + +static double +sqr(double const x) { + return x * x; +} + + + +static void +solveOnePlane(SampleSet const f, + SampleSet const t, + unsigned int const n, + Polynomial * const solutionP) { +/*---------------------------------------------------------------------------- + Find the transformation that maps f[i] to t[i] for 0 <= i < n. +-----------------------------------------------------------------------------*/ + double const eps = 0.00001; + + double a, b, c; + + /* I have decided against generic methods of solving systems of linear + equations in favour of simple explicit formulas, with no memory + allocation and tedious matrix processing. + */ + + switch (n) { + case 3: { + double const aDenom = + sqr( f._[0] ) * ( f._[1] - f._[2] ) - + sqr( f._[2] ) * ( f._[1] - f._[0] ) - + sqr( f._[1] ) * ( f._[0] - f._[2] ); + + if (fabs(aDenom) < eps) + errResolve(); + + a = (t._[1] * (f._[2] - f._[0]) - t._[0] * (f._[2] - f._[1]) - + t._[2] * (f._[1] - f._[0])) + / aDenom; + } break; + case 2: + a = 0.0; + break; + default: + a = 0.0; /* to avoid a warning that <a> "may be uninitialized". */ + pm_error("INTERNAL ERROR: solve(): impossible value of n: %u", n); + } + + { + double const bDenom = f._[1] - f._[0]; + + if (fabs(bDenom) < eps) + errResolve(); + + b = (t._[1] - t._[0] + a * (sqr(f._[0]) - sqr(f._[1]))) / bDenom; + } + + c = -a * sqr(f._[0]) - b * f._[0] + t._[0]; + + solutionP->coeff[0] = a; solutionP->coeff[1] = b; solutionP->coeff[2] = c; +} + + + +static void +chanData(TransSet const ta, + bool const fittingBrightness, + unsigned int const plane, + SampleSet * const fromP, + SampleSet * const toP) { +/*---------------------------------------------------------------------------- + Collate transformations from 'ta' for plane 'plane'. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; i < ta.n; ++i) { + if (fittingBrightness) { /* working with gamma-compressed values */ + fromP->_[i] = pm_gamma709(ta.t[i].from[plane]); + toP-> _[i] = pm_gamma709(ta.t[i].to [plane]); + } else { /* working in linear RGB */ + fromP->_[i] = ta.t[i].from[plane]; + toP-> _[i] = ta.t[i].to [plane]; + } + } +} + + + +typedef struct { + Polynomial _[3]; /* One per plane */ +} Solution; + + + +static void +solveFmCmdlineOpts(CmdlineInfo const cmdline, + unsigned int const depth, + Solution * const solutionP) { +/*---------------------------------------------------------------------------- + Compute the function that will transform the tuples, based on what the user + requested ('cmdline'). + + The function takes intensity-linear tuples for the normal levels function, + or brightness-linear for the brightness approximation levels function. + + The transformed image has 'depth' planes. +-----------------------------------------------------------------------------*/ + unsigned int plane; + SampleSet from, to; + /* This initialization to bypass the "may be uninitialized" warning: */ + to ._[0] = 0; to. _[1] = 0; to ._[2] = 0; + from._[0] = 1; from._[1] = 0; from._[2] = 0; + + for (plane = 0; plane < depth; ++plane) { + + chanData(cmdline.xlats, cmdline.fitbrightness, plane, &from, &to); + solveOnePlane(from, to, cmdline.xlats.n, &solutionP->_[plane]); + } +} + + + +static samplen +xformedSample(samplen const value, + Polynomial const polynomial) { +/*---------------------------------------------------------------------------- + 'sample' transformed by 'polynomial'. +-----------------------------------------------------------------------------*/ + double const res = + (polynomial.coeff[0] * value + polynomial.coeff[1]) * value + + polynomial.coeff[2]; + + return MAX(0.0f, MIN(1.0f, res)); +} + + + +static void +pamlevels(CmdlineInfo const cmdline) { + + unsigned int row; + pam inPam, outPam; + Solution solution; + tuplen * tuplerown; + FILE * ifP; + + ifP = pm_openr(cmdline.inputFileName); + + pnm_readpaminit(ifP, &inPam, PAM_STRUCT_SIZE(tuple_type)); + + outPam = inPam; + outPam.file = stdout; + + solveFmCmdlineOpts(cmdline, inPam.depth, &solution); + + tuplerown = pnm_allocpamrown(&inPam); + + pnm_writepaminit(&outPam); + + for (row = 0; row < inPam.height; ++row) { + unsigned int col; + + pnm_readpamrown(&inPam, tuplerown); + + if (!cmdline.linear && !cmdline.fitbrightness) + pnm_ungammarown(&inPam, tuplerown); + + for (col = 0; col < inPam.width; ++col) { + unsigned int plane; + + for (plane = 0; plane < inPam.depth; ++plane) { + tuplerown[col][plane] = + xformedSample(tuplerown[col][plane], solution._[plane]); + } + } + if (!cmdline.linear && !cmdline.fitbrightness) + pnm_gammarown(&inPam, tuplerown); + + pnm_writepamrown(&outPam, tuplerown); + } + pnm_freepamrown(tuplerown); + pm_close(ifP); +} + + + +static void +freeCmdLineInfo(CmdlineInfo cmdline) { +/*---------------------------------------------------------------------------- + Free any memory that has been dynamically allcoated in <cmdline>. +-----------------------------------------------------------------------------*/ + TransSet * const xxP = &cmdline.xlats; + + uint x; + + for (x = 0; x < xxP->n; ++x) { + free(xxP->t[x].from); + free(xxP->t[x].to); + } +} + + + +int main(int argc, const char * argv[]) { + + CmdlineInfo cmdline; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + pamlevels(cmdline); + + freeCmdLineInfo(cmdline); + + return 0; +} + + + diff --git a/editor/pamrecolor.c b/editor/pamrecolor.c index 6937fd8d..8c5bce12 100644 --- a/editor/pamrecolor.c +++ b/editor/pamrecolor.c @@ -404,7 +404,7 @@ parseCommandLine(int argc, const char ** const argv, cmdlineP->color2gray.rfrac + cmdlineP->color2gray.gfrac + cmdlineP->color2gray.bfrac; - if (fabsf(1.0 - maxLuminance) > REAL_EPSILON) + if (fabsf(1.0f - maxLuminance) > REAL_EPSILON) pm_error("The values given for --rmult, --gmult, and --bmult must " "sum to 1.0, not %.10g", maxLuminance); } else if (csSpec) diff --git a/editor/pamscale.c b/editor/pamscale.c index 0456d15a..433d5cee 100644 --- a/editor/pamscale.c +++ b/editor/pamscale.c @@ -11,9 +11,9 @@ people contributed code changes over the years. Copyright (C) 2003 by Michael Reinelt <reinelt@eunet.at> - + 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 @@ -54,14 +54,14 @@ /* x^2 and x^3 helper functions */ -static __inline__ double +static __inline__ double pow2(double const x) { return x * x; } -static __inline__ double +static __inline__ double pow3(double const x) { return x * x * x; } @@ -75,7 +75,7 @@ pow3(double const x) { #define radius_point (0.0) #define radius_box (0.5) -static double +static double filter_box(double const x) { double const absx = x < 0.0 ? -x : x; @@ -91,7 +91,7 @@ filter_box(double const x) { #define radius_triangle (1.0) -static double +static double filter_triangle(double const x) { double const absx = x < 0.0 ? -x : x; @@ -105,7 +105,7 @@ filter_triangle(double const x) { #define radius_quadratic (1.5) -static double +static double filter_quadratic(double const x) { double const absx = x < 0.0 ? -x : x; @@ -122,7 +122,7 @@ filter_quadratic(double const x) { #define radius_cubic (2.0) -static double +static double filter_cubic(double const x) { double const absx = x < 0.0 ? -x : x; @@ -139,7 +139,7 @@ filter_cubic(double const x) { #define radius_catrom (2.0) -static double +static double filter_catrom(double const x) { double const absx = x < 0.0 ? -x : x; @@ -158,7 +158,7 @@ filter_catrom(double const x) { #define radius_mitchell (2.0) -static double +static double filter_mitchell(double x) { @@ -187,7 +187,7 @@ filter_mitchell(double x) #define radius_gauss (1.25) -static double +static double filter_gauss(double const x) { return exp(-2.0*pow2(x)) * sqrt(2.0/M_PI); @@ -199,14 +199,14 @@ filter_gauss(double const x) { #define radius_sinc (4.0) -static double +static double filter_sinc(double const x) { /* Note: Some people say sinc(x) is sin(x)/x. Others say it's sin(PI*x)/(PI*x), a horizontal compression of the former which is zero at integer values. We use the latter, whose Fourier transform is a canonical rectangle function (edges at -1/2, +1/2, height 1). */ - return + return x == 0.0 ? 1.0 : sin(M_PI*x)/(M_PI*x); } @@ -218,10 +218,10 @@ filter_sinc(double const x) { #define radius_bessel (3.2383) -static double +static double filter_bessel(double const x) { - return + return x == 0.0 ? M_PI/4.0 : j1(M_PI * x) / (2.0 * x); } @@ -232,7 +232,7 @@ filter_bessel(double const x) { #define radius_hanning (1.0) -static double +static double filter_hanning(double const x) { return 0.5 * cos(M_PI * x) + 0.5; @@ -244,7 +244,7 @@ filter_hanning(double const x) { #define radius_hamming (1.0) -static double +static double filter_hamming(double const x) { return 0.46 * cos(M_PI * x) + 0.54; } @@ -255,7 +255,7 @@ filter_hamming(double const x) { #define radius_blackman (1.0) -static double +static double filter_blackman(double const x) { return 0.5 * cos(M_PI * x) + 0.08 * cos(2.0 * M_PI * x) + 0.42; } @@ -268,12 +268,12 @@ filter_blackman(double const x) { #define radius_kaiser (1.0) /* modified zeroth order Bessel function of the first kind. */ -static double +static double bessel_i0(double const x) { - + int i; double sum, y, t; - + sum = 1.0; y = pow2(x)/4.0; t = y; @@ -286,15 +286,15 @@ bessel_i0(double const x) { -static double +static double filter_kaiser(double const x) { /* typically 4 < a < 9 */ /* param a trades off main lobe width (sharpness) */ /* for side lobe amplitude (ringing) */ - + double const a = 6.5; double const i0a = 1.0/bessel_i0(a); - + return i0a * bessel_i0(a * sqrt(1.0-pow2(x))); } @@ -305,7 +305,7 @@ filter_kaiser(double const x) { #define radius_normal (1.0) -static double +static double filter_normal(double const x) { return exp(-pow2(x)/2.0) / sqrt(2.0*M_PI); } @@ -316,7 +316,7 @@ filter_normal(double const x) { #define radius_hermite (1.0) -static double +static double filter_hermite(double const x) { /* f(x) = 2|x|^3 - 3|x|^2 + 1, -1 <= x <= 1 */ @@ -333,7 +333,7 @@ filter_hermite(double const x) { #define radius_lanczos (3.0) -static double +static double filter_lanczos(double const x) { double const absx = x < 0.0 ? -x : x; @@ -352,7 +352,7 @@ typedef struct { /* This is how far from the Y axis (on either side) the function has significant value. (You can use this to limit how much of your domain you bother to compute the function - over). + over). */ bool windowed; } filter; @@ -420,25 +420,25 @@ struct CmdlineInfo { basicFunction_t filterFunction; /* NULL if not using resample method */ basicFunction_t windowFunction; /* Meaningful only when filterFunction != NULL */ - double filterRadius; + double filterRadius; /* Meaningful only when filterFunction != NULL */ enum scaleType scaleType; /* 'xsize' and 'ysize' are numbers of pixels. Their meaning depends upon - 'scaleType'. for SCALE_BOXFIT and SCALE_BOXFILL, they are the box + 'scaleType'. for SCALE_BOXFIT and SCALE_BOXFILL, they are the box dimensions. For SCALE_SEPARATE, they are the separate dimensions, or zero to indicate unspecified. For SCALE_PIXELMAX, they are meaningless. */ unsigned int xsize; unsigned int ysize; - /* 'xscale' and 'yscale' are meaningful only for scaleType == + /* 'xscale' and 'yscale' are meaningful only for scaleType == SCALE_SEPARATE and only where the corresponding xsize/ysize is unspecified. 0.0 means unspecified. */ float xscale; float yscale; /* 'pixels' is meaningful only for scaleType == SCALE_PIXELMAX */ - unsigned int pixels; + unsigned int pixels; unsigned int linear; unsigned int verbose; }; @@ -466,7 +466,7 @@ lookupFilterByName(const char * const filtername, strcpy(known_filters, ""); for (i = 0; Filters[i].name; ++i) { const char * const name = Filters[i].name; - if (strlen(known_filters) + strlen(name) + 1 + 1 < + if (strlen(known_filters) + strlen(name) + 1 + 1 < sizeof(known_filters)) { strcat(known_filters, name); strcat(known_filters, " "); @@ -489,13 +489,13 @@ processFilterOptions(unsigned int const filterSpec, if (filterSpec) { filter baseFilter; lookupFilterByName(filterOpt, &baseFilter); - cmdlineP->filterFunction = baseFilter.function; + cmdlineP->filterFunction = baseFilter.function; cmdlineP->filterRadius = baseFilter.radius; if (windowSpec) { filter windowFilter; lookupFilterByName(windowOpt, &windowFilter); - + if (cmdlineP->windowFunction == filter_box) cmdlineP->windowFunction = NULL; else @@ -526,28 +526,28 @@ parseSizeParm(const char * const sizeString, sizeLong = strtol(sizeString, &endptr, 10); if (strlen(sizeString) > 0 && *endptr != '\0') - pm_error("%s size argument not an integer: '%s'", + pm_error("%s size argument not an integer: '%s'", description, sizeString); else if (sizeLong > INT_MAX - 2) pm_error("%s size argument is too large " - "for computations: %ld", + "for computations: %ld", description, sizeLong); else if (sizeLong <= 0) - pm_error("%s size argument is not positive: %ld", + pm_error("%s size argument is not positive: %ld", description, sizeLong); else *sizeP = (unsigned int) sizeLong; -} +} static void -parseXyParms(int const argc, +parseXyParms(int const argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { /* parameters are box width (columns), box height (rows), and - optional filespec + optional filespec */ if (argc-1 < 2) pm_error("You must supply at least two parameters with " @@ -571,7 +571,7 @@ parseXyParms(int const argc, static void -parseScaleParms(int const argc, +parseScaleParms(int const argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- @@ -583,7 +583,7 @@ parseScaleParms(int const argc, "one parameter: the scale factor."); else { cmdlineP->xscale = cmdlineP->yscale = atof(argv[1]); - + if (cmdlineP->xscale <= 0.0) pm_error("The scale parameter %s is not a positive number.", argv[1]); @@ -592,7 +592,7 @@ parseScaleParms(int const argc, cmdlineP->inputFileName = "-"; else { cmdlineP->inputFileName = argv[2]; - + if (argc-1 > 2) pm_error("Too many arguments. There are at most two " "arguments with this set of options: " @@ -606,7 +606,7 @@ parseScaleParms(int const argc, static void -parseFilespecOnlyParms(int const argc, +parseFilespecOnlyParms(int const argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { @@ -618,13 +618,13 @@ parseFilespecOnlyParms(int const argc, } -static void -parseCommandLine(int argc, - const char ** argv, +static void +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. + and argv. Return the information in the options as *cmdlineP. If command line is internally inconsistent (invalid options, etc.), issue error message to stderr and abort program. @@ -635,7 +635,7 @@ parseCommandLine(int argc, optEntry * option_def; optStruct3 opt; /* Instructions to pm_optParseOptions3 on how to parse our options. */ - + unsigned int option_def_index; unsigned int xyfit, xyfill; int xsize, ysize, pixels; @@ -665,7 +665,7 @@ parseCommandLine(int argc, OPTENT3(0, "window", OPT_STRING, &window, &windowSpec, 0); OPTENT3(0, "nomix", OPT_FLAG, NULL, &cmdlineP->nomix, 0); OPTENT3(0, "linear", OPT_FLAG, NULL, &cmdlineP->linear, 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 */ @@ -673,7 +673,7 @@ parseCommandLine(int argc, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (cmdlineP->nomix && filterSpec) + if (cmdlineP->nomix && filterSpec) pm_error("You cannot specify both -nomix and -filter."); processFilterOptions(filterSpec, filterOpt, windowSpec, window, @@ -694,19 +694,19 @@ parseCommandLine(int argc, pm_error("Cannot specify both -xsize/width and -xscale."); if (ysizeSpec && yscaleSpec) pm_error("Cannot specify both -ysize/height and -yscale."); - + if ((xyfit || xyfill) && - (xsizeSpec || xscaleSpec || ysizeSpec || yscaleSpec || + (xsizeSpec || xscaleSpec || ysizeSpec || yscaleSpec || reduceSpec || pixelsSpec) ) pm_error("Cannot specify -xyfit/xyfill/xysize with other " "dimension options."); if (xyfit && xyfill) pm_error("Cannot specify both -xyfit and -xyfill"); - if (pixelsSpec && + if (pixelsSpec && (xsizeSpec || xscaleSpec || ysizeSpec || yscaleSpec || reduceSpec) ) pm_error("Cannot specify -pixels with other dimension options."); - if (reduceSpec && + if (reduceSpec && (xsizeSpec || xscaleSpec || ysizeSpec || yscaleSpec) ) pm_error("Cannot specify -reduce with other dimension options."); @@ -722,9 +722,9 @@ parseCommandLine(int argc, cmdlineP->scaleType = SCALE_SEPARATE; parseFilespecOnlyParms(argc, argv, cmdlineP); cmdlineP->xsize = cmdlineP->ysize = 0; - cmdlineP->xscale = cmdlineP->yscale = + cmdlineP->xscale = cmdlineP->yscale = ((double) 1.0) / ((double) reduce); - pm_message("reducing by %d gives scale factor of %f.", + pm_message("reducing by %d gives scale factor of %f.", reduce, cmdlineP->xscale); } else if (pixelsSpec) { cmdlineP->scaleType = SCALE_PIXELMAX; @@ -746,12 +746,12 @@ parseCommandLine(int argc, -static void -computeOutputDimensions(struct CmdlineInfo const cmdline, - unsigned int const cols, - unsigned int const rows, +static void +computeOutputDimensions(struct CmdlineInfo const cmdline, + unsigned int const cols, + unsigned int const rows, int * const newcolsP, - int * const newrowsP) { + int * const newrowsP) { double newcolsD, newrowsD; /* Intermediate calculation of the output dimensions, in double @@ -775,10 +775,10 @@ computeOutputDimensions(struct CmdlineInfo const cmdline, case SCALE_BOXFIT: case SCALE_BOXFILL: { double const aspect_ratio = (float) cols / (float) rows; - double const box_aspect_ratio = + double const box_aspect_ratio = (float) cmdline.xsize / (float) cmdline.ysize; - - if ((box_aspect_ratio > aspect_ratio && + + if ((box_aspect_ratio > aspect_ratio && cmdline.scaleType == SCALE_BOXFIT) || (box_aspect_ratio < aspect_ratio && cmdline.scaleType == SCALE_BOXFILL)) { @@ -809,7 +809,7 @@ computeOutputDimensions(struct CmdlineInfo const cmdline, newrowsD = rows; } } - + /* If the rounding yields a zero dimension, we fudge it up to 1. We do this rather than considering it a specification error (and dying) because it's friendlier to automated processes that work on arbitrary @@ -898,9 +898,9 @@ typedef struct { at index 0. */ unsigned int allocWeight; - /* Number of allocated frames in 'Weight' */ + /* Number of allocated frames in 'Weight' */ WEIGHT *Weight; - /* The terms of the linear combination. Has 'nWeight' elements. + /* The terms of the linear combination. Has 'nWeight' elements. The coefficients (weights) of each add up to unity. */ } WLIST; @@ -911,7 +911,7 @@ typedef struct { /* The row number in the input image of the row. -1 means no row. */ - tuple *tuplerow; + tuple *tuplerow; /* The tuples of the row. If rowNumber = -1, these are arbitrary, but allocated, tuples. */ @@ -957,7 +957,7 @@ appendWeight(WLIST * const WList, unsigned int const n = WList->nWeight; assert(WList->allocWeight >= n+1); - + WList->Weight[n].position = index; WList->Weight[n].weight = weight; ++WList->nWeight; @@ -977,7 +977,7 @@ unnormalize(double const normalized, wrong thing in actual practice, EG on Darwin PowerPC (my iBook running OS X) negative values clamp to maxval. We get negative values because some of the filters (EG catrom) have negative - weights. + weights. */ return MIN(maxval, (sample)(MAX(0.0, (normalized*maxval + 0.5)))); @@ -1007,10 +1007,10 @@ createWeightList(unsigned int const targetPos, WLIST * const weightListP) { /*---------------------------------------------------------------------------- Create a weight list for computing target pixel number 'targetPos' from - a set of source pixels. These pixels are a line of pixels either + a set of source pixels. These pixels are a line of pixels either horizontally or vertically. The weight list is a list of weights to give each source pixel in the set. - + The source pixel set is a window of source pixels centered on some point. The weights are defined by the function 'filter' of the position within the window, and normalized to add up to 1.0. @@ -1034,7 +1034,7 @@ createWeightList(unsigned int const targetPos, We want to calculate 3 weights, one to be applied to each source pixel in computing the target pixel. Ideally, we would compute the average - height of the filter function over each source pixel region. But + height of the filter function over each source pixel region. But that's too hard. So we approximate by assuming that the filter function is constant within each region, at the value the function has at the _center_ of the region. @@ -1064,12 +1064,12 @@ createWeightList(unsigned int const targetPos, 'leftPixel' and 'rightPixel' are the pixel positions of the pixels at the edges of that window. Note that if we're doing vertical weights, "left" and "right" mean top and - bottom. + bottom. */ double const windowCenter = ((double)targetPos + 0.5) / scale; double left = MAX(0.0, windowCenter - filter.radius - EPSILON); unsigned int const leftPixel = floor(left); - double right = MIN((double)sourceSize - EPSILON, + double right = MIN((double)sourceSize - EPSILON, windowCenter + filter.radius + EPSILON); unsigned int const rightPixel = floor(right); @@ -1082,7 +1082,7 @@ createWeightList(unsigned int const targetPos, norm = 0.0; /* initial value */ for (j = leftPixel; j <= rightPixel; ++j) { - /* Calculate the weight that source pixel 'j' will have in the + /* Calculate the weight that source pixel 'j' will have in the value of target pixel 'targetPos'. */ double const regionLeft = MAX(left, (double)j); @@ -1132,7 +1132,7 @@ createWeightListSet(unsigned int const sourceSize, pixels in a region to effect a resampling. Multiplying by these factors effects all of the following transformations on the original pixels: - + 1) Filter out any frequencies that are artifacts of the original sampling. We assume a perfect sampling was done, which means the original continuous dataset had a maximum @@ -1140,12 +1140,12 @@ createWeightListSet(unsigned int const sourceSize, above that is an artifact of the sampling. So we filter out anything above 1/2 of the original sample rate (sample rate == pixel resolution). - + 2) Filter out any frequencies that are too high to be captured by the new sampling -- i.e. frequencies above 1/2 the new sample rate. This is the information we must lose because of low sample rate. - + 3) Sample the result at the new sample rate. We do all three of these steps in a single convolution of the @@ -1154,7 +1154,7 @@ createWeightListSet(unsigned int const sourceSize, rectangle function is a pixel domain sinc function, which is what we assume 'filterFunction' is. We get Step 3 by computing the convolution only at the new sample points. - + I don't know what any of this means when 'filterFunction' is not sinc. Maybe it just means some approximation or additional filtering steps are happening. @@ -1164,7 +1164,7 @@ createWeightListSet(unsigned int const sourceSize, unsigned int targetPos; MALLOCARRAY_NOFAIL(weightListSet, targetSize); - + for (targetPos = 0; targetPos < targetSize; ++targetPos) createWeightList(targetPos, sourceSize, scale, filterFunction, &weightListSet[targetPos]); @@ -1210,7 +1210,7 @@ makeFilterFunction(double const scale, retval.basicFunction = basicFunction; retval.windowFunction = windowFunction; - + retval.horizontalScaler = freqLimit; /* Our 'windowFunction' argument is a function normalized to the @@ -1235,11 +1235,11 @@ makeFilterFunction(double const scale, return retval; } - - + + static void -destroyWeightListSet(WLIST * const weightListSet, +destroyWeightListSet(WLIST * const weightListSet, unsigned int const size) { unsigned int i; @@ -1264,14 +1264,14 @@ createScanBuf(struct pam * const pamP, scanbuf.width = pamP->width; scanbuf.height = maxRowWeights; MALLOCARRAY_NOFAIL(scanbuf.line, scanbuf.height); - + for (lineNumber = 0; lineNumber < scanbuf.height; ++lineNumber) { scanbuf.line[lineNumber].rowNumber = -1; scanbuf.line[lineNumber].tuplerow = pnm_allocpamrow(pamP); } - + if (verbose) - pm_message("scanline buffer: %d lines of %d pixels", + pm_message("scanline buffer: %d lines of %d pixels", scanbuf.height, scanbuf.width); *scanbufP = scanbuf; @@ -1296,10 +1296,10 @@ static void resampleDimensionMessage(struct pam * const inpamP, struct pam * const outpamP) { - pm_message ("resampling from %d*%d to %d*%d (%f, %f)", - inpamP->width, inpamP->height, + pm_message ("resampling from %d*%d to %d*%d (%f, %f)", + inpamP->width, inpamP->height, outpamP->width, outpamP->height, - (double)outpamP->width/inpamP->width, + (double)outpamP->width/inpamP->width, (double)outpamP->height/inpamP->height); } @@ -1325,12 +1325,12 @@ addInPixel(const struct pam * const pamP, for (plane = 0; plane < pamP->depth; ++plane) { double const normalizedSample = (double)tuple[plane]/pamP->maxval; double opacityAdjustment; - + if (haveOpacity && plane != opacityPlane) opacityAdjustment = (double)tuple[opacityPlane]/pamP->maxval; else opacityAdjustment = 1; - + accum[plane] += opacityAdjustment * normalizedSample * weight; } } @@ -1340,7 +1340,7 @@ addInPixel(const struct pam * const pamP, static void generateOutputTuple(const struct pam * const pamP, double const accum[], - bool const haveOpacity, + bool const haveOpacity, unsigned int const opacityPlane, tuple * const tupleP) { /*---------------------------------------------------------------------------- @@ -1358,7 +1358,7 @@ generateOutputTuple(const struct pam * const pamP, if (haveOpacity && plane != opacityPlane) { if (accum[opacityPlane] < EPSILON) { opacityAdjustedSample = 0.0; - } else + } else opacityAdjustedSample = accum[plane] / accum[opacityPlane]; } else opacityAdjustedSample = accum[plane]; @@ -1377,7 +1377,7 @@ outputOneResampledRow(const struct pam * const outpamP, tuple * const line, double * const accum) { /*---------------------------------------------------------------------------- - From the data in 'scanbuf' and weights in 'YW' and 'XWeight', + From the data in 'scanbuf' and weights in 'YW' and 'XWeight', generate one output row for the image described by *outpamP and output it. @@ -1411,24 +1411,24 @@ outputOneResampledRow(const struct pam * const outpamP, for (plane = 0; plane < outpamP->depth; ++plane) accum[plane] = 0.0; } - + for (i = 0; i < YW.nWeight; ++i) { int const yp = YW.Weight[i].position; float const yw = YW.Weight[i].weight; int const slot = yp % scanbuf.height; unsigned int j; - + for (j = 0; j < XW.nWeight; ++j) { int const xp = XW.Weight[j].position; tuple const tuple = scanbuf.line[slot].tuplerow[xp]; - - addInPixel(outpamP, tuple, yw * XW.Weight[j].weight, + + addInPixel(outpamP, tuple, yw * XW.Weight[j].weight, haveOpacity, opacityPlane, accum); } } - generateOutputTuple(outpamP, accum, haveOpacity, opacityPlane, + generateOutputTuple(outpamP, accum, haveOpacity, opacityPlane, &line[col]); } pnm_writepamrow(outpamP, line); @@ -1447,7 +1447,7 @@ scanbufContainsTheRows(SCAN const scanbuf, -----------------------------------------------------------------------------*/ bool missingRow; unsigned int i; - + for (i = 0, missingRow = FALSE; i < rowWeights.nWeight && !missingRow; ++i) { @@ -1481,7 +1481,7 @@ createWeightLists(struct pam * const inpamP, /*---------------------------------------------------------------------------- This is the function that actually does the resampling. Note that it does it without ever looking at the source or target pixels! It produces - a simple set of numbers that Caller can blindly apply to the source + a simple set of numbers that Caller can blindly apply to the source pixels to get target pixels. -----------------------------------------------------------------------------*/ struct filterFunction horizFilter, vertFilter; @@ -1490,14 +1490,14 @@ createWeightLists(struct pam * const inpamP, (double)outpamP->width/inpamP->width, filterFunction, filterRadius, windowFunction); - createWeightListSet(inpamP->width, outpamP->width, horizFilter, + createWeightListSet(inpamP->width, outpamP->width, horizFilter, horizWeightP); - + vertFilter = makeFilterFunction( (double)outpamP->height/inpamP->height, filterFunction, filterRadius, windowFunction); - createWeightListSet(inpamP->height, outpamP->height, vertFilter, + createWeightListSet(inpamP->height, outpamP->height, vertFilter, vertWeightP); *maxRowWeightsP = ceil(2.0*(vertFilter.radius+EPSILON) + 1 + EPSILON); @@ -1516,12 +1516,12 @@ resample(struct pam * const inpamP, /*--------------------------------------------------------------------------- Resample the image in the input file, described by *inpamP, so as to create the image in the output file, described by *outpamP. - + Input and output differ by height, width, and maxval only. Use the resampling filter function 'filterFunction', applied over radius 'filterRadius'. - + The input file is positioned past the header, to the beginning of the raster. The output file is too. ---------------------------------------------------------------------------*/ @@ -1539,7 +1539,7 @@ resample(struct pam * const inpamP, if (linear) pm_error("You cannot use the resampling scaling method on " "linear input."); - + createWeightLists(inpamP, outpamP, filterFunction, filterRadius, windowFunction, &horizWeight, &vertWeight, &maxRowWeights); @@ -1576,10 +1576,10 @@ resample(struct pam * const inpamP, i.e. what fractions of which input rows combine to create this output row. */ - assert(rowWeights.nWeight <= scanbuf.height); + assert(rowWeights.nWeight <= scanbuf.height); if (scanbufContainsTheRows(scanbuf, rowWeights)) { - outputOneResampledRow(outpamP, scanbuf, rowWeights, + outputOneResampledRow(outpamP, scanbuf, rowWeights, horizWeight, line, weight); ++outputRow; } else @@ -1609,7 +1609,7 @@ resample(struct pam * const inpamP, static void zeroNewRow(struct pam * const pamP, tuplen * const tuplenrow) { - + unsigned int col; for (col = 0; col < pamP->width; ++col) { @@ -1625,7 +1625,7 @@ zeroNewRow(struct pam * const pamP, static void accumOutputCol(struct pam * const pamP, tuplen const intuplen, - float const fraction, + float const fraction, tuplen const accumulator) { /*---------------------------------------------------------------------------- Add fraction 'fraction' of the pixel indicated by 'intuplen' to the @@ -1645,7 +1645,7 @@ accumOutputCol(struct pam * const pamP, static void -horizontalScale(tuplen * const inputtuplenrow, +horizontalScale(tuplen * const inputtuplenrow, tuplen * const newtuplenrow, struct pam * const inpamP, struct pam * const outpamP, @@ -1683,7 +1683,7 @@ horizontalScale(tuplen * const inputtuplenrow, /* Generate one output pixel in 'newtuplerow'. It will consist of anything accumulated from prior input pixels in accumulator[], plus a fraction of the current input - pixel. + pixel. */ assert(newcol < outpamP->width); accumOutputCol(inpamP, inputtuplenrow[col], fraccoltofill, @@ -1695,7 +1695,7 @@ horizontalScale(tuplen * const inputtuplenrow, ++newcol; fraccoltofill = 1.0; } - /* There's not enough left in the current input pixel to fill up + /* There's not enough left in the current input pixel to fill up a whole output column, so just accumulate the remainder of the pixel into the current output column. Because of rounding, we may have a tiny bit of pixel left and have run out of output pixels. @@ -1714,17 +1714,17 @@ horizontalScale(tuplen * const inputtuplenrow, newcol, outpamP->width-1); if (newcol < outpamP->width) { - /* We were still working on the last output column when we + /* We were still working on the last output column when we ran out of input columns. This would be because of rounding down, and we should be missing only a tiny fraction of that last output column. Just fill in the missing color with the color of the rightmost input pixel. */ - accumOutputCol(inpamP, inputtuplenrow[inpamP->width-1], + accumOutputCol(inpamP, inputtuplenrow[inpamP->width-1], fraccoltofill, newtuplenrow[newcol]); - + *stretchP = fraccoltofill; - } else + } else *stretchP = 0.0; } @@ -1747,11 +1747,11 @@ zeroAccum(struct pam * const pamP, static void accumOutputRow(struct pam * const pamP, - tuplen * const tuplenrow, - float const fraction, + tuplen * const tuplenrow, + float const fraction, tuplen * const accumulator) { /*---------------------------------------------------------------------------- - Take 'fraction' times the samples in row 'tuplenrow' and add it to + Take 'fraction' times the samples in row 'tuplenrow' and add it to 'accumulator' in the same way as accumOutputCol(). 'fraction' is less than 1.0. @@ -1838,7 +1838,7 @@ writeARow(struct pam * const pamP, static void -issueStretchWarning(bool const verbose, +issueStretchWarning(bool const verbose, double const fracrowtofill) { /* We need another input row to fill up this @@ -1847,11 +1847,11 @@ issueStretchWarning(bool const verbose, scaling arithmetic. So we go ahead with the data from the last row we read, which amounts to stretching out the last output - row. + row. */ if (verbose) pm_message("%f of bottom row stretched because of " - "arithmetic imprecision", + "arithmetic imprecision", fracrowtofill); } @@ -1873,21 +1873,21 @@ scaleHorizontallyAndOutputRow(struct pam * const inpamP, 'newtuplenrow' is work space Caller provides us. It is at least wide enough to hold one output row. -----------------------------------------------------------------------------*/ - if (outpamP->width == inpamP->width) + if (outpamP->width == inpamP->width) /* shortcut X scaling */ writeARow(outpamP, rowAccumulator, transform); /* This destroys 'rowAccumulator' */ else { float stretch; - + horizontalScale(rowAccumulator, newtuplenrow, inpamP, outpamP, xscale, &stretch); - + if (verbose && row == 0) pm_message("%f of right column stretched because of " - "arithmetic imprecision", + "arithmetic imprecision", stretch); - + writeARow(outpamP, newtuplenrow, transform); /* This destroys 'newtuplenrow' */ } @@ -1919,7 +1919,7 @@ destroyTransforms(const pnm_transformMap * const inputTransform, if (inputTransform) free((void*)inputTransform); - + if (outputTransform) free((void*)outputTransform); } @@ -1929,7 +1929,7 @@ destroyTransforms(const pnm_transformMap * const inputTransform, static void scaleWithMixing(struct pam * const inpamP, struct pam * const outpamP, - float const xscale, + float const xscale, float const yscale, bool const assumeLinear, bool const verbose) { @@ -1950,8 +1950,8 @@ scaleWithMixing(struct pam * const inpamP, approximate but fast results). -----------------------------------------------------------------------------*/ - /* Here's how we think of the color mixing scaling operation: - + /* Here's how we think of the color mixing scaling operation: + First, I'll describe scaling in one dimension. Assume we have a one row image. A raster row is ordinarily a sequence of discrete pixels which have no width and no distance between @@ -1973,7 +1973,7 @@ scaleWithMixing(struct pam * const inpamP, look the same. This works for all scale factors, both scaling up and scaling down. - + For images with an opacity plane, imagine Input Pixel 0's foreground is fully opaque red (1,0,0,1), and Input Pixel 1 is fully transparent (foreground irrelevant) (0,0,0,0). We make @@ -1994,14 +1994,14 @@ scaleWithMixing(struct pam * const inpamP, stretch the image vertically first (same process as above, but in place of a single-color pixels, we have a vector of colors). Then we take each row this vertical stretching generates and - stretch it horizontally. + stretch it horizontally. */ tuplen * tuplenrow; /* An input row */ tuplen * newtuplenrow; /* Working space */ float rowsleft; /* The number of rows of output that need to be formed from the - current input row (the one in tuplerow[]), less the number that + current input row (the one in tuplerow[]), less the number that have already been formed (either in accumulator[] or output to the file). This can be fractional because of the way we define rows as having height. @@ -2021,8 +2021,8 @@ scaleWithMixing(struct pam * const inpamP, int row; const pnm_transformMap * inputTransform; const pnm_transformMap * outputTransform; - - tuplenrow = pnm_allocpamrown(inpamP); + + tuplenrow = pnm_allocpamrown(inpamP); rowAccumulator = pnm_allocpamrown(inpamP); rowsread = 0; @@ -2087,7 +2087,7 @@ scaleWithMixing(struct pam * const inpamP, static void scaleWithoutMixing(const struct pam * const inpamP, const struct pam * const outpamP, - float const xscale, + float const xscale, float const yscale) { /*---------------------------------------------------------------------------- Scale the image described by *inpamP by xscale horizontally and @@ -2096,9 +2096,9 @@ scaleWithoutMixing(const struct pam * const inpamP, The input file is positioned past the header, to the beginning of the raster. The output file is too. - + Don't mix colors from different input pixels together in the output - pixels. Each output pixel is an exact copy of some corresponding + pixels. Each output pixel is an exact copy of some corresponding input pixel. -----------------------------------------------------------------------------*/ tuple * tuplerow; /* An input row */ @@ -2109,22 +2109,22 @@ scaleWithoutMixing(const struct pam * const inpamP, assert(outpamP->maxval == inpamP->maxval); assert(outpamP->depth == inpamP->depth); - tuplerow = pnm_allocpamrow(inpamP); + tuplerow = pnm_allocpamrow(inpamP); rowInInput = -1; newtuplerow = pnm_allocpamrow(outpamP); for (row = 0; row < outpamP->height; ++row) { int col; - + int const inputRow = (int) (row / yscale); - for (; rowInInput < inputRow; ++rowInInput) + for (; rowInInput < inputRow; ++rowInInput) pnm_readpamrow(inpamP, tuplerow); - + for (col = 0; col < outpamP->width; ++col) { int const inputCol = (int) (col / xscale); - + pnm_assigntuple(inpamP, newtuplerow[col], tuplerow[inputCol]); } @@ -2140,7 +2140,7 @@ static void pamscale(FILE * const ifP, FILE * const ofP, struct CmdlineInfo const cmdline) { - + struct pam inpam, outpam; float xscale, yscale; @@ -2158,21 +2158,21 @@ pamscale(FILE * const ifP, outpam.maxval = inpam.maxval; } - computeOutputDimensions(cmdline, inpam.width, inpam.height, + computeOutputDimensions(cmdline, inpam.width, inpam.height, &outpam.width, &outpam.height); xscale = (float) outpam.width / inpam.width; yscale = (float) outpam.height / inpam.height; if (cmdline.verbose) { - pm_message("Scaling by %f horizontally to %d columns.", + pm_message("Scaling by %f horizontally to %d columns.", xscale, outpam.width); - pm_message("Scaling by %f vertically to %d rows.", + pm_message("Scaling by %f vertically to %d rows.", yscale, outpam.height); } if (xscale * inpam.width < outpam.width - 1 || - yscale * inpam.height < outpam.height - 1) + yscale * inpam.height < outpam.height - 1) pm_error("Arithmetic precision of this program is inadequate to " "do the specified scaling. Use a smaller input image " "or a slightly different scale factor."); @@ -2186,7 +2186,7 @@ pamscale(FILE * const ifP, } else if (!cmdline.filterFunction) { if (cmdline.verbose) pm_message("Using simple pixel mixing rescaling method"); - scaleWithMixing(&inpam, &outpam, xscale, yscale, + scaleWithMixing(&inpam, &outpam, xscale, yscale, cmdline.linear, cmdline.verbose); } else { if (cmdline.verbose) @@ -2221,6 +2221,6 @@ main(int argc, const char **argv ) { pm_close(ifP); pm_close(stdout); - + return 0; } diff --git a/editor/pbmclean.c b/editor/pbmclean.c index 46e7dee6..08f410c0 100644 --- a/editor/pbmclean.c +++ b/editor/pbmclean.c @@ -6,13 +6,14 @@ =============================================================================*/ #include <assert.h> #include <stdio.h> +#include <stdbool.h> #include "pm_c_util.h" #include "mallocvar.h" #include "shhopt.h" #include "pbm.h" -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -28,7 +29,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo *cmdlineP) { + struct CmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -46,13 +47,13 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "black", OPT_FLAG, NULL, &black, 0); OPTENT3(0, "white", OPT_FLAG, NULL, &white, 0); - OPTENT3(0, "minneighbors", OPT_UINT, &cmdlineP->minneighbors, + OPTENT3(0, "minneighbors", OPT_UINT, &cmdlineP->minneighbors, &minneighborsSpec, 0); OPTENT3(0, "extended", OPT_FLAG, NULL, &cmdlineP->extended, 0); opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = TRUE; /* We sort of allow negative numbers as parms */ + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We sort of allow negative numbers as parms */ pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -64,8 +65,8 @@ parseCommandLine(int argc, const char ** argv, pm_error("With -extended, you cannot specify both " "-black and -white"); else if (!black & !white) { - cmdlineP->flipBlack = TRUE; - cmdlineP->flipWhite = FALSE; + cmdlineP->flipBlack = true; + cmdlineP->flipWhite = false; } else { cmdlineP->flipBlack = !!black; cmdlineP->flipWhite = !!white; @@ -77,7 +78,7 @@ parseCommandLine(int argc, const char ** argv, } else { cmdlineP->flipBlack = !!black; cmdlineP->flipWhite = !!white; - } + } } if (!minneighborsSpec) { /* Now we do a sleazy tour through the parameters to see if @@ -86,7 +87,7 @@ parseCommandLine(int argc, const char ** argv, unconventional syntax where a -N option was used instead of the current -minneighbors option. The only reason -N didn't get processed by pm_pm_optParseOptions3() is that it looked - like a negative number parameter instead of an option. + like a negative number parameter instead of an option. If we find a -N, we make like it was a -minneighbors=N option. */ int i; @@ -109,7 +110,7 @@ parseCommandLine(int argc, const char ** argv, --argc; } - if (argc-1 < 1) + if (argc-1 < 1) cmdlineP->inputFileName = "-"; else if (argc-1 == 1) cmdlineP->inputFileName = argv[1]; @@ -160,7 +161,7 @@ bitpop24(uint32_t const w){ -----------------------------------------------------------------------------*/ return (bitpop8((w >> 16) & 0xff) + bitpop8((w >> 8) & 0xff) + - bitpop8((w >> 0) & 0xff)); + bitpop8((w >> 0) & 0xff)); } @@ -204,11 +205,11 @@ and written to outrow at the byte boundary. static unsigned int -likeNeighbors(uint32_t const blackSample, +likeNeighbors(uint32_t const blackSample, unsigned int const offset) { bool const thispoint = ( blackSample >> (18-offset) ) & 0x01; - uint32_t const sample = (thispoint == PBM_BLACK ) + uint32_t const sample = (thispoint == PBM_BLACK ) ? blackSample : ~ blackSample ; uint32_t const selection = 0x701407; @@ -238,7 +239,7 @@ setSample(const bit * const prevrow, ((nextrow[col8 - 1] & 0x01) << 9) | ((nextrow[col8] ) << 1) | ((nextrow[col8 + 1] & 0x80) >> 7); - + return sample; } @@ -277,7 +278,7 @@ cleanrow(const bit * const prevrow, /* ---------------------------------------------------------------------- Work through row, scanning for bits that require flipping, and write the results to 'outrow'. - + Returns the number of bits flipped within this one row as *nFlippedP. -------------------------------------------------------------------------*/ uint32_t sample; @@ -350,9 +351,9 @@ setupInputBuffers(FILE * const ifP, for (i = 0; i < pbm_packed_bytes(cols+16); ++i) edgeRow[i] = 0x00; - + for (i = 0; i < 3; ++i) { - /* Add blank (all white) bytes beside the edges */ + /* Add blank (all white) bytes beside the edges */ buffer[i][0] = buffer[i][ pbm_packed_bytes( cols +16 ) - 1] = 0x00; } nextRow = &buffer[0][1]; @@ -374,7 +375,7 @@ setupInputBuffers(FILE * const ifP, static void cleanSimple(FILE * const ifP, FILE * const ofP, - struct cmdlineInfo const cmdline, + struct CmdlineInfo const cmdline, double * const nFlippedP) { /*---------------------------------------------------------------------------- Do the traditional clean where you look only at the immediate neighboring @@ -412,7 +413,7 @@ cleanSimple(FILE * const ifP, if (row < rows -1){ nextRow = &buffer[(row+1)%3][1]; /* We take the address directly instead of shuffling the rows - with the help of a temporary. This provision is for proper + with the help of a temporary. This provision is for proper handling of the initial edgerow. */ pbm_readpbmrow_packed(ifP, nextRow, cols, format); @@ -423,7 +424,7 @@ cleanSimple(FILE * const ifP, cleanrow(prevRow, thisRow, nextRow, outRow, cols, cmdline.minneighbors, cmdline.flipWhite, cmdline.flipBlack, &nFlipped); - + *nFlippedP += nFlipped; pbm_writepbmrow_packed(ofP, outRow, cols, 0) ; @@ -446,7 +447,7 @@ typedef struct { A queue of pixel locations. -----------------------------------------------------------------------------*/ unsigned int size; - + struct PixQueueElt * headP; struct PixQueueElt * tailP; } PixQueue; @@ -495,7 +496,7 @@ pixQueue_push(PixQueue * const queueP, newEltP->nextP = NULL; if (queueP->tailP) queueP->tailP->nextP = newEltP; - + queueP->tailP = newEltP; if (!queueP->headP) @@ -538,7 +539,7 @@ pixQueue_term(PixQueue * const queueP) { struct PixQueueElt * p; struct PixQueueElt * nextP; - + for (p = queueP->headP; p; p = nextP) { nextP = p->nextP; free(p); @@ -720,9 +721,9 @@ cleanPixels(bit ** const pixels, for (thisPix.col = 0; thisPix.col < cols; ++thisPix.col) { if (pixels[thisPix.row][thisPix.col] == foregroundColor && !visited[thisPix.row][thisPix.col]) { - + double nFlipped; - + processBlob(thisPix, pixels, cols, rows, trivialSize, visited, &nFlipped); @@ -772,7 +773,7 @@ cleanExtended(FILE * const ifP, static void pbmclean(FILE * const ifP, FILE * const ofP, - struct cmdlineInfo const cmdline, + struct CmdlineInfo const cmdline, double * const nFlippedP) { if (cmdline.extended) { @@ -791,7 +792,7 @@ pbmclean(FILE * const ifP, int main(int argc, const char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; double nFlipped; /* Number of pixels we have flipped so far. Use type double to diff --git a/editor/pbmmask.c b/editor/pbmmask.c index 25c71226..0be10435 100644 --- a/editor/pbmmask.c +++ b/editor/pbmmask.c @@ -10,13 +10,57 @@ ** implied warranty. */ +#include <stdbool.h> +#include <assert.h> + #include "pbm.h" +#include "shhopt.h" #include "mallocvar.h" -static bit ** bits; -static bit ** mask; -static bit backcolor; -static int rows, cols; +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + unsigned int expand; +}; + + + +static void +parseCommandLine(int argc, const char ** 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. +-----------------------------------------------------------------------------*/ + optStruct3 opt; /* set by OPTENT3 */ + optEntry * option_def; + unsigned int option_def_index; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "expand", OPT_FLAG, NULL, &cmdlineP->expand, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We sort of allow negative numbers as parms */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + free(option_def); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("You specified too many arguments (%u). The only " + "possible argument is the optional input file specification.", + argc-1); +} @@ -28,25 +72,78 @@ static int fstackp = 0; static void -addflood(int const col, - int const row) { +clearMask(bit ** const mask, + unsigned int const cols, + unsigned int const rows) { + + /* Clear out the mask. */ + unsigned int row; - if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK ) { - if ( fstackp >= fstacksize ) { - if ( fstacksize == 0 ) { + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) + mask[row][col] = PBM_BLACK; + } +} + + + +static bit +backcolorFmImage(bit ** const bits, + unsigned int const cols, + unsigned int const rows) { + + /* Figure out the background color, by counting along the edge. */ + + unsigned int row; + unsigned int col; + unsigned int wcount; + + assert(cols > 0); assert(rows > 0); + + wcount = 0; + for (row = 0; row < rows; ++row) { + if (bits[row][0] == PBM_WHITE) + ++wcount; + if (bits[row][cols - 1] == PBM_WHITE) + ++wcount; + } + for (col = 1; col < cols - 1; ++col) { + if (bits[0][col] == PBM_WHITE) + ++wcount; + if (bits[rows - 1][col] == PBM_WHITE) + ++wcount; + } + + return (wcount >= rows + cols - 2) ? PBM_WHITE : PBM_BLACK; +} + + + +static void +addflood(bit ** const bits, + bit ** const mask, + unsigned int const col, + unsigned int const row, + bit const backcolor) { + + if (bits[row][col] == backcolor && mask[row][col] == PBM_BLACK) { + if (fstackp >= fstacksize) { + if (fstacksize == 0) { fstacksize = 1000; MALLOCARRAY(fcols, fstacksize); MALLOCARRAY(frows, fstacksize); - if ( fcols == NULL || frows == NULL ) - pm_error( "out of memory" ); + if (fcols == NULL || frows == NULL) + pm_error("out of memory"); } else { fstacksize *= 2; fcols = (short*) realloc( - (char*) fcols, fstacksize * sizeof(short) ); + (char*) fcols, fstacksize * sizeof(short)); frows = (short*) realloc( - (char*) frows, fstacksize * sizeof(short) ); - if ( fcols == (short*) 0 || frows == (short*) 0 ) - pm_error( "out of memory" ); + (char*) frows, fstacksize * sizeof(short)); + if (fcols == (short*) 0 || frows == (short*)0) + pm_error("out of memory"); } } fcols[fstackp] = col; @@ -58,46 +155,81 @@ addflood(int const col, static void -flood(void) { +floodEdge(bit ** const bits, + unsigned int const cols, + unsigned int const rows, + bit const backcolor, + bit ** const mask) { + + int col; + int row; + + /* Flood the entire edge. Probably the first call will be enough, but + might as well be sure. + */ + assert(cols > 0); assert(rows > 0); + + for (col = cols - 3; col >= 2; col -= 2) { + addflood(bits, mask, col, rows - 1, backcolor); + addflood(bits, mask, col, 0, backcolor); + } + for (row = rows - 1; row >= 0; row -= 2) { + addflood(bits, mask, cols - 1, row, backcolor); + addflood(bits, mask, 0, row, backcolor); + } +} + + + +static void +flood(bit ** const bits, + unsigned int const cols, + unsigned int const rows, + bit const backcolor, + bit ** const mask) { + + assert(cols > 0); assert(rows > 0); - while ( fstackp > 0 ) { + floodEdge(bits, cols, rows, backcolor, mask); + + while (fstackp > 0) { int col, row; --fstackp; col = fcols[fstackp]; row = frows[fstackp]; - if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK ) { + if (bits[row][col] == backcolor && mask[row][col] == PBM_BLACK) { int c; mask[row][col] = PBM_WHITE; - if ( row - 1 >= 0 ) - addflood( col, row - 1 ); - if ( row + 1 < rows ) - addflood( col, row + 1 ); - for ( c = col + 1; c < cols; ++c ) { - if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK ) { + if (row - 1 >= 0) + addflood(bits, mask, col, row - 1, backcolor); + if (row + 1 < rows) + addflood(bits, mask, col, row + 1, backcolor); + for (c = col + 1; c < cols; ++c) { + if (bits[row][c] == backcolor && mask[row][c] == PBM_BLACK) { mask[row][c] = PBM_WHITE; - if ( row - 1 >= 0 && - ( bits[row - 1][c - 1] != backcolor || - mask[row - 1][c - 1] != PBM_BLACK ) ) - addflood( c, row - 1 ); - if ( row + 1 < rows && - ( bits[row + 1][c - 1] != backcolor || - mask[row + 1][c - 1] != PBM_BLACK ) ) - addflood( c, row + 1 ); + if (row - 1 >= 0 && + (bits[row - 1][c - 1] != backcolor || + mask[row - 1][c - 1] != PBM_BLACK)) + addflood(bits, mask, c, row - 1, backcolor); + if (row + 1 < rows && + (bits[row + 1][c - 1] != backcolor || + mask[row + 1][c - 1] != PBM_BLACK)) + addflood(bits, mask, c, row + 1, backcolor); } else break; } - for ( c = col - 1; c >= 0; --c ) { - if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK ) { + for (c = col - 1; c >= 0; --c) { + if (bits[row][c] == backcolor && mask[row][c] == PBM_BLACK) { mask[row][c] = PBM_WHITE; - if ( row - 1 >= 0 && - ( bits[row - 1][c + 1] != backcolor || - mask[row - 1][c + 1] != PBM_BLACK ) ) - addflood( c, row - 1 ); - if ( row + 1 < rows && - ( bits[row + 1][c + 1] != backcolor || - mask[row + 1][c + 1] != PBM_BLACK ) ) - addflood( c, row + 1 ); + if (row - 1 >= 0 && + (bits[row - 1][c + 1] != backcolor || + mask[row - 1][c + 1] != PBM_BLACK)) + addflood(bits, mask, c, row - 1, backcolor); + if (row + 1 < rows && + (bits[row + 1][c + 1] != backcolor || + mask[row + 1][c + 1] != PBM_BLACK)) + addflood(bits, mask, c, row + 1, backcolor); } else break; } @@ -107,121 +239,103 @@ flood(void) { -int -main(int argc, char * argv[]) { - - FILE* ifp; - int argn, expand, wcount; - register int row, col; - const char* const usage = "[-expand] [pbmfile]"; - - pbm_init( &argc, argv ); - - argn = 1; - expand = 0; - - if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-expand", 2 ) ) - expand = 1; - else if ( pm_keymatch( argv[argn], "-noexpand", 2 ) ) - expand = 0; - else - pm_usage( usage ); - ++argn; - } +static bit ** +expandedByOnePixel(bit ** const mask, + unsigned int const cols, + unsigned int const rows) { - if ( argn == argc ) - ifp = stdin; - else - { - ifp = pm_openr( argv[argn] ); - ++argn; + /* Expand by one pixel. */ + + bit ** const emask = pbm_allocarray(cols, rows); + + unsigned int row; + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) + if (mask[row][col] == PBM_BLACK) + emask[row][col] = PBM_BLACK; + else { + unsigned int srow; + + emask[row][col] = PBM_WHITE; + + for (srow = row - 1; srow <= row + 1; ++srow) { + unsigned int scol; + + for (scol = col - 1; scol <= col + 1; ++scol) { + if (srow >= 0 && srow < rows && + scol >= 0 && scol < cols && + mask[srow][scol] == PBM_BLACK) { + + emask[row][col] = PBM_BLACK; + break; + } + } + } + } } + return emask; +} + + - if ( argn != argc ) - pm_usage( usage ); +static void +pbmmask(FILE * const ifP, + FILE * const ofP, + struct CmdlineInfo const cmdline) { + + int cols, rows; + bit ** mask; + bit ** bits; + bit backcolor; - bits = pbm_readpbm( ifp, &cols, &rows ); + bits = pbm_readpbm(ifP, &cols, &rows); if (cols == 0 || rows == 0) pm_error("Image contains no pixels, so there is no such thing " "as background and foreground"); - pm_close( ifp ); - mask = pbm_allocarray( cols, rows ); + mask = pbm_allocarray(cols, rows); - /* Clear out the mask. */ - for ( row = 0; row < rows; ++row ) - for ( col = 0; col < cols; ++col ) - mask[row][col] = PBM_BLACK; + clearMask(mask, cols, rows); - /* Figure out the background color, by counting along the edge. */ - wcount = 0; - for ( row = 0; row < rows; ++row ) { - if ( bits[row][0] == PBM_WHITE ) - ++wcount; - if ( bits[row][cols - 1] == PBM_WHITE ) - ++wcount; - } - for ( col = 1; col < cols - 1; ++col ) { - if ( bits[0][col] == PBM_WHITE ) - ++wcount; - if ( bits[rows - 1][col] == PBM_WHITE ) - ++wcount; - } - if ( wcount >= rows + cols - 2 ) - backcolor = PBM_WHITE; - else - backcolor = PBM_BLACK; + backcolor = backcolorFmImage(bits, cols, rows); - /* Flood the entire edge. Probably the first call will be enough, but - might as well be sure. - */ - for ( col = cols - 3; col >= 2; col -= 2 ) { - addflood( col, rows - 1 ); - addflood( col, 0 ); - } - for ( row = rows - 1; row >= 0; row -= 2 ) { - addflood( cols - 1, row ); - addflood( 0, row ); - } - flood( ); + flood(bits, cols, rows, backcolor, mask); - if ( ! expand ) + if (!cmdline.expand) { /* Done. */ - pbm_writepbm( stdout, mask, cols, rows, 0 ); - else { - /* Expand by one pixel. */ - int srow, scol; - unsigned int row; - bit ** emask; - - emask = pbm_allocarray( cols, rows ); - - for ( row = 0; row < rows; ++row ) { - unsigned int col; - for ( col = 0; col < cols; ++col ) - if ( mask[row][col] == PBM_BLACK ) - emask[row][col] = PBM_BLACK; - else { - emask[row][col] = PBM_WHITE; - for ( srow = row - 1; srow <= row + 1; ++srow ) - for ( scol = col - 1; scol <= col + 1; ++scol ) - if ( srow >= 0 && srow < rows && - scol >= 0 && scol < cols && - mask[srow][scol] == PBM_BLACK ) { - - emask[row][col] = PBM_BLACK; - break; - } - } - } - pbm_writepbm( stdout, emask, cols, rows, 0 ); + pbm_writepbm(stdout, mask, cols, rows, 0); + } else { + bit ** const emask = expandedByOnePixel(mask, cols, rows); + + pbm_writepbm(stdout, emask, cols, rows, 0); + + pbm_freearray(emask, rows); } +} + + + +int +main(int argc, const char ** argv) { - pm_close( stdout ); + struct CmdlineInfo cmdline; + FILE * ifP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbmmask(ifP, stdout, cmdline); + + pm_close(ifP); + pm_close(stdout); return 0; } + diff --git a/editor/pnmremap.c b/editor/pnmremap.c index 59b1e84b..0038f4d7 100644 --- a/editor/pnmremap.c +++ b/editor/pnmremap.c @@ -501,9 +501,10 @@ fserr_init(struct pam * const pamP, static void -floydInitRow(struct pam * const pamP, struct Fserr * const fserrP) { +floydInitRow(struct pam * const pamP, + struct Fserr * const fserrP) { - int col; + unsigned int col; for (col = 0; col < pamP->width + 2; ++col) { unsigned int plane; @@ -571,7 +572,8 @@ floydPropagateErr(struct pam * const pamP, static void -floydSwitchDir(struct pam * const pamP, struct Fserr * const fserrP) { +floydSwitchDir(struct pam * const pamP, + struct Fserr * const fserrP) { unsigned int plane; diff --git a/editor/specialty/pammixinterlace.c b/editor/specialty/pammixinterlace.c index 1392777e..28dace25 100644 --- a/editor/specialty/pammixinterlace.c +++ b/editor/specialty/pammixinterlace.c @@ -2,7 +2,7 @@ pammixinterlace ******************************************************************************* De-interlace an image by merging adjacent rows. - + Copyright (C) 2007 Bruce Guenter, FutureQuest, Inc. Permission to use, copy, modify, and distribute this software and its @@ -37,9 +37,9 @@ clamp(sample const val, static bool -distant(long const above, - long const mid, - long const below) { +distant(int const above, + int const mid, + int const below) { return abs(mid - (above + below) / 2) > abs(above - below); } @@ -60,9 +60,9 @@ filterLinearBlend(tuple * const outputrow, unsigned int plane; for (plane = 0; plane < depth; ++plane) { - long const above = tuplerowWindow[0][col][plane]; - long const mid = tuplerowWindow[1][col][plane]; - long const below = tuplerowWindow[2][col][plane]; + int const above = tuplerowWindow[0][col][plane]; + int const mid = tuplerowWindow[1][col][plane]; + int const below = tuplerowWindow[2][col][plane]; sample out; @@ -70,7 +70,7 @@ filterLinearBlend(tuple * const outputrow, out = (above + mid * 2 + below) / 4; else out = mid; - + outputrow[col][plane] = out; } } @@ -87,23 +87,23 @@ filterFfmpeg(tuple * const outputrow, sample const maxval) { unsigned int col; - + for (col = 0; col < width; ++col) { unsigned int plane; - + for (plane = 0; plane < depth; ++plane) { - long const above = tuplerowWindow[1][col][plane]; - long const mid = tuplerowWindow[2][col][plane]; - long const below = tuplerowWindow[3][col][plane]; + int const above = tuplerowWindow[1][col][plane]; + int const mid = tuplerowWindow[2][col][plane]; + int const below = tuplerowWindow[3][col][plane]; sample out; - + if (!adaptive || distant(above, mid, below)) { - long const a = (- (long)tuplerowWindow[0][col][plane] + int const a = (- (int)tuplerowWindow[0][col][plane] + above * 4 + mid * 2 + below * 4 - - (long)tuplerowWindow[4][col][plane]) / 8; + - (int)tuplerowWindow[4][col][plane]) / 8; out = clamp(a, maxval); } else out = mid; @@ -130,22 +130,22 @@ filterFIR(tuple * const outputrow, for (plane = 0; plane < depth; ++plane) { - long const above = tuplerowWindow[1][col][plane]; - long const mid = tuplerowWindow[2][col][plane]; - long const below = tuplerowWindow[3][col][plane]; + int const above = tuplerowWindow[1][col][plane]; + int const mid = tuplerowWindow[2][col][plane]; + int const below = tuplerowWindow[3][col][plane]; sample out; if (!adaptive || distant(above, mid, below)) { - long const a = (- (long)tuplerowWindow[0][col][plane] + int const a = (- (int)tuplerowWindow[0][col][plane] + above * 2 + mid * 6 + below * 2 - - (long)tuplerowWindow[4][col][plane]) / 8; + - (int)tuplerowWindow[4][col][plane]) / 8; out = clamp(a, maxval); } else out = mid; - + outputrow[col][plane] = out; } } @@ -218,7 +218,7 @@ parseCommandLine(int argc, char ** argv, if (!cmdlineP->filterP) pm_error("The filter name '%s' is not known.", filterName); } - + if (argc-1 < 1) cmdlineP->inputFileName = "-"; else if (argc-1 == 1) @@ -280,12 +280,12 @@ main(int argc, char *argv[]) { FILE * ifP; struct cmdlineInfo cmdline; - struct pam inpam; + struct pam inpam; struct pam outpam; tuple * tuplerowWindow[5]; tuple * outputrow; unsigned int rows; - + pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -293,7 +293,7 @@ main(int argc, char *argv[]) { rows = cmdline.filterP->rows; ifP = pm_openr(cmdline.inputFileName); - + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); outpam = inpam; /* Initial value -- most fields should be same */ @@ -328,10 +328,10 @@ main(int argc, char *argv[]) { inpam.width, inpam.depth, cmdline.adaptive, inpam.maxval); pnm_writepamrow(&outpam, outputrow); - + slideWindowDown(tuplerowWindow, rows); } - + /* Pass through last rows */ for (row = rows/2; row < rows-1; ++row) pnm_writepamrow(&outpam, tuplerowWindow[row]); @@ -341,6 +341,9 @@ main(int argc, char *argv[]) { pnm_freepamrow(outputrow); pm_close(inpam.file); pm_close(outpam.file); - + return 0; } + + + |