about summary refs log tree commit diff
path: root/converter/other/pnmtopalm/pnmtopalm.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/pnmtopalm/pnmtopalm.c')
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c567
1 files changed, 365 insertions, 202 deletions
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
index a7d1fd46..25c8af2e 100644
--- a/converter/other/pnmtopalm/pnmtopalm.c
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -29,33 +29,37 @@
 
 #include "pm_c_util.h"
 #include "pnm.h"
-#include "palm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "runlength.h"
 
-enum compressionType {COMP_NONE, COMP_SCANLINE, COMP_RLE, COMP_PACKBITS};
+#include "palm.h"
+#include "palmcolormap.h"
+
+enum CompressionType {COMP_NONE, COMP_SCANLINE, COMP_RLE, COMP_PACKBITS};
 
-struct cmdline_info {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFilespec;  /* Filespecs of input files */
-    const char * transparent;    /* -transparent value.  Null if unspec */
-    unsigned int depth;         /* -depth value.  0 if unspec */
-    unsigned int maxdepth;      /* -maxdepth value.  0 if unspec */
-    enum compressionType compression;
+    const char * transparent;
+    unsigned int depthSpec;
+    unsigned int depth;
+    unsigned int maxdepthSpec;
+    unsigned int maxdepth;
+    enum CompressionType compression;
     unsigned int verbose;
     unsigned int colormap;
-    unsigned int offset;        /* -offset specified */
-    unsigned int density;       /* screen density */
+    unsigned int offset;
+    unsigned int density;
     unsigned int withdummy;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
+parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -64,7 +68,7 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
     optEntry *option_def;
     unsigned int option_def_index;
 
-    unsigned int transSpec, depthSpec, maxdepthSpec, densitySpec;
+    unsigned int transSpec, densitySpec;
     unsigned int scanline_compression, rle_compression, packbits_compression;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
@@ -73,9 +77,9 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
     OPTENT3(0, "transparent",      OPT_STRING, 
             &cmdlineP->transparent, &transSpec, 0);
     OPTENT3(0, "depth",            OPT_UINT, 
-            &cmdlineP->depth,       &depthSpec, 0);
+            &cmdlineP->depth,       &cmdlineP->depthSpec, 0);
     OPTENT3(0, "maxdepth",         OPT_UINT, 
-            &cmdlineP->maxdepth,    &maxdepthSpec, 0);
+            &cmdlineP->maxdepth,    &cmdlineP->maxdepthSpec, 0);
     OPTENT3(0, "scanline_compression", OPT_FLAG, 
             NULL,                   &scanline_compression, 0);
     OPTENT3(0, "rle_compression",  OPT_FLAG, 
@@ -97,28 +101,26 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
     opt.short_allowed = FALSE; /* We have some short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
-    if (depthSpec) {
+    if (cmdlineP->depthSpec) {
         if (cmdlineP->depth != 1 && cmdlineP->depth != 2 
             && cmdlineP->depth != 4 && cmdlineP->depth != 8
             && cmdlineP->depth != 16)
             pm_error("invalid value for -depth: %u.  Valid values are "
                      "1, 2, 4, 8, and 16", cmdlineP->depth);
-    } else
-        cmdlineP->depth = 0;
+    }
 
-    if (maxdepthSpec) {
+    if (cmdlineP->maxdepthSpec) {
         if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2 
             && cmdlineP->maxdepth != 4 && cmdlineP->maxdepth != 8
             && cmdlineP->maxdepth != 16)
             pm_error("invalid value for -maxdepth: %u.  Valid values are "
                      "1, 2, 4, 8, and 16", cmdlineP->maxdepth);
-    } else
-        cmdlineP->maxdepth = 0;
+    }
 
-    if (depthSpec && maxdepthSpec && 
+    if (cmdlineP->depthSpec && cmdlineP->maxdepthSpec && 
         cmdlineP->depth > cmdlineP->maxdepth)
         pm_error("-depth value (%u) is greater than -maxdepth (%u) value.",
                  cmdlineP->depth, cmdlineP->maxdepth);
@@ -132,8 +134,8 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
             cmdlineP->density != PALM_DENSITY_DOUBLE &&
             cmdlineP->density != PALM_DENSITY_TRIPLE &&
             cmdlineP->density != PALM_DENSITY_QUADRUPLE)
-            pm_error("Invalid value for -density: %d.  Valid values are "
-                     "%d, %d, %d, %d and %d.", cmdlineP->density, 
+            pm_error("Invalid value for -density: %u.  Valid values are "
+                     "%u, %u, %u, %u and %u.", cmdlineP->density, 
                      PALM_DENSITY_LOW, PALM_DENSITY_ONEANDAHALF,
                      PALM_DENSITY_DOUBLE, PALM_DENSITY_TRIPLE,
                      PALM_DENSITY_QUADRUPLE);
@@ -164,7 +166,7 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
         
     if (argc-1 > 1)
         pm_error("This program takes at most 1 argument: the file name.  "
-                 "You specified %d", argc-1);
+                 "You specified %u", argc-1);
     else if (argc-1 > 0) 
         cmdlineP->inputFilespec = argv[1];
     else
@@ -173,108 +175,241 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
 
 
 
+static xelval
+scaleSample(pixval const arg,
+            pixval const oldMaxval,
+            pixval const newMaxval) {
+
+    return (arg * newMaxval + oldMaxval/2) / oldMaxval;
+}
+
+
+
+static void
+determinePalmFormatPgm(xelval               const maxval, 
+                       bool                 const bppSpecified,
+                       unsigned int         const bpp,
+                       bool                 const maxBppSpecified,
+                       unsigned int         const maxBpp, 
+                       bool                 const wantCustomColormap,
+                       enum CompressionType const compression,
+                       bool                 const verbose,
+                       unsigned int *       const bppP) {
+        
+    /* We can usually handle this one, but may not have enough pixels.  So
+       check.
+    */
+
+    if (wantCustomColormap)
+        pm_error("You specified -colormap with a black and white input"
+                 "image.  -colormap is valid only with color.");
+    if (bppSpecified)
+        *bppP = bpp;
+    else if (maxBppSpecified && (maxval >= (1 << maxBpp)))
+        *bppP = maxBpp;
+    else if (compression != COMP_NONE && maxval > 255)
+        *bppP = 8;
+    else if (maxval > 16)
+        *bppP = 4;
+    else {
+        /* scale to minimum number of bpp needed */
+        unsigned int bpp;
+        for (bpp = 1;  (1 << bpp) < maxval;  bpp *= 2)
+            ;
+        *bppP = bpp;
+    }
+    if (verbose)
+        pm_message("output is grayscale %u bits-per-pixel", *bppP);
+}
+
+
+
+static void
+validateImageAgainstStandardColormap(const Colormap * const colormapP,
+                                     xel **           const xels,
+                                     unsigned int     const cols,
+                                     unsigned int     const rows,
+                                     xelval           const maxval) {
+/*----------------------------------------------------------------------------
+   Abort program if the image xels[][] (which is 'cols' x 'rows') contains a
+   color not in the colormap *colormapP, giving an error message assuming the
+   user chose the standard Palm colormap.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < cols; ++col) {
+            ColormapEntry const searchTarget = 
+                palmcolor_mapEntryColorFmPixel(xels[row][col], maxval, 255);
+
+            ColormapEntry * const foundEntryP = 
+                (bsearch(&searchTarget,
+                         colormapP->color_entries, colormapP->ncolors,
+                         sizeof(ColormapEntry), palmcolor_compare_colors));
+            if (!foundEntryP)
+                pm_error(
+                    "A color in the input image is not in the standard Palm "
+                    "8-bit color palette.  Either adjust the colors in the "
+                    "input with 'pnmremap' and the 'palmcolor8.map' file "
+                    "(see manual) or specify -colormap or -depth=16");
+        }
+    }
+}
+
+
+
+static void
+determinePalmFormatPpm(unsigned int         const cols, 
+                       unsigned int         const rows, 
+                       xelval               const maxval, 
+                       xel **               const xels,
+                       bool                 const bppSpecified,
+                       unsigned int         const bpp,
+                       bool                 const maxBppSpecified,
+                       unsigned int         const maxBpp, 
+                       bool                 const wantCustomColormap,
+                       enum CompressionType const compression,
+                       bool                 const verbose,
+                       unsigned int *       const bppP, 
+                       bool *               const directColorP, 
+                       Colormap **          const colormapPP) {
+            
+    /* We don't attempt to identify PPM files that are actually
+       monochrome.  So there are two options here: either 8-bit with a
+       colormap, either the standard one or a custom one, or 16-bit direct
+       color.  In the colormap case, if 'wantCustomColormap' is true (not
+       recommended by Palm) we will put in our own colormap that has the
+       colors of the input image; otherwise we will select the default
+       Palm colormap and will fail if the input image has any colors that
+       are not in that map (user should use Pnmremap and the
+       palmcolor8.map file that comes with Netpbm to avoid this).  We try
+       for colormapped first, since it works on more PalmOS devices.
+    */
+    if ((bppSpecified && bpp == 16) || 
+        (!bppSpecified && maxBppSpecified && maxBpp == 16)) {
+        /* we do the 16-bit direct color */
+        *directColorP = TRUE;
+        *colormapPP = NULL;
+        *bppP = 16;
+    } else if (!wantCustomColormap) {
+        /* colormapped with the standard colormap */
+        Colormap * colormapP;
+            
+        if ((bppSpecified && bpp != 8) || (maxBppSpecified && maxBpp < 8))
+            pm_error("Must use depth of 8 for color Palm Bitmap without "
+                     "custom color table.");
+        colormapP = palmcolor_build_default_8bit_colormap();
+        validateImageAgainstStandardColormap(colormapP,
+                                             xels, cols, rows, maxval);
+
+        *colormapPP = colormapP;
+        *bppP = 8;
+        *directColorP = FALSE;
+        if (verbose)
+            pm_message("Output is color with default colormap at 8 bpp");
+    } else {
+        /* colormapped with a custom colormap */
+        *colormapPP = 
+            palmcolor_build_custom_8bit_colormap(xels, rows, cols, maxval);
+        for (*bppP = 1; (1 << *bppP) < (*colormapPP)->ncolors; *bppP *= 2);
+        if (bppSpecified) {
+            if (bpp >= *bppP)
+                *bppP = bpp;
+            else
+                pm_error("Too many colors for specified depth.  "
+                         "Specified depth is %u bits; would need %u to "
+                         "represent the %u colors in the image.  "
+                         "Use pnmquant to reduce.",
+                         maxBpp, *bppP, (*colormapPP)->ncolors);
+        } else if (maxBppSpecified && maxBpp < *bppP) {
+            pm_error("Too many colors for specified max depth.  "
+                     "Specified maximum is %u bits; would need %u to "
+                     "represent the %u colors in the image.  "
+                     "Use pnmquant to reduce.",
+                     maxBpp, *bppP, (*colormapPP)->ncolors);
+        } else if (compression != COMP_NONE && *bppP > 8) {
+            pm_error("Too many colors for a compressed image.  "
+                     "Maximum is 256; the image has %u",
+                     (*colormapPP)->ncolors);
+        }
+        *directColorP = FALSE;
+        if (verbose)
+            pm_message("Output is color with custom colormap "
+                       "with %u colors at %u bpp", 
+                       (*colormapPP)->ncolors, *bppP);
+    }
+}
+
+
+
 static void
-determinePalmFormat(unsigned int   const cols, 
-                    unsigned int   const rows, 
-                    xelval         const maxval, 
-                    int            const format, 
-                    xel **         const xels,
-                    unsigned int   const specified_bpp,
-                    unsigned int   const max_bpp, 
-                    bool           const custom_colormap,
-                    bool           const verbose,
-                    unsigned int * const bppP, 
-                    bool *         const directColorP, 
-                    Colormap *     const colormapP) {
+determinePalmFormat(unsigned int         const cols, 
+                    unsigned int         const rows, 
+                    xelval               const maxval, 
+                    int                  const format, 
+                    xel **               const xels,
+                    bool                 const bppSpecified,
+                    unsigned int         const bpp,
+                    bool                 const maxBppSpecified,
+                    unsigned int         const maxBpp, 
+                    bool                 const wantCustomColormap,
+                    enum CompressionType const compression,
+                    bool                 const verbose,
+                    unsigned int *       const bppP, 
+                    bool *               const directColorP, 
+                    Colormap **          const colormapPP) {
+/*----------------------------------------------------------------------------
+   Determine what kind of Palm output file to make.
 
+   Also compute the colormap, if there is to be one.  This could be either one
+   we make up, that needs to go into the image, or a standard one.
+-----------------------------------------------------------------------------*/
+    if (compression != COMP_NONE) {
+        if (bppSpecified && bpp > 8)
+            pm_error("You requested %u bits per pixel and compression.  "
+                     "This program does not know how to generate a "
+                     "compressed image with more than 8 bits per pixel",
+                     bpp);
+        if (maxBppSpecified && maxBpp > 8)
+            pm_error("You requested %u max bits per pixel and compression.  "
+                     "This program does not know how to generate a "
+                     "compressed image with more than 8 bits per pixel",
+                     maxBpp);
+    }
     if (PNM_FORMAT_TYPE(format) == PBM_TYPE) {
-        if (custom_colormap)
+        if (wantCustomColormap)
             pm_error("You specified -colormap with a black and white input "
                      "image.  -colormap is valid only with color.");
-        if (specified_bpp)
-            *bppP = specified_bpp;
+        if (bppSpecified)
+            *bppP = bpp;
         else
             *bppP = 1;    /* no point in wasting bits */
         *directColorP = FALSE;
-        *colormapP = NULL;
+        *colormapPP = NULL;
         if (verbose)
             pm_message("output is black and white");
     } else if (PNM_FORMAT_TYPE(format) == PGM_TYPE) {
-        /* we can usually handle this one, but may not have enough
-           pixels.  So check... */
-        if (custom_colormap)
-            pm_error("You specified -colormap with a black and white input"
-                     "image.  -colormap is valid only with color.");
-        if (specified_bpp)
-            *bppP = specified_bpp;
-        else if (max_bpp && (maxval >= (1 << max_bpp)))
-            *bppP = max_bpp;
-        else if (maxval > 16)
-            *bppP = 4;
-        else {
-            /* scale to minimum number of bpp needed */
-            for (*bppP = 1;  (1 << *bppP) < maxval;  *bppP *= 2)
-                ;
-        }
-        if (*bppP > 4)
-            *bppP = 4;
-        if (verbose)
-            pm_message("output is grayscale %d bits-per-pixel", *bppP);
+        determinePalmFormatPgm(maxval,
+                               bppSpecified, bpp, maxBppSpecified, maxBpp,
+                               wantCustomColormap, compression,
+                               verbose,
+                               bppP);
+
         *directColorP = FALSE;
-        *colormapP = NULL;
+        *colormapPP = NULL;
     } else if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
-
-        /* We assume that we only get a PPM if the image cannot be
-           represented as PBM or PGM.  There are two options here: either
-           8-bit with a colormap, either the standard one or a custom one,
-           or 16-bit direct color.  In the 8-bit case, if "custom_colormap"
-           is specified (not recommended by Palm) we will put in our own
-           colormap; otherwise we will assume that the colors have been
-           mapped to the default Palm colormap by appropriate use of
-           pnmquant.  We try for 8-bit color first, since it works on
-           more PalmOS devices. 
-        */
-        if ((specified_bpp == 16) || 
-            (specified_bpp == 0 && max_bpp == 16)) {
-            /* we do the 16-bit direct color */
-            *directColorP = TRUE;
-            *colormapP = NULL;
-            *bppP = 16;
-        } else if (!custom_colormap) {
-            /* standard indexed 8-bit color */
-            *colormapP = palmcolor_build_default_8bit_colormap();
-            *bppP = 8;
-            if (((specified_bpp != 0) && (specified_bpp != 8)) ||
-                ((max_bpp != 0) && (max_bpp < 8)))
-                pm_error("Must use depth of 8 for color Palm Bitmap without "
-                         "custom color table.");
-            *directColorP = FALSE;
-            if (verbose)
-                pm_message("Output is color with default colormap at 8 bpp");
-        } else {
-            /* indexed 8-bit color with a custom colormap */
-            *colormapP = 
-                palmcolor_build_custom_8bit_colormap(rows, cols, xels);
-            for (*bppP = 1; (1 << *bppP) < (*colormapP)->ncolors; *bppP *= 2);
-            if (specified_bpp != 0) {
-                if (specified_bpp >= *bppP)
-                    *bppP = specified_bpp;
-                else
-                    pm_error("Too many colors for specified depth.  "
-                             "Use pnmquant to reduce.");
-            } else if ((max_bpp != 0) && (max_bpp < *bppP)) {
-                pm_error("Too many colors for specified max depth.  "
-                         "Use pnmquant to reduce.");
-            }
-            *directColorP = FALSE;
-            if (verbose)
-                pm_message("Output is color with custom colormap "
-                           "with %d colors at %d bpp", 
-                           (*colormapP)->ncolors, *bppP);
-        }
+        determinePalmFormatPpm(cols, rows, maxval, xels, bppSpecified, bpp,
+                               maxBppSpecified, maxBpp,
+                               wantCustomColormap, compression, verbose,
+                               bppP, directColorP, colormapPP);
     } else {
         pm_error("unknown format 0x%x on input file", (unsigned) format);
     }
+
+    if (compression != COMP_NONE)
+        assert(*bppP <= 8);
 }
 
 
@@ -300,25 +435,23 @@ findTransparentColor(const char *   const colorSpec,
                      pixval         const newMaxval,
                      bool           const directColor, 
                      pixval         const maxval, 
-                     Colormap       const colormap,
+                     Colormap *     const colormapP,
                      xel *          const transcolorP, 
                      unsigned int * const transindexP) {
 
     *transcolorP = ppm_parsecolor(colorSpec, maxval);
     if (!directColor) {
-        Color_s const temp_color = 
-            ((((PPM_GETR(*transcolorP)*newMaxval) / maxval) << 16) 
-             | (((PPM_GETG(*transcolorP)*newMaxval) / maxval) << 8)
-             | ((PPM_GETB(*transcolorP)*newMaxval) / maxval));
-        Color const found = 
-            (bsearch(&temp_color,
-                     colormap->color_entries, colormap->ncolors,
-                     sizeof(Color_s), palmcolor_compare_colors));
-        if (!found) {
+        ColormapEntry const searchTarget = 
+            palmcolor_mapEntryColorFmPixel(*transcolorP, maxval, newMaxval);
+        ColormapEntry * const foundEntryP = 
+            (bsearch(&searchTarget,
+                     colormapP->color_entries, colormapP->ncolors,
+                     sizeof(ColormapEntry), palmcolor_compare_colors));
+        if (!foundEntryP) {
             pm_error("Specified transparent color %s not found "
                      "in colormap.", colorSpec);
         } else
-            *transindexP = (*found >> 24) & 0xFF;
+            *transindexP = (*foundEntryP >> 24) & 0xFF;
     }
 }
 
@@ -326,9 +459,9 @@ findTransparentColor(const char *   const colorSpec,
 
 static unsigned int
 bitmapVersion(unsigned int         const bpp,
-              bool                 const colormap,
+              bool                 const colormapped,
               bool                 const transparent,
-              enum compressionType const compression,
+              enum CompressionType const compression,
               unsigned int         const density) {
 /*----------------------------------------------------------------------------
    Return the version number of the oldest version that can represent
@@ -343,7 +476,7 @@ bitmapVersion(unsigned int         const bpp,
         version = 3;
     else if (transparent || compression != COMP_NONE)
         version = 2;
-    else if (bpp > 1 || colormap)
+    else if (bpp > 1 || colormapped)
         version = 1;
     else
         version = 0;
@@ -357,8 +490,8 @@ static void
 writeCommonHeader(unsigned int         const cols,
                   unsigned int         const rows,
                   unsigned int         const rowbytes,
-                  enum compressionType const compression,
-                  bool                 const colormap,
+                  enum CompressionType const compression,
+                  bool                 const colormapped,
                   bool                 const transparent,
                   bool                 const directColor,
                   unsigned int         const bpp,
@@ -382,7 +515,7 @@ writeCommonHeader(unsigned int         const cols,
     flags = 0;  /* initial value */
     if (compression != COMP_NONE)
         flags |= PALM_IS_COMPRESSED_FLAG;
-    if (colormap)
+    if (colormapped)
         flags |= PALM_HAS_COLORMAP_FLAG;
     if (transparent)
         flags |= PALM_HAS_TRANSPARENCY_FLAG;
@@ -398,7 +531,7 @@ writeCommonHeader(unsigned int         const cols,
 
 
 static unsigned char 
-compressionFieldValue(enum compressionType const compression) {
+compressionFieldValue(enum CompressionType const compression) {
 
     unsigned char retval;
 
@@ -424,7 +557,7 @@ compressionFieldValue(enum compressionType const compression) {
 static void
 writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
                         unsigned int         const transindex,
-                        enum compressionType const compression,
+                        enum CompressionType const compression,
                         unsigned int         const bpp) {
 /*----------------------------------------------------------------------------
    Write last 6 bytes of a low density Palm Bitmap header. 
@@ -449,7 +582,7 @@ writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
 
 static void
 writeRemainingHeaderHigh(unsigned int         const bpp,
-                         enum compressionType const compression,
+                         enum CompressionType const compression,
                          unsigned int         const density,
                          xelval               const maxval,
                          bool                 const transparent,
@@ -480,9 +613,9 @@ writeRemainingHeaderHigh(unsigned int         const bpp,
         if (bpp == 16) {
             /* Blind guess here */
             fputc(0, stdout);
-            fputc((PPM_GETR(transcolor) * 255) / maxval, stdout);
-            fputc((PPM_GETG(transcolor) * 255) / maxval, stdout);
-            fputc((PPM_GETB(transcolor) * 255) / maxval, stdout);
+            fputc(scaleSample(PPM_GETR(transcolor), maxval, 255), stdout);
+            fputc(scaleSample(PPM_GETG(transcolor), maxval, 255), stdout);
+            fputc(scaleSample(PPM_GETB(transcolor), maxval, 255), stdout);
         } else {
             assert(transindex <= UCHAR_MAX);
             fputc(0, stdout);
@@ -523,7 +656,7 @@ writeDummy() {
 
 static void
 writeColormap(bool         const explicitColormap,
-              Colormap     const colormap,
+              Colormap *   const colormapP,
               bool         const directColor,
               unsigned int const bpp,
               bool         const transparent,
@@ -534,14 +667,14 @@ writeColormap(bool         const explicitColormap,
     /* if there's a colormap, write it out */
     if (explicitColormap) {
         unsigned int row;
-        if (!colormap)
+        if (!colormapP)
             pm_error("Internal error: user specified -colormap, but we did "
                      "not generate a colormap.");
-        qsort (colormap->color_entries, colormap->ncolors,
-               sizeof(Color_s), palmcolor_compare_indices);
-        pm_writebigshort( stdout, colormap->ncolors );
-        for (row = 0;  row < colormap->ncolors; ++row)
-            pm_writebiglong (stdout, colormap->color_entries[row]);
+        qsort(colormapP->color_entries, colormapP->ncolors,
+              sizeof(ColormapEntry), palmcolor_compare_indices);
+        pm_writebigshort( stdout, colormapP->ncolors );
+        for (row = 0;  row < colormapP->ncolors; ++row)
+            pm_writebiglong (stdout, colormapP->color_entries[row]);
     }
 
     if (directColor && (version < 3)) {
@@ -552,13 +685,13 @@ writeColormap(bool         const explicitColormap,
             fputc(5, stdout);   /* # of bits of blue */
             fputc(0, stdout);   /* reserved by Palm */
         } else
-            pm_error("Don't know how to create %d bit DirectColor bitmaps.", 
+            pm_error("Don't know how to create %u bit DirectColor bitmaps.", 
                      bpp);
         if (transparent) {
             fputc(0, stdout);
-            fputc((PPM_GETR(transcolor) * 255) / maxval, stdout);
-            fputc((PPM_GETG(transcolor) * 255) / maxval, stdout);
-            fputc((PPM_GETB(transcolor) * 255) / maxval, stdout);
+            fputc(scaleSample(PPM_GETR(transcolor) , maxval, 255), stdout);
+            fputc(scaleSample(PPM_GETG(transcolor) , maxval, 255), stdout);
+            fputc(scaleSample(PPM_GETB(transcolor) , maxval, 255), stdout);
         } else
             pm_writebiglong(stdout, 0);     /* no transparent color */
     }
@@ -571,17 +704,29 @@ computeRawRowDirectColor(const xel *     const xelrow,
                          unsigned int    const cols,
                          xelval          const maxval,
                          unsigned char * const rowdata) {
+/*----------------------------------------------------------------------------
+  Compute a row of Palm data in raw (uncompressed) form for an image that
+  uses direct color (really, true color: each pixel contains RGB intensities
+  as distinct R, G, and B numbers).
 
+  In this format, each pixel is 16 bits: 5 red, 6 green, 5 blue.
+
+  'xelrow' is the image contents of row.  It is 'cols' columns wide and
+  samples are based on maxval 'maxval'.
+
+  Put the output data at 'rowdata'. 
+-----------------------------------------------------------------------------*/
     unsigned int col;
-    unsigned char *outptr;
+    unsigned char * outCursor;
     
-    for (col = 0, outptr = rowdata; col < cols; ++col) {
+    for (col = 0, outCursor = &rowdata[0]; col < cols; ++col) {
         unsigned int const color = 
-            ((((PPM_GETR(xelrow[col])*31)/maxval) << 11) |
-             (((PPM_GETG(xelrow[col])*63)/maxval) << 5) |
-             ((PPM_GETB(xelrow[col])*31)/maxval));
-        *outptr++ = (color >> 8) & 0xFF;
-        *outptr++ = color & 0xFF;
+            (scaleSample(PPM_GETR(xelrow[col]), maxval, 31) << 11) |
+            (scaleSample(PPM_GETG(xelrow[col]), maxval, 63) <<  5) |
+            (scaleSample(PPM_GETB(xelrow[col]), maxval, 31) <<  0);
+
+        *outCursor++ = (color >> 8) & 0xFF;
+        *outCursor++ = color & 0xFF;
     }
 }
 
@@ -592,23 +737,40 @@ computeRawRowNonDirect(const xel *     const xelrow,
                        unsigned int    const cols,
                        xelval          const maxval,
                        unsigned int    const bpp,
-                       Colormap        const colormap,
+                       Colormap *      const colormapP,
                        unsigned int    const newMaxval,
                        unsigned char * const rowdata) {
+/*----------------------------------------------------------------------------
+  Compute a row of Palm data in raw (uncompressed) form for an image that
+  does not have a raster whose elements are explicit R, G, and B
+  intensities.
 
+  If 'colormapP' is non-null, the pixel is an index into that colormap.
+  'newMaxval' is meaningless.
+
+  If 'colormapP' is null, the pixel is a grayscale intensity, on a scale with
+  maximum value 'newMaxval'.  (N.B. this is really direct color, but for some
+  reason it's historically lumped in with the paletted formats).
+
+  'xelrow' is the image contents of row.  It is 'cols' columns wide and
+  samples are based on maxval 'maxval'.
+
+  Put the output data at 'rowdata', using 'bpp' bits per pixel.
+-----------------------------------------------------------------------------*/
     unsigned int col;
-    unsigned char *outptr;
+    unsigned char * outCursor;
+        /* Points to next slot in 'rowdata' we will fill */
     unsigned char outbyte;
         /* Accumulated bits to be output */
     unsigned char outbit;
         /* The lowest bit number we want to access for this pixel */
 
-    outbyte = 0x00;
-    outptr = rowdata;
+    outbyte = 0x00;  /* initial value */
+    outCursor = &rowdata[0];  /* Start at the beginning of the row */
 
     for (outbit = 8 - bpp, col = 0; col < cols; ++col) {
         unsigned int color;
-        if (!colormap) {
+        if (!colormapP) {
             /* we assume grayscale, and use simple scaling */
             color = (PNM_GET1(xelrow[col]) * newMaxval)/maxval;
             if (color > newMaxval)
@@ -616,24 +778,23 @@ computeRawRowNonDirect(const xel *     const xelrow,
                          "color of %u.", color);
             color = newMaxval - color; /* note grayscale maps are inverted */
         } else {
-            Color_s const temp_color =
-                ((((PPM_GETR(xelrow[col])*newMaxval)/maxval)<<16) 
-                 | (((PPM_GETG(xelrow[col])*newMaxval)/maxval)<<8)
-                 | (((PPM_GETB(xelrow[col])*newMaxval)/maxval)));
-            Color const found = (bsearch (&temp_color,
-                                          colormap->color_entries, 
-                                          colormap->ncolors,
-                                          sizeof(Color_s), 
-                                          palmcolor_compare_colors));
-            if (!found) {
-                pm_error("Color %d:%d:%d not found in colormap.  "
-                         "Try using pnmquant to reduce the "
-                         "number of colors.",
+            ColormapEntry const searchTarget =
+                palmcolor_mapEntryColorFmPixel(xelrow[col], maxval, 255);
+            ColormapEntry * const foundEntryP =
+                bsearch(&searchTarget,
+                        colormapP->color_entries, 
+                        colormapP->ncolors,
+                        sizeof(ColormapEntry), 
+                        palmcolor_compare_colors);
+            if (!foundEntryP) {
+                pm_error("INERNAL ERROR: "
+                         "Color (%u,%u,%u) not found in colormap, "
+                         "though it was supposedly there before",
                          PPM_GETR(xelrow[col]), 
                          PPM_GETG(xelrow[col]), 
                          PPM_GETB(xelrow[col]));
             }
-            color = (*found >> 24) & 0xFF;
+            color = (*foundEntryP >> 24) & 0xFF;
         }
 
         if (color > newMaxval)
@@ -642,7 +803,7 @@ computeRawRowNonDirect(const xel *     const xelrow,
         outbyte |= (color << outbit);
         if (outbit == 0) {
             /* Bit buffer is full.  Flush to to rowdata. */
-            *outptr++ = outbyte;
+            *outCursor++ = outbyte;
             outbyte = 0x00;
             outbit = 8 - bpp;
         } else
@@ -650,7 +811,7 @@ computeRawRowNonDirect(const xel *     const xelrow,
     }
     if ((cols % (8 / bpp)) != 0) {
         /* Flush bits remaining in the bit buffer to rowdata */
-        *outptr++ = outbyte;
+        *outCursor++ = outbyte;
     }
 }
 
@@ -830,7 +991,7 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
         unsigned int repeatcount;
         for (repeatcount = 1;  
              repeatcount < (rowbytes - pos) && repeatcount  < 255;  
-             ++repeatcount)
+             ++repeatcount) 
             if (rowdata[pos + repeatcount] != rowdata[pos])
                 break;
 
@@ -870,7 +1031,7 @@ packbitsCompressAndBufferRow(const unsigned char * const rowdata,
 static void
 bufferRowFromRawRowdata(const unsigned char *  const rowdata,
                         unsigned int           const rowbytes,
-                        enum compressionType   const compression,
+                        enum CompressionType   const compression,
                         const unsigned char *  const lastrow,
                         struct seqBuffer *     const rasterBufferP) {
 /*----------------------------------------------------------------------------
@@ -909,16 +1070,17 @@ bufferRow(const xel *          const xelrow,
           unsigned int         const rowbytes,
           unsigned int         const bpp,
           unsigned int         const newMaxval,
-          enum compressionType const compression,
+          enum CompressionType const compression,
           bool                 const directColor,
-          Colormap             const colormap,
+          Colormap *           const colormapP,
           unsigned char *      const rowdata,
           unsigned char *      const lastrow,
           struct seqBuffer *   const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Add a row of the Palm Bitmap raster to buffer 'rasterBufferP'.
    
-   'xelrow' is the image contents of row.  It is 'cols' columns wide.
+   'xelrow' is the image contents of row.  It is 'cols' columns wide and
+   samples are based on maxval 'maxval'.
 
    If 'compression' indicates scanline compression, 'lastrow' is the
    row immediately preceding this one in the image (and this function
@@ -930,7 +1092,7 @@ bufferRow(const xel *          const xelrow,
     if (directColor)
         computeRawRowDirectColor(xelrow, cols, maxval, rowdata);
     else 
-        computeRawRowNonDirect(xelrow, cols, maxval, bpp, colormap, newMaxval,
+        computeRawRowNonDirect(xelrow, cols, maxval, bpp, colormapP, newMaxval,
                                rowdata);
 
     bufferRowFromRawRowdata(rowdata, rowbytes, compression,
@@ -947,9 +1109,9 @@ bufferRaster(xel **               const xels,
              unsigned int         const rowbytes,
              unsigned int         const bpp,
              unsigned int         const newMaxval,
-             enum compressionType const compression,
+             enum CompressionType const compression,
              bool                 const directColor,
-             Colormap             const colormap,
+             Colormap *           const colormapP,
              struct seqBuffer **  const rasterBufferPP) {
     
     unsigned char * rowdata;
@@ -971,7 +1133,7 @@ bufferRaster(xel **               const xels,
     for (row = 0; row < rows; ++row) {
         bufferRow(xels[row], cols, maxval, rowbytes, bpp, newMaxval,
                   compression,
-                  directColor, colormap, rowdata, row > 0 ? lastrow : NULL,
+                  directColor, colormapP, rowdata, row > 0 ? lastrow : NULL,
                   *rasterBufferPP);
 
         if (compression == COMP_SCANLINE)
@@ -988,8 +1150,8 @@ static void
 computeOffsetStuff(bool                 const offsetWanted,
                    unsigned int         const version,
                    bool                 const directColor,
-                   enum compressionType const compression,
-                   bool                 const colormap,
+                   enum CompressionType const compression,
+                   bool                 const colormapped,
                    unsigned int         const colormapColorCount,
                    unsigned int         const sizePlusRasterSize,
                    unsigned int *       const nextDepthOffsetP,
@@ -1003,7 +1165,7 @@ computeOffsetStuff(bool                 const offsetWanted,
         */
         unsigned int const headerSize = ((version < 3) ? 16 : 24);
         unsigned int const colormapSize =
-            (colormap ? (2 + colormapColorCount * 4) : 0);
+            (colormapped ? (2 + colormapColorCount * 4) : 0);
         if (version < 3) {
             unsigned int const directSize = 
                 (directColor && version < 3) ? 8 : 0; 
@@ -1058,12 +1220,12 @@ writeBitmap(xel **               const xels,
             unsigned int         const rowbytes,
             unsigned int         const bpp,
             unsigned int         const newMaxval,
-            enum compressionType const compression,
+            enum CompressionType const compression,
             bool                 const transparent,
             bool                 const directColor,
             bool                 const offsetWanted,
-            bool                 const hasColormap,
-            Colormap             const colormap,
+            bool                 const colormapped,
+            Colormap *           const colormapP,
             unsigned int         const transindex,
             xel                  const transcolor,
             unsigned int         const version,
@@ -1086,11 +1248,11 @@ writeBitmap(xel **               const xels,
         */
     struct seqBuffer * rasterBufferP;
 
-    writeCommonHeader(cols, rows, rowbytes, compression, hasColormap, 
+    writeCommonHeader(cols, rows, rowbytes, compression, colormapped, 
                       transparent, directColor, bpp, version);
     
     bufferRaster(xels, cols, rows, maxval, rowbytes, bpp, newMaxval,
-                 compression, directColor, colormap, &rasterBufferP);
+                 compression, directColor, colormapP, &rasterBufferP);
 
     /* rasterSize itself takes 2 or 4 bytes */
     if (version < 3)
@@ -1099,7 +1261,7 @@ writeBitmap(xel **               const xels,
         sizePlusRasterSize = 4 + bufferLength(rasterBufferP);
     
     computeOffsetStuff(offsetWanted, version, directColor, compression,
-                       hasColormap, hasColormap ? colormap->ncolors : 0, 
+                       colormapped, colormapped ? colormapP->ncolors : 0, 
                        sizePlusRasterSize,
                        &nextDepthOffset, &nextBitmapOffset,
                        &padBytesRequired);
@@ -1111,7 +1273,7 @@ writeBitmap(xel **               const xels,
                                  maxval, transparent, transcolor,
                                  transindex, nextBitmapOffset);
 
-    writeColormap(hasColormap, colormap, directColor, bpp, 
+    writeColormap(colormapped, colormapP, directColor, bpp, 
                   transparent, transcolor, maxval, version);
 
     if (compression != COMP_NONE)
@@ -1134,8 +1296,8 @@ writeBitmap(xel **               const xels,
 
 
 int 
-main( int argc, char **argv ) {
-    struct cmdline_info cmdline;
+main( int argc, const char **argv ) {
+    struct CmdlineInfo cmdline;
     unsigned int version;
     FILE* ifP;
     xel** xels;
@@ -1148,10 +1310,9 @@ main( int argc, char **argv ) {
     unsigned int bpp;
     bool directColor;
     unsigned int newMaxval;
-    Colormap colormap;
+    Colormap * colormapP;
     
-    /* Parse default params */
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -1161,18 +1322,20 @@ main( int argc, char **argv ) {
     pm_close(ifP);
 
     if (cmdline.verbose)
-        pm_message("Input is %dx%d %s, maxval %d", 
+        pm_message("Input is %ux%u %s, maxval %u", 
                    cols, rows, formatName(format), maxval);
     
-    determinePalmFormat(cols, rows, maxval, format, xels, cmdline.depth,
-                        cmdline.maxdepth, cmdline.colormap, cmdline.verbose,
-                        &bpp, &directColor, &colormap);
+    determinePalmFormat(cols, rows, maxval, format, xels,
+                        cmdline.depthSpec, cmdline.depth,
+                        cmdline.maxdepthSpec, cmdline.maxdepth,
+                        cmdline.colormap, cmdline.compression, cmdline.verbose,
+                        &bpp, &directColor, &colormapP);
 
     newMaxval = (1 << bpp) - 1;
 
     if (cmdline.transparent) 
         findTransparentColor(cmdline.transparent, newMaxval, directColor,
-                             maxval, colormap, &transcolor, &transindex);
+                             maxval, colormapP, &transcolor, &transindex);
     else 
         transindex = 0;
 
@@ -1185,7 +1348,7 @@ main( int argc, char **argv ) {
     writeBitmap(xels, cols, rows, maxval,
                 rowbytes, bpp, newMaxval, cmdline.compression,
                 !!cmdline.transparent, directColor, cmdline.offset, 
-                cmdline.colormap, colormap, transindex, transcolor,
+                cmdline.colormap, colormapP, transindex, transcolor,
                 version, cmdline.density, cmdline.withdummy);
     
     return 0;