diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/Makefile | 6 | ||||
-rw-r--r-- | editor/pamperspective.c | 1 | ||||
-rw-r--r-- | editor/pamundice.c | 11 | ||||
-rw-r--r-- | editor/pnmcomp.c | 460 | ||||
-rw-r--r-- | editor/pnmconvol.c | 425 | ||||
-rw-r--r-- | editor/pnmmontage.c | 1 | ||||
-rw-r--r-- | editor/ppmcolormask.c | 1 | ||||
-rw-r--r-- | editor/ppmdraw.c | 5 | ||||
-rw-r--r-- | editor/specialty/pnmindex.c | 1 |
9 files changed, 280 insertions, 631 deletions
diff --git a/editor/Makefile b/editor/Makefile index 398c4aea..c163f220 100644 --- a/editor/Makefile +++ b/editor/Makefile @@ -26,7 +26,7 @@ PORTBINARIES = pamaddnoise pambackground pamcomp pamcut \ pbmclean pbmmask pbmpscale pbmreduce \ pgmdeshadow pgmenhance \ pgmmedian \ - pnmalias pnmcat pnmcomp pnmconvol pnmcrop \ + pnmalias pnmcat pnmconvol pnmcrop \ pnmgamma \ pnmhisteq pnminvert pnmmontage \ pnmnlfilt pnmnorm pnmpad pnmpaste \ @@ -94,3 +94,7 @@ install.bin.local: $(PKGDIR)/bin cd $(PKGDIR)/bin ; \ rm -f ppmquantall$(EXE) ; \ $(SYMLINK) pnmquantall ppmquantall +# In August 2014, pamcomp replaced pnmcomp + cd $(PKGDIR)/bin ; \ + rm -f pnmcomp$(EXE) ; \ + $(SYMLINK) pamcomp$(EXE) pnmcomp$(EXE) diff --git a/editor/pamperspective.c b/editor/pamperspective.c index a75e5243..16715c2e 100644 --- a/editor/pamperspective.c +++ b/editor/pamperspective.c @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup is int string.h */ #include <assert.h> diff --git a/editor/pamundice.c b/editor/pamundice.c index 93ce69f1..9a80e46d 100644 --- a/editor/pamundice.c +++ b/editor/pamundice.c @@ -491,7 +491,12 @@ openInStreams(struct pam inpam[], /*---------------------------------------------------------------------------- Open the input files for a single horizontal slice (there's one file for each vertical slice) and read the Netpbm headers from them. Return - the pam structures to describe each. + the pam structures to describe each as inpam[]. + + Open the files for horizontal slice number 'rank', assuming there are + 'fileCount' vertical slices (so open 'fileCount' files). Use + inputFilePattern[] with each rank and file number to compute the name of + each file. -----------------------------------------------------------------------------*/ unsigned int file; @@ -507,7 +512,9 @@ openInStreams(struct pam inpam[], static void closeInFiles(struct pam pam[], unsigned int const fileCount) { - +/*---------------------------------------------------------------------------- + Close the 'fileCount' input file streams represented by pam[]. +-----------------------------------------------------------------------------*/ unsigned int file; for (file = 0; file < fileCount; ++file) diff --git a/editor/pnmcomp.c b/editor/pnmcomp.c deleted file mode 100644 index b782d69d..00000000 --- a/editor/pnmcomp.c +++ /dev/null @@ -1,460 +0,0 @@ -/* +-------------------------------------------------------------------+ */ -/* | 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. | */ -/* +-------------------------------------------------------------------+ */ - -/* - - DON'T ADD NEW FUNCTION TO THIS PROGRAM. ADD IT TO pamcomp.c INSTEAD. - -*/ - - - -#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ -#include <string.h> - -#include "pm_c_util.h" -#include "pnm.h" -#include "shhopt.h" -#include "mallocvar.h" - -enum horizPos {BEYONDLEFT, LEFT, CENTER, RIGHT, BEYONDRIGHT}; -enum vertPos {ABOVE, TOP, MIDDLE, BOTTOM, BELOW}; - - -struct cmdlineInfo { - /* All the information the user supplied in the command line, - in a form easy for the program to use. - */ - const char *underlyingFilespec; /* '-' if stdin */ - const char *overlayFilespec; - const char *alphaFilespec; - const char *outputFilespec; /* '-' if stdout */ - int xoff, yoff; /* value of xoff, yoff options */ - float opacity; - unsigned int alphaInvert; - enum horizPos align; - enum vertPos valign; -}; - - - - -static void -parseCommandLine(int argc, 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. - - 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; - - char *align, *valign; - unsigned int xoffSpec, yoffSpec, alignSpec, valignSpec, opacitySpec, - alphaSpec; - - MALLOCARRAY_NOFAIL(option_def, 100); - - option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "invert", OPT_FLAG, NULL, - &cmdlineP->alphaInvert, 0 ); - OPTENT3(0, "xoff", OPT_INT, &cmdlineP->xoff, - &xoffSpec, 0 ); - OPTENT3(0, "yoff", OPT_INT, &cmdlineP->yoff, - &yoffSpec, 0 ); - OPTENT3(0, "opacity", OPT_FLOAT, &cmdlineP->opacity, - &opacitySpec, 0 ); - OPTENT3(0, "alpha", OPT_STRING, &cmdlineP->alphaFilespec, - &alphaSpec, 0 ); - OPTENT3(0, "align", OPT_STRING, &align, - &alignSpec, 0 ); - OPTENT3(0, "valign", OPT_STRING, &valign, - &valignSpec, 0 ); - - opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - - pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); - /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - - - if (!xoffSpec) - cmdlineP->xoff = 0; - if (!yoffSpec) - cmdlineP->yoff = 0; - if (!alphaSpec) - cmdlineP->alphaFilespec = NULL; - - if (alignSpec) { - if (strcasecmp(align, "BEYONDLEFT") == 0) - cmdlineP->align = BEYONDLEFT; - else if (strcasecmp(align, "LEFT") == 0) - cmdlineP->align = LEFT; - else if (strcasecmp(align, "CENTER") == 0) - cmdlineP->align = CENTER; - else if (strcasecmp(align, "RIGHT") == 0) - cmdlineP->align = RIGHT; - else if (strcasecmp(align, "BEYONDRIGHT") == 0) - cmdlineP->align = BEYONDRIGHT; - else - pm_error("Invalid value for align option: '%s'. Only LEFT, " - "RIGHT, CENTER, BEYONDLEFT, and BEYONDRIGHT are valid.", - align); - } else - cmdlineP->align = LEFT; - - if (valignSpec) { - if (strcasecmp(valign, "ABOVE") == 0) - cmdlineP->valign = ABOVE; - else if (strcasecmp(valign, "TOP") == 0) - cmdlineP->valign = TOP; - else if (strcasecmp(valign, "MIDDLE") == 0) - cmdlineP->valign = MIDDLE; - else if (strcasecmp(valign, "BOTTOM") == 0) - cmdlineP->valign = BOTTOM; - else if (strcasecmp(valign, "BELOW") == 0) - cmdlineP->valign = BELOW; - else - pm_error("Invalid value for valign option: '%s'. Only TOP, " - "BOTTOM, MIDDLE, ABOVE, and BELOW are valid.", - align); - } else - cmdlineP->valign = TOP; - - if (!opacitySpec) - cmdlineP->opacity = 1.0; - - if (argc-1 < 1) - pm_error("Need at least one argument: file specification of the " - "overlay image."); - - cmdlineP->overlayFilespec = argv[1]; - - if (argc-1 >= 2) - cmdlineP->underlyingFilespec = argv[2]; - else - cmdlineP->underlyingFilespec = "-"; - - if (argc-1 >= 3) - cmdlineP->outputFilespec = argv[3]; - else - cmdlineP->outputFilespec = "-"; - - if (argc-1 > 3) - pm_error("Too many arguments. Only acceptable arguments are: " - "overlay image, underlying image, output image"); -} - - - - -static void -warnOutOfFrame( int const originLeft, - int const originTop, - int const overCols, - int const overRows, - int const underCols, - int const underRows ) { - if (originLeft >= underCols) - pm_message("WARNING: the overlay is entirely off the right edge " - "of the underlying image. " - "It will not be visible in the result. The horizontal " - "overlay position you selected is %d, " - "and the underlying image " - "is only %d pixels wide.", originLeft, underCols ); - else if (originLeft + overCols <= 0) - pm_message("WARNING: the overlay is entirely off the left edge " - "of the underlying image. " - "It will not be visible in the result. The horizontal " - "overlay position you selected is %d and the overlay is " - "only %d pixels wide.", originLeft, overCols); - else if (originTop >= underRows) - pm_message("WARNING: the overlay is entirely off the bottom edge " - "of the underlying image. " - "It will not be visible in the result. The vertical " - "overlay position you selected is %d, " - "and the underlying image " - "is only %d pixels high.", originTop, underRows ); - else if (originTop + overRows <= 0) - pm_message("WARNING: the overlay is entirely off the top edge " - "of the underlying image. " - "It will not be visible in the result. The vertical " - "overlay position you selected is %d and the overlay is " - "only %d pixels high.", originTop, overRows); -} - - - -static void -computeOverlayPosition(const int underCols, const int underRows, - const int overCols, const int overRows, - const struct cmdlineInfo cmdline, - int * const originLeftP, - int * const originTopP) { -/*---------------------------------------------------------------------------- - Determine where to overlay the overlay image, based on the options the - user specified and the realities of the image dimensions. - - The origin may be outside the underlying image (so e.g. *originLeftP may - be negative or > image width). That means not all of the overlay image - actually gets used. In fact, there may be no overlap at all. ------------------------------------------------------------------------------*/ - int xalign, yalign; - - switch (cmdline.align) { - case BEYONDLEFT: xalign = -overCols; break; - case LEFT: xalign = 0; break; - case CENTER: xalign = (underCols-overCols)/2; break; - case RIGHT: xalign = underCols - overCols; break; - case BEYONDRIGHT: xalign = underCols; break; - } - switch (cmdline.valign) { - case ABOVE: yalign = -overRows; break; - case TOP: yalign = 0; break; - case MIDDLE: yalign = (underRows-overRows)/2; break; - case BOTTOM: yalign = underRows - overRows; break; - case BELOW: yalign = underRows; break; - } - *originLeftP = xalign + cmdline.xoff; - *originTopP = yalign + cmdline.yoff; - - warnOutOfFrame( *originLeftP, *originTopP, - overCols, overRows, underCols, underRows ); -} - - - -static pixval -composeComponents(pixval const compA, - pixval const compB, - float const distrib, - pixval const maxval) { -/*---------------------------------------------------------------------------- - Compose a single component of each of two pixels, with 'distrib' being - the fraction of 'compA' in the result, 1-distrib the fraction of 'compB'. - - Both inputs are based on a maxval of 'maxval', and so is our result. - - 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 pixval. ------------------------------------------------------------------------------*/ - return MIN(maxval, MAX(0, (int)compA * distrib + - (int)compB * (1.0 - distrib) + - 0.5 - ) - ); -} - - - -static pixel -composePixels(pixel const pixelA, - pixel const pixelB, - float const distrib, - pixval const maxval) { -/*---------------------------------------------------------------------------- - Compose two pixels 'pixelA' and 'pixelB', with 'distrib' being the - fraction of 'pixelA' in the result, 1-distrib the fraction of 'pixelB'. - - Both inputs are based on a maxval of 'maxval', and so is our result. - - 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 pixval. ------------------------------------------------------------------------------*/ - pixel retval; - - pixval const red = - composeComponents(PPM_GETR(pixelA), PPM_GETR(pixelB), distrib, maxval); - pixval const grn = - composeComponents(PPM_GETG(pixelA), PPM_GETG(pixelB), distrib, maxval); - pixval const blu = - composeComponents(PPM_GETB(pixelA), PPM_GETB(pixelB), distrib, maxval); - - PPM_ASSIGN(retval, red, grn, blu); - - return retval; -} - - - -static void -composite(int const originleft, - int const origintop, - pixel ** const overlayImage, - int const overlayCols, - int const overlayRows, - xelval const overlayMaxval, - int const overlayType, - int const cols, - int const rows, - xelval const maxval, - int const type, - gray ** const alpha, - gray const alphaMax, - bool const invertAlpha, - float const opacity, - FILE * const ifp, - FILE * const ofp) { -/*---------------------------------------------------------------------------- - Overlay the overlay image 'overlayImage' onto the underlying image - which is in file 'ifp', and output the composite to file 'ofp'. - - The underlying image file 'ifp' is positioned after its header. The - width, height, format, and maxval of the underlying image are 'cols', - 'rows', 'type', and 'maxval'. - - The width, height, format, and maxval of the overlay image are - overlayCols, overlayRows, overlayType and overlayMaxval. - - 'originleft' and 'origintop' are the coordinates in the underlying - image plane where the top left corner of the overlay image is - to go. It is not necessarily inside the underlying image (in fact, - may be negative). Only the part of the overlay that actually intersects - the underlying image, if any, gets into the output. - - Note that we modify the overlay image 'overlayImage' to change its - format and maxval to the format and maxval of the output. ------------------------------------------------------------------------------*/ - /* otype and oxmaxv are the type and maxval for the composed (output) - image, and are derived from that of the underlying and overlay - images. - */ - int const otype = (overlayType < type) ? type : overlayType; - xelval const omaxv = pm_lcm(maxval, overlayMaxval, 1, PNM_OVERALLMAXVAL); - - int row; - xel *pixelrow; - - pixelrow = pnm_allocrow(cols); - - if (overlayType != otype || overlayMaxval != omaxv) { - pnm_promoteformat(overlayImage, overlayCols, overlayRows, - overlayMaxval, overlayType, omaxv, otype); - } - - pnm_writepnminit(ofp, cols, rows, omaxv, otype, 0); - - for (row = 0; row < rows; ++row) { - int col; - - /* Read a row and convert it to the output type */ - pnm_readpnmrow(ifp, pixelrow, cols, maxval, type); - - if (type != otype || maxval != omaxv) - pnm_promoteformatrow(pixelrow, cols, maxval, type, omaxv, otype); - - /* Now overlay the overlay with alpha (if defined) */ - for (col = 0; col < cols; ++col) { - int const ovlcol = col - originleft; - int const ovlrow = row - origintop; - - double overlayWeight; - - if (ovlcol >= 0 && ovlcol < overlayCols && - ovlrow >= 0 && ovlrow < overlayRows) { - - if (alpha == NULL) { - overlayWeight = opacity; - } else { - double alphaval; - alphaval = - (double)alpha[ovlrow][ovlcol] / (double)alphaMax; - if (invertAlpha) - alphaval = 1.0 - alphaval; - overlayWeight = alphaval * opacity; - } - - pixelrow[col] = composePixels(overlayImage[ovlrow][ovlcol], - pixelrow[col], - overlayWeight, omaxv); - } - } - pnm_writepnmrow(ofp, pixelrow, cols, omaxv, otype, 0); - } - pnm_freerow(pixelrow); -} - - - -int -main(int argc, char *argv[]) { - - FILE *ifp, *ofp; - pixel **image; - int imageCols, imageRows, imageType; - xelval imageMax; - int cols, rows, type; - xelval maxval; - gray **alpha; - int alphaCols, alphaRows; - xelval alphaMax; - struct cmdlineInfo cmdline; - int originLeft, originTop; - - pnm_init(&argc, argv); - - parseCommandLine(argc, argv, &cmdline); - - { /* Read the overlay image into 'image' */ - FILE *fp; - fp = pm_openr(cmdline.overlayFilespec); - image = - pnm_readpnm(fp, &imageCols, &imageRows, &imageMax, &imageType); - pm_close(fp); - } - if (cmdline.alphaFilespec) { - /* Read the alpha mask file into 'alpha' */ - FILE *fp = pm_openr(cmdline.alphaFilespec); - alpha = pgm_readpgm(fp, &alphaCols, &alphaRows, &alphaMax); - pm_close(fp); - - if (imageCols != alphaCols || imageRows != alphaRows) - pm_error("Alpha map and overlay image are not the same size"); - } else - alpha = NULL; - - ifp = pm_openr(cmdline.underlyingFilespec); - - ofp = pm_openw(cmdline.outputFilespec); - - pnm_readpnminit(ifp, &cols, &rows, &maxval, &type); - - computeOverlayPosition(cols, rows, imageCols, imageRows, - cmdline, &originLeft, &originTop); - - composite(originLeft, originTop, - image, imageCols, imageRows, imageMax, imageType, - cols, rows, maxval, type, - alpha, alphaMax, cmdline.alphaInvert, cmdline.opacity, - ifp, ofp); - - pm_close(ifp); - pm_close(ofp); - - /* If the program failed, it previously aborted with nonzero completion - code, via various function calls. - */ - return 0; -} - - diff --git a/editor/pnmconvol.c b/editor/pnmconvol.c index 105f4644..485fa0b8 100644 --- a/editor/pnmconvol.c +++ b/editor/pnmconvol.c @@ -27,6 +27,16 @@ #include "pam.h" + +static sample const +clipSample(sample const unclipped, + sample const maxval) { + + return MIN(maxval, MAX(0, unclipped)); +} + + + static void validateKernelDimensions(unsigned int const width, unsigned int const height) { @@ -67,6 +77,7 @@ struct cmdlineInfo { unsigned int matrixSpec; struct matrixOpt matrix; unsigned int normalize; + unsigned int bias; }; @@ -304,6 +315,7 @@ parseCommandLine(int argc, char ** argv, unsigned int option_def_index; unsigned int matrixfileSpec; const char * matrixOpt; + unsigned int biasSpec; MALLOCARRAY_NOFAIL(option_def, 100); @@ -316,6 +328,8 @@ parseCommandLine(int argc, char ** argv, &cmdlineP->nooffset, 0); OPTENT3(0, "normalize", OPT_FLAG, NULL, &cmdlineP->normalize, 0); + OPTENT3(0, "bias", OPT_UINT, &cmdlineP->bias, + &biasSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -324,6 +338,9 @@ parseCommandLine(int argc, char ** argv, pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + if (!biasSpec) + cmdlineP->bias = 0; + if (matrixfileSpec && cmdlineP->matrixSpec) pm_error("You can't specify by -matrix and -matrixfile"); @@ -375,7 +392,7 @@ parseCommandLine(int argc, char ** argv, -struct convKernel { +struct ConvKernel { unsigned int cols; /* Width of the convolution window */ unsigned int rows; @@ -393,12 +410,18 @@ struct convKernel { It can have magnitude greater than or less than one. It can be positive or negative. */ + unsigned int bias; + /* The amount to be added to the linear combination of sample values. + We take a little liberty with the term "convolution kernel" to + include this value, since convolution per se does not involve any + such biasing. + */ }; static void -warnBadKernel(struct convKernel * const convKernelP) { +warnBadKernel(struct ConvKernel * const convKernelP) { float sum[3]; unsigned int plane; @@ -456,7 +479,7 @@ convKernelCreatePnm(struct pam * const cpamP, tuple * const * const ctuples, unsigned int const depth, bool const offsetPnm, - struct convKernel ** const convKernelPP) { + struct ConvKernel ** const convKernelPP) { /*---------------------------------------------------------------------------- Compute the convolution matrix in normalized form from the PGM form 'ctuples'/'cpamP'. Each element of the output matrix is the actual weight @@ -479,7 +502,7 @@ convKernelCreatePnm(struct pam * const cpamP, double const offset = offsetPnm ? - 1.0 : 0.0; unsigned int const planes = MIN(3, depth); - struct convKernel * convKernelP; + struct ConvKernel * convKernelP; unsigned int plane; MALLOCVAR_NOFAIL(convKernelP); @@ -507,13 +530,15 @@ convKernelCreatePnm(struct pam * const cpamP, } } } + convKernelP->bias = 0; + *convKernelPP = convKernelP; } static void -convKernelDestroy(struct convKernel * const convKernelP) { +convKernelDestroy(struct ConvKernel * const convKernelP) { unsigned int plane; @@ -531,7 +556,7 @@ convKernelDestroy(struct convKernel * const convKernelP) { static void -normalizeKernelPlane(struct convKernel * const convKernelP, +normalizeKernelPlane(struct ConvKernel * const convKernelP, unsigned int const plane) { unsigned int row; @@ -563,7 +588,7 @@ normalizeKernelPlane(struct convKernel * const convKernelP, static void -normalizeKernel(struct convKernel * const convKernelP) { +normalizeKernel(struct ConvKernel * const convKernelP) { /*---------------------------------------------------------------------------- Modify *convKernelP by scaling every weight in a plane by the same factor such that the weights in the plane all add up to 1. @@ -580,7 +605,7 @@ static void getKernelPnm(const char * const fileName, unsigned int const depth, bool const offset, - struct convKernel ** const convKernelPP) { + struct ConvKernel ** const convKernelPP) { /*---------------------------------------------------------------------------- Get the convolution kernel from the PNM file named 'fileName'. 'offset' means the PNM convolution matrix is defined in offset form so @@ -613,7 +638,8 @@ static void convKernelCreateMatrixOpt(struct matrixOpt const matrixOpt, bool const normalize, unsigned int const depth, - struct convKernel ** const convKernelPP) { + unsigned int const bias, + struct ConvKernel ** const convKernelPP) { /*---------------------------------------------------------------------------- Create a convolution kernel as described by a -matrix command line option. @@ -625,7 +651,7 @@ convKernelCreateMatrixOpt(struct matrixOpt const matrixOpt, so they may form a biased matrix -- i.e. one which brightens or dims the image overall. -----------------------------------------------------------------------------*/ - struct convKernel * convKernelP; + struct ConvKernel * convKernelP; unsigned int plane; MALLOCVAR(convKernelP); @@ -652,6 +678,8 @@ convKernelCreateMatrixOpt(struct matrixOpt const matrixOpt, if (normalize) normalizeKernel(convKernelP); + convKernelP->bias = bias; + *convKernelPP = convKernelP; } @@ -821,7 +849,8 @@ static void convKernelCreateSimpleFile(const char ** const fileNameList, bool const normalize, unsigned int const depth, - struct convKernel ** const convKernelPP) { + unsigned int const bias, + struct ConvKernel ** const convKernelPP) { /*---------------------------------------------------------------------------- Create a convolution kernel as described by a convolution matrix file. This is the simple file with floating point numbers in it, not the @@ -834,7 +863,7 @@ convKernelCreateSimpleFile(const char ** const fileNameList, so they may form a biased matrix -- i.e. one which brightens or dims the image overall. -----------------------------------------------------------------------------*/ - struct convKernel * convKernelP; + struct ConvKernel * convKernelP; unsigned int fileCt; unsigned int planeCt; unsigned int plane; @@ -887,6 +916,8 @@ convKernelCreateSimpleFile(const char ** const fileNameList, convKernelP->cols = width; convKernelP->rows = height; + convKernelP->bias = bias; + *convKernelPP = convKernelP; } @@ -895,7 +926,7 @@ convKernelCreateSimpleFile(const char ** const fileNameList, static void getKernel(struct cmdlineInfo const cmdline, unsigned int const depth, - struct convKernel ** const convKernelPP) { + struct ConvKernel ** const convKernelPP) { /*---------------------------------------------------------------------------- Figure out what the convolution kernel is. It can come from various sources in various forms, as described on the command line, represented @@ -904,17 +935,17 @@ getKernel(struct cmdlineInfo const cmdline, We generate a kernel object in standard form (free of any indication of where it came from) and return a handle to it as *convKernelPP. ----------------------------------------------------------------------------*/ - struct convKernel * convKernelP; + struct ConvKernel * convKernelP; if (cmdline.pnmMatrixFileName) getKernelPnm(cmdline.pnmMatrixFileName, depth, !cmdline.nooffset, &convKernelP); else if (cmdline.matrixfile) convKernelCreateSimpleFile(cmdline.matrixfile, cmdline.normalize, - depth, &convKernelP); + depth, cmdline.bias, &convKernelP); else if (cmdline.matrixSpec) convKernelCreateMatrixOpt(cmdline.matrix, cmdline.normalize, - depth, &convKernelP); + depth, cmdline.bias, &convKernelP); warnBadKernel(convKernelP); @@ -925,7 +956,7 @@ getKernel(struct cmdlineInfo const cmdline, static void validateEnoughImageToConvolve(const struct pam * const inpamP, - const struct convKernel * const convKernelP) { + const struct ConvKernel * const convKernelP) { /*---------------------------------------------------------------------------- Abort program if the image isn't big enough in both directions to have at least one convolved pixel. @@ -1025,8 +1056,39 @@ readAndScaleRows(struct pam * const inpamP, static void +writePamRowBiased(struct pam * const outpamP, + tuple * const row, + unsigned int const bias) { +/*---------------------------------------------------------------------------- + Write row[] to the output file according to *outpamP, but with + 'bias' added to each sample value, clipped to maxval. +-----------------------------------------------------------------------------*/ + if (bias == 0) + pnm_writepamrow(outpamP, row); + else { + unsigned int col; + + tuple * const outrow = pnm_allocpamrow(outpamP); + + for (col = 0; col < outpamP->width; ++col) { + unsigned int plane; + + for (plane = 0; plane < outpamP->depth; ++plane) { + outrow[col][plane] = + MIN(outpamP->maxval, bias + row[col][plane]); + } + } + pnm_writepamrow(outpamP, outrow); + + pnm_freepamrow(outrow); + } +} + + + +static void writeUnconvolvedTop(struct pam * const outpamP, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, tuple ** const rowbuf) { /*---------------------------------------------------------------------------- Write out the top part that we can't convolve because the convolution @@ -1038,14 +1100,14 @@ writeUnconvolvedTop(struct pam * const outpamP, unsigned int row; for (row = 0; row < convKernelP->rows/2; ++row) - pnm_writepamrow(outpamP, rowbuf[row]); + writePamRowBiased(outpamP, rowbuf[row], convKernelP->bias); } static void writeUnconvolvedBottom(struct pam * const outpamP, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const windowHeight, tuple ** const circMap) { /*---------------------------------------------------------------------------- @@ -1061,7 +1123,7 @@ writeUnconvolvedBottom(struct pam * const outpamP, row < windowHeight; ++row) { - pnm_writepamrow(outpamP, circMap[row]); + writePamRowBiased(outpamP, circMap[row], convKernelP->bias); } } @@ -1093,7 +1155,7 @@ setupCircMap(tuple ** const circMap, static void convolveGeneralRowPlane(struct pam * const pamP, tuple ** const window, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const plane, tuple * const outputrow) { /*---------------------------------------------------------------------------- @@ -1114,7 +1176,10 @@ convolveGeneralRowPlane(struct pam * const pamP, for (col = 0; col < pamP->width; ++col) { if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; + /* The unconvolved left or right edge */ + outputrow[col][plane] = + clipSample(convKernelP->bias + window[crowso2][col][plane], + pamP->maxval); else { unsigned int const leftcol = col - ccolso2; unsigned int crow; @@ -1127,7 +1192,8 @@ convolveGeneralRowPlane(struct pam * const pamP, sum += leftrptr[ccol][plane] * convKernelP->weight[plane][crow][ccol]; } - outputrow[col][plane] = MIN(pamP->maxval, MAX(0, sum + 0.5)); + outputrow[col][plane] = + clipSample(convKernelP->bias + sum + 0.5, pamP->maxval); } } } @@ -1137,7 +1203,7 @@ convolveGeneralRowPlane(struct pam * const pamP, static void convolveGeneral(struct pam * const inpamP, struct pam * const outpamP, - const struct convKernel * const convKernelP) { + const struct ConvKernel * const convKernelP) { /*---------------------------------------------------------------------------- Do the convolution without taking advantage of any useful redundancy in the convolution matrix. @@ -1244,7 +1310,7 @@ freeSum(sample ** const sum, static void computeInitialColumnSums(struct pam * const pamP, tuple ** const window, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, sample ** const convColumnSum) { /*---------------------------------------------------------------------------- Add up the sum of each column of window[][], whose rows are described @@ -1271,7 +1337,7 @@ computeInitialColumnSums(struct pam * const pamP, static void -convolveRowWithColumnSumsMean(const struct convKernel * const convKernelP, +convolveRowWithColumnSumsMean(const struct ConvKernel * const convKernelP, struct pam * const pamP, tuple ** const window, tuple * const outputrow, @@ -1301,30 +1367,32 @@ convolveRowWithColumnSumsMean(const struct convKernel * const convKernelP, unsigned int col; sample gisum; - gisum = 0; - for (col = 0; col < pamP->width; ++col) { - if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; - else if (col == ccolso2) { - unsigned int const leftcol = col - ccolso2; - - unsigned int ccol; - - for (ccol = 0; ccol < convKernelP->cols; ++ccol) - gisum += convColumnSum[plane][leftcol + ccol]; - + for (col = 0, gisum = 0; col < pamP->width; ++col) { + if (col < ccolso2 || col >= pamP->width - ccolso2) { + /* The unconvolved left or right edge */ outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, gisum * weight + 0.5)); + clipSample(convKernelP->bias + + window[crowso2][col][plane], + pamP->maxval); } else { - /* Column numbers to subtract or add to isum */ - unsigned int const subcol = col - ccolso2 - 1; - unsigned int const addcol = col + ccolso2; + if (col == ccolso2) { + unsigned int const leftcol = col - ccolso2; - gisum -= convColumnSum[plane][subcol]; - gisum += convColumnSum[plane][addcol]; + unsigned int ccol; + for (ccol = 0; ccol < convKernelP->cols; ++ccol) + gisum += convColumnSum[plane][leftcol + ccol]; + } else { + /* Column numbers to subtract or add to isum */ + unsigned int const subcol = col - ccolso2 - 1; + unsigned int const addcol = col + ccolso2; + + gisum -= convColumnSum[plane][subcol]; + gisum += convColumnSum[plane][addcol]; + } outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, gisum * weight + 0.5)); + clipSample(convKernelP->bias + gisum * weight + 0.5, + pamP->maxval); } } } @@ -1334,7 +1402,7 @@ convolveRowWithColumnSumsMean(const struct convKernel * const convKernelP, static void convolveRowWithColumnSumsVertical( - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, struct pam * const pamP, tuple ** const window, tuple * const outputrow, @@ -1363,9 +1431,13 @@ convolveRowWithColumnSumsVertical( unsigned int col; for (col = 0; col < pamP->width; ++col) { - if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; - else { + if (col < ccolso2 || col >= pamP->width - ccolso2) { + /* The unconvolved left or right edge */ + outputrow[col][plane] = + clipSample(convKernelP->bias + + window[crowso2][col][plane], + pamP->maxval); + } else { unsigned int const leftcol = col - ccolso2; unsigned int ccol; float sum; @@ -1376,7 +1448,8 @@ convolveRowWithColumnSumsVertical( sum += convColumnSum[plane][leftcol + ccol] * convKernelP->weight[plane][0][ccol]; - outputrow[col][plane] = MIN(pamP->maxval, MAX(0, sum + 0.5)); + outputrow[col][plane] = + clipSample(convKernelP->bias + sum + 0.5, pamP->maxval); } } } @@ -1387,7 +1460,7 @@ convolveRowWithColumnSumsVertical( static void convolveMeanRowPlane(struct pam * const pamP, tuple ** const window, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const plane, tuple * const outputrow, sample * const convColumnSum) { @@ -1417,38 +1490,40 @@ convolveMeanRowPlane(struct pam * const pamP, unsigned int col; sample gisum; - gisum = 0; - for (col = 0; col < pamP->width; ++col) { - if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; - else if (col == ccolso2) { - unsigned int const leftcol = col - ccolso2; - - unsigned int ccol; - - for (ccol = 0; ccol < convKernelP->cols; ++ccol) { - sample * const thisColumnSumP = - &convColumnSum[leftcol + ccol]; - *thisColumnSumP = *thisColumnSumP - - window[subrow][ccol][plane] - + window[addrow][ccol][plane]; - gisum += *thisColumnSumP; - } + for (col = 0, gisum = 0; col < pamP->width; ++col) { + if (col < ccolso2 || col >= pamP->width - ccolso2) { + /* The unconvolved left or right edge */ outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, gisum * weight + 0.5)); + clipSample(convKernelP->bias + window[crowso2][col][plane], + pamP->maxval); } else { - /* Column numbers to subtract or add to isum */ - unsigned int const subcol = col - ccolso2 - 1; - unsigned int const addcol = col + ccolso2; - - convColumnSum[addcol] = convColumnSum[addcol] - - window[subrow][addcol][plane] - + window[addrow][addcol][plane]; + if (col == ccolso2) { + unsigned int const leftcol = col - ccolso2; - gisum = gisum - convColumnSum[subcol] + convColumnSum[addcol]; + unsigned int ccol; + for (ccol = 0; ccol < convKernelP->cols; ++ccol) { + sample * const thisColumnSumP = + &convColumnSum[leftcol + ccol]; + *thisColumnSumP = *thisColumnSumP + - window[subrow][ccol][plane] + + window[addrow][ccol][plane]; + gisum += *thisColumnSumP; + } + } else { + /* Column numbers to subtract or add to isum */ + unsigned int const subcol = col - ccolso2 - 1; + unsigned int const addcol = col + ccolso2; + + convColumnSum[addcol] = convColumnSum[addcol] + - window[subrow][addcol][plane] + + window[addrow][addcol][plane]; + + gisum = gisum - convColumnSum[subcol] + convColumnSum[addcol]; + } outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, gisum * weight + 0.5)); + clipSample(convKernelP->bias + gisum * weight + 0.5, + pamP->maxval); } } } @@ -1457,7 +1532,7 @@ convolveMeanRowPlane(struct pam * const pamP, typedef void convolver(struct pam * const inpamP, struct pam * const outpamP, - const struct convKernel * const convKernelP); + const struct ConvKernel * const convKernelP); @@ -1466,7 +1541,7 @@ static convolver convolveMean; static void convolveMean(struct pam * const inpamP, struct pam * const outpamP, - const struct convKernel * const convKernelP) { + const struct ConvKernel * const convKernelP) { /*---------------------------------------------------------------------------- Mean Convolution @@ -1645,7 +1720,7 @@ freeRowSum(sample *** const sum, static void convolveHorizontalRowPlane0(struct pam * const outpamP, tuple ** const window, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const plane, tuple * const outputrow, sample ** const sumWindow) { @@ -1659,47 +1734,57 @@ convolveHorizontalRowPlane0(struct pam * const outpamP, unsigned int col; for (col = 0; col < outpamP->width; ++col) { - if (col < ccolso2 || col >= outpamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; - else if (col == ccolso2) { - /* This is the first column for which the entire convolution - kernel fits within the image horizontally. I.e. the window - starts at the left edge of the image. - */ - unsigned int const leftcol = 0; - + if (col < ccolso2 || col >= outpamP->width - ccolso2) { + /* The unconvolved left or right edge */ + outputrow[col][plane] = + clipSample(convKernelP->bias + window[crowso2][col][plane], + outpamP->maxval); + } else { float matrixSum; - unsigned int crow; - for (crow = 0, matrixSum = 0.0; crow < convKernelP->rows; ++crow) { - tuple * const tuplesInWindow = &window[crow][leftcol]; + if (col == ccolso2) { + /* This is the first column for which the entire convolution + kernel fits within the image horizontally. I.e. the window + starts at the left edge of the image. + */ + unsigned int const leftcol = 0; + + unsigned int crow; - unsigned int ccol; - - sumWindow[crow][col] = 0; - for (ccol = 0; ccol < convKernelP->cols; ++ccol) - sumWindow[crow][col] += tuplesInWindow[ccol][plane]; - matrixSum += - sumWindow[crow][col] * convKernelP->weight[plane][crow][0]; - } - outputrow[col][plane] = - MIN(outpamP->maxval, MAX(0, matrixSum + 0.5)); - } else { - unsigned int const subcol = col - ccolso2 - 1; - unsigned int const addcol = col + ccolso2; + for (crow = 0, matrixSum = 0.0; + crow < convKernelP->rows; + ++crow) { + tuple * const tuplesInWindow = &window[crow][leftcol]; - float matrixSum; - unsigned int crow; + unsigned int ccol; + + sumWindow[crow][col] = 0; + for (ccol = 0; ccol < convKernelP->cols; ++ccol) + sumWindow[crow][col] += tuplesInWindow[ccol][plane]; + matrixSum += + sumWindow[crow][col] * + convKernelP->weight[plane][crow][0]; + } + } else { + unsigned int const subcol = col - ccolso2 - 1; + unsigned int const addcol = col + ccolso2; - for (crow = 0, matrixSum = 0.0; crow < convKernelP->rows; ++crow) { - sumWindow[crow][col] = sumWindow[crow][col-1] + - + window[crow][addcol][plane] - - window[crow][subcol][plane]; - matrixSum += - sumWindow[crow][col] * convKernelP->weight[plane][crow][0]; + unsigned int crow; + + for (crow = 0, matrixSum = 0.0; + crow < convKernelP->rows; + ++crow) { + sumWindow[crow][col] = sumWindow[crow][col-1] + + + window[crow][addcol][plane] + - window[crow][subcol][plane]; + matrixSum += + sumWindow[crow][col] * + convKernelP->weight[plane][crow][0]; + } } outputrow[col][plane] = - MIN(outpamP->maxval, MAX(0, matrixSum + 0.5)); + clipSample(convKernelP->bias + matrixSum + 0.5, + outpamP->maxval); } } } @@ -1737,7 +1822,7 @@ setupCircMap2(tuple ** const rowbuf, static void convolveHorizontalRowPlane(struct pam * const pamP, tuple ** const window, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const plane, tuple * const outputrow, sample ** const sumWindow) { @@ -1763,14 +1848,16 @@ convolveHorizontalRowPlane(struct pam * const pamP, unsigned int col; for (col = 0; col < pamP->width; ++col) { - if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = window[crowso2][col][plane]; - else if (col == ccolso2) { + float matrixSum; + + if (col < ccolso2 || col >= pamP->width - ccolso2) { + outputrow[col][plane] = + clipSample(convKernelP->bias + window[crowso2][col][plane], + pamP->maxval); + } else if (col == ccolso2) { unsigned int const leftcol = 0; /* Window is up againt left edge of image */ - float matrixSum; - { unsigned int ccol; sumWindow[newrow][col] = 0; @@ -1787,13 +1874,10 @@ convolveHorizontalRowPlane(struct pam * const pamP, convKernelP->weight[plane][crow][0]; } } - outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, matrixSum + 0.5)); } else { unsigned int const subcol = col - ccolso2 - 1; unsigned int const addcol = col + ccolso2; - float matrixSum; unsigned int crow; sumWindow[newrow][col] = @@ -1805,9 +1889,9 @@ convolveHorizontalRowPlane(struct pam * const pamP, matrixSum += sumWindow[crow][col] * convKernelP->weight[plane][crow][0]; } - outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, matrixSum + 0.5)); } + outputrow[col][plane] = + clipSample(convKernelP->bias + matrixSum + 0.5, pamP->maxval); } } @@ -1818,7 +1902,7 @@ static convolver convolveHorizontal; static void convolveHorizontal(struct pam * const inpamP, struct pam * const outpamP, - const struct convKernel * const convKernelP) { + const struct ConvKernel * const convKernelP) { /*---------------------------------------------------------------------------- Horizontal Convolution @@ -1909,7 +1993,7 @@ convolveHorizontal(struct pam * const inpamP, static void convolveVerticalRowPlane(struct pam * const pamP, tuple ** const circMap, - const struct convKernel * const convKernelP, + const struct ConvKernel * const convKernelP, unsigned int const plane, tuple * const outputrow, sample * const convColumnSum) { @@ -1927,45 +2011,54 @@ convolveVerticalRowPlane(struct pam * const pamP, unsigned int col; for (col = 0; col < pamP->width; ++col) { - if (col < ccolso2 || col >= pamP->width - ccolso2) - outputrow[col][plane] = circMap[crowso2][col][plane]; - else if (col == ccolso2) { - unsigned int const leftcol = 0; - /* Convolution window is againt left edge of image */ - - float matrixSum; - unsigned int ccol; - - /* Slide window down in the first kernel's worth of columns */ - for (ccol = 0; ccol < convKernelP->cols; ++ccol) { - convColumnSum[leftcol + ccol] += - circMap[addrow][leftcol + ccol][plane]; - convColumnSum[leftcol + ccol] -= - circMap[subrow][leftcol + ccol][plane]; - } - for (ccol = 0, matrixSum = 0.0; ccol < convKernelP->cols; ++ccol) { - matrixSum += convColumnSum[leftcol + ccol] * - convKernelP->weight[plane][0][ccol]; - } + if (col < ccolso2 || col >= pamP->width - ccolso2) { + /* The unconvolved left or right edge */ outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, matrixSum + 0.5)); + clipSample(convKernelP->bias + circMap[crowso2][col][plane], + pamP->maxval); } else { - unsigned int const leftcol = col - ccolso2; - unsigned int const addcol = col + ccolso2; - float matrixSum; - unsigned int ccol; - /* Slide window down in the column that just entered the window */ - convColumnSum[addcol] += circMap[addrow][addcol][plane]; - convColumnSum[addcol] -= circMap[subrow][addcol][plane]; + if (col == ccolso2) { + unsigned int const leftcol = 0; + /* Convolution window is againt left edge of image */ + + unsigned int ccol; - for (ccol = 0, matrixSum = 0.0; ccol < convKernelP->cols; ++ccol) { - matrixSum += convColumnSum[leftcol + ccol] * - convKernelP->weight[plane][0][ccol]; + /* Slide window down in the first kernel's worth of columns */ + for (ccol = 0; ccol < convKernelP->cols; ++ccol) { + convColumnSum[leftcol + ccol] += + circMap[addrow][leftcol + ccol][plane]; + convColumnSum[leftcol + ccol] -= + circMap[subrow][leftcol + ccol][plane]; + } + for (ccol = 0, matrixSum = 0.0; + ccol < convKernelP->cols; + ++ccol) { + matrixSum += convColumnSum[leftcol + ccol] * + convKernelP->weight[plane][0][ccol]; + } + } else { + unsigned int const leftcol = col - ccolso2; + unsigned int const addcol = col + ccolso2; + + unsigned int ccol; + + /* Slide window down in the column that just entered the + window + */ + convColumnSum[addcol] += circMap[addrow][addcol][plane]; + convColumnSum[addcol] -= circMap[subrow][addcol][plane]; + + for (ccol = 0, matrixSum = 0.0; + ccol < convKernelP->cols; + ++ccol) { + matrixSum += convColumnSum[leftcol + ccol] * + convKernelP->weight[plane][0][ccol]; + } } outputrow[col][plane] = - MIN(pamP->maxval, MAX(0, matrixSum + 0.5)); + clipSample(convKernelP->bias + matrixSum + 0.5, pamP->maxval); } } } @@ -1977,7 +2070,7 @@ static convolver convolveVertical; static void convolveVertical(struct pam * const inpamP, struct pam * const outpamP, - const struct convKernel * const convKernelP) { + const struct ConvKernel * const convKernelP) { /* Uses column sums as in mean convolution, above */ @@ -2058,7 +2151,7 @@ struct convolveType { static bool -convolutionIncludesHorizontal(const struct convKernel * const convKernelP) { +convolutionIncludesHorizontal(const struct ConvKernel * const convKernelP) { bool horizontal; unsigned int row; @@ -2086,7 +2179,7 @@ convolutionIncludesHorizontal(const struct convKernel * const convKernelP) { static bool -convolutionIncludesVertical(const struct convKernel * const convKernelP) { +convolutionIncludesVertical(const struct ConvKernel * const convKernelP) { bool vertical; unsigned int col; @@ -2114,7 +2207,7 @@ convolutionIncludesVertical(const struct convKernel * const convKernelP) { static void -determineConvolveType(const struct convKernel * const convKernelP, +determineConvolveType(const struct ConvKernel * const convKernelP, struct convolveType * const typeP) { /*---------------------------------------------------------------------------- Determine which form of convolution is best to convolve the kernel @@ -2150,7 +2243,7 @@ main(int argc, char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; struct convolveType convolveType; - struct convKernel * convKernelP; + struct ConvKernel * convKernelP; struct pam inpam; struct pam outpam; diff --git a/editor/pnmmontage.c b/editor/pnmmontage.c index 47827610..e54afc45 100644 --- a/editor/pnmmontage.c +++ b/editor/pnmmontage.c @@ -10,6 +10,7 @@ * implied warranty. */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup() is in <string.h> */ #include <assert.h> #include <limits.h> diff --git a/editor/ppmcolormask.c b/editor/ppmcolormask.c index 4e462f3e..31fbff2a 100644 --- a/editor/ppmcolormask.c +++ b/editor/ppmcolormask.c @@ -9,6 +9,7 @@ Contributed to the public domain by its author. =========================================================================*/ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup() is in <string.h> */ #include <assert.h> #include <string.h> diff --git a/editor/ppmdraw.c b/editor/ppmdraw.c index c733ffcb..63d781ec 100644 --- a/editor/ppmdraw.c +++ b/editor/ppmdraw.c @@ -1,5 +1,6 @@ -#define _XOPEN_SOURCE /* Make sure M_PI is in math.h */ -#define _BSD_SOURCE /* Make sure strdup is in string.h */ +#define _XOPEN_SOURCE 500 + /* Make sure M_PI is in math.h, strdup is in string.h */ +#define _BSD_SOURCE /* Make sure strdup is in string.h (alternate) */ #include <string.h> #include <ctype.h> diff --git a/editor/specialty/pnmindex.c b/editor/specialty/pnmindex.c index 1909c93a..4ec9edaa 100644 --- a/editor/specialty/pnmindex.c +++ b/editor/specialty/pnmindex.c @@ -14,6 +14,7 @@ ============================================================================*/ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup is in string.h */ #include <assert.h> |