about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-05-16 23:20:52 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-05-16 23:20:52 +0000
commita795e001646b249b311348df2da83f1bb1444976 (patch)
treec198c7fa0865bda95944cc8a5ae07b60518a7de5
parentdbdc0476c3ed226ccba2750b09e25887ba12b2bb (diff)
downloadnetpbm-mirror-a795e001646b249b311348df2da83f1bb1444976.tar.gz
netpbm-mirror-a795e001646b249b311348df2da83f1bb1444976.tar.xz
netpbm-mirror-a795e001646b249b311348df2da83f1bb1444976.zip
Release 10.35.64
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@923 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--Makefile.version2
-rw-r--r--converter/other/giftopnm.c7
-rw-r--r--doc/HISTORY17
-rw-r--r--editor/pnmremap.c155
-rw-r--r--generator/ppmpat.c13
-rw-r--r--lib/libppmd.c86
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 <afu@wta.att.ne.jp>.
+
 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);