about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-12-26 09:16:41 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-12-26 09:16:41 +0000
commite15e137ba527ba97c82149ad8c6bed59088d8616 (patch)
treed97d0742d8fa448232faad05a7b40ccc18641b68
parent2d31b9e0a06dde404131dbc2300502bfd2698819 (diff)
downloadnetpbm-mirror-e15e137ba527ba97c82149ad8c6bed59088d8616.tar.gz
netpbm-mirror-e15e137ba527ba97c82149ad8c6bed59088d8616.tar.xz
netpbm-mirror-e15e137ba527ba97c82149ad8c6bed59088d8616.zip
Release 10.73.38
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@4219 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--converter/other/pamtogif.c144
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c22
-rw-r--r--converter/other/sunicontopnm.c20
-rw-r--r--converter/pbm/escp2topbm.c19
-rw-r--r--converter/pbm/mgrtopbm.c50
-rw-r--r--converter/pbm/ybmtopbm.c31
-rw-r--r--doc/HISTORY20
-rw-r--r--editor/pamcut.c4
-rw-r--r--editor/pamrubber.c8
-rw-r--r--editor/pbmpscale.c6
-rw-r--r--editor/pnmcat.c3
-rw-r--r--editor/pnmpad.c2
-rw-r--r--lib/libpbm2.c7
-rw-r--r--version.mk2
14 files changed, 243 insertions, 95 deletions
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index d20fa650..592a0472 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -24,6 +24,13 @@ static bool verbose;
 
 
 typedef int stringCode;
+
+enum TransparencyType {TRANS_NONE, TRANS_COLOR, TRANS_ALPHA};
+    /* The source of transparency for the GIF: nothing is transparent,
+       All pixels of a certain color are transparent, or the alpha plane
+       in the input tells what is transparent.
+    */
+
     /* A code to be place in the GIF raster.  It represents
        a string of one or more pixels.  You interpret this in the context
        of a current code size.  The lower half of the values representable
@@ -89,7 +96,12 @@ struct cmdlineInfo {
 
 static unsigned int
 pamAlphaPlane(struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+   The number of the alpha plane, or zero if there is no alpha plane, as
+   indicated by *pamP.
 
+   Note that the alpha plane is never zero in any Netpbm tuple type.
+-----------------------------------------------------------------------------*/
     unsigned int alphaPlane;
 
     if (streq(pamP->tuple_type, "RGB_ALPHA"))
@@ -440,18 +452,25 @@ gifPixel(struct pam *   const pamP,
          sample         const alphaThreshold, 
          struct cmap *  const cmapP) {
 /*----------------------------------------------------------------------------
-   Return as *colorIndexP the colormap index of the tuple 'tuple',
-   whose format is described by *pamP, using colormap *cmapP.
+   Return the colormap index of the tuple 'tuple', whose format is described
+   by *pamP, using colormap *cmapP.
+
+   'alphaPlane' is the number of the plane in 'tuple' to use for transparency,
+   or zero if we aren't to use any plane for transparency.  (note that Caller
+   cannot specify plane 0 for transparency).
+
+   'alphaThreshold' is the alpha level below which we consider a pixel
+   transparent for GIF purposes.
 
-   'alphaThreshold' is the alpha level below which we consider a
-   pixel transparent for GIF purposes.
+   If 'alphaPlane' is nonzero, we assume *cmapP contains a transparent
+   entry.
 -----------------------------------------------------------------------------*/
     int colorIndex;
 
-    if (alphaPlane && tuple[alphaPlane] < alphaThreshold &&
-        cmapP->haveTransparent)
+    if (alphaPlane && tuple[alphaPlane] < alphaThreshold) {
+        assert(cmapP->haveTransparent);
         colorIndex = cmapP->transparent;
-    else {
+    } else {
         int found;
 
         pnm_lookuptuple(pamP, cmapP->tuplehash, tuple,
@@ -1223,6 +1242,14 @@ writeRaster(struct pam *  const pamP,
    Get the raster to write from 'rowReaderP', which gives tuples whose
    format is described by 'pamP'.
 
+   'alphaPlane' is the number of the plane in the tuples supplied by
+   'rowReaderP' that we should use for transparency information, and
+   'alphaThreshold' is the value in that plane below which we should consider
+   the pixel transparent for GIF purposes.
+
+   'alphaPlane' is zero to indicate we should not use any plane as an alpha
+   plane (so it's not possible to specify Plane 0 as alpha).
+
    Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives
    pixel values as RGB samples; the GIF raster is colormap indices).
 
@@ -1438,8 +1465,13 @@ gifEncode(struct pam *  const pamP,
           struct cmap * const cmapP,
           char          const comment[],
           float         const aspect,
-          bool          const lzw) {
-
+          bool          const lzw,
+          bool          const usingAlpha) {
+/*----------------------------------------------------------------------------
+   'usingAlpha' means use the alpha (transparency) plane, if there is one, to
+   determine which GIF pixels are transparent.  When this is true, the
+   colormap *cmapP must contain a transparent entry.
+-----------------------------------------------------------------------------*/
     unsigned int const leftOffset = 0;
     unsigned int const topOffset  = 0;
 
@@ -1451,7 +1483,7 @@ gifEncode(struct pam *  const pamP,
            pixels in the output image.
         */
 
-    unsigned int const alphaPlane = pamAlphaPlane(pamP);
+    unsigned int const alphaPlane = usingAlpha ? pamAlphaPlane(pamP) : 0;
 
     rowReader * rowReaderP;
 
@@ -1493,9 +1525,22 @@ gifEncode(struct pam *  const pamP,
 
 
 static void
-reportTransparent(struct cmap * const cmapP) {
+reportTransparent(enum TransparencyType const transType,
+                  struct cmap *         const cmapP) {
 
     if (verbose) {
+        switch (transType) {
+        case TRANS_NONE:
+            pm_message("Not making transparent pixels");
+            break;
+        case TRANS_COLOR:
+            pm_message("Making pixels of a certain color transparent");
+            break;
+        case TRANS_ALPHA:
+            pm_message("Making pixels transparent per input alpha mask");
+            break;
+        }
+
         if (cmapP->haveTransparent) {
             tuple const color = cmapP->color[cmapP->transparent];
             pm_message("Color %u (%lu, %lu, %lu) is transparent",
@@ -1511,42 +1556,46 @@ reportTransparent(struct cmap * const cmapP) {
 
 
 static void
-computeTransparent(char          const colorarg[], 
-                   bool          const usingFakeTrans,
-                   unsigned int  const fakeTransparent,
-                   struct cmap * const cmapP) {
+computeTransparent(enum TransparencyType const transType,
+                   char                  const colorarg[],
+                   unsigned int          const fakeTransparent,
+                   struct cmap *         const cmapP) {
 /*----------------------------------------------------------------------------
    Figure out the color index (index into the colormap) of the color
-   that is to be transparent in the GIF.
+   that is to be transparent in the GIF and set it in the colormap.
+
+   'transType' tells what the source of the transparency is.
+
+   If 'transType' says all pixels of a single foreground color are to be
+   transparent:
 
-   colorarg[] is the string that specifies the color the user wants to
-   be transparent (e.g. "red", "#fefefe").  Its maxval is the maxval
-   of the colormap.  'cmap' is the full colormap except that its
-   'transparent' component isn't valid.
+     'colorarg' is the specification of that color.  Its
+     maxval is the maxval of the colormap.
 
-   colorarg[] is a standard Netpbm color specification, except that
-   may have a "=" prefix, which means it specifies a particular exact
-   color, as opposed to without the "=", which means "the color that
-   is closest to this and actually in the image."
+     colorarg[] is a standard Netpbm color specification (e.g. "red",
+     "#fefefe"), except that may have a "=" prefix, which means it specifies a
+     particular exact color, as opposed to without the "=", which means "the
+     color that is closest to this and actually in the image."
 
-   colorarg[] null means the color didn't ask for a particular color
-   to be transparent.
+     Establish no transparent color if colorarg[] specifies an exact
+     color and that color is not in the image.  Also issue an
+     informational message.
 
-   Establish no transparent color if colorarg[] specifies an exact
-   color and that color is not in the image.  Also issue an
-   informational message.
+   If 'transType' says an input alpha channel will dtermine what pixels are
+   transparent:
 
-   'usingFakeTrans' means pixels will be transparent because of something
-   other than their foreground color, and 'fakeTransparent' is the
-   color map index for transparent colors.
+     'fakeTransparent' is the special color map index for transparent pixels.
 -----------------------------------------------------------------------------*/
-    if (colorarg) {
+    switch (transType) {
+    case TRANS_COLOR: {
         const char * colorspec;
         bool exact;
         tuple transcolor;
         int found;
         int colorindex;
         
+        assert(colorarg);
+
         if (colorarg[0] == '=') {
             colorspec = &colorarg[1];
             exact = TRUE;
@@ -1570,13 +1619,16 @@ computeTransparent(char          const colorarg[],
             pm_message("Warning: specified transparent color "
                        "does not occur in image.");
         }
-    } else if (usingFakeTrans) {
+    } break;
+    case TRANS_ALPHA: {
         cmapP->haveTransparent = TRUE;
         cmapP->transparent = fakeTransparent;
-    } else
+    } break;
+    case TRANS_NONE: {
         cmapP->haveTransparent = FALSE;
-
-    reportTransparent(cmapP);
+    } break;
+    }  /* switch */
+    reportTransparent(transType, cmapP);
 }
 
 
@@ -1889,13 +1941,13 @@ main(int argc, char *argv[]) {
     struct pam pam;
     unsigned int bitsPerPixel;
     pm_filepos rasterPos;
-
     struct cmap cmap;
         /* The colormap, with all its accessories */
+    enum TransparencyType transType;
     unsigned int fakeTransparent;
         /* colormap index of the fake transparency color we're using to
-           implement the alpha mask.  Undefined if we're not doing an alpha
-           mask.
+           implement the alpha mask.  Defined only if 'transType' is
+           TRANS_ALPHA.
         */
     
     pnm_init(&argc, argv);
@@ -1916,7 +1968,11 @@ main(int argc, char *argv[]) {
     
     assert(cmap.pam.maxval == pam.maxval);
 
-    if (pamAlphaPlane(&pam)) {
+    transType = cmdline.transparent ? TRANS_COLOR :
+        pamAlphaPlane(&pam) ? TRANS_ALPHA :
+        TRANS_NONE;
+
+    if (transType == TRANS_ALPHA) {
         /* Add a fake entry to the end of the colormap for transparency.  
            Make its color black. 
         */
@@ -1925,14 +1981,12 @@ main(int argc, char *argv[]) {
 
     bitsPerPixel = cmap.cmapSize == 1 ? 1 : nSignificantBits(cmap.cmapSize-1);
 
-    computeTransparent(cmdline.transparent,
-                       !!pamAlphaPlane(&pam), fakeTransparent, &cmap);
+    computeTransparent(transType, cmdline.transparent, fakeTransparent, &cmap);
 
     /* All set, let's do it. */
     gifEncode(&pam, stdout, rasterPos,
               cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment,
-              cmdline.aspect, !cmdline.nolzw);
-    
+              cmdline.aspect, !cmdline.nolzw, !cmdline.transparent);
     destroyCmap(&cmap);
 
     pm_close(ifP);
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
index 0f76207d..e7138cce 100644
--- a/converter/other/pnmtopalm/palmtopnm.c
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -817,11 +817,12 @@ readPackBitsRow16(FILE *          const ifP,
     unsigned int j;
 
     for (j = 0;  j < bytesPerRow; ) {
-        char incount;
-        pm_readchar(ifP, &incount);
-        if (incount < 0) { 
+        unsigned char incountByte;
+        pm_readcharu(ifP, &incountByte);
+        if (incountByte & 0x80) {
+            int const signedIncount = (signed char)incountByte;
             /* How do we handle incount == -128 ? */
-            unsigned int const runlength = (-incount + 1) * 2;
+            unsigned int const runlength = (-signedIncount + 1) * 2;
             unsigned int k;
             unsigned short inval;
             pm_readlittleshortu(ifP, &inval);
@@ -832,7 +833,7 @@ readPackBitsRow16(FILE *          const ifP,
             j += runlength;
         } else {
             /* We just read the stream of shorts as a stream of chars */
-            unsigned int const nonrunlength = (incount + 1) * 2;
+            unsigned int const nonrunlength = (incountByte + 1) * 2;
             unsigned int k;
             for (k = 0; (k < nonrunlength) && (j + k <= bytesPerRow); ++k) {
                 unsigned char inval;
@@ -859,18 +860,19 @@ readPackBitsRow(FILE *          const ifP,
     unsigned int j;
 
     for (j = 0;  j < bytesPerRow; ) {
-        char incount;
-        pm_readchar(ifP, &incount);
-        if (incount < 0) { 
+        unsigned char incountByte;
+        pm_readcharu(ifP, &incountByte);
+        if (incountByte & 0x80) {
             /* How do we handle incount == -128 ? */
-            unsigned int const runlength = -incount + 1;
+            int const signedIncount = (char)incountByte;
+            unsigned int const runlength = -signedIncount + 1;
             unsigned char inval;
             pm_readcharu(ifP, &inval);
             if (j + runlength <= bytesPerRow)
                 memset(palmrow + j, inval, runlength);
             j += runlength;
         } else {
-            unsigned int const nonrunlength = incount + 1;
+            unsigned int const nonrunlength = incountByte + 1;
             unsigned int k;
             for (k = 0; k < nonrunlength && j + k <= bytesPerRow; ++k) {
                 unsigned char inval;
diff --git a/converter/other/sunicontopnm.c b/converter/other/sunicontopnm.c
index eff1be58..db26663e 100644
--- a/converter/other/sunicontopnm.c
+++ b/converter/other/sunicontopnm.c
@@ -12,10 +12,12 @@
 
 /*
   Most icon images are monochrome: Depth=1
+
   Depth=8 images are extremely rare.  At least some of these are color
-  images but we can't tell the palette color order.
+  images but we haven't found information on the palette color order.
   Output will be in pgm.  Convert to ppm with pgmtoppm or pamlookup
-  if necessary.
+  if necessary.  It is up to the user to provide the color palette in
+  a form acceptable by the above conversion utilities.
 */
 
 #include <assert.h>
@@ -93,12 +95,19 @@ ReadIconFileHeader(FILE * const file,
 
     if (*widthP <= 0)
         pm_error("invalid width (must be positive): %d", *widthP);
+    else if (*widthP % 8 > 0)
+        pm_message("warning: width not a multiple of 8: %d", *widthP);
+        /* We don't know whether widths which are not a multiple of 8
+           are allowed.   The program must gracefully handle this case
+           because sun icon files are easy to edit by hand.
+        */
     if (*heightP <= 0)
         pm_error("invalid height (must be positive): %d", *heightP);
 
 }
 
 
+
 int
 main(int argc, const char ** argv) {
 
@@ -125,7 +134,7 @@ main(int argc, const char ** argv) {
         maxval = 1;
         pbm_writepbminit(stdout, cols, rows, 0);
         bitrow = pbm_allocrow_packed(cols);
-        colChars = cols / 8;
+        colChars = pbm_packed_bytes(cols);
     } else {
         assert(depth == 8);
         format = PGM_TYPE;
@@ -166,6 +175,11 @@ main(int argc, const char ** argv) {
             pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
     }
 
+    if (format == PBM_TYPE)
+        pbm_freerow_packed(bitrow);
+    else
+        pgm_freerow(grayrow);
+
     pm_close(ifP);
     pm_close(stdout);
     return 0;
diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c
index 632e6345..8acd13d6 100644
--- a/converter/pbm/escp2topbm.c
+++ b/converter/pbm/escp2topbm.c
@@ -47,10 +47,17 @@
 
 
 #include <stdbool.h>
+#include <assert.h>
 
 #include "mallocvar.h"
 #include "pbm.h"
 
+static unsigned int widthMax = 127 * 256 + 255;
+    /* Limit in official Epson manual */
+
+static unsigned int const heightMax = 5120 * 200;
+    /* 5120 rows is sufficient for US legal at 360 DPI */
+
 #define ESC 033
 
 
@@ -120,6 +127,10 @@ readStripeHeader(unsigned int * const widthThisStripeP,
         pm_error("Error: Abnormal value in data block header:  "
                  "Says stripe has zero width or height");
 
+    if (widthThisStripe > widthMax)
+        pm_error("Error: Abnormal width value in data block header:  %u",
+                 widthThisStripe);
+
     if (compression != 0 && compression != 1)
         pm_error("Error: Unknown compression mode %u", compression);
 
@@ -221,12 +232,10 @@ expandBitarray(unsigned char *** const bitarrayP,
                unsigned int   *  const bitarraySizeP) {
 
     unsigned int const heightIncrement = 5120;
-    unsigned int const heightMax = 5120 * 200;
-        /* 5120 rows is sufficient for US legal at 360 DPI */
 
     *bitarraySizeP += heightIncrement;
     if (*bitarraySizeP > heightMax)
-        pm_error("Image too tall");
+        pm_error("Error: Image too tall");
     else
         REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); 
 }
@@ -326,6 +335,10 @@ main(int          argc,
                              width, widthThisStripe);
                 }
                 height += rowsThisStripe;
+                assert(height <= INT_MAX - 10);
+                    /* Becuse image height is tested in expandBitarray()
+                       with a more stringent condition.
+                    */
                 if (height > bitarraySize)
                     expandBitarray(&bitarray, &bitarraySize);
 
diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c
index 9f7004a1..712e3be9 100644
--- a/converter/pbm/mgrtopbm.c
+++ b/converter/pbm/mgrtopbm.c
@@ -16,6 +16,48 @@
 
 
 static void
+interpHdrWidth(struct b_header const head,
+               unsigned int *  const colsP) {
+
+    if (head.h_wide < ' ' || head.l_wide < ' ')
+        pm_error("Invalid width field in MGR header");
+    else {
+        unsigned int const maxDimension = 4095;
+
+        unsigned int const cols =
+            (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' ');
+
+        if (cols == 0 || cols > maxDimension)
+            pm_error("Invalid width value (%u) in MGR header", cols);
+        else
+            *colsP = cols;
+    }
+}
+
+
+
+static void
+interpHdrHeight(struct b_header const head,
+                unsigned int *  const rowsP) {
+
+    if (head.h_high < ' ' || head.l_high < ' ')
+        pm_error("Invalid height field in MGR header");
+    else {
+        unsigned int const maxDimension = 4095;
+
+        unsigned int const rows =
+            (((int)head.h_high - ' ') << 6) + ((int)head.l_high - ' ');
+
+        if (rows == 0 || rows > maxDimension)
+            pm_error("Invalid height value (%u) in MGR header", rows);
+        else
+            *rowsP = rows;
+    }
+}
+
+
+
+static void
 readMgrHeader(FILE *          const ifP, 
               unsigned int *  const colsP, 
               unsigned int *  const rowsP, 
@@ -60,13 +102,9 @@ readMgrHeader(FILE *          const ifP,
         pad = 0;  /* should never reach here */
     }
 
-    if (head.h_wide < ' ' || head.l_wide < ' ')
-        pm_error("Invalid width field in MGR header");
-    if (head.h_high < ' ' || head.l_high < ' ')
-        pm_error("Invalid width field in MGR header");
+    interpHdrWidth (head, colsP);
+    interpHdrHeight(head, rowsP);
     
-    *colsP = (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' ');
-    *rowsP = (((int)head.h_high - ' ') << 6) + ((int) head.l_high - ' ');
     *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP;
 }
 
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index 2a429086..ea7e66a7 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -20,44 +20,47 @@ static short const ybmMagic = ( ( '!' << 8 ) | '!' );
 
 static void
 getinit(FILE *  const ifP,
-        short * const colsP,
-        short * const rowsP,
-        short * const depthP) {
+        unsigned int * const colsP,
+        unsigned int * const rowsP,
+        int *          const depthP) {
 
-    short magic;
+    short int magic;
+    short int cols, rows;
     int rc;
 
     rc = pm_readbigshort(ifP, &magic);
     if (rc == -1)
         pm_error("EOF / read error");
-
-    if (magic != ybmMagic)
+    else if (magic != ybmMagic)
         pm_error("bad magic number in YBM file");
 
-    rc = pm_readbigshort(ifP, colsP);
+    rc = pm_readbigshort(ifP, &cols);
     if (rc == -1 )
         pm_error("EOF / read error");
+    else if (cols <= 0)
+        pm_error("invalid width value in YBM file");
 
-    rc = pm_readbigshort(ifP, rowsP);
+    rc = pm_readbigshort(ifP, &rows);
     if (rc == -1)
         pm_error("EOF / read error");
+    else if (rows <= 0)
+        pm_error("invalid height value in YBM file");
 
+    *colsP = (unsigned int) cols;
+    *rowsP = (unsigned int) rows;
     *depthP = 1;
 }
 
 
 
-
-
-
 int
 main(int argc, const char * argv[]) {
 
     FILE * ifP;
     bit * bitrow;
-    short rows, cols;
+    unsigned int rows, cols;
     unsigned int row;
-    short depth;
+    int depth;
     const char * inputFile;
 
     pm_proginit(&argc, argv);
@@ -76,7 +79,7 @@ main(int argc, const char * argv[]) {
 
     getinit(ifP, &cols, &rows, &depth);
     if (depth != 1)
-        pm_error("YBM file has depth of %u, must be 1", (unsigned)depth);
+        pm_error("YBM file has depth of %u, must be 1", (unsigned int) depth);
     
     pbm_writepbminit(stdout, cols, rows, 0);
 
diff --git a/doc/HISTORY b/doc/HISTORY
index ff4a346b..005dd131 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,6 +4,24 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
+21.12.26 BJH  Release 10.73.38
+
+              pamtogif: Fix bug: doesn't ignore the input alpha mask when user
+              specified -transparent.  Broken in Netpbm 10.37 (December 2006).
+
+              palmtopnm: Fix bug: fails with PackBits input on platform with
+              default unsigned char, such as ppc64.  Always broken.  (Ability
+              to convert PackBits input was new in Netpbm 10.27 (March 2005).
+              
+              pamrubber: Fix bug: random behavior with -quad when you specify
+              both points for source or target and the second one is lower in
+              the image than the first.  Always broken (Pamrubber was new in
+              Netpbm 10.54 (March 2011)).
+
+              sunicontopnm, escp2topbm, mgrtopbm, ybmtopbm, pamcut, pbmpscale,
+              pnmcat, pnmpad: Fix arithmetic overrun with ridiculously large
+              image.
+
 21.09.25 BJH  Release 10.73.37
 
               ximtoppm: Fix bug: invalid memory references with pathological
@@ -168,7 +186,7 @@ CHANGE HISTORY
 19.12.25 BJH  Release 10.73.30
 
               pamrubber: Fix bug: -frame doesn't work.  Always broken.
-              (Pamrubber was new in Netpbm 10.54 (March 2011).
+              (Pamrubber was new in Netpbm 10.54 (March 2011)).
 
 19.09.28 BJH  Release 10.73.29
 
diff --git a/editor/pamcut.c b/editor/pamcut.c
index 7c41af38..0f0144ef 100644
--- a/editor/pamcut.c
+++ b/editor/pamcut.c
@@ -570,7 +570,7 @@ extractRowsPBM(const struct pam * const inpamP,
 
     if (leftcol > 0) {
         totalWidth = MAX(rightcol+1, inpamP->width) + 7;
-        if (totalWidth > INT_MAX)
+        if (totalWidth > INT_MAX - 10)
             /* Prevent overflows in pbm_allocrow_packed() */
             pm_error("Specified right edge is too far "
                      "from the right end of input image");
@@ -579,7 +579,7 @@ extractRowsPBM(const struct pam * const inpamP,
         writeOffset = leftcol;
     } else {
         totalWidth = -leftcol + MAX(rightcol+1, inpamP->width);
-        if (totalWidth > INT_MAX)
+        if (totalWidth > INT_MAX - 10)
             pm_error("Specified left/right edge is too far "
                      "from the left/right end of input image");
         
diff --git a/editor/pamrubber.c b/editor/pamrubber.c
index 1890ac58..aaf62788 100644
--- a/editor/pamrubber.c
+++ b/editor/pamrubber.c
@@ -1007,10 +1007,10 @@ prepQuad(void) {
         } else if ((oldCP[0].x > oldCP[1].x) && (oldCP[0].y < oldCP[1].y)) {
             /* top-right and bottom-left */
             quad1 = quadRect(oldCP[1].x, oldCP[0].x, oldCP[0].y, oldCP[1].y);
-        } else if ((oldCP[0].x < oldCP[1].x) && (oldCP[0].y < oldCP[1].y)) {
+        } else if ((oldCP[0].x < oldCP[1].x) && (oldCP[0].y > oldCP[1].y)) {
             /* bottom-left and top-right */
             quad1 = quadRect(oldCP[0].x, oldCP[1].x, oldCP[1].y, oldCP[0].y);
-        } else if ((oldCP[0].x > oldCP[1].x) && (oldCP[0].y < oldCP[1].y)) {
+        } else if ((oldCP[0].x > oldCP[1].x) && (oldCP[0].y > oldCP[1].y)) {
             /* bottom-right and top-left */
             quad1 = quadRect(oldCP[1].x, oldCP[0].x, oldCP[1].y, oldCP[0].y);
         }
@@ -1021,10 +1021,10 @@ prepQuad(void) {
         } else if ((newCP[0].x > newCP[1].x) && (newCP[0].y < newCP[1].y)) {
             /* top-right and bottom-left */
             quad2 = quadRect(newCP[1].x, newCP[0].x, newCP[0].y, newCP[1].y);
-        } else if ((newCP[0].x < newCP[1].x) && (newCP[0].y < newCP[1].y)) {
+        } else if ((newCP[0].x < newCP[1].x) && (newCP[0].y > newCP[1].y)) {
             /* bottom-left and top-right */
             quad2 = quadRect(newCP[0].x, newCP[1].x, newCP[1].y, newCP[0].y);
-        } else if ((newCP[0].x > newCP[1].x) && (newCP[0].y < newCP[1].y)) {
+        } else if ((newCP[0].x > newCP[1].x) && (newCP[0].y > newCP[1].y)) {
             /* bottom-right and top-left */
             quad2 = quadRect(newCP[1].x, newCP[0].x, newCP[1].y, newCP[0].y);
         }
diff --git a/editor/pbmpscale.c b/editor/pbmpscale.c
index 9ab89350..3b6935b2 100644
--- a/editor/pbmpscale.c
+++ b/editor/pbmpscale.c
@@ -141,7 +141,7 @@ validateComputableDimensions(unsigned int const width,
    See validateComputetableSize() in libpam.c
    and pbm_readpbminitrest() in libpbm2.c
 -----------------------------------------------------------------------------*/
-    unsigned int const maxWidthHeight = INT_MAX - 2;
+    unsigned int const maxWidthHeight = INT_MAX - 10;
     unsigned int const maxScaleFactor = maxWidthHeight / MAX(height, width);
 
     if (scaleFactor > maxScaleFactor)
@@ -154,8 +154,8 @@ validateComputableDimensions(unsigned int const width,
 
 static void
 writeBitSpan(unsigned char * const packedBitrow,
-             int             const cols,
-             int             const offset,
+             unsigned int    const cols,
+             unsigned int    const offset,
              int             const color) {
 /*----------------------------------------------------------------------------
    Write white (color="0") or black (="1") bits into packedBitrow[],
diff --git a/editor/pnmcat.c b/editor/pnmcat.c
index a26dcf3e..217f6b57 100644
--- a/editor/pnmcat.c
+++ b/editor/pnmcat.c
@@ -367,7 +367,8 @@ getPbmImageInfo(struct imgInfo        const img[],
             switch (backcolor) {
             case BACK_AUTO: {
                 bit bgBit;
-                img2[i].proberow = pbm_allocrow_packed(img[i].cols+7);
+                img2[i].proberow =
+                    pbm_allocrow_packed((unsigned int)img[i].cols + 7);
                 pbm_readpbmrow_bitoffset(
                     img[i].ifP, img2[i].proberow,
                     img[i].cols, img[i].format, img2[i].offset % 8);
diff --git a/editor/pnmpad.c b/editor/pnmpad.c
index 051f3895..a4f7c5cb 100644
--- a/editor/pnmpad.c
+++ b/editor/pnmpad.c
@@ -10,7 +10,7 @@
 #include "shhopt.h"
 #include "pnm.h"
 
-#define MAX_WIDTHHEIGHT INT_MAX-10
+#define MAX_WIDTHHEIGHT ((INT_MAX)-10)
     /* The maximum width or height value we can handle without risking
        arithmetic overflow
     */
diff --git a/lib/libpbm2.c b/lib/libpbm2.c
index f199c51a..8fde27fd 100644
--- a/lib/libpbm2.c
+++ b/lib/libpbm2.c
@@ -216,6 +216,9 @@ pbm_readpbmrow_bitoffset(FILE *          const ifP,
    Read it into packedBits[], preserving surrounding image data.
 
    Logic not tested for negative offsets.
+
+   Because we are reading in packed mode large cols and offset values are
+   acceptable; dividing by 8 prevents overflows.
 -----------------------------------------------------------------------------*/
     unsigned int const rsh = offset % 8;
     unsigned int const lsh = (8 - rsh) % 8;
@@ -224,13 +227,15 @@ pbm_readpbmrow_bitoffset(FILE *          const ifP,
            Aligned to nearest byte boundary to the left, so the first
            few bits might contain original data, not output.
         */
-    unsigned int const last = pbm_packed_bytes(cols+rsh) - 1;
+    unsigned int const last = pbm_packed_bytes((unsigned int)cols + rsh) - 1;
         /* Position within window of rightmost byte after shift */
 
     /* The original leftmost and rightmost chars. */
     unsigned char const origHead = window[0];
     unsigned char const origEnd  = window[last];
 
+    assert(cols > 0 && pbm_packed_bytes(cols) > 0);
+
     pbm_readpbmrow_packed(ifP, window, cols, format);
 
     if (rsh > 0) {
diff --git a/version.mk b/version.mk
index a9ce42e8..f2b4ef46 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
 NETPBM_MINOR_RELEASE = 73
-NETPBM_POINT_RELEASE = 37
+NETPBM_POINT_RELEASE = 38