about summary refs log tree commit diff
path: root/converter/ppm/ppmtobmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/ppm/ppmtobmp.c')
-rw-r--r--converter/ppm/ppmtobmp.c512
1 files changed, 331 insertions, 181 deletions
diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c
index 635464dd..c295f70c 100644
--- a/converter/ppm/ppmtobmp.c
+++ b/converter/ppm/ppmtobmp.c
@@ -18,15 +18,24 @@
 
 #include <assert.h>
 #include <string.h>
-#include "bmp.h"
-#include "ppm.h"
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "shhopt.h"
+#include "bmp.h"
 #include "bitio.h"
+#include "ppm.h"
 
 #define MAXCOLORS 256
 
 enum colortype {TRUECOLOR, PALETTE};
 
+struct rgb {
+    unsigned char red;
+    unsigned char grn;
+    unsigned char blu;
+};
+
 typedef struct {
 /*----------------------------------------------------------------------------
    A color map for a BMP file.
@@ -34,13 +43,13 @@ typedef struct {
     unsigned int count;
         /* Number of colors in the map.  The first 'count' elements of these
            arrays are defined; all others are not.
+
+           At most MAXCOLORS.
         */
     colorhash_table cht;
 
-    /* Indices in the following arrays are the same as in 'cht', above. */
-    unsigned char red[MAXCOLORS];
-    unsigned char grn[MAXCOLORS];
-    unsigned char blu[MAXCOLORS];
+    /* Indices in the following array are the same as in 'cht', above. */
+    struct rgb bmpMap[MAXCOLORS];
 } colorMap;
 
 
@@ -54,7 +63,7 @@ freeColorMap(const colorMap * const colorMapP) {
 
 
 
-static struct cmdline_info {
+struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -62,63 +71,71 @@ static struct cmdline_info {
     int class;  /* C_WIN or C_OS2 */
     unsigned int bppSpec;
     unsigned int bpp;
-} cmdline;
+    const char * mapfile;
+};
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdline_p) {
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdline_p structure are actually in the supplied argv array.  And
    sometimes, one of these strings is actually just a suffix of an entry
    in argv!
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
-    unsigned int windowsSpec, os2Spec;
+    unsigned int windowsSpec, os2Spec, mapfileSpec;
 
     unsigned int option_def_index;
+    
+    MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3('w', "windows",   OPT_FLAG, NULL, &windowsSpec,            0);
     OPTENT3('o', "os2",       OPT_FLAG, NULL, &os2Spec,                0);
-    OPTENT3(0,   "bpp",       OPT_UINT, &cmdline_p->bpp, 
-            &cmdline_p->bppSpec,      0);
+    OPTENT3(0,   "bpp",       OPT_UINT, &cmdlineP->bpp, 
+            &cmdlineP->bppSpec,      0);
+    OPTENT3(0,   "mapfile",   OPT_STRING, &cmdlineP->mapfile, 
+            &mapfileSpec,             0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (windowsSpec && os2Spec) 
         pm_error("Can't specify both -windows and -os2 options.");
     else if (windowsSpec) 
-        cmdline_p->class = C_WIN;
+        cmdlineP->class = C_WIN;
     else if (os2Spec)
-        cmdline_p->class = C_OS2;
+        cmdlineP->class = C_OS2;
     else 
-        cmdline_p->class = C_WIN;
+        cmdlineP->class = C_WIN;
 
 
-    if (cmdline_p->bppSpec) {
-        if (cmdline_p->bpp != 1 && cmdline_p->bpp != 4 && 
-            cmdline_p->bpp != 8 && cmdline_p->bpp != 24)
-        pm_error("Invalid -bpp value specified: %u.  The only values valid\n"
+    if (cmdlineP->bppSpec) {
+        if (cmdlineP->bpp != 1 && cmdlineP->bpp != 4 && 
+            cmdlineP->bpp != 8 && cmdlineP->bpp != 24)
+        pm_error("Invalid -bpp value specified: %u.  The only values valid "
                  "in the BMP format are 1, 4, 8, and 24 bits per pixel",
-                 cmdline_p->bpp);
+                 cmdlineP->bpp);
     }
 
+    if (!mapfileSpec)
+        cmdlineP->mapfile = NULL;
+
     if (argc - 1 == 0)
-        cmdline_p->input_filename = strdup("-");  /* he wants stdin */
+        cmdlineP->input_filename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
-        cmdline_p->input_filename = strdup(argv[1]);
+        cmdlineP->input_filename = strdup(argv[1]);
     else 
-        pm_error("Too many arguments.  The only argument accepted\n"
+        pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specificaton");
 
 }
@@ -243,7 +260,7 @@ BMPwriteinfoheader(FILE *        const fp,
 
 
 static int
-BMPwritergb(FILE * const fp, 
+BMPwriteRgb(FILE * const fp, 
             int    const class, 
             pixval const R, 
             pixval const G, 
@@ -264,7 +281,7 @@ BMPwritergb(FILE * const fp,
         PutByte(fp, R);
         return 3;
     default:
-        pm_error(er_internal, "BMPwritergb");
+        pm_error(er_internal, "BMPwriteRgb");
     }
     return -1;
 }
@@ -272,101 +289,118 @@ BMPwritergb(FILE * const fp,
 
 
 static int
-BMPwritecolormap(FILE *           const ifP, 
+BMPwriteColormap(FILE *           const ifP, 
                  int              const class, 
                  int              const bpp,
                  const colorMap * const colorMapP) {
 /*----------------------------------------------------------------------------
   Return the number of bytes written, or -1 on error.
 -----------------------------------------------------------------------------*/
-    long const ncolors = (1 << bpp);
+    unsigned int const ncolors = (1 << bpp);
 
-    unsigned int  nbyte;
-    unsigned int  i;
+    unsigned int nbyte;
+    unsigned int i;
 
-    nbyte = 0;
-    for (i = 0; i < colorMapP->count; ++i)
-        nbyte += BMPwritergb(ifP, class,
-                             colorMapP->red[i],
-                             colorMapP->grn[i],
-                             colorMapP->blu[i]);
+    assert(ncolors <= MAXCOLORS);
+    assert(ncolors <= ARRAY_SIZE(colorMapP->bmpMap));
 
+    nbyte = 0;
+    for (i = 0; i < colorMapP->count; ++i) {
+        const struct rgb * const mapEntryP = &colorMapP->bmpMap[i];
+        nbyte += BMPwriteRgb(ifP, class,
+                             mapEntryP->red, mapEntryP->grn, mapEntryP->blu);
+    }
     for (; i < ncolors; ++i)
-        nbyte += BMPwritergb(ifP, class, 0, 0, 0);
+        nbyte += BMPwriteRgb(ifP, class, 0, 0, 0);
 
     return nbyte;
 }
 
 
 
-static int
-BMPwriterow_palette(FILE *          const fp, 
+static void
+lookupColor(colorhash_table const cht,
+            pixel           const color,
+            unsigned int *  const colorIndexP) {
+
+    int rc;
+
+    rc = ppm_lookupcolor(cht, &color);
+
+    if (rc < 0)
+        pm_error("Color (%u,%u,%u) is not in the provided palette",
+                 PPM_GETR(color), PPM_GETG(color), PPM_GETB(color));
+    else
+        *colorIndexP = rc;
+}
+
+
+
+static void
+bmpWriteRow_palette(FILE *          const fp, 
                     const pixel *   const row, 
-                    unsigned long   const cx, 
+                    unsigned int    const cols,
                     unsigned short  const bpp, 
-                    colorhash_table const cht) {
+                    colorhash_table const cht,
+                    unsigned int *  const nBytesP) {
 /*----------------------------------------------------------------------------
-  Return the number of bytes written, or -1 on error.
+   Write a row to the raster in paletted format.
+
+   Return the number of bytes written as *nBytesP.
 -----------------------------------------------------------------------------*/
-    BITSTREAM    b;
-    int retval;
+    BITSTREAM b;
     
     b = pm_bitinit(fp, "w");
     if (b == NULL)
-        retval = -1;
+        pm_error("Failed to initialize output file for output");
     else {
+        int rc;
         unsigned int nbyte;
-        unsigned int x;
-        bool         error;
+        unsigned int col;
         
         nbyte = 0;      /* initial value */
-        error = FALSE;  /* initial value */
         
-        for (x = 0; x < cx && !error; ++x) {
+        for (col = 0; col < cols; ++col) {
+            unsigned int colorIndex;
             int rc;
-            rc = pm_bitwrite(b, bpp, ppm_lookupcolor(cht, &row[x]));
+
+            lookupColor(cht, row[col], &colorIndex);
+
+            rc = pm_bitwrite(b, bpp, colorIndex);
             if (rc == -1)
-                error = TRUE;
+                pm_error("Failed in writing a pixel "
+                         "to the raster in the output file");
             else
                 nbyte += rc;
         }
-        if (error)
-            retval = -1;
-        else {
-            int rc;
 
-            rc = pm_bitfini(b);
-            if (rc == -1)
-                retval = -1;
-            else {
-                nbyte += rc;
+        rc = pm_bitfini(b);
+
+        nbyte += rc;
                 
-                /* Make sure we write a multiple of 4 bytes.  */
-                while (nbyte % 4 != 0) {
-                    PutByte(fp, 0);
-                    ++nbyte;
-                }
-                retval = nbyte;
-            }
+        /* Make sure we write a multiple of 4 bytes.  */
+        while (nbyte % 4 != 0) {
+            PutByte(fp, 0);
+            ++nbyte;
         }
+        *nBytesP = nbyte;
     }
-    return retval;
 }
 
 
 
-static int
-BMPwriterow_truecolor(FILE *        const fp, 
-                      const pixel * const row, 
-                      unsigned long const cols,
-                      pixval        const maxval) {
+static void
+bmpWriteRow_truecolor(FILE *         const fp, 
+                      const pixel *  const row, 
+                      unsigned long  const cols,
+                      pixval         const maxval,
+                      unsigned int * const nBytesP) {
 /*----------------------------------------------------------------------------
   Write a row of a truecolor BMP image to the file 'fp'.  The row is 
   'row', which is 'cols' columns long.
 
-  Return the number of bytes written.
 
-  On error, issue error message and exit program.
+  Return the number of bytes written as *nBytesP.
 -----------------------------------------------------------------------------*/
     /* This works only for 24 bits per pixel.  To implement this for the
        general case (which is only hypothetical -- this program doesn't
@@ -380,7 +414,7 @@ BMPwriterow_truecolor(FILE *        const fp,
     int col;  
         
     nbyte = 0;  /* initial value */
-    for (col = 0; col < cols; col++) {
+    for (col = 0; col < cols; ++col) {
         /* We scale to the BMP maxval, which is always 255. */
         PutByte(fp, PPM_GETB(row[col]) * 255 / maxval);
         PutByte(fp, PPM_GETG(row[col]) * 255 / maxval);
@@ -393,18 +427,18 @@ BMPwriterow_truecolor(FILE *        const fp,
      */
     while (nbyte % 4) {
         PutByte(fp, 0);
-        nbyte++;
+        ++nbyte;
     }
     
-    return nbyte;
+    *nBytesP = nbyte;
 }
 
 
 
 static int
 BMPwritebits(FILE *          const fp, 
-             unsigned long   const cx, 
-             unsigned long   const cy, 
+             unsigned long   const cols, 
+             unsigned long   const rows,
              enum colortype  const colortype,
              unsigned short  const cBitCount, 
              const pixel **  const pixels, 
@@ -413,29 +447,29 @@ BMPwritebits(FILE *          const fp,
 /*----------------------------------------------------------------------------
   Return the number of bytes written, or -1 on error.
 -----------------------------------------------------------------------------*/
-    int  nbyte;
-    long y;
+    unsigned int nbyte;
+    int row;
 
     if (cBitCount > 24)
-        pm_error("cannot handle cBitCount: %d", cBitCount);
+        pm_error("cannot handle cBitCount: %hu", cBitCount);
 
     nbyte = 0;  /* initial value */
 
     /* The picture is stored bottom line first, top line last */
 
-    for (y = cy - 1; y >= 0; --y) {
-        int rc;
+    for (row = rows - 1; row >= 0; --row) {
+        unsigned int nBytesThisRow;
+
         if (colortype == PALETTE)
-            rc = BMPwriterow_palette(fp, pixels[y], cx, 
-                                     cBitCount, cht);
+            bmpWriteRow_palette(fp, pixels[row], cols, 
+                                cBitCount, cht, &nBytesThisRow);
         else 
-            rc = BMPwriterow_truecolor(fp, pixels[y], cx, maxval);
+            bmpWriteRow_truecolor(fp, pixels[row], cols, maxval,
+                                  &nBytesThisRow);
 
-        if (rc == -1)
-            pm_error("couldn't write row %ld", y);
-        if (rc % 4 != 0)
-            pm_error("row had bad number of bytes: %d", rc);
-        nbyte += rc;
+        if (nBytesThisRow % 4 != 0)
+            pm_error("row had bad number of bytes: %u", nBytesThisRow);
+        nbyte += nBytesThisRow;
     }
 
     return nbyte;
@@ -444,10 +478,10 @@ BMPwritebits(FILE *          const fp,
 
 
 static void
-BMPEncode(FILE *           const ifP, 
+bmpEncode(FILE *           const ifP, 
           int              const class, 
           enum colortype   const colortype,
-          int              const bpp,
+          unsigned int     const bpp,
           int              const x, 
           int              const y, 
           const pixel **   const pixels, 
@@ -459,25 +493,25 @@ BMPEncode(FILE *           const ifP,
     unsigned long nbyte;
 
     if (colortype == PALETTE)
-        pm_message("Writing %d bits per pixel with a color palette", bpp);
+        pm_message("Writing %u bits per pixel with a color palette", bpp);
     else
-        pm_message("Writing %d bits per pixel truecolor (no palette)", bpp);
+        pm_message("Writing %u bits per pixel truecolor (no palette)", bpp);
 
     nbyte = 0;  /* initial value */
     nbyte += BMPwritefileheader(ifP, class, bpp, x, y);
     nbyte += BMPwriteinfoheader(ifP, class, bpp, x, y);
     if (colortype == PALETTE)
-        nbyte += BMPwritecolormap(ifP, class, bpp, colorMapP);
+        nbyte += BMPwriteColormap(ifP, class, bpp, colorMapP);
 
     if (nbyte != (BMPlenfileheader(class)
                   + BMPleninfoheader(class)
                   + BMPlencolormap(class, bpp, 0)))
-        pm_error(er_internal, "BMPEncode 1");
+        pm_error(er_internal, "BmpEncode 1");
 
     nbyte += BMPwritebits(ifP, x, y, colortype, bpp, pixels, maxval,
                           colorMapP->cht);
     if (nbyte != BMPlenfile(class, bpp, -1, x, y))
-        pm_error(er_internal, "BMPEncode 2");
+        pm_error(er_internal, "BmpEncode 2");
 }
 
 
@@ -487,18 +521,18 @@ makeBilevelColorMap(colorMap * const colorMapP) {
 
     colorMapP->count  = 2;
     colorMapP->cht    = NULL;
-    colorMapP->red[0] = 0;
-    colorMapP->grn[0] = 0;
-    colorMapP->blu[0] = 0;
-    colorMapP->red[1] = 255;
-    colorMapP->grn[1] = 255;
-    colorMapP->blu[1] = 255;
+    colorMapP->bmpMap[0].red = 0;
+    colorMapP->bmpMap[0].grn = 0;
+    colorMapP->bmpMap[0].blu = 0;
+    colorMapP->bmpMap[1].red = 255;
+    colorMapP->bmpMap[1].grn = 255;
+    colorMapP->bmpMap[1].blu = 255;
 }
 
 
 
 static void
-BMPEncodePBM(FILE *           const ifP, 
+bmpEncodePbm(FILE *           const ifP, 
              int              const class, 
              int              const cols, 
              int              const rows, 
@@ -508,7 +542,7 @@ BMPEncodePBM(FILE *           const ifP,
 -----------------------------------------------------------------------------*/
     /* Note:
        Only PBM input uses this routine.  Color images represented by 1 bpp via
-       color palette use the general BMPEncode().
+       color palette use the general bmpEncode().
     */
     unsigned int const adjustedCols = (cols + 31) / 32 * 32;
     unsigned int const packedBytes  = adjustedCols / 8;
@@ -526,12 +560,12 @@ BMPEncodePBM(FILE *           const ifP,
 
     makeBilevelColorMap(&bilevelColorMap);
 
-    nbyte += BMPwritecolormap(ifP, class, 1, &bilevelColorMap);
+    nbyte += BMPwriteColormap(ifP, class, 1, &bilevelColorMap);
 
     if (nbyte != (BMPlenfileheader(class)
                   + BMPleninfoheader(class)
                   + BMPlencolormap(class, 1, 0)))
-        pm_error(er_internal, "BMPEncodePBM 1");
+        pm_error(er_internal, "bmpEncodePBM 1");
    
     for (row = 0; row < rows; ++row){
         size_t bytesWritten;
@@ -548,23 +582,129 @@ BMPEncodePBM(FILE *           const ifP,
     }
 
     if (nbyte != BMPlenfile(class, 1, -1, cols, rows))
-        pm_error(er_internal, "BMPEncodePBM 2");
+        pm_error(er_internal, "bmpEncodePbm 2");
 }
 
 
 
 static void
-analyze_colors(const pixel **    const pixels, 
-               int               const cols, 
-               int               const rows, 
-               pixval            const maxval, 
-               int *             const minimum_bpp_p,
-               colorMap *        const colorMapP) {
+makeHashFromBmpMap(const struct rgb * const bmpMap,
+                   unsigned int       const nColors,
+                   colorhash_table *  const chtP) {
+
+    colorhist_vector chv;
+    unsigned int i;
+
+    MALLOCARRAY_NOFAIL(chv, nColors);
+
+    for (i = 0; i < nColors; ++i) {
+        const struct rgb * const mapEntryP = &bmpMap[i];
+
+        PPM_ASSIGN(chv[i].color,
+                   mapEntryP->red, mapEntryP->grn, mapEntryP->blu);
+    }
+
+    *chtP = ppm_colorhisttocolorhash(chv, nColors);
+
+    ppm_freecolorhist(chv);
+}
+
+
+
+static unsigned int
+minBmpBitsForColorCount(unsigned int const colorCount) {
+
+    unsigned int const minbits = pm_maxvaltobits(colorCount - 1);
+
+    /* Only 1, 4, 8, and 24 are defined in the BMP spec we
+       implement and other bpp's have in fact been seen to confuse
+       viewers.  There is an extended BMP format that has 16 bpp
+       too, but this program doesn't know how to generate that
+       (see Bmptopnm.c, though).  
+    */
+    if (minbits == 1)
+        return 1;
+    else if (minbits <= 4)
+        return 4;
+    else if (minbits <= 8)
+        return 8;
+    else
+        return 24;
+}
+
+
+
+static void
+getMapFile(const char *   const mapFileName,
+           unsigned int * const minimumBppP,
+           colorMap *     const colorMapP) {
+/*----------------------------------------------------------------------------
+   Get the color map (palette) for the BMP from file 'mapFileName'.
+
+   Return the color map as *colormapP.
+
+   Return as *minimumBppP the minimum number of bits per pixel it will
+   take to represent all the colors in the map in the BMP format.
+-----------------------------------------------------------------------------*/
+
+    FILE * mapFileP;
+    int cols, rows;
+    pixval maxval;
+    pixel ** pixels;
+    unsigned int row;
+    unsigned int count;
+
+    mapFileP = pm_openr(mapFileName);
+
+    pixels = ppm_readppm(mapFileP, &cols, &rows, &maxval);
+
+    if (cols * rows > MAXCOLORS)
+        pm_error("The colormap file you gave (-mapfile) has too "
+                 "many entries for a BMP.  A BMP can have at most "
+                 "%u colors; the file has %u pixels, each of which "
+                 "represents an entry in the color map.",
+                 MAXCOLORS, cols * rows);
+
+    count = 0; /* initial value */
+    
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            pixel        const color     = pixels[row][col];
+            struct rgb * const mapEntryP = &colorMapP->bmpMap[count++];
+
+            assert(count <= ARRAY_SIZE(colorMapP->bmpMap));
+
+            mapEntryP->red = PPM_GETR(color) * 255 / maxval;
+            mapEntryP->grn = PPM_GETG(color) * 255 / maxval;
+            mapEntryP->blu = PPM_GETB(color) * 255 / maxval;
+        }
+    }
+    ppm_freearray(pixels, rows);
+
+    colorMapP->count = count;
+
+    makeHashFromBmpMap(colorMapP->bmpMap, colorMapP->count, &colorMapP->cht);
+
+    *minimumBppP = minBmpBitsForColorCount(count);
+
+    pm_close(mapFileP);
+}
+
+
+
+static void
+analyzeColors(const pixel **    const pixels, 
+              int               const cols, 
+              int               const rows, 
+              pixval            const maxval, 
+              unsigned int *    const minimumBppP,
+              colorMap *        const colorMapP) {
 /*----------------------------------------------------------------------------
   Look at the colors in the image 'pixels' and compute values to use in
   representing those colors in a BMP image.  
 
-  First of all, count the distinct colors.  Return as *minimum_bpp_p
+  First of all, count the distinct colors.  Return as *minimumBppP
   the minimum number of bits per pixel it will take to represent all
   the colors in BMP format.
 
@@ -589,37 +729,23 @@ analyze_colors(const pixel **    const pixels,
     colorMapP->count = colorCount;
     if (chv == NULL) {
         pm_message("More than %u colors found", MAXCOLORS);
-        *minimum_bpp_p = 24;
+        *minimumBppP = 24;
         colorMapP->cht = NULL;
     } else {
-        unsigned int const minbits = pm_maxvaltobits(colorMapP->count - 1);
-
         unsigned int i;
 
         pm_message("%u colors found", colorMapP->count);
 
-        /* Only 1, 4, 8, and 24 are defined in the BMP spec we
-           implement and other bpp's have in fact been seen to confuse
-           viewers.  There is an extended BMP format that has 16 bpp
-           too, but this program doesn't know how to generate that
-           (see Bmptopnm.c, though).  
-        */
-        if (minbits == 1)
-            *minimum_bpp_p = 1;
-        else if (minbits <= 4)
-            *minimum_bpp_p = 4;
-        else if (minbits <= 8)
-            *minimum_bpp_p = 8;
-        else
-            *minimum_bpp_p = 24;
+        *minimumBppP = minBmpBitsForColorCount(colorMapP->count);
 
         /*
          * Now scale the maxval to 255 as required by BMP format.
          */
         for (i = 0; i < colorMapP->count; ++i) {
-            colorMapP->red[i] = (pixval) PPM_GETR(chv[i].color) * 255 / maxval;
-            colorMapP->grn[i] = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
-            colorMapP->blu[i] = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
+            struct rgb * const mapEntryP = &colorMapP->bmpMap[i];
+            mapEntryP->red = (pixval) PPM_GETR(chv[i].color) * 255 / maxval;
+            mapEntryP->grn = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
+            mapEntryP->blu = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
         }
     
         /* And make a hash table for fast lookup. */
@@ -631,38 +757,52 @@ analyze_colors(const pixel **    const pixels,
 
 
 static void
-choose_colortype_bpp(struct cmdline_info const cmdline,
-                     unsigned int        const colors, 
-                     unsigned int        const minimum_bpp,
-                     enum colortype *    const colortype_p, 
-                     unsigned int *      const bits_per_pixel_p) {
+chooseColortypeBpp(bool             const userRequestsBpp,
+                   unsigned int     const requestedBpp,
+                   unsigned int     const minimumBpp,
+                   enum colortype * const colortypeP, 
+                   unsigned int *   const bitsPerPixelP) {
+/*----------------------------------------------------------------------------
+   Determine whether the BMP raster should contain RGB values or palette
+   indices and how many bits is should have for each pixel.
 
-    if (!cmdline.bppSpec) {
+   'userRequestsBpp' says the user has requested a particular number of
+   bits per pixel.  'requestedBpp' is his request, and we assume it's a
+   valid value for a BMP.
+
+   'colors' is how many colors are in the image.
+
+   'minimumBpp' is the minimum number of bits it takes to represent all
+   the colors in the image.  We assume it is valid for a BMP.
+
+   We return our choices as *colortypeP and *bitsPerPixelP.
+-----------------------------------------------------------------------------*/
+    if (!userRequestsBpp) {
         /* User has no preference as to bits per pixel.  Choose the
            smallest number possible for this image.
         */
-        *bits_per_pixel_p = minimum_bpp;
+        *bitsPerPixelP = minimumBpp;
     } else {
-        if (cmdline.bpp < minimum_bpp)
+        if (requestedBpp < minimumBpp)
             pm_error("There are too many colors in the image to "
-                     "represent in the\n"
-                     "number of bits per pixel you requested: %d.\n"
-                     "You may use Ppmquant to reduce the number of "
+                     "represent in the "
+                     "number of bits per pixel you requested: %d.  "
+                     "You may use Pnmquant to reduce the number of "
                      "colors in the image.",
-                     cmdline.bpp);
+                     requestedBpp);
         else
-            *bits_per_pixel_p = cmdline.bpp;
+            *bitsPerPixelP = requestedBpp;
     }
 
-    assert(*bits_per_pixel_p == 1 || 
-           *bits_per_pixel_p == 4 || 
-           *bits_per_pixel_p == 8 || 
-           *bits_per_pixel_p == 24);
+    assert(*bitsPerPixelP == 1 || 
+           *bitsPerPixelP == 4 || 
+           *bitsPerPixelP == 8 || 
+           *bitsPerPixelP == 24);
 
-    if (*bits_per_pixel_p > 8) 
-        *colortype_p = TRUECOLOR;
+    if (*bitsPerPixelP > 8) 
+        *colortypeP = TRUECOLOR;
     else {
-        *colortype_p = PALETTE;
+        *colortypeP = PALETTE;
     }
 }
 
@@ -676,12 +816,12 @@ doPbm(FILE *       const ifP,
       int          const class,
       FILE *       const ofP) {
     
-    /*  In the PBM case the raster is read directly from the input by 
-        pbm_readpbmrow_packed.  The raster format is almost identical,
-        except that BMP specifies rows to be zero-filled to 32 bit borders 
-        and that in BMP the bottom row comes first in order.
+    /* We read the raster directly from the input with
+        pbm_readpbmrow_packed().  The raster format is almost
+        identical, except that BMP specifies rows to be zero-filled to
+        32 bit borders and that in BMP the bottom row comes first in
+        order.
     */
-
     int const CHARBITS = (sizeof(unsigned char)*8); 
     int const colChars = pbm_packed_bytes(cols);
     int const adjustedCols = (cols+31) /32 * 32;
@@ -709,7 +849,7 @@ doPbm(FILE *       const ifP,
                 thisRow[i] = ~thisRow[i]; /* flip all pixels */
         }
         /* This may seem unnecessary, because the color palette 
-           (RGB[] in BMPEncodePBM) can be inverted for the same effect.
+           (RGB[] in bmpEncodePbm) can be inverted for the same effect.
            However we take this precaution, for there is indication that
            some BMP viewers may get confused with that.
         */
@@ -721,25 +861,28 @@ doPbm(FILE *       const ifP,
         }
     }
 
-    BMPEncodePBM(ofP, class, cols, rows, bitrow);
+    bmpEncodePbm(ofP, class, cols, rows, bitrow);
 }            
 
 
 
 static void
-doPgmPpm(FILE * const ifP,
+doPgmPpm(FILE *       const ifP,
          unsigned int const cols,
          unsigned int const rows,
          pixval       const maxval,
          int          const ppmFormat,
          int          const class,
+         bool         const userRequestsBpp,
+         unsigned int const requestedBpp,
+         const char * const mapFileName,
          FILE *       const ofP) {
 
-    /* PGM and PPM.  The input image is read into a PPM array, scanned
-       for color analysis and converted to a BMP raster.
-       Logic works for PBM.
+    /* PGM and PPM.  We read the input image into a PPM array, scan it
+       to analyze the colors, and convert it to a BMP raster.  Logic
+       works for PBM.
     */
-    int minimumBpp;
+    unsigned int minimumBpp;
     unsigned int bitsPerPixel;
     enum colortype colortype;
     unsigned int row;
@@ -752,13 +895,16 @@ doPgmPpm(FILE * const ifP,
     for (row = 0; row < rows; ++row)
         ppm_readppmrow(ifP, pixels[row], cols, maxval, ppmFormat);
     
-    analyze_colors((const pixel**)pixels, cols, rows, maxval, 
-                   &minimumBpp, &colorMap);
+    if (mapFileName)
+        getMapFile(mapFileName, &minimumBpp, &colorMap);
+    else
+        analyzeColors((const pixel**)pixels, cols, rows, maxval, 
+                      &minimumBpp, &colorMap);
     
-    choose_colortype_bpp(cmdline, colorMap.count, minimumBpp, &colortype, 
-                         &bitsPerPixel);
+    chooseColortypeBpp(userRequestsBpp, requestedBpp, minimumBpp,
+                       &colortype, &bitsPerPixel);
     
-    BMPEncode(stdout, class, colortype, bitsPerPixel,
+    bmpEncode(ofP, class, colortype, bitsPerPixel,
               cols, rows, (const pixel**)pixels, maxval, &colorMap);
     
     freeColorMap(&colorMap);
@@ -767,17 +913,19 @@ doPgmPpm(FILE * const ifP,
 
 
 int
-main(int argc, char **argv) {
+main(int           argc,
+     const char ** argv) {
 
+    struct cmdlineInfo cmdline;
     FILE * ifP;
     int rows;
     int cols;
     pixval maxval;
     int ppmFormat;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.input_filename);
     
@@ -786,7 +934,9 @@ main(int argc, char **argv) {
     if (PPM_FORMAT_TYPE(ppmFormat) == PBM_TYPE)
         doPbm(ifP, cols, rows, ppmFormat, cmdline.class, stdout);
     else
-        doPgmPpm(ifP, cols, rows, maxval, ppmFormat, cmdline.class, stdout);
+        doPgmPpm(ifP, cols, rows, maxval, ppmFormat,
+                 cmdline.class, cmdline.bppSpec, cmdline.bpp, cmdline.mapfile,
+                 stdout);
 
     pm_close(ifP);
     pm_close(stdout);