about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/other/Makefile19
-rw-r--r--converter/other/bmptopnm.c11
-rw-r--r--converter/other/cameratopam/camera.c4
-rw-r--r--converter/other/cameratopam/ljpeg.c237
-rw-r--r--converter/other/cameratopam/ljpeg.h9
-rw-r--r--converter/other/pamrgbatopng.c136
-rw-r--r--converter/other/pamtopng.c771
-rw-r--r--converter/other/pamtosvg/pxl-outline.c1
-rw-r--r--converter/other/pngtxt.c4
-rw-r--r--converter/other/pngx.c47
-rw-r--r--converter/other/pngx.h16
-rw-r--r--converter/other/pnmtopng.c53
-rw-r--r--converter/other/pnmtops.c8
-rw-r--r--converter/other/pnmtoxwd.c20
-rw-r--r--converter/other/sgitopnm.c7
-rw-r--r--converter/pbm/atktopbm.c425
-rw-r--r--converter/pbm/brushtopbm.c6
-rw-r--r--converter/pbm/macp.h18
-rw-r--r--converter/pbm/macptopbm.c426
-rw-r--r--converter/pbm/pbmto10x.c113
-rw-r--r--converter/pbm/pbmtoatk.c69
-rw-r--r--converter/pbm/pbmtoepson.c59
-rw-r--r--converter/pbm/pbmtog3.c6
-rw-r--r--converter/pbm/pbmtomacp.c707
-rw-r--r--converter/pbm/pbmtomatrixorbital.c35
-rw-r--r--converter/pbm/pbmtomgr.c6
-rw-r--r--converter/pbm/pbmtopi3.c163
-rw-r--r--converter/pbm/pbmtopk.c30
-rw-r--r--converter/pbm/pbmtoptx.c135
-rw-r--r--converter/pbm/pbmtoxbm.c59
-rw-r--r--converter/pbm/pbmtoybm.c86
-rw-r--r--converter/pbm/pbmtozinc.c241
-rw-r--r--converter/pbm/pi3topbm.c224
-rw-r--r--converter/pbm/xbmtopbm.c8
-rw-r--r--converter/pbm/ybmtopbm.c63
-rw-r--r--converter/ppm/ppmtoarbtxt.c7
-rw-r--r--converter/ppm/ppmtobmp.c26
-rw-r--r--converter/ppm/ppmtoicr.c532
-rw-r--r--converter/ppm/ppmtompeg/Makefile3
-rw-r--r--converter/ppm/ppmtompeg/headers/all.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/ansi.h76
-rw-r--r--converter/ppm/ppmtompeg/headers/bitio.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/dct.h9
-rw-r--r--converter/ppm/ppmtompeg/headers/frame.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/frames.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/frametype.h2
-rw-r--r--converter/ppm/ppmtompeg/headers/jpeg.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/mheaders.h23
-rw-r--r--converter/ppm/ppmtompeg/headers/motion_search.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/mpeg.h5
-rw-r--r--converter/ppm/ppmtompeg/headers/mproto.h47
-rw-r--r--converter/ppm/ppmtompeg/headers/opts.h15
-rw-r--r--converter/ppm/ppmtompeg/headers/parallel.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/param.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/prototypes.h35
-rw-r--r--converter/ppm/ppmtompeg/headers/rate.h18
-rw-r--r--converter/ppm/ppmtompeg/headers/specifics.h9
-rw-r--r--converter/ppm/ppmtompeg/jrevdct.c7
-rw-r--r--converter/ppm/ppmtompeg/mpeg.c6
-rw-r--r--converter/ppm/ppmtompeg/opts.c2
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c4
-rw-r--r--converter/ppm/ppmtompeg/rate.c14
-rw-r--r--converter/ppm/ppmtompeg/readframe.c26
-rw-r--r--converter/ppm/ppmtompeg/specifics.c16
-rw-r--r--converter/ppm/ppmtopcx.c16
65 files changed, 3127 insertions, 2001 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
index e76373ef..f51a780b 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -46,7 +46,7 @@ else
     HAVE_PNGLIB = Y
     EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags)
   else
-    # System can't tell use where libpng is; use stuff from config.mk
+    # System can't tell us where libpng is; use stuff from config.mk
     ifneq ($(PNGLIB),NONE)
       HAVE_PNGLIB = Y
       ifneq ($(PNGHDR_DIR)x,x)
@@ -131,7 +131,7 @@ ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
 endif
 
 ifeq ($(HAVE_PNGLIB),Y)
-  PORTBINARIES += pnmtopng pngtopam pamrgbatopng
+  PORTBINARIES += pamtopng pnmtopng pngtopam
 endif
 ifneq ($(JPEGLIB),NONE)
   PORTBINARIES += jpegtopnm pnmtojpeg
@@ -207,14 +207,14 @@ pngtopam: pngx.o
 pngtopam: ADDL_OBJECTS = pngx.o
 pngtopam: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
 
+pamtopng: pngx.o pngtxt.o
+pamtopng: ADDL_OBJECTS = pngx.o pngtxt.o
+pamtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
+
 pnmtopng: pngx.o pngtxt.o
 pnmtopng: ADDL_OBJECTS = pngx.o pngtxt.o
 pnmtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
 
-pamrgbatopng: pngx.o
-pamrgbatopng: ADDL_OBJECTS = pngx.o
-pamrgbatopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
-
 jpegtopnm: jpegdatasource.o exif.o
 jpegtopnm: ADDL_OBJECTS = jpegdatasource.o exif.o
 jpegtopnm: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB))
@@ -242,6 +242,8 @@ pnmtorast rasttopnm: ADDL_OBJECTS = rast.o
 pdbimgtopam pamtopdbimg: ipdb.o
 pdbimgtopam pamtopdbimg: ADDL_OBJECTS = ipdb.o
 
+# Declare dependencies on created header files (symbolic links, actually).
+
 bmptopnm.o bmptopnm.o2: bmp.h
 
 pamtotga.o pamtotga.o2: tga.h
@@ -289,3 +291,8 @@ endif
 # In December 2010, sunicontopnm replaced icontopbm
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) sunicontopnm$(EXE) icontopbm$(EXE)
+ifeq ($(HAVE_PNGLIB),Y)
+# In June 2015, pamtopng replaced pamrgbapng
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtopng$(EXE) pamrgbatopng$(EXE)
+endif
diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c
index 84d39989..a069092f 100644
--- a/converter/other/bmptopnm.c
+++ b/converter/other/bmptopnm.c
@@ -1442,8 +1442,6 @@ writeRasterPbm(unsigned char ** const bmpRaster,
   
   We destroy *bmpRaster as a side effect.
 -----------------------------------------------------------------------------*/
-    unsigned int const charBits = (sizeof(unsigned char) * 8);
-        /* Number of bits in a character */
     unsigned int const colChars = pbm_packed_bytes(cols);
     
     int row;
@@ -1463,13 +1461,8 @@ writeRasterPbm(unsigned char ** const bmpRaster,
             for (i = 0; i < colChars; ++i) 
                 bitrow[i] = ~bitrow[i]; /* flip all pixels */ 
         }   
-            
-        if (cols % 8 > 0) {
-            /* adjust final partial byte */
-            bitrow[colChars-1] >>= charBits - cols % charBits;
-            bitrow[colChars-1] <<= charBits - cols % charBits;
-        }
-        
+
+        pbm_cleanrowend_packed(bitrow, cols);
         pbm_writepbmrow_packed(stdout, bitrow, cols, FALSE);
     }
 }
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index d318e379..a1adba95 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -108,7 +108,7 @@ adobe_dng_load_raw_lj(Image const image) {
             twide = raw_width-tcol;
 
         for (jrow=0; jrow < jh.high; jrow++) {
-            ljpeg_row (&jh);
+            ljpeg_row(ifp, &jh);
             for (rp=jh.row, jcol=0; jcol < twide; jcol++)
                 adobeCopyPixel(image,
                                trow+jrow, tcol+jcol, &rp, use_secondary);
@@ -170,7 +170,7 @@ nikon_compressed_load_raw(Image const image) {
     for (row=0; row < height; row++)
         for (col=0; col < raw_width; col++)
         {
-            diff = ljpeg_diff (first_decode);
+            diff = ljpeg_diff (ifp, first_decode);
             if (col < 2) {
                 i = 2*(row & 1) + (col & 1);
                 vpred[i] += diff;
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
index d5e21d3b..07791e25 100644
--- a/converter/other/cameratopam/ljpeg.c
+++ b/converter/other/cameratopam/ljpeg.c
@@ -20,128 +20,145 @@
  */
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh)
-{
-  int i, tag, len;
-  unsigned char data[256], *dp;
-
-  init_decoder();
-  for (i=0; i < 4; i++)
-    jh->huff[i] = free_decode;
-  fread (data, 2, 1, ifp);
-  if (data[0] != 0xff || data[1] != 0xd8) return 0;
-  do {
-    fread (data, 2, 2, ifp);
-    tag =  data[0] << 8 | data[1];
-    len = (data[2] << 8 | data[3]);
-    if (len < 2)
-      pm_error("Length field is %u; must be at least 2", len);
-    else {
-      unsigned int const dataLen = len - 2;
-      if (tag <= 0xff00 || dataLen > 255) return 0;
-      fread (data, 1, dataLen, ifp);
-      switch (tag) {
-      case 0xffc3:
-        jh->bits = data[0];
-        jh->high = data[1] << 8 | data[2];
-        jh->wide = data[3] << 8 | data[4];
-        jh->clrs = data[5];
-        break;
-      case 0xffc4:
-        for (dp = data; dp < data+dataLen && *dp < 4; ) {
-          jh->huff[*dp] = free_decode;
-          dp = make_decoder (++dp, 0);
+ljpeg_start(FILE *         const ifP,
+            struct jhead * const jhP) {
+
+    int i, tag;
+    unsigned char data[256], *dp;
+
+    init_decoder();
+    for (i=0; i < 4; i++)
+        jhP->huff[i] = free_decode;
+    fread (data, 2, 1, ifP);
+    if (data[0] != 0xff || data[1] != 0xd8) return 0;
+    do {
+        unsigned int len;
+
+        fread (data, 2, 2, ifP);
+        tag =  data[0] << 8 | data[1];
+        len = data[2] << 8 | data[3];
+
+        if (len < 2)
+            pm_error("Length field is %u; must be at least 2", len);
+        else {
+            unsigned int const dataLen = len - 2;
+
+            if (tag <= 0xff00 || dataLen > 255) return 0;
+            fread (data, 1, dataLen, ifP);
+            switch (tag) {
+            case 0xffc3:
+                jhP->bits = data[0];
+                jhP->high = data[1] << 8 | data[2];
+                jhP->wide = data[3] << 8 | data[4];
+                jhP->clrs = data[5];
+                break;
+            case 0xffc4:
+                for (dp = data; dp < data + dataLen && *dp < 4; ) {
+                    jhP->huff[*dp] = free_decode;
+                    dp = make_decoder (++dp, 0);
+                }
+            }
         }
-      }
-    }
-  } while (tag != 0xffda);
-  jh->row = calloc (jh->wide*jh->clrs, 2);
-  if (jh->row == NULL)
-      pm_error("Out of memory in ljpeg_start()");
-  for (i=0; i < 4; i++)
-    jh->vpred[i] = 1 << (jh->bits-1);
-  zero_after_ff = 1;
-  getbits(ifp, -1);
-  return 1;
+    } while (tag != 0xffda);
+    jhP->row = calloc (jhP->wide*jhP->clrs, 2);
+    if (jhP->row == NULL)
+        pm_error("Out of memory in ljpeg_start()");
+    for (i=0; i < 4; i++)
+        jhP->vpred[i] = 1 << (jhP->bits-1);
+    zero_after_ff = 1;
+    getbits(ifP, -1);
+    return 1;
 }
 
+
+
 int 
-ljpeg_diff (struct decode *dindex)
-{
-  int len, diff;
-
-  while (dindex->branch[0])
-    dindex = dindex->branch[getbits(ifp, 1)];
-  diff = getbits(ifp, len = dindex->leaf);
-  if ((diff & (1 << (len-1))) == 0)
-    diff -= (1 << len) - 1;
-  return diff;
+ljpeg_diff(FILE *          const ifP,
+           struct decode * const dindexHeadP) {
+
+    int len;
+    int diff;
+    struct decode * dindexP;
+
+    for (dindexP = dindexHeadP; dindexP->branch[0]; )
+        dindexP = dindexP->branch[getbits(ifP, 1)];
+
+    diff = getbits(ifP, len = dindexP->leaf);
+
+    if ((diff & (1 << (len-1))) == 0)
+        diff -= (1 << len) - 1;
+
+    return diff;
 }
 
+
+
 void
-ljpeg_row (struct jhead *jh)
-{
-  int col, c, diff;
-  unsigned short *outp=jh->row;
-
-  for (col=0; col < jh->wide; col++)
-    for (c=0; c < jh->clrs; c++) {
-      diff = ljpeg_diff (jh->huff[c]);
-      *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff);
-      outp++;
-    }
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP) {
+
+    int col, c, diff;
+    unsigned short *outp=jhP->row;
+
+    for (col=0; col < jhP->wide; col++)
+        for (c=0; c < jhP->clrs; c++) {
+            diff = ljpeg_diff(ifP, jhP->huff[c]);
+            *outp = col ? outp[-jhP->clrs]+diff : (jhP->vpred[c] += diff);
+            outp++;
+        }
 }
 
 
+
 void  
-lossless_jpeg_load_raw(Image const image) {
-
-  int jwide, jrow, jcol, val, jidx, i, row, col;
-  struct jhead jh;
-  int min=INT_MAX;
-
-  if (!ljpeg_start (ifp, &jh)) return;
-  jwide = jh.wide * jh.clrs;
-
-  for (jrow=0; jrow < jh.high; jrow++) {
-    ljpeg_row (&jh);
-    for (jcol=0; jcol < jwide; jcol++) {
-      val = curve[jh.row[jcol]];
-      jidx = jrow*jwide + jcol;
-      if (raw_width == 5108) {
-    i = jidx / (1680*jh.high);
-    if (i < 2) {
-      row = jidx / 1680 % jh.high;
-      col = jidx % 1680 + i*1680;
-    } else {
-      jidx -= 2*1680*jh.high;
-      row = jidx / 1748;
-      col = jidx % 1748 + 2*1680;
-    }
-      } else if (raw_width == 3516) {
-    row = jidx / 1758;
-    col = jidx % 1758;
-    if (row >= raw_height) {
-      row -= raw_height;
-      col += 1758;
-    }
-      } else {
-    row = jidx / raw_width;
-    col = jidx % raw_width;
-      }
-      if ((unsigned) (row-top_margin) >= height) continue;
-      if ((unsigned) (col-left_margin) < width) {
-    BAYER(row-top_margin,col-left_margin) = val;
-    if (min > val) min = val;
-      } else
-    black += val;
+lossless_jpeg_load_raw(Image  const image) {
+
+    int jwide, jrow, jcol, val, jidx, i, row, col;
+    struct jhead jh;
+    int min=INT_MAX;
+
+    if (!ljpeg_start (ifp, &jh)) return;
+    jwide = jh.wide * jh.clrs;
+
+    for (jrow=0; jrow < jh.high; jrow++) {
+        ljpeg_row (ifp, &jh);
+        for (jcol=0; jcol < jwide; jcol++) {
+            val = curve[jh.row[jcol]];
+            jidx = jrow*jwide + jcol;
+            if (raw_width == 5108) {
+                i = jidx / (1680*jh.high);
+                if (i < 2) {
+                    row = jidx / 1680 % jh.high;
+                    col = jidx % 1680 + i*1680;
+                } else {
+                    jidx -= 2*1680*jh.high;
+                    row = jidx / 1748;
+                    col = jidx % 1748 + 2*1680;
+                }
+            } else if (raw_width == 3516) {
+                row = jidx / 1758;
+                col = jidx % 1758;
+                if (row >= raw_height) {
+                    row -= raw_height;
+                    col += 1758;
+                }
+            } else {
+                row = jidx / raw_width;
+                col = jidx % raw_width;
+            }
+            if ((unsigned) (row-top_margin) >= height) continue;
+            if ((unsigned) (col-left_margin) < width) {
+                BAYER(row-top_margin,col-left_margin) = val;
+                if (min > val) min = val;
+            } else
+                black += val;
+        }
     }
-  }
-  free (jh.row);
-  if (raw_width > width)
-    black /= (raw_width - width) * height;
-  if (!strcasecmp(make,"KODAK"))
-    black = min;
+    free (jh.row);
+    if (raw_width > width)
+        black /= (raw_width - width) * height;
+    if (!strcasecmp(make,"KODAK"))
+        black = min;
 }
 
 
diff --git a/converter/other/cameratopam/ljpeg.h b/converter/other/cameratopam/ljpeg.h
index cfd68eb4..9d9d8ee9 100644
--- a/converter/other/cameratopam/ljpeg.h
+++ b/converter/other/cameratopam/ljpeg.h
@@ -9,10 +9,13 @@ struct jhead {
 LoadRawFn lossless_jpeg_load_raw;
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh);
+ljpeg_start (FILE *         const ifP,
+             struct jhead * const jhP);
 
 int 
-ljpeg_diff (struct decode *dindex);
+ljpeg_diff (FILE *          const ifP,
+            struct decode * const dindexP);
 
 void
-ljpeg_row (struct jhead *jh);
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP);
diff --git a/converter/other/pamrgbatopng.c b/converter/other/pamrgbatopng.c
deleted file mode 100644
index 07a5181b..00000000
--- a/converter/other/pamrgbatopng.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-/* Because of poor design of libpng, you must not #include <setjmp.h> before
-<png.h>.  Compile failure results.
-*/
-#include <png.h>
-#include <setjmp.h>
-
-#include "pm_c_util.h"
-#include "mallocvar.h"
-#include "pam.h"
-#include "pngx.h"
-
-
-
-struct cmdlineInfo {
-    const char * inputFileName;
-};
-
-
-
-static void
-processCommandLine(int                  const argc,
-                   char *               const argv[],
-                   struct cmdlineInfo * const cmdlineP) {
-        
-    if (argc-1 < 1)
-        cmdlineP->inputFileName = "-";
-    else {
-        cmdlineP->inputFileName = argv[1];
-
-        if (argc-1 > 1)
-            pm_error("Too many arguments.  "
-                     "The only argument is the input file name.");
-    }
-}
-
-
-
-static void
-convertPamToPng(const struct pam * const pamP,
-                const tuple *      const tuplerow,
-                png_byte *         const pngRow) {
-    
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        
-        for (plane = 0; plane < 4; ++plane)
-            pngRow[4 * col + plane] = tuplerow[col][plane];
-    }
-}
-
-
-
-static void
-writeRaster(const struct pam * const pamP,
-            struct pngx *      const pngxP) {
-    
-    tuple * tupleRow;
-    png_byte * pngRow;
-    
-    tupleRow = pnm_allocpamrow(pamP);
-    MALLOCARRAY(pngRow, pamP->width * 4);
-
-    if (pngRow == NULL)
-        pm_error("Unable to allocate space for PNG pixel row.");
-    else {
-        unsigned int row;
-        for (row = 0; row < pamP->height; ++row) {
-            pnm_readpamrow(pamP, tupleRow);
-            
-            convertPamToPng(pamP, tupleRow, pngRow);
-            
-            png_write_row(pngxP->png_ptr, pngRow);
-        }
-        free(pngRow);
-    }
-    pnm_freepamrow(tupleRow);
-}
-
-
-
-static void
-writePng(const struct pam * const pamP,
-         FILE *             const ofP) {
-
-    struct pngx * pngxP;
-
-    pngx_create(&pngxP, PNGX_WRITE, NULL);
-    
-    pngx_setIhdr(pngxP, pamP->width, pamP->height,
-                 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0, 0);
-        
-    png_init_io(pngxP->png_ptr, ofP);
-
-    pngx_writeInfo(pngxP);
-        
-    writeRaster(pamP, pngxP);
-
-    pngx_writeEnd(pngxP);
-        
-    pngx_destroy(pngxP);
-}
-    
-
-
-int
-main(int argc, char * argv[]) {
-
-    FILE * ifP;
-    struct cmdlineInfo cmdline;
-    struct pam pam;
-
-    pnm_init(&argc, argv);
-
-    processCommandLine(argc, argv, &cmdline);
-
-    ifP = pm_openr(cmdline.inputFileName);
-
-    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
-    
-    if (pam.depth < 4)
-        pm_error("PAM must have depth at least 4 (red, green, blue, alpha).  "
-                 "This one has depth %u", pam.depth);
-        
-    if (pam.maxval != 255)
-        pm_error("PAM must have maxval 255.  This one has %lu", pam.maxval);
-
-    writePng(&pam, stdout);
-
-    pm_close(ifP);
-
-    return 0;
-}
diff --git a/converter/other/pamtopng.c b/converter/other/pamtopng.c
new file mode 100644
index 00000000..af284ac0
--- /dev/null
+++ b/converter/other/pamtopng.c
@@ -0,0 +1,771 @@
+/*
+** read a PNM/PAM image and produce a Portable Network Graphics (PNG) file
+**
+** derived from pnmtorast.c by Jef Poskanzer and pamrgbatopng.c by Bryan
+** Henderson <bryanh@giraffe-data.com> and probably some other sources
+**
+** Copyright (C) 1995-1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+** Copyright (C) 1999,2001 by Greg Roelofs <newt@pobox.com>
+** Copyright (C) 2015 by Willem van Schaik <willem@schaik.com>
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+/*
+  This Netpbm program pamtopng was derived in 2015 from the Netpbm program
+  Pnmtopng. This was a nearly complete rewrite with the following goals:
+
+  - Add ability to create a PNG alpha channel from the alpha channel in a
+    PAM (format P7) file.
+
+  - Simplify the 20 year old pnmtopng code. Because of the many, many features
+    that program implements and its need for backward compatibility, the code
+    had become rather complex.  This program is roughly 1/3 the size of
+    pnmtopng.c that it replaces.
+
+  - In 1995 bandwith was limited and therefore filesize had to be kept
+    small. The original program tried to optimize for that by applying
+    many "clever tricks". Today that isn't an issue anymore, so gone 
+    are filters, palettes, etc. Also, image conversions were removed,
+    because those should be done with other NetPBM tools.
+
+  - Add support for iTXt (international language) chunks.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+/* setjmp.h needs to be included after png.h */
+#include <setjmp.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+#include "pngx.h"
+#include "pngtxt.h"
+
+
+/* global variable */
+static bool verbose;
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int verbose;
+    unsigned int transparencySpec;
+    const char * transparency;
+    unsigned int chromaSpec;
+    struct pngx_chroma chroma;
+    unsigned int gammaSpec;
+    float gamma;
+    unsigned int srgbintentSpec;
+    pngx_srgbIntent srgbintent;
+    unsigned int textSpec;
+    const char * text;
+    unsigned int ztxtSpec;
+    const char * ztxt;
+    unsigned int itxtSpec;
+    const char * itxt;
+    unsigned int backgroundSpec;
+    const char * background;
+    unsigned int timeSpec;
+    time_t time;
+};
+
+
+
+static void
+parseChromaOpt(const char *         const chromaOpt,
+               struct pngx_chroma * const chromaP) {
+
+    int count;
+    
+    count = sscanf(chromaOpt, "%f %f %f %f %f %f %f %f",
+                   &chromaP->wx, &chromaP->wy,
+                   &chromaP->rx, &chromaP->ry,
+                   &chromaP->gx, &chromaP->gy,
+                   &chromaP->bx, &chromaP->by);
+
+    if (count != 6)
+        pm_error("Invalid syntax for the -rgb option value '%s'.  "
+                 "Should be 6 floating point number: "
+                 "x and y for each of white, red, green, and blue",
+                 chromaOpt);
+}
+
+
+
+static void
+parseSrgbintentOpt(const char *      const srgbintentOpt,
+                   pngx_srgbIntent * const srgbintentP) {
+    
+    if (streq(srgbintentOpt, "perceptual"))
+        *srgbintentP = PNGX_PERCEPTUAL;
+    else if (streq(srgbintentOpt, "relativecolorimetric"))
+        *srgbintentP = PNGX_RELATIVE_COLORIMETRIC;
+    else if (streq(srgbintentOpt, "saturation"))
+        *srgbintentP = PNGX_SATURATION;
+    else if (streq(srgbintentOpt, "absolutecolorimetric"))
+        *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC;
+    else
+        pm_error("Unrecognized sRGB intent value '%s'.  We understand "
+                 "only 'perceptual', 'relativecolorimetric', "
+                 "'saturation', and 'absolutecolorimetric'",
+                 srgbintentOpt);
+}
+
+
+
+static void
+parseTimeOpt(const char * const timeOpt,
+             time_t *     const timeP) {
+
+    struct tm brokenTime;
+    int year;
+    int month;
+    int count;
+
+    count = sscanf(timeOpt, "%d-%d-%d %d:%d:%d",
+                   &year,
+                   &month,
+                   &brokenTime.tm_mday,
+                   &brokenTime.tm_hour,
+                   &brokenTime.tm_min,
+                   &brokenTime.tm_sec);
+
+    if (count != 6)
+        pm_error("Invalid value for -time '%s'.   It should have "
+                 "the form [yy]yy-mm-dd hh:mm:ss.", timeOpt);
+    
+    if (year < 0)
+        pm_error("Year is negative in -time value '%s'", timeOpt);
+    if (year > 9999)
+        pm_error("Year is more than 4 digits in -time value '%s'",
+                 timeOpt);
+    if (month < 0)
+        pm_error("Month is negative in -time value '%s'", timeOpt);
+    if (month > 12)
+        pm_error("Month is >12 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_mday < 0)
+        pm_error("Day of month is negative in -time value '%s'",
+                 timeOpt);
+    if (brokenTime.tm_mday > 31)
+        pm_error("Day of month is >31 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_hour < 0)
+        pm_error("Hour is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_hour > 23)
+        pm_error("Hour is >23 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_min < 0)
+        pm_error("Minute is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_min > 59)
+        pm_error("Minute is >59 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_sec < 0)
+        pm_error("Second is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_sec > 59)
+        pm_error("Second is >59 in -time value '%s'", timeOpt);
+
+    brokenTime.tm_mon = month - 1;
+    if (year >= 1900)
+        brokenTime.tm_year = year - 1900;
+    else
+        brokenTime.tm_year = year;
+
+    /* Note that mktime() considers brokeTime to be in local time.
+       This is what we want, since we got it from a user.  User should
+       set his local time zone to UTC if he wants absolute time.
+    */
+    *timeP = mktime(&brokenTime);
+}
+
+
+
+static void
+parseCommandLine (int                  argc,
+                  const char **        argv,
+                  struct CmdlineInfo * const cmdlineP) {
+    
+    optEntry * option_def;
+    optStruct3 opt;
+    unsigned int option_def_index = 0;  /* incremented by OPTENT3 */
+
+    const char * srgbintent;
+    const char * chroma;
+    const char * time;
+
+    MALLOCARRAY(option_def, 100);
+
+    OPTENT3(0,  "verbose",      OPT_FLAG,       NULL,
+            &cmdlineP->verbose,        0);
+    OPTENT3(0,  "transparency", OPT_STRING,     &cmdlineP->transparency,
+            &cmdlineP->transparencySpec, 0);
+    OPTENT3(0,  "chroma",       OPT_STRING,     &chroma,
+            &cmdlineP->chromaSpec,     0);
+    OPTENT3(0,  "gamma",        OPT_FLOAT,      &cmdlineP->gamma,
+            &cmdlineP->gammaSpec,      0);
+    OPTENT3(0,  "srgbintent",   OPT_STRING,     &srgbintent,
+            &cmdlineP->srgbintentSpec, 0);
+    OPTENT3(0,  "text",         OPT_STRING,     &cmdlineP->text,
+            &cmdlineP->textSpec,       0);
+    OPTENT3(0,  "ztxt",         OPT_STRING,     &cmdlineP->ztxt,
+            &cmdlineP->ztxtSpec,       0);
+    OPTENT3(0,  "itxt",         OPT_STRING,     &cmdlineP->itxt,
+            &cmdlineP->itxtSpec,       0);
+    OPTENT3(0,  "background",   OPT_STRING,     &cmdlineP->background,
+            &cmdlineP->backgroundSpec, 0);
+    OPTENT3(0,  "time",         OPT_STRING,        &time,
+            &cmdlineP->timeSpec,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* we have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* we have no parms that are negative numbers */
+
+    /* uses and sets argc, argv, and some of *cmdlineP and others */
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+
+    if (cmdlineP->chromaSpec)
+        parseChromaOpt(chroma, &cmdlineP->chroma);
+
+    if (cmdlineP->srgbintentSpec)
+        parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent);
+
+    if (cmdlineP->timeSpec)
+        parseTimeOpt(time, &cmdlineP->time);
+    
+    /* get the input-file or stdin pipe */
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.");
+
+    free(option_def);
+}
+
+
+
+static png_byte
+colorTypeFromInputType(const struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+  Analyse the Netpbm image for color-type and bit-depth
+-----------------------------------------------------------------------------*/
+    png_byte retval;
+
+    if (pamP->depth < 1 && pamP->depth > 4)
+        pm_error ("Number of color planes must be between 1 and 4 inclusive");
+
+    if (pamP->maxval != 1 && pamP->maxval != 3 && pamP->maxval != 15 &&
+        pamP->maxval != 255 && pamP->maxval != 65535)
+        pm_error("The maxval of the input image is %u; "
+                 "it must be 1, 3, 15, 255 or 65535", (unsigned)pamP->maxval);
+
+    if (strneq(pamP->tuple_type, "RGB_ALPHA", 9)) {
+        if (pamP->depth == 4)
+            retval = PNG_COLOR_TYPE_RGB_ALPHA;
+        else
+            pm_error("Input tuple type is RGB_ALPHA, "
+                     "but number of planes is %u instead of 4",
+                pamP->depth);
+    } else if (strneq(pamP->tuple_type, "RGB", 3)) {
+        if (pamP->depth == 3)
+            retval = PNG_COLOR_TYPE_RGB;
+        else
+            pm_error("Input tuple type is RGB, "
+                     "but number of planes is %u instead of 3",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "GRAYSCALE_ALPHA", 15)) {
+        if (pamP->depth == 2)
+            retval = PNG_COLOR_TYPE_GRAY_ALPHA;
+        else
+            pm_error("Input tupel type is GRAYSCALE_ALPHA, "
+                     "but number of planes is %u instread of 2",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "GRAYSCALE", 9)) {
+        if (pamP->depth == 1)
+            retval = PNG_COLOR_TYPE_GRAY;
+        else
+            pm_error("Input tuple type is GRAYSCALE, "
+                     "but number of planes is %u instead of 1",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "BLACKANDWHITE", 3)) {
+        if (pamP->depth != 1)
+            pm_error("Input tuple type is BLACKANDWHITE, "
+                     "but number of planes is %u instead of 1",
+                     pamP->depth);
+        if (pamP->maxval != 1)
+            pm_error("Input tuple type is BLACKANDWHITE, "
+                     "but maxval is %u instead of 1", (unsigned)pamP->maxval);
+
+        retval = PNG_COLOR_TYPE_GRAY;
+    } else
+        pm_error("Unrecognized tuple type: '%s'", pamP->tuple_type);
+
+    return retval;
+}
+
+
+
+/*****************************************************************************
+*  Subroutines that create all the (ancillary) chunks
+*****************************************************************************/
+
+
+
+static png_color_16
+parseAndScaleColor(const char * const colorString,
+                   xelval       const pngMaxval) {
+
+    png_color_16 pngColor;
+
+    if (colorString) {
+        xel const inputColor = ppm_parsecolor(colorString, PNM_OVERALLMAXVAL);
+
+        xel scaledColor;
+
+        /* Scale the color down to the PNG bit depth */
+        PPM_DEPTH(scaledColor, inputColor, PNM_OVERALLMAXVAL, pngMaxval);
+
+        pngColor.red   = PPM_GETR(scaledColor);
+        pngColor.green = PPM_GETG(scaledColor);
+        pngColor.blue  = PPM_GETB(scaledColor);
+        pngColor.gray  = PNM_GET1(scaledColor);
+    }
+
+    return pngColor;
+}
+
+
+
+static void
+doTrnsChunk(const struct pam * const pamP,
+            struct pngx *      const pngxP,
+            const char *       const trans) {
+
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA || 
+        pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA)
+        pm_error("Both alpha channel and transparency chunk not allowed.");
+    else {
+        xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP));
+        png_color_16 const pngColor = parseAndScaleColor(trans, pngMaxval);
+            /* Transparency color from text format scaled from 16-bit to
+               maxval.
+            */
+
+        pngx_setTrnsValue(pngxP, pngColor);
+
+        if (verbose) {
+            if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY) {
+                pm_message("writing tRNS chunk with color {gray} = {%u}",
+                           pngColor.gray );
+            } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB) {
+                pm_message("writing tRNS chunk with color "
+                           "{red, green, blue} = {%u, %u, %u}",
+                           pngColor.red, pngColor.green, pngColor.blue);
+            }
+        }
+    }
+}
+
+
+
+static void
+doChrmChunk(struct pngx *      const pngxP,
+            struct pngx_chroma const chroma) {
+    
+    pngx_setChrm(pngxP, chroma);
+
+    if (verbose) {
+        pm_message("writing cHRM chunk { wx, wy, rx, ry, gx, gy, bx, by } = "
+                   "{ %4.2f, %4.2f, %4.2f, %4.2f, "
+                   "%4.2f, %4.2f, %4.2f, %4.2f }", 
+                   chroma.wx, chroma.wy,
+                   chroma.rx, chroma.ry,
+                   chroma.gx, chroma.gy,
+                   chroma.bx, chroma.by);
+    }
+}
+
+
+
+static void 
+doGamaChunk(struct pngx *  const pngxP,
+            float          const gamma) {
+
+    pngx_setGama(pngxP, gamma);
+
+    if (verbose) {
+        pm_message("writing gAMA chunk with image gamma value %4.2f", gamma);
+    }
+}
+
+
+
+static void
+doSbitChunk(const struct pam * const pamP,
+            struct pngx *      const pngxP) {
+
+    unsigned int const pnmBitDepth = pm_maxvaltobits(pamP->maxval);
+
+    /* create SBIT chunk in case of 1,2,4 bit deep images stored in 8 bit
+       format PNG files 
+    */
+    if (pngx_colorType(pngxP) != PNG_COLOR_TYPE_GRAY && pnmBitDepth < 8) {
+        png_color_8 sBit;
+
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || 
+            pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) {
+            sBit.red = sBit.green = sBit.blue = pnmBitDepth;
+        } else {
+            sBit.gray = pnmBitDepth;
+        }
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA || 
+            pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) {
+            sBit.alpha = pnmBitDepth;
+        }
+        pngx_setSbit(pngxP, sBit);
+    }
+}
+
+
+
+static void
+doSrgbChunk(struct pngx *   const pngxP,
+            pngx_srgbIntent const srgbIntent) {
+
+    pngx_setSrgb(pngxP, srgbIntent);
+
+    if (verbose) {
+        pm_message("writing sRGB chunk with intent value %s",
+                   pngx_srgbIntentDesc(srgbIntent));
+    }
+}
+
+
+
+static void
+doTextChunk(struct pngx * const pngxP,
+            const char *  const textFileName) {
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+    
+    pngtxt_read(pngxP, tfP, false, verbose);
+    
+    if (verbose)
+        pm_message("writing tEXt chunk");
+
+    pm_close(tfP);
+}
+
+
+
+static void
+doZtxtChunk(struct pngx * const pngxP,
+            const char *  const textFileName) {
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+    
+    pngtxt_read(pngxP, tfP, true, verbose);
+    
+    if (verbose)
+        pm_message("writing zTXt chunk");
+
+    pm_close(tfP);
+    
+}
+
+
+
+
+static void
+doItxtChunk (struct pngx * const pngxP,
+             const char *  const textFileName) {
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+
+    pm_error("Code to handle an ITXT chunk has not been written yet");
+
+    /* pngtxt_read(pngxP, tfP, true, true, verbose); */
+
+    if (verbose)
+        pm_message("writing iTXt chunk");
+}
+
+
+
+static void
+doBkgdChunk (const struct pam * const pamP,
+             struct pngx *      const pngxP,
+             const char *       const colorName)
+{
+    xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP));
+
+    png_color_16 const pngColor = parseAndScaleColor(colorName, pngMaxval);
+        /* Background color from text format, scaled from 16-bit to maxval */
+
+    pngx_setBkgdRgb(pngxP, pngColor);
+
+    if (verbose) {
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || 
+            pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) {
+            pm_message("writing bKGD chunk with gray level = %u",
+                       pngColor.gray);
+        } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || 
+                   pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) {
+            pm_message("writing bKGD chunk with color {red, green, blue} = "
+                       "{%u, %u, %u}",
+                       pngColor.red, pngColor.green, pngColor.blue);
+        }
+    }
+}
+
+
+
+static void
+doTimeChunk(struct pngx * const pngxP,
+            time_t        const time) {
+
+    pngx_setTime(pngxP, time);
+
+    if (verbose) {
+        struct tm * const brokenTimeP = gmtime(&time);
+
+        char buffer[100];
+
+        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", brokenTimeP);
+
+        pm_message("Writing tIME chunk specifying datetime %s", buffer);
+    }
+}
+
+
+
+static void
+convertRaster(const struct pam * const pamP,
+              const tuple *      const tuplerow,
+              png_byte *         const pngRow,
+              unsigned int       const bitDepth) {
+
+    unsigned int col;
+
+    /* An image row consists of columns x planes like gray or rgb(a) x 8 or 16
+       bits.
+    */
+    for (col = 0; col < pamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < pamP->depth; ++plane) {
+            if (bitDepth > 8) {
+                /* Copy 2 bytes = 16 bits for one pixel */
+                pngRow[2 * (pamP->depth * col + plane)] =
+                    (tuplerow[col][plane] >> 8) & 0xff ;
+                pngRow[2 * (pamP->depth * col + plane) + 1] =
+                    tuplerow[col][plane] & 0xff ;
+            } else {
+                /* Copy 1 byte for one pixel. Later, a packing of 2, 4 or 8
+                   pixels into a single byte can still happen.
+                */
+                pngRow[pamP->depth * col + plane] = tuplerow[col][plane];
+            }
+        }
+    }
+}
+
+
+
+static void
+writeRaster(const struct pam * const pamP,
+            struct pngx *      const pngxP,
+            int                const bitDepth) {
+
+    tuple * tupleRow;
+    png_byte * pngRow;
+    unsigned int row;
+
+    /* We process row-by-row and do not read the complete image into memory */
+
+    tupleRow = pnm_allocpamrow(pamP);
+
+    MALLOCARRAY(pngRow, pamP->width * 8);
+        /* sufficient to store a 16-bit RGB+A row */
+
+    if (pngRow == NULL)
+        pm_error("Unable to allocate space for PNG pixel row for "
+                 "%u columns", pamP->width);
+    else {
+        for (row = 0; row < pamP->height; ++row) {
+            pnm_readpamrow(pamP, tupleRow);
+
+            convertRaster(pamP, tupleRow, pngRow, bitDepth);
+
+            png_write_row(pngxP->png_ptr, pngRow);
+        }
+        free(pngRow);
+    }
+    pnm_freepamrow(tupleRow);
+}
+
+
+
+static void
+writePng(const struct pam * const pamP,
+         FILE *             const ofP,
+         struct CmdlineInfo const cmdline) {
+
+    unsigned int const pnmBitDepth = pm_maxvaltobits(pamP->maxval);
+    int const pngColorType = colorTypeFromInputType(pamP);
+
+    struct pngx * pngxP;
+    unsigned int pngBitDepth;
+    png_color_8 sBit;
+
+    pngx_create(&pngxP, PNGX_WRITE, NULL);
+
+
+
+    if ((pngColorType == PNG_COLOR_TYPE_RGB ||
+         pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) &&
+        pnmBitDepth < 8) {
+
+        pngBitDepth = 8;
+    } else
+        pngBitDepth = pnmBitDepth;
+
+    png_init_io(pngxP->png_ptr, ofP);
+
+    pngx_setIhdr(pngxP, pamP->width, pamP->height,
+                 pngBitDepth, pngColorType,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
+                 PNG_FILTER_TYPE_BASE);
+
+    /* Where requested, add ancillary chunks */
+    if (cmdline.transparencySpec)
+        doTrnsChunk(pamP, pngxP,cmdline.transparency);
+
+    if (cmdline.chromaSpec)
+        doChrmChunk(pngxP, cmdline.chroma);
+
+    if (cmdline.gammaSpec)
+        doGamaChunk(pngxP, cmdline.gamma);
+
+    /* no iccp */
+
+    doSbitChunk(pamP, pngxP);
+
+    if (cmdline.srgbintentSpec)
+        doSrgbChunk(pngxP, cmdline.srgbintent);
+
+    if (cmdline.textSpec)
+        doTextChunk(pngxP, cmdline.text);
+
+    if (cmdline.ztxtSpec)
+        doZtxtChunk(pngxP, cmdline.ztxt);
+
+    if (cmdline.itxtSpec)
+        doItxtChunk(pngxP, cmdline.itxt);
+
+    if (cmdline.backgroundSpec)
+        doBkgdChunk(pamP, pngxP, cmdline.background);
+
+    /* no hist */
+
+    /* no phys */
+
+    /* no splt */
+
+    if (cmdline.timeSpec)
+        doTimeChunk(pngxP, cmdline.time);
+
+    /* Write the ancillary chunks to PNG file */
+    pngx_writeInfo(pngxP);
+
+    if (pngColorType != PNG_COLOR_TYPE_GRAY && pnmBitDepth < 8) {
+        /* Move the 1, 2, 4 bits to most significant bits */
+        pngx_setShift(pngxP, sBit);
+    }
+    if ((pngColorType == PNG_COLOR_TYPE_GRAY) && (pnmBitDepth < 8)) {
+        /* Pack multiple pixels in a byte */
+        pngx_setPacking(pngxP);
+    }
+
+    writeRaster(pamP, pngxP, pnmBitDepth);
+
+    pngx_writeEnd(pngxP);
+    pngx_destroy(pngxP);
+}
+
+
+
+
+static void
+reportInputFormat(const struct pam * const pamP) {
+
+    const char * formatDesc;
+
+    if (pamP->format == PBM_FORMAT || pamP->format == RPBM_FORMAT)
+        formatDesc = "PBM";
+    else if (pamP->format == PGM_FORMAT || pamP->format == RPGM_FORMAT)
+        formatDesc = "PGM";
+    else if (pamP->format == PPM_FORMAT || pamP->format == RPPM_FORMAT)
+        formatDesc = "PPM";
+    else if (pamP->format == PAM_FORMAT)
+        formatDesc = "PAM";
+    else
+        formatDesc = NULL;
+
+    if (formatDesc)
+        pm_message("Input format = %s", formatDesc);
+    else
+        pm_message("Unrecognized input format, format code = 0x%x",
+                   pamP->format);
+
+    pm_message("Input tuple type = '%s'", pamP->tuple_type);
+    pm_message("Input depth = %u", pamP->depth);
+    pm_message("Input maxval = %u", (unsigned int) pamP->maxval);
+}
+
+
+
+int
+main(int           argc,
+     const char ** argv) {
+
+    FILE * ifP;
+    struct CmdlineInfo cmdline;
+    struct pam pam;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (verbose)
+        reportInputFormat(&pam);
+
+    writePng(&pam, stdout, cmdline);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/pamtosvg/pxl-outline.c b/converter/other/pamtosvg/pxl-outline.c
index a1fa5299..456f41e1 100644
--- a/converter/other/pamtosvg/pxl-outline.c
+++ b/converter/other/pamtosvg/pxl-outline.c
@@ -9,7 +9,6 @@
 
 #include "message.h"
 #include "bitmap.h"
-#include "bitmap.h"
 #include "logreport.h"
 #include "pxl-outline.h"
 
diff --git a/converter/other/pngtxt.c b/converter/other/pngtxt.c
index 853edf0a..bca06d73 100644
--- a/converter/other/pngtxt.c
+++ b/converter/other/pngtxt.c
@@ -242,7 +242,7 @@ handleArrayAllocation(png_text **    const arrayP,
 
 void 
 pngtxt_read(struct pngx * const pngxP,
-            FILE *        const tfp, 
+            FILE *        const fileP, 
             bool          const ztxt,
             bool          const verbose) {
 
@@ -266,7 +266,7 @@ pngtxt_read(struct pngx * const pngxP,
    
     eof = FALSE;
     while (!eof) {
-        getFileLine(tfp, &textline, &lineLength);
+        getFileLine(fileP, &textline, &lineLength);
         if (textline == NULL)
             eof = TRUE;
         else {
diff --git a/converter/other/pngx.c b/converter/other/pngx.c
index 8d7b7c70..c9f6c7e9 100644
--- a/converter/other/pngx.c
+++ b/converter/other/pngx.c
@@ -322,6 +322,45 @@ pngx_setChrm(struct pngx *      const pngxP,
 
 
 
+const char *
+pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent) {
+
+    switch (srgbIntent) {
+    case PNGX_PERCEPTUAL:            return "PERCEPTUAL";
+    case PNGX_RELATIVE_COLORIMETRIC: return "RELATIVE COLORIMETRIC";
+    case PNGX_SATURATION:            return "SATURATION";
+    case PNGX_ABSOLUTE_COLORIMETRIC: return "ABSOLUTE_COLORIMETRIC";
+    }
+    assert(false);
+}
+
+
+
+static int
+const libpngSrgbIntentCode(pngx_srgbIntent const srgbIntent) {
+
+    switch (srgbIntent) {
+    case PNGX_PERCEPTUAL:            return 0;
+    case PNGX_RELATIVE_COLORIMETRIC: return 1;
+    case PNGX_SATURATION:            return 2;
+    case PNGX_ABSOLUTE_COLORIMETRIC: return 3;
+    }
+
+    assert(false);  /* All cases above return */
+}
+
+
+
+void
+pngx_setSrgb(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent) {
+
+    png_set_sRGB(pngxP->png_ptr, pngxP->info_ptr,
+                 libpngSrgbIntentCode(srgbIntent));
+}
+
+
+
 void
 pngx_setCompressionSize(struct pngx * const pngxP,
                         unsigned int  const bufferSize) {
@@ -476,13 +515,13 @@ pngx_setText(struct pngx * const pngxP,
 
 void
 pngx_setTime(struct pngx * const pngxP,
-             png_time      const timeArg) {
+             time_t        const timeArg) {
 
-    png_time time;
+    png_time pngTime;
 
-    time = timeArg;
+    png_convert_from_time_t(&pngTime, timeArg);
 
-    png_set_tIME(pngxP->png_ptr, pngxP->info_ptr, &time);
+    png_set_tIME(pngxP->png_ptr, pngxP->info_ptr, &pngTime);
 }
 
 
diff --git a/converter/other/pngx.h b/converter/other/pngx.h
index 10e8204d..1252e32a 100644
--- a/converter/other/pngx.h
+++ b/converter/other/pngx.h
@@ -128,6 +128,20 @@ void
 pngx_setChrm(struct pngx *      const pngxP,
              struct pngx_chroma const chroma);
 
+typedef enum {
+    PNGX_PERCEPTUAL,
+    PNGX_RELATIVE_COLORIMETRIC,
+    PNGX_SATURATION,
+    PNGX_ABSOLUTE_COLORIMETRIC
+} pngx_srgbIntent;
+
+const char *
+pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent);
+
+void
+pngx_setSrgb(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent);
+
 void
 pngx_setCompressionSize(struct pngx * const pngxP,
                         unsigned int  const bufferSize);
@@ -196,7 +210,7 @@ pngx_setText(struct pngx * const pngxP,
 
 void
 pngx_setTime(struct pngx * const pngxP,
-             png_time      const time);
+             time_t        const timeArg);
 
 void
 pngx_setTrnsPalette(struct pngx *    const pngxP,
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index 154ca279..8cf9f92e 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -120,6 +120,8 @@ struct cmdlineInfo {
     struct pngx_chroma rgb;          /* Meaningless if !rgbSpec */
     unsigned int  sizeSpec;
     struct pngx_phys   size;         /* Meaningless if !sizeSpec */
+    unsigned int srgbintentSpec;
+    pngx_srgbIntent srgbintent;
     const char *  text;         /* NULL if none */
     const char *  ztxt;         /* NULL if none */
     unsigned int  modtimeSpec;
@@ -199,6 +201,27 @@ parseRgbOpt(const char *         const rgbOpt,
 
 
 static void
+parseSrgbintentOpt(const char *      const srgbintentOpt,
+                   pngx_srgbIntent * const srgbintentP) {
+    
+    if (streq(srgbintentOpt, "perceptual"))
+        *srgbintentP = PNGX_PERCEPTUAL;
+    else if (streq(srgbintentOpt, "relativecolorimetric"))
+        *srgbintentP = PNGX_RELATIVE_COLORIMETRIC;
+    else if (streq(srgbintentOpt, "saturation"))
+        *srgbintentP = PNGX_SATURATION;
+    else if (streq(srgbintentOpt, "absolutecolorimetric"))
+        *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC;
+    else
+        pm_error("Unrecognized sRGB intent value '%s'.  We understand "
+                 "only 'perceptual', 'relativecolorimetric', "
+                 "'saturation', and 'absolutecolorimetric'",
+                 srgbintentOpt);
+}
+
+
+
+static void
 parseModtimeOpt(const char * const modtimeOpt,
                 time_t *     const modtimeP) {
 
@@ -292,6 +315,7 @@ parseCommandLine(int argc, const char ** argv,
     const char * modtime;
     const char * compMethod;
     const char * compStrategy;
+    const char * srgbintent;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -306,6 +330,8 @@ parseCommandLine(int argc, const char ** argv,
             &cmdlineP->rgbSpec,    0);
     OPTENT3(0, "size",             OPT_STRING,    &size,
             &cmdlineP->sizeSpec,   0);
+    OPTENT3(0,  "srgbintent",      OPT_STRING,    &srgbintent,
+            &cmdlineP->srgbintentSpec, 0);
     OPTENT3(0, "text",             OPT_STRING,    &cmdlineP->text,
             &textSpec,             0);
     OPTENT3(0, "ztxt",             OPT_STRING,    &cmdlineP->ztxt,
@@ -433,6 +459,9 @@ parseCommandLine(int argc, const char ** argv,
     if (cmdlineP->rgbSpec)
         parseRgbOpt(rgb, &cmdlineP->rgb);
     
+    if (cmdlineP->srgbintentSpec)
+        parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent);
+
     if (cmdlineP->modtimeSpec)
         parseModtimeOpt(modtime, &cmdlineP->modtime);
 
@@ -2460,11 +2489,8 @@ static void
 doTimeChunk(struct cmdlineInfo const cmdline,
             struct pngx *      const pngxP) {
 
-    if (cmdline.modtimeSpec) {
-        png_time pngTime;
-        png_convert_from_time_t(&pngTime, cmdline.modtime);
-        pngx_setTime(pngxP, pngTime);
-    }
+    if (cmdline.modtimeSpec)
+        pngx_setTime(pngxP, cmdline.modtime);
 }
 
 
@@ -2604,6 +2630,20 @@ doSbitChunk(struct pngx * const pngxP,
 
 
 
+static void
+addSrgbChunk(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent) {
+
+    pngx_setSrgb(pngxP, srgbIntent);
+
+    if (verbose) {
+        pm_message("writing sRGB chunk with intent value %s",
+                   pngx_srgbIntentDesc(srgbIntent));
+    }
+}
+
+
+
 static void 
 convertpnm(struct cmdlineInfo const cmdline,
            FILE *             const ifP,
@@ -2813,6 +2853,9 @@ convertpnm(struct cmdlineInfo const cmdline,
 
     doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval);
 
+    if (cmdline.srgbintentSpec)
+        addSrgbChunk(pngxP, cmdline.srgbintent);
+
     /* tEXT and zTXT chunks */
     if (cmdline.text || cmdline.ztxt)
         pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose);
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index cf6b2873..6cd6be95 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -1853,18 +1853,14 @@ convertRowPbm(struct pam *     const pamP,
 ----------------------------------------------------------------------*/
     unsigned int colChar;
     unsigned int const colChars = pbm_packed_bytes(pamP->width);
-    unsigned int const padRight = (8 - pamP->width %8) %8;
 
     pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format);
 
     for (colChar = 0; colChar < colChars; ++colChar)
         bitrow[colChar] =  ~ bitrow[colChar];
 
-    if (padRight > 0) {
-        bitrow[colChars-1] >>= padRight;  /* Zero clear padding beyond */
-        bitrow[colChars-1] <<= padRight;  /* right edge */
-    }
-
+    /* Zero clear padding beyond right edge */
+    pbm_cleanrowend_packed(bitrow, pamP->width);
     writeFile(bitrow, colChars, "PBM reader", fP);
 }
 
diff --git a/converter/other/pnmtoxwd.c b/converter/other/pnmtoxwd.c
index 8a001390..eda2ee8f 100644
--- a/converter/other/pnmtoxwd.c
+++ b/converter/other/pnmtoxwd.c
@@ -20,11 +20,11 @@
 #include "x11wd.h"
 
 
-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 *inputFilespec;  /* Filespecs of input file */
+    const char * inputFilename;  /* Filename of input file */
     unsigned int pseudodepth;
     unsigned int directcolor;
 };
@@ -34,7 +34,7 @@ struct cmdlineInfo {
 static void 
 parseCommandLine(int argc, 
                  char ** argv, 
-                 struct cmdlineInfo  * const cmdlineP) {
+                 struct CmdlineInfo  * const cmdlineP) {
 /* --------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -78,12 +78,12 @@ parseCommandLine(int argc,
     }
 
     if (argc-1 == 0) 
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFilename = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFilename = argv[1];
 }
 
 
@@ -410,7 +410,7 @@ writeRaster(FILE *           const ofP,
 int
 main(int argc, char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE* ifP;
     xel ** xels;
     int rows, cols, format, colors;
@@ -426,7 +426,7 @@ main(int argc, char * argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFilename);
 
     xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
     xmaxval = (1 << cmdline.pseudodepth) - 1;
@@ -473,13 +473,13 @@ main(int argc, char * argv[]) {
         }
     }
 
-    if (streq(cmdline.inputFilespec, "-"))
+    if (streq(cmdline.inputFilename, "-"))
         dumpname = "stdin";
     else {
-        if (strlen(cmdline.inputFilespec) > XWDVAL_MAX - sizeof(h11) - 1)
+        if (strlen(cmdline.inputFilename) > XWDVAL_MAX - sizeof(h11) - 1)
             pm_error("Input file name is ridiculously long.");
         else
-            dumpname = cmdline.inputFilespec;
+            dumpname = cmdline.inputFilename;
     }
 
     setupX11Header(&h11, dumpname, cols, rows, format, 
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c
index 008d5376..6fd4efcf 100644
--- a/converter/other/sgitopnm.c
+++ b/converter/other/sgitopnm.c
@@ -28,6 +28,7 @@
 #include "pnm.h"
 #include "sgi.h"
 
+#define MAX_ZSIZE 256
 
 
 struct CmdlineInfo {
@@ -82,6 +83,10 @@ parseCommandLine(int argc, const char ** argv,
 
     free(option_def);
 
+    if (!cmdlineP->channelSpec)
+        cmdlineP->channel = MAX_ZSIZE + 1;
+            /* Invalid value; to suppress Valgrind error */
+
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
@@ -212,7 +217,7 @@ readHeader(FILE *       const ifP,
     headP->xsize     = getBigShort(ifP);
     headP->ysize     = getBigShort(ifP);
     headP->zsize     = getBigShort(ifP);
-    if (headP->zsize > 256)
+    if (headP->zsize > MAX_ZSIZE)
         pm_error("Too many channels in input image: %u",
                  (unsigned int) headP->zsize );
     headP->pixmin    = getBigLong(ifP);
diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c
index 62664999..807e4f4a 100644
--- a/converter/pbm/atktopbm.c
+++ b/converter/pbm/atktopbm.c
@@ -61,17 +61,24 @@
 */
 
 /* macros to generate case entries for switch statement */
-#define case1(v) case v
-#define case4(v) case v: case (v)+1: case (v)+2: case(v)+3
-#define case6(v) case4(v): case ((v)+4): case ((v)+5)
-#define case8(v) case4(v): case4((v)+4)
+#define CASE1(v) case v
+#define CASE4(v) case v: case (v)+1: case (v)+2: case(v)+3
+#define CASE6(v) CASE4(v): case ((v)+4): case ((v)+5)
+#define CASE8(v) CASE4(v): CASE4((v)+4)
+
+
 
 static long
-ReadRow(FILE * const file, unsigned char * const row, long const length) {
+ReadRow(FILE *          const file,
+        unsigned char * const row,
+        long            const length) {
 /*----------------------------------------------------------------------------
   'file' is where to get them from.
   'row' is where to put bytes.
   'length' is how many bytes in row must be filled.
+  
+  Return the delimiter that marks the end of the row, or EOF if EOF marks
+  the end of the row, or NUL in some cases.
 -----------------------------------------------------------------------------*/
     /* Each input character is processed by the central loop.  There are 
     ** some input codes which require two or three characters for
@@ -80,18 +87,23 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) {
     ** to the Ready state whenever a character unacceptable to the
     ** current state is read.
     */
-    enum stateCode {
-        Ready,      /* any input code is allowed */
-        HexDigitPending,    /* have seen the first of a hex digit pair */
-        RepeatPending,  /* repeat code has been seen:
-                   must be followed by two hex digits */
-        RepeatAndDigit};    /* have seen repeat code and its first
-                   following digit */
-    enum stateCode InputState;  /* current state */
-    register int c;     /* the current input character */
-    register long repeatcount = 0;  /* current repeat value */
-    register long hexval;   /* current hex value */
-    long pendinghex = 0;    /* the first of a pair of hex characters */
+    enum StateCode {
+        Ready,
+            /* any input code is allowed */
+        HexDigitPending,
+            /* have seen the first of a hex digit pair */
+        RepeatPending,
+            /* repeat code has been seen: must be followed by two hex digits
+             */
+        RepeatAndDigit
+            /* have seen repeat code and its first following digit */
+    };
+    
+    enum StateCode InputState;  /* current state */
+    int c;     /* the current input character */
+    long repeatcount;  /* current repeat value */
+    long hexval;   /* current hex value */
+    long pendinghex;    /* the first of a pair of hex characters */
     int lengthRemaining;
     unsigned char * cursor;
     
@@ -101,262 +113,239 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) {
     ** zero, we ungetc the byte.
     */
 
-    lengthRemaining = length;
-    cursor = row;
+    repeatcount = 0;  /* initial value */
+    pendinghex = 0;  /* initial value */
+
+    lengthRemaining = length;  /* initial value */
+    cursor = row;  /* initial value */
+    InputState = Ready;  /* initial value */
 
-    InputState = Ready;
     while ((c=getc(file)) != EOF) switch (c) {
 
-    case8(0x0):
-    case8(0x8):
-    case8(0x10):
-    case8(0x18):
-    case1(' '):
-        /* control characters and space are legal and ignored */
-        break;
-    case1(0x40):    /* '@' */
-    case1(0x5B):    /* '[' */
-    case4(0x5D):    /*  ']'  '^'  '_'  '`' */
-    case4(0x7D):    /* '}'  '~'  DEL  0x80 */
-    default:        /* all above 0x80 */
-        /* error code:  Ignored at present.  Reset InputState. */
-        InputState = Ready;
-        break;
-
-    case1(0x7B):    /* '{' */
-    case1(0x5C):    /* '\\' */
-        /* illegal end of line:  exit anyway */
-        ungetc(c, file);    /* retain terminator in stream */
-        /* DROP THROUGH */
-    case1(0x7C):    /* '|' */
-        /* legal end of row: may have to pad  */
-        while (lengthRemaining-- > 0)
-            *cursor++ = WHITEBYTE;
-        return c;
+        CASE8(0x0):
+        CASE8(0x8):
+        CASE8(0x10):
+        CASE8(0x18):
+        CASE1(' '):
+            /* control characters and space are legal and ignored */
+            break;
+        CASE1(0x40):    /* '@' */
+        CASE1(0x5B):    /* '[' */
+        CASE4(0x5D):    /*  ']'  '^'  '_'  '`' */
+        CASE4(0x7D):    /* '}'  '~'  DEL  0x80 */
+        default:        /* all above 0x80 */
+            /* error code:  Ignored at present.  Reset InputState. */
+            InputState = Ready;
+            break;
+
+        CASE1(0x7B):    /* '{' */
+        CASE1(0x5C):    /* '\\' */
+            /* illegal end of line:  exit anyway */
+            ungetc(c, file);    /* retain terminator in stream */
+            /* DROP THROUGH */
+        CASE1(0x7C):    /* '|' */
+            /* legal end of row: may have to pad  */
+            while (lengthRemaining-- > 0)
+                *cursor++ = WHITEBYTE;
+            return c;
     
-    case1(0x21):
-    case6(0x22):
-    case8(0x28):
-        /* punctuation characters: repeat byte given by two
-        ** succeeding hex chars
-        */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - OTHERZERO;
-        InputState = RepeatPending;
-        break;
-
-    case8(0x30):
-    case8(0x38):
-        /* digit (or following punctuation)  -  hex digit */
-        hexval = c - 0x30;
-        goto hexdigit;
-    case6(0x41):
-        /* A ... F    -  hex digit */
-        hexval = c - (0x41 - 0xA);
-        goto hexdigit;
-    case6(0x61):
-        /* a ... f  - hex digit */
-        hexval = c - (0x61 - 0xA);
-        goto hexdigit;
-
-    case8(0x67):
-    case8(0x6F):
-    case4(0x77):
-        /* g ... z   -   multiple WHITE bytes */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - WHITEZERO;
-        hexval = WHITEBYTE;
-        goto store;
-    case8(0x47):
-    case8(0x4F):
-    case4(0x57):
-        /* G ... Z   -   multiple BLACK bytes */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - BLACKZERO;
-        hexval = BLACKBYTE;
-        goto store;
-
-hexdigit:
-        /* process a hex digit.  Use InputState to determine
-            what to do with it. */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        switch(InputState) {
-        case Ready:
-            InputState = HexDigitPending;
-            pendinghex = hexval << 4;
+        CASE1(0x21):
+        CASE6(0x22):
+        CASE8(0x28):
+            /* punctuation characters: repeat byte given by two
+            ** succeeding hex chars
+            */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - OTHERZERO;
+            InputState = RepeatPending;
             break;
-        case HexDigitPending:
-            hexval |= pendinghex;
-            repeatcount = 1;
+
+        CASE8(0x30):
+        CASE8(0x38):
+            /* digit (or following punctuation)  -  hex digit */
+            hexval = c - 0x30;
+            goto hexdigit;
+        CASE6(0x41):
+            /* A ... F    -  hex digit */
+            hexval = c - (0x41 - 0xA);
+            goto hexdigit;
+        CASE6(0x61):
+            /* a ... f  - hex digit */
+            hexval = c - (0x61 - 0xA);
+            goto hexdigit;
+
+        CASE8(0x67):
+        CASE8(0x6F):
+        CASE4(0x77):
+            /* g ... z   -   multiple WHITE bytes */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - WHITEZERO;
+            hexval = WHITEBYTE;
             goto store;
-        case RepeatPending:
-            InputState = RepeatAndDigit;
-            pendinghex = hexval << 4;
-            break;
-        case RepeatAndDigit:
-            hexval |= pendinghex;
+        CASE8(0x47):
+        CASE8(0x4F):
+        CASE4(0x57):
+            /* G ... Z   -   multiple BLACK bytes */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - BLACKZERO;
+            hexval = BLACKBYTE;
             goto store;
-        }
-        break;
-
-store:
-        /* generate byte(s) into the output row 
-            Use repeatcount, depending on state.  */
-        if (lengthRemaining < repeatcount) 
-            /* reduce repeat count if it would exceed
-                available space */
-            repeatcount = lengthRemaining;
-        lengthRemaining -= repeatcount;  /* do this before repeatcount-- */
-        while (repeatcount-- > 0)
+
+        hexdigit:
+            /* process a hex digit.  Use InputState to determine
+               what to do with it. */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            switch(InputState) {
+            case Ready:
+                InputState = HexDigitPending;
+                pendinghex = hexval << 4;
+                break;
+            case HexDigitPending:
+                hexval |= pendinghex;
+                repeatcount = 1;
+                goto store;
+            case RepeatPending:
+                InputState = RepeatAndDigit;
+                pendinghex = hexval << 4;
+                break;
+            case RepeatAndDigit:
+                hexval |= pendinghex;
+                goto store;
+            }
+            break;
+
+        store:
+            /* generate byte(s) into the output row 
+               Use repeatcount, depending on state.  */
+            if (lengthRemaining < repeatcount) 
+                /* reduce repeat count if it would exceed
+                   available space */
+                repeatcount = lengthRemaining;
+            lengthRemaining -= repeatcount;  /* do this before repeatcount-- */
+            while (repeatcount-- > 0)
                 *cursor++ = hexval;
-        InputState = Ready;
-        break;
+            InputState = Ready;
+            break;
 
-    } /* end of while( - )switch( - ) */
+        } /* end of while( - )switch( - ) */
     return EOF;
 }
 
 
 
-#undef case1
-#undef case4
-#undef case6
-#undef case8
+#undef CASE1
+#undef CASE4
+#undef CASE6
+#undef CASE8
 
 
 
 static void
-ReadATKRaster(FILE * const file, 
-              int * const rwidth, 
-              int * const rheight, 
-              unsigned char ** const destaddrP) {
+ReadATKRaster(FILE * const ifP) {
 
-    int row, rowlen;  /* count rows;  byte length of row */
+    int row;  /* count rows;  byte length of row */
     int version;
     char keyword[6];
     int discardid;
     int objectid;     /* id read for the incoming pixel image */
     long tc;            /* temp */
     int width, height;      /* dimensions of image */
+    bit * bitrow;
 
-    if (fscanf(file, "\\begindata{raster,%d", &discardid) != 1
-                || getc(file) != '}' || getc(file) != '\n')
-      pm_error ("input file not Andrew raster object");
+    if (fscanf(ifP, "\\begindata{raster,%d", &discardid) != 1
+        || getc(ifP) != '}' || getc(ifP) != '\n')
+        pm_error ("input file not Andrew raster object");
 
-    fscanf(file, " %d ", &version);
+    fscanf(ifP, " %d ", &version);
     if (version < 2) 
-      pm_error ("version too old to parse");
+        pm_error ("version too old to parse");
 
     {
         unsigned int options;
         long xscale, yscale;
         long xoffset, yoffset, subwidth, subheight;
         /* ignore all these features: */
-        fscanf(file, " %u %ld %ld %ld %ld %ld %ld",  
+        fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld",  
                &options, &xscale, &yscale, &xoffset, 
                &yoffset, &subwidth, &subheight);
     }
     /* scan to end of line in case this is actually something beyond V2 */
-    while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {}
+    while (((tc=getc(ifP)) != '\n') && (tc != '\\') && (tc != EOF)) {}
 
     /* read the keyword */
-    fscanf(file, " %5s", keyword);
+    fscanf(ifP, " %5s", keyword);
     if (!streq(keyword, "bits"))
-      pm_error ("keyword is not 'bits'!");
+        pm_error ("keyword is not 'bits'!");
 
-    fscanf(file, " %d %d %d ", &objectid, &width, &height);
+    fscanf(ifP, " %d %d %d ", &objectid, &width, &height);
 
     if (width < 1 || height < 1 || width > 1000000 || height > 1000000) 
-      pm_error ("bad width or height");
-
-    *rwidth = width;
-    *rheight = height;
-    rowlen = (width + 7) / 8;
-    MALLOCARRAY(*destaddrP, height * rowlen);
-    if (destaddrP == NULL)
-        pm_error("Unable to allocate %u bytes for the input image.",
-                 height * rowlen);
-    for (row = 0;   row < height;   row++)
-      {
-        long c;
-
-        c = ReadRow(file, *destaddrP + (row * rowlen), rowlen);
-        if (c != '|')
-          {
-        if (c == EOF)
-          pm_error ("premature EOF");
-        else
-          pm_error ("bad format");
-        break;
-          }
-      }
-    while (! feof(file) && getc(file) != '\\') {};  /* scan for \enddata */
-    if (fscanf(file, "enddata{raster,%d", &discardid) != 1
-        || getc(file) != '}' || getc(file) != '\n')
-      pm_error ("missing end-of-object marker");
-}
+        pm_error("bad width or height");
 
+    pbm_writepbminit(stdout, width, height, 0);
+    bitrow = pbm_allocrow_packed(width);
 
+    for (row = 0;   row < height; ++row) {
+        unsigned int const rowlen = (width + 7) / 8;
+        long const nextChar = ReadRow(ifP, bitrow, rowlen);
 
-int
-main(int argc, char **argv) {
+        switch (nextChar) {
+        case '|': 
+            pbm_writepbmrow_packed(stdout, bitrow, width, 0);
+            break;
+        case EOF:
+            pm_error("premature EOF");
+            break;
+        default:
+            pm_error("bad format");
+        }
+    }
 
-    FILE *ifp;
-    register bit *bitrow, *bP;
-    int rows, cols, row, col, charcount;
-    unsigned char *data, mask;
+    pbm_freerow_packed(bitrow);
 
+    while (! feof(ifP) && getc(ifP) != '\\') {};  /* scan for \enddata */
 
-    pbm_init ( &argc, argv );
+    if (fscanf(ifP, "enddata{raster,%d", &discardid) != 1
+        || getc(ifP) != '}' || getc(ifP) != '\n')
+        pm_error("missing end-of-object marker");
+}
 
-    if ( argc > 2 )
-        pm_usage( "[raster obj]" );
-    
-    if ( argc == 2 )
-        ifp = pm_openr( argv[1] );
-    else
-        ifp = stdin;
 
-    ReadATKRaster( ifp, &cols, &rows, &data );
 
-    pm_close( ifp );
+int
+main(int argc, const char ** argv) {
 
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
+    FILE * ifP;
 
-    for ( row = 0; row < rows; ++row )
-    {
-        charcount = 0;
-        mask = 0x80;
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-        {
-            if ( charcount >= 8 )
-            {
-                ++data;
-                charcount = 0;
-                mask = 0x80;
-            }
-            *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
-            ++charcount;
-            mask >>= 1;
-        }
-        ++data;
-        pbm_writepbmrow( stdout, bitrow, cols, 0 );
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else {
+        ifP = pm_openr(argv[1]);
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument is "
+                     "the input file name");
     }
 
-    pm_close( stdout );
-    exit( 0 );
-}
+    ReadATKRaster(ifP);
+
+    pm_close(ifP);
 
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c
index c50fe8a1..ebd817be 100644
--- a/converter/pbm/brushtopbm.c
+++ b/converter/pbm/brushtopbm.c
@@ -93,11 +93,7 @@ main(int argc, const char ** argv)  {
             bitrow[i] = ~bitrow[i];
 
         /* Clean off remainder of fractional last character */
-        if (cols % 8 > 0) {
-            unsigned int const colChars = pbm_packed_bytes(cols);
-            bitrow[colChars-1] >>= 8 - cols % 8;
-            bitrow[colChars-1] <<= 8 - cols % 8;
-        }
+        pbm_cleanrowend_packed(bitrow, cols);
 
         pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
diff --git a/converter/pbm/macp.h b/converter/pbm/macp.h
index 26a720a2..d00dc5c9 100644
--- a/converter/pbm/macp.h
+++ b/converter/pbm/macp.h
@@ -1,12 +1,16 @@
-/* macp.h - header file for MacPaint files
-*/
-
+/*=============================================================================
+                               macp.h
+===============================================================================
+  Information about MacPaint files
+=============================================================================*/
 #ifndef MACP_H_INCLUDED
 #define MACP_H_INCLUDED
 
-#define	HEADER_LENGTH	512
-#define	MAX_LINES	720
-#define	BYTES_WIDE	72
-#define MAX_COLS	576	/* = BYTES_WIDE * 8 */
+#define	MACBIN_HEAD_LEN	128
+#define	MACP_HEAD_LEN	512
+#define	MACP_ROWS	720
+#define	MACP_COLCHARS	72
+#define MACP_COLS	((MACP_COLCHARS) * 8)
+#define MACP_BYTES	((MACP_COLCHARS) * (MACP_ROWS))
 
 #endif
diff --git a/converter/pbm/macptopbm.c b/converter/pbm/macptopbm.c
index f4a341d3..db628b6c 100644
--- a/converter/pbm/macptopbm.c
+++ b/converter/pbm/macptopbm.c
@@ -1,6 +1,8 @@
 /* macptopbm.c - read a MacPaint file and produce a portable bitmap
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
+** Some code of ReadMacPaintFile() is based on the work of
+** Patrick J. Naughton.  (C) 1987, All Rights Reserved.
 **
 ** Permission to use, copy, modify, and distribute this software and its
 ** documentation for any purpose and without fee is hereby granted, provided
@@ -8,133 +10,347 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
+
+
+** Apr 2015 afu
+** Changed code style (ANSI-style function definitions, etc.)
+** Added automatic detection of MacBinary header.
+** Added diagnostics for corruptions.
+** Replaced byte-wise operations with bit-wise ones.
 */
 
 #include "pbm.h"
+#include "pm_c_util.h"
 #include "macp.h"
 
-static void ReadMacPaintFile ARGS(( FILE* file, int extraskip, int* scanLineP, unsigned char Pic[MAX_LINES][BYTES_WIDE] ));
 
-static unsigned char Pic[MAX_LINES][BYTES_WIDE];
+
+static bool
+validateMacPaintVersion( const unsigned char * const rBuff,
+                         const int offset ) {
+/*---------------------------------------------------------------------------
+  Macpaint (or PNTG) files have two headers.
+  The 512 byte MacPaint header is mandatory.
+  The newer 128 byte MacBinary header is optional.  If it exists, it comes
+  before the MacPaint header.
+
+  Here we examine the first four bytes of the MacPaint header to get
+  the version number.
+
+  Valid version numbers are 0, 2, 3.
+  We also allow 1.
+-----------------------------------------------------------------------------*/
+
+    bool retval;
+    const unsigned char * const vNum = rBuff + offset;
+
+   if ( ( ( vNum[0] | vNum[1] | vNum[2] ) != 0x00 ) || vNum[3] > 3 )
+        retval = FALSE;
+    else
+        retval = TRUE;
+
+    pm_message("MacPaint version (at offset %u): %02x %02x %02x %02x (%s)",
+               offset, vNum[0], vNum[1], vNum[2], vNum[3],
+               retval == TRUE ? "valid" : "not valid" );
+
+    return( retval );
+}
+
+
+
+static bool
+scanMacBinaryHeader( const unsigned char * rBuff ) {
+/*----------------------------------------------------------------------------
+  We check byte 0 and 1, and then the MacPaint header version assuming it
+  starts at offset 128.
+
+  Byte 0: must be 0x00.
+  Byte 1: (filename length) must be 1-63.
+
+  Other fields that may be of interest:
+
+  Bytes 2 through 63: (Internal Filename)
+    See Apple Charmap for valid characters.
+    Unlike US-Ascii, 8-bit characters (range 0x80 - 0xFF) are valid.
+    0x00-0x1F and 0x7F are control characters.  0x00 appears in some files.
+    Colon ':' (0x3a) should be avoided in Mac environments but in practice
+    does appear.
+
+  Bytes 65 through 68: (File Type)
+    Four Ascii characters.  Should be "PNTG".
+
+  Bytes 82 to 85: (SizeOfDataFork)
+    uint32 value.  It seems this is file size (in bytes) / 256 + N, N <= 4.
+
+  Bytes 100 through 124:
+    Should be all zero if the header is MacBinary I.
+    Defined and used in MacBinary II.
+
+  Bytes 124,125: CRC
+    (MacBinary II only) CRC value of bytes 0 through 123.
+
+  All multi-byte values are big-endian.
+
+  Reference:
+  http://www.fileformat.info/format/macpaint/egff.htm
+  Fully describes the fields.  However, the detection method described
+  does not work very well.
+
+  Also see:
+  http://fileformats.archiveteam.org/wiki/MacPaint
+-----------------------------------------------------------------------------*/
+    bool          foundMacBinaryHeader;
+
+    /* Examine byte 0.  It should be 0x00.  Note that the first
+       byte of a valid MacPaint header should also be 0x00.
+    */
+    if ( rBuff[0] != 0x00 ) {
+        foundMacBinaryHeader = FALSE;
+    }
+
+    /* Examine byte 1, the length of the filename.
+       It should be in the range 1 - 63.
+    */
+    else if( rBuff[1] == 0 || rBuff[1] > 63 ) {
+        foundMacBinaryHeader = FALSE;
+    }
+
+    /* Check the MacPaint header version starting at offset 128. */
+    else if ( validateMacPaintVersion ( rBuff, MACBIN_HEAD_LEN ) == FALSE) {
+        foundMacBinaryHeader = FALSE;
+    }
+    else
+        foundMacBinaryHeader = TRUE;
+
+    if( foundMacBinaryHeader == TRUE)
+      pm_message("Input file contains a MacBinary header "
+                   "followed by a MacPaint header.");
+    else
+      pm_message("Input file does not start with a MacBinary header.");
+
+    return ( foundMacBinaryHeader );
+}
+
+
+
+
+static void
+skipHeader( FILE * const ifP ) {
+/*--------------------------------------------------------------------------
+  Determine whether the MacBinary header exists.
+  If it does, read off the initial 640 (=128 + 512) bytes of the file.
+  If it doesn't, read off 512 bytes.
+
+  In the latter case we check the MacHeader version number, but just issue
+  a warning if the value is invalid.  This is for backward comaptibility.
+---------------------------------------------------------------------------*/
+    unsigned int re;
+    const unsigned int buffsize = MAX( MACBIN_HEAD_LEN, MACP_HEAD_LEN );
+    unsigned char * const rBuff = malloc(buffsize);
+
+    if( rBuff == NULL )
+        pm_error("Out of memory.");
+
+    /* Read 512 bytes.
+       See if MacBinary header exists in the first 128 bytes and
+       the next 4 bytes signal the start of a MacPaint header. */
+    re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP);
+        if (re < 1)
+        pm_error("EOF/error while reading header.");
+
+    if ( scanMacBinaryHeader( rBuff ) == TRUE ) {
+    /* MacBinary header found.  Read another 128 bytes to complete the
+       MacPaint header, but don't conduct any further analysis. */
+        re = fread ( rBuff, MACBIN_HEAD_LEN, 1, ifP);
+            if (re < 1)
+            pm_error("EOF/error while reading MacPaint header.");
+
+    } else {
+    /* MacBinary header not found.  We assume file starts with
+       MacPaint header.   Check MacPaint version but dismiss error. */
+        if (validateMacPaintVersion( rBuff, 0 ) == TRUE)
+          pm_message("Input file starts with valid MacPaint header.");
+        else
+          pm_message("  - Ignoring invalid version number.");
+    }
+    free( rBuff );
+}
+
+
+
+static void
+skipExtraBytes( FILE * const ifP,
+                int    const extraskip) {
+/*--------------------------------------------------------------------------
+  This function exists for backward compatibility.  Its purpose is to
+  manually delete the MacBinary header.
+
+  We check the MacHeader version number, but just issue a warning if the
+  value is invalid.
+---------------------------------------------------------------------------*/
+    unsigned int re;
+    unsigned char * const rBuff = malloc(MAX (extraskip, MACP_HEAD_LEN));
+
+    if( rBuff == NULL )
+        pm_error("Out of memory.");
+
+    re = fread ( rBuff, 1, extraskip, ifP);
+        if (re < extraskip)
+        pm_error("EOF/error while reading off initial %u bytes"
+                     "specified by -extraskip.", extraskip);
+    re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP);
+        if (re < 1)
+        pm_error("EOF/error while reading MacPaint header.");
+
+    /* Check the MacPaint version number.  Dismiss error. */
+    if (validateMacPaintVersion( rBuff, 0 ) == TRUE)
+        pm_message("Input file starts with valid MacPaint header.");
+    else
+        pm_message("  - Ignoring invalid version number.");
+
+    free( rBuff );
+}
+
+
+
+static unsigned char
+readChar( FILE * const ifP ) {
+
+    int const ch = getc( ifP );
+
+    if (ch ==EOF)
+        pm_error("EOF encountered while unpacking image data.");
+
+    /* else */
+        return ((unsigned char) ch);
+}
+
+
+
+
+static void
+ReadMacPaintFile( FILE *  const ifP,
+                  int  * outOfSyncP,
+                  int  * pixelCntP ) {
+/*---------------------------------------------------------------------------
+  Unpack image data.  Compression method is called "Packbits".
+  This run-length encoding scheme has also been adopted by
+  Postscript and TIFF.  See source: converter/other/pnmtops.c
+
+  Unpacked raster array is raw PBM.  No conversion is required.
+
+  One source says flag byte should not be 0xFF (255), but we don't reject
+  the value, for in practice, it is widely used.
+
+  Sequences should never cross row borders.
+  Violations of this rule are recorded in outOfSync.
+
+  Note that pixelCnt counts bytes, not bits, so it is the number of pixels
+  multiplied by 8.  This counter exists to detect corruptions.
+---------------------------------------------------------------------------*/
+    int           pixelCnt   = 0;   /* Initial value */
+    int           outOfSync  = 0;   /* Initial value */
+    unsigned int  flag;             /* Read from input */
+    unsigned int  i;
+    unsigned char * const bitrow = pbm_allocrow_packed(MACP_COLS);
+
+    while ( pixelCnt < MACP_BYTES ) {
+        flag = (unsigned int) readChar( ifP );    /* Flag (count) byte */
+        if ( flag < 0x80 ) {
+            /* Unpack next (flag + 1) chars as is */
+            for ( i = 0; i <= flag; i++ )
+                if( pixelCnt < MACP_BYTES) {
+                  int const colChar = pixelCnt % MACP_COLCHARS;
+                  pixelCnt++;
+                  bitrow[colChar] = readChar( ifP );
+                  if (colChar == MACP_COLCHARS-1)
+                      pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 );
+                  if (colChar == 0 && i > 0 )
+                      outOfSync++;
+                }
+        }
+        else {
+          /* Repeat next char (2's complement of flagCnt) times */
+            unsigned int  const flagCnt = 256 - flag;
+            unsigned char const ch = readChar( ifP );
+            for ( i = 0; i <= flagCnt; i++ )
+                if( pixelCnt < MACP_BYTES) {
+                  int const colChar = pixelCnt % MACP_COLCHARS;
+                  pixelCnt++;
+                  bitrow[colChar] = ch;
+                  if (colChar == MACP_COLCHARS-1)
+                      pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 );
+                  if (colChar == 0 && i > 0 )
+                      outOfSync++;
+                }
+        }
+    }
+    pbm_freerow_packed ( bitrow );
+    *outOfSyncP  = outOfSync;
+    *pixelCntP   = pixelCnt;
+}
+
 
 int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    int argn, extraskip, scanLine, rows, cols, row, bcol, i;
-    const char* usage = "[-extraskip N] [macpfile]";
+main( int argc, char * argv[])  {
 
+    FILE * ifp;
+    int argn, extraskip;
+    const char * const usage = "[-extraskip N] [macpfile]";
+    int outOfSync;
+    int pixelCnt;
 
     pbm_init( &argc, argv );
 
-    argn = 1;
-    extraskip = 0;
+    argn = 1;      /* initial value */
+    extraskip = 0; /* initial value */
 
     /* Check for flags. */
-    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-extraskip", 2 ) )
-	    {
-	    argn++;
-	    if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 )
-		pm_usage( usage );
-	    }
-	else
-	    pm_usage( usage );
-	argn++;
-	}
-
-    if ( argn < argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	argn++;
-	}
+    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
+        if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) {
+            argn++;
+            if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 )
+                pm_usage( usage );
+        }
+        else
+            pm_usage( usage );
+        argn++;
+    }
+
+    if ( argn < argc ) {
+        ifp = pm_openr( argv[argn] );
+        argn++;
+        }
     else
-	ifp = stdin;
+        ifp = stdin;
 
     if ( argn != argc )
-	pm_usage( usage );
+        pm_usage( usage );
 
-    ReadMacPaintFile( ifp, extraskip, &scanLine, Pic );
+    if ( extraskip > 256 * 1024 )
+        pm_error("-extraskip value too large");
+    else if ( extraskip > 0 )
+        skipExtraBytes( ifp, extraskip);
+    else
+        skipHeader( ifp );
 
+    pbm_writepbminit( stdout, MACP_COLS, MACP_ROWS, 0 );
+
+    ReadMacPaintFile( ifp, &outOfSync, &pixelCnt );
+    /* We may not be at EOF.
+       Macpaint files often have extra bytes after image data. */
     pm_close( ifp );
 
-    cols = BYTES_WIDE * 8;
-    rows = scanLine;
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
+    if ( pixelCnt == 0 )
+        pm_error("No image data.");
+
+    else if ( pixelCnt < MACP_BYTES )
+        pm_error("Compressed image data terminated prematurely.");
 
-    for ( row = 0; row < rows; row++ )
-	{
-	for ( bcol = 0; bcol < BYTES_WIDE; bcol++ )
-	    for ( i = 0; i < 8; i++ )
-		bitrow[bcol * 8 + i] =
-		    ( (Pic[row][bcol] >> (7 - i)) & 1 ) ? PBM_BLACK : PBM_WHITE;
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
+    else if ( outOfSync > 0 )
+        pm_message("Warning: Corrupt image data.  %d rows misaligned.",
+                   outOfSync);
 
     pm_close( stdout );
     exit( 0 );
-    }
-
-/*
-** Some of the following routine is:
-**
-**                Copyright 1987 by Patrick J. Naughton
-**                         All Rights Reserved
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted,
-** provided that the above copyright notice appear in all copies and that
-** both that copyright notice and this permission notice appear in
-** supporting documentation.
-*/
-
-static void
-ReadMacPaintFile( file, extraskip, scanLineP, Pic )
-    FILE* file;
-    int extraskip;
-    int* scanLineP;
-    unsigned char Pic[MAX_LINES][BYTES_WIDE];
-    {
-    unsigned int i, j, k;
-    unsigned char ch;
-
-    /* Skip over the header. */
-    for ( i = 0; i < extraskip; i++ )
-	getc( file );
-    for ( i = 0; i < HEADER_LENGTH; i++ )
-	getc( file );
-
-    *scanLineP = 0;
-    k = 0;
-
-    while ( *scanLineP < MAX_LINES )
-	{
-	ch = (unsigned char) getc( file );	/* Count byte */
-	i = (unsigned int) ch;
-	if ( ch < 0x80 )
-	    {	/* Unpack next (I+1) chars as is */
-	    for ( j = 0; j <= i; j++ )
-		if ( *scanLineP < MAX_LINES )
-		    {
-		    Pic[*scanLineP][k++] = (unsigned char) getc( file );
-		    if ( ! (k %= BYTES_WIDE) )
-			*scanLineP += 1;
-		    }
-	    }
-	else
-	    {	/* Repeat next char (2's comp I) times */
-	    ch = getc( file );
-	    for ( j = 0; j <= 256 - i; j++ )
-		if ( *scanLineP < MAX_LINES )
-		    {
-		    Pic[*scanLineP][k++] = (unsigned char) ch;
-		    if ( ! (k %= BYTES_WIDE) )
-			*scanLineP += 1;
-		    }
-	    }
-	}
-    }
+}
diff --git a/converter/pbm/pbmto10x.c b/converter/pbm/pbmto10x.c
index 8a3edb36..d040b3ed 100644
--- a/converter/pbm/pbmto10x.c
+++ b/converter/pbm/pbmto10x.c
@@ -12,16 +12,14 @@
 ** Modified to shorten stripes and eliminate blank stripes. Dec 1994.
 */
 
+#include <stdbool.h>
+
 #include "pbm.h"
 #include "mallocvar.h"
 
 #define LOW_RES_ROWS    8       /* printed per pass */
 #define HIGH_RES_ROWS   16      /* printed per pass */
 
-static int  highres = 0;
-static FILE *ifp;
-static int  rows, cols, format;
-
 
 
 static void
@@ -29,8 +27,6 @@ outstripe(char * const stripe,
           char * const sP, 
           int    const reschar) {
 
-    int ncols;
-
     char * p;
 
     p = sP;  /* initial value */
@@ -41,10 +37,14 @@ outstripe(char * const stripe,
             ++p;
             break;
         }
-    ncols = p - stripe;
-    if (ncols > 0) {
-        printf("\033%c%c%c", reschar, ncols % 256, ncols / 256);
-        fwrite(stripe, sizeof(char), ncols, stdout);
+
+    {
+        unsigned int const ncols = p - stripe;
+
+        if (ncols > 0) {
+            printf("\033%c%c%c", reschar, ncols % 256, ncols / 256);
+            fwrite(stripe, sizeof(char), ncols, stdout);
+        }
     }
     putchar('\n');          /* flush buffer */
 }
@@ -52,26 +52,44 @@ outstripe(char * const stripe,
 
 
 static void
-res_60x72(void) {
-    int i, item, npins, row, col;
-    bit *bitrows[LOW_RES_ROWS], *bP[LOW_RES_ROWS];
-    char *stripe, *sP;
+res_60x72(FILE * const ifP,
+          int    const rows,
+          int    const cols,
+          int    const format) {
+
+    int row;
+    unsigned int i;
+    bit * bitrows[LOW_RES_ROWS];
+    char *stripe;
+    char *sP;
 
     MALLOCARRAY(stripe, cols);
     if (stripe == NULL)
         pm_error("Unable to allocate %u bytes for a stripe buffer.",
                  (unsigned)(cols * sizeof(stripe[0])));
+
     for (i = 0; i < LOW_RES_ROWS; ++i)
         bitrows[i] = pbm_allocrow(cols);
+
     printf("\033A\010");        /* '\n' = 8/72 */
+
     for (row = 0, sP = stripe; row < rows; row += LOW_RES_ROWS, sP = stripe) {
+        unsigned int col;
+        unsigned int i;
+        unsigned int npins;
+        bit * bP[LOW_RES_ROWS];
+
         if (row + LOW_RES_ROWS <= rows)
             npins = LOW_RES_ROWS;
         else
             npins = rows - row;
+
         for (i = 0; i < npins; ++i)
-            pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format);
+            pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format);
+
         for (col = 0; col < cols; ++col) {
+            unsigned int item;
+
             item = 0;
             for (i = 0; i < npins; ++i)
                 if (*(bP[i]++) == PBM_BLACK)
@@ -81,32 +99,52 @@ res_60x72(void) {
         outstripe(stripe, sP, 'K');
     }
     printf("\033@");
+
+    for (i = 0; i < LOW_RES_ROWS; ++i)
+        pbm_freerow(bitrows[i]);
+
     free(stripe);
 }
 
 
 
 static void
-res_120x144(void) {
-    int i, pin, item, npins, row, col;
-    bit *bitrows[HIGH_RES_ROWS], *bP[HIGH_RES_ROWS];
-    char *stripe, *sP;
+res_120x144(FILE * const ifP,
+            int    const rows,
+            int    const cols,
+            int    const format) {
+
+    unsigned int i;
+    int row;
+    char *stripe;
+    char * sP;
+    bit * bitrows[HIGH_RES_ROWS];
 
     MALLOCARRAY(stripe, cols);
     if (stripe == NULL)
         pm_error("Unable to allocate %u bytes for a stripe buffer.",
                  (unsigned)(cols * sizeof(stripe[0])));
+
     for (i = 0; i < HIGH_RES_ROWS; ++i)
         bitrows[i] = pbm_allocrow(cols);
+
     printf("\0333\001");            /* \n = 1/144" */
+
     for (row = 0, sP = stripe; row < rows; row += HIGH_RES_ROWS, sP = stripe) {
+        unsigned int i;
+        unsigned int col;
+        bit * bP[HIGH_RES_ROWS];
+        unsigned int npins;
+
         if (row + HIGH_RES_ROWS <= rows)
             npins = HIGH_RES_ROWS;
         else
             npins = rows - row;
         for (i = 0; i < npins; ++i)
-            pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format);
+            pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format);
         for (col = 0; col < cols; ++col) {
+            unsigned int pin;
+            unsigned int item;
             item = 0;
             /* even rows */
             for (pin = i = 0; i < npins; i += 2, ++pin)
@@ -115,8 +153,9 @@ res_120x144(void) {
             *sP++ = item;
         }
         outstripe(stripe, sP, 'L');
-        sP = stripe;
-        for (col = 0; col < cols; ++col) {
+        for (col = 0, sP = stripe; col < cols; ++col) {
+            unsigned int pin;
+            unsigned int item;
             item = 0;
             /* odd rows */
             for (i = 1, pin = 0; i < npins; i += 2, ++pin)
@@ -128,20 +167,29 @@ res_120x144(void) {
         printf("\033J\016");        /* 14/144 down, \n did 1/144 */
     }
     printf("\033@");
+
+    for (i = 0; i < LOW_RES_ROWS; ++i)
+        pbm_freerow(bitrows[i]);
+
     free(stripe);
 }
 
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char ** argv) {
 
     const char * fname;
+    static FILE * ifP;
+    int rows, cols, format;
+
+    bool isHighRes;
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
+    isHighRes = false;  /* initial assumption */
     if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h') {
-        highres = 1;
+        isHighRes = true;
         --argc;
         ++argv;
     }
@@ -152,17 +200,18 @@ main(int argc, char * argv[]) {
     else
         fname = "-";
     
-    ifp = pm_openr(fname);
+    ifP = pm_openr(fname);
 
-    pbm_readpbminit(ifp, &cols, &rows, &format);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
 
-    if (highres)
-        res_120x144();
+    if (isHighRes)
+        res_120x144(ifP, rows, cols, format);
     else
-        res_60x72();
+        res_60x72(ifP, rows, cols, format);
+
+    pm_close(ifP);
 
-    pm_close(ifp);
-    exit(0);
+    return 0;
 }
 
 
diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c
index 9399f602..ea5b7abe 100644
--- a/converter/pbm/pbmtoatk.c
+++ b/converter/pbm/pbmtoatk.c
@@ -118,63 +118,52 @@ process_atk_byte(int *           const pcurcount,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
 
-    FILE *ifd;
-    bit *bitrow;
-    register bit *bP;
-    int rows, cols, format, row;
-    int col;
-    unsigned char curbyte, newbyte;
-    int curcount, gather;
+    FILE * ifP;
+    bit * bitrow;
+    int rows, cols, format;
+    unsigned int row;
+    unsigned char curbyte;
+    int curcount;
 
-    pbm_init ( &argc, argv );
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
         pm_error("Too many arguments.  Only argument is file name");
 
     else if (argc-1 == 1) {
-        ifd = pm_openr( argv[1] );
+        ifP = pm_openr(argv[1]);
     } else {
-        ifd = stdin;
+        ifP = stdin;
     }
 
-    pbm_readpbminit(ifd, &cols, &rows, &format);
-    bitrow = pbm_allocrow(cols);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+    bitrow = pbm_allocrow_packed(cols);
 
-    printf ("\\begindata{raster,%d}\n", 1);
-    printf ("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE);
-    printf ("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */
-    printf ("bits %d %d %d\n", 1, cols, rows);
+    printf("\\begindata{raster,%d}\n", 1);
+    printf("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE);
+    printf("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */
+    printf("bits %d %d %d\n", 1, cols, rows);
 
     for (row = 0; row < rows; ++row) {
-        pbm_readpbmrow(ifd, bitrow, cols, format);
-        bP = bitrow;
-        gather = 0;
-        newbyte = 0;
-        curbyte = 0;
-        curcount = 0;
-        col = 0;
-        while (col < cols) {
-            if (gather > 7) {
-                process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE);
-                gather = 0;
-                newbyte = 0;
-            }
-            newbyte = (newbyte << 1) | (*bP++);
-            gather += 1;
-            col += 1;
-        }
-
-        if (gather > 0) {
-            newbyte = (newbyte << (8 - gather));
-            process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE);
+        unsigned int const byteCt = pbm_packed_bytes(cols);
+        unsigned int i;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
+        
+        for (i = 0, curbyte = 0, curcount = 0; i < byteCt; ++i) {
+            process_atk_byte(&curcount, &curbyte, stdout,
+                             bitrow[i],
+                             i + 1 < byteCt ? FALSE : TRUE );
         }
     }
 
-    pm_close( ifd );
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
     
-    printf ("\\enddata{raster, %d}\n", 1);
+    printf("\\enddata{raster, %d}\n", 1);
 
     return 0;
 }
diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c
index 8e9d75a9..bb36791d 100644
--- a/converter/pbm/pbmtoepson.c
+++ b/converter/pbm/pbmtoepson.c
@@ -11,13 +11,12 @@
 ** implied warranty.
 */
 
-#define _BSD_SOURCE    /* Make sure strcasecmp() is in string.h */
-
+#define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
 #include <stdio.h>
-#include <string.h>
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 
 #include "pbm.h"
@@ -29,22 +28,22 @@ enum epsonProtocol {ESCP9, ESCP};
 
 enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO};
 
-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 *inputFilespec;  /* '-' if stdin */
-    unsigned int dpi;  /* zero means "any" */
-    enum adjacence adjacence;
+    const char *       inputFileName;  /* '-' if stdin */
+    unsigned int       dpi;  /* zero means "any" */
+    enum adjacence     adjacence;
     enum epsonProtocol protocol;
 };
 
 
 
 static void
-parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+parseCommandLine(int                  argc, 
+                 const char **        argv,
+                 struct CmdlineInfo * cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -69,20 +68,20 @@ parseCommandLine(int                 argc,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "protocol",   OPT_STRING,   &protocol,
+    OPTENT3(0, "protocol",     OPT_STRING,   &protocol,
             &protocolSpec,                    0);
-    OPTENT3(0, "dpi",        OPT_UINT,   &cmdlineP->dpi,
-            &dpiSpec,                    0);
-    OPTENT3(0, "adjacent",   OPT_FLAG,   NULL,
+    OPTENT3(0, "dpi",          OPT_UINT,     &cmdlineP->dpi,
+            &dpiSpec,                         0);
+    OPTENT3(0, "adjacent",     OPT_FLAG,     NULL,
             &adjacentSpec,                    0);
-    OPTENT3(0, "nonadjacent",   OPT_FLAG,   NULL,
-            &nonadjacentSpec,                    0);
+    OPTENT3(0, "nonadjacent",  OPT_FLAG,     NULL,
+            &nonadjacentSpec,                 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -96,11 +95,11 @@ parseCommandLine(int                 argc,
     if (!protocolSpec)
         cmdlineP->protocol = ESCP9;
     else {
-        if (strcasecmp(protocol, "escp9") == 0)
+        if (strcaseeq(protocol, "escp9"))
             cmdlineP->protocol = ESCP9;
-        else if (strcasecmp(protocol, "escp") == 0)
+        else if (strcaseeq(protocol, "escp"))
             cmdlineP->protocol = ESCP;
-        else if (strcasecmp(protocol, "escp2") == 0)
+        else if (strcaseeq(protocol, "escp2"))
             pm_error("This program cannot do ESC/P2.  Try Pbmtoescp2.");
         else
             pm_error("Unrecognized value '%s' for -protocol.  "
@@ -118,13 +117,15 @@ parseCommandLine(int                 argc,
         cmdlineP->adjacence = ADJACENT_ANY;
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else {
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
         if (argc-1 > 1)
             pm_error("Too many arguments (%d).  The only non-option argument "
                      "is the file name", argc-1);
     }
+
+    free(option_def);
 }
 
 
@@ -273,7 +274,7 @@ convertToEpson(const bit **       const bits,
                enum adjacence     const adjacence) {
     
     unsigned int const rowsPerStripe = 8;
-    unsigned int const stripes = (rows + rowsPerStripe-1) / rowsPerStripe;
+    unsigned int const stripeCt = (rows + rowsPerStripe-1) / rowsPerStripe;
 
     unsigned int stripe;
     char m;
@@ -288,7 +289,7 @@ convertToEpson(const bit **       const bits,
        stripe can be fewer than 8 rows.
     */
 
-    for (stripe = 0; stripe < stripes; ++stripe) {
+    for (stripe = 0; stripe < stripeCt; ++stripe) {
         const bit ** const stripeBits = &bits[stripe*rowsPerStripe];
         unsigned int const stripeRows = 
             MIN(rowsPerStripe, rows - stripe * rowsPerStripe);
@@ -313,18 +314,18 @@ convertToEpson(const bit **       const bits,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     const bit** bits;
     int rows, cols;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     bits = (const bit **)pbm_readpbm(ifP, &cols, &rows);
 
diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c
index cd96c9dc..f0fd1252 100644
--- a/converter/pbm/pbmtog3.c
+++ b/converter/pbm/pbmtog3.c
@@ -65,7 +65,7 @@ struct outStream {
 static struct outStream out;
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -79,7 +79,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, char ** const 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.
@@ -407,7 +407,7 @@ int
 main(int    argc,
      char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     unsigned char * bitrow;
        /* This is the bits of the current row, as read from the input and
diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c
index 82ccce06..7ddb1ef5 100644
--- a/converter/pbm/pbmtomacp.c
+++ b/converter/pbm/pbmtomacp.c
@@ -1,294 +1,497 @@
-/* pbmtomacp.c - read a portable bitmap and produce a MacPaint bitmap file
-**
-** Copyright (C) 1988 by Douwe vand der Schaaf.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
+/*=============================================================================
+                                  pbmtomacp
+===============================================================================
+  Read a PBM file and produce a MacPaint bitmap file
+
+  Copyright (C) 2015 by Akira Urushibata ("douso").
+
+  Replacement of a previous program of the same name written in 1988
+  by Douwe van der Schaaf (...!mcvax!uvapsy!vdschaaf).
+
+  Permission to use, copy, modify, and distribute this software and its
+  documentation for any purpose and without fee is hereby granted, provided
+  that the above copyright notice appear in all copies and that both that
+  copyright notice and this permission notice appear in supporting
+  documentation.  This software is provided "as is" without express or implied
+  warranty.
+=============================================================================*/
+
+/*
+
+  Implemention notes
+
+  Header size is 512 bytes.  There is no MacBinary header.
+
+  White margin which is added for input files with small dimensions
+  is treated separately from the active image raster.  The margins
+  are directly coded based on the number of rows/columns.
+
+  Output file size never exceeds 53072 bytes.  When -norle is specified,
+  output is always 53072 bytes.  It is conceivable that decoders which
+  examine the size of Macpaint files (for general validation or for
+  determination of header type and size) do exist.
+
+  The uncompressed output (-norle case) fully conforms to Macpaint
+  specifications.  No special treatment by the decoder is required.
 */
 
-#include <string.h>
+#include <assert.h>
 
 #include "pm_c_util.h"
 #include "pbm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
 #include "macp.h"
 
-#define EQUAL		1
-#define UNEQUAL		0
-
 #define MIN3(a,b,c)     (MIN((MIN((a),(b))),(c)))
 
-static void fillbits ARGS(( bit **bits, bit **bitsr, int top, int left, int bottom, int right ));
-static void writemacp ARGS(( bit **bits ));
-static int packit ARGS(( bit *pb, bit *bits ));
-static void filltemp ARGS(( bit *dest, bit *src ));
-static void sendbytes ARGS(( bit *pb, register int npb ));
-static void header ARGS(( void ));
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line, in a form
+       easy for the program to use.
+    */
+    const char * inputFileName;  /* File name of input file */
+    unsigned int left;
+    unsigned int right;
+    unsigned int top;
+    unsigned int bottom;
+    unsigned int leftSpec;
+    unsigned int rightSpec;
+    unsigned int topSpec;
+    unsigned int bottomSpec;
+    bool         norle;
+};
 
-static FILE *fdout;
 
-int
-main(argc, argv)
-int argc;
-char *argv[];
-{ FILE *ifp;
-  register bit **bits, **bitsr;
-  int argn, rows, cols;
-  int left,bottom,right,top;
-  int lflg, rflg, tflg, bflg;
-  const char * const usage = "[-l left] [-r right] [-b bottom] [-t top] [pbmfile]";
-
-
-  pbm_init( &argc, argv );
-
-  argn = 1;
-  fdout = stdout;
-  lflg = rflg = tflg = bflg = 0;
-  left = right = top = bottom = 0;  /* To quiet compiler warning */
-
-  while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-  { switch ( argv[argn][1] )
-    { case 'l':
-      lflg++;
-      argn++;
-      left = atoi( argv[argn] );
-      break;
-
-      case 'r':
-      rflg++;
-      argn++;
-      right = atoi( argv[argn] );
-      break;
-
-      case 't':
-      tflg++;
-      argn++;
-      top = atoi( argv[argn] );
-      break;
-
-      case 'b':
-      bflg++;
-      argn++;
-      bottom = atoi( argv[argn] );
-      break;
-
-      case '?':
-      default:
-      pm_usage( usage );
+
+static void
+parseCommandLine(int                        argc,
+                 const char **        const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+        /* Instructions to OptParseOptions3 on how to parse our options.  */
+    optStruct3 opt;
+
+    unsigned int norleSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "left",     OPT_UINT,  &cmdlineP->left,
+            &cmdlineP->leftSpec,     0);
+    OPTENT3(0, "right",    OPT_UINT,  &cmdlineP->right,
+            &cmdlineP->rightSpec,    0);
+    OPTENT3(0, "top",      OPT_UINT,  &cmdlineP->top,
+            &cmdlineP->topSpec,      0);
+    OPTENT3(0, "bottom",   OPT_UINT,  &cmdlineP->bottom,
+            &cmdlineP->bottomSpec,   0);
+    OPTENT3(0, "norle", OPT_FLAG,  NULL,
+            &norleSpec, 0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    cmdlineP->norle = norleSpec;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        if (argc-1 > 1)
+            pm_error("Program takes zero or one argument (filename).  You "
+                     "specified %d", argc-1);
     }
-    ++argn;
-  }
 
-  if ( argn == argc )
-  { ifp = stdin;
-  }
-  else
-  { ifp = pm_openr( argv[argn] );
-    ++argn;
-  }
+    free(option_def);
+}
+
+
+
+struct CropPadDimensions {
+    unsigned int imageWidth;   /* Active image content */
+    unsigned int imageHeight;
+    unsigned int leftCrop;     /* Cols cropped off from input */
+    unsigned int topCrop;      /* Rows cropped off from input */
+    unsigned int topMargin;    /* White padding for output */
+    unsigned int bottomMargin;
+    unsigned int leftMargin;
+};
+
+
 
-  if ( argn != argc )
-    pm_usage( usage );
+static void
+calculateCropPad(struct CmdlineInfo         const cmdline,
+                 unsigned int               const cols,
+                 unsigned int               const rows,
+                 struct CropPadDimensions * const cropPadP) {
+/*--------------------------------------------------------------------------
+  Validate -left -right -top -bottom from command line.
+
+  Determine what rows, columns to take from input if any of these are
+  specified and return it as *cropPadP.
+
+  'cols and 'rows' are the dimensions of the input image.
+
+  Center image if it is smaller than the fixed Macpaint format size.
+----------------------------------------------------------------------------*/
+    unsigned int const left = cmdline.leftSpec ? cmdline.left : 0;
+    unsigned int const top  = cmdline.topSpec  ? cmdline.top  : 0;
+
+    unsigned int right, bottom, width, height;
+
+    if (cmdline.leftSpec) {
+        if (cmdline.rightSpec && left >= cmdline.right)
+            pm_error("-left value must be smaller than -right value");
+        else if (left + 1 > cols)
+            pm_error("Specified -left value is beyond right edge "
+                     "of input image");
+    }
+    if (cmdline.topSpec) {
+        if (cmdline.bottomSpec && top >= cmdline.bottom)
+            pm_error("-top value must be smaller than -bottom value");
+        else if (top + 1 > rows)
+            pm_error("Specified -top value is beyond bottom edge "
+                     "of input image");
+    }
+    if (cmdline.rightSpec) {
+        if (cmdline.right + 1 > cols)
+            pm_message("Specified -right value %u is beyond edge of "
+                       "input image", cmdline.right);
 
-  bitsr = pbm_readpbm( ifp, &cols, &rows );
+        right = MIN3(cmdline.right, cols - 1, left + MACP_COLS - 1);
+    } else
+        right = MIN(cols - 1,  left + MACP_COLS - 1);
 
-  pm_close( ifp );
+    if (cmdline.bottomSpec) {
+        if (cmdline.bottom + 1 > rows)
+            pm_message("Specified -bottom value %u is beyond edge of "
+                       "input image", cmdline.bottom);
 
-  bits = pbm_allocarray( MAX_COLS, MAX_LINES );
+            bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
+    } else
+        bottom = MIN(rows - 1, top + MACP_ROWS - 1);
 
-  if( !lflg )
-    left = 0;
+    cropPadP->leftCrop = left;
+    cropPadP->topCrop  = top;
 
-  if( rflg )
-    right = MIN3( right, cols - 1, left + MAX_COLS - 1 );
-  else
-    right = MIN( cols - 1,  left + MAX_COLS - 1 );
+    assert(right >= left);
 
-  if( !tflg )
-    top = 0;
+    width = right - left + 1;
+    assert(width > 0 && width <= MACP_COLS);
 
-  if( bflg )
-    bottom = MIN3( bottom, rows - 1, top + MAX_LINES - 1);
-  else
-    bottom = MIN( rows - 1, top + MAX_LINES - 1 );
+    cropPadP->leftMargin = (MACP_COLS - width) / 2;
 
-    if( right <= left || left < 0 || right - left + 1 > MAX_COLS )
-      pm_error("error in right (= %d) and/or left (=%d)",right,left );
-    if( bottom <= top || top < 0 || bottom - top + 1 > MAX_LINES )
-      pm_error("error in bottom (= %d) and/or top (=%d)",bottom,top );
+    if (width < cols)
+        pm_message("%u of %u input columns will be output", width, cols);
 
-  fillbits( bits, bitsr, top, left, bottom, right );
+    height = bottom - top + 1;
+    assert(height > 0 && height <= MACP_ROWS);
 
-  writemacp( bits );
+    cropPadP->topMargin    = (MACP_ROWS - height) / 2;
+    cropPadP->bottomMargin = cropPadP->topMargin + height - 1;
 
-  exit( 0 );
+    if (height < rows)
+        pm_message("%u out of %u input rows will be output", height, rows);
 
+    cropPadP->imageWidth  = width;
+    cropPadP->imageHeight = height;
 }
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
-/* centreer het over te zenden plaatje in het MacPaint document
- *
- * Het plaatje wordt vanaf al of niet opgegeven (left, bottom)
- * in een pbm bitmap van de juist macpaint afmetingen gezet,
- * en eventueel afgekapt.
- */
+
 static void
-fillbits( bits, bitsr, top, left, bottom, right )
-bit **bits, **bitsr;
-int top, left, bottom, right;
-{ register bit *bi, *bir;
-  register int i, j;
-  register int bottomr, leftr, topr, rightr;
-  int width, height;
-
-  width = right - left + 1;
-  leftr = (MAX_COLS - width) / 2;
-  rightr = leftr + width - 1;
-
-  height = bottom - top + 1;
-  topr = ( MAX_LINES - height ) / 2;
-  bottomr = topr + height - 1;
-
-  for( i = 0; i < topr; i++ )
-  { bi = bits[i];
-    for( j = 0; j < MAX_COLS; j++ )
-      *bi++ = 0;
-  }
-
-  for( i = topr; i <= bottomr; i++ )
-  { bi = bits[i];
-    { for( j = 0; j < leftr; j++ )
-	*bi++ = 0;
-      bir = bitsr[ i - topr + top ];
-      for( j = leftr; j <= rightr; j++ )
-	*bi++ = bir[j - leftr + left];
-      for( j = rightr + 1; j < MAX_COLS; j++ )
-	*bi++ = 0;
-  } }
-
-  for( i = bottomr + 1; i < MAX_LINES; i++ )
-  { bi = bits[i];
-    for( j = 0; j < MAX_COLS; j++ )
-      *bi++ = 0;
-  }
-} /* fillbits */
-      
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+writeMacpHeader(FILE * const ofP) {
+
+    char const ch = 0x00;    /* header contains nothing */
+
+    unsigned int i;
+
+    for (i = 0; i < MACP_HEAD_LEN; ++i)
+        fputc(ch, ofP);
+}
+
+
 
 static void
-writemacp( bits )
-bit **bits;
-{ register int i;
-  bit pb[MAX_COLS * 2];
-  int npb;
-
-  header();
-  for( i=0; i < MAX_LINES; i++ )
-  { npb = packit( pb, bits[i] );
-    sendbytes( pb, npb );
-  }
-} /* writemacp */
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-/* pack regel van MacPaint doc in Apple's format
- * return value = # of bytes in pb 
- */
-static int
-packit( pb, bits )
-     bit *pb, *bits;
-{ register int charcount, npb, newcount, flg;
-  bit temp[72];
-  bit *count, *srcb, *destb, save;
-
-  srcb = bits; destb = temp;
-  filltemp( destb, srcb );
-  srcb = temp;
-  destb = pb;
-  npb = 0;
-  charcount = BYTES_WIDE;
-  flg = EQUAL;
-  while( charcount ) { 
-      save = *srcb++;
-      charcount--;
-      newcount = 1;
-      while( charcount && (*srcb == save) ) { 
-          srcb++;
-          newcount++;
-          charcount--;
-      }
-      if( newcount > 2 ) { 
-          count = destb++;
-          *count = 257 - newcount;
-          *destb++ = save;
-          npb += 2;
-          flg = EQUAL;
-      } else { 
-          if( flg == EQUAL ) { 
-              count = destb++;
-              *count = newcount - 1;
-              npb++;
-          } else
-            *count += newcount;
-          while( newcount-- ) { 
-              *destb++ = save;
-              npb++;
-          }
-          flg = UNEQUAL;
-      } 
-  }
-  return npb;
-} /* packit */
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+writeMacpRowUnpacked(const bit  * const imageBits,
+                     unsigned int const leftMarginCharCt,
+                     unsigned int const imageColCharCt,
+                     FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Encode (without compression) and output one row.  The row comes divided into
+  three parts: left margin, image, right margin.
+----------------------------------------------------------------------------*/
+    char const marginByte = 0x00;  /* White bits for margin */
+    unsigned int const rightMarginCharCt =
+        MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
+    
+    unsigned int i;
+
+    fputc(MACP_COLCHARS - 1, ofP);
+
+    for (i = 0; i < leftMarginCharCt; ++i)
+        fputc(marginByte, ofP);
+
+    if (imageColCharCt > 0)
+        fwrite(imageBits, 1, imageColCharCt, ofP);
+
+    for (i = 0; i < rightMarginCharCt; ++i)
+        fputc(marginByte, ofP);
+}
+
+
 
 static void
-filltemp( dest, src )
-bit *dest, *src;
-{ register unsigned char ch, zero, acht;
-  register int i, j;
-
-  zero = '\0';
-  acht = 8;
-  i = BYTES_WIDE;
-  while( i-- )
-  { ch = zero; 
-    j = acht;
-    while( j-- )
-    { ch <<= 1;
-      if( *src++ )
-	ch++;
+writeMacpRowPacked(const bit  * const packedBits,
+                   unsigned int const leftMarginCharCt,
+                   unsigned int const imageColCharCt,
+                   unsigned int const rightMarginCharCt,
+                   FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Encode one row and write it to *ofP.
+
+  As in the unpacked case, the row comes divided into three parts: left
+  margin, image, right margin.  Unlike the unpacked case we need to know both
+  the size of the packed data and the size of the right margin.
+----------------------------------------------------------------------------*/
+    char const marginByte = 0x00;  /* White bits for margin */
+
+    if (leftMarginCharCt > 0) {
+        fputc(257 - leftMarginCharCt, ofP);
+        fputc(marginByte, ofP);
     }
-    *dest++ = ch;
-  }
-} /* filltemp */
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+    if (imageColCharCt > 0)
+        fwrite(packedBits, 1, imageColCharCt, ofP);
+
+    if (rightMarginCharCt > 0) {
+        fputc(257 - rightMarginCharCt, ofP);
+        fputc(marginByte, ofP);
+    }
+}
+
+
 
 static void
-sendbytes( pb, npb )
-bit *pb;
-register int npb;
-{ register bit *b;
+packit(const bit *     const sourceBits,
+       unsigned int    const imageColCharCt,
+       unsigned char * const packedBits,
+       unsigned int  * const packedImageLengthP ) {
+/*--------------------------------------------------------------------------
+  Compress according to packbits algorithm, a byte-level run-length encoding
+  scheme.
+
+  Each row is encoded separately.
+
+  The following code does not produce optimum output when there are 2-byte
+  long sequences between longer ones: the 2-byte run in between does not get
+  packed, using up 3 bytes where 2 would do.
+----------------------------------------------------------------------------*/
+    int charcount, packcount;
+    enum {EQUAL, UNEQUAL} status;
+    bit * count;
+
+    for (packcount = 0, charcount = 0, status = EQUAL;
+         charcount < imageColCharCt;
+        ) {
+        bit const save = sourceBits[charcount++];
+
+        int newcount;
+
+        newcount = 1;
+        while (charcount < imageColCharCt && sourceBits[charcount] == save) {
+            ++charcount;
+            ++newcount;
+        }
+        if (newcount > 2) {
+            count = (unsigned char *) &packedBits[packcount++];
+            *count = 257 - newcount;
+            packedBits[packcount++] = save;
+            status = EQUAL;
+        } else {
+            if (status == EQUAL) {
+                count = (unsigned char *) &packedBits[packcount++];
+                *count = newcount - 1;
+             } else
+                *count += newcount;
+
+            for( ; newcount > 0; --newcount) {
+                packedBits[packcount++] = save;
+            }
+            status = UNEQUAL;
+        }
+    }
+    *packedImageLengthP = packcount;
+}
+
+
+
+static void
+writeMacpRow(bit        * const imageBits,
+             unsigned int const leftMarginCharCt,
+             unsigned int const imageColCharCt,
+             bool         const norle,
+             FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Write the row 'imageBits' to Standard Output.
+
+  Write it packed, unless packing would lead to unnecessary bloat or 'norle'
+  is true.
+----------------------------------------------------------------------------*/
+    if (norle)
+        writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, ofP);
+    else {
+        unsigned int const rightMarginCharCt =
+            MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
+        unsigned char * const packedBits = malloc(MACP_COLCHARS+1);
+        
+        unsigned int packedImageLength;
+
+        if (packedBits == NULL)
+            pm_error("Failed to get memory for a %u-column row buffer",
+                     MACP_COLCHARS);
+
+        packit(imageBits, imageColCharCt, packedBits, &packedImageLength);
+
+        /* Check if we are we better off with compression.  If not, send row
+           unpacked.  See note at top of file.
+        */
+        
+        if (packedImageLength +
+            (leftMarginCharCt  > 0 ? 1 : 0) * 2 +
+            (rightMarginCharCt > 0 ? 1 : 0) * 2
+            < MACP_COLCHARS)
+            writeMacpRowPacked(packedBits, leftMarginCharCt,
+                               packedImageLength, rightMarginCharCt, ofP);
+        else /* Extremely rare */
+            writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt,
+                                 ofP);
+
+        free(packedBits);
+    }
+}
 
-  b = pb;
-  while( npb-- )
-    (void) putc( *b++, fdout );
-} /* sendbytes */
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
 static void
-header()
-{ register int i;
-  register char ch;
-
-  /* header contains nothing ... */
-  ch = '\0';
-  for(i = 0; i < HEADER_LENGTH; i++ )
-    (void) putc( ch, fdout );
-} /* header */
+encodeRowsWithShift(bit *                    const bitrow,
+                    FILE *                   const ifP,
+                    int                      const inCols,
+                    int                      const format,
+                    bool                     const norle,
+                    struct CropPadDimensions const cropPad,
+                    FILE *                   const ofP) {
+/*--------------------------------------------------------------------------
+  Shift input rows to put only specified columns to output.  Add padding on
+  left and right if necessary.
+
+  No shift if the input image is the exact size (576 columns) of the Macpaint
+  format.  If the input image is too wide and -left was not specified, extra
+  content on the right is discarded.
+----------------------------------------------------------------------------*/
+    unsigned int const offset     =
+        (cropPad.leftMargin + 8 - cropPad.leftCrop % 8) % 8;
+    unsigned int const leftTrim   =
+        cropPad.leftMargin % 8;
+    unsigned int const rightTrim  =
+        (8 - (leftTrim + cropPad.imageWidth) % 8 ) % 8;
+    unsigned int const startChar  =
+        (cropPad.leftCrop + offset) / 8;
+    unsigned int const imageCharCt =
+        pbm_packed_bytes(leftTrim + cropPad.imageWidth);
+    unsigned int const leftMarginCharCt =
+        cropPad.leftMargin / 8;
+
+    unsigned int row;
+
+    for (row = 0; row < cropPad.imageHeight; ++row) {
+        pbm_readpbmrow_bitoffset(ifP, bitrow, inCols, format, offset);
+        
+        /* Trim off fractional margin portion in first byte of image data */
+        if (leftTrim > 0) {
+            bitrow[startChar] <<= leftTrim;
+            bitrow[startChar] >>= leftTrim;
+        }
+        /* Do the same with bits in last byte of relevant image data */
+        if (rightTrim > 0) {
+            bitrow[startChar + imageCharCt - 1] >>= rightTrim;
+            bitrow[startChar + imageCharCt - 1] <<= rightTrim;
+        }
+
+        writeMacpRow(&bitrow[startChar], leftMarginCharCt,
+                     imageCharCt, norle, ofP);
+    }
+}
+
+
+
+static void
+writeMacp(unsigned int             const cols,
+          unsigned int             const rows,
+          int                      const format,
+          FILE *                   const ifP,
+          bool                     const norle,
+          struct CropPadDimensions const cropPad,
+          FILE *                   const ofP) {
+
+    unsigned int row, skipRow;
+    bit * bitrow;
+
+    writeMacpHeader(ofP);
+
+    /* Write top padding */
+    for (row = 0; row < cropPad.topMargin; ++row)
+        writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP);
+
+    /* Allocate PBM row with one extra byte for the shift case. */
+    bitrow = pbm_allocrow_packed(cols + 8);
+
+    for (skipRow = 0; skipRow < cropPad.topCrop; ++skipRow)
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+    encodeRowsWithShift(bitrow, ifP, cols, format, norle, cropPad, ofP);
+
+    pbm_freerow_packed(bitrow);
+
+    /* Add bottom padding */
+    for (row = cropPad.bottomMargin + 1; row < MACP_ROWS; ++row)
+        writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    FILE * ifP;
+    int rows, cols;
+    int format;
+    struct CmdlineInfo cmdline;
+    struct CropPadDimensions cropPad;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    calculateCropPad(cmdline, cols, rows, &cropPad);
+
+    writeMacp(cols, rows, format, ifP, cmdline.norle, cropPad, stdout);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
diff --git a/converter/pbm/pbmtomatrixorbital.c b/converter/pbm/pbmtomatrixorbital.c
index 96e1406a..41f8e260 100644
--- a/converter/pbm/pbmtomatrixorbital.c
+++ b/converter/pbm/pbmtomatrixorbital.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
 #include "pbm.h"
 
 /* By Bryan Henderson, San Jose CA 2003.09.06.
@@ -12,10 +14,10 @@
 
 
 static void
-generateMo(FILE * const ofP, 
-           bit ** const bits,
-           int    const cols,
-           int    const rows) {
+generateMo(FILE *       const ofP, 
+           bit **       const bits,
+           unsigned int const cols,
+           unsigned int const rows) {
 
     unsigned int col;
 
@@ -51,37 +53,40 @@ generateMo(FILE * const ofP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char ** argv) {
 
-    FILE* ifp;
-    bit** bits;
+    FILE * ifP;
+    bit ** bits;
     int rows, cols;
     const char * inputFilename;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
-        pm_error("Too many arguments (%d).  The only valid argument is an "
+        pm_error("Too many arguments (%u).  The only valid argument is an "
                  "input file name.", argc-1);
     else if (argc-1 == 1) 
         inputFilename = argv[1];
     else
         inputFilename = "-";
 
-    ifp = pm_openr(inputFilename);
+    ifP = pm_openr(inputFilename);
     
-    bits = pbm_readpbm(ifp, &cols, &rows);
+    bits = pbm_readpbm(ifP, &cols, &rows);
 
     if (rows > 255)
-        pm_error("Image is too high:  %d rows.  Max height: 255 rows", rows);
+        pm_error("Image is too high:  %u rows.  Max height: 255 rows", rows);
     if (cols > 255)
-        pm_error("Image is too wide:  %d cols.  Max width: 255 cols", cols);
+        pm_error("Image is too wide:  %u cols.  Max width: 255 cols", cols);
 
     generateMo(stdout, bits, cols, rows);
     
-    pm_close(ifp);
+    pm_close(ifP);
 
     pbm_freearray(bits, rows);
 
-    exit(0);
+    return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index d12e6635..e8e30148 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -89,11 +89,7 @@ main(int argc,
         size_t bytesWritten;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
-        
-        if (padright > 0) {
-            bitrow[bytesPerRow-1] >>= padright;
-            bitrow[bytesPerRow-1] <<= padright;
-        }
+        pbm_cleanrowend_packed(bitrow, cols);
 
         bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout);
         if (bytesWritten != bytesPerRow )
diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c
index 6a60af62..791bcb50 100644
--- a/converter/pbm/pbmtopi3.c
+++ b/converter/pbm/pbmtopi3.c
@@ -1,4 +1,4 @@
-/* pbmtopi3.c - read a portable bitmap and produce a Atari Degas .pi3 file
+/* pbmtopi3.c - read a PBM image and produce a Atari Degas .pi3 file
 **
 ** Module created from other pbmplus tools by David Beckemeyer.
 **
@@ -12,106 +12,87 @@
 ** implied warranty.
 */
 
+/* Output file should always be 32034 bytes. */
+
 #include <stdio.h>
+#include "pm_c_util.h"
 #include "pbm.h"
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
-
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row, col;
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    if (cols > 640)
-	cols = 640;
-    if (rows > 400)
-	rows = 400;
-    bitrow = pbm_allocrow( cols );
-    
-    /* Compute padding to round cols up to 640 */
-    padright = 640 - cols;
-
-    putinit( );
-    for ( row = 0; row < rows; ++row )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    putbit( *bP );
-	for ( col = 0; col < padright; ++col )
-	    putbit( 0 );
-        }
-    while (row++ < 400)
-	for ( col = 0; col < 640; ++col)
-	    putbit( 0 );
-
-    pm_close( ifp );
-
-    putrest( );
-
-    exit( 0 );
-    }
 
-static char item;
-static short bitsperitem, bitshift;
 
 static void
-putinit( )
-    {
-    int i;
-    if (pm_writebigshort (stdout, (short) 2) == -1
-	|| pm_writebigshort (stdout, (short) 0x777) == -1)
-      pm_error ("write error");
-    for (i = 1; i < 16; i++)
-      if (pm_writebigshort (stdout, (short) 0) == -1)
-	pm_error ("write error");
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
+putinit(FILE * const ofP)  {
+
+    unsigned int i;
+
+    pm_writebigshort(ofP, (short) 2);
+    pm_writebigshort(ofP, (short) 0x777);
+
+    for (i = 1; i < 16; ++i) {
+        pm_writebigshort (ofP, (short) 0);
     }
+}
 
-static void
-putbit( bit b )
-    {
-    if (bitsperitem == 8)
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    --bitshift;
+
+
+int
+main(int argc, const char ** argv) {
+
+    unsigned int const outRows = 400;
+    unsigned int const outCols = 640;
+    unsigned int const outColByteCt = pbm_packed_bytes(outCols);
+
+    FILE * ifP;
+
+    int inRows, inCols, format;
+    unsigned int row;
+    unsigned int inColByteCt;
+    unsigned int i;
+    bit * bitrow;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else  {
+        ifP = pm_openr(argv[1]);
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument "
+                     "is the input file name");
     }
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
+    pbm_readpbminit(ifP, &inCols, &inRows, &format);
+
+    inColByteCt = pbm_packed_bytes(inCols);
+
+    bitrow = pbm_allocrow_packed(MAX(outCols, inCols));
+    
+    /* Add padding to round cols up to 640 */
+    for (i = inColByteCt; i < outColByteCt; ++i)
+        bitrow[i] = 0x00;
+
+    putinit(stdout);
+
+    for (row = 0; row < MIN(inRows, outRows); ++row) {
+        pbm_readpbmrow_packed(ifP, bitrow, inCols, format);
+        pbm_cleanrowend_packed(bitrow, inCols);
+        fwrite (bitrow, outColByteCt, 1, stdout);
     }
+    pm_close(ifP);
 
-static void
-putitem( )
-    {
-    putc (item, stdout);
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
+    if (row < outRows)  {
+        unsigned int i;
+
+        /* Clear entire row */
+        for (i = 0; i < outColByteCt; ++i)
+            bitrow[i] = 0x00;
+
+        while (row++ < outRows)
+            fwrite(bitrow, outColByteCt, 1, stdout);
     }
+
+    pbm_freerow_packed(bitrow);
+
+    return 0;
+}
diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c
index fc94f855..3948ae0d 100644
--- a/converter/pbm/pbmtopk.c
+++ b/converter/pbm/pbmtopk.c
@@ -1,7 +1,12 @@
 /*
   pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90
   
-  compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm
+  References (retrieved May 31 2015):
+  Packed (PK) Font File Format 
+  https://www.tug.org/TUGboat/tb06-3/tb13pk.pdf
+
+  Tex Font Metric Files (TFM)
+  https://www.tug.org/TUGboat/tb06-1/tb11gf.pdf
 */
 
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
@@ -26,6 +31,29 @@
 #define MAXPARAMS 30
 #define NAMELENGTH 80
 
+/*-----------------------------------------------------------------------
+Macros to handle fixed point numbers
+
+This program uses uses fixed-point numbers to store data where
+normally a floating-point data type (float or double) would be
+employed.
+
+Numbers that contain fractions are stored as signed integers.
+The 20 least-significant bits are for the fractional part, the rest
+(12 bits assuming that int is 32 bit) are for the integer part.
+The technical term for this is "Q20" or "Q12.20" notation.
+
+Float/double data is converted to Q20 fixed point by multiplying
+by 2^20 (= 1048576).  The opposite conversion is conducted by
+dividing by 2^20.
+
+The Q20 data must be within the range -16 < r < 16.  The reason
+behind this restriction is unclear.  The program generally writes
+Q20 data to the output files in 32 bits.  (Exception: in function
+shipchar() there is a provision to write Q20 data in 24 bits,
+provided that 24 bits is sufficient.)
+---------------------------------------------------------------------*/
+
 #define fixword(d) ((int)((double)(d)*1048576))
 #define unfixword(f) ((double)(f) / 1048576)
 #define fixrange(f) ((f) < 16777216 && (f) > -16777216)
diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c
index 8cd60326..c0fb0f80 100644
--- a/converter/pbm/pbmtoptx.c
+++ b/converter/pbm/pbmtoptx.c
@@ -12,84 +12,79 @@
 
 #include "pbm.h"
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
+/* Follwing is obtained by reversing bit order (MFS-LFS) and adding 64. */
+/* Note the two escape sequences: \\ and \x7f . */
 
-int
-main( argc, argv )
-int argc;
-char *argv[];
-    {
-    FILE *ifp;
-    register bit *bitrow, *bP;
-    int rows, cols, format, row, col;
-    const char * const usage = "[pbmfile]";
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( usage );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-
-    putinit( );
-    for ( row = 0; row < rows; row++ )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
-	    putbit( *bP );
-	putrest( );
-	putchar( 5 );
-	putchar( '\n' );
-        }
+static unsigned char const ptxchar[64] = 
+  "@`PpHhXxDdTtLl\\|BbRrJjZzFfVvNn^~AaQqIiYyEeUuMm]}CcSsKk[{GgWwOo_\x7f";
 
-    pm_close( ifp );
-    
-    exit( 0 );
-    }
 
-static char item;
-static int bitsperitem, bitshift;
 
 static void
-putinit( )
-    {
-    bitsperitem = 0;
-    item = 64;
-    bitshift = 0;
-    }
+putBitrow(const bit *  const bitrow,
+          unsigned int const cols) {
+/*----------------------------------------------------------------------------
+  Pick up items in 6 bit units from bitrow and convert each to ptx format.
+----------------------------------------------------------------------------*/
+    unsigned int itemCnt;
 
-static void
-putbit( bit b )
-    {
-    if ( bitsperitem == 6 )
-	putitem( );
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    bitsperitem++;
-    bitshift++;
+    for (itemCnt = 0; itemCnt * 6 < cols; ++itemCnt) {
+        unsigned int const byteCnt = (itemCnt * 6) / 8;
+        bit const byteCur  = bitrow[byteCnt];
+        bit const byteNext = bitrow[byteCnt + 1];
+        
+        unsigned int item;
+
+        switch (itemCnt % 4) {
+        case 0: item = byteCur >> 2;                 break;
+        case 1: item = byteCur << 4 | byteNext >> 4; break;
+        case 2: item = byteCur << 2 | byteNext >> 6; break;
+        case 3: item = byteCur;                      break;
+        }
+        putchar(ptxchar[item & 0x3f]);
     }
+    putchar(5); putchar('\n');  /* end of row mark */
+}
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
+
+
+int
+main(int argc, const char ** argv)  {
+
+    FILE * ifP;
+    bit * bitrow;
+    int rows, cols, format;
+    unsigned int row;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else {
+        ifP = pm_openr(argv[1]);
+        
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument is "
+                     "the input fil name");
     }
 
-static void
-putitem( )
-    {
-    putchar( item );
-    bitsperitem = 0;
-    item = 64;
-    bitshift = 0;
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    bitrow = pbm_allocrow_packed(cols + 8);
+
+    bitrow[pbm_packed_bytes(cols)] = 0x00;
+
+    for (row = 0; row < rows; ++row) {
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
+        putBitrow(bitrow, cols);
     }
+
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
+    
+    return 0;
+}
+
+
+
diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c
index c6c4a9e6..14c6b85e 100644
--- a/converter/pbm/pbmtoxbm.c
+++ b/converter/pbm/pbmtoxbm.c
@@ -23,6 +23,7 @@
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 
 #include "pm_c_util.h"
@@ -35,7 +36,7 @@
 
 enum xbmVersion { X10, X11 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -46,8 +47,8 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+                 const char **       argv,
+                 struct CmdlineInfo *cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -58,7 +59,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;
@@ -76,7 +77,7 @@ parseCommandLine(int                 argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!nameSpec)
@@ -111,6 +112,7 @@ parseCommandLine(int                 argc,
             pm_error("Program takes zero or one argument (filename).  You "
                      "specified %u", argc-1);
     }
+    free(option_def);
 }
 
 
@@ -242,18 +244,22 @@ puttermX10(void) {
 
     unsigned int i;
 
+    assert(itemCnt % 2 == 0);
+
     for (i = 0; i < itemCnt; i += 2) {
         int rc;
 
+        assert(i + 1 < itemCnt);
+
         rc = printf("%s0x%02x%02x%s",
                     (i == 0) ? " " : "",
                     itemBuff[i+1],
                     itemBuff[i], 
-                    (i == itemCnt - 2) ? "" : ",");
+                    (i + 2 >= itemCnt) ? "" : ",");
         if (rc < 0)        
-            pm_error("Error writing end of X10 bitmap raster.  "
+            pm_error("Error writing Item %u at end of X10 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
-                     errno, strerror(errno));
+                     i, errno, strerror(errno));
     }
 }
 
@@ -270,12 +276,12 @@ puttermX11(void) {
         rc = printf("%s0x%02x%s",
                     (i == 0)  ? " " : "",
                     itemBuff[i],
-                    (i == itemCnt - 1) ? "" : ",");
+                    (i + 1 >= itemCnt) ? "" : ",");
 
         if (rc < 0)        
-            pm_error("Error writing end of X11 bitmap raster.  "
+            pm_error("Error writing Item %u at end of X11 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
-                     errno, strerror(errno));
+                     i, errno, strerror(errno));
     }
 }
 
@@ -319,8 +325,8 @@ writeXbmHeader(enum xbmVersion const xbmVersion,
                unsigned int    const height,
                FILE *          const ofP) {
 
-    printf("#define %s_width %d\n", name, width);
-    printf("#define %s_height %d\n", name, height);
+    printf("#define %s_width %u\n", name, width);
+    printf("#define %s_height %u\n", name, height);
     printf("static %s %s_bits[] = {\n",
            xbmVersion == X10 ? "short" : "char",
            name);
@@ -337,8 +343,7 @@ convertRaster(FILE *          const ifP,
               enum xbmVersion const xbmVersion) {
               
     unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8;   
-    unsigned int const padright =
-        ((cols + bitsPerUnit - 1 ) / bitsPerUnit) * bitsPerUnit - cols;
+    unsigned int const padright = ROUNDUP(cols, bitsPerUnit) - cols;
         /* Amount of padding to round cols up to the nearest multiple of 
            8 (if x11) or 16 (if x10).
         */
@@ -352,21 +357,15 @@ convertRaster(FILE *          const ifP,
     bitrow = pbm_allocrow_packed(cols + padright);
     
     for (row = 0; row < rows; ++row) {
-        int const bitrowInBytes = pbm_packed_bytes(cols);
-        int const padrightIn    = bitrowInBytes * 8 - cols;
-
         unsigned int i;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
 
-        if (padrightIn > 0) {
-            bitrow[bitrowInBytes - 1] >>= padrightIn;
-            bitrow[bitrowInBytes - 1] <<= padrightIn;
-        }
-
-        if (padright >= 8)
+        if (padright >= 8) {
+            assert(bitrowBytes > 0);
             bitrow[bitrowBytes-1] = 0x00;
-
+        }
         for (i = 0; i < bitrowBytes; ++i)
             putitem(bitrow[i]);
     }
@@ -379,15 +378,15 @@ convertRaster(FILE *          const ifP,
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int           argc,
+     const char ** argv) {
 
-    struct cmdlineInfo cmdline; 
+    struct CmdlineInfo cmdline; 
     FILE * ifP;
     int rows, cols, format;
     const char * name;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
     if (cmdline.name == NULL) 
@@ -409,3 +408,5 @@ main(int    argc,
     return 0;
 }
 
+
+
diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c
index 3fdd805d..27ce6cb1 100644
--- a/converter/pbm/pbmtoybm.c
+++ b/converter/pbm/pbmtoybm.c
@@ -19,26 +19,11 @@
 
 #include "pm.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
 #define YBM_MAGIC  ( ( '!' << 8 ) | '!' )
 #define INT16MAX 32767
 
-static long item;
-static int bitsperitem, bitshift;
-
-
-static void
-putitem(void) {
-
-    pm_writebigshort(stdout, item);
-
-    item        = 0;
-    bitsperitem = 0;
-    bitshift    = 0;
-}
-
-
-
 static void
 putinit(int const cols,
         int const rows) {
@@ -46,35 +31,6 @@ putinit(int const cols,
     pm_writebigshort(stdout, YBM_MAGIC);
     pm_writebigshort(stdout, cols);
     pm_writebigshort(stdout, rows);
-
-    item        = 0;
-    bitsperitem = 0;
-    bitshift    = 0;
-}
-
-
-
-static void
-putbit(bit const b) {
-
-    if (bitsperitem == 16)
-        putitem();
-
-    ++bitsperitem;
-
-    if (b == PBM_BLACK)
-        item += 1 << bitshift;
-
-    ++bitshift;
-}
-
-
-
-static void
-putrest(void) {
-
-    if (bitsperitem > 0)
-        putitem();
 }
 
 
@@ -87,51 +43,55 @@ main(int argc, const char *argv[]) {
     int rows;
     int cols;
     int format;
-    unsigned int padright;
     unsigned int row;
-    const char * inputFile;
+    const char * inputFileName;
 
     pm_proginit(&argc, argv);
 
     if (argc-1 < 1)
-        inputFile = "-";
+        inputFileName = "-";
     else {
-        inputFile = argv[1];
+        inputFileName = argv[1];
 
-        if (argc-1 > 2)
+        if (argc-1 > 1)
             pm_error("Too many arguments.  The only argument is the optional "
                      "input file name");
     }
 
-    ifP = pm_openr(inputFile);
+    ifP = pm_openr(inputFileName);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
 
     if (rows > INT16MAX || cols > INT16MAX)
         pm_error("Input image is too large.");
 
-    bitrow = pbm_allocrow(cols);
+    bitrow = pbm_allocrow_packed(cols + 8);
     
-    /* Compute padding to round cols up to the nearest multiple of 16. */
-    padright = ((cols + 15) / 16) * 16 - cols;
-
     putinit(cols, rows);
+
+    bitrow[pbm_packed_bytes(cols + 8) - 1] = 0x00;
     for (row = 0; row < rows; ++row) {
-        unsigned int col;
+        uint16_t *   const itemrow = (uint16_t *) bitrow;
+        unsigned int const itemCt   = (cols + 15) / 16;
+
+        unsigned int i;
 
-        pbm_readpbmrow(ifP, bitrow, cols, format);
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
 
-        for (col = 0; col < cols; ++col)
-            putbit(bitrow[col]);
+        for (i = 0; i < pbm_packed_bytes(cols); ++i)
+            bitrow[i] = bitreverse[bitrow[i]];
 
-        for (col = 0; col < padright; ++col)
-            putbit(0);
+        for (i = 0; i < itemCt; ++i)
+            pm_writebigshort(stdout, itemrow[i]);
     }
 
+    pbm_freerow_packed(bitrow);
+
     if (ifP != stdin)
         fclose(ifP);
 
-    putrest();
-
     return 0;
 }
+
+
diff --git a/converter/pbm/pbmtozinc.c b/converter/pbm/pbmtozinc.c
index 2df39f0d..66ec5582 100644
--- a/converter/pbm/pbmtozinc.c
+++ b/converter/pbm/pbmtozinc.c
@@ -1,4 +1,4 @@
-/* pbmtozinc.c - read a portable bitmap and produce an bitmap file
+/* pbmtozinc.c - read a PBM image and produce a bitmap file
 **               in the format used by the Zinc Interface Library (v1.0)
 **               November 1990.
 **
@@ -21,108 +21,163 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "mallocvar.h"
 #include "nstring.h"
 #include "pbm.h"
 
-int
-main(int argc, char * argv[]) {
-
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row;
-    register int col;
-    char name[100];
-    char* cp;
-    int itemsperline;
-    register int bitsperitem;
-    register int item;
-    int firstitem;
-    const char * const hexchar = "084c2a6e195d3b7f";
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	{
-        ifp = pm_openr( argv[1] );
-        strcpy( name, argv[1] );
-        if ( streq( name, "-" ) )
-            strcpy( name, "noname" );
-
-        if ( ( cp = strchr( name, '.' ) ) != 0 )
+static void
+parseCommandLine(int           const argc,
+                 const char ** const argv,
+                 const char ** const inputFileNameP) {
+
+    if (argc-1 > 0) {
+        *inputFileNameP = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("To many arguments: %u.  "
+                     "The only possible argument is the "
+                     "name of the input file", argc-1);
+    } else
+        *inputFileNameP = "-";
+}
+
+
+
+static const char *
+imageName(const char * const inputFileName) {
+/*----------------------------------------------------------------------------
+   The image name to put in the Zinc file, based on the input file name
+   'inputFileName' ("-" to indicate Standard Input).
+
+   Result is newly malloc'ed space that Caller must free.
+-----------------------------------------------------------------------------*/
+    const char * retval;
+
+    if (streq(inputFileName, "-"))
+        pm_asprintf(&retval, "noname");
+    else {
+        char * nameBuf;
+        char * cp;
+
+        MALLOCARRAY_NOFAIL(nameBuf, strlen(inputFileName) + 1);
+
+        strcpy(nameBuf, inputFileName);
+
+        cp = strchr(nameBuf, '.' );
+        if (cp)
             *cp = '\0';
-	}
-    else
-	{
-        ifp = stdin;
-        strcpy( name, "noname" );
-	}
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-
-    /* Compute padding to round cols up to the nearest multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
-
-    printf( "USHORT %s[] = {\n",name);
-    printf( "  %d\n", cols );
-    printf( "  %d\n", rows );
-
-    itemsperline = 0;
-    bitsperitem = 0;
-    item = 0;
-    firstitem = 1;
-
-#define PUTITEM \
-    { \
-    if ( firstitem ) \
-	firstitem = 0; \
-    else \
-	putchar( ',' ); \
-    if ( itemsperline == 11 ) \
-	{ \
-	putchar( '\n' ); \
-	itemsperline = 0; \
-	} \
-    if ( itemsperline == 0 ) \
-	putchar( ' ' ); \
-    ++itemsperline; \
-    putchar('0'); \
-    putchar('x'); \
-    putchar(hexchar[item & 15]); \
-    putchar(hexchar[(item >> 4) & 15]); \
-    putchar(hexchar[(item >> 8) & 15]); \
-    putchar(hexchar[item >> 12]); \
-    bitsperitem = 0; \
-    item = 0; \
+
+        retval = nameBuf;
     }
+    return retval;
+}
 
-#define PUTBIT(b) \
-    { \
-    if ( bitsperitem == 16 ) \
-	PUTITEM; \
-    if ( (b) == PBM_BLACK ) \
-	item += 1 << bitsperitem; \
-    ++bitsperitem; \
+
+
+typedef struct {
+    unsigned int itemsperline;
+    uint16_t     item;
+    unsigned int firstitem;
+} Packer;
+
+
+
+static void
+packer_init(Packer * const packerP) {
+
+    packerP->itemsperline = 0;
+    packerP->firstitem = 1;
+}
+
+
+
+static void
+packer_putitem(Packer * const packerP) {
+
+    if (packerP->firstitem)
+        packerP->firstitem = 0;
+    else
+        putchar(',');
+
+    if (packerP->itemsperline == 11) {
+        putchar('\n');
+        packerP->itemsperline = 0;
     }
+    if (packerP->itemsperline == 0)
+        putchar(' ');
+
+    ++packerP->itemsperline;
+    printf ("0x%02x%02x", packerP->item & 255, packerP->item >> 8);
 
-    for ( row = 0; row < rows; ++row )
-	{
-        pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-            PUTBIT( *bP );
-        for ( col = 0; col < padright; ++col )
-            PUTBIT( 0 );
+}
+
+
+
+static void
+writeRaster(FILE *       const ifP,
+            unsigned int const rows,
+            unsigned int const cols,
+            int          const format) {
+
+    bit * const bitrow = pbm_allocrow_packed(cols + 8);
+
+    Packer packer;
+    unsigned int row;
+
+    packer_init(&packer);
+
+    bitrow[pbm_packed_bytes(cols+8) -1 ] = 0x00;
+
+    for (row = 0; row < rows; ++row) {
+        uint16_t * const itemrow = (uint16_t *) bitrow;
+        unsigned int const itemCt = (cols + 15 ) / 16;
+
+        unsigned int i;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+        pbm_cleanrowend_packed(bitrow, cols);
+
+        for (i = 0; i < itemCt; ++i) {
+            packer.item = itemrow[i];
+            packer_putitem(&packer);
+        }
     }
+    pbm_freerow_packed(bitrow);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    const char * inputFileName;
+    FILE * ifP;
+    int rows, cols;
+    int format;
+    const char * name;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &inputFileName);
+
+    ifP = pm_openr(inputFileName);
+
+    name = imageName(inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    printf("USHORT %s[] = {\n", name);
+    printf("  %d\n", cols);
+    printf("  %d\n", rows);
+
+    writeRaster(ifP, rows, cols, format);
+
+    printf("};\n");
+
+    pm_close(ifP);
 
-    pm_close( ifp );
-    
-    if ( bitsperitem > 0 )
-        PUTITEM;
-    printf( "};\n" );
+    pm_strfree(name);
 
     return 0;
 }
diff --git a/converter/pbm/pi3topbm.c b/converter/pbm/pi3topbm.c
index 8b3b21e3..17b07d6f 100644
--- a/converter/pbm/pi3topbm.c
+++ b/converter/pbm/pi3topbm.c
@@ -22,91 +22,147 @@
  */
 
 #include <stdio.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pbm.h"
 
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* Filename of input file */
+    unsigned int debug;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 const char ** argv, 
+                 struct CmdlineInfo * const cmdlineP) {
+/* --------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   If command line is internally inconsistent (invalid options, etc.),
+   issue error message to stderr and abort program.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+--------------------------------------------------------------------------*/
+    optEntry * option_def;
+    optStruct3 opt;
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
+    unsigned int option_def_index;
+  
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "debug",    OPT_FLAG,    NULL,       &cmdlineP->debug,       0);
+  
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1) 
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Program takes zero or one argument (filename).  You "
+                     "specified %u", argc-1);
+    }
+}
+
+
+
+static void
+readAndValidateHeader(FILE * const ifP,
+                      bool   const debug,
+                      bool * const reverseP) {
+
+    short item;
+
+    pm_readbigshort(ifP, &item);
+
+    if (debug)
+        pm_message("resolution is %d", item);
+
+    /* only handles hi-rez 640x400 */
+    if (item != 2)
+        pm_error("bad resolution %d", item);
+
+    pm_readbigshort(ifP, &item);
+
+    *reverseP = (item == 0);
+
+    {
+        unsigned int i;
+
+        for (i = 1; i < 16; ++i)
+            pm_readbigshort (ifP, &item);
+    }
+}
+
+
+
 int
-main(argc, argv)
-	int             argc;
-	char           *argv[];
-{
-	int             debug = 0;
-	FILE           *f;
-	int             x;
-	int             i, k;
-	int             c;
-	int		rows, cols;
-	bit		*bitrow;
-	short res;
-	int black, white;
-	const char * const usage = "[-debug] [pi3file]";
-	int argn = 1;
-
-	pbm_init( &argc, argv );
-
-	while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0')
-	  {
-	    if (pm_keymatch(argv[1], "-debug", 2))
-	      debug = 1;
-	    else
-	      pm_usage (usage);
-	    ++argn;
-	  }
-
-	if (argn == argc)
-	    f = stdin;
-	else
-	  {
-	    f = pm_openr (argv[argn]);
-	    ++argn;
-	  }
-
-	if (argn != argc)
-	  pm_usage (usage);
-
-	if (pm_readbigshort (f, &res) == -1)
-		pm_error ("EOF / read error");
-
-	if (debug)
-		pm_message ("resolution is %d", res);
-
-	/* only handles hi-rez 640x400 */
-	if (res != 2)
-		pm_error( "bad resolution" );
-
-	pm_readbigshort (f, &res);
-	if (res == 0)
-	  {
-	    black = PBM_WHITE;
-	    white = PBM_BLACK;
-	  }
-	else
-	  {
-	    black = PBM_BLACK;
-	    white = PBM_WHITE;
-	  }
-
-	for (i = 1; i < 16; i++)
-	  if (pm_readbigshort (f, &res) == -1)
-	    pm_error ("EOF / read error");
-
-	cols = 640;
-	rows = 400;
-	pbm_writepbminit( stdout, cols, rows, 0 );
-	bitrow = pbm_allocrow( cols );
-
-	for (i = 0; i < rows; ++i) {
-		x = 0;
-		while (x < cols) {
-			if ((c = getc(f)) == EOF)
-				pm_error( "end of file reached" );
-			for (k = 0x80; k; k >>= 1) {
-				bitrow[x] = (k & c) ? black : white;
-				++x;
-			}
-		}
-		pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-	pm_close( f );
-	pm_close( stdout );
-	exit(0);
+main(int argc, const char ** argv) {
+
+    unsigned int const rows = 400;
+    unsigned int const cols = 640;
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    unsigned int row;
+    bit * bitrow;
+    bool reverse;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    readAndValidateHeader(ifP, cmdline.debug, &reverse);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+
+    bitrow = pbm_allocrow_packed(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const colChars = cols / 8;
+
+        unsigned int bytesReadCt;
+
+        bytesReadCt = fread(bitrow, cols / 8, 1, ifP);
+        if (bytesReadCt != 1) {
+            if (feof(ifP))
+                pm_error( "EOF reached while reading image data" );
+            else
+                pm_error("read error while reading image data");
+        }
+
+        if (reverse) {
+            /* flip all pixels */
+            unsigned int colChar;
+            for (colChar = 0; colChar < colChars; ++colChar)
+                bitrow[colChar] = ~bitrow[colChar];
+        }
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
 }
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index 0cbebc5e..bbf4e395 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -362,12 +362,8 @@ main(int    argc,
         
         for (i = 0; i < bytesPerRow; ++i)
             bitrow[i] = bitreverse[*p++];
-            
-        if (cols % 8 > 0) {
-            bitrow[bytesPerRow-1] >>= 8 - cols % 8;
-            bitrow[bytesPerRow-1] <<= 8 - cols % 8;
-        }
-            
+
+        pbm_cleanrowend_packed(bitrow, cols);
         pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
 
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index 3d012483..2a429086 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -12,23 +12,17 @@
 
 #include "pm.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
 static short const ybmMagic = ( ( '!' << 8 ) | '!' );
 
 
 
-
-static int item;
-static int bitsInBuffer, bitshift;
-
-
-
 static void
 getinit(FILE *  const ifP,
         short * const colsP,
         short * const rowsP,
-        short * const depthP,
-        short * const padrightP) {
+        short * const depthP) {
 
     short magic;
     int rc;
@@ -49,31 +43,10 @@ getinit(FILE *  const ifP,
         pm_error("EOF / read error");
 
     *depthP = 1;
-    *padrightP = ((*colsP + 15) / 16) * 16 - *colsP;
 }
 
 
 
-static bit
-getbit(FILE * const ifP) {
-
-    bit b;
-
-    if (bitsInBuffer == 0) {
-        item = (getc(ifP) << 8) | (getc(ifP) << 0);
-
-        if (item == EOF)
-            pm_error("EOF / read error");
-
-        bitsInBuffer = 16;
-        bitshift = 0;
-    }
-
-    b = ((item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE;
-    --bitsInBuffer;
-    ++bitshift;
-    return b;
-}
 
 
 
@@ -82,7 +55,7 @@ main(int argc, const char * argv[]) {
 
     FILE * ifP;
     bit * bitrow;
-    short rows, cols, padright;
+    short rows, cols;
     unsigned int row;
     short depth;
     const char * inputFile;
@@ -94,36 +67,42 @@ main(int argc, const char * argv[]) {
     else {
         inputFile = argv[1];
 
-        if (argc-1 > 2)
+        if (argc-1 > 1)
             pm_error("Too many arguments.  The only argument is the optional "
                      "input file name");
     }
 
     ifP = pm_openr(inputFile);
 
-    bitsInBuffer = 0;
-
-    getinit(ifP, &cols, &rows, &depth, &padright);
+    getinit(ifP, &cols, &rows, &depth);
     if (depth != 1)
         pm_error("YBM file has depth of %u, must be 1", (unsigned)depth);
     
     pbm_writepbminit(stdout, cols, rows, 0);
 
-    bitrow = pbm_allocrow(cols);
+    bitrow = pbm_allocrow_packed(cols + 8);
 
     for (row = 0; row < rows; ++row) {
+        uint16_t *   const itemrow = (uint16_t *) bitrow;
+        unsigned int const itemCt  = (cols + 15) / 16;
+
+        unsigned int i;
+
         /* Get raster. */
-        unsigned int col;
+        for (i = 0; i < itemCt; ++i) {
+            short int item;
+            pm_readbigshort(ifP, &item);
+            itemrow[i] = (uint16_t) item; 
+        }
 
-        for (col = 0; col < cols; ++col)
-            bitrow[col] = getbit(ifP);
+        for (i = 0; i < pbm_packed_bytes(cols); ++i)
+            bitrow[i] = bitreverse[bitrow[i]];
 
-        /* Discard line padding */
-        for (col = 0; col < padright; ++col)
-            getbit(ifP);
-        pbm_writepbmrow(stdout, bitrow, cols, 0);
+        pbm_cleanrowend_packed(bitrow, cols);
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
 
+    pbm_freerow_packed(bitrow);
     pm_close(ifP);
     pm_close(stdout);
 
diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c
index 93b3605b..83a93441 100644
--- a/converter/ppm/ppmtoarbtxt.c
+++ b/converter/ppm/ppmtoarbtxt.c
@@ -225,8 +225,9 @@ writeIcol(FILE *           const ofP,
     */
 
     struct Icdat * const icdataP = &objectP->odata.icolData;
-    unsigned int const outValue = icdataP->icolmin +
-        ROUNDU(((double) icdataP->icolmax - icdataP->icolmin) * value);
+    unsigned int const outValue =
+        ROUNDU( icdataP->icolmin +
+                ((double)icdataP->icolmax - icdataP->icolmin) * value);
 
     fprintf(ofP, icdataP->icformat, outValue);
 }
@@ -470,7 +471,7 @@ validateFormatWithPpf(const char *       const format,
 
     default:
         pm_asprintf(errorP, "Has %lu extra transformation%s ",
-                    n-1, n-1 > 1 ? "s" : "");
+                    (unsigned long)n-1, n-1 > 1 ? "s" : "");
         break;
     }
 }
diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c
index 24b1b3e5..6d65d744 100644
--- a/converter/ppm/ppmtobmp.c
+++ b/converter/ppm/ppmtobmp.c
@@ -20,6 +20,7 @@
 #include <string.h>
 
 #include "pm_c_util.h"
+#include "nstring.h"
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "bmp.h"
@@ -131,13 +132,22 @@ parseCommandLine(int argc, const char ** argv,
         cmdlineP->mapfile = NULL;
 
     if (argc - 1 == 0)
-        cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
+        cmdlineP->inputFilename = pm_strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
-        cmdlineP->inputFilename = strdup(argv[1]);
+        cmdlineP->inputFilename = pm_strdup(argv[1]);
     else 
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specificaton");
 
+    free(option_def);
+}
+
+
+
+static void
+freeCommandLine(struct CmdlineInfo const cmdline) {
+
+    pm_strfree(cmdline.inputFilename);
 }
 
 
@@ -821,7 +831,6 @@ doPbm(FILE *       const ifP,
         32 bit borders and that in BMP the bottom row comes first in
         order.
     */
-    int const CHARBITS = (sizeof(unsigned char)*8); 
     int const colChars = pbm_packed_bytes(cols);
     int const adjustedCols = (cols+31) /32 * 32;
     int const packedBytes  =  adjustedCols /8;
@@ -853,11 +862,8 @@ doPbm(FILE *       const ifP,
            some BMP viewers may get confused with that.
         */
 
-        if (cols % 8 >0) {
-            /* adjust final partial byte */
-            thisRow[colChars-1] >>= CHARBITS - cols % CHARBITS;
-            thisRow[colChars-1] <<= CHARBITS - cols % CHARBITS;
-        }
+        /* Clean off remainder of fractional last character */
+        pbm_cleanrowend_packed(thisRow, cols);
     }
 
     bmpEncodePbm(ofP, class, cols, rows, bitrow);
@@ -907,6 +913,8 @@ doPgmPpm(FILE *       const ifP,
               cols, rows, (const pixel**)pixels, maxval, &colorMap);
     
     freeColorMap(&colorMap);
+
+    ppm_freearray(pixels, rows);
 }
 
 
@@ -937,6 +945,8 @@ main(int           argc,
                  cmdline.class, cmdline.bppSpec, cmdline.bpp, cmdline.mapfile,
                  stdout);
 
+    freeCommandLine(cmdline);
+
     pm_close(ifP);
     pm_close(stdout);
 
diff --git a/converter/ppm/ppmtoicr.c b/converter/ppm/ppmtoicr.c
index feca0c18..3c8be421 100644
--- a/converter/ppm/ppmtoicr.c
+++ b/converter/ppm/ppmtoicr.c
@@ -10,311 +10,255 @@
 ** implied warranty.
 */
 
+#include <stdbool.h>
+#include <assert.h>
 #include "ppm.h"
 
-#define MAXCOLORS 256
-#define CLUTCOLORS 768
+#define MAXCOLORCT 256
+#define CLUTCOLORCT 768
 
-static int colorstobpp ARGS(( int colors ));
-static int GetPixel ARGS(( int x, int y ));
-static int rleit ARGS(( char* buf, char* bufto, int len ));
 
-static pixel** pixels;
-static colorhash_table cht;
-static char* testimage;
 
-int
-main(argc, argv)
-int argc;
-char* argv[];
-{
-	FILE* ifp;
-	int argn, rows, cols, colors, i, j, BitsPerPixel, newxsize;
-	pixval maxval;
-	colorhist_vector chv;
-	char rgb[CLUTCOLORS];
-	const char* windowname;
-	char* thischar;
-	char* thisline;
-	char* space;
-	register unsigned char c;
-	register char* p;
-	int display, expand;
-	int rleflag, winflag;
-	const char* const usage = "[-windowname windowname] [-expand expand] [-display display] [-rle] [ppmfile]";
-
-
-	ppm_init( &argc, argv );
-
-	argn = 1;
-	windowname = "untitled";
-	winflag = 0;
-	expand = 1;
-	display = 0;
-	rleflag = 0;
-
-	while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	    {
-	    if ( pm_keymatch(argv[argn],"-windowname",2) && argn + 1 < argc )
-		{
-		++argn;
-		windowname = argv[argn];
-		winflag = 1;
-		}
-	    else if ( pm_keymatch(argv[argn],"-expand",2) && argn + 1 < argc )
-		{
-		++argn;
-		if ( sscanf( argv[argn], "%d",&expand ) != 1 )
-		    pm_usage( usage );
-		}
-	    else if ( pm_keymatch(argv[argn],"-display",2) && argn + 1 < argc )
-		{
-		++argn;
-		if ( sscanf( argv[argn], "%d",&display ) != 1 )
-		    pm_usage( usage );
-		}
-	    else if ( pm_keymatch(argv[argn],"-rle",2) )
-		rleflag = 1;
-	    else if ( pm_keymatch(argv[argn],"-norle",2) )
-		rleflag = 0;
-	    else
-		pm_usage( usage );
-	    }
-
-	if ( argn < argc )
-	    {
-	    ifp = pm_openr( argv[argn] );
-	    if ( ! winflag )
-		windowname = argv[argn];
-	    ++argn;
-	    }
-	else
-	    ifp = stdin;
-
-	if ( argn != argc )
-	    pm_usage( usage );
-
-	pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
-
-	pm_close( ifp );
-
-	for (i = 0; i < CLUTCOLORS; i++)
-	    rgb[i] = 0;
-
-	/* Figure out the colormap. */
-	pm_message("computing colormap..." );
-	chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
-	if (chv == (colorhist_vector) 0)
-	pm_error( "too many colors - try doing a 'pnmquant %d'", MAXCOLORS );
-	pm_message("%d colors found", colors );
-
-	/* Turn the ppm colormap into an ICR colormap. */
-	if (maxval > 255)
-	pm_message(
-		"maxval is not 255 - automatically rescaling colors" );
-	for (i = 0; i < colors; i++)
-	{
-	j = (3 * i);
-	if (maxval == 255)
-		{
-		rgb[j] = PPM_GETR(chv[i].color) ;
-		j++;
-		rgb[j] = PPM_GETG(chv[i].color) ;
-		j++;
-		rgb[j] = PPM_GETB(chv[i].color) ;
-		}
-	else
-		{
-		rgb[j] = (int) PPM_GETR(chv[i].color) * 255 / maxval;
-		j++;
-		rgb[j] = (int) PPM_GETG(chv[i].color) * 255 / maxval;
-		j++;
-		rgb[j] = (int) PPM_GETB(chv[i].color) * 255 / maxval;
-		}
-	}
-	BitsPerPixel = colorstobpp(colors);
-
-	/* And make a hash table for fast lookup. */
-	cht = ppm_colorhisttocolorhash(chv, colors);
-	ppm_freecolorhist(chv);
-
-
-	/************** Create a new window using ICR protocol *********/
-	/* Format is "ESC^W;left;top;width;height;display;windowname"  */
-
-	pm_message("creating window %s ...", windowname );
-	(void)printf("\033^W;%d;%d;%d;%d;%d;%s^",0,0,cols*expand,rows*expand,display,windowname);
-	fflush(stdout);
-
-
-	/****************** Download the colormap.  ********************/
-	pm_message("downloading colormap for %s ...", windowname );
-
-	(void)printf("\033^M;%d;%d;%d;%s^",0,MAXCOLORS,CLUTCOLORS,windowname);
-	thischar = rgb;
-	for (j=0; j<CLUTCOLORS; j++) {
-	c = *thischar++;
-		if (c > 31 && c < 123 ) {	 /* printable ASCII */
-		putchar(c);
-		}
-		else {
-		putchar((c>>6)+123);	 /* non-printable, so encode it */
-		putchar((c & 0x3f) + 32);
-		}
-	}
-	fflush(stdout);
-
-	/**************** send out picture *************************/
-	/* Protocol's RLE scheme is quicker but buggy              */
-
-	if (rleflag) {	
-		pm_message("sending run-length encoded picture data ..." );
-		testimage = (char*) malloc(rows*cols);
-		p = testimage;
-		for (i=0; i<rows; i++)
-			for (j=0; j<cols; j++) 
-			*p++ = GetPixel(j,i);
-		space = (char*) malloc(rows*3);
-		thisline = testimage;
-		for (i = 0; i < rows; i++) {
-			newxsize = rleit(thisline,space,cols);
-			thisline += cols;	/* increment to next line */
-		(void)printf("\033^R;%d;%d;%d;%d;%s^",0,i*expand,expand,newxsize,windowname);
-		thischar = space;
-		for (j=0; j< newxsize; j++) {
-			c= *thischar++;  /*get byte to send */
-			if (c>31 && c <123) {
-				putchar(c);
-				}
-			else {
-				putchar((c>>6) + 123);
-				putchar((c & 0x3f) + 32);
-				}
-			}
-			fflush(stdout);
-		}
-		free(space);
-		exit(0);
-		}
-
-	/* Otherwise, send out uncompressed pixel data via the slow method */
-
-		else {
-		pm_message("sending picture data ..." );
-		for (i = 0; i < rows; i++) {
-			(void)printf("\033^P;%d;%d;%d;%d;%s^",0,i*expand,expand,cols,windowname);
-			for (j = 0; j < cols; j++) {
-				c  = GetPixel(j,i);
-				if (c > 31 && c < 123) {
-						putchar(c);
-						}
-				else		{
-						putchar((c>>6)+123);
-						putchar((c & 0x3f) + 32);
-						}
-				}
-			}
-		fflush(stdout);
-		exit(0);
-		}
-	}
+static void
+makeIcrColormap(colorhist_vector const chv,
+                unsigned int     const colorCt,
+                pixval           const maxval,
+                char *           const rgb) {
+
+    unsigned int i;
+
+    if (maxval > 255)
+        pm_message("Maxval is not 255 - automatically rescaling colors" );
+
+    for (i = 0; i < CLUTCOLORCT; ++i)
+        rgb[i] = 0;
+
+    for (i = 0; i < colorCt; ++i) {
+        unsigned int j;
+
+        j = (3 * i);
+
+        if (maxval == 255) {
+            rgb[j++] = PPM_GETR(chv[i].color) ;
+            rgb[j++] = PPM_GETG(chv[i].color) ;
+            rgb[j++] = PPM_GETB(chv[i].color) ;
+        } else {
+            rgb[j++] = (unsigned int) PPM_GETR(chv[i].color) * 255 / maxval;
+            rgb[j++] = (unsigned int) PPM_GETG(chv[i].color) * 255 / maxval;
+            rgb[j++] = (unsigned int) PPM_GETB(chv[i].color) * 255 / maxval;
+        }
+    }
+}
+
+
 
 static int
-colorstobpp(colors)
-int colors;
-	{
-	int bpp;
-
-	if (colors <= 2)
-	bpp = 1;
-	else if (colors <= 4)
-	bpp = 2;
-	else if (colors <= 8)
-	bpp = 3;
-	else if (colors <= 16)
-	bpp = 4;
-	else if (colors <= 32)
-	bpp = 5;
-	else if (colors <= 64)
-	bpp = 6;
-	else if (colors <= 128)
-	bpp = 7;
-	else if (colors <= 256)
-	bpp = 8;
-	else
-	pm_error("can't happen" );
-	return bpp;
-	}
+bppFromColorCt(unsigned int const colorCt) {
+
+    unsigned int bpp;
+
+    if (colorCt <= 2)
+        bpp = 1;
+    else if (colorCt <= 4)
+        bpp = 2;
+    else if (colorCt <= 8)
+        bpp = 3;
+    else if (colorCt <= 16)
+        bpp = 4;
+    else if (colorCt <= 32)
+        bpp = 5;
+    else if (colorCt <= 64)
+        bpp = 6;
+    else if (colorCt <= 128)
+        bpp = 7;
+    else if (colorCt <= 256)
+        bpp = 8;
+    else
+        assert(false);
+
+    return bpp;
+}
+
+
 
 static int
-GetPixel(x, y)
-int x, y;
-	{
-	int color;
+colorIndexAtPosition(unsigned int    const x,
+                     unsigned int    const y,
+                     pixel **        const pixels,
+                     colorhash_table const cht) {
 
-	color = ppm_lookupcolor(cht, &pixels[y][x]);
-	return color;
-	}
+    int rc;
 
+    rc = ppm_lookupcolor(cht, &pixels[y][x]);
 
-/* rleit   compress with run length encoding as per NCSA's documentation */
+    /* Every color in the image is in the palette */
+    assert(rc >= 0);
 
-static int
-rleit(buf,bufto,len)
-	char* buf;
-	char* bufto;
-	int len;
-	{
-	register char* p;
-	register char* q;
-	register char* cfoll;
-	register char* clead;
-	char* begp;
-	int i;
-
-	p = buf;
-	cfoll = bufto;
-	clead = cfoll + 1;
-
-	begp = p;
-	while (len > 0 ) {		/* encode until gone */
-		
-		q = p + 1;
-		i = len-1;
-	while (*p == *q && i+120 > len && i) {
-		q++;
-		i--;
-	}
-
-	if (q > p +2) {			/* three in a row */
-		if (p > begp) {
-			*cfoll = p - begp;
-			cfoll = clead;
-		}
-		*cfoll++ = 128 | (q-p);		/*len of seq*/
-		*cfoll++ = *p;			/* char of seq */
-		len -= q-p;		/* subtract len of seq */
-		p = q;
-		clead = cfoll+1;
-		begp = p;
-	}
-	else {
-		*clead++ = *p++;	/* copy one char */
-		len--;
-		if (p>begp + 120) {
-			*cfoll = p - begp;
-			cfoll = clead++;
-			begp = p;
-		}
-	}
-	}
-
-/* fillin last bytecount */
-
-	if (p>begp)
-		*cfoll = (p - begp);
-	else
-		clead--;
-
-	return((int) (clead-bufto));	/*how many stored as encoded */
+    return rc;
 }
+
+
+
+static void
+downloadColormap(char         const rgb[CLUTCOLORCT],
+                 const char * const windowName) {
+
+    unsigned int i;
+
+    pm_message("Downloading colormap for %s ...", windowName);
+
+    printf("\033^M;%d;%d;%d;%s^",
+           0, MAXCOLORCT, CLUTCOLORCT, windowName);
+
+    for (i = 0; i < CLUTCOLORCT; ++i) {
+        unsigned char const c = rgb[i];
+
+        if (c > 31 && c < 123) {
+            /* printable ASCII */
+            putchar(c);
+        } else {
+            /* non-printable, so encode it */
+            putchar((c >> 6) + 123);
+            putchar((c & 0x3f) + 32);
+        }
+    }
+    fflush(stdout);
+}
+
+
+
+static void
+sendOutPicture(pixel **        const pixels,
+               unsigned int    const rows,
+               unsigned int    const cols,
+               colorhash_table const cht,
+               int             const expand,
+               const char *    const windowName) {
+
+    unsigned int row;
+
+    pm_message("Sending picture data ..." );
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        printf("\033^P;%d;%d;%d;%d;%s^",
+               0, row * expand, expand, cols, windowName);
+        for (col = 0; col < cols; ++col) {
+            unsigned char const c =
+                colorIndexAtPosition(col, row, pixels, cht);
+            if (c > 31 && c < 123) {
+                putchar(c);
+            } else {
+                putchar((c >> 6) + 123);
+                putchar((c & 0x3f) + 32);
+            }
+        }
+    }
+    fflush(stdout);
+}
+
+
+
+int
+main(int argc, const char ** const argv) {
+
+    FILE * ifP;
+    int rows, cols;
+    int colorCt;
+    int argn;
+    unsigned int bitsPerPixel;
+    pixval maxval;
+    colorhist_vector chv;
+    char rgb[CLUTCOLORCT];
+    const char * windowName;
+    int display, expand;
+    int winflag;
+    const char* const usage = "[-windowname windowname] [-expand expand] [-display display] [ppmfile]";
+    pixel** pixels;
+    colorhash_table cht;
+
+    pm_proginit(&argc, argv);
+
+    argn = 1;
+    windowName = "untitled";
+    winflag = 0;
+    expand = 1;
+    display = 0;
+
+    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+    {
+        if ( pm_keymatch(argv[argn],"-windowname",2) && argn + 1 < argc )
+        {
+            ++argn;
+            windowName = argv[argn];
+            winflag = 1;
+        }
+        else if ( pm_keymatch(argv[argn],"-expand",2) && argn + 1 < argc )
+        {
+            ++argn;
+            if ( sscanf( argv[argn], "%d",&expand ) != 1 )
+                pm_usage( usage );
+        }
+        else if ( pm_keymatch(argv[argn],"-display",2) && argn + 1 < argc )
+        {
+            ++argn;
+            if ( sscanf( argv[argn], "%d",&display ) != 1 )
+                pm_usage( usage );
+        }
+        else
+            pm_usage( usage );
+    }
+
+    if ( argn < argc )
+    {
+        ifP = pm_openr( argv[argn] );
+        if ( ! winflag )
+            windowName = argv[argn];
+        ++argn;
+    }
+    else
+        ifP = stdin;
+
+    if ( argn != argc )
+        pm_usage( usage );
+
+    pixels = ppm_readppm(ifP, &cols, &rows, &maxval);
+
+    pm_close(ifP);
+
+    /* Figure out the colormap. */
+    pm_message("Computing colormap..." );
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORCT, &colorCt);
+    if (!chv)
+        pm_error("Too many colors - try doing a 'pnmquant %u'", MAXCOLORCT);
+    pm_message("%u colors found", colorCt );
+
+    makeIcrColormap(chv, colorCt, maxval, rgb);
+
+    bitsPerPixel = bppFromColorCt(colorCt);
+
+    /* And make a hash table for fast lookup. */
+    cht = ppm_colorhisttocolorhash(chv, colorCt);
+
+    ppm_freecolorhist(chv);
+
+    /************** Create a new window using ICR protocol *********/
+    /* Format is "ESC^W;left;top;width;height;display;windowname"  */
+
+    pm_message("Creating window %s ...", windowName);
+
+    printf("\033^W;%d;%d;%d;%d;%d;%s^",
+           0, 0, cols * expand, rows * expand, display, windowName);
+    fflush(stdout);
+
+    /****************** Download the colormap.  ********************/
+
+    downloadColormap(rgb, windowName);
+
+    sendOutPicture(pixels, rows, cols, cht, expand, windowName);
+
+    return 0;
+}
+
+
+
diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile
index 49aeb7f8..eeab9727 100644
--- a/converter/ppm/ppmtompeg/Makefile
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -31,9 +31,6 @@ endif
 #	1) long's are 32 bits and
 #	2) int's are not
 #
-# if you are using a non-ANSI compiler, then use:
-#	-DNON_ANSI_COMPILER
-#
 # one other option:
 #	-DHEINOUS_DEBUG_MODE
 #
diff --git a/converter/ppm/ppmtompeg/headers/all.h b/converter/ppm/ppmtompeg/headers/all.h
index 5c559528..8f095d8e 100644
--- a/converter/ppm/ppmtompeg/headers/all.h
+++ b/converter/ppm/ppmtompeg/headers/all.h
@@ -80,7 +80,6 @@
 #include <time.h>
 #endif
 
-#include "ansi.h"
 #include "general.h"
 
 /* some machines have #define index strchr; get rid of this nonsense */
diff --git a/converter/ppm/ppmtompeg/headers/ansi.h b/converter/ppm/ppmtompeg/headers/ansi.h
deleted file mode 100644
index b3c3ab17..00000000
--- a/converter/ppm/ppmtompeg/headers/ansi.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*===========================================================================*
- * ansi.h								     *
- *									     *
- *	macro for non-ansi compilers					     *
- *									     *
- *===========================================================================*/
-
-/*
- * Copyright (c) 1995 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-/*  
- *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/ansi.h,v 1.6 1995/08/15 23:43:13 smoot Exp $
- *  $Log: ansi.h,v $
- *  Revision 1.6  1995/08/15 23:43:13  smoot
- *  *** empty log message ***
- *
- *  Revision 1.5  1995/01/19 23:54:35  eyhung
- *  Changed copyrights
- *
- * Revision 1.4  1994/11/12  02:12:13  keving
- * nothing
- *
- * Revision 1.3  1993/07/22  22:24:23  keving
- * nothing
- *
- * Revision 1.2  1993/07/09  00:17:23  keving
- * nothing
- *
- * Revision 1.1  1993/06/14  22:50:22  keving
- * nothing
- *
- */
-
-
-#ifndef ANSI_INCLUDED
-#define ANSI_INCLUDED
-
-
-/*  
- *  _ANSI_ARGS_ macro stolen from Tcl6.5 by John Ousterhout
- */
-#undef _ANSI_ARGS_
-#undef const
-#ifdef NON_ANSI_COMPILER
-#define _ANSI_ARGS_(x)       ()
-#define CONST
-#else
-#define _ANSI_ARGS_(x)   x
-#define CONST const
-#ifdef __cplusplus
-#define VARARGS (...)
-#else
-#define VARARGS ()
-#endif
-#endif
-
-
-#endif /* ANSI_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/bitio.h b/converter/ppm/ppmtompeg/headers/bitio.h
index a24c21cd..931bcdd9 100644
--- a/converter/ppm/ppmtompeg/headers/bitio.h
+++ b/converter/ppm/ppmtompeg/headers/bitio.h
@@ -63,7 +63,6 @@
 #include <stdio.h>
 
 #include "general.h"
-#include "ansi.h"
 
 
 /*===========*
diff --git a/converter/ppm/ppmtompeg/headers/dct.h b/converter/ppm/ppmtompeg/headers/dct.h
index d5ea9f4a..3b824cf0 100644
--- a/converter/ppm/ppmtompeg/headers/dct.h
+++ b/converter/ppm/ppmtompeg/headers/dct.h
@@ -31,7 +31,6 @@
 #define DCT_INCLUDED
 
 
-#include "ansi.h"
 
 
 
@@ -47,12 +46,12 @@ typedef DCTELEM DCTBLOCK_2D[DCTSIZE][DCTSIZE];
 /*  
  *  from mfwddct.c:
  */
-void init_fdct _ANSI_ARGS_((void));
-extern void mp_fwd_dct_block2 _ANSI_ARGS_((DCTBLOCK_2D src, DCTBLOCK_2D dest));
+void init_fdct (void);
+extern void mp_fwd_dct_block2 (DCTBLOCK_2D src, DCTBLOCK_2D dest);
 
 /* jrevdct.c */
-extern void init_pre_idct _ANSI_ARGS_((void ));
-extern void mpeg_jrevdct _ANSI_ARGS_((DCTBLOCK data ));
+extern void init_pre_idct (void );
+extern void mpeg_jrevdct (DCTBLOCK data );
 
 
 /* We assume that right shift corresponds to signed division by 2 with
diff --git a/converter/ppm/ppmtompeg/headers/frame.h b/converter/ppm/ppmtompeg/headers/frame.h
index 1f460ac2..e1f587a2 100644
--- a/converter/ppm/ppmtompeg/headers/frame.h
+++ b/converter/ppm/ppmtompeg/headers/frame.h
@@ -35,7 +35,6 @@
  *==============*/
 
 #include "netpbm/pm_c_util.h"
-#include "ansi.h"
 #include "mtypes.h"
 
 /*===========*
diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h
index 966d9214..2ec11d69 100644
--- a/converter/ppm/ppmtompeg/headers/frames.h
+++ b/converter/ppm/ppmtompeg/headers/frames.h
@@ -13,7 +13,6 @@
  *==============*/
 
 #include "pm_config.h"  /* For __inline__ */
-#include "ansi.h"
 #include "mtypes.h"
 #include "mheaders.h"
 #include "iframe.h"
diff --git a/converter/ppm/ppmtompeg/headers/frametype.h b/converter/ppm/ppmtompeg/headers/frametype.h
index 63bee964..33b604e6 100644
--- a/converter/ppm/ppmtompeg/headers/frametype.h
+++ b/converter/ppm/ppmtompeg/headers/frametype.h
@@ -7,7 +7,7 @@ FType_Type(unsigned int const frameNum);
 unsigned int
 FType_FutureRef(unsigned int const currFrameNum);
 
-int	FType_PastRef _ANSI_ARGS_((int currFrameNum));
+int	FType_PastRef (int currFrameNum);
 
 void SetFramePattern(const char * const pattern);
 
diff --git a/converter/ppm/ppmtompeg/headers/jpeg.h b/converter/ppm/ppmtompeg/headers/jpeg.h
index 17aa0808..76d73d9e 100644
--- a/converter/ppm/ppmtompeg/headers/jpeg.h
+++ b/converter/ppm/ppmtompeg/headers/jpeg.h
@@ -1,5 +1,4 @@
 #include <stdio.h>
-#include "ansi.h"
 #include "frame.h"
 
 void
diff --git a/converter/ppm/ppmtompeg/headers/mheaders.h b/converter/ppm/ppmtompeg/headers/mheaders.h
index 21d43e3d..edd9552d 100644
--- a/converter/ppm/ppmtompeg/headers/mheaders.h
+++ b/converter/ppm/ppmtompeg/headers/mheaders.h
@@ -54,7 +54,6 @@
  *==============*/
 
 #include "general.h"
-#include "ansi.h"
 #include "bitio.h"
 
 
@@ -62,7 +61,7 @@
  * EXTERNAL PROCEDURE prototypes *
  *===============================*/
 
-void	SetGOPStartTime _ANSI_ARGS_((int index));
+void	SetGOPStartTime (int index);
 
 void
 Mhead_GenSequenceHeader(BitBucket *   const bbPtr, 
@@ -80,21 +79,21 @@ Mhead_GenSequenceHeader(BitBucket *   const bbPtr,
                         uint8 *       const user_data,
                         int32         const user_data_size);
 
-void	Mhead_GenSequenceEnder _ANSI_ARGS_((BitBucket *bbPtr));
-void	Mhead_GenGOPHeader _ANSI_ARGS_((BitBucket *bbPtr,
+void	Mhead_GenSequenceEnder (BitBucket *bbPtr);
+void	Mhead_GenGOPHeader (BitBucket *bbPtr,
 	   int32 drop_frame_flag,
            int32 tc_hrs, int32 tc_min,
            int32 tc_sec, int32 tc_pict,
            int32 closed_gop, int32 broken_link,
            uint8 *ext_data, int32 ext_data_size,
-           uint8 *user_data, int32 user_data_size));
-void	Mhead_GenPictureHeader _ANSI_ARGS_((BitBucket *bbPtr, int frameType,
-					    int pictCount, int f_code));
-void	Mhead_GenSliceHeader _ANSI_ARGS_((BitBucket *bbPtr, uint32 slicenum,
+           uint8 *user_data, int32 user_data_size);
+void	Mhead_GenPictureHeader (BitBucket *bbPtr, int frameType,
+					    int pictCount, int f_code);
+void	Mhead_GenSliceHeader (BitBucket *bbPtr, uint32 slicenum,
 					  uint32 qscale, uint8 *extra_info,
-					  uint32 extra_info_size));
-void	Mhead_GenSliceEnder _ANSI_ARGS_((BitBucket *bbPtr));
-void	Mhead_GenMBHeader _ANSI_ARGS_((BitBucket *bbPtr,
+					  uint32 extra_info_size);
+void	Mhead_GenSliceEnder (BitBucket *bbPtr);
+void	Mhead_GenMBHeader (BitBucket *bbPtr,
 	  uint32 pict_code_type, uint32 addr_incr,
           uint32 q_scale,
           uint32 forw_f_code, uint32 back_f_code,
@@ -103,7 +102,7 @@ void	Mhead_GenMBHeader _ANSI_ARGS_((BitBucket *bbPtr,
           int32 motion_forw, int32 m_horiz_forw,
           int32 m_vert_forw, int32 motion_back,
           int32 m_horiz_back, int32 m_vert_back,
-          uint32 mb_pattern, uint32 mb_intra));
+          uint32 mb_pattern, uint32 mb_intra);
 
 
 #endif /* MHEADERS_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/motion_search.h b/converter/ppm/ppmtompeg/headers/motion_search.h
index 117b914a..d00509c4 100644
--- a/converter/ppm/ppmtompeg/headers/motion_search.h
+++ b/converter/ppm/ppmtompeg/headers/motion_search.h
@@ -9,7 +9,6 @@
  * HEADER FILES *
  *==============*/
 
-#include "ansi.h"
 
 
 /*===========*
diff --git a/converter/ppm/ppmtompeg/headers/mpeg.h b/converter/ppm/ppmtompeg/headers/mpeg.h
index 56862c42..fbfaaf2c 100644
--- a/converter/ppm/ppmtompeg/headers/mpeg.h
+++ b/converter/ppm/ppmtompeg/headers/mpeg.h
@@ -34,7 +34,6 @@
 
 #include "pm_c_util.h"
 #include "ppm.h"
-#include "ansi.h"
 #include "mtypes.h"
 #include "frame.h"
 
@@ -80,7 +79,7 @@ ComputeGOPFrames(int            const whichGOP,
                  unsigned int * const lastFrameP, 
                  unsigned int   const numFrames);
 
-extern void	IncrementTCTime _ANSI_ARGS_((void));
+extern void	IncrementTCTime (void);
 void SetReferenceFrameType(const char * const type);
 
 boolean
@@ -93,7 +92,7 @@ ReadDecodedRefFrame(MpegFrame *  const frameP,
 void
 SetBitRateFileName(const char * const fileName);
 
-extern void	SetFrameRate _ANSI_ARGS_((void));
+extern void	SetFrameRate (void);
 
 
 /*==================*
diff --git a/converter/ppm/ppmtompeg/headers/mproto.h b/converter/ppm/ppmtompeg/headers/mproto.h
index d8fefd84..5b003b2e 100644
--- a/converter/ppm/ppmtompeg/headers/mproto.h
+++ b/converter/ppm/ppmtompeg/headers/mproto.h
@@ -70,7 +70,6 @@
  *==============*/
 
 #include "general.h"
-#include "ansi.h"
 #include "bitio.h"
 
 
@@ -86,39 +85,39 @@ typedef DCTELEM DCTBLOCK[DCTSIZE2];
 /*  
  *  from mbasic.c:
  */
-void mp_reset _ANSI_ARGS_((void));
-void mp_free _ANSI_ARGS_((MpegFrame *mf));
-MpegFrame *mp_new _ANSI_ARGS_((int fnumber, char type, MpegFrame *oldFrame));
-void mp_ycc_calc _ANSI_ARGS_((MpegFrame *mf));
-void mp_dct_blocks _ANSI_ARGS_((MpegFrame *mf));
-void	AllocDecoded _ANSI_ARGS_((MpegFrame *frame));
+void mp_reset (void);
+void mp_free (MpegFrame *mf);
+MpegFrame *mp_new (int fnumber, char type, MpegFrame *oldFrame);
+void mp_ycc_calc (MpegFrame *mf);
+void mp_dct_blocks (MpegFrame *mf);
+void	AllocDecoded (MpegFrame *frame);
 
 /*  
  *  from moutput.c:
  */
-boolean mp_quant_zig_block _ANSI_ARGS_((Block in, FlatBlock out, int qscale, int iblock));
-void	UnQuantZig _ANSI_ARGS_((FlatBlock in, Block out, int qscale, boolean iblock));
-void mp_rle_huff_block _ANSI_ARGS_((FlatBlock in, BitBucket *out));
-void mp_rle_huff_pblock _ANSI_ARGS_((FlatBlock in, BitBucket *out));
-void mp_create_blocks _ANSI_ARGS_((MpegFrame *mf));
+boolean mp_quant_zig_block (Block in, FlatBlock out, int qscale, int iblock);
+void	UnQuantZig (FlatBlock in, Block out, int qscale, boolean iblock);
+void mp_rle_huff_block (FlatBlock in, BitBucket *out);
+void mp_rle_huff_pblock (FlatBlock in, BitBucket *out);
+void mp_create_blocks (MpegFrame *mf);
 
 
 
 
-void	ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer, int width,
-			    int height));
-boolean	ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer));
-void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
+void	ReadEYUV (MpegFrame * mf, FILE *fpointer, int width,
+			    int height);
+boolean	ReadPPM (MpegFrame *mf, FILE *fpointer);
+void PPMtoYCC (MpegFrame * mf);
 
-void	ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
-void mp_validate_size _ANSI_ARGS_((int *x, int *y));
-void AllocYCC _ANSI_ARGS_((MpegFrame * mf));
+void	ComputeHalfPixelData (MpegFrame *frame);
+void mp_validate_size (int *x, int *y);
+void AllocYCC (MpegFrame * mf);
 
 
 /* jrevdct.c */
-void init_pre_idct _ANSI_ARGS_((void ));
-void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos ));
-void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
-void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos ));
-void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
+void init_pre_idct (void );
+void j_rev_dct_sparse (DCTBLOCK data , int pos );
+void j_rev_dct (DCTBLOCK data );
+void j_rev_dct_sparse (DCTBLOCK data , int pos );
+void j_rev_dct (DCTBLOCK data );
 
diff --git a/converter/ppm/ppmtompeg/headers/opts.h b/converter/ppm/ppmtompeg/headers/opts.h
index 5901a677..1756334e 100644
--- a/converter/ppm/ppmtompeg/headers/opts.h
+++ b/converter/ppm/ppmtompeg/headers/opts.h
@@ -38,7 +38,6 @@
  */
 
 #include "general.h"
-#include "ansi.h"
 #include "mtypes.h"
 
 /*
@@ -110,14 +109,14 @@ extern int LaplaceNum, LaplaceCnum;
 extern boolean BSkipBlocks;
 
 /* Procedures Prototypes */
-int	GetIQScale _ANSI_ARGS_((void));
-int	GetPQScale _ANSI_ARGS_((void));
-int	GetBQScale _ANSI_ARGS_((void));
-void	Tune_Init _ANSI_ARGS_((void));
-int     CalcRLEHuffLength _ANSI_ARGS_((FlatBlock in));
+int	GetIQScale (void);
+int	GetPQScale (void);
+int	GetBQScale (void);
+void	Tune_Init (void);
+int     CalcRLEHuffLength (FlatBlock in);
 void    ParseTuneParam(const char * const charPtr);
-int     mse _ANSI_ARGS_((Block blk1, Block blk2));
-void    Mpost_UnQuantZigBlockLaplace _ANSI_ARGS_((FlatBlock in, Block out, int qscale, boolean iblock));
+int     mse (Block blk1, Block blk2);
+void    Mpost_UnQuantZigBlockLaplace (FlatBlock in, Block out, int qscale, boolean iblock);
 extern void CalcLambdas(void);
 
 
diff --git a/converter/ppm/ppmtompeg/headers/parallel.h b/converter/ppm/ppmtompeg/headers/parallel.h
index 90edd874..0a31fac2 100644
--- a/converter/ppm/ppmtompeg/headers/parallel.h
+++ b/converter/ppm/ppmtompeg/headers/parallel.h
@@ -30,7 +30,6 @@
  * HEADER FILES *
  *==============*/
 
-#include "ansi.h"
 #include "bitio.h"
 #include "frame.h"
 
diff --git a/converter/ppm/ppmtompeg/headers/param.h b/converter/ppm/ppmtompeg/headers/param.h
index 0c6d8e5c..46a544b3 100644
--- a/converter/ppm/ppmtompeg/headers/param.h
+++ b/converter/ppm/ppmtompeg/headers/param.h
@@ -1,7 +1,6 @@
 /* COPYRIGHT information is at end of file */
 
 #include "pm_c_util.h"
-#include "ansi.h"
 #include "input.h"
 
 
diff --git a/converter/ppm/ppmtompeg/headers/prototypes.h b/converter/ppm/ppmtompeg/headers/prototypes.h
index b421af35..432062e3 100644
--- a/converter/ppm/ppmtompeg/headers/prototypes.h
+++ b/converter/ppm/ppmtompeg/headers/prototypes.h
@@ -30,7 +30,6 @@
  *==============*/
 
 #include "general.h"
-#include "ansi.h"
 #include "frame.h"
 
 
@@ -38,34 +37,34 @@
  * EXTERNAL PROCEDURE prototypes *
  *===============================*/
 
-int GetBQScale _ANSI_ARGS_((void));
-int GetPQScale _ANSI_ARGS_((void));
-void    ResetBFrameStats _ANSI_ARGS_((void));
-void    ResetPFrameStats _ANSI_ARGS_((void));
+int GetBQScale (void);
+int GetPQScale (void);
+void    ResetBFrameStats (void);
+void    ResetPFrameStats (void);
 void SetSearchRange (int const pixelsP,
                      int const pixelsB);
 void
 SetPixelSearch(const char * const searchType);
-void    SetPQScale _ANSI_ARGS_((int qP));
-void    SetBQScale _ANSI_ARGS_((int qB));
-float   EstimateSecondsPerPFrame _ANSI_ARGS_((void));
-float   EstimateSecondsPerBFrame _ANSI_ARGS_((void));
-void    SetGOPSize _ANSI_ARGS_((int size));
+void    SetPQScale (int qP);
+void    SetBQScale (int qB);
+float   EstimateSecondsPerPFrame (void);
+float   EstimateSecondsPerBFrame (void);
+void    SetGOPSize (int size);
 void
 SetStatFileName(const char * const fileName);
 
 
-void DCTFrame _ANSI_ARGS_((MpegFrame * mf));
+void DCTFrame (MpegFrame * mf);
 
-void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
+void PPMtoYCC (MpegFrame * mf);
 
-void    MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame));
+void    MotionSearchPreComputation (MpegFrame *frame);
 
-void    ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
-void mp_validate_size _ANSI_ARGS_((int *x, int *y));
+void    ComputeHalfPixelData (MpegFrame *frame);
+void mp_validate_size (int *x, int *y);
 
 
 /* psearch.c */
-void    ShowPMVHistogram _ANSI_ARGS_((FILE *fpointer));
-void    ShowBBMVHistogram _ANSI_ARGS_((FILE *fpointer));
-void    ShowBFMVHistogram _ANSI_ARGS_((FILE *fpointer));
+void    ShowPMVHistogram (FILE *fpointer);
+void    ShowBBMVHistogram (FILE *fpointer);
+void    ShowBFMVHistogram (FILE *fpointer);
diff --git a/converter/ppm/ppmtompeg/headers/rate.h b/converter/ppm/ppmtompeg/headers/rate.h
index 8d691174..a5f5076f 100644
--- a/converter/ppm/ppmtompeg/headers/rate.h
+++ b/converter/ppm/ppmtompeg/headers/rate.h
@@ -68,7 +68,7 @@ targetRateControl(MpegFrame * const frameP);
  *
  * RETURNS:     nothing
  *===========================================================================*/
-extern void MB_RateOut _ANSI_ARGS_((int type));
+extern void MB_RateOut (int type);
 
 
 /*===========================================================================*
@@ -92,7 +92,7 @@ updateRateControl(int const type);
  *
  * RETURNS:     new Qscale
  *===========================================================================*/
-extern int needQScaleChange _ANSI_ARGS_((int oldQScale,  Block blk0, Block blk1, Block blk2, Block blk3));
+extern int needQScaleChange (int oldQScale,  Block blk0, Block blk1, Block blk2, Block blk3);
 
 /*===========================================================================*
  *
@@ -101,7 +101,7 @@ extern int needQScaleChange _ANSI_ARGS_((int oldQScale,  Block blk0, Block blk1,
  *
  * RETURNS:   nothing
  *===========================================================================*/
-extern void incNumBlocks _ANSI_ARGS_((int num));
+extern void incNumBlocks (int num);
 
 
 /*===========================================================================*
@@ -113,7 +113,7 @@ extern void incNumBlocks _ANSI_ARGS_((int num));
  *
  * RETURNS:   nothing
  *===========================================================================*/
-extern void incMacroBlockBits _ANSI_ARGS_((int num));
+extern void incMacroBlockBits (int num);
 
 
 /*===========================================================================*
@@ -125,7 +125,7 @@ extern void incMacroBlockBits _ANSI_ARGS_((int num));
  *
  * RETURNS:     nothing
  *===========================================================================*/
-extern void SetRateControl _ANSI_ARGS_((char *charPtr));
+extern void SetRateControl (char *charPtr);
 
 
 /*===========================================================================*
@@ -150,7 +150,7 @@ setBufferSize(const char * const charPtr);
  *
  * RETURNS:     int (or -1 if invalid)
  *===========================================================================*/
-extern int getBufferSize _ANSI_ARGS_((void));
+extern int getBufferSize (void);
 
 
 /*===========================================================================*
@@ -178,7 +178,7 @@ setBitRate(const char * const charPtr);
  *
  * RETURNS:     int (-1 if Variable mode operation)
  *===========================================================================*/
-extern int getBitRate _ANSI_ARGS_((void));
+extern int getBitRate (void);
 
 
 /*===========================================================================*
@@ -189,7 +189,7 @@ extern int getBitRate _ANSI_ARGS_((void));
  *
  * RETURNS:     integer
  *===========================================================================*/
-extern int getRateMode _ANSI_ARGS_((void));
+extern int getRateMode (void);
 
 
 /*===========================================================================*
@@ -200,5 +200,5 @@ extern int getRateMode _ANSI_ARGS_((void));
  *
  * RETURNS:   nothing
  *===========================================================================*/
-extern void incQuantOverride  _ANSI_ARGS_((int num));
+extern void incQuantOverride  (int num);
 
diff --git a/converter/ppm/ppmtompeg/headers/specifics.h b/converter/ppm/ppmtompeg/headers/specifics.h
index 7bcf4ace..4f5c7074 100644
--- a/converter/ppm/ppmtompeg/headers/specifics.h
+++ b/converter/ppm/ppmtompeg/headers/specifics.h
@@ -1,4 +1,3 @@
-#include "ansi.h"
 
 
 /*===========*
@@ -29,8 +28,8 @@ typedef struct fsl_def {
 } FrameSpecList;
 
 
-void	Specifics_Init _ANSI_ARGS_((void));
-int     SpecLookup _ANSI_ARGS_((int fn, int typ, int num, 
-				BlockMV **info, int start_qs));
-int SpecTypeLookup _ANSI_ARGS_((int fn));
+void	Specifics_Init (void);
+int     SpecLookup (int fn, int typ, int num,
+			    BlockMV **info, int start_qs);
+int SpecTypeLookup (int fn);
 
diff --git a/converter/ppm/ppmtompeg/jrevdct.c b/converter/ppm/ppmtompeg/jrevdct.c
index c3379d7a..bf9196c4 100644
--- a/converter/ppm/ppmtompeg/jrevdct.c
+++ b/converter/ppm/ppmtompeg/jrevdct.c
@@ -28,7 +28,6 @@
 
 #include <memory.h>
 #include "all.h"
-#include "ansi.h"
 #include "dct.h"
 
 
@@ -162,9 +161,9 @@ ones here or successive P-frames will drift too much with Reference frame coding
 /*
   Switch on reverse_dct choices
 */
-void reference_rev_dct _ANSI_ARGS_((int16 *block));
-void mpeg_jrevdct_quick _ANSI_ARGS_((int16 *block));
-void init_idctref _ANSI_ARGS_((void));
+void reference_rev_dct (int16 *block);
+void mpeg_jrevdct_quick (int16 *block);
+void init_idctref (void);
 
 extern boolean pureDCT;
 
diff --git a/converter/ppm/ppmtompeg/mpeg.c b/converter/ppm/ppmtompeg/mpeg.c
index 5cd7b099..24d337ed 100644
--- a/converter/ppm/ppmtompeg/mpeg.c
+++ b/converter/ppm/ppmtompeg/mpeg.c
@@ -126,9 +126,9 @@ int32 bit_rate, buf_size;
  * INTERNAL PROCEDURE prototypes *
  *===============================*/
 
-static void ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
-static void OpenBitRateFile _ANSI_ARGS_((void));
-static void CloseBitRateFile _ANSI_ARGS_((void));
+static void ComputeDHMSTime (int32 someTime, char *timeText);
+static void OpenBitRateFile (void);
+static void CloseBitRateFile (void);
 
 
 static void
diff --git a/converter/ppm/ppmtompeg/opts.c b/converter/ppm/ppmtompeg/opts.c
index 9eee971f..841efdab 100644
--- a/converter/ppm/ppmtompeg/opts.c
+++ b/converter/ppm/ppmtompeg/opts.c
@@ -52,7 +52,7 @@ extern int32   qtable[], niqtable[];
 extern int     ZAG[];
 extern boolean printSNR, decodeRefFrames;
 
-void init_idctref _ANSI_ARGS_((void));
+void init_idctref (void);
 
 
 /*===================*
diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
index bc788552..cd94db39 100644
--- a/converter/ppm/ppmtompeg/ppmtompeg.c
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -59,7 +59,7 @@
 
 #include <time.h>
 
-int main _ANSI_ARGS_((int argc, char **argv));
+int main (int argc, char **argv);
 
 
 /*==================*
@@ -92,7 +92,7 @@ const char * hostname;
  * External PROCEDURE prototypes  *
  *================================*/
 
-void init_idctref _ANSI_ARGS_((void));
+void init_idctref (void);
 
 
 struct cmdlineInfo {
diff --git a/converter/ppm/ppmtompeg/rate.c b/converter/ppm/ppmtompeg/rate.c
index d92afb64..c775e055 100644
--- a/converter/ppm/ppmtompeg/rate.c
+++ b/converter/ppm/ppmtompeg/rate.c
@@ -204,13 +204,13 @@ extern int framePatternLen;
  * INTERNAL PROCEDURE prototypes *
  *===============================*/
 
-int initGOPRateControl _ANSI_ARGS_((void));
-int determineMBCount _ANSI_ARGS_((void));
-void checkBufferFullness _ANSI_ARGS_((int count));
-void checkSpatialActivity _ANSI_ARGS_((Block blk0, Block blk1, Block blk2, Block blk3));
-void incNumBlocks _ANSI_ARGS_((int num));
-void calculateVBVDelay _ANSI_ARGS_((int num));
-int BlockExperiments  _ANSI_ARGS_((int16 *OrigBlock, int16 *NewBlock, int control));
+int initGOPRateControl (void);
+int determineMBCount (void);
+void checkBufferFullness (int count);
+void checkSpatialActivity (Block blk0, Block blk1, Block blk2, Block blk3);
+void incNumBlocks (int num);
+void calculateVBVDelay (int num);
+int BlockExperiments  (int16 *OrigBlock, int16 *NewBlock, int control);
      
      
 
diff --git a/converter/ppm/ppmtompeg/readframe.c b/converter/ppm/ppmtompeg/readframe.c
index cac6bdad..23752706 100644
--- a/converter/ppm/ppmtompeg/readframe.c
+++ b/converter/ppm/ppmtompeg/readframe.c
@@ -74,19 +74,19 @@ const char *CurrFile;
  * INTERNAL PROCEDURE prototypes *
  *===============================*/
 
-static void ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
-                 int width, int height));
-static void ReadAYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
-                 int width, int height));
-static void SeparateLine _ANSI_ARGS_((FILE *fpointer, struct YuvLine *lineptr,
-                     int width));
-static void ReadY _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
-                 int width, int height));
-static void ReadSub4 _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
-                  int width, int height));
-static void DoGamma  _ANSI_ARGS_((MpegFrame *mf, int width, int height));
-
-static void DoKillDim _ANSI_ARGS_((MpegFrame *mf, int w, int h));
+static void ReadEYUV (MpegFrame * mf, FILE *fpointer,
+                 int width, int height);
+static void ReadAYUV (MpegFrame * mf, FILE *fpointer,
+                 int width, int height);
+static void SeparateLine (FILE *fpointer, struct YuvLine *lineptr,
+                     int width);
+static void ReadY (MpegFrame * mf, FILE *fpointer,
+                 int width, int height);
+static void ReadSub4 (MpegFrame * mf, FILE *fpointer,
+                  int width, int height);
+static void DoGamma  (MpegFrame *mf, int width, int height);
+
+static void DoKillDim (MpegFrame *mf, int w, int h);
 
 #define safe_fread(ptr,sz,len,fileptr)                           \
     if ((safe_read_count=fread(ptr,sz,len,fileptr))!=sz*len) {   \
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
index ffbce80a..fb5e3649 100644
--- a/converter/ppm/ppmtompeg/specifics.c
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -58,14 +58,14 @@ FrameSpecList *fsl;
  * Internal procedures *
  *=====================*/
 
-void Parse_Specifics_File _ANSI_ARGS_((FILE *fp));
-void Parse_Specifics_File_v1 _ANSI_ARGS_((FILE *fp));
-void Parse_Specifics_File_v2 _ANSI_ARGS_((FILE *fp));
-FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
-void AddSlc _ANSI_ARGS_((FrameSpecList *c,int snum, int qs));
-Block_Specifics *AddBs _ANSI_ARGS_((FrameSpecList *c,int bnum, 
-				    boolean rel, int qs));
-FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
+void Parse_Specifics_File (FILE *fp);
+void Parse_Specifics_File_v1 (FILE *fp);
+void Parse_Specifics_File_v2 (FILE *fp);
+FrameSpecList *MakeFslEntry (void);
+void AddSlc (FrameSpecList *c,int snum, int qs);
+Block_Specifics *AddBs (FrameSpecList *c,int bnum, 
+				    boolean rel, int qs);
+FrameSpecList *MakeFslEntry (void);
 #define my_upper(c) (((c>='a') && (c<='z')) ? (c-'a'+'A') : c)
 #define CvtType(x) ReallyCvt(my_upper(x))
 #define ReallyCvt(x) (x=='I' ? 1 : (x=='P')?2: ((x=='B')?3:-1))
diff --git a/converter/ppm/ppmtopcx.c b/converter/ppm/ppmtopcx.c
index 4c25ca29..fa68edc5 100644
--- a/converter/ppm/ppmtopcx.c
+++ b/converter/ppm/ppmtopcx.c
@@ -12,6 +12,10 @@
 **
 ** 11/Dec/94: first version
 ** 12/Dec/94: added handling of "packed" format (16 colors or less)
+** 
+** ZSoft PCX File Format Technical Reference Manual
+** http://bespin.org/~qz/pc-gpe/pcx.txt
+** http://web.archive.org/web/20100206055706/http://www.qzx.com/pc-gpe/pcx.txt
 */
 #include <assert.h>
 
@@ -158,6 +162,8 @@ parseCommandLine(int argc, char ** argv,
         pm_error("Program takes at most one argument "
                  "(input file specification).  You specified %d",
                  argc-1);
+
+    free(option_def);
 }
 
 
@@ -632,6 +638,16 @@ generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
         putPcxColorInHash(cht, pcxColor, colorIndex, maxval);
     }
 
+    /* Set remaining slots in palette to black.  The values are not
+       meaningful, but this suppresses a Valgrind warning about our writing
+       undefined values to the file and makes our output constant with input.
+    */
+    for ( ; colorIndex < MAXCOLORS; ++colorIndex) {
+        pcxcmap[colorIndex].r = 0;
+        pcxcmap[colorIndex].g = 0;
+        pcxcmap[colorIndex].b = 0;
+    }
+
     *chtP = cht;
     *colorsP = stdPaletteSize;
 }