about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/other/fitstopnm.c212
-rw-r--r--converter/other/xwdtopnm.c188
-rw-r--r--converter/pbm/mrftopbm.c64
-rw-r--r--converter/pbm/pbmtog3.c30
-rw-r--r--converter/pbm/pbmtomrf.c162
-rw-r--r--converter/ppm/ilbmtoppm.c446
-rw-r--r--converter/ppm/mitsu.h1
-rw-r--r--converter/ppm/picttoppm.c632
-rw-r--r--converter/ppm/ppmtomitsu.c143
-rw-r--r--converter/ppm/ppmtomitsu.test4
-rw-r--r--converter/ppm/ppmtopict.c4
11 files changed, 1183 insertions, 703 deletions
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c
index b41e0960..0d8753e5 100644
--- a/converter/other/fitstopnm.c
+++ b/converter/other/fitstopnm.c
@@ -39,11 +39,12 @@
 #include <string.h>
 #include <float.h>
 
+#include "pm_config.h"
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "floatcode.h"
 #include "shhopt.h"
 #include "pnm.h"
-#include "pm_config.h"
 
 
 
@@ -156,109 +157,150 @@ struct FITS_Header {
 };
 
 
+/* This code deals properly with integers, no matter what the byte order
+   or integer size of the host machine.  We handle sign extension manually to
+   prevent problems with signed/unsigned characters.  We read floating point
+   values properly only when the host architecture conforms to IEEE-754.  If
+   you need to tweak this code for other machines, you might want to get a
+   copy of the FITS documentation from nssdca.gsfc.nasa.gov
+*/
+
 static void
-swapbytes(void *       const p,
-          unsigned int const nbytes) {
-#if BYTE_ORDER == LITTLE_ENDIAN
-    unsigned char * const c = p;
-    unsigned int i;
-    for (i = 0; i < nbytes/2; ++i) {
-        unsigned char const orig = c[i];
-        c[i] = c[nbytes-(i+1)];
-        c[nbytes-(i+1)] = orig;
-    }
-#endif
+readFitsChar(FILE *   const ifP,
+             double * const vP) {
+
+    /* 8 bit FITS integers are unsigned */
+
+    int const ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+    else
+        *vP = ich;
 }
 
 
-/*
- ** This code will deal properly with integers, no matter what the byte order
- ** or integer size of the host machine.  Sign extension is handled manually
- ** to prevent problems with signed/unsigned characters.  Floating point
- ** values will only be read properly when the host architecture is IEEE-754
- ** conformant.  If you need to tweak this code for other machines, you might
- ** want to snag a copy of the FITS documentation from nssdca.gsfc.nasa.gov
- */
 
 static void
-readVal(FILE *   const ifP,
-        int      const bitpix,
-        double * const vP) {
+readFitsShort(FILE *   const ifP,
+              double * const vP) {
 
-    switch (bitpix) {
-        /* 8 bit FITS integers are unsigned */
-    case 8: {
+    int ich;
+    int ival;
+    unsigned char c[8];
+
+    ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+
+    c[0] = ich;
+
+    ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+
+    c[1] = ich;
+
+    if (c[0] & 0x80)
+        ival = ~0xFFFF | c[0] << 8 | c[1];
+    else
+        ival = c[0] << 8 | c[1];
+
+    *vP = ival;
+}
+
+
+
+static void
+readFitsLong(FILE *   const ifP,
+             double * const vP) {
+
+    unsigned int i;
+    long int lval;
+    unsigned char c[4];
+
+    for (i = 0; i < 4; ++i) {
         int const ich = getc(ifP);
         if (ich == EOF)
             pm_error("EOF / read error");
-        *vP = ich;
-    } break;
+        c[i] = ich;
+    }
+
+    if (c[0] & 0x80)
+        lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
+    else
+        lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0;
+
+    *vP = lval;
+}
+
+
+
+static void
+readFitsFloat(FILE *   const ifP,
+              double * const vP) {
 
-    case 16: {
-        int ich;
-        int ival;
-        unsigned char c[8];
+    unsigned int i;
+    pm_bigendFloat bigend;
 
-        ich = getc(ifP);
+    for (i = 0; i < 4; ++i) {
+        int const ich = getc(ifP);
         if (ich == EOF)
             pm_error("EOF / read error");
-        c[0] = ich;
-        ich = getc(ifP);
+        bigend.bytes[i] = ich;
+    }
+
+    *vP = pm_floatFromBigendFloat(bigend);
+}
+
+
+
+static void
+readFitsDouble(FILE *   const ifP,
+               double * const vP) {
+
+    unsigned int i;
+    pm_bigendDouble bigend;
+
+    for (i = 0; i < 8; ++i) {
+        int const ich = getc(ifP);
         if (ich == EOF)
             pm_error("EOF / read error");
-        c[1] = ich;
-        if (c[0] & 0x80)
-            ival = ~0xFFFF | c[0] << 8 | c[1];
-        else
-            ival = c[0] << 8 | c[1];
-        *vP = ival;
-    } break;
+        bigend.bytes[i] = ich;
+    }
+
+    *vP = pm_doubleFromBigendDouble(bigend);
+}
+
+
+
+static void
+readVal(FILE *   const ifP,
+        int      const bitpix,
+        double * const vP) {
+
+    switch (bitpix) {
+    case 8:
+        readFitsChar(ifP, vP);
+        break;
+
+    case 16:
+        readFitsShort(ifP, vP);
+        break;
       
-    case 32: {
-        unsigned int i;
-        long int lval;
-        unsigned char c[4];
-
-        for (i = 0; i < 4; ++i) {
-            int const ich = getc(ifP);
-            if (ich == EOF)
-                pm_error("EOF / read error");
-            c[i] = ich;
-        }
-        if (c[0] & 0x80)
-            lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
-        else
-            lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0;
-        *vP = lval;
-    } break;
+    case 32:
+        readFitsLong(ifP, vP);
+        break;
       
-    case -32: {
-        unsigned int i;
-        unsigned char c[4];
-
-        for (i = 0; i < 4; ++i) {
-            int const ich = getc(ifP);
-            if (ich == EOF)
-                pm_error("EOF / read error");
-            c[i] = ich;
-        }
-        swapbytes(c, 4);
-        *vP = *((float *)c);
-    } break;
+    case -32:
+        readFitsFloat(ifP, vP);
+        break;
       
-    case -64: {
-        unsigned int i;
-        unsigned char c[8];
-
-        for (i = 0; i < 8; ++i) {
-            int const ich = getc(ifP);
-            if (ich == EOF)
-                pm_error("EOF / read error");
-            c[i] = ich;
-        }
-        swapbytes(c, 8);
-        *vP = *((double *)c);
-    } break;
+    case -64:
+        readFitsDouble(ifP, vP);
+        break;
       
     default:
         pm_error("Strange bitpix value %d in readVal()", bitpix);
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
index c919ca70..4bb642e7 100644
--- a/converter/other/xwdtopnm.c
+++ b/converter/other/xwdtopnm.c
@@ -53,6 +53,7 @@ struct cmdlineInfo {
     unsigned int verbose;
     unsigned int debug;
     unsigned int headerdump;
+    unsigned int cmapdump;
 };
 
 
@@ -123,6 +124,7 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
     OPTENT3(0,   "debug",      OPT_FLAG,   NULL, &cmdlineP->debug,         0);
     OPTENT3(0,   "headerdump", OPT_FLAG,   NULL, &cmdlineP->headerdump,    0);
+    OPTENT3(0,   "cmapdump",   OPT_FLAG,   NULL, &cmdlineP->cmapdump,      0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -166,9 +168,7 @@ processX10Header(X10WDFileHeader *  const h10P,
     bool grayscale;
     bool byte_swap;
 
-    *maxvalP = 65535;   /* Initial assumption */
-
-    if ( h10P->file_version != X10WD_FILE_VERSION ) {
+    if (h10P->file_version != X10WD_FILE_VERSION) {
         byte_swap = TRUE;
         h10P->header_size     = pm_bs_long(h10P->header_size);
         h10P->file_version    = pm_bs_long(h10P->file_version);
@@ -186,51 +186,53 @@ processX10Header(X10WDFileHeader *  const h10P,
     } else
         byte_swap = FALSE;
 
-    for ( i = 0; i < h10P->header_size - sizeof(*h10P); ++i )
-        if ( getc( file ) == EOF )
-            pm_error( "couldn't read rest of X10 XWD file header" );
+    for (i = 0; i < h10P->header_size - sizeof(*h10P); ++i)
+        if (getc(file) == EOF)
+            pm_error("couldn't read rest of X10 XWD file header");
 
     /* Check whether we can handle this dump. */
-    if ( h10P->window_ncolors > 256 )
-        pm_error( "can't handle X10 window_ncolors > %d", 256 );
-    if ( h10P->pixmap_format != ZFormat && h10P->display_planes != 1 )
-        pm_error(
-            "can't handle X10 pixmap_format %d with planes != 1",
-            h10P->pixmap_format );
+    if (h10P->window_ncolors > 256)
+        pm_error("can't handle X10 window_ncolors > %d", 256);
+    if (h10P->pixmap_format != ZFormat && h10P->display_planes != 1)
+        pm_error("can't handle X10 pixmap_format %d with planes != 1",
+                 h10P->pixmap_format);
 
     grayscale = TRUE;  /* initial assumption */
-    if ( h10P->window_ncolors != 0 ) {
+    if (h10P->window_ncolors != 0) {
         /* Read X10 colormap. */
-        MALLOCARRAY( x10colors, h10P->window_ncolors );
-        if ( x10colors == NULL )
-            pm_error( "out of memory" );
-        for ( i = 0; i < h10P->window_ncolors; ++i ) {
-            if ( fread( &x10colors[i], sizeof(X10Color), 1, file ) != 1 )
-                pm_error( "couldn't read X10 XWD colormap" );
-            if ( byte_swap ) {
+        MALLOCARRAY(x10colors, h10P->window_ncolors);
+        if (x10colors == NULL)
+            pm_error("out of memory");
+        for (i = 0; i < h10P->window_ncolors; ++i) {
+            size_t bytesRead;
+            bytesRead = fread(&x10colors[i], sizeof(X10Color), 1, file);
+            if (bytesRead != 1)
+                pm_error("couldn't read X10 XWD colormap");
+            if (byte_swap) {
                 x10colors[i].red   = pm_bs_short(x10colors[i].red);
                 x10colors[i].green = pm_bs_short(x10colors[i].green);
                 x10colors[i].blue  = pm_bs_short(x10colors[i].blue);
             }
-            if ( x10colors[i].red != x10colors[i].green ||
-                 x10colors[i].green != x10colors[i].blue )
+            if (x10colors[i].red != x10colors[i].green ||
+                x10colors[i].green != x10colors[i].blue)
                 grayscale = FALSE;
         }
     }
 
-    if ( h10P->display_planes == 1 ) {
+    if (h10P->display_planes == 1) {
         *formatP = PBM_TYPE;
         *visualclassP = StaticGray;
         *maxvalP = 1;
-        *colorsP = pnm_allocrow( 2 );
-        PNM_ASSIGN1( (*colorsP)[0], 0 );
-        PNM_ASSIGN1( (*colorsP)[1], *maxvalP );
+        *colorsP = pnm_allocrow(2);
+        PNM_ASSIGN1((*colorsP)[0], 0);
+        PNM_ASSIGN1((*colorsP)[1], *maxvalP);
         *padrightP =
             (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8;
         *bits_per_itemP = 16;
         *bits_per_pixelP = 1;
-    } else if ( h10P->window_ncolors == 0 ) { 
+    } else if (h10P->window_ncolors == 0) { 
         /* Must be grayscale. */
+        unsigned int i;
         *formatP = PGM_TYPE;
         *visualclassP = StaticGray;
         if (h10P->display_planes > sizeof(*maxvalP) * 8 - 1)
@@ -242,23 +244,27 @@ processX10Header(X10WDFileHeader *  const h10P,
             pm_error("XWD header says display_planes = %u, which is too "
                      "large for maximum maxval of %u",
                      h10P->display_planes, PNM_OVERALLMAXVAL);
-        *colorsP = pnm_allocrow( *maxvalP + 1 );
-        for ( i = 0; i <= *maxvalP; ++i )
-            PNM_ASSIGN1( (*colorsP)[i], i );
+        *colorsP = pnm_allocrow(*maxvalP + 1);
+        for (i = 0; i <= *maxvalP; ++i)
+            PNM_ASSIGN1((*colorsP)[i], i);
         *padrightP =
             (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8;
         *bits_per_itemP = 16;
         *bits_per_pixelP = 1;
     } else {
-        *colorsP = pnm_allocrow( h10P->window_ncolors );
+        *maxvalP = 65535;
+
+        *colorsP = pnm_allocrow(h10P->window_ncolors);
         *visualclassP = PseudoColor;
-        if ( grayscale ) {
+        if (grayscale) {
+            unsigned int i;
             *formatP = PGM_TYPE;
-            for ( i = 0; i < h10P->window_ncolors; ++i )
-                PNM_ASSIGN1( (*colorsP)[i], x10colors[i].red );
+            for (i = 0; i < h10P->window_ncolors; ++i)
+                PNM_ASSIGN1((*colorsP)[i], x10colors[i].red);
         } else {
+            unsigned int i;
             *formatP = PPM_TYPE;
-            for ( i = 0; i < h10P->window_ncolors; ++i )
+            for (i = 0; i < h10P->window_ncolors; ++i)
                 PPM_ASSIGN(
                     (*colorsP)[i], x10colors[i].red, x10colors[i].green,
                     x10colors[i].blue);
@@ -319,36 +325,46 @@ fixH11ByteOrder(X11WDFileHeader *  const h11P,
 
 
 static void
-readX11Colormap(FILE *      const file,
-                int         const ncolors, 
-                bool        const byteSwap,
-                X11XColor** const x11colorsP) {
+dumpX11Cmap(unsigned int       const nColors,
+            const X11XColor *  const x11colors) {
+
+    unsigned int i;
+    for (i = 0; i < nColors; ++i)
+        pm_message("Color %u r/g/b = %u/%u/%u", i, 
+                   x11colors[i].red, x11colors[i].green, 
+                   x11colors[i].blue);
+}
+
+
+
+static void
+readX11Colormap(FILE *       const file,
+                unsigned int const nColors, 
+                bool         const byteSwap,
+                bool         const cmapDump,
+                X11XColor**  const x11colorsP) {
                 
     X11XColor * x11colors;
     int rc;
 
     /* Read X11 colormap. */
-    MALLOCARRAY(x11colors, ncolors);
+    MALLOCARRAY(x11colors, nColors);
     if (x11colors == NULL)
         pm_error("out of memory");
-    rc = fread(x11colors, sizeof(x11colors[0]), ncolors, file);
-    if (rc != ncolors)
+    rc = fread(x11colors, sizeof(x11colors[0]), nColors, file);
+    if (rc != nColors)
         pm_error("couldn't read X11 XWD colormap");
     if (byteSwap) {
         unsigned int i;
-        for (i = 0; i < ncolors; ++i) {
+        for (i = 0; i < nColors; ++i) {
             x11colors[i].red   = pm_bs_short(x11colors[i].red);
             x11colors[i].green = pm_bs_short(x11colors[i].green);
             x11colors[i].blue  = pm_bs_short(x11colors[i].blue);
         }
     }
-    if (debug) {
-        unsigned int i;
-        for (i = 0; i < ncolors && i < 8; ++i)
-            pm_message("Color %d r/g/b = %d/%d/%d", i, 
-                       x11colors[i].red, x11colors[i].green, 
-                       x11colors[i].blue);
-    }
+    if (cmapDump)
+        dumpX11Cmap(nColors, x11colors);
+
     *x11colorsP = x11colors;
 }
 
@@ -490,10 +506,36 @@ computeComponentMasks(X11WDFileHeader * const h11P,
 }
 
 
+/* About TrueColor maxval:
+
+   The X11 spec says that in TrueColor, you use the bits in the raster for a
+   particular color component of a particular pixel to index the server's
+   colormap for that component, which contains 'bits_per_rgb' significant bits
+   of intensity information.  'bits_per_rgb' is in the XWD header, and in
+   practice is normally 8 or 16, usually 8.
+
+   We don't have the server's colormap, so we assume the most ordinary
+   one, a linear-as-possible distribution over the indices.
+
+   That means the maxval is that implied by 'bits_per_rgb' bits and we get
+   the proper sample value by scaling the value from the raster to that
+   maxval.
+
+   We (mostly Julian Bradfield <jcb@inf.ed.ac.uk>) figured this out in Netpbm
+   10.46 (March 2009).  Between ca. 2000 and 10.46, we instead assumed the
+   value in the XWD raster to be the exact brightness value, and chose a
+   maxval that would best allow us to represent that exact value for all
+   three components (e.g. if the XWD had 5 bits for blue, 5 for red, and
+   6 for red, we'd use maxval 31*63=1953).  Before that, the maxval was
+   31 if bits per pixel was 16 and 255 otherwise.
+*/
+
+
 
 static void
 processX11Header(X11WDFileHeader *  const h11P, 
-                 FILE *             const file,
+                 FILE *             const fileP,
+                 bool               const cmapDump,
                  int *              const colsP, 
                  int *              const rowsP, 
                  unsigned int *     const padrightP, 
@@ -519,7 +561,7 @@ processX11Header(X11WDFileHeader *  const h11P,
         pm_message("Header is different endianness from this machine.");
     
     for (i = 0; i < h11FixedP->header_size - sizeof(*h11FixedP); ++i)
-        if (getc(file) == EOF)
+        if (getc(fileP) == EOF)
             pm_error("couldn't read rest of X11 XWD file header");
 
     /* Check whether we can handle this dump. */
@@ -541,7 +583,8 @@ processX11Header(X11WDFileHeader *  const h11P,
                  h11FixedP->bitmap_unit);
 
     if (h11FixedP->ncolors > 0) {
-        readX11Colormap(file, h11FixedP->ncolors, byte_swap, &x11colors);
+        readX11Colormap(fileP, h11FixedP->ncolors, byte_swap, cmapDump,
+                        &x11colors);
         grayscale = colormapAllGray(x11colors, h11FixedP->ncolors);
     } else
         grayscale = TRUE;
@@ -565,11 +608,8 @@ processX11Header(X11WDFileHeader *  const h11P,
     } else if (*visualclassP == TrueColor) {
         *formatP = PPM_TYPE;
 
-        *maxvalP = pm_lcm(pm_bitstomaxval(one_bits(h11FixedP->red_mask)),
-                          pm_bitstomaxval(one_bits(h11FixedP->green_mask)),
-                          pm_bitstomaxval(one_bits(h11FixedP->blue_mask)),
-                          PPM_OVERALLMAXVAL
-            );
+        /* See discussion above about this maxval */
+        *maxvalP = pm_bitstomaxval(h11FixedP->bits_per_rgb);
     } else if (*visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1) {
         *formatP = PBM_TYPE;
         *maxvalP = 1;
@@ -681,7 +721,8 @@ getinit(FILE *             const ifP,
         struct compMask *  const compMaskP,
         enum byteorder *   const byte_orderP,
         enum byteorder *   const bit_orderP,
-        bool               const headerDump) {
+        bool               const headerDump,
+        bool               const cmapDump) {
 /*----------------------------------------------------------------------------
    Read the header from the XWD image in input stream 'ifP'.  Leave
    the stream positioned to the beginning of the raster.
@@ -743,7 +784,8 @@ getinit(FILE *             const ifP,
         if (headerDump)
             dumpX11Header(h11P);
 
-        processX11Header(h11P, ifP, colsP, rowsP, padrightP, maxvalP, 
+        processX11Header(h11P, ifP, cmapDump,
+                         colsP, rowsP, padrightP, maxvalP, 
                          visualclassP, formatP, 
                          colorsP, bits_per_pixelP, bits_per_itemP, 
                          compMaskP, byte_orderP, bit_orderP);
@@ -1126,6 +1168,28 @@ reportInfo(int              const cols,
 
 
 
+static void
+warn16Bit(xelval const maxval) {
+/*----------------------------------------------------------------------------
+   This program is often used by users of X, and those users often use
+   'xv', which doesn't properly interpret PNM files with 16 bit samples.
+   Furthermore, the maxval is often much larger than the user assumes
+   because of PNM's need to use the same maxval for all color components,
+   while XWD often uses different resolution for each.
+
+   Users get really frustrated when Xv displays something other than the
+   original mimage, almost always assuming that means Xwdtopnm converted
+   incorrectly.
+-----------------------------------------------------------------------------*/
+
+    if (pm_maxvaltobits(maxval) > 8)
+        pm_message("WARNING: Producing maxval %u output.  This involves "
+                   "multiple bytes per sample, which some programs, e.g. "
+                   "'xv', can't handle.  See manual.", maxval);
+}
+
+
+
 static void 
 convertRowSimpleIndex(pixelReader *  const pixelReaderP,
                       int            const cols,
@@ -1318,7 +1382,9 @@ main(int argc, char *argv[]) {
     getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format, 
             &colors, &bitsPerPixel, &bitsPerItem, 
             &compMask, &byteOrder, &bitOrder,
-            cmdline.headerdump);
+            cmdline.headerdump, cmdline.cmapdump);
+
+    warn16Bit(maxval);
     
     if (verbose) 
         reportInfo(cols, rows, padright, maxval, visualclass,
diff --git a/converter/pbm/mrftopbm.c b/converter/pbm/mrftopbm.c
index b7534115..51281028 100644
--- a/converter/pbm/mrftopbm.c
+++ b/converter/pbm/mrftopbm.c
@@ -41,34 +41,50 @@ bit_input(FILE * const in) {
 
 
 static void 
-doSquare(FILE *          const in,
-          unsigned char * const image,
-          int             const ox,
-          int             const oy,
-          int             const w,
-          int             const size) {
-
-    if (size == 1 || bit_input(in)) { 
+doSquare(FILE *          const ifP,
+         unsigned char * const image,
+         unsigned int    const ulCol,
+         unsigned int    const ulRow,
+         unsigned int    const imageWidth,
+         unsigned int    const size) {
+/*----------------------------------------------------------------------------
+   Do a square of side 'size', whose upper left corner is at (ulCol, ulRow).
+   The contents of that square are next in file *ifP, in MRF format.
+
+   Return the pixel values of the square in the corresponding position of
+   image[], which is a concatenation of rows 'imageWidth' pixels wide, one
+   byte per pixel.
+-----------------------------------------------------------------------------*/
+    if (size == 1 || bit_input(ifP)) { 
         /* It's all black or all white.  Next bit says which. */
 
-        unsigned int const c = bit_input(in);
+        unsigned int const c = bit_input(ifP);
 
-        unsigned int y;
+        unsigned int rowOfSquare;
 
-        for (y = 0; y < size; ++y) {
-            unsigned int x;
-            for (x = 0; x < size; ++x)
-                image[(oy+y)*w+ox+x] = c;
+        for (rowOfSquare = 0; rowOfSquare < size; ++rowOfSquare) {
+            unsigned int colOfSquare;
+            for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) {
+                unsigned int rowOfImage = ulRow + rowOfSquare;
+                unsigned int colOfImage = ulCol + colOfSquare;
+
+                image[rowOfImage * imageWidth + colOfImage] = c;
+            }
         }
     } else {
-        /* not all one color, so recurse. */
-
-        int halfsize = size >> 1;
-
-        doSquare(in, image, ox,          oy,          w, halfsize);
-        doSquare(in, image, ox+halfsize, oy,          w, halfsize);
-        doSquare(in, image, ox,          oy+halfsize, w, halfsize);
-        doSquare(in, image, ox+halfsize, oy+halfsize, w, halfsize);
+        /* Square is not all one color, so recurse.  Do each of the four
+           quadrants of this square individually.
+        */
+        unsigned int const quadSize = size/2;
+
+        doSquare(ifP, image, ulCol,            ulRow,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol + quadSize, ulRow,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol,            ulRow + quadSize,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol + quadSize, ulRow + quadSize,
+                 imageWidth, quadSize);
     }
 }
 
@@ -80,7 +96,7 @@ writeOutput(FILE *                const ofP,
             int                   const rows,
             const unsigned char * const image) {
             
-    /* w64 is units-of-64-bits width, h64 same for height */
+    /* w64 is units-of-64-bits width */
     unsigned int const w64 = (cols+63)/64;
 
     bit * bitrow;
@@ -145,7 +161,7 @@ readMrfImage(FILE *           const ifP,
         pm_error("Ridiculously large, unprocessable image: %u cols x %u rows",
                  cols, rows);
 
-    image = calloc(w64*h64*64*64,1);
+    image = calloc(w64*h64*64*64, 1);
     if (image == NULL)
         pm_error("Unable to get memory for raster");
                  
diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c
index 0b536390..3fe7f3fc 100644
--- a/converter/pbm/pbmtog3.c
+++ b/converter/pbm/pbmtog3.c
@@ -55,7 +55,7 @@ struct bitString {
 
 struct outStream {
     struct bitString buffer;
-    
+
     bool reverseBits;
 };
 
@@ -109,6 +109,8 @@ parseCommandLine(int argc, char ** const argv,
     optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
+    free(option_def);
+
     if (argc-1 == 0) 
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
@@ -142,7 +144,7 @@ makeBs(wordint      const bits,
     return retval;
 }
 
-    
+
 
 static __inline__ void
 putbits(struct bitString const newBits) {
@@ -153,7 +155,7 @@ putbits(struct bitString const newBits) {
    Flush the buffer to stdout as necessary to make room.
 
    'newBits' must be shorter than a whole word.
-   
+
    N.B. the definition of struct bitString requires upper bits to be zero.
 -----------------------------------------------------------------------------*/
     unsigned int const spaceLeft = 
@@ -182,11 +184,11 @@ putbits(struct bitString const newBits) {
                        | (newBits.intBuffer >> nextBufBitCount));
         if (out.reverseBits)
             reversebuffer(outbytes, sizeof(outbytes));
-            
+
         rc = fwrite(outbytes, 1, sizeof(outbytes), stdout);
         if (rc != sizeof(outbytes))
             pm_error("Output error.  Unable to fwrite() to stdout");
-        
+
         out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); 
         out.buffer.bitCount = nextBufBitCount;
     }
@@ -237,7 +239,7 @@ putcode2(int const clr,
 
     if (sizeof(wordint) * 8 > 24) {
         unsigned int const l1 = ttable[loIndex].length;
-        
+
         putbits(
             makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code,
                    mtable[hiIndex].length + l1)
@@ -299,7 +301,7 @@ puteol(void) {
         puts("EOL");
     else {
         struct bitString const eol = {12, 1};
-            
+
         putbits(eol);
     }
 }
@@ -341,7 +343,7 @@ convertRowToRunLengths(unsigned char * const bitrow,
     wordint      * const bitrowByWord = (wordint *) bitrow;
     int            const wordCount    = (cols + bitsPerWord - 1)/bitsPerWord; 
         /* Number of full and partial words in the row */
-        
+
 
     if (cols % bitsPerWord != 0) {
         /* Clean final word in row.  For loop simplicity */
@@ -411,7 +413,7 @@ main(int    argc,
            a word of zero padding on the high (right) end for the convenience
            of code that accesses this buffer in word-size bites.
         */
-     
+
     int rows;
     int cols;
     int readcols;
@@ -423,7 +425,7 @@ main(int    argc,
     pbm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-     
+
     ifP = pm_openr(cmdline.inputFileName);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
@@ -447,9 +449,9 @@ main(int    argc,
         unsigned int i;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
-        
+
         convertRowToRunLengths(bitrow, readcols, milepost, &nRun);
-        
+
         padToDesiredWidth(milepost, &nRun, readcols, outwidth);
 
         for (i = p = 0; i < nRun; p = milepost[i++])
@@ -459,6 +461,8 @@ main(int    argc,
     }
 
     free(milepost);
+    pbm_freerow_packed(bitrow);
+
     {
         unsigned int i;  
         for( i = 0; i < 6; ++i)
@@ -467,7 +471,7 @@ main(int    argc,
     if (out.buffer.bitCount > 0) {
         /* flush final partial buffer */
         unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8;
-        
+
         unsigned char outbytes[sizeof(wordint)];
         size_t rc;
         wordintToBytes(&outbytes, 
diff --git a/converter/pbm/pbmtomrf.c b/converter/pbm/pbmtomrf.c
index c93c88aa..e7b7fcc9 100644
--- a/converter/pbm/pbmtomrf.c
+++ b/converter/pbm/pbmtomrf.c
@@ -13,83 +13,139 @@
 #include "pm_c_util.h"
 #include "pbm.h"
 
-static int bitbox;
-static int bitsleft;
 
-static FILE *bit_out;
+
+typedef struct bitOut {
+    int bitbox;
+    int bitsleft;
+    FILE * fileP;
+} bitOut;
+
 
 
 static void 
-bit_init(FILE * const out) {
-    bitbox = 0; 
-    bitsleft = 8;
-    bit_out = out;
+bit_init(struct bitOut * const bitOutP,
+         FILE *          const ofP) {
+
+    bitOutP->bitbox = 0; 
+    bitOutP->bitsleft = 8;
+    bitOutP->fileP = ofP;
 }
 
 
 
 static void 
-bit_output(int const bit) {
-    --bitsleft;
-    bitbox |= (bit << bitsleft);
-    if (bitsleft == 0) {
-        fputc(bitbox, bit_out);
-        bitbox = 0;
-        bitsleft = 8;
+bit_output(struct bitOut * const bitOutP,
+           int             const bit) {
+
+    --bitOutP->bitsleft;
+    bitOutP->bitbox |= (bit << bitOutP->bitsleft);
+    if (bitOutP->bitsleft == 0) {
+        fputc(bitOutP->bitbox, bitOutP->fileP);
+        bitOutP->bitbox = 0;
+        bitOutP->bitsleft = 8;
     }
 }
 
 
 
 static void 
-bit_flush(void) {
+bit_flush(struct bitOut * const bitOutP) {
     /* there are never 0 bits left outside of bit_output, but
      * if 8 bits are left here there's nothing to flush, so
      * only do it if bitsleft!=8.
      */
-    if (bitsleft != 8) {
-        bitsleft = 1;
-        bit_output(0);    /* yes, really. This will always work. */
+    if (bitOutP->bitsleft != 8) {
+        bitOutP->bitsleft = 1;
+        bit_output(bitOutP, 0);    /* yes, really. This will always work. */
     }
 }
 
 
 
-static void 
-doSquare(unsigned char * const image,
-         int             const ox,
-         int             const oy,
-         int             const w,
-         int             const size) {
-
-    unsigned int y;
+static void
+determineBlackWhiteOrMix(const unsigned char * const image,
+                         unsigned int          const ulCol,
+                         unsigned int          const ulRow,
+                         unsigned int          const imageWidth,
+                         unsigned int          const size,
+                         bool *                const oneColorP,
+                         int *                 const colorP) {
+/*----------------------------------------------------------------------------
+   Determine whether a square within 'image' is all white, all black,
+   or a mix.
+-----------------------------------------------------------------------------*/
+    unsigned int rowOfSquare;
     unsigned int t;
 
-    /* check square to see if it's all black or all white. */
+    for (rowOfSquare = 0, t = 0; rowOfSquare < size; ++rowOfSquare) {
+        unsigned int colOfSquare;
+        for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) {
+            unsigned int rowOfImage = ulRow + rowOfSquare;
+            unsigned int colOfImage = ulCol + colOfSquare;
 
-    t = 0;
-    for (y = 0; y < size; ++y) {
-        unsigned int x;
-        for (x = 0; x < size; ++x)
-            t += image[(oy+y)*w + ox + x];
+            t += image[rowOfImage * imageWidth + colOfImage];
+        }
     }        
     /* if the total's 0, it's black. if it's size*size, it's white. */
-    if (t == 0 || t == size*size) {
-        if (size != 1)     /* (it's implicit when size is 1, of course) */
-            bit_output(1);  /* all same color */
-        bit_output(t?1:0);
-        return;
-    }
-    
-    /* otherwise, if our square is greater than 1x1, we need to recurse. */
-    if(size > 1) {
-        int halfsize = size >> 1;
-
-        bit_output(0);    /* not all same */
-        doSquare(image, ox,          oy,          w, halfsize);
-        doSquare(image, ox+halfsize, oy,          w, halfsize);
-        doSquare(image, ox,          oy+halfsize, w, halfsize);
-        doSquare(image, ox+halfsize, oy+halfsize, w, halfsize);
+    if (t == 0) {
+        *oneColorP = TRUE;
+        *colorP = 0;
+    } else if (t == SQR(size)) {
+        *oneColorP = TRUE;
+        *colorP = 1;
+    } else
+        *oneColorP = FALSE;
+}
+
+
+
+static void 
+doSquare(bitOut *              const bitOutP,
+         const unsigned char * const image,
+         unsigned int          const ulCol,
+         unsigned int          const ulRow,
+         unsigned int          const imageWidth,
+         unsigned int          const size) {
+/*----------------------------------------------------------------------------
+   Do a square of side 'size', whose upper left corner is at (ulCol, ulRow).
+   This is a square within 'image', which is a concatenation of rows
+   'imageWidth' pixels wide, one byte per pixel.
+
+   Write the pixel values out to the bit stream *bitOutP, in MRF format.
+-----------------------------------------------------------------------------*/
+    if (size == 1) {
+        /* The fact that it is all one color is implied because the square is
+           just one pixel; no bit goes in MRF output to state that.
+        */
+        bit_output(bitOutP, image[ulRow * imageWidth + ulCol] ? 1 : 0);
+    } else {
+        bool oneColor;
+        int color;
+
+        determineBlackWhiteOrMix(image, ulCol, ulRow, imageWidth, size,
+                                 &oneColor, &color);
+
+        if (oneColor) {
+            bit_output(bitOutP, 1);  /* all same color */
+            bit_output(bitOutP, color);
+        } else {
+            /* Square is not all the same color, so recurse.  Do each
+               of the four quadrants of this square individually.
+            */
+            unsigned int const quadSize = size/2;
+
+            bit_output(bitOutP, 0);    /* not all same color */
+
+            doSquare(bitOutP, image, ulCol,            ulRow,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol + quadSize, ulRow,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol,            ulRow + quadSize,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol + quadSize, ulRow + quadSize,
+                     imageWidth, quadSize);
+        }
     }
 }
     
@@ -243,7 +299,7 @@ readPbmImage(FILE *           const ifP,
         pm_error("Ridiculously large, unprocessable image: %u cols x %u rows",
                  cols, rows);
 
-    image = calloc(w64*h64*64*64,1);
+    image = calloc(w64*h64*64*64, 1);
     if (image == NULL)
         pm_error("Unable to get memory for raster");
                  
@@ -276,6 +332,8 @@ outputMrf(FILE *          const ofP,
     unsigned int const w64 = (cols + 63) / 64;
     unsigned int const h64 = (rows + 63) / 64;
 
+    bitOut bitOut;
+
     unsigned int row;
 
     fprintf(ofP, "MRF1");
@@ -285,14 +343,14 @@ outputMrf(FILE *          const ofP,
     
     /* now recursively check squares. */
 
-    bit_init(ofP);
+    bit_init(&bitOut, ofP);
 
     for (row = 0; row < h64; ++row) {
         unsigned int col;
         for (col = 0; col < w64; ++col)
-            doSquare(image, col*64, row*64, w64*64, 64);
+            doSquare(&bitOut, image, col*64, row*64, w64*64, 64);
     }
-    bit_flush();
+    bit_flush(&bitOut);
 }
 
 
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c
index d140d088..0c365834 100644
--- a/converter/ppm/ilbmtoppm.c
+++ b/converter/ppm/ilbmtoppm.c
@@ -1,4 +1,4 @@
-/* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
+/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -43,11 +43,10 @@
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
-#include "ilbm.h"
 #include "mallocvar.h"
-
-/*#define DEBUG*/
+#include "intcode.h"
+#include "ilbm.h"
+#include "ppm.h"
 
 typedef struct {
     int reg;            /* color register to change */
@@ -765,10 +764,15 @@ multi_free(cmap)
  ****************************************************************************/
 
 static void
-check_cmap(bmhd, cmap)
-    BitMapHeader *bmhd;
-    ColorMap *cmap;
-{
+prepareCmap(const BitMapHeader * const bmhd,
+            ColorMap *           const cmap) {
+/*----------------------------------------------------------------------------
+   This is a really ugly subroutine that 1) analyzes a colormap and its
+   context (returning the analysis in global variables); and 2) modifies that
+   color map, because it's really one type of data structure as input and
+   another as output.
+
+-----------------------------------------------------------------------------*/
     pixval colmaxval = 0;
     int shifted = 1;
     int i, r, g, b;
@@ -987,6 +991,8 @@ std_to_ppm(FILE *         const ifp,
            ColorMap *     const cmap, 
            long           const viewportmodes);
 
+
+
 static void
 ham_to_ppm(FILE *         const ifp, 
            long           const chunksize, 
@@ -1342,16 +1348,10 @@ dcol_to_ppm(FILE *         const ifP,
 
 
 static void
-cmap_to_ppm(cmap)
-    ColorMap *cmap;
-{
-    ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL);
-#if 0
-    int i;
-    ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1);
-    for( i = 0; i < cmap->ncolors; i++ )
-        ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1);
-#endif
+cmapToPpm(FILE *     const ofP,
+            ColorMap * const cmapP) {
+
+    ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL);
 }
 
 
@@ -1656,39 +1656,41 @@ PCHG_DecompHuff(src, dest, tree, origsize)
 }
 
 
+
 static void
-PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
-    PCHGHeader *PCHG;
-    PCHGCompHeader *CompHdr;
-    unsigned char *compdata;
-    unsigned long compsize;
-    unsigned char *comptree;
-    unsigned char *data;
-{
-    short *hufftree;
-    unsigned long huffsize, i;
-    unsigned long treesize = CompHdr->CompInfoSize;
+PCHG_Decompress(PCHGHeader *     const PCHG,
+                PCHGCompHeader * const CompHdr,
+                unsigned char *  const compdata,
+                unsigned long    const compsize,
+                unsigned char *  const comptree,
+                unsigned char *  const data) {
 
-    switch( PCHG->Compression ) {
-        case PCHG_COMP_HUFFMAN:
+    switch(PCHG->Compression) {
+    case PCHG_COMP_HUFFMAN: {
+        unsigned long const treesize = CompHdr->CompInfoSize;
+        unsigned long const huffsize = treesize / 2;
+        const bigend16 * const bigendComptree = (const void *)comptree;
 
-#ifdef DEBUG
-            pm_message("PCHG Huffman compression");
-#endif
-            /* turn big-endian 2-byte shorts into native format */
-            huffsize = treesize/2;
-            MALLOCARRAY_NOFAIL(hufftree, huffsize);
-            for( i = 0; i < huffsize; i++ ) {
-                hufftree[i] = (short)BIG_WORD(comptree);
-                comptree += 2;
-            }
+        short * hufftree;
+        unsigned long i;
 
-            /* decompress the change structure data */
-            PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
-                            CompHdr->OriginalDataSize);
+        /* Convert big-endian 2-byte shorts to C shorts */
 
-            free(hufftree);
-            break;
+        MALLOCARRAY(hufftree, huffsize);
+
+        if (!hufftree)
+            pm_error("Couldn't get memory for %lu-byte Huffman tree",
+                     huffsize);
+
+        for (i = 0; i < huffsize; ++i)
+            hufftree[i] = pm_uintFromBigend16(bigendComptree[i]);
+
+        /* decompress the change structure data */
+        PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
+                        CompHdr->OriginalDataSize);
+        
+        free(hufftree);
+    } break;
         default:
             pm_error("unknown PCHG compression type %d", PCHG->Compression);
     }
@@ -1797,94 +1799,119 @@ fail2:
 }
 
 
+
 static void
-PCHG_ConvertBig(PCHG, cmap, mask, datasize)
-    PCHGHeader *PCHG;
-    ColorMap *cmap;
-    unsigned char *mask;
-    unsigned long datasize;
-{
-    unsigned char *data;
+PCHG_ConvertBig(PCHGHeader *    const PCHG,
+                ColorMap *      const cmap,
+                unsigned char * const maskStart,
+                unsigned long   const datasize) {
+
+    unsigned char * data;
     unsigned char thismask;
-    int bits, row, i, changes, masklen, reg;
-    unsigned long totalchanges = 0;
-    int changedlines = PCHG->ChangedLines;
+    int bits;
+    unsigned int row;
+    int changes;
+    int masklen;
+    int reg;
+    unsigned long totalchanges;
+    int changedlines;
+    unsigned long dataRemaining;
+    unsigned char * mask;
+
+    mask = maskStart;  /* initial value */
+    dataRemaining = datasize;  /* initial value */
+    changedlines = PCHG->ChangedLines;  /* initial value */
+    totalchanges = 0;  /* initial value */
 
     masklen = 4 * MaskLongWords(PCHG->LineCount);
-    data = mask + masklen; datasize -= masklen;
+    data = mask + masklen; dataRemaining -= masklen;
 
-    bits = 0;
-    for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
+
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
 
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_init[reg - PCHG->MinReg].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_init[reg - PCHG->MinReg].r = *data++;
                 cmap->mp_init[reg - PCHG->MinReg].b = *data++;  /* yes, RBG */
                 cmap->mp_init[reg - PCHG->MinReg].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
 
-    for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
+
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
 
             MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1);
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
+
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_change[row][i].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_change[row][i].r = *data++;
                 cmap->mp_change[row][i].b = *data++;    /* yes, RBG */
                 cmap->mp_change[row][i].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             cmap->mp_change[row][changes].reg = MP_REG_END;
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
-    if( totalchanges != PCHG->TotalChanges )
+    if (totalchanges != PCHG->TotalChanges)
         pm_message("warning - got %ld change structures, "
                    "chunk header reports %ld", 
                    totalchanges, PCHG->TotalChanges);
-    return;
-fail:
-    pm_error("insufficient data in BigLineChanges structures");
-fail2:
-    pm_error("insufficient data in line mask");
 }
 
 
+
 static void
 read_pchg(FILE *     const ifp,
           IFF_ID     const iffid,
@@ -1938,7 +1965,7 @@ read_pchg(FILE *     const ifp,
             read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize);
 
             compsize = remainingChunksize;
-            MALLOCARRAY_NOFAIL(compdata, remainingChunksize);
+            MALLOCARRAY_NOFAIL(compdata, compsize);
             read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize);
 
             datasize = CompHdr.OriginalDataSize;
@@ -2032,7 +2059,7 @@ process_body( FILE *          const ifp,
         pm_error("%s chunk without %s chunk", 
                  ID2string(ID_BODY), ID2string(ID_BMHD));
 
-    check_cmap(bmhdP, cmap);
+    prepareCmap(bmhdP, cmap);
 
     pixelrow = ppm_allocrow(bmhdP->w);
     if( maskfile ) {
@@ -2080,21 +2107,21 @@ process_body( FILE *          const ifp,
 
 
 static void 
-process_chunk(FILE *          const ifp,
-              long            const formsize,
-              IFF_ID          const ignorelist[],
-              unsigned int    const ignorecount,
-              int             const fakeviewport,
-              int             const viewportmask,
-              int             const isdeepopt,
-              bool            const cmaponly,
-              bool *          const bodyChunkProcessedP,
-              bool *          const endchunkP,
-              BitMapHeader ** const bmhdP,
-              ColorMap *      const cmap,
-              DirectColor **  const dcolP,
-              int *           const viewportmodesP,
-              long *          const bytesReadP
+processChunk(FILE *          const ifP,
+             long            const formsize,
+             IFF_ID          const ignorelist[],
+             unsigned int    const ignorecount,
+             int             const fakeviewport,
+             int             const viewportmask,
+             int             const isdeepopt,
+             bool            const cmaponly,
+             bool *          const bodyChunkProcessedP,
+             bool *          const endchunkP,
+             BitMapHeader ** const bmhdP,
+             ColorMap *      const cmap,
+             DirectColor **  const dcolP,
+             int *           const viewportmodesP,
+             long *          const bytesReadP
     ) {
 
     IFF_ID iffid;
@@ -2103,129 +2130,168 @@ process_chunk(FILE *          const ifp,
 
     bytesread = 0;
 
-    iffid = get_big_long(ifp, ID_FORM, NULL);
-    chunksize = get_big_long(ifp, iffid, NULL);
+    iffid = get_big_long(ifP, ID_FORM, NULL);
+    chunksize = get_big_long(ifP, iffid, NULL);
     bytesread += 8;
 
     if (debug)
-        pm_message("reading %s chunk: %ld bytes", 
-                   ID2string(iffid), chunksize);
+        pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize);
 
-    if( ignored_iffid(iffid, ignorelist, ignorecount) ) {
+    if (ignored_iffid(iffid, ignorelist, ignorecount)) {
         pm_message("ignoring %s chunk", ID2string(iffid));
-        skip_chunk(ifp, iffid, chunksize);
-    } else if( iffid == ID_END ) {
+        skip_chunk(ifP, iffid, chunksize);
+    } else if (iffid == ID_END) {
         /* END chunks are not officially valid in IFF, but
            suggested as a future expansion for stream-writing,
            see Amiga RKM Devices, 3rd Ed, page 376 
         */
-        if( chunksize != 0 ) {
+        if (chunksize != 0 ) {
             pm_message("warning - non-0 %s chunk", ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
         }
-        if( formsize != 0xffffffff )
+        if (formsize != 0xffffffff)
             pm_message("warning - %s chunk with FORM size 0x%08lx "
                        "(should be 0x%08x)",
                        ID2string(iffid), formsize, 0xffffffff);
         *endchunkP = 1;
-    } else if( *bodyChunkProcessedP ) {
+    } else if (*bodyChunkProcessedP) {
         pm_message("%s chunk found after %s chunk - skipping", 
                    ID2string(iffid), ID2string(ID_BODY));
-        skip_chunk(ifp, iffid, chunksize);
+        skip_chunk(ifP, iffid, chunksize);
     } else
-        switch( iffid ) {
+        switch (iffid) {
         case ID_BMHD:
-            *bmhdP = read_bmhd(ifp, iffid, chunksize);
+            *bmhdP = read_bmhd(ifP, iffid, chunksize);
             break;
         case ID_CMAP:
-            read_cmap(ifp, iffid, chunksize, cmap);
+            read_cmap(ifP, iffid, chunksize, cmap);
             break;
         case ID_CMYK:
-            read_cmyk(ifp, iffid, chunksize, cmap);
+            read_cmyk(ifP, iffid, chunksize, cmap);
             break;
         case ID_CLUT:
-            read_clut(ifp, iffid, chunksize, cmap);
+            read_clut(ifP, iffid, chunksize, cmap);
             break;
         case ID_CAMG:
-            if( chunksize != CAMGChunkSize )
+            if (chunksize != CAMGChunkSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
-            *viewportmodesP = get_big_long(ifp, ID_CAMG, NULL);
+            *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL);
             *viewportmodesP &= viewportmask;      /* -isnotham/-isnotehb */
             break;
         case ID_PCHG:
-            read_pchg(ifp, iffid, chunksize, cmap);
+            read_pchg(ifP, iffid, chunksize, cmap);
             break;
         case ID_CTBL:
         case ID_SHAM:
-            read_4bit_mp(ifp, iffid, chunksize, cmap);
+            read_4bit_mp(ifP, iffid, chunksize, cmap);
             break;
         case ID_DCOL:
-            if( chunksize != DirectColorSize )
+            if (chunksize != DirectColorSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
             MALLOCVAR_NOFAIL(*dcolP);
-            (*dcolP)->r = get_byte(ifp, iffid, NULL);
-            (*dcolP)->g = get_byte(ifp, iffid, NULL);
-            (*dcolP)->b = get_byte(ifp, iffid, NULL);
-            (void)get_byte(ifp, iffid, NULL);       /* skip pad byte */
+            (*dcolP)->r = get_byte(ifP, iffid, NULL);
+            (*dcolP)->g = get_byte(ifP, iffid, NULL);
+            (*dcolP)->b = get_byte(ifP, iffid, NULL);
+            get_byte(ifP, iffid, NULL);       /* skip pad byte */
             break;
         case ID_BODY: 
-            if( cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0 )) {
-                skip_chunk(ifp, ID_BODY,  chunksize);
-                return;
-            }
-    
-            process_body(ifp, chunksize, *bmhdP, cmap, 
-                         maskfile, fakeviewport, isdeepopt, *dcolP,
-                         viewportmodesP);
-
-            *bodyChunkProcessedP = TRUE;
+            if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0))
+                skip_chunk(ifP, ID_BODY,  chunksize);
+            else {
+                process_body(ifP, chunksize, *bmhdP, cmap, 
+                             maskfile, fakeviewport, isdeepopt, *dcolP,
+                             viewportmodesP);
 
-            break;
+                *bodyChunkProcessedP = TRUE;
+            } break;
         case ID_GRAB:   case ID_DEST:   case ID_SPRT:   case ID_CRNG:
         case ID_CCRT:   case ID_DYCP:   case ID_DPPV:   case ID_DRNG:
         case ID_EPSF:   case ID_JUNK:   case ID_CNAM:   case ID_PRVW:
         case ID_TINY:   case ID_DPPS:
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         case ID_copy:   case ID_AUTH:   case ID_NAME:   case ID_ANNO:
         case ID_TEXT:   case ID_FVER:
-            if( verbose )
-                display_chunk(ifp, iffid, chunksize);
+            if (verbose)
+                display_chunk(ifP, iffid, chunksize);
             else
-                skip_chunk(ifp, iffid, chunksize);
+                skip_chunk(ifP, iffid, chunksize);
             break;
-        case ID_DPI:
-        {
+        case ID_DPI: {
             int x, y;
 
-            x = get_big_short(ifp, ID_DPI, NULL);
-            y = get_big_short(ifp, ID_DPI, NULL);
-            if( verbose )
+            x = get_big_short(ifP, ID_DPI, NULL);
+            y = get_big_short(ifP, ID_DPI, NULL);
+            if (verbose)
                 pm_message("%s chunk:  dpi_x = %d    dpi_y = %d", 
                            ID2string(ID_DPI), x, y);
-        }
-        break;
+        } break;
         default:
             pm_message("unknown chunk type %s - skipping", 
                        ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         }
 
     bytesread += chunksize;
 
-    if( ODD(chunksize) ) {
-        (void) get_byte(ifp, iffid, NULL);
+    if (ODD(chunksize)) {
+        get_byte(ifP, iffid, NULL);
         bytesread += 1;
     } 
     *bytesReadP = bytesread;
 }
 
 
+
+static void
+maybeWriteColorMap(FILE *               const ofP,
+                   const BitMapHeader * const bmhdP,
+                   ColorMap *           const cmapP,
+                   bool                 const bodyChunkProcessed,
+                   bool                 const cmaponly) {
+/*----------------------------------------------------------------------------
+   Write to file *ofP the color map *cmapP as a PPM, if appropriate.
+
+   The logic (not just here -- in the program as a whole) for deciding whether
+   to write the image or the colormap is quite twisted.  If I thought anyone
+   was actually using this program, I would take the time to straighten it
+   out.
+
+   What's really sick about this subroutine is that in choosing to write
+   a color map, it has to know that Caller hasn't already written
+   the image.  Huge modularity violation.
+-----------------------------------------------------------------------------*/
+    if (cmaponly) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("You specified -cmaponly, but the ILBM "
+                     "has no colormap");
+    } else if (bmhdP && bmhdP->nPlanes == 0) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither a color map nor color planes");
+    } else if (!bodyChunkProcessed) {
+        if (HAS_COLORMAP(cmapP)) {
+            pm_message("input is a colormap file");
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither %s or %s chunk", 
+                     ID2string(ID_BODY), ID2string(ID_CMAP));
+    }
+}
+
+
+
 int
 main(int argc, char *argv[]) {
 
-    FILE *ifp;
+    FILE * ifP;
     int argn;
     short cmaponly = 0, isdeepopt = 0;
     bool endchunk;
@@ -2299,25 +2365,25 @@ main(int argc, char *argv[]) {
     }    
 
     if( argn < argc ) {
-        ifp = pm_openr( argv[argn] );
+        ifP = pm_openr( argv[argn] );
         argn++;
     } else
-        ifp = stdin;
+        ifP = stdin;
 
     if( argn != argc )
         pm_usage(usage);
 
     /* Read in the ILBM file. */
 
-    firstIffid = get_big_long(ifp, ID_FORM, NULL);
-    if( firstIffid != ID_FORM )
+    firstIffid = get_big_long(ifP, ID_FORM, NULL);
+    if (firstIffid != ID_FORM)
         pm_error("input is not a FORM type IFF file");
-    formsize = get_big_long(ifp, ID_FORM, NULL);
-    typeid = get_big_long(ifp, ID_FORM, NULL);
-    if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
-        typeid != ID_PBM )
-        pm_error( "input is not an ILBM, RGBN, RGB8 or PBM "
-                  "type FORM IFF file" );
+    formsize = get_big_long(ifP, ID_FORM, NULL);
+    typeid = get_big_long(ifP, ID_FORM, NULL);
+    if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
+        typeid != ID_PBM)
+        pm_error("input is not an ILBM, RGBN, RGB8 or PBM "
+                 "type FORM IFF file");
     bytesread = 4;  /* FORM and formsize do not count */
 
     cmap = alloc_cmap();
@@ -2325,55 +2391,41 @@ main(int argc, char *argv[]) {
     /* Main loop, parsing the IFF FORM. */
     bodyChunkProcessed = FALSE;
     endchunk = FALSE;
-    while( !endchunk && formsize-bytesread >= 8 ) {
-        long bytes_read_for_chunk;
+    while (!endchunk && formsize-bytesread >= 8) {
+        long bytesReadForChunk;
 
-        process_chunk(ifp, formsize, ignorelist, ignorecount,
-                      fakeviewport, viewportmask,
-                      isdeepopt, cmaponly,
-                      &bodyChunkProcessed,
-                      &endchunk, &bmhdP, cmap, &dcol,
-                      &viewportmodes, &bytes_read_for_chunk);
+        processChunk(ifP, formsize, ignorelist, ignorecount,
+                     fakeviewport, viewportmask,
+                     isdeepopt, cmaponly,
+                     &bodyChunkProcessed,
+                     &endchunk, &bmhdP, cmap, &dcol,
+                     &viewportmodes, &bytesReadForChunk);
 
-        bytesread += bytes_read_for_chunk;
+        bytesread += bytesReadForChunk;
     }
 
-    if( maskfile ) {
+    if (maskfile) {
         pm_close(maskfile);
-        if( !wrotemask )
+        if (!wrotemask)
             remove(maskname);
         pbm_freerow(maskrow);
     }
 
-    if( cmaponly || (bmhdP && bmhdP->nPlanes == 0 )) {
-        if( HAS_COLORMAP(cmap) ) {
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no colormap");
-    } else if( !bodyChunkProcessed ) {
-        if( HAS_COLORMAP(cmap) ) {
-            pm_message("input is a colormap file");
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no %s or %s chunk found", 
-                     ID2string(ID_BODY), ID2string(ID_CMAP));
-    }
+    maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly);
 
     {
         unsigned int skipped;
         
-        for( skipped = 0; fgetc(ifp) != EOF; ++skipped )
-            bytesread++;
+        for (skipped = 0; fgetc(ifP) != EOF; ++skipped)
+            ++bytesread;
 
-        if( skipped > 0 )
+        if (skipped > 0)
             pm_message("skipped %u extraneous byte%s after last chunk",
                        skipped, (skipped == 1 ? "" : "s"));
     }
-    pm_close(ifp);
+    pm_close(ifP);
 
-    if( !endchunk && bytesread != formsize ) {
+    if (!endchunk && bytesread != formsize) {
         pm_message("warning - file length/FORM size field mismatch "
                    "(%ld != %ld+8)",
                    bytesread+8 /* FORM+size */, formsize);
diff --git a/converter/ppm/mitsu.h b/converter/ppm/mitsu.h
index 8676a39d..bca4fbdf 100644
--- a/converter/ppm/mitsu.h
+++ b/converter/ppm/mitsu.h
@@ -1,7 +1,6 @@
 #ifndef MITSU_H_INCLUDED
 #define MITSU_H_INCLUDED
 
-/* static char SCCSid[] = "@(#)mitsu.h\t\t1.3\t(SPZ)\t3/11/92\n"; */
 #define MAXLUTCOL   255
 
 #define A4_MAXCOLS  1184
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index b7da0c79..9a7d8e7c 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -142,15 +142,6 @@ static int ps_cent_x;
 static int ps_cent_y;
 static int ps_cent_set;
 
-typedef void (drawFn)(struct canvas *, int);
-
-struct opdef {
-    const char* name;
-    int len;
-    drawFn * impl;
-    const char* description;
-};
-
 struct raster {
 /*----------------------------------------------------------------------------
    An image raster.  May be either truecolor or paletted.
@@ -265,13 +256,30 @@ struct blit_info {
     struct raster      srcplane;
     int                pixSize;
     struct Rect        dstRect;
-    struct RGBColor *  color_map;
+    struct RGBColor *  colorMap;
     int                mode;
     struct blit_info * next;
 };
 
-static struct blit_info* blit_list = 0;
-static struct blit_info** last_bl = &blit_list;
+typedef struct {
+    struct blit_info * firstP;
+    struct blit_info ** connectorP;
+    bool unblittableText;
+        /* The image contains text opcodes, and we don't know how to put that
+           in a blit list (I really don't even know what a blit _is_), so
+           the image information here is incomplete.
+        */
+} blitList;
+
+
+typedef void (drawFn)(struct canvas *, blitList *, int);
+
+struct opdef {
+    const char* name;
+    int len;
+    drawFn * impl;
+    const char* description;
+};
 
 #define WORD_LEN (-1)
 
@@ -610,6 +618,7 @@ static drawFn ShortComment;
 
 static void
 ShortComment(struct canvas * const canvasP,
+             blitList *      const blitListP,
              int             const version) {
 
     picComment(read_word(), 0);
@@ -621,6 +630,7 @@ static drawFn LongComment;
 
 static void
 LongComment(struct canvas * const canvasP,
+            blitList *      const blitListP,
             int             const version) {
 
     word type;
@@ -635,6 +645,7 @@ static drawFn skip_poly_or_region;
 
 static void
 skip_poly_or_region(struct canvas * const canvasP,
+                    blitList *      const blitListP,
                     int             const version) {
 
     stage = "skipping polygon or region";
@@ -765,24 +776,33 @@ load_fontdir(const char * const dirfile) {
 
 
 static void
+dumpRect(const char * const label,
+         struct Rect  const rectangle) {
+
+    pm_message("%s (%u,%u) (%u,%u)",
+               label,
+               rectangle.left,  rectangle.top,
+               rectangle.right, rectangle.bottom);
+}
+
+
+
+static void
 read_rect(struct Rect * const r) {
 
     r->top    = read_word();
     r->left   = read_word();
     r->bottom = read_word();
     r->right  = read_word();
-}
-
 
+    if (r->top > r->bottom || r->right < r->left)
+        dumpRect("Invalid rectangle", *r);
 
-static void
-dumpRect(const char * const label,
-         struct Rect  const rectangle) {
-
-    pm_message("%s (%u,%u) (%u,%u)",
-               label,
-               rectangle.left,  rectangle.top,
-               rectangle.right, rectangle.bottom);
+    if (r->top > r->bottom)
+        pm_error("Invalid PICT: a rectangle has a top below its bottom");
+    if (r->right < r->left)
+        pm_error("Invalid PICT: a rectangle has a right edge "
+                 "left of its left edge");
 }
 
 
@@ -802,10 +822,10 @@ rectheight(const struct Rect * const r) {
 
 
 static bool
-rectsamesize(const struct Rect * const r1, 
-             const struct Rect * const r2) {
-    return r1->right - r1->left == r2->right - r2->left &&
-           r1->bottom - r1->top == r2->bottom - r2->top ;
+rectsamesize(struct Rect const r1, 
+             struct Rect const r2) {
+    return r1.right - r1.left == r2.right - r2.left &&
+           r1.bottom - r1.top == r2.bottom - r2.top ;
 }
 
 
@@ -835,20 +855,45 @@ rectscale(struct Rect * const r,
 
 
 
-static struct blit_info* 
-add_blit_list(void) {
+static void
+    initBlitList(blitList * const blitListP) {
 
-    struct blit_info * bi;
+    blitListP->firstP          = NULL;
+    blitListP->connectorP      = &blitListP->firstP;
+    blitListP->unblittableText = false;
+}
+
+
+
+static void
+addBlitList(blitList *        const blitListP,
+            struct Rect       const srcRect,
+            struct Rect       const srcBounds,
+            struct raster     const srcplane,
+            int               const pixSize,
+            struct Rect       const dstRect,
+            struct RGBColor * const colorMap,
+            int               const mode) {
+
+    struct blit_info * biP;
     
-    MALLOCVAR(bi);
-    if (bi == NULL)
+    MALLOCVAR(biP);
+    if (biP == NULL)
         pm_error("out of memory for blit list");
-    
-    bi->next = 0;
-    *last_bl = bi;
-    last_bl = &bi->next;
-    
-    return bi;
+    else {
+        biP->srcRect   = srcRect;
+        biP->srcBounds = srcBounds;
+        biP->srcplane  = srcplane;
+        biP->pixSize   = pixSize;
+        biP->dstRect   = dstRect;
+        biP->colorMap  = colorMap;
+        biP->mode      = mode;
+
+        biP->next = NULL;
+
+        *blitListP->connectorP = biP;
+        blitListP->connectorP = &biP->next;
+    }
 }
 
 
@@ -1327,8 +1372,6 @@ doSameSize(transfer_func           trf,
            struct rgbPlanes  const dst,
            unsigned int      const dstwid) {
 /*----------------------------------------------------------------------------
-   Generalized (but slow) blit.
-
    Transfer pixels from 'src' to 'dst', applying the transfer function
    'trf'.
 
@@ -1501,19 +1544,30 @@ blitIdempotent(unsigned int          const pixSize,
 
 
 static void
-generalBlit(struct Rect       const srcRect, 
-            struct Rect       const srcBounds, 
-            struct raster     const srcplane,
-            struct rgbPlanes  const planes,
-            int               const pixSize, 
-            struct Rect       const dstRect, 
-            struct Rect       const dstBounds, 
-            int               const dstwid, 
-            struct RGBColor * const color_map, 
-            int               const mode,
-            struct Rect       const clipsrc,
-            struct Rect       const clipdst) {
-    
+doBlit(struct Rect       const srcRect, 
+       struct Rect       const dstRect, 
+       struct Rect       const srcBounds, 
+       struct raster     const srcplane,
+       struct Rect       const dstBounds, 
+       struct rgbPlanes  const canvasPlanes,
+       int               const pixSize, 
+       int               const dstwid, 
+       struct RGBColor * const color_map, 
+       int               const mode) {
+/*----------------------------------------------------------------------------
+   Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the
+   transfer function 'trf'.
+
+   'srcplane' contains the rectangle 'srcBounds' of the image.
+   'canvasPlanes' contains the rectangle 'dstRect' of the image.
+
+   Take the rectangle 'srcRect' of the source image and copy it to the
+   rectangle 'dstRec' of the destination image.
+
+   Each plane of 'canvasPlanes' is one word per pixel and contains actual
+   colors, never a palette index.  It is an array in row-major order
+   with 'dstwid' words per row.
+-----------------------------------------------------------------------------*/
     unsigned char * src;
     struct rgbPlanes dst;
     int dstoff;
@@ -1523,31 +1577,31 @@ generalBlit(struct Rect       const srcRect,
     transfer_func trf;
 
     if (verbose) {
-        dumpRect("copying from:", clipsrc);
-        dumpRect("to:          ", clipdst);
+        dumpRect("copying from:", srcRect);
+        dumpRect("to:          ", dstRect);
         pm_message("a %u x %u area to a %u x %u area",
-                   rectwidth(&clipsrc), rectheight(&clipsrc),
-                   rectwidth(&clipdst), rectheight(&clipdst));
+                   rectwidth(&srcRect), rectheight(&srcRect),
+                   rectwidth(&dstRect), rectheight(&dstRect));
     }
 
     {
         unsigned int const pkpixsize = pixSize == 16 ? 2 : 1;
-        unsigned int const srcRowNumber = clipsrc.top - srcBounds.top;
+        unsigned int const srcRowNumber = srcRect.top - srcBounds.top;
         unsigned int const srcRowOffset =
-            (clipsrc.left - srcBounds.left) * pkpixsize;
+            (srcRect.left - srcBounds.left) * pkpixsize;
         assert(srcRowNumber < srcplane.rowCount);
         assert(srcRowOffset < srcplane.rowSize);
         src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset;
-        xsize = clipsrc.right - clipsrc.left;
-        ysize = clipsrc.bottom - clipsrc.top;
+        xsize = rectwidth(&srcRect);
+        ysize = rectheight(&srcRect);
         srcadd = srcplane.rowSize - xsize * pkpixsize;
     }
 
-    dstoff = (clipdst.top - dstBounds.top) * dstwid +
-        (clipdst.left - dstBounds.left);
-    dst.red = planes.red + dstoff;
-    dst.grn = planes.grn + dstoff;
-    dst.blu = planes.blu + dstoff;
+    dstoff = (dstRect.top - dstBounds.top) * dstwid +
+        (dstRect.left - dstBounds.left);
+    dst.red = canvasPlanes.red + dstoff;
+    dst.grn = canvasPlanes.grn + dstoff;
+    dst.blu = canvasPlanes.blu + dstoff;
 
     /* get rid of Text mask mode bit, if (erroneously) set */
     if ((mode & ~64) == 0)
@@ -1555,8 +1609,8 @@ generalBlit(struct Rect       const srcRect,
     else
         trf = transfer(mode & ~64);
 
-    if (!rectsamesize(&clipsrc, &clipdst))
-        doDiffSize(clipsrc, clipdst, pixSize, xsize, ysize,
+    if (!rectsamesize(srcRect, dstRect))
+        doDiffSize(srcRect, dstRect, pixSize, xsize, ysize,
                    trf, color_map, src, srcplane.rowSize, dst, dstwid);
     else {
         if (trf == NULL)
@@ -1575,12 +1629,21 @@ blit(struct Rect       const srcRect,
      struct Rect       const srcBounds, 
      struct raster     const srcplane,
      struct canvas *   const canvasP,
+     blitList *        const blitListP,
      int               const pixSize, 
      struct Rect       const dstRect, 
      struct Rect       const dstBounds, 
      int               const dstwid, 
      struct RGBColor * const color_map, 
      int               const mode) {
+/*----------------------------------------------------------------------------
+   'srcplane' contains the rectangle 'srcBounds' of the image.
+
+   We transfer rectangle 'srcRect' from that.
+
+   if 'blitListP' is non-null, we don't draw anything on 'canvasP'; instead,
+   we add to the list *blitlistP a description of what needs to be drawn.
+-----------------------------------------------------------------------------*/
 
     /* I can't tell what the result value of this function is supposed to mean,
        but I found several return statements that did not set it to anything,
@@ -1595,9 +1658,7 @@ blit(struct Rect       const srcRect,
         retval = 1;
     else {
         /* Almost got it.  Clip source rect with source bounds.
-           clip dest rect with dest bounds.  If source and
-           destination are not the same size, use Pnmscale
-           to get a nicely sized rectangle.
+           clip dest rect with dest bounds.
         */
         struct Rect clipsrc;
         struct Rect clipdst;
@@ -1605,22 +1666,16 @@ blit(struct Rect       const srcRect,
         rectinter(srcBounds, srcRect, &clipsrc);
         rectinter(dstBounds, dstRect, &clipdst);
 
-        if (fullres) {
-            struct blit_info * bi;
-            bi = add_blit_list();
-            bi->srcRect   = clipsrc;
-            bi->srcBounds = srcBounds;
-            bi->srcplane  = srcplane;
-            bi->pixSize   = pixSize;
-            bi->dstRect   = clipdst;
-            bi->color_map = color_map;
-            bi->mode      = mode;
+        if (blitListP) {
+            addBlitList(blitListP,
+                        clipsrc, srcBounds, srcplane, pixSize,
+                        clipdst, color_map, mode);
 
             retval = 0;
         } else {
-            generalBlit(srcRect, srcBounds, srcplane, canvasP->planes, pixSize,
-                        dstRect, dstBounds, dstwid, color_map, mode,
-                        clipsrc, clipdst);
+            doBlit(clipsrc, clipdst,
+                   srcBounds, srcplane, dstBounds, canvasP->planes,
+                   pixSize, dstwid, color_map, mode);
 
             retval = 1;
         }
@@ -1680,9 +1735,31 @@ compact(word const input) {
 
 
 static void
-do_blits(struct canvas * const canvasP) {
+reportBlitList(blitList * const blitListP) {
+
+    if (verbose) {
+        unsigned int count;
+        struct blit_info * biP;
+
+        for (count = 0, biP = blitListP->firstP; biP; biP = biP->next)
+            ++count;
+
+        pm_message("# blits: %u", count);
+    }
+}
+
 
-    struct blit_info* bi;
+
+static void
+doBlitList(struct canvas * const canvasP,
+           blitList *      const blitListP) {
+/*----------------------------------------------------------------------------
+   Do the list of blits *blitListP, drawing on canvas *canvasP.
+
+   We allocate new plane data structures in *canvasP.  We assume it doesn't
+   have them already.
+-----------------------------------------------------------------------------*/
+    struct blit_info * bi;
     int srcwidth, dstwidth, srcheight, dstheight;
     double  scale, scalelow, scalehigh;
     double  xscale = 1.0;
@@ -1690,9 +1767,11 @@ do_blits(struct canvas * const canvasP) {
     double  lowxscale, highxscale, lowyscale, highyscale;
     int     xscalecalc = 0, yscalecalc = 0;
 
+    reportBlitList(blitListP);
+
     fullres = 0;
 
-    for (bi = blit_list; bi; bi = bi->next) {
+    for (bi = blitListP->firstP; bi; bi = bi->next) {
         srcwidth = rectwidth(&bi->srcRect);
         dstwidth = rectwidth(&bi->dstRect);
         srcheight = rectheight(&bi->srcRect);
@@ -1768,11 +1847,12 @@ do_blits(struct canvas * const canvasP) {
     }
 
     if (xscale != 1.0 || yscale != 1.0) {
-        for (bi = blit_list; bi; bi = bi->next)
-            rectscale(&bi->dstRect, xscale, yscale);
+        struct blit_info * biP;
+        
+        for (biP = blitListP->firstP; biP; biP = biP->next)
+            rectscale(&biP->dstRect, xscale, yscale);
 
-        pm_message("Scaling output by %f in X and %f in Y",
-                   xscale, yscale);
+        pm_message("Scaling output by %f in X and %f in Y", xscale, yscale);
         rectscale(&picFrame, xscale, yscale);
     }
 
@@ -1783,12 +1863,10 @@ do_blits(struct canvas * const canvasP) {
 
     clip_rect = picFrame;
 
-    for (bi = blit_list; bi; bi = bi->next) {
-        blit(bi->srcRect, bi->srcBounds, bi->srcplane, canvasP,
-             bi->pixSize,
-             bi->dstRect, picFrame, rowlen,
-             bi->color_map,
-             bi->mode);
+    for (bi = blitListP->firstP; bi; bi = bi->next) {
+        doBlit(bi->srcRect, bi->dstRect,
+               bi->srcBounds, bi->srcplane, picFrame, canvasP->planes,
+               bi->pixSize, rowlen, bi->colorMap, bi->mode);
     }
 }
 
@@ -1856,6 +1934,7 @@ static drawFn Clip;
 
 static void
 Clip(struct canvas * const canvasP,
+     blitList *      const blitListP,
      int             const version) {
 
     word len;
@@ -1878,6 +1957,7 @@ static drawFn OpColor;
 
 static void
 OpColor(struct canvas * const canvasP,
+        blitList *      const blitListP,
         int             const version) {
 
     op_color.red = read_word();
@@ -1967,7 +2047,7 @@ read_color_table(void) {
         color_table[val].blu = read_word();
 
         if (verbose > 1)
-            pm_message("%d: [%d,%d,%d]", val,
+            pm_message("Color %3u: [%u,%u,%u]", val,
                 color_table[val].red,
                 color_table[val].grn,
                 color_table[val].blu);
@@ -2173,6 +2253,42 @@ unpackUncompressedBits(FILE *          const ifP,
 
 
 static void
+reportValidateCompressedLineLen(unsigned int const row,
+                                unsigned int const linelen,
+                                unsigned int const rowSize) {
+/*----------------------------------------------------------------------------
+   'row' is a row number in the raster.
+
+   'linelen' is the number of bytes of PICT that the PICT says hold the
+   compressed version of that row.
+
+   'rowSize' is the number of bytes we expect the uncompressed line to
+   be (includes pad pixels on the right).
+-----------------------------------------------------------------------------*/
+    if (verbose > 1)
+        pm_message("Row %u: %u-byte compressed line", row, linelen);
+
+    /* When the line length value is garbage, it often causes the program to
+       try to read beyond EOF.  To make that failure easier to diagnose,
+       we sanity check the line length now.
+    */
+
+    /* In the worst case, a pixel is represented by two bytes: a one byte
+       repeat count of one followed by a one byte pixel value (the byte could
+       be up to 8 pixels) or a one byte block length of one followed by the
+       pixel value.  So expansion factor two.
+    */
+
+    if (linelen > rowSize * 2)
+        pm_error("Invalid PICT: compressed line of %u bytes for Row %u "
+                 "is too big "
+                 "to represent a %u-byte padded row, even with worse case "
+                 "compression.", linelen, row, rowSize);
+}
+
+
+
+static void
 expandRun(unsigned char * const block,
           unsigned int    const blockLimit,
           unsigned int    const bitsPerPixel,
@@ -2375,7 +2491,7 @@ interpretCompressedLine(unsigned char * const linebuf,
         
         assert(lineCursor <= linelen);
             
-        if (verbose > 1)
+        if (verbose > 2)
             pm_message("At Byte %u of line, Column %u of row",
                        lineCursor, rasterCursor);
 
@@ -2394,6 +2510,32 @@ interpretCompressedLine(unsigned char * const linebuf,
 }
 
 
+/* There is some confusion about when, in PICT, a line length is one byte and
+  when it is two.  An Apple document says it is two bytes when the number of
+  pixels in the row, padded, is > 250.  Ppmtopict generated PICTs that way
+  until January 2009.  Picttoppm assumed something similar until March 2004:
+  It assumed the line length is two bytes when the number of pixels > 250 _or_
+  bits per pixel > 8.  But in March 2004, Steve Summit did a bunch of
+  experiments on existing PICT files and found that they all worked with the
+  rule "pixels per row > 200 => 2 byte line length" and some did not work
+  with the original rule.
+
+  So in March 2004, Picttoppm changed to pixels per row > 200.  Ppmtopict
+  didn't catch up until January 2009.
+
+  http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-460.html#HEADING460-0
+
+  Of course, neither 200 nor 250 make any logical sense.  In the worst case,
+  you can represent 254 pixels of 8 bpp or less in a 255 byte line.
+  In the worst case, you can represent 127 16bpp pixels in a 255 byte line.
+  So with 200 being the cutoff, it's actually impossible to represent some 
+  16 bpp images with 200 pixels per row.
+
+  We have not been able to find an offical spec for PICT.
+
+  Some day, we may have to make a user option for this.
+*/
+
 
 static void
 unpackCompressedBits(FILE *          const ifP,
@@ -2410,14 +2552,13 @@ unpackCompressedBits(FILE *          const ifP,
    "packing" and I don't know what packing is called.  But we don't
    use that confusing terminology in this program, except when talking
    to the user.
-
-   *boundsP describes the rectangle.
 -----------------------------------------------------------------------------*/
     unsigned int const llsize = rowBytes > 200 ? 2 : 1;
         /* Width in bytes of the field at the beginning of a line that tells
-           how long (in bytes) the line is.
+           how long (in bytes) the line is.  See notes above about this
+           computation.
         */
-    unsigned int rowOfRect;
+    unsigned int row;
     unsigned char * linebuf;
     unsigned int linebufSize;
 
@@ -2426,9 +2567,9 @@ unpackCompressedBits(FILE *          const ifP,
     if (linebuf == NULL)
         pm_error("can't allocate memory for line buffer");
 
-    for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) {
+    for (row = 0; row < raster.rowCount; ++row) {
         unsigned char * const rowRaster =
-            &raster.bytes[rowOfRect * raster.rowSize];
+            &raster.bytes[row * raster.rowSize];
         unsigned int linelen;
 
         if (llsize == 2)
@@ -2436,8 +2577,7 @@ unpackCompressedBits(FILE *          const ifP,
         else
             linelen = read_byte();
 
-        if (verbose > 1)
-            pm_message("Row %u: %u-byte line", rowOfRect, linelen);
+        reportValidateCompressedLineLen(row, linelen, raster.rowSize);
 
         if (linelen > linebufSize) {
             linebufSize = linelen;
@@ -2554,6 +2694,7 @@ static drawFn BkPixPat;
 
 static void
 BkPixPat(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     read_pattern();
@@ -2565,6 +2706,7 @@ static drawFn PnPixPat;
 
 static void
 PnPixPat(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     read_pattern();
@@ -2576,6 +2718,7 @@ static drawFn FillPixPat;
 
 static void
 FillPixPat(struct canvas * const canvasP,
+           blitList *      const blitListP,
            int             const version) {
 
     read_pattern();
@@ -2610,6 +2753,7 @@ static drawFn BkPat;
 
 static void 
 BkPat(struct canvas * const canvasP,
+      blitList *      const blitListP,
       int             const version) {
 
     read_8x8_pattern(&bkpat);
@@ -2621,6 +2765,7 @@ static drawFn PnPat;
 
 static void 
 PnPat(struct canvas * const canvasP,
+      blitList *      const blitListP,
       int             const version) {
 
     read_8x8_pattern(&pen_pat);
@@ -2632,6 +2777,7 @@ static drawFn FillPat;
 
 static void 
 FillPat(struct canvas * const canvasP,
+        blitList *      const blitListP,
         int             const version) {
 
     read_8x8_pattern(&fillpat);
@@ -2643,6 +2789,7 @@ static drawFn PnSize;
 
 static void 
 PnSize(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     pen_height = read_word();
@@ -2657,6 +2804,7 @@ static drawFn PnSize;
 
 static void 
 PnMode(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     pen_mode = read_word();
@@ -2685,6 +2833,7 @@ static drawFn RGBFgCol;
 
 static void 
 RGBFgCol(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     read_rgb(&foreground);
@@ -2699,6 +2848,7 @@ static drawFn RGBBkCol;
 
 static void 
 RGBBkCol(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     read_rgb(&background);
@@ -2857,6 +3007,7 @@ static drawFn Line;
 
 static void 
 Line(struct canvas * const canvasP,
+     blitList *      const blitListP,
      int             const version) {
 
   struct Point p1;
@@ -2874,6 +3025,7 @@ static drawFn LineFrom;
 
 static void 
 LineFrom(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     struct Point p1;
@@ -2881,7 +3033,7 @@ LineFrom(struct canvas * const canvasP,
     if (verbose)
         pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y);
 
-    if (!fullres)
+    if (!blitListP)
         scan_line(canvasP, current.x, current.y, p1.x, p1.y);
 
     current.x = p1.x;
@@ -2894,6 +3046,7 @@ static drawFn ShortLine;
 
 static void 
 ShortLine(struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version) {
 
     struct Point p1;
@@ -2904,7 +3057,7 @@ ShortLine(struct canvas * const canvasP,
     current.x += p1.x;
     current.y += p1.y;
     
-    if (!fullres)
+    if (!blitListP)
         scan_line(canvasP, p1.x, p1.y, current.x, current.y);
 }
 
@@ -2914,6 +3067,7 @@ static drawFn ShortLineFrom;
 
 static void 
 ShortLineFrom(struct canvas * const canvasP,
+              blitList *      const blitListP,
               int             const version) {
 
     struct Point p1;
@@ -2923,7 +3077,7 @@ ShortLineFrom(struct canvas * const canvasP,
                    current.x,current.y,p1.x,p1.y);
     p1.x += current.x;
     p1.y += current.y;
-    if (!fullres)
+    if (!blitListP)
         scan_line(canvasP, current.x, current.y, p1.x, p1.y);
     current.x = p1.x;
     current.y = p1.y;
@@ -2937,9 +3091,6 @@ do_paintRect(struct canvas * const canvasP,
 
     struct Rect rect;
   
-    if (fullres)
-        return;
-
     if (verbose)
         dumpRect("painting", prect);
 
@@ -2954,10 +3105,12 @@ static drawFn paintRect;
 
 static void 
 paintRect(struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version) {
 
     read_rect(&cur_rect);
-    do_paintRect(canvasP, cur_rect);
+    if (!blitListP)
+        do_paintRect(canvasP, cur_rect);
 }
 
 
@@ -2966,9 +3119,11 @@ static drawFn paintSameRect;
 
 static void 
 paintSameRect(struct canvas * const canvasP,
+              blitList *      const blitListP,
               int             const version) {
 
-    do_paintRect(canvasP, cur_rect);
+    if (!blitListP)
+        do_paintRect(canvasP, cur_rect);
 }
 
 
@@ -2976,25 +3131,22 @@ paintSameRect(struct canvas * const canvasP,
 static void 
 do_frameRect(struct canvas * const canvasP,
              struct Rect     const rect) {
-    int x, y;
 
-    if (fullres)
-        return;
-  
     if (verbose)
         dumpRect("framing", rect);
 
-    if (pen_width == 0 || pen_height == 0)
-        return;
-
-    for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
-        draw_pen(canvasP, x, rect.top);
-        draw_pen(canvasP, x, rect.bottom - pen_height);
-    }
+    if (pen_width > 0 && pen_height > 0) {
+        unsigned int x, y;
 
-    for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
-        draw_pen(canvasP, rect.left, y);
-        draw_pen(canvasP, rect.right - pen_width, y);
+        for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
+            draw_pen(canvasP, x, rect.top);
+            draw_pen(canvasP, x, rect.bottom - pen_height);
+        }
+        
+        for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
+            draw_pen(canvasP, rect.left, y);
+            draw_pen(canvasP, rect.right - pen_width, y);
+        }
     }
 }
 
@@ -3004,10 +3156,12 @@ static drawFn frameRect;
 
 static void 
 frameRect(struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version) {
 
     read_rect(&cur_rect);
-    do_frameRect(canvasP, cur_rect);
+    if (!blitListP)
+        do_frameRect(canvasP, cur_rect);
 }
 
 
@@ -3016,9 +3170,11 @@ static drawFn frameSameRect;
 
 static void 
 frameSameRect(struct canvas * const canvasP,
+              blitList *      const blitListP,
               int             const version) {
 
-    do_frameRect(canvasP, cur_rect);
+    if (!blitListP)
+        do_frameRect(canvasP, cur_rect);
 }
 
 
@@ -3165,6 +3321,7 @@ static drawFn paintPoly;
   
 static void 
 paintPoly(struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version) {
 
   struct Rect bb;
@@ -3176,7 +3333,7 @@ paintPoly(struct canvas * const canvasP,
     read_point(&pts[i]);
 
   /* scan convert poly ... */
-  if (!fullres)
+  if (!blitListP)
       scan_poly(canvasP, np, pts);
 }
 
@@ -3186,6 +3343,7 @@ static drawFn PnLocHFrac;
 
 static void 
 PnLocHFrac(struct canvas * const canvasP,
+           blitList *      const blitListP,
            int             const version) {
 
     word frac = read_word();
@@ -3200,6 +3358,7 @@ static drawFn TxMode;
 
 static void 
 TxMode(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     text_mode = read_word();
@@ -3220,6 +3379,7 @@ static drawFn TxFont;
 
 static void 
 TxFont(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     text_font = read_word();
@@ -3233,6 +3393,7 @@ static drawFn TxFace;
 
 static void 
 TxFace(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     text_face = read_byte();
@@ -3246,6 +3407,7 @@ static drawFn TxSize;
 
 static void 
 TxSize(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     text_size = read_word();
@@ -3256,11 +3418,11 @@ TxSize(struct canvas * const canvasP,
 
 
 static void
-skip_text(void) {
+skip_text(blitList * const blitListP) {
 
-    pm_message("Warning: text is omitted from the output because "
-               "we don't know how to do text with -fullres.");
     skip(read_byte());
+
+    blitListP->unblittableText = true;
 }
 
 
@@ -3279,6 +3441,7 @@ static struct font*
 get_font(int const font, 
          int const size, 
          int const style) {
+
     int closeness, bestcloseness;
     struct fontinfo* fi, *best;
 
@@ -3410,11 +3573,12 @@ do_ps_text(struct canvas * const canvasP,
 
 static void
 do_text(struct canvas *  const canvasP,
+        blitList *       const blitListP,
         word             const startx, 
         word             const starty) {
 
-    if (fullres)
-        skip_text();
+    if (blitListP)
+        skip_text(blitListP);
     else {
         if (!(tfont = get_font(text_font, text_size, text_face)))
             tfont = pbm_defaultfont("bdf");
@@ -3459,13 +3623,14 @@ static drawFn LongText;
 
 static void
 LongText(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     struct Point p;
 
     read_point(&p);
 
-    do_text(canvasP, p.x, p.y);
+    do_text(canvasP, blitListP, p.x, p.y);
 }
 
 
@@ -3474,10 +3639,12 @@ static drawFn DHText;
 
 static void
 DHText(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     current.x += read_byte();
-    do_text(canvasP, current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3486,10 +3653,12 @@ static drawFn DVText;
 
 static void
 DVText(struct canvas * const canvasP,
+       blitList *      const blitListP,
        int             const version) {
 
     current.y += read_byte();
-    do_text(canvasP, current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3498,6 +3667,7 @@ static drawFn DHDVText;
 
 static void
 DHDVText(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
     byte dh, dv;
 
@@ -3509,7 +3679,8 @@ DHDVText(struct canvas * const canvasP,
 
     current.x += dh;
     current.y += dv;
-    do_text(canvasP, current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3520,6 +3691,7 @@ DHDVText(struct canvas * const canvasP,
 
 static void
 directBits(struct canvas * const canvasP,
+           blitList *      const blitListP,
            unsigned int    const pictVersion, 
            bool            const skipRegion) {
 
@@ -3561,11 +3733,11 @@ directBits(struct canvas * const canvasP,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (skipRegion) 
-        skip_poly_or_region(canvasP, pictVersion);
+        skip_poly_or_region(canvasP, blitListP, pictVersion);
 
     unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster);
 
-    blit(srcRect, p.Bounds, raster, canvasP, p.pixelSize,
+    blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize,
          dstRect, picFrame, rowlen, NULL, mode);
 
     freeRaster(raster);
@@ -3580,9 +3752,10 @@ static drawFn DirectBitsRect;
 
 static void
 DirectBitsRect(struct canvas * const canvasP,
+               blitList *      const blitListP,
                int             const version) {
 
-    directBits(canvasP, version, SKIP_REGION_FALSE);
+    directBits(canvasP, blitListP, version, SKIP_REGION_FALSE);
 }
 
 
@@ -3591,15 +3764,17 @@ static drawFn DirectBitsRgn;
 
 static void
 DirectBitsRgn(struct canvas * const canvasP,
+              blitList *      const blitListP,
               int             const version) {
 
-    directBits(canvasP, version, SKIP_REGION_TRUE);
+    directBits(canvasP, blitListP, version, SKIP_REGION_TRUE);
 }
 
 
 
 static void
 do_pixmap(struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version, 
           word            const rowBytes, 
           int             const is_region) {
@@ -3638,13 +3813,13 @@ do_pixmap(struct canvas * const canvasP,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(canvasP, version);
+        skip_poly_or_region(canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
     unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster);
 
-    blit(srcRect, p.Bounds, raster, canvasP, 8,
+    blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8,
          dstRect, picFrame, rowlen, color_table, mode);
 
     free(color_table);
@@ -3656,6 +3831,7 @@ do_pixmap(struct canvas * const canvasP,
 static void
 do_bitmap(FILE *          const ifP,
           struct canvas * const canvasP,
+          blitList *      const blitListP,
           int             const version, 
           int             const rowBytes, 
           int             const is_region) {
@@ -3683,13 +3859,13 @@ do_bitmap(FILE *          const ifP,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(canvasP, version);
+        skip_poly_or_region(canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
     unpackbits(ifP, &Bounds, rowBytes, 1, &raster);
 
-    blit(srcRect, Bounds, raster, canvasP, 8,
+    blit(srcRect, Bounds, raster, canvasP, blitListP, 8,
          dstRect, picFrame, rowlen, color_table, mode);
 
     freeRaster(raster);
@@ -3701,6 +3877,7 @@ static drawFn BitsRect;
 
 static void
 BitsRect(struct canvas * const canvasP,
+         blitList *      const blitListP,
          int             const version) {
 
     word rowBytesWord;
@@ -3713,9 +3890,9 @@ BitsRect(struct canvas * const canvasP,
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, version, rowBytes, 0);
+        do_pixmap(canvasP, blitListP, version, rowBytes, 0);
     else
-        do_bitmap(ifp, canvasP, version, rowBytes, 0);
+        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0);
 }
 
 
@@ -3724,6 +3901,7 @@ static drawFn BitsRegion;
 
 static void
 BitsRegion(struct canvas * const canvasP,
+           blitList *      const blitListP,
            int             const version) {
     
     word rowBytesWord;
@@ -3736,9 +3914,9 @@ BitsRegion(struct canvas * const canvasP,
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, version, rowBytes, 1);
+        do_pixmap(canvasP, blitListP, version, rowBytes, 1);
     else
-        do_bitmap(ifp, canvasP, version, rowBytes, 1);
+        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1);
 }
 
 
@@ -3921,15 +4099,85 @@ static struct opdef const optable[] = {
 
 
 static void
+processOpcode(word const opcode, 
+              struct canvas * const canvasP,
+              blitList *      const blitListP,
+              unsigned int    const version) {
+
+    if (opcode < 0xa2) {
+        stage = optable[opcode].name;
+        if (verbose) {
+            if (streq(stage, "reserved"))
+                pm_message("reserved opcode=0x%x", opcode);
+            else
+                pm_message("Opcode: %s", optable[opcode].name);
+        }
+
+        if (optable[opcode].impl != NULL)
+            (*optable[opcode].impl)(canvasP, blitListP, version);
+        else if (optable[opcode].len >= 0)
+            skip(optable[opcode].len);
+        else {
+            switch (optable[opcode].len) {
+            case WORD_LEN: {
+                word const len = read_word();
+                skip(len);
+                } break;
+            default:
+                pm_error("can't do length %u", optable[opcode].len);
+            }
+        }
+    } else if (opcode == 0xc00) {
+        if (verbose)
+            pm_message("HeaderOp");
+        stage = "HeaderOp";
+        skip(24);
+    } else if (opcode >= 0xa2 && opcode <= 0xaf) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_word());
+    } else if (opcode >= 0xb0 && opcode <= 0xcf) {
+        /* just a reserved opcode, no data */
+        if (verbose)
+            pm_message("reserved 0x%x", opcode);
+    } else if (opcode >= 0xd0 && opcode <= 0xfe) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_long());
+    } else if (opcode >= 0x100 && opcode <= 0x7fff) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip((opcode >> 7) & 255);
+    } else if (opcode >= 0x8000 && opcode <= 0x80ff) {
+        /* just a reserved opcode */
+        if (verbose)
+            pm_message("reserved 0x%x", opcode);
+    } else if (opcode >= 0x8100) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_long());
+    } else
+        pm_error("This program does not understand opcode 0x%04x", opcode);
+}
+
+
+
+static void
 interpret_pict(FILE * const ofP) {
 
     byte ch;
     word picSize;
     word opcode;
-    word len;
     unsigned int version;
     int i;
     struct canvas canvas;
+    blitList blitList;
+
+    initBlitList(&blitList);
 
     for (i = 0; i < 64; i++)
         pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1;
@@ -3943,16 +4191,16 @@ interpret_pict(FILE * const ofP) {
     picSize = read_word();
 
     if (verbose)
-        pm_message("picture size = %d (0x%x)", picSize, picSize);
+        pm_message("picture size = %u (0x%x)", picSize, picSize);
 
     stage = "reading picture frame";
     read_rect(&picFrame);
 
     if (verbose) {
         dumpRect("Picture frame:", picFrame);
-        pm_message("Picture size is %d x %d",
-            picFrame.right - picFrame.left,
-            picFrame.bottom - picFrame.top);
+        pm_message("Picture size is %u x %u",
+                   picFrame.right - picFrame.left,
+                   picFrame.bottom - picFrame.top);
     }
 
     if (!fullres) {
@@ -3988,68 +4236,15 @@ interpret_pict(FILE * const ofP) {
     if (verbose)
         pm_message("PICT version %u", version);
 
-    while((opcode = get_op(version)) != 0xff) {
-        if (opcode < 0xa2) {
-            stage = optable[opcode].name;
-            if (verbose) {
-                if (streq(stage, "reserved"))
-                    pm_message("reserved opcode=0x%x", opcode);
-                else
-                    pm_message("Opcode: %s", optable[opcode].name);
-            }
-
-            if (optable[opcode].impl != NULL)
-                (*optable[opcode].impl)(&canvas, version);
-            else if (optable[opcode].len >= 0)
-                skip(optable[opcode].len);
-            else switch (optable[opcode].len) {
-            case WORD_LEN:
-                len = read_word();
-                skip(len);
-                break;
-            default:
-                pm_error("can't do length %u", optable[opcode].len);
-            }
-        } else if (opcode == 0xc00) {
-            if (verbose)
-                pm_message("HeaderOp");
-            stage = "HeaderOp";
-            skip(24);
-        } else if (opcode >= 0xa2 && opcode <= 0xaf) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_word());
-        } else if (opcode >= 0xb0 && opcode <= 0xcf) {
-            /* just a reserved opcode, no data */
-            if (verbose)
-                pm_message("reserved 0x%x", opcode);
-        } else if (opcode >= 0xd0 && opcode <= 0xfe) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_long());
-        } else if (opcode >= 0x100 && opcode <= 0x7fff) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip((opcode >> 7) & 255);
-        } else if (opcode >= 0x8000 && opcode <= 0x80ff) {
-            /* just a reserved opcode */
-            if (verbose)
-                pm_message("reserved 0x%x", opcode);
-        } else if (opcode >= 0x8100) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_long());
-        } else
-            pm_error("This program does not understand opcode 0x%04x", opcode);
-    }
+    while((opcode = get_op(version)) != 0xff)
+        processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version);
     
-    if (fullres)
-        do_blits(&canvas);
-
+    if (fullres) {
+        if (blitList.unblittableText)
+            pm_message("Warning: text is omitted from the output because "
+                       "we don't know how to do text with -fullres.");
+        doBlitList(&canvas, &blitList);
+    }
     outputPpm(ofP, canvas.planes);
 
     freePlanes(canvas.planes);
@@ -4123,6 +4318,7 @@ main(int argc, char * argv[]) {
 
     if (header) {
         stage = "Reading 512 byte header";
+        /* Note that the "header" in PICT is entirely comment! */
         skip(512);
     }
 
diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c
index 837d9e2b..e59f09b3 100644
--- a/converter/ppm/ppmtomitsu.c
+++ b/converter/ppm/ppmtomitsu.c
@@ -1,10 +1,10 @@
-/* ppmtomitsu.c - read a portable pixmap and produce output for the
+/* ppmtomitsu.c - read a PPM image and produce output for the
 **                Mitsubishi S340-10 Thermo-Sublimation Printer
 **                (or the S3410-30 parallel interface)
 **
 ** Copyright (C) 1992,93 by S.Petra Zeidler
 ** Minor modifications by Ingo Wilken:
-x**  - mymalloc() and check_and_rotate() functions for often used
+**  - mymalloc() and check_and_rotate() functions for often used
 **    code fragments.  Reduces code size by a few KB.
 **  - use pm_error() instead of fprintf(stderr)
 **  - localized allocation of colorhastable
@@ -271,12 +271,12 @@ frametransferinit(int              const cols,
 
 
 static void
-colorRow(colorhist_vector const table,
-         unsigned int     const colanz,
-         hashinfo *       const colorhashtable) {
+doLookupTableColors(colorhist_vector const table,
+                    unsigned int     const nColor,
+                    hashinfo *       const colorhashtable) {
                 
     unsigned int colval;
-    for (colval = 0; colval < colanz; ++colval) {
+    for (colval = 0; colval < nColor; ++colval) {
         struct hashinfo * const hashchain =
             &colorhashtable[myhash((table[colval]).color)];
 
@@ -308,12 +308,12 @@ colorRow(colorhist_vector const table,
 
 
 static void
-grayRow(colorhist_vector const table,
-        unsigned int     const colanz,
-        hashinfo *       const colorhashtable) {
+doLookupTableGrays(colorhist_vector const table,
+                   unsigned int     const nColor,
+                   hashinfo *       const colorhashtable) {
 
     unsigned int colval;
-    for (colval = 0; colval < colanz; ++colval) {
+    for (colval = 0; colval < nColor; ++colval) {
         struct hashinfo * const hashchain =
             &colorhashtable[myhash((table[colval]).color)];
         struct hashinfo * hashrun;
@@ -329,8 +329,7 @@ grayRow(colorhist_vector const table,
         if (hashrun->flag == -1) {
             hashrun->color = (table[colval]).color;
             hashrun->flag  = colval;
-                    }
-        else {
+        } else {
             while (hashrun->next != NULL)
                 hashrun = hashrun->next;
             MALLOCVAR_NOFAIL(hashrun->next);
@@ -345,20 +344,28 @@ grayRow(colorhist_vector const table,
 
 
 static void
-useLookupTable(pixel **         const pixels,
-               colorhist_vector const table,
-               int              const sharpness,
-               int              const enlarge,
-               int              const copy,
-               struct mediasize const medias,
-               unsigned int     const cols,
-               unsigned int     const rows,
-               int              const format,
-               unsigned int     const colanz) {
-
+generateLookupTable(colorhist_vector const table,
+                    unsigned int     const nColor,
+                    unsigned int     const cols,
+                    unsigned int     const rows,
+                    int              const format,
+                    int              const sharpness,
+                    int              const enlarge,
+                    int              const copy,
+                    struct mediasize const medias,
+                    hashinfo **      const colorhashtableP) {
+/*----------------------------------------------------------------------------
+   Write to the output file the palette (color lookup table) indicated by
+   'table' and generate a hash table to use with it: *colorhashtableP.
+
+   Also write the various properties 'sharpness', 'enlarge', 'copy', and
+   'medias' to the output file.
+-----------------------------------------------------------------------------*/
     hashinfo * colorhashtable;
 
-    pm_message("found %u colors - using the lookuptable-method", colanz);
+    lookuptableinit(sharpness, enlarge, copy, medias);
+
+    /* Initialize the hash table to empty */
 
     MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE);
     {
@@ -369,34 +376,75 @@ useLookupTable(pixel **         const pixels,
         }
     }
 
-    lookuptableinit(sharpness, enlarge, copy, medias);
     switch(PPM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        colorRow(table, colanz, colorhashtable);
+        doLookupTableColors(table, nColor, colorhashtable);
         break;
     default:
-        grayRow(table, colanz, colorhashtable);
+        doLookupTableGrays(table, nColor, colorhashtable);
     }
     lookuptabledata(cols, rows, enlarge, medias);
-    {
-        unsigned int row;
-        for (row = 0; row < rows; ++row) {
-            unsigned int col;
-            for (col = 0; col < cols; ++col) {
-                pixel * const pixrow = pixels[row];
-                struct hashinfo * const hashchain =
-                    &colorhashtable[myhash(pixrow[col])];
-                struct hashinfo * p;
+
+    *colorhashtableP = colorhashtable;
+}
+
+
+
+static void
+writeColormapRaster(pixel **         const pixels,
+                    unsigned int     const cols,
+                    unsigned int     const rows,
+                    hashinfo *       const colorhashtable) {
+/*----------------------------------------------------------------------------
+   Write a colormapped raster: write the pixels pixels[][] (dimensions cols x
+   rows) as indices into the colormap (palette; lookup table) indicated by
+   'colorhashtable'.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < cols; ++col) {
+            pixel * const pixrow = pixels[row];
+            struct hashinfo * const hashchain =
+                &colorhashtable[myhash(pixrow[col])];
+            struct hashinfo * p;
                 
-                p = hashchain;
-                while (!PPM_EQUAL((p->color), pixrow[col])) {
-                    assert(p->next);
-                    p = p->next;
-                }
-                datum(p->flag);
+            p = hashchain;
+            while (!PPM_EQUAL((p->color), pixrow[col])) {
+                assert(p->next);
+                p = p->next;
             }
+            datum(p->flag);
         }
     }
+}
+
+
+
+static void
+useLookupTable(pixel **         const pixels,
+               colorhist_vector const table,
+               int              const sharpness,
+               int              const enlarge,
+               int              const copy,
+               struct mediasize const medias,
+               unsigned int     const cols,
+               unsigned int     const rows,
+               int              const format,
+               unsigned int     const nColor) {
+
+    hashinfo * colorhashtable;
+
+    pm_message("found %u colors - using the lookuptable-method", nColor);
+
+    generateLookupTable(table, nColor, cols, rows, format,
+                        sharpness, enlarge, copy, medias,
+                        &colorhashtable);
+
+    writeColormapRaster(pixels, cols, rows, colorhashtable);
+
     free(colorhashtable);
 }
 
@@ -540,7 +588,7 @@ doTiny(FILE *           const ifP,
             data(blurow, cols);
             data(blurow, cols);
             data(blurow, cols);
-            }
+        }
         }
     }
 }
@@ -649,21 +697,21 @@ main(int argc, char * argv[]) {
 
     } else {
         pixel ** pixels;
-        int colanz;
+        int nColor;
         colorhist_vector table;
         unsigned int row;
 
         pixels = ppm_allocarray(cols, rows);
-        for (row = 0; row < rows; row++)
+        for (row = 0; row < rows; ++row)
             ppm_readppmrow(ifP, pixels[row], cols, maxval, format);
 
         /* first check wether we can use the lut transfer */
 
         table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1, 
-                                     &colanz);
+                                     &nColor);
         if (table)
             useLookupTable(pixels, table, sharpness, enlarge, copy, medias,
-                           cols, rows, format, colanz);
+                           cols, rows, format, nColor);
         else
             useNoLookupTable(pixels, sharpness, enlarge, copy, medias,
                              cols, rows, format);
@@ -673,4 +721,3 @@ main(int argc, char * argv[]) {
     pm_close(ifP);
     return 0;
 }
-
diff --git a/converter/ppm/ppmtomitsu.test b/converter/ppm/ppmtomitsu.test
index 1805838a..f574d927 100644
--- a/converter/ppm/ppmtomitsu.test
+++ b/converter/ppm/ppmtomitsu.test
@@ -2,9 +2,9 @@ echo Test 1.  Should print 3110813682 101562
 ./ppmtomitsu ../../testimg.ppm | cksum 
 echo Test 2.  Should print 239186803 34399
 pnmquant 100 ../../testimg.ppm | ./ppmtomitsu | cksum 
-echo Test 3.  Should print 816221676 310
+echo Test 3.  Should print 3201293405 310
 ./ppmtomitsu ../../testgrid.pbm | cksum 
-echo Test 4.  Should print 629834989 752
+echo Test 4.  Should print 3354679572 752
 ./ppmtomitsu -tiny ../../testgrid.pbm | cksum 
 echo Test 5.  Should print 3999654426 101549
 ./ppmtomitsu -tiny ../../testimg.ppm | cksum 
diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c
index 22456857..1b9f2d5c 100644
--- a/converter/ppm/ppmtopict.c
+++ b/converter/ppm/ppmtopict.c
@@ -398,7 +398,7 @@ char *packed;
 		*p++ = counttochar(count);
 
 	packcols = p - packed;		/* how many did we write? */
-	if (cols > 250)
+	if (cols > 200)
 	{
 		putShort(fd, packcols);
 		oc = packcols + 2;
@@ -436,7 +436,7 @@ char *packed;
 	bzero(aux, cols); /* aux?? */
 #endif /*notdef*/
 	bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT;
-	if (bc > 250)
+	if (bc > 200)
 	{
 		putShort(fd, bc);
 		oc = bc + 2;