about summary refs log tree commit diff
path: root/converter/other
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
commit380588e187c12000ac8082cb2a20a905d3c422a5 (patch)
tree296b1324b7a9360646a34ae836b8eb486b7feede /converter/other
parentf8b633c2be1231a0c194214271caa456dc669ecb (diff)
downloadnetpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.gz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.xz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.zip
Release 10.63.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@1968 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other')
-rw-r--r--converter/other/Makefile5
-rw-r--r--converter/other/cameratopam/camera.c2
-rw-r--r--converter/other/cameratopam/cameratopam.c2
-rw-r--r--converter/other/cameratopam/foveon.c4
-rw-r--r--converter/other/cameratopam/foveon.h4
-rw-r--r--converter/other/ipdb.c1
-rw-r--r--converter/other/pamtogif.c4
-rw-r--r--converter/other/pamtooctaveimg.c4
-rw-r--r--converter/other/pamtopam.c2
-rw-r--r--converter/other/pamtopnm.c2
-rw-r--r--converter/other/pamtosrf.c4
-rw-r--r--converter/other/pamtosvg/pamtosvg.c2
-rw-r--r--converter/other/pamtotiff.c2
-rw-r--r--converter/other/pamtowinicon.c1177
-rw-r--r--converter/other/pamtoxvmini.c4
-rw-r--r--converter/other/pnmtopclxl.c2
-rw-r--r--converter/other/pnmtopng.c534
-rw-r--r--converter/other/pnmtops.c82
-rw-r--r--converter/other/pstopnm.c378
-rw-r--r--converter/other/winicon.h82
-rw-r--r--converter/other/winicontopam.c1282
21 files changed, 3114 insertions, 465 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 746db87c..35f420f2 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -118,12 +118,13 @@ PORTBINARIES =  avstopam bmptopnm fitstopnm \
 		pamtoavs pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
 		pamtopam pamtopfm pamtopnm pamtouil \
-		pamtoxvmini \
+		pamtowinicon pamtoxvmini \
 		pbmtopgm pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
 		pnmtopclxl \
 		pnmtosgi pnmtosir pamtotga pnmtoxwd \
-		rlatopam sgitopnm sirtopnm sunicontopnm xwdtopnm zeisstopnm
+		rlatopam sgitopnm sirtopnm sunicontopnm \
+		winicontopam xwdtopnm zeisstopnm
 
 BINARIES = \
   $(PORTBINARIES) \
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index ea5eec39..254b6710 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -761,7 +761,7 @@ kodak_radc_load_raw()
 void kodak_jpeg_load_raw() {}
 #else
 
-static boolean
+static bool
 fill_input_buffer (j_decompress_ptr cinfo)
 {
   static char jpeg_buffer[4096];
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index 54b68a23..71c9c7af 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -69,7 +69,7 @@ int fuji_secondary;
 float cam_mul[4], pre_mul[4], coeff[3][4];
 int histogram[3][0x2000];
 jmp_buf failure;
-bool use_secondary;
+int use_secondary;
 bool verbose;
 
 #ifdef USE_LCMS
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index 0198940c..78e40baf 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) {
 
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]) {
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]) {
 
     static const float foveon[3][3] =
     { {  1.4032, -0.2231, -0.1016 },
diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h
index 57be2244..f3177e50 100644
--- a/converter/other/cameratopam/foveon.h
+++ b/converter/other/cameratopam/foveon.h
@@ -10,5 +10,5 @@ void
 foveon_load_raw(void);
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]);
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]);
diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c
index 5c1fc314..eec4495a 100644
--- a/converter/other/ipdb.c
+++ b/converter/other/ipdb.c
@@ -19,6 +19,7 @@
  *   Authors:  Eric A. Howe (mu@trends.net)
  *             Bryan Henderson, 2010
  */
+#define _BSD_SOURCE   /* Ensure strdup() is in <string.h> */
 #include <assert.h>
 #include <time.h>
 #include <string.h>
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index 4dac8923..5b9c219c 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -220,7 +220,7 @@ closestColor(tuple         const color,
     
     unsigned int i;
     unsigned int imin, dmin;
-    bool fits;
+    int fits;
 
     dmin = UINT_MAX;
     imin = 0;
@@ -1544,7 +1544,7 @@ computeTransparent(char          const colorarg[],
         const char * colorspec;
         bool exact;
         tuple transcolor;
-        bool found;
+        int found;
         int colorindex;
         
         if (colorarg[0] == '=') {
diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c
index b090281d..28bc4cd4 100644
--- a/converter/other/pamtooctaveimg.c
+++ b/converter/other/pamtooctaveimg.c
@@ -75,13 +75,13 @@ findOrAddColor(tuple          const color,
   colormap *cmapP.  If the color isn't in the map, give it a new
   colormap index, put it in the colormap, and return that.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int colorIndex;
 
     pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex);
 
     if (!found) {
-        bool fits;
+        int fits;
         unsigned int plane;
 
         colorIndex = cmapP->nColors++;
diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c
index cae54060..9cb82f7a 100644
--- a/converter/other/pamtopam.c
+++ b/converter/other/pamtopam.c
@@ -17,7 +17,7 @@
 int
 main(int argc, const char * argv[]) {
 
-    bool       eof;     /* no more images in input stream */
+    int        eof;     /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
 
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
index ba655b1e..9bb662b7 100644
--- a/converter/other/pamtopnm.c
+++ b/converter/other/pamtopnm.c
@@ -109,7 +109,7 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE* ifP;
-    bool eof;   /* no more images in input stream */
+    int eof;   /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PNM image */
 
diff --git a/converter/other/pamtosrf.c b/converter/other/pamtosrf.c
index 19328073..3800d77c 100644
--- a/converter/other/pamtosrf.c
+++ b/converter/other/pamtosrf.c
@@ -112,7 +112,7 @@ srfAlphaFromTuple(tuple              const t,
                   const struct pam * const pamP) {
 
     uint8_t retval;
-    bool haveOpacity;
+    int haveOpacity;
     unsigned int opacityPlane;
 
     pnm_getopacity(pamP, &haveOpacity, &opacityPlane);
@@ -181,7 +181,7 @@ main(int argc, const char * argv[]) {
   struct cmdlineInfo cmdline;
   FILE *             ifP;
   struct srf         srf;
-  bool               eof;   /* No more images in input */
+  int                eof;   /* No more images in input */
   unsigned int       imageSeq;
       /* Sequence of current image in input file.  First = 0 */
 
diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
index 72aa4151..adf76801 100644
--- a/converter/other/pamtosvg/pamtosvg.c
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -134,7 +134,7 @@ parseCommandLine(int argc,
    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;
+    optEntry * option_def;
     /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 551909a0..0206678d 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -1055,7 +1055,7 @@ main(int argc, char *argv[]) {
     const char * inputFileDescription;
     FILE* ifP;
     TIFF* tifP;
-    bool eof;
+    int eof;
     unsigned int imageSeq;
 
     pnm_init(&argc, argv);
diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c
new file mode 100644
index 00000000..c67267e4
--- /dev/null
+++ b/converter/other/pamtowinicon.c
@@ -0,0 +1,1177 @@
+#define _POSIX_SOURCE   /* Make sure fdopen() is in <stdio.h> */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pm_system.h"
+#include "netpbm/pam.h"
+#include "winicon.h"
+
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int verbose;
+    int          pngthreshold;
+    unsigned int truetransparent;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+    unsigned int pngthresholdSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3 (0, "verbose",         OPT_FLAG, NULL,
+             &cmdlineP->verbose,         0);
+    OPTENT3 (0, "pngthreshold",    OPT_UINT, &cmdlineP->pngthreshold,
+             &pngthresholdSpec,          0);
+    OPTENT3 (0, "truetransparent", OPT_FLAG, NULL,
+             &cmdlineP->truetransparent, 0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (pngthresholdSpec) {
+        if (UINT_MAX / cmdlineP->pngthreshold < cmdlineP->pngthreshold)
+            pm_error("-pngthreshold is too large: %u", cmdlineP->pngthreshold);
+    } else
+        cmdlineP->pngthreshold = 128;
+
+    if (argc-1 > 0) {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments: %u.  The only non-option "
+                     "argument is the optional input file name", argc-1);
+    } else
+        cmdlineP->inputFileName = "-";
+
+    free(option_def);
+}
+
+
+
+static bool verbose;
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct Palette {
+    sample color[256][3];
+    unsigned int colorCt;
+        /* Number of colors in color[][] */
+    bool tooManyColors;
+        /* There are too many colors for a BMP palette (more than 256); only
+           the first 256 are in color[][]
+        */
+};
+
+
+
+static struct IconDir *
+newIconDir() {
+
+    struct IconDir * dirP;
+
+    MALLOCVAR_NOFAIL(dirP);
+
+    dirP->zero           = 0;
+    dirP->type           = ICONDIR_TYPE_ICO;
+    dirP->count          = 0;
+
+    dirP->entriesAllocCt = 0;
+    dirP->entries        = NULL;
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+    if (dirP->entries)
+        free(dirP->entries);
+
+    free(dirP);
+}
+
+
+
+static void
+addToDirectory(struct IconDirEntry * const dirEntryP,
+               struct IconDir *      const dirP) {
+/*----------------------------------------------------------------------------
+  Add an icon to the icon directory.
+-----------------------------------------------------------------------------*/
+    if (dirP->count + 1 > dirP->entriesAllocCt) {
+        /* Out of space in dirP->entries[].  Expand. */
+
+        dirP->entriesAllocCt += 8;
+
+        REALLOCARRAY(dirP->entries, dirP->entriesAllocCt);
+
+        if (!dirP->entries)
+            pm_error("Unable to get memory for %u entries "
+                     "in the Icon directory.", dirP->entriesAllocCt);
+    }
+
+    dirP->entries[dirP->count++] = *dirEntryP;
+}
+
+
+
+typedef void (GetPixelFn) (tuple **     const tuples,
+                           unsigned int const col,
+                           unsigned int const row,
+                           sample *     const pixel);
+
+
+
+static GetPixelFn get_grayscalePixel;
+
+static void
+get_grayscalePixel(tuple **     const tuples,
+                   unsigned int const col,
+                   unsigned int const row,
+                   sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from a grayscale PAM
+-----------------------------------------------------------------------------*/
+    pixel[0] = tuples[row][col][0];
+    pixel[1] = tuples[row][col][0];
+    pixel[2] = tuples[row][col][0];
+}
+
+
+
+static GetPixelFn get_rgbPixel;
+
+static void
+get_rgbPixel(tuple **     const tuples,
+             unsigned int const col,
+             unsigned int const row,
+             sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from an RGB PAM
+-----------------------------------------------------------------------------*/
+    pixel [0] = tuples [row][col][0];
+    pixel [1] = tuples [row][col][1];
+    pixel [2] = tuples [row][col][2];
+}
+
+
+static bool
+andMakesOpaque(const struct pam * const pamP,
+               tuple **           const tuples,
+               unsigned int       const row,
+               unsigned int       const col,
+               bool               const haveAlpha,
+               unsigned int       const alphaPlane,
+               bool               const haveAnd,
+               unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+   The AND mask makes a pixel opaque
+-----------------------------------------------------------------------------*/
+    if (haveAnd)
+        return (pamP->maxval <= tuples[row][col][andPlane]);
+    else if (haveAlpha)
+        return (pamP->maxval <= tuples[row][col][alphaPlane]);
+    else
+        /* neither alpha channel nor AND mask: full opacity */
+        return true;
+}
+
+
+
+static void
+getPalette(struct pam *     const pamP,
+           tuple **         const tuples,
+           GetPixelFn *     const getPixel,
+           struct Palette * const paletteP) {
+/*----------------------------------------------------------------------------
+  Create the palette for all the colors in 'tuples'.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    paletteP->colorCt = 0;  /* initial value */
+    paletteP->tooManyColors = false;  /* initial value */
+
+    for (row = 0; pamP->height > row && !paletteP->tooManyColors; ++row) {
+        unsigned int col;
+        for (col = 0; pamP->width > col && !paletteP->tooManyColors; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i) {
+                if ((paletteP->color[i][0] == pixel[0])
+                    && (paletteP->color[i][1] == pixel[1])
+                    && (paletteP->color[i][2] == pixel[2]))
+                    break;
+            }
+            if (i == paletteP->colorCt) {
+                /* We didn't find the color. */
+                if (paletteP->colorCt >= 256) {
+                    /* Image exceeds the palette capacity */
+                    paletteP->tooManyColors = true;
+                } else {
+                    /* Add the color to the palette */
+                    paletteP->color[paletteP->colorCt][0] = pixel[0];
+                    paletteP->color[paletteP->colorCt][1] = pixel[1];
+                    paletteP->color[paletteP->colorCt][2] = pixel[2];
+
+                    ++paletteP->colorCt;
+                }
+            }
+        }
+    }
+}
+
+
+
+static bool
+realAlphaNeeded(const struct pam * const pamP,
+                tuple **           const tuples,
+                unsigned int       const alphaPlane) {
+/*----------------------------------------------------------------------------
+  A real alpha channel (in contrast to an AND mask) is needed to represent the
+  image in 'tuples', given that 'alphaPlane' is the alpha plane.
+
+  A real alpha channel is needed if any pixel is translucent (neither opaque
+  nor transparent).
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample const opacity = tuples[row][col][alphaPlane];
+
+            if (opacity != 0 && opacity != pamP->maxval)
+                return true;
+        }
+    }
+    return false;
+}
+
+
+
+static void
+writeBmpImageHeader(unsigned int const width,
+                    unsigned int const height,
+                    unsigned int const bpp,
+                    unsigned int const rasterSize,
+                    FILE *       const ofP) {
+/*----------------------------------------------------------------------------
+
+  Write BMP image header
+    
+  Note: bm_height is sum of rows in XOR mask and AND mask, while
+  image_size is the size of the AND mask only.
+    
+  image_size does not include the sizes of the (optional) palette
+  and the (mandatory) AND mask.
+-----------------------------------------------------------------------------*/
+    pm_writelittlelongu  (ofP, 40);              /* header_size          */
+    pm_writelittlelongu  (ofP, width);           /* bm_width             */
+    pm_writelittlelongu  (ofP, height *2);       /* bm_height            */
+    pm_writelittleshortu (ofP, 1);               /* color_planes         */
+    pm_writelittleshortu (ofP, bpp);             /* bits_per_pixel       */
+    pm_writelittlelongu  (ofP, BI_RGB);          /* compression_method   */
+    pm_writelittlelongu  (ofP, rasterSize);      /* image_size           */
+    pm_writelittlelongu  (ofP, 0);               /* horizontal_resolution*/
+    pm_writelittlelongu  (ofP, 0);               /* vertical_resolution  */
+    pm_writelittlelongu  (ofP, 0);               /* colors_in_palette    */
+    pm_writelittlelongu  (ofP, 0);               /* important_colors     */
+}
+
+
+
+static void
+write32BitBmp(const struct pam *   const pamP,
+              tuple     **         const tuples,
+              GetPixelFn *         const getPixel,
+              bool                 const haveAlpha,
+              unsigned int         const alphaPlane,
+              FILE *               const ofP,
+              uint32_t *           const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a 32-bit BMP encoded image to file *ofP.
+-----------------------------------------------------------------------------*/
+    int row;
+    
+    writeBmpImageHeader(pamP->width, pamP->height, 32, 
+                        pamP->width * 4 * pamP->height, ofP);
+
+    /*  write "XOR mask" */
+    for (row = pamP->height - 1; row >= 0; --row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample   pixel[3];
+            uint32_t val;
+
+            getPixel(tuples, col, row, pixel);
+
+            val = ((uint32_t) pixel[PAM_RED_PLANE] << 16)
+                + ((uint32_t) pixel[PAM_GRN_PLANE] <<  8)
+                + ((uint32_t) pixel[PAM_BLU_PLANE] <<  0)
+                ;
+            
+            if (haveAlpha)
+                val += (uint32_t) tuples[row][col][alphaPlane] << 24;
+
+            pm_writelittlelongu(ofP, val);
+       }
+    }
+    *sizeP = 40 + pamP->height * pamP->width * 4;
+}
+
+
+
+static void
+writeBmpPalette(const struct Palette * const paletteP,
+                unsigned int           const maxColors,
+                FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the palette of a BMP image.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < paletteP->colorCt; ++i)
+        pm_writelittlelongu(ofP, 0
+                            +(paletteP->color[i][PAM_RED_PLANE] << 16)
+                            +(paletteP->color[i][PAM_GRN_PLANE] <<  8)
+                            +(paletteP->color[i][PAM_BLU_PLANE] <<  0));
+    
+    for (; i < maxColors; ++i)
+        pm_writelittlelongu(ofP, 0);
+}
+
+
+
+static void
+writeXorMask(const struct pam *     const pamP,
+             tuple **               const tuples,
+             GetPixelFn *           const getPixel,
+             const struct Palette * const paletteP,
+             unsigned int           const bpp,
+             FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the "XOR mask" part of a BMP image.
+
+   This is what one normally thinks of as the foreground image raster.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp;
+
+    int row;
+                 
+    for (row = pamP->height - 1; row >= 0; --row) {
+        uint8_t  val;
+        uint16_t mask;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            mask <<= bpp;
+            val  <<= bpp;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i)
+                if (true
+                    && (pixel[0] == paletteP->color[i][0])
+                    && (pixel[1] == paletteP->color[i][1])
+                    && (pixel[2] == paletteP->color[i][2]))
+                    break;
+
+            assert(i < paletteP->colorCt);
+
+            val |= i;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= bpp;
+            val  <<= bpp;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+            }
+        }
+    }
+}
+
+
+
+static void
+writePaletteBmp(unsigned int           const bpp,
+                const struct pam   *   const pamP,
+                tuple **               const tuples,
+                GetPixelFn *           const getPixel,
+                const struct Palette * const paletteP,
+                FILE *                 const ofP,
+                uint32_t *             const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a `BMP with palette' encoded image to file *ofP.
+
+  Unless it would be smaller as a 32-bit direct image, in which case
+  write that instead.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxColors = 1 << bpp;
+
+    unsigned int const rasterSize =
+        pamP->height *((pamP->width * bpp + 31) & ~31) / 8;
+
+    if (pamP->height * pamP->width * 4 <= maxColors * 4 + rasterSize)
+        write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                      ofP, sizeP);
+    else {
+        unsigned int const headerSize = 40;
+        unsigned int const paletteSize = maxColors * 4;
+
+        writeBmpImageHeader(pamP->width, pamP->height, bpp, rasterSize, ofP);
+
+        writeBmpPalette(paletteP, maxColors, ofP);
+
+        writeXorMask(pamP, tuples, getPixel, paletteP, bpp, ofP);
+
+        *sizeP = headerSize + paletteSize + rasterSize;
+    }
+}
+
+
+
+static void
+writeAndMask(const struct pam * const pamP,
+             tuple     **       const tuples,
+             bool               const haveAlpha,
+             unsigned int       const alphaPlane,
+             bool               const haveAnd,
+             unsigned int       const andPlane,
+             FILE *             const ofP,
+             uint32_t *         const sizeP) {
+/*----------------------------------------------------------------------------
+  Write the AND mask to file *ofP.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxCol =((pamP->width * 1 + 31) & ~31) / 1;
+
+    int row;
+    unsigned int sizeSoFar;
+
+    sizeSoFar = 0;
+
+    for (row = pamP->height - 1; row >= 0; --row) {
+        uint8_t  val;
+        uint16_t mask;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (!andMakesOpaque(pamP, tuples, row, col, 
+                                haveAlpha, alphaPlane, haveAnd, andPlane))
+                val |= 0x1;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (mask > 0xFF){
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+            }
+        }
+    }
+    *sizeP = sizeSoFar;
+}
+
+
+
+static void
+makeAlphaFile(const struct pam * const imagePamP,
+              tuple **           const imageTuples,
+              unsigned int       const alphaPlane,
+              const char **      const alphaFileNameP) {
+
+    FILE * alphaFileP;
+    struct pam alphaPam;
+    tuple ** alphaTuples;
+    unsigned int row;
+    
+    pm_make_tmpfile(&alphaFileP, alphaFileNameP);
+
+    alphaPam.size   = sizeof(alphaPam);
+    alphaPam.len    = PAM_STRUCT_SIZE(tuple_type);
+    alphaPam.file   = alphaFileP;
+    alphaPam.format = PAM_FORMAT;
+    alphaPam.width  = imagePamP->width;
+    alphaPam.height = imagePamP->height;
+    alphaPam.depth  = 1;
+    alphaPam.maxval = imagePamP->maxval;
+    strcpy(alphaPam.tuple_type, PAM_PGM_TUPLETYPE);
+
+    alphaTuples = pnm_allocpamarray(&alphaPam);
+
+    assert(alphaPlane < imagePamP->depth);
+
+    for (row = 0; row < alphaPam.height; ++row) {
+        unsigned int col;
+        for (col = 0; col < alphaPam.width; ++col)
+            alphaTuples[row][col][0] = imageTuples[row][col][alphaPlane];
+    }
+
+    pnm_writepam(&alphaPam, alphaTuples);
+
+    pnm_freepamarray(alphaTuples, &alphaPam);
+
+    pm_close(alphaFileP);
+}
+
+
+
+struct AcceptToFileParm {
+    FILE *   ofP;
+    size_t * writeCtP;
+};
+
+static void
+acceptToFile(int    const pipeToSuckFd,
+             void * const accepterParm) {
+
+    struct AcceptToFileParm * const parmP = accepterParm;
+
+    FILE * const inFileP = fdopen(pipeToSuckFd, "r");
+
+    bool eof;
+    size_t copyCt;
+
+    for (eof = false, copyCt = 0; !eof; ) {
+        size_t readCt;
+        unsigned char buffer[1024];
+
+        readCt = fread(buffer, 1, sizeof(buffer), inFileP);
+
+        if (readCt == 0)
+            eof = true;
+        else {
+            size_t writeCt;
+
+            writeCt = fwrite(buffer, 1, readCt, parmP->ofP);
+
+            if (writeCt != readCt)
+                pm_error("Write to images file failed.  errno=%d (%s)",
+                         errno, strerror(errno));
+
+            copyCt += writeCt;
+        }
+    }
+    *parmP->writeCtP = copyCt;
+}
+
+
+
+static void
+writePng(const struct pam * const pamP,
+         tuple **           const tuples,
+         bool               const haveAlpha,
+         unsigned int       const alphaPlane,
+         bool               const haveAnd,
+         unsigned int       const andPlane,
+         uint32_t *         const sizeP,
+         FILE *             const ofP) {
+
+    struct pamtuples pamTuples;
+    size_t pngSize;
+    struct AcceptToFileParm acceptParm;
+    struct pam pam;
+
+    pam = *pamP;
+    pam.depth = pamP->depth - (haveAlpha ? 1 : 0) - (haveAnd ? 1 : 0);
+
+    pamTuples.pamP    = &pam;
+    pamTuples.tuplesP = (tuple ***)&tuples;
+
+    /* We're going to fork a process to add stuff to *ofP, so we flush
+       out this process' previous writes to that file first:
+    */
+    fflush(ofP);
+
+    acceptParm.ofP = ofP;
+    acceptParm.writeCtP = &pngSize;
+    
+    if (haveAlpha || haveAnd) {
+        const char * alphaFileName;
+        const char * command;
+
+        if (haveAlpha)
+            makeAlphaFile(pamP, tuples, alphaPlane, &alphaFileName);
+        else
+            makeAlphaFile(pamP, tuples, andPlane, &alphaFileName);
+
+        strcpy (pam.tuple_type,
+                pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE);
+        
+        pm_asprintf(&command, "pnmtopng -alpha=\"%s\"", alphaFileName);
+
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  command);
+    
+        pm_strfree(command);
+    
+        unlink(alphaFileName);
+    } else {
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  "pnmtopng");
+    }
+
+    *sizeP = pngSize;
+}
+
+
+
+static void
+blackenXor(const struct pam * const pamP,
+           tuple     **       const tuples,
+           bool               const haveAlpha,
+           unsigned int       const alphaPlane,
+           bool               const haveAnd,
+           unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+  Set all pixels marked as transparent in AND mask to black.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            if (!andMakesOpaque(pamP, tuples, row, col,
+                                haveAlpha, alphaPlane, haveAnd, andPlane)) {
+                tuples[row][col][0] = PAM_BLACK;
+
+                if (pamP->depth >= 3) {
+                    tuples[row][col][1] = PAM_BLACK;
+                    tuples[row][col][2] = PAM_BLACK;
+                }
+            }
+        }
+    }
+}
+
+
+
+
+static void
+readAndScalePam(struct pam * const pamP,
+                bool         const doingPng,
+                tuple **     const tuples) {
+
+    if (doingPng) {
+        /* Read the image with its native maxval */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row)
+            pnm_readpamrow(pamP, tuples[row]);
+    } else {
+        /* Read the image and scale to maxval 255 */
+        tuple * tuplerow;
+        unsigned int row;
+        tuplerow = pnm_allocpamrow(pamP);
+
+        for (row = 0; row < pamP->height; ++row) {
+            pnm_readpamrow(pamP, tuplerow);
+            pnm_scaletuplerow(pamP, tuples[row], tuplerow, 255);
+        }
+        pnm_freepamrow(tuplerow);
+        pamP->maxval = 255;
+    }
+}
+
+
+
+static void
+determineImageType(const struct pam * const pamP,
+                   tuple **           const tuples,
+                   GetPixelFn **      const getPixelP,
+                   bool *             const haveAlphaP,
+                   unsigned int *     const alphaPlaneP,
+                   bool *             const haveAndP,
+                   unsigned int *     const andPlaneP) {
+
+    /*  PAM input channels:
+     *
+     *  1-channel PAM: Grayscale
+     *  2-channel PAM: Grayscale +Alpha
+     *  3-channel PAM: RGB
+     *  4-channel PAM: RGB +Alpha
+     *  5-channel PAM: RGB +Alpha +AND mask
+     */
+    switch (pamP->depth) {
+    case 1:
+        *getPixelP  = get_grayscalePixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 2:
+        *getPixelP = get_grayscalePixel;
+        if (realAlphaNeeded(pamP, tuples, 1)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 1;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP   = true;
+            *andPlaneP  = 1;
+        }
+        break;
+
+    case 3:
+        *getPixelP  = get_rgbPixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 4:
+        *getPixelP = get_rgbPixel;
+        if (realAlphaNeeded(pamP, tuples, 3)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 3;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP    = true;
+            *andPlaneP  = 3;
+        }
+        break;
+
+    case 5:
+        *getPixelP   = get_rgbPixel;
+        *haveAlphaP  = true;
+        *alphaPlaneP = 3;
+        *haveAndP    = true;
+        *andPlaneP   = 4;
+        break;
+
+    default:
+        pm_error("unexpected PAM depth %u.  "
+                 "We understand depths 1-5", pamP->depth);
+        break;
+    }
+}
+
+
+
+static void
+reportImageInfo(unsigned int           const imageNum,
+                const struct pam *     const pamP,
+                const struct Palette * const paletteP,
+                bool                   const haveAlpha,
+                bool                   const haveAnd) {
+
+    const char * colorCt;
+
+    if (paletteP->tooManyColors)
+        pm_asprintf(&colorCt, "> 256");
+    else
+        pm_asprintf(&colorCt, "%u", paletteP->colorCt);
+
+    pm_message("Image %2u:"
+               " %3u x %3u x %u, %s colors%s%s",
+               imageNum,
+               pamP->width, pamP->height, pamP->depth,
+               colorCt,
+               haveAlpha ? ", alpha channel": "",
+               haveAnd ? ", AND mask": "");
+
+    pm_strfree(colorCt);
+}
+
+
+
+static void
+writeIconAndCreateDirEntry(const struct pam *     const pamP,
+                           tuple **               const tuples,
+                           GetPixelFn *           const getPixel,
+                           bool                   const doingPng,
+                           bool                   const haveAlpha,
+                           unsigned int           const alphaPlane,
+                           bool                   const haveAnd,
+                           unsigned int           const andPlane,
+                           bool                   const mustBlackenXor,
+                           const struct Palette * const paletteP,
+                           FILE *                 const ofP,
+                           struct IconDirEntry *  const dirEntryP) {
+/*----------------------------------------------------------------------------
+   Write to *ofP the icon image for the image represented by *pamP and
+   'tuples'.
+
+   Generate the information for an icon directory entry for this image
+   and return it as *dirEntryP.  ==>BUT: the 'offset' member of this
+   structure will not be meaningful. <==
+
+   Make a PNG image if 'doingPng' is true; BMP otherwise.
+
+   'haveAlpha' means that there is an alpha plane in 'tuples' and it is
+   Plane 'alphaPlane'.
+
+   'haveAnd' means that there is an AND plane in 'tuples' and it is Plane
+   'andPlane'.
+
+   *paletteP is the color palette for the icon; it contains an entry for each
+   color in 'tuples'.  Except: it may simply indicate that there are too many
+   colors in 'tuples' to have a palette.
+
+   The 'bits_per_pixel' member of the directory entry is supposed to tell the
+   color resolution of the image so the user can decide which of many versions
+   of the icon in the file to use.  But we just call it 32 bits in every case
+   except paletted BMP, where it actually relates to how many colors are in
+   the image.
+-----------------------------------------------------------------------------*/
+    dirEntryP->width          = pamP->width;
+    dirEntryP->height         = pamP->height;
+    dirEntryP->color_planes   = 1;
+    dirEntryP->zero           = 0;
+
+    if (doingPng) {
+        dirEntryP->color_count    = 0;
+        dirEntryP->bits_per_pixel = 32;
+
+        writePng(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                 &dirEntryP->size, ofP);
+    } else {
+        uint32_t bmpSize;
+        uint32_t andMaskSize;
+
+        if (mustBlackenXor)
+            blackenXor(pamP, tuples,
+                       haveAlpha, alphaPlane, haveAnd, andPlane);
+
+        if (haveAlpha) {
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, haveAlpha, alphaPlane,
+                          ofP, &bmpSize);
+        } else if (paletteP->tooManyColors) {
+            /* Do a truecolor image */
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                          ofP, &bmpSize);
+        } else {
+            /* Do a paletted image */
+
+            if (paletteP->colorCt <= 2) {
+                dirEntryP->color_count    = paletteP->colorCt;
+                dirEntryP->bits_per_pixel = 1;
+                    
+                writePaletteBmp(1, pamP, tuples, getPixel, paletteP,
+                                ofP, &bmpSize);
+            } else if (paletteP->colorCt <= 16) {
+                dirEntryP->color_count    = paletteP->colorCt;
+                dirEntryP->bits_per_pixel = 4;
+                    
+                writePaletteBmp(4, pamP, tuples, getPixel,paletteP,
+                                ofP, &bmpSize);
+            } else {
+                dirEntryP->color_count    = 0;
+                dirEntryP->bits_per_pixel = 8;
+                    
+                writePaletteBmp(8, pamP, tuples, getPixel, paletteP,
+                                ofP, &bmpSize);
+            }
+        }
+        writeAndMask(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                     ofP, &andMaskSize);
+
+        dirEntryP->size = bmpSize + andMaskSize;
+    }
+}
+
+
+
+static void
+convertOneImage(unsigned int     const imageNum,
+                FILE *           const ifP,
+                unsigned int     const pngThreshold,
+                bool             const mustBlackenXor,
+                FILE *           const ofP,
+                struct IconDir * const dirP) {
+
+    struct IconDirEntry dirEntry;
+    struct pam          pam;
+    tuple **            tuples;
+    bool                haveAlpha;
+    unsigned int        alphaPlane;
+    bool                haveAnd;
+    unsigned int        andPlane;
+    GetPixelFn *        getPixel;
+    struct Palette      palette;
+    bool                doingPng;
+        
+    /*  Output:
+     *
+     *  threshold^2 pixels or more:
+     *      no alpha channel:        PNG (RGB)
+     *      alpha channel:           PNG (RGBA)
+     *      alpha channel +AND mask: PNG (RGBA), AND mask dropped
+     *  alpha values other than 0 and maxval: 32bit +alpha BMP
+     *  no more than   2 colors:  1bit or 32bit BMP
+     *  no more than  16 colors:  4bit or 32bit BMP
+     *  no more than 256 colors:  8bit or 32bit BMP
+     *  more than    256 colors: 32bit BMP
+     */
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (pam.width > 256 || pam.height > 256)
+        pm_error("Image %u: too large as a windows icon (%u x %u).  "
+                 "Maximum allowed dimension is 256",
+                 imageNum, pam.width, pam.height);
+
+    tuples = pnm_allocpamarray(&pam);
+
+    doingPng = pam.width * pam.height >= pngThreshold;
+
+    readAndScalePam(&pam, doingPng, tuples);
+
+    determineImageType(&pam, tuples, &getPixel,
+                       &haveAlpha, &alphaPlane, &haveAnd, &andPlane);
+
+    getPalette(&pam, tuples, getPixel, &palette);
+
+    if (verbose)
+        reportImageInfo(imageNum, &pam, &palette, haveAlpha, haveAnd);
+
+    writeIconAndCreateDirEntry(&pam, tuples, getPixel, doingPng,
+                               haveAlpha, alphaPlane,
+                               haveAnd, andPlane,
+                               mustBlackenXor,
+                               &palette,
+                               ofP, &dirEntry);
+
+    if (verbose)
+        pm_message("Image %2u: %u bytes", imageNum, dirEntry.size);
+
+    pnm_freepamarray(tuples, &pam);
+
+    addToDirectory(&dirEntry, dirP);
+}
+
+
+
+static void
+convert(FILE *           const ifP,
+        unsigned int     const pngThreshold,
+        bool             const mustBlackenXor,
+        struct IconDir * const dirP,
+        FILE *           const ofP) {
+/*----------------------------------------------------------------------------
+  Read a (multi-image) PAM file from *ifP and convert the individual images
+  to the proper format for a Windows icon file and write those to *ofP.
+
+  Where the number of pixels in an image is at least 'pngThreshold', use
+  a PNG image.  Otherwise, use a BMP.
+-----------------------------------------------------------------------------*/
+    unsigned int imageNum;
+    int eof;
+    
+    for (imageNum = 0, eof = false; !eof; ++imageNum) {
+        convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor,
+                        ofP, dirP);
+
+        pnm_nextimage(ifP, &eof);
+    }
+}
+
+
+
+static void
+writeIconDirEntry(const struct IconDirEntry * const dirEntryP,
+                  FILE *                      const ofP) {
+        
+    pm_writecharu        (ofP, dirEntryP->width);
+    pm_writecharu        (ofP, dirEntryP->height);
+    pm_writecharu        (ofP, dirEntryP->color_count);
+    pm_writecharu        (ofP, dirEntryP->zero);
+    pm_writelittleshortu (ofP, dirEntryP->color_planes);
+    pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel);
+    pm_writelittlelongu  (ofP, dirEntryP->size); 
+    pm_writelittlelongu  (ofP, dirEntryP->offset);
+}
+
+
+
+static void
+writeIconDirectory(const struct IconDir * const dirP,
+                   FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write to file *ofP the icon directory described by *dirP.
+
+  *dirP's image offset members are meaningless as input.  We fill them in.
+-----------------------------------------------------------------------------*/
+    uint32_t const hsize = 6 + dirP->count * 16;
+
+    unsigned int imageNum;
+    unsigned int imageOffset;
+
+    pm_writelittleshortu(ofP, dirP->zero);
+    pm_writelittleshortu(ofP, dirP->type);
+    pm_writelittleshortu(ofP, dirP->count);
+
+    for (imageNum = 0, imageOffset = hsize;
+         imageNum < dirP->count;
+         ++imageNum) {
+
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum];
+        
+        pm_message("image %2u: %3u x %3u x %2u",
+                   imageNum,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   dirEntryP->bits_per_pixel);
+
+        dirEntryP->offset = imageOffset;
+
+        writeIconDirEntry(dirEntryP, ofP);
+
+        imageOffset += dirEntryP->size;
+    }
+}
+
+
+
+static void
+copyFile(FILE * const ifP,
+         FILE * const ofP) {
+
+    bool eof;
+    
+    for (eof = false; !eof; ) {
+        unsigned char buffer[1024];
+        size_t bytesRead;
+
+        bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+
+        if (bytesRead == 0)
+            eof = true;
+        else {
+            size_t bytesWritten;
+
+            bytesWritten = fwrite(buffer, 1, bytesRead, ofP);
+
+            if (bytesWritten < bytesRead)
+                pm_error("Error writing to output file.");
+        }
+    }
+}
+
+
+
+static void
+writeIconFile(const struct IconDir * const dirP,
+              FILE *                 const imagesFileP,
+              FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write a windows icon file.
+
+  *dirP is the icon directory to put in it.
+
+  *imagesFileP contains all the text of the icon images.  The contents of
+  this file go verbatim into the output.
+-----------------------------------------------------------------------------*/
+    writeIconDirectory(dirP, ofP);
+
+    copyFile(imagesFileP, ofP);
+}
+
+
+
+int
+main(int argc, const char *argv []) {
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * imagesFileP;
+        /* This is the file in which we collect the individual icon
+           images to be copied later to the output.
+        */
+    struct IconDir * dirP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    /* The output icon file has directory information at the top that we
+       can't know until we have looked at the input images.  So as we pass
+       through the input, we collect the directory information and generate
+       the individual icon images and store them in *imageFileP.  When we've
+       been through all of the input, we write out the directory and then
+       copy the images from *imageFileP to the output.
+    */
+
+    dirP = newIconDir();
+
+    imagesFileP = pm_tmpfile();
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    convert(ifP, SQR(cmdline.pngthreshold), cmdline.truetransparent,
+            dirP, imagesFileP);
+
+    rewind(imagesFileP);
+
+    writeIconFile(dirP, imagesFileP, stdout);
+
+    freeIconDir(dirP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
index e1aa9b52..b57bcc74 100644
--- a/converter/other/pamtoxvmini.c
+++ b/converter/other/pamtoxvmini.c
@@ -152,14 +152,14 @@ getPaletteIndexThroughCache(struct pam *      const pamP,
    If the tuple-index association is in *paletteIndexP, use it.  If not,
    find it the hard way and add it to *palettedIndexP for the next guy.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int paletteIndex;
 
     pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
     if (found)
         *paletteIndexP = paletteIndex;
     else {
-        bool fits;
+        int fits;
         findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
         
         pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c
index 83fdf7bf..4cd7c4d0 100644
--- a/converter/other/pnmtopclxl.c
+++ b/converter/other/pnmtopclxl.c
@@ -1177,7 +1177,7 @@ printPages(int                 const outFd,
     while (sourceP) {
         FILE * ifP;
         struct pam pam;
-        bool eof;
+        int eof;
         unsigned int pageNum;
 
         ifP = pm_openr(sourceP->name);
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index edbe57f5..bcb94612 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -128,7 +128,6 @@ struct cmdlineInfo {
     int           filterSet;
     unsigned int  force;
     unsigned int  libversion;
-    unsigned int  compressionSpec;
     struct zlibCompression zlibCompression;
 };
 
@@ -480,6 +479,27 @@ parseCommandLine(int argc, const char ** argv,
 
 
 
+static void
+reportInputType(int    const format,
+                xelval const maxval) {
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        pm_message ("reading a PBM file");
+        break;
+    case PGM_TYPE:
+        pm_message ("reading a PGM file (maxval=%d)", maxval);
+        break;
+    case PPM_TYPE:
+        pm_message ("reading a PPM file (maxval=%d)", maxval);
+        break;
+    default:
+        assert(false);
+    }
+}
+
+
+
 static png_color_16
 xelToPngColor_16(xel    const input, 
                  xelval const maxval, 
@@ -857,7 +877,7 @@ tryTransparentColor(FILE *     const ifp,
                     pixel      const transcolor,
                     bool *     const singleColorIsTransP) {
 
-    int const pnm_type = PNM_FORMAT_TYPE(format);
+    int const pnmType = PNM_FORMAT_TYPE(format);
 
     xel * xelrow;
     bool singleColorIsTrans;
@@ -878,7 +898,7 @@ tryTransparentColor(FILE *     const ifp,
                 /* If we have a second transparent color, we're
                    disqualified
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (!PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -895,7 +915,7 @@ tryTransparentColor(FILE *     const ifp,
                    the same color as our candidate transparent color,
                    that disqualifies us.
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -1118,6 +1138,51 @@ determineBackground(struct cmdlineInfo const cmdline,
 
 
 
+static bool
+hasColor(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         xelval       const maxval,
+         int          const format,
+         pm_filepos   const rasterPos) {
+/*----------------------------------------------------------------------------
+   The image contains colors other than black, white, and gray.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+        unsigned int row;
+        xel * xelrow;    /* malloc'ed */
+            /* The row of the input image currently being analyzed */
+        bool isGray;
+
+        xelrow = pnm_allocrow(cols);
+
+        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+        for (row = 0, isGray = true; row < rows && isGray; ++row) {
+            unsigned int col;
+
+            pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+
+            for (col = 0; col < cols && isGray; ++col) {
+                    xel const p = xelrow[col];
+                if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
+                    isGray = FALSE;
+            }
+        }
+
+        pnm_freerow(xelrow);
+
+        retval = !isGray;
+    } else
+        retval = false;
+
+    return retval;
+}
+
+
+
 static void
 findRedundantBits(FILE *         const ifp, 
                   int            const rasterPos, 
@@ -1819,19 +1884,19 @@ tryAlphaPalette(FILE *         const ifP,
 
 
 static void
-computePixelWidth(int            const pnm_type,
-                  unsigned int   const pnm_meaningful_bits,
+computePixelWidth(bool           const colorPng,
+                  unsigned int   const pnmMeaningfulBitCt,
                   bool           const alpha,
                   unsigned int * const bitsPerSampleP,
                   unsigned int * const bitsPerPixelP) {
 
     unsigned int bitsPerSample, bitsPerPixel;
 
-    if (pnm_type == PPM_TYPE || alpha) {
+    if (colorPng || alpha) {
         /* PNG allows only depths of 8 and 16 for a truecolor image 
            and for a grayscale image with an alpha channel.
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
         else 
             bitsPerSample = 8;
@@ -1839,24 +1904,24 @@ computePixelWidth(int            const pnm_type,
         /* A grayscale, non-colormapped, no-alpha PNG may have any 
              bit depth from 1 to 16
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
-        else if (pnm_meaningful_bits > 4)
+        else if (pnmMeaningfulBitCt > 4)
             bitsPerSample = 8;
-        else if (pnm_meaningful_bits > 2)
+        else if (pnmMeaningfulBitCt > 2)
             bitsPerSample = 4;
-        else if (pnm_meaningful_bits > 1)
+        else if (pnmMeaningfulBitCt > 1)
             bitsPerSample = 2;
         else
             bitsPerSample = 1;
     }
     if (alpha) {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 4 * bitsPerSample;
         else
             bitsPerPixel = 2 * bitsPerSample;
     } else {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 3 * bitsPerSample;
         else
             bitsPerPixel = bitsPerSample;
@@ -1904,7 +1969,7 @@ computeColorMap(FILE *         const ifP,
                 int            const cols,
                 int            const rows,
                 xelval         const maxval,
-                int            const pnmType,
+                bool           const colorPng,
                 int            const format,
                 bool           const force,
                 FILE *         const pfP,
@@ -1947,6 +2012,8 @@ computeColorMap(FILE *         const ifP,
 
   If the image is to have a background color, we return the palette index
   of that color as *backgroundIndexP.
+
+  'colorPng' means the PNG will be of the RGB variety.
 -------------------------------------------------------------------------- */
     if (force)
         pm_asprintf(noColormapReasonP, "You requested no color map");
@@ -1956,7 +2023,7 @@ computeColorMap(FILE *         const ifP,
                     maxval, PALETTEMAXVAL);
     else {
         unsigned int bitsPerPixel;
-        computePixelWidth(pnmType, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnm_meaningful_bits, alpha,
                           NULL, &bitsPerPixel);
 
         if (!pfP && bitsPerPixel == 1)
@@ -2069,9 +2136,9 @@ static void computeColorMapLookupTable(
 
 static void
 computeRasterWidth(bool           const colorMapped,
-                   unsigned int   const palette_size,
-                   int            const pnm_type,
-                   unsigned int   const pnm_meaningful_bits,
+                   unsigned int   const paletteSize,
+                   bool           const colorPng,
+                   unsigned int   const pnmMeaningfulBitCt,
                    bool           const alpha,
                    unsigned int * const bitsPerSampleP,
                    unsigned int * const bitsPerPixelP) {
@@ -2082,24 +2149,24 @@ computeRasterWidth(bool           const colorMapped,
 -----------------------------------------------------------------------------*/
     if (colorMapped) {
         /* The raster element is a palette index */
-        if (palette_size <= 2)
+        if (paletteSize <= 2)
             *bitsPerSampleP = 1;
-        else if (palette_size <= 4)
+        else if (paletteSize <= 4)
             *bitsPerSampleP = 2;
-        else if (palette_size <= 16)
+        else if (paletteSize <= 16)
             *bitsPerSampleP = 4;
         else
             *bitsPerSampleP = 8;
         *bitsPerPixelP = *bitsPerSampleP;
         if (verbose)
-            pm_message("Writing %d-bit color indexes", *bitsPerSampleP);
+            pm_message("Writing %u-bit color indexes", *bitsPerSampleP);
     } else {
         /* The raster element is an explicit pixel -- color and transparency */
-        computePixelWidth(pnm_type, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnmMeaningfulBitCt, alpha,
                           bitsPerSampleP, bitsPerPixelP);
 
         if (verbose)
-            pm_message("Writing %d bits per component per pixel", 
+            pm_message("Writing %u bits per component per pixel", 
                        *bitsPerSampleP);
     }
 }
@@ -2339,14 +2406,14 @@ doIhdrChunk(struct pngx * const pngxP,
             unsigned int  const height,
             unsigned int  const depth,
             bool          const colorMapped,
-            int           const pnmType,
+            bool          const colorPng,
             bool          const alpha) {
 
     int colorType;
 
     if (colorMapped)
         colorType = PNG_COLOR_TYPE_PALETTE;
-    else if (pnmType == PPM_TYPE)
+    else if (colorPng)
         colorType = PNG_COLOR_TYPE_RGB;
     else
         colorType = PNG_COLOR_TYPE_GRAY;
@@ -2552,252 +2619,235 @@ convertpnm(struct cmdlineInfo const cmdline,
    lazy -- it takes a great deal of work to carry all that information as
    separate arguments -- and it's only a very small violation.
 -----------------------------------------------------------------------------*/
-  xel p;
-  int rows, cols, format;
-  xelval maxval;
-      /* The maxval of the input image */
-  xelval png_maxval;
-      /* The maxval of the samples in the PNG output 
-         (must be 1, 3, 7, 15, 255, or 65535)
-      */
-  pixel transcolor;
-      /* The color that is to be transparent, with maxval equal to that
-         of the input image.
-      */
-  int transexact;  
-      /* boolean: the user wants only the exact color he specified to be
-         transparent; not just something close to it.
-      */
-  int transparent;
-  bool alpha;
-      /* There will be an alpha mask */
-  unsigned int pnm_meaningful_bits;
-  pixel backcolor;
-      /* The background color, with maxval equal to that of the input
-         image.
-      */
-  jmp_buf jmpbuf;
-  struct pngx * pngxP;
-
-  bool colorMapped;
-  pixel palettePnm[MAXCOLORS];
-  png_color palette[MAXCOLORS];
-      /* The color part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int paletteSize;
-
-  gray transPnm[MAXCOLORS];
-  png_byte  trans[MAXCOLORS];
-      /* The alpha part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int transSize;
-
-  colorhash_table cht;
-  coloralphahash_table caht;
-
-  unsigned int background_index;
-      /* Index into palette[] of the background color. */
-
-  gray alphaMaxval;
-  const char * noColormapReason;
-      /* The reason that we shouldn't make a colormapped PNG, or NULL if
-         we should.  malloc'ed null-terminated string.
-      */
-  unsigned int depth;
-      /* The number of bits per sample in the (uncompressed) png 
-         raster -- if the raster contains palette indices, this is the
-         number of bits in the index.
-      */
-  unsigned int fulldepth;
-      /* The total number of bits per pixel in the (uncompressed) png
-         raster, including all channels.
-      */
-  pm_filepos rasterPos;  
-      /* file position in input image file of start of image (i.e. after
-         the header)
-      */
-  xel *xelrow;    /* malloc'ed */
-      /* The row of the input image currently being processed */
-
-  int pnmType;
-  gray ** alpha_mask;
-
-  /* We initialize these guys to quiet compiler warnings: */
-  depth = 0;
-
-  errorlevel = 0;
-
-  if (setjmp(jmpbuf))
-      pm_error ("setjmp returns error condition");
-
-  pngx_create(&pngxP, PNGX_WRITE, &jmpbuf);
-
-  pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
-  pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
-  pnmType = PNM_FORMAT_TYPE(format);
-
-  xelrow = pnm_allocrow(cols);
-
-  if (verbose) {
-      if (pnmType == PBM_TYPE)    
-          pm_message ("reading a PBM file");
-      else if (pnmType == PGM_TYPE)    
-          pm_message ("reading a PGM file (maxval=%d)", maxval);
-      else if (pnmType == PPM_TYPE)    
-          pm_message ("reading a PPM file (maxval=%d)", maxval);
-  }
-
-  determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format,
-                        afP,
-                        &alpha, &transparent, &transcolor, &transexact,
-                        &alpha_mask, &alphaMaxval);
-
-  determineBackground(cmdline, maxval, &backcolor);
-
-  /* first of all, check if we have a grayscale image written as PPM */
-
-  if (pnmType == PPM_TYPE && !cmdline.force) {
-      unsigned int row;
-      bool isgray;
-
-      isgray = TRUE;  /* initial assumption */
-      pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
-      for (row = 0; row < rows && isgray; ++row) {
-          unsigned int col;
-          pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
-          for (col = 0; col < cols && isgray; ++col) {
-              p = xelrow[col];
-              if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
-                  isgray = FALSE;
-          }
-      }
-      if (isgray)
-          pnmType = PGM_TYPE;
-  }
-
-  /* handle `odd' maxvalues */
-
-  if (maxval > 65535 && !cmdline.downscale) {
-      pm_error("can only handle files up to 16-bit "
-               "(use -downscale to override");
-  }
-
-  findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha,
-                    cmdline.force, &pnm_meaningful_bits);
+    int rows, cols, format;
+    xelval maxval;
+    /* The maxval of the input image */
+    xelval pngMaxval;
+        /* The maxval of the samples in the PNG output 
+           (must be 1, 3, 7, 15, 255, or 65535)
+        */
+    pixel transcolor;
+        /* The color that is to be transparent, with maxval equal to that
+           of the input image.
+        */
+    bool transExact;  
+        /* boolean: the user wants only the exact color he specified to be
+           transparent; not just something close to it.
+        */
+    int transparent;
+    bool alpha;
+        /* There will be an alpha mask */
+    unsigned int pnmMeaningfulBitCt;
+    pixel backColor;
+        /* The background color, with maxval equal to that of the input
+           image.
+        */
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
+
+    bool colorMapped;
+    pixel palettePnm[MAXCOLORS];
+    png_color palette[MAXCOLORS];
+        /* The color part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int paletteSize;
+
+    gray transPnm[MAXCOLORS];
+    png_byte  trans[MAXCOLORS];
+        /* The alpha part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int transSize;
+
+    colorhash_table cht;
+    coloralphahash_table caht;
+
+    unsigned int backgroundIndex;
+        /* Index into palette[] of the background color. */
+
+    gray alphaMaxval;
+    const char * noColormapReason;
+        /* The reason that we shouldn't make a colormapped PNG, or NULL if
+           we should.  malloc'ed null-terminated string.
+        */
+    unsigned int depth;
+        /* The number of bits per sample in the (uncompressed) png 
+           raster -- if the raster contains palette indices, this is the
+           number of bits in the index.
+        */
+    unsigned int fulldepth;
+        /* The total number of bits per pixel in the (uncompressed) png
+           raster, including all channels.
+        */
+    pm_filepos rasterPos;  
+        /* file position in input image file of start of image (i.e. after
+           the header)
+        */
+    xel * xelrow;    /* malloc'ed */
+        /* The row of the input image currently being processed */
+
+    gray ** alpha_mask;
+
+    bool colorPng;
+        /* The PNG shall be of the color (RGB) variety */
+
+    /* We initialize these guys to quiet compiler warnings: */
+    depth = 0;
+
+    errorlevel = 0;
+
+    if (setjmp(jmpbuf))
+        pm_error ("setjmp returns error condition");
+
+    pngx_create(&pngxP, PNGX_WRITE, &jmpbuf);
+
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    xelrow = pnm_allocrow(cols);
+
+    if (verbose)
+        reportInputType(format, maxval);
+
+    determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format,
+                          afP,
+                          &alpha, &transparent, &transcolor, &transExact,
+                          &alpha_mask, &alphaMaxval);
+
+    determineBackground(cmdline, maxval, &backColor);
+
+    if (cmdline.force)
+        colorPng = (PNM_FORMAT_TYPE(format) == PPM_TYPE);
+    else {
+        if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+            colorPng = hasColor(ifP, cols, rows, maxval, format, rasterPos); 
+        } else
+            colorPng = false;
+    }
+
+
+    /* handle `odd' maxvalues */
+
+    if (maxval > 65535 && !cmdline.downscale) {
+        pm_error("can only handle files up to 16-bit "
+                 "(use -downscale to override");
+    }
+
+    findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha,
+                      cmdline.force, &pnmMeaningfulBitCt);
   
-  computeColorMap(ifP, rasterPos, cols, rows, maxval, pnmType, format,
-                  cmdline.force, pfP,
-                  alpha, transparent >= 0, transcolor, transexact, 
-                  !!cmdline.background, backcolor,
-                  alpha_mask, alphaMaxval, pnm_meaningful_bits,
-                  palettePnm, &paletteSize, transPnm, &transSize,
-                  &background_index, &noColormapReason);
-
-  if (noColormapReason) {
-      if (pfP)
-          pm_error("You specified a particular palette, but this image "
-                   "cannot be represented by any palette.  %s",
-                   noColormapReason);
-      if (verbose)
-          pm_message("Not using color map.  %s", noColormapReason);
-      pm_strfree(noColormapReason);
-      colorMapped = FALSE;
-  } else
-      colorMapped = TRUE;
+    computeColorMap(ifP, rasterPos, cols, rows, maxval, colorPng, format,
+                    cmdline.force, pfP,
+                    alpha, transparent >= 0, transcolor, transExact, 
+                    !!cmdline.background, backColor,
+                    alpha_mask, alphaMaxval, pnmMeaningfulBitCt,
+                    palettePnm, &paletteSize, transPnm, &transSize,
+                    &backgroundIndex, &noColormapReason);
+
+    if (noColormapReason) {
+        if (pfP)
+            pm_error("You specified a particular palette, but this image "
+                     "cannot be represented by any palette.  %s",
+                     noColormapReason);
+        if (verbose)
+            pm_message("Not using color map.  %s", noColormapReason);
+        pm_strfree(noColormapReason);
+        colorMapped = FALSE;
+    } else
+        colorMapped = TRUE;
   
-  computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
-                             transPnm, transSize, alpha, alphaMaxval,
-                             &cht, &caht);
+    computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
+                               transPnm, transSize, alpha, alphaMaxval,
+                               &cht, &caht);
 
-  computeRasterWidth(colorMapped, paletteSize, pnmType, 
-                     pnm_meaningful_bits, alpha,
-                     &depth, &fulldepth);
-  if (verbose)
-    pm_message ("writing a%s %d-bit %s%s file%s",
-                fulldepth == 8 ? "n" : "", fulldepth,
-                colorMapped ? "palette": 
-                (pnmType == PPM_TYPE ? "RGB" : "gray"),
-                alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
-                cmdline.interlace ? " (interlaced)" : "");
+    computeRasterWidth(colorMapped, paletteSize, colorPng,
+                       pnmMeaningfulBitCt, alpha,
+                       &depth, &fulldepth);
+    if (verbose)
+        pm_message ("writing a%s %d-bit %s%s file%s",
+                    fulldepth == 8 ? "n" : "", fulldepth,
+                    colorMapped ? "palette": 
+                    colorPng ? "RGB" : "gray",
+                    alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
+                    cmdline.interlace ? " (interlaced)" : "");
 
-  /* now write the file */
+    /* now write the file */
 
-  png_maxval = pm_bitstomaxval(depth);
+    pngMaxval = pm_bitstomaxval(depth);
 
-  if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
-    pm_error ("setjmp returns error condition (2)");
-  }
+    if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
+        pm_error ("setjmp returns error condition (2)");
+    }
 
-  doIhdrChunk(pngxP, cols, rows, depth, colorMapped, pnmType, alpha);
+    doIhdrChunk(pngxP, cols, rows, depth, colorMapped, colorPng, alpha);
 
-  if (cmdline.interlace)
-      pngx_setInterlaceHandling(pngxP);
+    if (cmdline.interlace)
+        pngx_setInterlaceHandling(pngxP);
 
-  doGamaChunk(cmdline, pngxP);
+    doGamaChunk(cmdline, pngxP);
 
-  doChrmChunk(cmdline, pngxP);
+    doChrmChunk(cmdline, pngxP);
 
-  doPhysChunk(cmdline, pngxP);
+    doPhysChunk(cmdline, pngxP);
 
-  if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
 
-      /* creating PNG palette (Not counting the transparency palette) */
+        /* creating PNG palette (Not counting the transparency palette) */
 
-      createPngPalette(palettePnm, paletteSize, maxval,
-                       transPnm, transSize, alphaMaxval, 
-                       palette, trans);
-      pngx_setPlte(pngxP, palette, paletteSize);
+        createPngPalette(palettePnm, paletteSize, maxval,
+                         transPnm, transSize, alphaMaxval, 
+                         palette, trans);
+        pngx_setPlte(pngxP, palette, paletteSize);
 
-      doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos,
-                  cols, rows, maxval, format, cmdline.verbose);
-  }
+        doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos,
+                    cols, rows, maxval, format, cmdline.verbose);
+    }
 
-  doTrnsChunk(pngxP, trans, transSize,
-              transparent, transcolor, maxval, png_maxval);
+    doTrnsChunk(pngxP, trans, transSize,
+                transparent, transcolor, maxval, pngMaxval);
 
-  doBkgdChunk(pngxP, !!cmdline.background,
-              background_index, backcolor,
-              maxval, png_maxval, cmdline.verbose);
+    doBkgdChunk(pngxP, !!cmdline.background,
+                backgroundIndex, backColor,
+                maxval, pngMaxval, cmdline.verbose);
 
-  doSbitChunk(pngxP, png_maxval, maxval, alpha, alphaMaxval);
+    doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval);
 
-  /* tEXT and zTXT chunks */
-  if (cmdline.text || cmdline.ztxt)
-      pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose);
+    /* tEXT and zTXT chunks */
+    if (cmdline.text || cmdline.ztxt)
+        pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose);
 
-  doTimeChunk(cmdline, pngxP);
+    doTimeChunk(cmdline, pngxP);
 
-  if (cmdline.filterSet != 0)
-      pngx_setFilter(pngxP, cmdline.filterSet);
+    if (cmdline.filterSet != 0)
+        pngx_setFilter(pngxP, cmdline.filterSet);
 
-  setZlibCompression(pngxP, cmdline.zlibCompression);
+    setZlibCompression(pngxP, cmdline.zlibCompression);
 
-  png_init_io(pngxP->png_ptr, ofP);
+    png_init_io(pngxP->png_ptr, ofP);
 
-  /* write the png-info struct */
-  pngx_writeInfo(pngxP);
+    /* write the png-info struct */
+    pngx_writeInfo(pngxP);
 
-  /* let libpng take care of, e.g., bit-depth conversions */
-  pngx_setPacking(pngxP);
+    /* let libpng take care of, e.g., bit-depth conversions */
+    pngx_setPacking(pngxP);
 
-  writeRaster(pngxP, ifP, rasterPos,
-              cols, rows, maxval, format,
-              png_maxval, depth, alpha, alpha_mask, cht, caht);
+    writeRaster(pngxP, ifP, rasterPos,
+                cols, rows, maxval, format,
+                pngMaxval, depth, alpha, alpha_mask, cht, caht);
 
-  pngx_writeEnd(pngxP);
+    pngx_writeEnd(pngxP);
 
-  pngx_destroy(pngxP);
+    pngx_destroy(pngxP);
 
-  pnm_freerow(xelrow);
+    pnm_freerow(xelrow);
 
-  if (cht)
-      ppm_freecolorhash(cht);
-  if (caht)
-      freecoloralphahash(caht);
+    if (cht)
+        ppm_freecolorhash(cht);
+    if (caht)
+        freecoloralphahash(caht);
 
-  *errorLevelP = errorlevel;
+    *errorLevelP = errorlevel;
 }
 
 
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index dc55a7e3..1cf23be7 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -335,6 +335,22 @@ basebasename(const char * const filespec) {
 
 
 
+static void
+writeFile(const unsigned char * const buffer,
+          size_t                const writeCt,
+          const char *          const name,
+          FILE *                const ofP) {
+
+    size_t writtenCt;
+
+    writtenCt = fwrite(buffer, 1, writeCt, ofP);
+
+    if (writtenCt != writeCt)
+        pm_error("Error writing to %s output file", name);
+}
+
+
+
 #define MAX_FILTER_CT 10
     /* The maximum number of filters this code is capable of applying */
 
@@ -494,18 +510,12 @@ flateFilter(FILE *          const ifP,
         */
         do {
             unsigned int have;
-            size_t bytesWritten;
 
             strm.avail_out = chunkSz;
             strm.next_out = out;
             deflate(&strm, flush);
             have = chunkSz - strm.avail_out;
-            bytesWritten = fwrite(out, 1, have, ofP);
-            if (ferror(ofP) || bytesWritten != have) {
-                deflateEnd(&strm);
-                pm_error("Error writing to internal pipe during "
-                         "flate compression.");
-            }
+            writeFile(out, have, "flate filter", ofP);
         } while (strm.avail_out == 0);
         assert(strm.avail_in == 0);     /* all input is used */
 
@@ -548,10 +558,8 @@ rlePutBuffer (unsigned int    const repeat,
     if (repeat) {
         fputc(257 - count,  fP);
         fputc(repeatitem, fP);
-    } else {
-        fputc(count - 1, fP);
-        fwrite(itembuf, 1, count, fP);
-    }
+    } else
+        writeFile(itembuf, count, "rlePutBuffer", fP);
 }
 
 
@@ -673,23 +681,24 @@ asciiHexFilter(FILE *          const ifP,
     unsigned char inbuff[40], outbuff[81];
 
     for (eof = false; !eof; ) {
-        size_t bytesRead;
+        size_t readCt;
 
-        bytesRead = fread(inbuff, 1, 40, ifP);
+        readCt = fread(inbuff, 1, 40, ifP);
 
-        if (bytesRead == 0)
+        if (readCt == 0)
             eof = true;
         else {
             unsigned int i;
 
-            for (i = 0; i < bytesRead; ++i) {
+            for (i = 0; i < readCt; ++i) {
                 int const item = inbuff[i]; 
                 outbuff[i*2]   = hexits[item >> 4];
                 outbuff[i*2+1] = hexits[item & 15];
             }
         }
-        outbuff[bytesRead * 2] = '\n';
-        fwrite(outbuff, 1, bytesRead*2 + 1, ofP);
+        outbuff[readCt * 2] = '\n';
+
+        writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
     }
 
     fclose(ifP);
@@ -737,7 +746,9 @@ ascii85Filter(FILE *          const ifP,
                 outbuff[1] = value % 85 + 33;
                 outbuff[0] = value / 85 + 33;
 
-                fwrite(outbuff, 1, count + 1, ofP);
+                writeFile((const unsigned char *)outbuff, count + 1,
+                          "ASCII 85 filter", ofP);
+
                 count = value = 0;
                 outcount += 5; 
             }
@@ -759,7 +770,8 @@ ascii85Filter(FILE *          const ifP,
         outbuff[0] = value / 85 + 33;
         outbuff[count + 1] = '\n';
 
-        fwrite(outbuff, 1, count + 2, ofP);
+        writeFile((const unsigned char *)outbuff, count + 2,
+                  "ASCII 85 filter", ofP);
     }
 
     fclose(ifP);
@@ -869,13 +881,22 @@ addFilter(const char *    const description,
           OutputEncoder * const oeP,
           FILE **         const feedFilePP,
           pid_t *         const pidList) {
+/*----------------------------------------------------------------------------
+   Add a filter to the front of the chain.
 
-    pid_t pid;
+   Spawn a process to do the filtering, by running function 'filter'.
 
+   *feedFilePP is the present head of the chain.  We make the new filter
+   process write its output to that and get its input from a new pipe.
+   We update *feedFilePP to the sending end of the new pipe.
+
+   Add to the list pidList[] the PID of the process we spawn.
+-----------------------------------------------------------------------------*/
     FILE * const oldFeedFileP = *feedFilePP;
 
     FILE * newFeedFileP;
-        
+    pid_t pid;
+
     spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid);
             
     if (verbose)
@@ -883,7 +904,7 @@ addFilter(const char *    const description,
                    description, (unsigned)pid);
     
     fclose(oldFeedFileP);  /* Child keeps this open now */
-    
+
     addToPidList(pidList, pid);
 
     *feedFilePP = newFeedFileP;
@@ -1720,7 +1741,7 @@ convertRowPbm(struct pam *     const pamP,
         bitrow[colChars-1] <<= padRight;  /* right edge */
     }
 
-    fwrite(bitrow, 1, colChars, fP); 
+    writeFile(bitrow, colChars, "PBM reader", fP);
 }
 
 
@@ -1863,6 +1884,21 @@ convertRaster(struct pam * const inpamP,
 
 
 
+/* FILE MANAGEMENT: File management is pretty hairy here.  A filter, which
+   runs in its own process, needs to be able to cause its output file to
+   close because it might be an internal pipe and the next stage needs to
+   know output is done.  So the forking process must close its copy of the
+   file descriptor.  BUT: if the output of the filter is not an internal
+   pipe but this program's output, then we don't want it closed when the
+   filter terminates because we'll need it to be open for the next image
+   the program converts (with a whole new chain of filters).
+   
+   To prevent the progam output file from getting closed, we pass a
+   duplicate of it to spawnFilters() and keep the original open.
+*/
+
+
+
 static void
 convertPage(FILE *       const ifP, 
             int          const turnflag, 
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index 1dd27140..3704841b 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -18,6 +18,7 @@
 #define _XOPEN_SOURCE 500  
     /* Make sure fdopen() is in stdio.h and strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -32,8 +33,8 @@
 #include "shhopt.h"
 #include "nstring.h"
 
-enum orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
-struct box {
+enum Orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
+struct Box {
     /* Description of a rectangle within an image; all coordinates 
        measured in points (1/72") with lower left corner of page being the 
        origin.
@@ -45,15 +46,15 @@ struct box {
     int ury;  /* upper right Y coord */
 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* Names of input files */
     unsigned int forceplain;
-    struct box extract_box;
+    struct Box extractBox;
     unsigned int nocrop;
-    unsigned int format_type;
+    unsigned int formatType;
     unsigned int verbose;
     float xborder;
     unsigned int xmax;
@@ -62,15 +63,15 @@ struct cmdlineInfo {
     unsigned int ymax;
     unsigned int ysize;  /* zero means unspecified */
     unsigned int dpi;    /* zero means unspecified */
-    enum orientation orientation;
-    unsigned int goto_stdout;
+    enum Orientation orientation;
+    unsigned int stdout;
     unsigned int textalphabits;
 };
 
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -82,8 +83,8 @@ parseCommandLine(int argc, char ** argv,
 
     unsigned int option_def_index;
 
-    unsigned int pbm_opt, pgm_opt, ppm_opt;
-    unsigned int portrait_opt, landscape_opt;
+    unsigned int pbmOpt, pgmOpt, ppmOpt;
+    unsigned int portraitOpt, landscapeOpt;
     float llx, lly, urx, ury;
     unsigned int llxSpec, llySpec, urxSpec, urySpec;
     unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec;
@@ -98,9 +99,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "urx",        OPT_FLOAT, &urx, &urxSpec,                  0);
     OPTENT3(0, "ury",        OPT_FLOAT, &ury, &urySpec,                  0);
     OPTENT3(0, "nocrop",     OPT_FLAG,  NULL, &cmdlineP->nocrop,         0);
-    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbm_opt,                  0);
-    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgm_opt,                  0);
-    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppm_opt,                  0);
+    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbmOpt ,                  0);
+    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgmOpt,                   0);
+    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppmOpt,                  0);
     OPTENT3(0, "verbose",    OPT_FLAG,  NULL, &cmdlineP->verbose,        0);
     OPTENT3(0, "xborder",    OPT_FLOAT, &cmdlineP->xborder, NULL,        0);
     OPTENT3(0, "xmax",       OPT_UINT,  &cmdlineP->xmax, &xmaxSpec,      0);
@@ -109,9 +110,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "ymax",       OPT_UINT,  &cmdlineP->ymax, &ymaxSpec,      0);
     OPTENT3(0, "ysize",      OPT_UINT,  &cmdlineP->ysize, &ysizeSpec,    0);
     OPTENT3(0, "dpi",        OPT_UINT,  &cmdlineP->dpi, &dpiSpec,        0);
-    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portrait_opt,             0);
-    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscape_opt,            0);
-    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->goto_stdout,    0);
+    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portraitOpt,             0);
+    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscapeOpt,            0);
+    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->stdout,         0);
     OPTENT3(0, "textalphabits", OPT_UINT,
             &cmdlineP->textalphabits,  &textalphabitsSpec, 0);
 
@@ -149,38 +150,38 @@ parseCommandLine(int argc, char ** argv,
     } else 
         cmdlineP->ysize = 0;
 
-    if (portrait_opt && !landscape_opt)
+    if (portraitOpt && !landscapeOpt)
         cmdlineP->orientation = PORTRAIT;
-    else if (!portrait_opt && landscape_opt)
+    else if (!portraitOpt && landscapeOpt)
         cmdlineP->orientation = LANDSCAPE;
-    else if (!portrait_opt && !landscape_opt)
+    else if (!portraitOpt && !landscapeOpt)
         cmdlineP->orientation = UNSPECIFIED;
     else
         pm_error("Cannot specify both -portrait and -landscape options");
 
-    if (pbm_opt)
-        cmdlineP->format_type = PBM_TYPE;
-    else if (pgm_opt)
-        cmdlineP->format_type = PGM_TYPE;
-    else if (ppm_opt)
-        cmdlineP->format_type = PPM_TYPE;
+    if (pbmOpt)
+        cmdlineP->formatType = PBM_TYPE;
+    else if (pgmOpt)
+        cmdlineP->formatType = PGM_TYPE;
+    else if (ppmOpt)
+        cmdlineP->formatType = PPM_TYPE;
     else
-        cmdlineP->format_type = PPM_TYPE;
+        cmdlineP->formatType = PPM_TYPE;
 
     /* If any one of the 4 bounding box coordinates is given on the
        command line, we default any of the 4 that aren't.  
     */
     if (llxSpec || llySpec || urxSpec || urySpec) {
-        if (!llxSpec) cmdlineP->extract_box.llx = 72;
-        else cmdlineP->extract_box.llx = llx * 72;
-        if (!llySpec) cmdlineP->extract_box.lly = 72;
-        else cmdlineP->extract_box.lly = lly * 72;
-        if (!urxSpec) cmdlineP->extract_box.urx = 540;
-        else cmdlineP->extract_box.urx = urx * 72;
-        if (!urySpec) cmdlineP->extract_box.ury = 720;
-        else cmdlineP->extract_box.ury = ury * 72;
+        if (!llxSpec) cmdlineP->extractBox.llx = 72;
+        else cmdlineP->extractBox.llx = llx * 72;
+        if (!llySpec) cmdlineP->extractBox.lly = 72;
+        else cmdlineP->extractBox.lly = lly * 72;
+        if (!urxSpec) cmdlineP->extractBox.urx = 540;
+        else cmdlineP->extractBox.urx = urx * 72;
+        if (!urySpec) cmdlineP->extractBox.ury = 720;
+        else cmdlineP->extractBox.ury = ury * 72;
     } else {
-        cmdlineP->extract_box.llx = -1;
+        cmdlineP->extractBox.llx = -1;
     }
 
     if (dpiSpec) {
@@ -230,19 +231,19 @@ addPsToFileName(char          const origFileName[],
    *newFileNameP.
 -----------------------------------------------------------------------------*/
     struct stat statbuf;
-    int stat_rc;
+    int statRc;
 
-    stat_rc = lstat(origFileName, &statbuf);
+    statRc = lstat(origFileName, &statbuf);
     
-    if (stat_rc == 0)
+    if (statRc == 0)
         *newFileNameP = strdup(origFileName);
     else {
         const char * fileNamePlusPs;
 
         pm_asprintf(&fileNamePlusPs, "%s.ps", origFileName);
 
-        stat_rc = lstat(fileNamePlusPs, &statbuf);
-        if (stat_rc == 0)
+        statRc = lstat(fileNamePlusPs, &statbuf);
+        if (statRc == 0)
             *newFileNameP = strdup(fileNamePlusPs);
         else
             *newFileNameP = strdup(origFileName);
@@ -311,9 +312,9 @@ computeSizeResBlind(unsigned int   const xmax,
 
 
 static void
-computeSizeRes(struct cmdlineInfo const cmdline, 
-               enum orientation   const orientation, 
-               struct box         const bordered_box,
+computeSizeRes(struct CmdlineInfo const cmdline, 
+               enum Orientation   const orientation, 
+               struct Box         const borderedBox,
                unsigned int *     const xsizeP, 
                unsigned int *     const ysizeP,
                unsigned int *     const xresP, 
@@ -344,11 +345,11 @@ computeSizeRes(struct cmdlineInfo const cmdline,
         */
 
     if (orientation == LANDSCAPE) {
-        sx = bordered_box.ury - bordered_box.lly;
-        sy = bordered_box.urx - bordered_box.llx;
+        sx = borderedBox.ury - borderedBox.lly;
+        sy = borderedBox.urx - borderedBox.llx;
     } else {
-        sx = bordered_box.urx - bordered_box.llx;
-        sy = bordered_box.ury - bordered_box.lly;
+        sx = borderedBox.urx - borderedBox.llx;
+        sy = borderedBox.ury - borderedBox.lly;
     }
 
     if (cmdline.dpi) {
@@ -373,9 +374,9 @@ computeSizeRes(struct cmdlineInfo const cmdline,
 
 
 
-enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
+enum PostscriptLanguage {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
 
-static enum postscript_language
+static enum PostscriptLanguage
 languageDeclaration(char const inputFileName[],
                     bool const verbose) {
 /*----------------------------------------------------------------------------
@@ -383,7 +384,7 @@ languageDeclaration(char const inputFileName[],
   (Except that if the file is on Standard Input or doesn't validly declare
   a languages, just say it is Common Postscript).
 -----------------------------------------------------------------------------*/
-    enum postscript_language language;
+    enum PostscriptLanguage language;
 
     if (streq(inputFileName, "-"))
         /* Can't read stdin, because we need it to remain positioned for the 
@@ -399,9 +400,9 @@ languageDeclaration(char const inputFileName[],
         if (fgets(line, sizeof(line), infile) == NULL)
             language = COMMON_POSTSCRIPT;
         else {
-            const char eps_header[] = " EPSF-";
+            const char epsHeader[] = " EPSF-";
 
-            if (strstr(line, eps_header))
+            if (strstr(line, epsHeader))
                 language = ENCAPSULATED_POSTSCRIPT;
             else
                 language = COMMON_POSTSCRIPT;
@@ -418,61 +419,64 @@ languageDeclaration(char const inputFileName[],
 
 
 
-static struct box
-computeBoxToExtract(struct box const cmdline_extract_box,
+static struct Box
+computeBoxToExtract(struct Box const cmdlineExtractBox,
                     char       const inputFileName[],
                     bool       const verbose) {
 
-    struct box retval;
+    struct Box retval;
 
-    if (cmdline_extract_box.llx != -1)
+    if (cmdlineExtractBox.llx != -1)
         /* User told us what box to extract, so that's what we'll do */
-        retval = cmdline_extract_box;
+        retval = cmdlineExtractBox;
     else {
         /* Try to get the bounding box from the DSC %%BoundingBox
            statement (A Postscript comment) in the input.
         */
-        struct box ps_bb;  /* Box described by %%BoundingBox stmt in input */
+        struct Box psBb;  /* Box described by %%BoundingBox stmt in input */
 
         if (streq(inputFileName, "-"))
             /* Can't read stdin, because we need it to remain
                positioned for the Ghostscript interpreter to read it.  
             */
-            ps_bb.llx = -1;
+            psBb.llx = -1;
         else {
-            FILE *infile;
-            int found_BB, eof;  /* logical */
-            infile = pm_openr(inputFileName);
+            FILE * ifP;
+            bool foundBb;
+            bool eof;
+
+            ifP = pm_openr(inputFileName);
             
-            found_BB = FALSE;
-            eof = FALSE;
-            while (!eof && !found_BB) {
+            for (foundBb = FALSE, eof = FALSE; !foundBb && !eof; ) {
                 char line[200];
-                
-                if (fgets(line, sizeof(line), infile) == NULL)
+                char * fgetsRc;
+
+                fgetsRc = fgets(line, sizeof(line), ifP);
+
+                if (fgetsRc == NULL)
                     eof = TRUE;
                 else {
                     int rc;
                     rc = sscanf(line, "%%%%BoundingBox: %d %d %d %d",
-                                &ps_bb.llx, &ps_bb.lly, 
-                                &ps_bb.urx, &ps_bb.ury);
+                                &psBb.llx, &psBb.lly, 
+                                &psBb.urx, &psBb.ury);
                     if (rc == 4) 
-                        found_BB = TRUE;
+                        foundBb = TRUE;
                 }
             }
-            fclose(infile);
+            fclose(ifP);
 
-            if (!found_BB) {
-                ps_bb.llx = -1;
+            if (!foundBb) {
+                psBb.llx = -1;
                 pm_message("Warning: no %%%%BoundingBox statement "
-                           "in the input or command line.\n"
+                           "in the input or command line.  "
                            "Will use defaults");
             }
         }
-        if (ps_bb.llx != -1) {
+        if (psBb.llx != -1) {
             if (verbose)
                 pm_message("Using %%%%BoundingBox statement from input.");
-            retval = ps_bb;
+            retval = psBb;
         } else { 
             /* Use the center of an 8.5" x 11" page with 1" border all around*/
             retval.llx = 72;
@@ -489,13 +493,14 @@ computeBoxToExtract(struct box const cmdline_extract_box,
 
 
 
-static enum orientation
-computeOrientation(struct cmdlineInfo const cmdline, 
-                   struct box         const extract_box) {
+static enum Orientation
+computeOrientation(struct CmdlineInfo const cmdline, 
+                   struct Box         const extractBox) {
 
-    enum orientation retval;
-    unsigned int const input_width  = extract_box.urx - extract_box.llx;
-    unsigned int const input_height = extract_box.ury - extract_box.lly;
+    unsigned int const inputWidth  = extractBox.urx - extractBox.llx;
+    unsigned int const inputHeight = extractBox.ury - extractBox.lly;
+
+    enum Orientation retval;
 
     if (cmdline.orientation != UNSPECIFIED)
         retval = cmdline.orientation;
@@ -506,24 +511,24 @@ computeOrientation(struct cmdlineInfo const cmdline,
                so we can't use output dimensions to make the decision.  So
                just use the input dimensions.
             */
-            if (input_height > input_width) retval = PORTRAIT;
+            if (inputHeight > inputWidth) retval = PORTRAIT;
             else retval = LANDSCAPE;
         } else {
-            int output_width, output_height;
+            unsigned int outputWidth, outputHeight;
             if (cmdline.xsize) {
                 /* He gave xsize and ysize, so that's the output size */
-                output_width = cmdline.xsize;
-                output_height = cmdline.ysize;
+                outputWidth  = cmdline.xsize;
+                outputHeight = cmdline.ysize;
             } else {
                 /* Well then we'll just use his (or default) xmax, ymax */
-                output_width = cmdline.xmax;
-                output_height = cmdline.ymax;
+                outputWidth  = cmdline.xmax;
+                outputHeight = cmdline.ymax;
             }
 
-            if (input_height > input_width && output_height > output_width)
+            if (inputHeight > inputWidth && outputHeight > outputWidth)
                 retval = PORTRAIT;
-            else if (input_height < input_width && 
-                     output_height < output_width)
+            else if (inputHeight < inputWidth && 
+                     outputHeight < outputWidth)
                 retval = PORTRAIT;
             else 
                 retval = LANDSCAPE;
@@ -534,32 +539,39 @@ computeOrientation(struct cmdlineInfo const cmdline,
 
 
 
-static struct box
-addBorders(struct box const input_box, 
-           float      const xborder_scale,
-           float      const yborder_scale,
+static struct Box
+addBorders(struct Box const inputBox, 
+           float      const xborderScale,
+           float      const yborderScale,
            bool       const verbose) {
 /*----------------------------------------------------------------------------
-   Return a box which is 'input_box' plus some borders.
+   Return a box which is 'inputBox' plus some borders.
 
-   Add left and right borders that are the fraction 'xborder_scale' of the
+   Add left and right borders that are the fraction 'xborderScale' of the
    width of the input box; likewise for top and bottom borders with 
-   'yborder_scale'.
+   'yborderScale'.
 -----------------------------------------------------------------------------*/
-    struct box retval;
+    unsigned int const leftRightBorderSize = 
+        ROUNDU((inputBox.urx - inputBox.llx) * xborderScale);
+    unsigned int const topBottomBorderSize = 
+        ROUNDU((inputBox.ury - inputBox.lly) * yborderScale);
+
+    struct Box retval;
+
 
-    const int left_right_border_size = 
-        (int) ((input_box.urx - input_box.llx) * xborder_scale + 0.5);
-    const int top_bottom_border_size = 
-        (int) ((input_box.ury - input_box.lly) * yborder_scale + 0.5);
+    assert(inputBox.urx >= inputBox.llx);
+    assert(inputBox.ury >= inputBox.lly);
 
-    retval.llx = input_box.llx - left_right_border_size;
-    retval.lly = input_box.lly - top_bottom_border_size;
-    retval.urx = input_box.urx + left_right_border_size;
-    retval.ury = input_box.ury + top_bottom_border_size;
+    assert(inputBox.llx >= leftRightBorderSize);
+    assert(inputBox.lly >= topBottomBorderSize);
+
+    retval.llx = inputBox.llx - leftRightBorderSize;
+    retval.lly = inputBox.lly - topBottomBorderSize;
+    retval.urx = inputBox.urx + leftRightBorderSize;
+    retval.ury = inputBox.ury + topBottomBorderSize;
 
     if (verbose)
-        pm_message("With borders, extracted box is ((%d,%d),(%d,%d))",
+        pm_message("With borders, extracted box is ((%u,%u),(%u,%u))",
                    retval.llx, retval.lly, retval.urx, retval.ury);
 
     return retval;
@@ -568,8 +580,8 @@ addBorders(struct box const input_box,
 
 
 static const char *
-computePstrans(struct box       const box,
-               enum orientation const orientation,
+computePstrans(struct Box       const box,
+               enum Orientation const orientation,
                int              const xsize,
                int              const ysize, 
                int              const xres,
@@ -598,11 +610,20 @@ computePstrans(struct box       const box,
 
 
 static const char *
-computeOutfileArg(struct cmdlineInfo const cmdline) {
-
+computeOutfileArg(struct CmdlineInfo const cmdline) {
+/*----------------------------------------------------------------------------
+   Determine the value for the "OutputFile" variable to pass to Ghostscript,
+   which is what tells Ghostscript where to put its output.  This is either
+   a pattern such as "foo%03d.ppm" or "-" to indicate Standard Output.
+
+   We go with "-" if, according to 'cmdline', the user asked for
+   Standard Output or is giving his input on Standard Input.  Otherwise,
+   we go with the pattern, based on the name of the input file and output
+   format type the user requested.
+-----------------------------------------------------------------------------*/
     const char * retval;  /* malloc'ed */
 
-    if (cmdline.goto_stdout)
+    if (cmdline.stdout)
         retval = strdup("-");
     else if (streq(cmdline.inputFileName, "-"))
         retval = strdup("-");
@@ -616,12 +637,12 @@ computeOutfileArg(struct cmdlineInfo const cmdline) {
             /* The input file name ends in ".ps".  Chop it off. */
             basename[strlen(basename)-3] = '\0';
 
-        switch (cmdline.format_type) {
+        switch (cmdline.formatType) {
         case PBM_TYPE: suffix = "pbm"; break;
         case PGM_TYPE: suffix = "pgm"; break;
         case PPM_TYPE: suffix = "ppm"; break;
-        default: pm_error("Internal error: invalid value for format_type: %d",
-                          cmdline.format_type);
+        default: pm_error("Internal error: invalid value for formatType: %d",
+                          cmdline.formatType);
         }
         pm_asprintf(&retval, "%s%%03d.%s", basename, suffix);
 
@@ -633,17 +654,17 @@ computeOutfileArg(struct cmdlineInfo const cmdline) {
 
 
 static const char *
-computeGsDevice(int  const format_type,
+computeGsDevice(int  const formatType,
                 bool const forceplain) {
 
     const char * basetype;
     const char * retval;
 
-    switch (format_type) {
+    switch (formatType) {
     case PBM_TYPE: basetype = "pbm"; break;
     case PGM_TYPE: basetype = "pgm"; break;
     case PPM_TYPE: basetype = "ppm"; break;
-    default: pm_error("Internal error: invalid value format_type");
+    default: pm_error("Internal error: invalid value formatType");
     }
     if (forceplain)
         retval = strdup(basetype);
@@ -703,14 +724,13 @@ findGhostscriptProg(const char ** const retvalP) {
 
 static void
 execGhostscript(int          const inputPipeFd,
-                char         const ghostscript_device[],
-                char         const outfile_arg[], 
+                char         const ghostscriptDevice[],
+                char         const outfileArg[], 
                 int          const xsize,
                 int          const ysize, 
                 int          const xres,
                 int          const yres,
                 unsigned int const textalphabits,
-                char         const inputFileName[],
                 bool         const verbose) {
     
     const char * arg0;
@@ -729,8 +749,8 @@ execGhostscript(int          const inputPipeFd,
     close(inputPipeFd);
 
     pm_asprintf(&arg0, "gs");
-    pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscript_device);
-    pm_asprintf(&outfileopt, "-sOutputFile=%s", outfile_arg);
+    pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscriptDevice);
+    pm_asprintf(&outfileopt, "-sOutputFile=%s", outfileArg);
     pm_asprintf(&gopt, "-g%dx%d", xsize, ysize);
     pm_asprintf(&ropt, "-r%dx%d", xres, yres);
     pm_asprintf(&textalphabitsopt, "-dTextAlphaBits=%u", textalphabits);
@@ -760,26 +780,26 @@ execGhostscript(int          const inputPipeFd,
 
 
 static void
-executeGhostscript(char                     const pstrans[],
-                   char                     const ghostscript_device[],
-                   char                     const outfile_arg[], 
-                   int                      const xsize,
-                   int                      const ysize, 
-                   int                      const xres,
-                   int                      const yres,
-                   unsigned int             const textalphabits,
-                   char                     const inputFileName[], 
-                   enum postscript_language const language,
-                   bool                     const verbose) {
-
-    int gs_exit;  /* wait4 exit code from Ghostscript */
-    FILE *gs;  /* Pipe to Ghostscript's standard input */
-    FILE *infile;
+executeGhostscript(char                    const pstrans[],
+                   char                    const ghostscriptDevice[],
+                   char                    const outfileArg[], 
+                   int                     const xsize,
+                   int                     const ysize, 
+                   int                     const xres,
+                   int                     const yres,
+                   unsigned int            const textalphabits,
+                   char                    const inputFileName[], 
+                   enum PostscriptLanguage const language,
+                   bool                    const verbose) {
+
+    int gsTermStatus;  /* termination status of Ghostscript process */
+    FILE * pipeToGsP;  /* Pipe to Ghostscript's standard input */
+    FILE * ifP;
     int rc;
     int eof;  /* End of file on input */
     int pipefd[2];
 
-    if (strlen(outfile_arg) > 80)
+    if (strlen(outfileArg) > 80)
         pm_error("output file spec too long.");
     
     rc = pm_pipe(pipefd);
@@ -794,20 +814,20 @@ executeGhostscript(char                     const pstrans[],
     else if (rc == 0) {
         /* Child process */
         close(pipefd[1]);
-        execGhostscript(pipefd[0], ghostscript_device, outfile_arg,
+        execGhostscript(pipefd[0], ghostscriptDevice, outfileArg,
                         xsize, ysize, xres, yres, textalphabits,
-                        inputFileName, verbose);
+                        verbose);
     } else {
         pid_t const ghostscriptPid = rc;
         int const pipeToGhostscriptFd = pipefd[1];
         /* parent process */
         close(pipefd[0]);
 
-        gs = fdopen(pipeToGhostscriptFd, "w");
-        if (gs == NULL) 
+        pipeToGsP = fdopen(pipeToGhostscriptFd, "w");
+        if (pipeToGsP == NULL) 
             pm_error("Unable to open stream on pipe to Ghostscript process.");
     
-        infile = pm_openr(inputFileName);
+        ifP = pm_openr(inputFileName);
         /*
           In encapsulated Postscript, we the encapsulator are supposed to
           handle showing the page (which we do by passing a showpage
@@ -822,12 +842,12 @@ executeGhostscript(char                     const pstrans[],
           here, I think, so I boiled it down a bit.  JM 
         */
         if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\n/b4_Inc_state save def /showpage { } def\n");
+            fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n");
  
         if (verbose) 
             pm_message("Postscript prefix command: '%s'", pstrans);
 
-        fprintf(gs, "%s\n", pstrans);
+        fprintf(pipeToGsP, "%s\n", pstrans);
 
         /* If our child dies, it closes the pipe and when we next write to it,
            we get a SIGPIPE.  We must survive that signal in order to report
@@ -840,34 +860,34 @@ executeGhostscript(char                     const pstrans[],
             char buffer[4096];
             int bytes_read;
             
-            bytes_read = fread(buffer, 1, sizeof(buffer), infile);
+            bytes_read = fread(buffer, 1, sizeof(buffer), ifP);
             if (bytes_read == 0) 
                 eof = TRUE;
             else 
-                fwrite(buffer, 1, bytes_read, gs);
+                fwrite(buffer, 1, bytes_read, pipeToGsP);
         }
-        pm_close(infile);
+        pm_close(ifP);
 
         if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\nb4_Inc_state restore showpage\n");
+            fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n");
 
-        fclose(gs);
+        fclose(pipeToGsP);
         
-        waitpid(ghostscriptPid, &gs_exit, 0);
+        waitpid(ghostscriptPid, &gsTermStatus, 0);
         if (rc < 0)
             pm_error("Wait for Ghostscript process to terminated failed.  "
                      "errno = %d (%s)", errno, strerror(errno));
 
-        if (gs_exit != 0) {
-            if (WIFEXITED(gs_exit))
+        if (gsTermStatus != 0) {
+            if (WIFEXITED(gsTermStatus))
                 pm_error("Ghostscript failed.  Exit code=%d\n", 
-                         WEXITSTATUS(gs_exit));
-            else if (WIFSIGNALED(gs_exit))
+                         WEXITSTATUS(gsTermStatus));
+            else if (WIFSIGNALED(gsTermStatus))
                 pm_error("Ghostscript process died due to a signal %d.",
-                         WTERMSIG(gs_exit));
+                         WTERMSIG(gsTermStatus));
             else 
                 pm_error("Ghostscript process died with exit code %d", 
-                         gs_exit);
+                         gsTermStatus);
         }
     }
 }
@@ -877,22 +897,22 @@ executeGhostscript(char                     const pstrans[],
 int
 main(int argc, char ** argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     const char * inputFileName;  /* malloc'ed */
         /* The file specification of our Postscript input file */
     unsigned int xres, yres;    /* Resolution in pixels per inch */
     unsigned int xsize, ysize;  /* output image size in pixels */
-    struct box extract_box;
+    struct Box extractBox;
         /* coordinates of the box within the input we are to extract; i.e.
            that will become the output. 
            */
-    struct box bordered_box;
+    struct Box borderedBox;
         /* Same as above, but expanded to include borders */
 
-    enum postscript_language language;
-    enum orientation orientation;
-    const char * ghostscript_device;
-    const char * outfile_arg;
+    enum PostscriptLanguage language;
+    enum Orientation orientation;
+    const char * ghostscriptDevice;
+    const char * outfileArg;
     const char * pstrans;
 
     pnm_init(&argc, argv);
@@ -901,36 +921,36 @@ main(int argc, char ** argv) {
 
     addPsToFileName(cmdline.inputFileName, &inputFileName, cmdline.verbose);
 
-    extract_box = computeBoxToExtract(cmdline.extract_box, inputFileName, 
+    extractBox = computeBoxToExtract(cmdline.extractBox, inputFileName, 
                                       cmdline.verbose);
 
     language = languageDeclaration(inputFileName, cmdline.verbose);
     
-    orientation = computeOrientation(cmdline, extract_box);
+    orientation = computeOrientation(cmdline, extractBox);
 
-    bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder,
-                              cmdline.verbose);
+    borderedBox = addBorders(extractBox, cmdline.xborder, cmdline.yborder,
+                             cmdline.verbose);
 
-    computeSizeRes(cmdline, orientation, bordered_box, 
+    computeSizeRes(cmdline, orientation, borderedBox, 
                    &xsize, &ysize, &xres, &yres);
     
-    pstrans = computePstrans(bordered_box, orientation,
+    pstrans = computePstrans(borderedBox, orientation,
                              xsize, ysize, xres, yres);
 
-    outfile_arg = computeOutfileArg(cmdline);
+    outfileArg = computeOutfileArg(cmdline);
 
-    ghostscript_device = 
-        computeGsDevice(cmdline.format_type, cmdline.forceplain);
+    ghostscriptDevice = 
+        computeGsDevice(cmdline.formatType, cmdline.forceplain);
     
-    pm_message("Writing %s file", ghostscript_device);
+    pm_message("Writing %s format", ghostscriptDevice);
     
-    executeGhostscript(pstrans, ghostscript_device, outfile_arg, 
+    executeGhostscript(pstrans, ghostscriptDevice, outfileArg, 
                        xsize, ysize, xres, yres, cmdline.textalphabits,
                        inputFileName,
                        language, cmdline.verbose);
 
-    pm_strfree(ghostscript_device);
-    pm_strfree(outfile_arg);
+    pm_strfree(ghostscriptDevice);
+    pm_strfree(outfileArg);
     pm_strfree(pstrans);
     
     return 0;
diff --git a/converter/other/winicon.h b/converter/other/winicon.h
new file mode 100644
index 00000000..9ede01f5
--- /dev/null
+++ b/converter/other/winicon.h
@@ -0,0 +1,82 @@
+#include "pm_c_util.h"
+
+#define ICONDIR_TYPE_ICO (1)
+
+/*  windows icon structures  */
+struct IconDirEntry {
+    uint16_t width;               /* image width in pixels 0 == 256 */
+    uint16_t height;              /* image height in pixels 0 == 256 */
+    uint8_t  color_count;         /* 0 if bits_per_pixel >= 8 */
+    uint8_t  zero;                /* 0 */
+    uint16_t color_planes;        /* 1 */
+    uint16_t bits_per_pixel;      /* allowed values: 1, 4, 8, 16 or 32 (1) */
+    uint32_t size;                /* size of image */
+    uint32_t offset;              /* file offset of image */
+
+    uint16_t index;               /* extra field (not in file) */
+};
+
+/*  (1) This is from
+ *  http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx.
+ *
+ *  However, the bpp value in the icon directory is used as a hint for
+ *  image selection only.  It seems to be legal to set this value to
+ *  zero, and e.g. in SHELL32.DLL of Win98SE, there are many 8bpp
+ *  images described as 24 bit images in the icon directory.
+ *
+ *  The bpp value of image 1 in icon 150 in SHELL32.DLL of WinXP is 24
+ *  (in header and BMP).  This may be a bug, as the 32 x 32 x 8 image
+ *  is missing, but it shows the Windows icon rendering engine is able
+ *  to cope with 24 bit images).
+ *
+ *  16bpp icons are at least rare in the wild.
+ */
+struct IconDir {
+    uint16_t zero;                /* 0 */
+    uint16_t type;                /* 1 */
+    uint16_t count;               /* number of images in icon */
+
+    unsigned int entriesAllocCt;     /* # of allocated slots in 'entries'*/
+    struct IconDirEntry * entries;   /* one entry for each image */
+};
+
+/*  BMP image structures  */
+
+struct BitmapInfoHeader {
+    uint32_t header_size;         /* >= 40 */
+    int32_t  bm_width;
+    int32_t  bm_height;
+    uint16_t color_planes;
+    uint16_t bits_per_pixel;
+    uint32_t compression_method;
+    uint32_t image_size;
+    int32_t  horizontal_resolution; /* pixels per meter (!) */
+    int32_t  vertical_resolution;   /* pixels per meter (!) */
+    uint32_t colors_in_palette;
+    uint32_t important_colors;
+
+    bool top_down;                /* extra field (not in file) */
+
+};
+
+typedef enum {
+    BI_RGB       = 0,
+    BI_BITFIELDS = 3
+
+} BiCompression;
+
+/*  PNG image structures  */
+#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
+
+struct PngIhdr {
+    uint32_t length;              /* 13 */
+    uint32_t signature;           /* "IHDR" */
+    uint32_t width;               /* image width in pixels */
+    uint32_t height;              /* image height in pixels */
+    uint8_t  bit_depth;           /* depth per channel */
+    uint8_t  color_type;          /* recognized values: 0, 2, 3, 4 and 6 */
+    uint8_t  compression;
+    uint8_t  filter;
+    uint8_t  interlace;
+    uint32_t crc;
+};
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
new file mode 100644
index 00000000..9bee8b3c
--- /dev/null
+++ b/converter/other/winicontopam.c
@@ -0,0 +1,1282 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pam.h"
+#include "netpbm/pm_system.h"
+
+#include "winicon.h"
+
+#define RED   0
+#define GRN   1
+#define BLU   2
+#define ALPHA 3
+#define CHANNEL_CHARS "RGBA"
+
+
+
+static bool verbose;
+
+
+
+struct CmdlineInfo {
+    
+    const char * inputFileName;
+    unsigned int allimages;
+    unsigned int imageSpec;
+    unsigned int image;
+    unsigned int andmasks;
+    unsigned int headerdump;
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3 (0, "allimages",   OPT_FLAG,   NULL,
+             &cmdlineP->allimages,         0);
+    OPTENT3 (0, "image",     OPT_UINT,   &cmdlineP->image,
+             &cmdlineP->imageSpec,         0);
+    OPTENT3 (0, "andmasks",  OPT_FLAG,   NULL,
+             &cmdlineP->andmasks,          0);
+    OPTENT3 (0, "headerdump",   OPT_FLAG,   NULL,
+             &cmdlineP->headerdump,        0);
+    OPTENT3 (0, "verbose",   OPT_FLAG,   NULL,
+             &cmdlineP->verbose,           0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (cmdlineP->allimages && cmdlineP->imageSpec)
+        pm_error("You cannot specify both -allimages and -image");
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible "
+                     "non-option argument is the input file name");
+    }
+        
+    free(option_def);
+}
+
+
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct File {
+
+    FILE *       fileP;
+    const char * name;
+    pm_filepos   pos;
+    
+};
+
+
+
+static uint32_t
+u8_le(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u16_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return
+        ((uint32_t)buf[offset + 0] << 0) +
+        ((uint32_t)buf[offset + 1] << 8);
+}
+
+
+
+static uint32_t
+u32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+s32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+u8_be(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u32_be(const unsigned char * const buf,
+       size_t                const offset) {
+    
+    return 
+        ((uint32_t)buf[offset + 0] << 24) +
+        ((uint32_t)buf[offset + 1] << 16) +
+        ((uint32_t)buf[offset + 2] <<  8) +
+        ((uint32_t)buf[offset + 3] <<  0);
+}
+
+
+
+static uint32_t
+u32_xx(const unsigned char * const buf,
+       size_t                const offset) {
+
+    uint32_t u32;
+
+    ((uint8_t*) &u32)[0] = buf[offset + 0];
+    ((uint8_t*) &u32)[1] = buf[offset + 1];
+    ((uint8_t*) &u32)[2] = buf[offset + 2];
+    ((uint8_t*) &u32)[3] = buf[offset + 3];
+
+    return (u32);
+}
+
+
+
+static int
+cmpfn(const void * const aP,
+      const void * const bP) {
+
+    const struct IconDirEntry * const dirEntryAP = aP;
+    const struct IconDirEntry * const dirEntryBP = bP;
+
+    if (dirEntryAP->offset < dirEntryBP->offset)
+        return -1;
+    else if (dirEntryAP->offset > dirEntryBP->offset)
+        return +1;
+    else
+        return 0;
+}
+
+
+
+static void
+dumpIconDir(const struct IconDir * const dirP) {
+
+    unsigned int i;
+
+    pm_message("Type: %u", dirP->type);
+    pm_message("Icon directory has %u images:", dirP->count);
+
+    for (i = 0; i < dirP->count; ++i) {
+        const struct IconDirEntry * const dirEntryP = &dirP->entries[i];
+
+        pm_message("width: %u", dirEntryP->width);
+        pm_message("height: %u", dirEntryP->height);
+        pm_message("color count: %u", dirEntryP->color_count);
+        pm_message("# color planes: %u", dirEntryP->color_planes);
+        pm_message("bits per pixel: %u", dirEntryP->bits_per_pixel);
+        pm_message("offset in file of image: %u", dirEntryP->offset);
+        pm_message("size of image: %u", dirEntryP->size);
+        pm_message("zero field: %u", dirEntryP->zero);
+    }
+}
+
+            
+
+static struct IconDir *
+readIconDir(struct File * const fP,
+            bool          const needHeaderDump) {
+
+    struct IconDir head;
+    struct IconDir * dirP;
+    uint32_t  imageIndex; /* more bits than dir.count */
+
+    pm_readlittleshortu(fP->fileP, &head.zero);
+    pm_readlittleshortu(fP->fileP, &head.type);
+    pm_readlittleshortu(fP->fileP, &head.count);
+    fP->pos += 6;
+
+    if (head.zero != 0 || head.type != ICONDIR_TYPE_ICO)
+        pm_error("Not a valid windows icon file");
+
+    MALLOCVAR(dirP);
+
+    if (dirP == NULL)
+        pm_error("Could't allocate memory for Icon directory");
+
+    MALLOCARRAY(dirP->entries, head.count);
+
+    if (dirP->entries == NULL)
+        pm_error("Could not allocate memory for %u entries in icon directory",
+                 head.count);
+
+    dirP->zero           = head.zero;
+    dirP->type           = head.type;
+    dirP->count          = head.count;
+    dirP->entriesAllocCt = head.count;
+
+    for (imageIndex = 0; imageIndex < head.count; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        unsigned char widthField, heightField;
+
+        unsigned long ul;
+
+        pm_readcharu(fP->fileP, &widthField);
+        dirEntryP->width  = (widthField == 0 ? 256 : widthField);
+
+        pm_readcharu(fP->fileP, &heightField);
+        dirEntryP->height = (heightField == 0 ? 256 : heightField);
+        
+        pm_readcharu(fP->fileP, &dirEntryP->color_count);
+
+        pm_readcharu(fP->fileP, &dirEntryP->zero);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->color_planes);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->bits_per_pixel);
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->size = ul;
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->offset = ul;
+
+        fP->pos += 16;
+
+        dirEntryP->index = imageIndex;
+    }
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with having the entries
+       in the directory stored in a different order than the images
+       themselves.  However, the file format allows for it ...
+     */
+    qsort(dirP->entries, dirP->count, sizeof(struct IconDirEntry), cmpfn);
+
+    if (verbose) {
+        pm_message("%s icon directory (%u image%s):",
+                   fP->name,
+                   dirP->count, dirP->count == 1 ? "" : "s");
+        
+        for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) {
+            const struct IconDirEntry * const dirEntryP =
+                &dirP->entries[imageIndex];
+
+            uint32_t colorCt;
+
+            if (dirEntryP->bits_per_pixel == 0)
+                colorCt = 0;
+            else if (dirEntryP->bits_per_pixel >= 32)
+                colorCt = 1u << 24;
+            else
+                colorCt = 1u << dirEntryP->bits_per_pixel;
+
+            if (dirEntryP->color_count != 0 &&
+                colorCt > dirEntryP->color_count) {
+                colorCt = dirEntryP->color_count;
+            }
+            pm_message ("%5u: %3u x %3u, %8u colors, %5u bytes",
+                        dirEntryP->index,
+                        dirEntryP->width,
+                        dirEntryP->height,
+                        colorCt,
+                        dirEntryP->size);
+        }
+    }
+
+    if (needHeaderDump)
+        dumpIconDir(dirP);
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+
+    free(dirP->entries);
+    free(dirP);
+}
+
+
+
+static const unsigned char *
+readImage(struct File *         const fP,
+          struct IconDirEntry * const dirEntryP) {
+
+    size_t rc;
+    unsigned char * image;
+    uint32_t skippedCt;
+
+    /*  Don't try to read an image that is smaller than the
+        BITMAPINFOHEADER of BMP images (40 bytes).
+     
+        PNG compressed images can't be smaller than that either, as the
+        PNG header plus the mandantory IHDR and IEND chunks already take
+        8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too.
+     */
+    if (dirEntryP->size < 40) {
+        pm_error("image %2u: format violation: too small as an image.",
+                  dirEntryP->index);
+    }
+    if ((pm_filepos) dirEntryP->offset < fP->pos)
+        pm_error("image %2u: format violation: invalid offset.",
+                 dirEntryP->index);
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with gaps between
+       the images, but the file format allows for it, and Microsoft
+       expects the user to fseek() to the start of each image.
+     */
+    skippedCt = 0;
+
+    while ((pm_filepos) dirEntryP->offset > fP->pos) {
+        if (getc(fP->fileP) == EOF) {
+            pm_error("seeking to image %u: unexpected EOF", dirEntryP->index);
+        }
+        ++fP->pos;
+        ++skippedCt;
+    }
+
+    /*  The additional four bytes are for purify and friends, as the
+        routines reading BMP XOR and AND masks might read (but not
+        evaluate) some bytes beyond the image data.
+     */
+    image = malloc(dirEntryP->size + sizeof(uint32_t));
+    if (image == NULL)
+        pm_error("out of memory.");
+
+    rc = fread (image, 1, dirEntryP->size, fP->fileP);
+    if (rc != dirEntryP->size) {
+        pm_error("reading image %2u: unexpected EOF", dirEntryP->index);
+    }
+    fP->pos += dirEntryP->size;
+
+    return image;
+}
+
+
+
+static uint8_t
+getIdx1(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + (col >> 3)) >> (7 - (col & 0x07)) & 0x1;
+}
+
+
+
+static uint8_t
+getIdx4(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    if ((col & 1) == 0x0000)
+        return u8_le(bitmap, offset + (col >> 1)) >> 4 & 0x0F;
+    else
+        return u8_le(bitmap, offset + (col >> 1)) >> 0 & 0x0F;
+}
+
+
+
+static uint8_t
+getIdx8(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + col);
+}
+
+
+
+typedef unsigned char PaletteEntry[4];
+
+
+
+static void
+dumpPalette(const PaletteEntry * const palette,
+            unsigned int         const colorCt) {
+
+    unsigned int i;
+
+    for (i = 0; i < colorCt; ++i) {
+        pm_message("Color %u: (%u, %u, %u)",
+                   i, palette[i][2], palette[i][1], palette[i][0]);
+    }
+}
+
+
+
+static void
+readXorPalette(struct BitmapInfoHeader * const hdrP,
+               const unsigned char *     const bitmap,
+               uint32_t                  const maxSize,
+               tuple **                  const tuples,
+               uint16_t                  const index,
+               bool                      const needHeaderDump,
+               uint32_t *                const bytesConsumedP) {
+
+    uint32_t paletteSize;
+
+    int16_t     row;
+    const PaletteEntry * palette;
+    uint32_t    truncatedXorSize;
+    uint32_t    bytesConsumed;
+    uint32_t    bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t sizeRemaining;
+  
+    uint8_t (*getIdx) (const unsigned char * bitmap,
+                       uint32_t rowOffset,
+                       int16_t col);
+  
+    if (hdrP->compression_method != BI_RGB)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel < 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 1:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 2;
+        getIdx = getIdx1;
+        break;
+
+    case 4:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 16;
+        getIdx = getIdx4;
+        break;
+
+    case 8:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 256;
+        getIdx = getIdx8;
+        break;
+
+    default:
+        pm_error("image %2u: "
+                 "bits per pixel is a value we don't understand: %u",
+                  index, hdrP->bits_per_pixel);
+        getIdx = NULL;
+    }
+
+    bitmapCursor = &bitmap[0];  /* initial value */
+    sizeRemaining = maxSize;    /* initial value */
+    bytesConsumed = 0;          /* initial value */
+
+    paletteSize = hdrP->colors_in_palette * 4;
+
+    if (sizeRemaining < paletteSize)
+        pm_error("image %2u: "
+                 "reading palette: image truncated.", index);
+    
+    palette = (const PaletteEntry *) bitmapCursor;
+
+    if (needHeaderDump)
+        dumpPalette(palette, hdrP->colors_in_palette);
+
+    bitmapCursor  += paletteSize;
+    sizeRemaining -= paletteSize;
+    bytesConsumed += paletteSize;
+
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; hdrP->bm_height / 2 > row; ++row) {
+        uint32_t rowOffset;
+
+        if (hdrP->top_down)
+            rowOffset = row * bytesPerRow;
+        else
+            rowOffset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (rowOffset + bytesPerRow <= truncatedXorSize) {
+            int16_t col;
+            for (col = 0; hdrP->bm_width > col; ++col) {
+                uint8_t const idx = getIdx(bitmapCursor, rowOffset, col);
+
+                if (idx > hdrP->colors_in_palette)
+                    pm_error("invalid palette index in row %u, column %u.",
+                             row, col);
+
+                /*  The palette is an array of little-endian 32-bit values,
+                    where the RGB value is encoded as follows:
+                 
+                    red:   bits 2^16..2^23
+                    green: bits 2^8 ..2^15
+                    blue:  bits 2^0 ..2^7
+                 */
+                tuples[row][col][PAM_RED_PLANE] = palette[idx][2];
+                tuples[row][col][PAM_GRN_PLANE] = palette[idx][1];
+                tuples[row][col][PAM_BLU_PLANE] = palette[idx][0];
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    bytesConsumed += truncatedXorSize;
+
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readXorBitfields(struct BitmapInfoHeader * const hdrP,
+                 const unsigned char *     const bitmap,
+                 uint32_t                  const maxSize,
+                 tuple **                  const tuples,
+                 uint16_t                  const index,
+                 bool *                    const haveAlphaP,
+                 uint32_t *                const bytesConsumedP) {
+
+    uint32_t   bitfields[4];
+    uint8_t    shift    [4];
+    sample     maxval   [4];
+
+    int16_t      row;
+    uint32_t     bytesConsumed;
+    uint32_t     bytesPerSample;
+    uint32_t     bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t     sizeRemaining;
+    uint32_t     truncatedXorSize;
+
+    static uint8_t alphas [256];
+    bool         allOpaque;
+    bool         allTransparent;
+
+    bytesConsumed = 0;
+
+    if (hdrP->compression_method != BI_RGB
+        && hdrP->compression_method != BI_BITFIELDS)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel >= 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 16:
+        bytesPerSample = 2;
+        bitfields[RED]   = 0x7C00;
+        bitfields[GRN]   = 0x03E0;
+        bitfields[BLU]   = 0x001F;
+        bitfields[ALPHA] = 0x0000;
+        break;
+
+    case 24:
+        bytesPerSample = 3;
+        bitfields[RED]   = 0xFF0000;
+        bitfields[GRN]   = 0x00FF00;
+        bitfields[BLU]   = 0x0000FF;
+        bitfields[ALPHA] = 0x000000;
+        break;
+
+    case 32:
+        bytesPerSample = 4;
+        bitfields[RED]   = 0x00FF0000;
+        bitfields[GRN]   = 0x0000FF00;
+        bitfields[BLU]   = 0x000000FF;
+        bitfields[ALPHA] = 0xFF000000;
+        break;
+
+    default:
+        pm_error("image %2u: bits per pixel is one we don't understand: %u.",
+                 index, hdrP->bits_per_pixel);
+        bytesPerSample = 0;
+    }
+
+    bitmapCursor = &bitmap[0]; /* initial value */
+    sizeRemaining = maxSize;  /* initial value */
+
+    /*  read bit fields from image data  */
+    if (hdrP->compression_method == BI_BITFIELDS) {
+        if (sizeRemaining < 12)
+            pm_error("image %2u: "
+                     "reading bit fields: image truncated.", index);
+
+        bitfields[RED]   = u32_le(bitmapCursor, 0);
+        bitfields[GRN]   = u32_le(bitmapCursor, 4);
+        bitfields[BLU]   = u32_le(bitmapCursor, 8);
+        bitfields[ALPHA] = 0;
+
+        bitmapCursor  += 12;
+        sizeRemaining -= 12;
+        bytesConsumed += 12;
+    }
+
+    /*  determine shift and maxval from bit field for each channel */
+    {
+        unsigned int i;
+
+        for (i = 0; 4 > i; ++i) {
+            if (bitfields[i] == 0) {
+                maxval[i] = 1;
+                shift [i] = 0;
+            } else {
+                unsigned int j;
+
+                maxval[i] = bitfields[i];
+
+                for (j = 0; 32 > j; ++j) {
+                    if ((maxval[i] & 0x1) != 0)
+                        break;
+                    maxval[i] >>= 1;
+                }
+                shift[i] = j;
+            }
+
+        }
+    }
+
+    /*  read the XOR mask */
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+    MEMSZERO(alphas);
+
+    for (row = 0, allOpaque = true, allTransparent = true;
+         hdrP->bm_height / 2 > row;
+         ++row) {
+
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= truncatedXorSize) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                uint32_t const pixel = u32_le(bitmapCursor, offset);
+                offset += bytesPerSample;
+
+                tuples[row][col][PAM_RED_PLANE] =
+                    pnm_scalesample((pixel & bitfields[RED]) >> shift[RED],
+                                    maxval[RED], 255);
+                tuples[row][col][PAM_GRN_PLANE] =
+                    pnm_scalesample((pixel & bitfields[GRN]) >> shift[GRN],
+                                    maxval[GRN], 255);
+                tuples [row][col][PAM_BLU_PLANE]
+                    = pnm_scalesample((pixel & bitfields[BLU]) >> shift[BLU],
+                                      maxval[BLU], 255);
+
+                if (bitfields [ALPHA] != 0) {
+                    tuples[row][col][PAM_TRN_PLANE]
+                        = pnm_scalesample(
+                            (pixel & bitfields[ALPHA]) >> shift[ALPHA],
+                            maxval[ALPHA], 255);
+
+                    if (tuples[row][col][PAM_TRN_PLANE] != 0)
+                        allTransparent = false;
+
+                    if (tuples [row][col][PAM_TRN_PLANE] != 255)
+                        allOpaque = false;
+
+                    alphas[tuples[row][col][PAM_TRN_PLANE]] = !0;
+                }
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    bytesConsumed += truncatedXorSize;
+
+    /*  A fully transparent alpha channel (all zero) in XOR mask is
+        defined to be void by Microsoft, and a fully opaque alpha
+        channel (all maxval) is trivial and will be dropped.
+    */
+    *haveAlphaP = !allTransparent && !allOpaque;
+
+    if (!allTransparent && verbose) {
+        unsigned int i;
+        unsigned int c;
+
+        for (i = 0, c = 0; 256 > i; ++i) {
+            if (alphas[i] != 0)
+                ++c;
+        }
+        pm_message("image %2u: %u distinct transparency value%s",
+                   index, c, (c == 1) ? "": "s");
+    }
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readAnd(struct BitmapInfoHeader * const hdrP,
+        const unsigned char *     const bitmap,
+        uint32_t                  const maxSize,
+        tuple **                  const tuples,
+        uint16_t                  const index,
+        unsigned int              const plane,
+        sample                    const maxval) {
+
+    int16_t  row;
+    uint32_t bytesConsumed;
+    uint32_t bytesPerRow;
+    uint32_t sizeRemaining;
+    uint32_t truncatedAndSize;
+
+    sizeRemaining = maxSize;  /* initial value */
+    bytesConsumed = 0;  /* initial value */
+
+    {
+        uint32_t const andSize = (uint32_t)
+            (((1 * hdrP->bm_width + 31) / 32) * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < andSize) {
+            pm_message ("image %2u: "
+                        "Input image ends %u bytes into the %u-byte "
+                        "AND mask.  Implying remainder of mask",
+                        index, sizeRemaining, andSize);
+            truncatedAndSize = sizeRemaining;
+        } else
+            truncatedAndSize = andSize;
+    }
+
+    bytesPerRow = ((1 * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; row < hdrP->bm_height / 2; ++row) {
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= sizeRemaining) {
+            unsigned int col;
+            
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][plane] =
+                    ((u8_le(bitmap, offset + col/8)
+                      & (1 << (7 - (col & 0x7)))) == 0x00) ?
+                    maxval : 0
+                ;
+            }
+        }
+    }
+    sizeRemaining -= truncatedAndSize;
+    bytesConsumed += truncatedAndSize;
+}
+
+
+
+static void
+dumpBmpHeader(struct BitmapInfoHeader const hdr,
+              unsigned int            const imageIndex) {
+
+    pm_message("BMP header for Image %u:", imageIndex);
+
+    pm_message("header size: %u", hdr.header_size);
+    pm_message("bitmap width: %u", hdr.bm_width);
+    pm_message("bitmap height * 2: %u", hdr.bm_height);
+    pm_message("row order: %s", hdr.top_down ? "top down" : "bottom up");
+    pm_message("# color planes: %u", hdr.color_planes);
+    pm_message("bits per pixel: %u", hdr.bits_per_pixel);
+    pm_message("image size: %u", hdr.image_size);
+    pm_message("horizontal resolution: %u", hdr.horizontal_resolution);
+    pm_message("vertical resolution: %u", hdr.vertical_resolution);
+    pm_message("# colors in palette: %u", hdr.colors_in_palette);
+    pm_message("# important colors: %u", hdr.important_colors);
+}
+
+
+
+static void
+readBmpHeader(const unsigned char *     const image,
+              uint32_t                  const size,
+              unsigned int              const imageIndex,
+              bool                      const needHeaderDump,
+              struct BitmapInfoHeader * const hdrP) {
+
+    /*  BITMAPINFOHEADER structure */
+
+    if (size < 40)
+        pm_error("image %2u: reading BITMAPINFOHEADER: not enough data.",
+                 imageIndex);
+
+    hdrP->header_size           = u32_le(image,  0);
+    hdrP->bm_width              = s32_le(image,  4);
+    hdrP->bm_height             = s32_le(image,  8);
+    hdrP->color_planes          = u16_le(image, 12);
+    hdrP->bits_per_pixel        = u16_le(image, 14);
+    hdrP->compression_method    = u32_le(image, 16);
+    hdrP->image_size            = u32_le(image, 20);
+    hdrP->horizontal_resolution = s32_le(image, 24);
+    hdrP->vertical_resolution   = s32_le(image, 28);
+    hdrP->colors_in_palette     = u32_le(image, 32);
+    hdrP->important_colors      = u32_le(image, 36);
+
+    if (hdrP->bm_height > 0) {
+        hdrP->top_down = false;
+    } else {
+        hdrP->top_down   = true;
+        hdrP->bm_height *= -1;
+    }
+
+    if (hdrP->header_size < 36
+        || hdrP->bm_width == 0 || hdrP->bm_height == 0
+        || (hdrP->bm_height & 1) != 0x0000) {
+        pm_error("image %2u: format violation: invalid BMP header.",
+                 imageIndex);
+    }
+
+    if (needHeaderDump)
+        dumpBmpHeader(*hdrP, imageIndex);
+}
+
+
+
+static void
+readXorMask(struct BitmapInfoHeader * const hdrP,
+            const unsigned char *     const imageCursor,
+            uint32_t                  const imageSize,
+            tuple **                  const tuples,
+            uint16_t                  const index,
+            bool                      const needHeaderDump,
+            bool *                    const haveAlphaP,
+            uint32_t *                const bytesConsumedP) {
+/*----------------------------------------------------------------------------
+   Read the so-called XOR mask (for non-monochrome images, this is the
+   color pixmap)
+-----------------------------------------------------------------------------*/
+    /*  preset the PAM with fully opaque black (just in case the image
+        is truncated and not all pixels are filled in below).
+    */
+    {
+        unsigned int row;
+
+        for (row = 0; row < hdrP->bm_height / 2; ++row) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][PAM_RED_PLANE] = 0;
+                tuples[row][col][PAM_GRN_PLANE] = 0;
+                tuples[row][col][PAM_BLU_PLANE] = 0;
+                tuples[row][col][PAM_TRN_PLANE] = 255;
+            }
+        }
+    }
+
+    if (hdrP->bits_per_pixel < 16) {
+        readXorPalette(hdrP, imageCursor, imageSize, tuples, index,
+                       needHeaderDump,
+                       bytesConsumedP);
+        *haveAlphaP = false;
+    } else
+        readXorBitfields(hdrP, imageCursor, imageSize, tuples, index,
+                         haveAlphaP, bytesConsumedP);
+}
+
+
+
+static void
+reportImage(unsigned int            const imageIndex,
+            struct BitmapInfoHeader const hdr,
+            bool                    const haveAlpha) {
+
+    const char * const style = 
+        haveAlpha ? "RGB +alpha" :
+        hdr.bits_per_pixel < 16 ? "RGB/palette" :
+        "RGB"
+        ;
+
+    pm_message("image %2u: "
+               "BMP %3u x %3u x %2u (%s)",
+               imageIndex,
+               hdr.bm_width, hdr.bm_height / 2, hdr.bits_per_pixel,
+               style);
+}
+
+
+
+static void
+convertBmp(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP,
+           bool                  const needHeaderDump,
+           bool                  const wantAndMaskPlane) {
+    
+    struct BitmapInfoHeader hdr;
+    uint32_t                offset;
+    bool                    haveAlpha;
+    uint32_t                xorByteCt;
+
+    struct pam outpam;
+    tuple **   tuples;
+
+    readBmpHeader(image, dirEntryP->size, dirEntryP->index, needHeaderDump,
+                  &hdr);
+
+    offset = hdr.header_size;  /* Start after header */
+
+    if ((dirEntryP->width != hdr.bm_width)
+        || (dirEntryP->height != hdr.bm_height / 2)) {
+        pm_message("image %2u: "
+                   "mismatch in header and image dimensions "
+                   "(%u x %u vs. %u x %u)",
+                   dirEntryP->index,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   hdr.bm_width,
+                   hdr.bm_height / 2);
+    }
+
+    if ((dirEntryP->bits_per_pixel != 0)
+        && (dirEntryP->bits_per_pixel != hdr.bits_per_pixel)) {
+        pm_message("image %2u "
+                   "mismatch in header and image bpp value"
+                   "(%u vs. %u)",
+                   dirEntryP->index,
+                   dirEntryP->bits_per_pixel,
+                   hdr.bits_per_pixel);
+    }
+
+    outpam.size   = sizeof(struct pam);
+    outpam.len    = PAM_STRUCT_SIZE(allocation_depth);
+    outpam.file   = ofP;
+    outpam.format = PAM_FORMAT;
+    outpam.width  = hdr.bm_width;
+    outpam.height = hdr.bm_height / 2;
+    outpam.maxval = 255;
+    outpam.allocation_depth = 5;
+    outpam.depth  = 0;
+        /* Just for tuple array allocation; we set the value for the actual
+           output image below.
+        */
+
+    tuples = pnm_allocpamarray(&outpam);
+
+    readXorMask(&hdr, &image[offset], 
+                dirEntryP->size - offset,
+                tuples, dirEntryP->index, needHeaderDump,
+                &haveAlpha, &xorByteCt);
+
+    offset += xorByteCt;
+
+    {
+        /* If there is no alpha channel in XOR mask, store the AND mask to
+           the transparency plane.  Else, here are two transparency
+           maps. If requested, store the AND mask to a fifth PAM plane
+        */
+        bool haveAnd;
+        unsigned int andPlane;
+
+        if (!haveAlpha) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        } else if (wantAndMaskPlane) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE + 1;
+            outpam.depth  = 5;
+            strcpy(outpam.tuple_type, "RGB_ALPHA_ANDMASK");
+        } else {
+            haveAnd = false;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        }
+        if (haveAnd) {
+            readAnd(&hdr, &image[offset], dirEntryP->size - offset,
+                    tuples, dirEntryP->index, andPlane, outpam.maxval);
+        }
+    }
+    pnm_writepam(&outpam, tuples);
+    pnm_freepamarray(tuples, &outpam);
+
+    reportImage(dirEntryP->index, hdr, haveAlpha);
+}
+
+
+
+static void
+reportPngInfo(const unsigned char * const image,
+              struct IconDirEntry * const dirEntryP) {
+    
+    struct PngIhdr ihdr;
+
+    ihdr.length      = u32_be (image, sizeof(pngHeader)  +0);
+    ihdr.signature   = u32_xx (image, sizeof(pngHeader)  +4);
+    ihdr.width       = u32_be (image, sizeof(pngHeader)  +8);
+    ihdr.height      = u32_be (image, sizeof(pngHeader) +12);
+    ihdr.bit_depth   = u8_be  (image, sizeof(pngHeader) +16);
+    ihdr.color_type  = u8_be  (image, sizeof(pngHeader) +17);
+    ihdr.compression = u8_be  (image, sizeof(pngHeader) +18);
+    ihdr.filter      = u8_be  (image, sizeof(pngHeader) +19);
+    ihdr.interlace   = u8_be  (image, sizeof(pngHeader) +20);
+
+    if ((ihdr.length != 13)
+        || ihdr.signature != *(uint32_t*)"IHDR") {
+        pm_message("image %2u: PNG (uncommonly formatted)",
+                   dirEntryP->index);
+    } else {
+        uint32_t depth;
+        const char * colorType;
+
+        switch (ihdr.color_type) {
+        case 0:
+            colorType = "grayscale";
+            depth     = ihdr.bit_depth;
+            break;
+
+        case 2:
+            colorType = "RGB";
+            depth     = ihdr.bit_depth * 3;
+            break;
+
+        case 3:
+            colorType = "RGB/palette";
+            depth     = 8;
+            break;
+
+        case 4:
+            colorType = "grayscale + alpha";
+            depth     = ihdr.bit_depth * 2;
+            break;
+
+        case 6:
+            colorType = "RGB + alpha";
+            depth     = ihdr.bit_depth * 4;
+            break;
+
+        default:
+            colorType = "unknown color system";
+            depth     = 0;
+            break;
+        }
+        pm_message("image %2u: PNG %3u x %3u x %2u (%s)",
+                   dirEntryP->index,
+                   ihdr.width, ihdr.height, depth, colorType);
+
+        if ((dirEntryP->width != ihdr.width)
+            || (dirEntryP->height != ihdr.height)) {
+            pm_message("image %2u:"
+                       " mismatch in header and image dimensions"
+                       " (%u x %u vs %u x %u)",
+                       dirEntryP->index, dirEntryP->width, dirEntryP->height,
+                       ihdr.width, ihdr.height);
+        }
+        /* Mismatch between dirEntryP->bits_per_pixel and 'depth' is
+           normal, because the creator of the winicon file doesn't necessarily
+           know the true color resolution.
+        */
+    }
+}
+
+
+
+static void
+convertPng(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP) {
+
+    struct bufferDesc imageBuffer;
+
+    reportPngInfo(image, dirEntryP);
+
+    imageBuffer.size = dirEntryP->size;
+    imageBuffer.buffer = (unsigned char *)image;
+
+    fflush (stdout);
+    pm_system(pm_feed_from_memory, &imageBuffer,
+              NULL /* stdout accepter */, NULL,
+              "pngtopam -alphapam");
+}
+
+
+
+static uint32_t
+bestImage(struct IconDir * const dirP) {
+
+    uint32_t imageIndex;
+    uint32_t bestPixelCt;
+    uint32_t bestColorCt;
+    uint16_t best;
+
+    bestPixelCt = 0;  /* initial value */
+    bestColorCt = 0;  /* initial value */
+    best        = 0;  /* initial value */
+    
+    for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        uint32_t const pixelCt = dirEntryP->width * dirEntryP->height;
+
+        uint32_t colorCt;
+
+        /*  32-bit icons have 24 bit color information only.
+         
+            Since NT 5.1 (aka WinXP), it is allowed to place 8-bit
+            transparency information in the remaining bits (to check,
+            you have to read all these bits in the image!), so I prefer
+            32-bit images over 24-bit images (which violate the
+            spec. anyway).
+        */
+        if (dirEntryP->bits_per_pixel > 24)
+            colorCt = 1u << 25;
+        else
+            colorCt = 1u << dirEntryP->bits_per_pixel;
+
+        if (dirEntryP->color_count != 0 && colorCt > dirEntryP->color_count)
+            colorCt = dirEntryP->color_count;
+
+        if ((pixelCt > bestPixelCt)
+            || ((pixelCt == bestPixelCt) && (colorCt > bestColorCt))) {
+            /* This is a new best */
+            bestPixelCt = pixelCt;
+            bestColorCt = colorCt;
+            best        = imageIndex;
+        }
+    }
+    return best;
+}
+
+
+
+static void
+convertImage(struct File *         const icoP,
+             struct IconDirEntry * const dirEntryP,
+             FILE *                const ofP,
+             bool                  const needHeaderDump,
+             bool                  const wantAndMaskPlane) {
+
+    const unsigned char * image;  /* malloced */
+
+    image = readImage(icoP, dirEntryP);
+
+    if (MEMEQ(image, pngHeader, sizeof (pngHeader)))
+        convertPng(image, ofP, dirEntryP);
+    else
+        convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane);
+
+    free((void *)image);
+}
+
+
+
+int
+main (int argc, const char *argv []) {
+
+    struct File ico;
+    struct IconDir * dirP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit (&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ico.name =
+        streq(cmdline.inputFileName, "-") ?  "<stdin>" : cmdline.inputFileName;
+    ico.pos   = 0;
+    ico.fileP = pm_openr(cmdline.inputFileName);
+
+    dirP = readIconDir(&ico, cmdline.headerdump);
+
+    if (cmdline.allimages) {
+        unsigned int i;
+        for (i = 0; i < dirP->count; ++i)
+            convertImage(&ico, &dirP->entries[i], stdout,
+                         cmdline.headerdump, cmdline.andmasks);
+    } else if (cmdline.imageSpec) {
+        unsigned int i;
+        bool found;
+        for (i = 0, found = false; i < dirP->count; ++i) {
+            if (dirP->entries[i].index == cmdline.image) {
+                found = true;
+                convertImage(&ico, &dirP->entries[i], stdout,
+                             cmdline.headerdump, cmdline.andmasks);
+            }
+        }
+        if (!found)
+            pm_error("no image index %u in.input", cmdline.image);
+    } else {
+        convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout,
+                     cmdline.headerdump, cmdline.andmasks);
+    }
+    
+    freeIconDir(dirP);
+
+    if (ico.fileP != stdin)
+        pm_close(ico.fileP);
+
+    return 0;
+}
+
+
+