From a795e001646b249b311348df2da83f1bb1444976 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 16 May 2009 23:20:52 +0000 Subject: Release 10.35.64 git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@923 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- Makefile.version | 2 +- converter/other/giftopnm.c | 7 +- doc/HISTORY | 17 +++++ editor/pnmremap.c | 155 +++++++++++++++++++++++++++++++-------------- generator/ppmpat.c | 13 ++-- lib/libppmd.c | 86 ++++++++++++++++++++++--- 6 files changed, 218 insertions(+), 62 deletions(-) diff --git a/Makefile.version b/Makefile.version index a1f06d84..4e5d5ba7 100644 --- a/Makefile.version +++ b/Makefile.version @@ -1,3 +1,3 @@ NETPBM_MAJOR_RELEASE = 10 NETPBM_MINOR_RELEASE = 35 -NETPBM_POINT_RELEASE = 63 +NETPBM_POINT_RELEASE = 64 diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c index d3d02fde..7337960c 100644 --- a/converter/other/giftopnm.c +++ b/converter/other/giftopnm.c @@ -514,9 +514,14 @@ doGetCode(FILE * const ifP, struct getCodeState * const gsP, int * const retvalP) { - if ((gsP->curbit+codeSize) > gsP->bufCount*8 && !gsP->streamExhausted) + while (gsP->curbit + codeSize > gsP->bufCount * 8 && + !gsP->streamExhausted) /* Not enough left in buffer to satisfy request. Get the next data block into the buffer. + + Note that a data block may be as small as one byte, so we may need + to do this multiple times to get the full code. (This probably + never happens in practice). */ getAnotherBlock(ifP, gsP); diff --git a/doc/HISTORY b/doc/HISTORY index dff0a79b..5913f93c 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -4,6 +4,23 @@ Netpbm. CHANGE HISTORY -------------- +09.05.16 BJH Release 10.35.64 + + pnmremap: fix: -firstisdefault uses an arbitrary color from the + map as default. + + pnmremap: fix -missingcolor: where map file (ergo output) is not + depth 3, uses an arbitrary color. + + giftopnm: fix for unlikely case of a block smaller than a code. + + ppmpat: fix crash in -squig. + + ppmpat: fix crash when width or height is zero. + + libppmd (ppmdraw, ppmpat): Fix bugs with coordinates too large. + Thanks Prophet of the Way . + 09.04.28 BJH Release 10.35.63 ximtoppm: fix crash in command line processing. diff --git a/editor/pnmremap.c b/editor/pnmremap.c index 6e7651d8..1ed07fdb 100644 --- a/editor/pnmremap.c +++ b/editor/pnmremap.c @@ -623,7 +623,6 @@ convertRow(struct pam * const pamP, tuplehash const colorhash, bool * const usehashP, bool const floyd, - enum missingMethod const missingMethod, tuple const defaultColor, struct fserr * const fserrP, unsigned int * const missingCountP) { @@ -668,7 +667,7 @@ convertRow(struct pam * const pamP, floydAdjustColor(pamP, tuplerow[col], fserrP, col); lookupThroughHash(pamP, tuplerow[col], - missingMethod != MISSING_CLOSE, colorFinderP, + !!defaultColor, colorFinderP, colorhash, &colormapIndex, usehashP); if (floyd) floydPropagateErr(pamP, fserrP, col, tuplerow[col], @@ -676,16 +675,10 @@ convertRow(struct pam * const pamP, if (colormapIndex == -1) { ++*missingCountP; - switch (missingMethod) { - case MISSING_SPECIFIED: - pnm_assigntuple(pamP, tuplerow[col], defaultColor); - break; - case MISSING_FIRST: - pnm_assigntuple(pamP, tuplerow[col], colormap[0]->tuple); - break; - default: - pm_error("Internal error: invalid value of missingMethod"); - } + + assert(defaultColor); // Otherwise, lookup would have succeeded + + pnm_assigntuple(pamP, tuplerow[col], defaultColor); } else pnm_assigntuple(pamP, tuplerow[col], colormap[colormapIndex]->tuple); @@ -708,7 +701,6 @@ copyRaster(struct pam * const inpamP, tupletable const colormap, unsigned int const colormapSize, bool const floyd, - enum missingMethod const missingMethod, tuple const defaultColor, unsigned int * const missingCountP) { @@ -719,7 +711,7 @@ copyRaster(struct pam * const inpamP, tuple * tuplerow = pnm_allocpamrow(inpamP); int row; - if (outpamP->maxval != inpamP->maxval && missingMethod != MISSING_CLOSE) + if (outpamP->maxval != inpamP->maxval && defaultColor) pm_error("The maxval of the colormap (%u) is not equal to the " "maxval of the input image (%u). This is allowable only " "if you are doing an approximate mapping (i.e. you don't " @@ -752,7 +744,7 @@ copyRaster(struct pam * const inpamP, */ convertRow(outpamP, tuplerow, colormap, colorFinderP, colorhash, &usehash, - floyd, missingMethod, defaultColor, &fserr, &missingCount); + floyd, defaultColor, &fserr, &missingCount); *missingCountP += missingCount; @@ -766,22 +758,33 @@ copyRaster(struct pam * const inpamP, static void -remap(FILE * const ifP, +remap(FILE * const ifP, const struct pam * const outpamCommonP, tupletable const colormap, unsigned int const colormapSize, bool const floyd, - enum missingMethod const missingMethod, tuple const defaultColor, bool const verbose) { +/*---------------------------------------------------------------------------- + Remap the pixels from the raster on *ifP to the 'colormapSize' colors in + 'colormap'. + Where the input pixel's color is in the map, just use that for the output. + Where it isn't, use 'defaultColor', except if that is NULL, use the + closest color in the map to the input color. + + But if 'floyd' is true and 'defaultColor' is NULL, also do Floyd-Steinberg + dithering on the output so the aggregate color of a region is about the + same as that of the input even though the individual pixels have different + colors. +-----------------------------------------------------------------------------*/ bool eof; eof = FALSE; while (!eof) { struct pam inpam, outpam; unsigned int missingCount; - /* Number of pixels that were not matched in the color map (where - missingMethod is MISSING_CLOSE, this is always zero). + /* Number of pixels that were mapped to 'defaultColor' because + they weren't present in the color map. */ pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(allocation_depth)); @@ -798,7 +801,7 @@ remap(FILE * const ifP, pnm_setminallocationdepth(&inpam, outpam.depth); copyRaster(&inpam, &outpam, colormap, colormapSize, floyd, - missingMethod, defaultColor, &missingCount); + defaultColor, &missingCount); if (verbose) pm_message("%u pixels not matched in color map", missingCount); @@ -809,6 +812,64 @@ remap(FILE * const ifP, +static void +processMapFile(const char * const mapFileName, + struct pam * const outpamCommonP, + tupletable * const colormapP, + unsigned int * const colormapSizeP, + tuple * const firstColorP) { + + FILE * mapfile; + struct pam mappam; + tuple ** maptuples; + tuple firstColor; + + mapfile = pm_openr(mapFileName); + maptuples = pnm_readpam(mapfile, &mappam, PAM_STRUCT_SIZE(tuple_type)); + pm_close(mapfile); + + computeColorMapFromMap(&mappam, maptuples, colormapP, colormapSizeP); + + firstColor = pnm_allocpamtuple(&mappam); + pnm_assigntuple(&mappam, firstColor, maptuples[0][0]); + *firstColorP = firstColor; + + pnm_freepamarray(maptuples, &mappam); + + *outpamCommonP = mappam; + outpamCommonP->file = stdout; +} + + + +static void +getSpecifiedMissingColor(struct pam * const pamP, + const char * const colorName, + tuple * const specColorP) { + + tuple specColor; + + specColor = pnm_allocpamtuple(pamP); + + if (colorName) { + pixel const color = ppm_parsecolor(colorName, pamP->maxval); + if (pamP->depth == 3) { + specColor[PAM_RED_PLANE] = PPM_GETR(color); + specColor[PAM_GRN_PLANE] = PPM_GETG(color); + specColor[PAM_BLU_PLANE] = PPM_GETB(color); + } else if (pamP->depth == 1) { + specColor[0] = PPM_LUMIN(color); + } else { + pm_error("You may not use -missing with a colormap that is not " + "of depth 1 or 3. Yours has depth %u", + pamP->depth); + } + } + *specColorP = specColor; +} + + + int main(int argc, char * argv[] ) { @@ -822,9 +883,17 @@ main(int argc, char * argv[] ) { */ tupletable colormap; unsigned int colormapSize; + tuple specColor; + /* A tuple of the color the user specified to use for input colors + that are not in the colormap. Arbitrary tuple if he didn't + specify any. + */ + tuple firstColor; + /* A tuple of the first color present in the map file */ tuple defaultColor; - /* A tuple of the color that should replace any input color that is - not in the colormap, if we're doing MISSING_SPECIFIED. + /* The color to which we will map an input color that is not in the + colormap. NULL if we are not to map such a color to a particular + color (i.e. we'll choose an approximate match from the map). */ pnm_init(&argc, argv); @@ -832,36 +901,30 @@ main(int argc, char * argv[] ) { parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); - { - FILE * mapfile; - struct pam mappam; - tuple ** maptuples; - - mapfile = pm_openr(cmdline.mapFilespec); - maptuples = pnm_readpam(mapfile, &mappam, PAM_STRUCT_SIZE(tuple_type)); - pm_close(mapfile); - - computeColorMapFromMap(&mappam, maptuples, &colormap, &colormapSize); - pnm_freepamarray(maptuples, &mappam); - - outpamCommon = mappam; - outpamCommon.file = stdout; - } - defaultColor = pnm_allocpamtuple(&outpamCommon); - if (cmdline.missingcolor && outpamCommon.depth == 3) { - pixel const color = - ppm_parsecolor(cmdline.missingcolor, outpamCommon.maxval); - defaultColor[PAM_RED_PLANE] = PPM_GETR(color); - defaultColor[PAM_GRN_PLANE] = PPM_GETG(color); - defaultColor[PAM_BLU_PLANE] = PPM_GETB(color); + processMapFile(cmdline.mapFilespec, &outpamCommon, + &colormap, &colormapSize, &firstColor); + + getSpecifiedMissingColor(&outpamCommon, cmdline.missingcolor, &specColor); + + switch (cmdline.missingMethod) { + case MISSING_CLOSE: + defaultColor = NULL; + break; + case MISSING_FIRST: + defaultColor = firstColor; + break; + case MISSING_SPECIFIED: + defaultColor = specColor; + break; } remap(ifP, &outpamCommon, colormap, colormapSize, - cmdline.floyd, cmdline.missingMethod, defaultColor, + cmdline.floyd, defaultColor, cmdline.verbose); - pnm_freepamtuple(defaultColor); + pnm_freepamtuple(firstColor); + pnm_freepamtuple(specColor); pm_close(stdout); diff --git a/generator/ppmpat.c b/generator/ppmpat.c index f4190d6c..9e2f6d05 100644 --- a/generator/ppmpat.c +++ b/generator/ppmpat.c @@ -770,7 +770,7 @@ squig( pixels, cols, rows, maxval ) x1 = rand() % cols; y1 = 0; if ( x1 < cols / 2 ) - xc[0] = rand() % ( x1 * 2 ); + xc[0] = rand() % ( x1 * 2 + 1); else xc[0] = cols - 1 - rand() % ( ( cols - x1 ) * 2 ); yc[0] = rand() % rows; @@ -788,7 +788,7 @@ squig( pixels, cols, rows, maxval ) x2 = rand() % cols; y2 = 0; if ( x2 < cols / 2 ) - xc[SQ_POINTS - 1] = rand() % ( x2 * 2 ); + xc[SQ_POINTS - 1] = rand() % ( x2 * 2 + 1); else xc[SQ_POINTS - 1] = cols - 1 - rand() % ( ( cols - x2 ) * 2 ); yc[SQ_POINTS - 1] = rand() % rows; @@ -807,7 +807,7 @@ squig( pixels, cols, rows, maxval ) y1 = rand() % rows; xc[0] = rand() % cols; if ( y1 < rows / 2 ) - yc[0] = rand() % ( y1 * 2 ); + yc[0] = rand() % ( y1 * 2 + 1); else yc[0] = rows - 1 - rand() % ( ( rows - y1 ) * 2 ); x2 = cols - 1; @@ -825,7 +825,7 @@ squig( pixels, cols, rows, maxval ) y2 = rand() % rows; xc[SQ_POINTS - 1] = rand() % cols; if ( y2 < rows / 2 ) - yc[SQ_POINTS - 1] = rand() % ( y2 * 2 ); + yc[SQ_POINTS - 1] = rand() % ( y2 * 2 + 1); else yc[SQ_POINTS - 1] = rows - 1 - rand() % ( ( rows - y2 ) * 2 ); x1 = cols - 1; @@ -1006,6 +1006,11 @@ main(int argc, char ** argv) { if ( argn != argc ) pm_usage( usage); + if (cols < 1) + pm_error("width must be at least 1"); + if (rows < 1) + pm_error("height must be at least 1"); + srand( (int) ( time( 0 ) ^ getpid( ) ) ); pixels = ppm_allocarray( cols, rows ); diff --git a/lib/libppmd.c b/lib/libppmd.c index 6970b9f7..892794a5 100644 --- a/lib/libppmd.c +++ b/lib/libppmd.c @@ -26,13 +26,43 @@ #include "ppmdraw.h" -#define DDA_SCALE 8192 struct penpos { int x; int y; }; +static long int const DDA_SCALE = 8192; + +#define PPMD_MAXCOORD 32767 +/* + Several factors govern the limit of x, y coordination values. + + The limit must be representable as (signed) int for coordinates to + be carried in struct penpos (immediately above). + + The following calculation, done with long ints, must not overflow: + cy0 = cy0 + (y1 - cy0) * (cols - 1 - cx0) / (x1 - cx0); + + The following must not overflow when DDA_SCALE is set to 8092: + dy = (y1 - y0) * DDA_SCALE / abs(x1 - x0); + + Overflow conditions for ppmd_text are rather complicated, for commands + come from an external PPMD font file. See comments below. +*/ + + + +static void +ppmd_validateCoords(int const x, + int const y) { + + if (x < -PPMD_MAXCOORD || x > PPMD_MAXCOORD) + pm_error("x coordinate out of bounds: %d", x); + + if (y < -PPMD_MAXCOORD || y > PPMD_MAXCOORD) + pm_error("y coordinate out of bounds: %d", y); +} @@ -460,6 +490,10 @@ ppmd_line(pixel ** const pixels, int cx0, cy0, cx1, cy1; bool noLine; /* There's no line left after clipping */ + ppmd_validateCoords(cols, rows); + ppmd_validateCoords(x0, y0); + ppmd_validateCoords(x1, y1); + if (lineclip) { clipLine(x0, y0, x1, y1, cols, rows, &cx0, &cy0, &cx1, &cy1, &noLine); } else { @@ -610,13 +644,31 @@ ppmd_circle(pixel ** const pixels, int x0, y0, x, y, prevx, prevy, nopointsyet; long sx, sy, e; + if (radius < 0) + pm_error("Error drawing circle. Radius must be positive: %d", radius); + else if (radius == 0) + return; + else if (radius >= DDA_SCALE) + pm_error("Error drawing circle. Radius too large: %d", radius); + + ppmd_validateCoords(cx + radius, cy + radius); + ppmd_validateCoords(cx - radius, cy - radius); + x0 = x = radius; y0 = y = 0; sx = x * DDA_SCALE + DDA_SCALE / 2; sy = y * DDA_SCALE + DDA_SCALE / 2; e = DDA_SCALE / radius; - drawPoint(drawProc, clientdata, - pixels, cols, rows, maxval, x + cx, y + cy); + + /* If lineclip is on, draw only points within pixmap. + Initial point is 3 o'clock. + If lineclip is off, "draw" all points (by designated drawproc). + */ + + if ((x + cx >= 0 && x + cx < cols && y + cy >= 0 && y + cy < rows) || + !lineclip) + drawPoint(drawProc, clientdata, + pixels, cols, rows, maxval, x + cx, y + cy); nopointsyet = 1; do { @@ -628,8 +680,10 @@ ppmd_circle(pixel ** const pixels, y = sy / DDA_SCALE; if (x != prevx || y != prevy) { nopointsyet = 0; - drawPoint(drawProc, clientdata, - pixels, cols, rows, maxval, x + cx, y + cy); + if ((x + cx >= 0 && x + cx < cols && y + cy >= 0 && y + cy < rows) + || !lineclip) + drawPoint(drawProc, clientdata, + pixels, cols, rows, maxval, x + cx, y + cy); } } while (nopointsyet || x != x0 || y != y0); @@ -641,9 +695,9 @@ ppmd_circle(pixel ** const pixels, typedef struct { - short x; - short y; - short edge; + int x; + int y; + int edge; } coord; typedef struct fillobj { @@ -736,6 +790,8 @@ ppmd_fill_drawproc(pixel** const pixels, REALLOCARRAY(fh->coords, fh->size); if (fh->coords == NULL) pm_error( "out of memory enlarging a fillhandle" ); + + ocp = &(fh->coords[fh->n - 1]); } /* Check for extremum and set the edge number. */ @@ -756,12 +812,14 @@ ppmd_fill_drawproc(pixel** const pixels, /* Oops, first edge and last edge are the same. Renumber the first edge in the old segment. */ + const coord * const fcpLast= &(fh->coords[fh->n -1]); coord * fcp; + int oldedge; fcp = &(fh->coords[fh->segstart]); oldedge = fcp->edge; - for ( ; fcp->edge == oldedge; ++fcp ) + for (; fcp <= fcpLast && fcp->edge == oldedge ; ++fcp) fcp->edge = ocp->edge; } /* And start new segment. */ @@ -850,12 +908,13 @@ ppmd_fill(pixel ** const pixels, if (fh->startydir == fh->ydir) { /* Oops, first edge and last edge are the same. */ coord * fcp; + const coord * const fcpLast = & (fh->coords[fh->n - 1]); int lastedge, oldedge; lastedge = fh->coords[fh->n - 1].edge; fcp = &(fh->coords[fh->segstart]); oldedge = fcp->edge; - for ( ; fcp->edge == oldedge; ++fcp ) + for ( ; fcp<=fcpLast && fcp->edge == oldedge; ++fcp ) fcp->edge = lastedge; } } @@ -1082,6 +1141,9 @@ drawGlyph(const struct ppmd_glyph * const glyphP, ty1 = ypos + (mx1 * rotsin + my1 * rotcos) / 65536; tx2 = xpos + (mx2 * rotcos - my2 * rotsin) / 65536; ty2 = ypos + (mx2 * rotsin + my2 * rotcos) / 65536; + + ppmd_validateCoords(tx1, ty1); + ppmd_validateCoords(tx2, ty2); ppmd_line(pixels, cols, rows, maxval, tx1, ty1, tx2, ty2, drawProc, clientdata); @@ -1127,6 +1189,8 @@ ppmd_text(pixel** const pixels, int x, y; const char * s; + ppmd_validateCoords(xpos, ypos); + x = y = 0; rotsin = isin(-angle); rotcos = icos(-angle); @@ -1141,6 +1205,8 @@ ppmd_text(pixel** const pixels, const struct ppmd_glyph * const glyphP = &fontP->glyphTable[ch - fontP->header.firstCodePoint]; + ppmd_validateCoords(x, y); + drawGlyph(glyphP, &x, y, pixels, cols, rows, maxval, height, xpos, ypos, rotcos, rotsin, drawProc, clientdata); -- cgit 1.4.1