about summary refs log tree commit diff
path: root/converter/other/pamtogif.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/pamtogif.c')
-rw-r--r--converter/other/pamtogif.c505
1 files changed, 302 insertions, 203 deletions
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index 9b833214..c41c778c 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -22,6 +22,12 @@
 static bool verbose;
 
 
+enum TransparencyType {TRANS_NONE, TRANS_COLOR, TRANS_ALPHA};
+    /* The source of transparency for the GIF: nothing is transparent,
+       All pixels of a certain color are transparent, or the alpha plane
+       in the input tells what is transparent.
+    */
+
 typedef unsigned int StringCode;
     /* A code to be place in the GIF raster.  It represents
        a string of one or more pixels.  You interpret this in the context
@@ -85,15 +91,20 @@ struct CmdlineInfo {
 
 static unsigned int
 pamAlphaPlane(struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+   The number of the alpha plane, or zero if there is no alpha plane, as
+   indicated by *pamP.
 
+   Note that the alpha plane is never zero in any Netpbm tuple type.
+-----------------------------------------------------------------------------*/
     unsigned int alphaPlane;
 
     if (streq(pamP->tuple_type, "RGB_ALPHA"))
         alphaPlane = 3;
     else if (streq(pamP->tuple_type, "GRAYSCALE_ALPHA"))
-        alphaPlane = 2;
+        alphaPlane = 1;
     else if (streq(pamP->tuple_type, "BLACKANDWHITE_ALPHA"))
-        alphaPlane = 2;
+        alphaPlane = 1;
     else
         alphaPlane = 0;
 
@@ -107,7 +118,7 @@ pamAlphaPlane(struct pam * const pamP) {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** argv,
                  struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Parse the program arguments (given by argc and argv) into a form
@@ -161,7 +172,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0)
@@ -201,9 +212,9 @@ Putword(int const w, FILE * const fp) {
 
 
 static int
-closestColor(tuple         const color,
-             struct pam *  const pamP,
-             struct Cmap * const cmapP) {
+closestColor(tuple               const color,
+             struct pam *        const pamP,
+             const struct Cmap * const cmapP) {
 /*----------------------------------------------------------------------------
    Return the colormap index of the color in the colormap *cmapP
    that is closest to the color 'color', whose format is specified by
@@ -305,7 +316,7 @@ rowReader_destroy(RowReader * const rdrP) {
 
 
 static void
-rowReaderSkipRows(RowReader *  const rdrP,
+rowReader_skipRows(RowReader *  const rdrP,
                   unsigned int const rowCount,
                   bool *       const eofP) {
 /*----------------------------------------------------------------------------
@@ -336,7 +347,7 @@ rowReaderSkipRows(RowReader *  const rdrP,
 
 
 static void
-rowReaderGotoNextInterlaceRow(RowReader * const rdrP) {
+rowReader_gotoNextInterlaceRow(RowReader * const rdrP) {
 /*----------------------------------------------------------------------------
   Position reader to the next row in the interlace pattern, assuming it
   is now positioned immediately after the current row.
@@ -352,16 +363,16 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) {
 
     switch (rdrP->pass) {
     case MULT8PLUS0:
-        rowReaderSkipRows(rdrP, 7, &endOfPass);
+        rowReader_skipRows(rdrP, 7, &endOfPass);
         break;
     case MULT8PLUS4:
-        rowReaderSkipRows(rdrP, 7, &endOfPass);
+        rowReader_skipRows(rdrP, 7, &endOfPass);
         break;
     case MULT4PLUS2:
-        rowReaderSkipRows(rdrP, 3, &endOfPass);
+        rowReader_skipRows(rdrP, 3, &endOfPass);
         break;
     case MULT2PLUS1:
-        rowReaderSkipRows(rdrP, 1, &endOfPass);
+        rowReader_skipRows(rdrP, 1, &endOfPass);
         break;
     }
 
@@ -376,15 +387,15 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) {
         switch (rdrP->pass) {
         case MULT8PLUS0:
             rdrP->pass = MULT8PLUS4;
-            rowReaderSkipRows(rdrP, 4, &endOfPass);
+            rowReader_skipRows(rdrP, 4, &endOfPass);
             break;
         case MULT8PLUS4:
             rdrP->pass = MULT4PLUS2;
-            rowReaderSkipRows(rdrP, 2, &endOfPass);
+            rowReader_skipRows(rdrP, 2, &endOfPass);
             break;
         case MULT4PLUS2:
             rdrP->pass = MULT2PLUS1;
-            rowReaderSkipRows(rdrP, 1, &endOfPass);
+            rowReader_skipRows(rdrP, 1, &endOfPass);
             break;
         case MULT2PLUS1:
             rdrP->eof = TRUE;
@@ -395,9 +406,8 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) {
 
 
 
-
 static void
-rowReaderGotoNextStraightRow(RowReader * const rdrP) {
+rowReader_gotoNextStraightRow(RowReader * const rdrP) {
 /*----------------------------------------------------------------------------
   Position reader to the next row in a straight, non-interlace
   pattern, assuming the file is now positioned immediately after the
@@ -424,32 +434,39 @@ rowReader_read(RowReader * const rdrP,
     ++rdrP->nextRow;
 
     if (rdrP->interlace)
-        rowReaderGotoNextInterlaceRow(rdrP);
+        rowReader_gotoNextInterlaceRow(rdrP);
     else
-        rowReaderGotoNextStraightRow(rdrP);
+        rowReader_gotoNextStraightRow(rdrP);
 }
 
 
 
 static unsigned int
-gifPixel(struct pam *   const pamP,
-         tuple          const tuple,
-         unsigned int   const alphaPlane,
-         sample         const alphaThreshold,
-         struct Cmap *  const cmapP) {
+gifPixel(struct pam *        const pamP,
+         tuple               const tuple,
+         unsigned int        const alphaPlane,
+         sample              const alphaThreshold,
+         const struct Cmap * const cmapP) {
 /*----------------------------------------------------------------------------
-   Return as *colorIndexP the colormap index of the tuple 'tuple',
-   whose format is described by *pamP, using colormap *cmapP.
+   Return the colormap index of the tuple 'tuple', whose format is described
+   by *pamP, using colormap *cmapP.
+
+   'alphaPlane' is the number of the plane in 'tuple' to use for transparency,
+   or zero if we aren't to use any plane for transparency.  (note that Caller
+   cannot specify plane 0 for transparency).
 
-   'alphaThreshold' is the alpha level below which we consider a
-   pixel transparent for GIF purposes.
+   'alphaThreshold' is the alpha level below which we consider a pixel
+   transparent for GIF purposes.
+
+   If 'alphaPlane' is nonzero, we assume *cmapP contains a transparent
+   entry.
 -----------------------------------------------------------------------------*/
     int colorIndex;
 
-    if (alphaPlane && tuple[alphaPlane] < alphaThreshold &&
-        cmapP->haveTransparent)
+    if (alphaPlane && tuple[alphaPlane] < alphaThreshold) {
+        assert(cmapP->haveTransparent);
         colorIndex = cmapP->transparent;
-    else {
+    } else {
         int found;
 
         pnm_lookuptuple(pamP, cmapP->tuplehash, tuple,
@@ -1251,80 +1268,6 @@ writePixelUncompressed(LzwCompressor * const lzwP,
 }
 
 
-static void
-writeRaster(struct pam *  const pamP,
-            RowReader *   const rowReaderP,
-            unsigned int  const alphaPlane,
-            unsigned int  const alphaThreshold,
-            struct Cmap * const cmapP,
-            unsigned int  const initBits,
-            FILE *        const ofP,
-            bool          const lzw,
-            bool          const noclear) {
-/*----------------------------------------------------------------------------
-   Write the raster to file 'ofP'.
-
-   Get the raster to write from 'rowReaderP', which gives tuples whose
-   format is described by 'pamP'.
-
-   Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives
-   pixel values as RGB samples; the GIF raster is colormap indices).
-
-   Write the raster using LZW compression, or uncompressed depending
-   on 'lzw'.
-
-   If 'noclear', don't use any GIF clear codes in the output; i.e. don't
-   recompute the string table from current input.  Once the string table gets
-   to maximum size, just keep using that table for the rest of the image.
------------------------------------------------------------------------------*/
-    LzwCompressor * lzwP;
-    tuple * tuplerow;
-    unsigned int nRowsDone;
-        /* Number of rows we have read so far from the the input (the
-           last of which is the one we're working on now).  Note that
-           in case of interlace, this is not the same thing as the row
-           number of the current row.
-        */
-
-    lzwP = lzw_create(ofP, initBits, lzw, noclear, pamP->height * pamP->width);
-
-    tuplerow = pnm_allocpamrow(pamP);
-
-    lzw_clearBlock(lzwP);
-
-    nRowsDone = 0;
-
-    while (nRowsDone < pamP->height) {
-        unsigned int col;
-
-        rowReader_read(rowReaderP, tuplerow);
-
-        for (col = 0; col < pamP->width; ++col) {
-            unsigned int const colorIndex =
-                gifPixel(pamP, tuplerow[col], alphaPlane, alphaThreshold,
-                         cmapP);
-
-                /* The value for the pixel in the GIF image.  I.e. the colormap
-                   index.
-                */
-            if (lzw)
-                lzw_encodePixel(lzwP, colorIndex);
-            else
-                writePixelUncompressed(lzwP, colorIndex);
-        }
-        ++nRowsDone;
-    }
-    /* Gif is no good with no pixels; fortunately, that's impossible: */
-    assert(nRowsDone > 0);
-
-    lzw_flush(lzwP);
-
-    pnm_freepamrow(tuplerow);
-
-    lzw_destroy(lzwP);
-}
-
-
 
 static void
 writeGlobalColorMap(FILE *              const ofP,
@@ -1378,6 +1321,23 @@ writeGlobalColorMap(FILE *              const ofP,
 
 
 static void
+reportImageInfo(bool         const interlace,
+                unsigned int const background,
+                unsigned int const bitsPerPixel) {
+
+    if (verbose) {
+        if (interlace)
+            pm_message("interlaced");
+        else
+            pm_message("not interlaced");
+        pm_message("Background color index = %u", background);
+        pm_message("%u bits per pixel", bitsPerPixel);
+    }
+}
+
+
+
+static void
 writeGifHeader(FILE *              const ofP,
                unsigned int        const width,
                unsigned int        const height,
@@ -1434,6 +1394,15 @@ writeGifHeader(FILE *              const ofP,
 
 
 static void
+writeImageSeparator(FILE * const ofP) {
+
+    fputc(',', ofP);
+
+}
+
+
+
+static void
 writeImageHeader(FILE *       const ofP,
                  unsigned int const leftOffset,
                  unsigned int const topOffset,
@@ -1460,37 +1429,110 @@ writeImageHeader(FILE *       const ofP,
 
 
 static void
-reportImageInfo(bool         const interlace,
-                unsigned int const background,
-                unsigned int const bitsPerPixel) {
+writeRaster(struct pam *        const pamP,
+            RowReader *         const rowReaderP,
+            unsigned int        const alphaPlane,
+            unsigned int        const alphaThreshold,
+            const struct Cmap * const cmapP,
+            unsigned int        const initBits,
+            FILE *              const ofP,
+            bool                const lzw,
+            bool                const noclear) {
+/*----------------------------------------------------------------------------
+   Write the raster to file 'ofP'.
 
-    if (verbose) {
-        if (interlace)
-            pm_message("interlaced");
-        else
-            pm_message("not interlaced");
-        pm_message("Background color index = %u", background);
-        pm_message("%u bits per pixel", bitsPerPixel);
+   Get the raster to write from 'rowReaderP', which gives tuples whose
+   format is described by 'pamP'.
+
+   'alphaPlane' is the number of the plane in the tuples supplied by
+   'rowReaderP' that we should use for transparency information, and
+   'alphaThreshold' is the value in that plane below which we should consider
+   the pixel transparent for GIF purposes.
+
+   'alphaPlane' is zero to indicate we should not use any plane as an alpha
+   plane (so it's not possible to specify Plane 0 as alpha).
+
+   Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives
+   pixel values as RGB samples; the GIF raster is colormap indices).
+
+   Write the raster using LZW compression, or uncompressed depending
+   on 'lzw'.
+
+   If 'noclear', don't use any GIF clear codes in the output; i.e. don't
+   recompute the string table from current input.  Once the string table gets
+   to maximum size, just keep using that table for the rest of the image.
+-----------------------------------------------------------------------------*/
+    LzwCompressor * lzwP;
+    tuple * tuplerow;
+    unsigned int nRowsDone;
+        /* Number of rows we have read so far from the the input (the
+           last of which is the one we're working on now).  Note that
+           in case of interlace, this is not the same thing as the row
+           number of the current row.
+        */
+
+    lzwP = lzw_create(ofP, initBits, lzw, noclear, pamP->height * pamP->width);
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    lzw_clearBlock(lzwP);
+
+    nRowsDone = 0;
+
+    while (nRowsDone < pamP->height) {
+        unsigned int col;
+
+        rowReader_read(rowReaderP, tuplerow);
+
+        for (col = 0; col < pamP->width; ++col) {
+            unsigned int const colorIndex =
+                gifPixel(pamP, tuplerow[col], alphaPlane, alphaThreshold,
+                         cmapP);
+
+                /* The value for the pixel in the GIF image.  I.e. the colormap
+                   index.
+                */
+            if (lzw)
+                lzw_encodePixel(lzwP, colorIndex);
+            else
+                writePixelUncompressed(lzwP, colorIndex);
+        }
+        ++nRowsDone;
     }
+    /* Gif is no good with no pixels; fortunately, that's impossible: */
+    assert(nRowsDone > 0);
+
+    lzw_flush(lzwP);
+
+    pnm_freepamrow(tuplerow);
+
+    lzw_destroy(lzwP);
 }
 
 
 
 static void
-gifEncode(struct pam *  const pamP,
-          FILE *        const ofP,
-          pm_filepos    const rasterPos,
-          bool          const gInterlace,
-          int           const background,
-          unsigned int  const bitsPerPixel,
-          struct Cmap * const cmapP,
-          char          const comment[],
-          float         const aspect,
-          bool          const lzw,
-          bool          const noclear) {
+writeEndOfImage(FILE * const ofP) {
 
-    unsigned int const leftOffset = 0;
-    unsigned int const topOffset  = 0;
+    /* An empty block marks the end of a series of blocks */
+
+    fputc(0, ofP);
+}
+
+
+
+static void
+writeGifImage(FILE *              const ofP,
+              unsigned int        const leftOffset,
+              unsigned int        const topOffset,
+              struct pam *        const pamP,
+              pm_filepos          const rasterPos,
+              bool                const gInterlace,
+              unsigned int        const bitsPerPixel,
+              bool                const lzw,
+              bool                const noclear,
+              bool                const usingAlpha,
+              const struct Cmap * const cmapP) {
 
     unsigned int const initCodeSize = bitsPerPixel <= 1 ? 2 : bitsPerPixel;
         /* The initial code size */
@@ -1500,10 +1542,56 @@ gifEncode(struct pam *  const pamP,
            pixels in the output image.
         */
 
-    unsigned int const alphaPlane = pamAlphaPlane(pamP);
+    unsigned int const alphaPlane = usingAlpha ? pamAlphaPlane(pamP) : 0;
 
     RowReader * rowReaderP;
 
+    writeImageSeparator(ofP);
+
+    writeImageHeader(ofP, leftOffset, topOffset, pamP->width, pamP->height,
+                     gInterlace, initCodeSize);
+
+    rowReaderP = rowReader_create(pamP, rasterPos, gInterlace);
+
+    writeRaster(pamP, rowReaderP, alphaPlane, alphaThreshold,
+                cmapP, initCodeSize + 1, ofP, lzw, noclear);
+
+    rowReader_destroy(rowReaderP);
+
+    writeEndOfImage(ofP);
+}
+
+
+
+static void
+writeGifStreamTerminator(FILE * const ofP) {
+
+    fputc(';', ofP);
+}
+
+
+
+static void
+writeGif(struct pam *        const pamP,
+         FILE *              const ofP,
+         pm_filepos          const rasterPos,
+         bool                const gInterlace,
+         int                 const background,
+         unsigned int        const bitsPerPixel,
+         const struct Cmap * const cmapP,
+         char                const comment[],
+         float               const aspect,
+         bool                const lzw,
+         bool                const noclear,
+         bool                const usingAlpha) {
+/*----------------------------------------------------------------------------
+   'usingAlpha' means use the alpha (transparency) plane, if there is one, to
+   determine which GIF pixels are transparent.  When this is true, the
+   colormap *cmapP must contain a transparent entry.
+-----------------------------------------------------------------------------*/
+    unsigned int const leftOffset = 0;
+    unsigned int const topOffset  = 0;
+
     reportImageInfo(gInterlace, background, bitsPerPixel);
 
     if (pamP->width > 65535)
@@ -1517,34 +1605,32 @@ gifEncode(struct pam *  const pamP,
     writeGifHeader(ofP, pamP->width, pamP->height, background,
                    bitsPerPixel, cmapP, comment, aspect);
 
-    /* Write an Image separator */
-    fputc(',', ofP);
+    writeGifImage(ofP, leftOffset, topOffset, pamP, rasterPos,
+                  gInterlace, bitsPerPixel, lzw, noclear, usingAlpha,
+                  cmapP);
 
-    writeImageHeader(ofP, leftOffset, topOffset, pamP->width, pamP->height,
-                     gInterlace, initCodeSize);
-
-    rowReaderP = rowReader_create(pamP, rasterPos, gInterlace);
-
-    /* Write the actual raster */
-
-    writeRaster(pamP, rowReaderP, alphaPlane, alphaThreshold,
-                cmapP, initCodeSize + 1, ofP, lzw, noclear);
-
-    rowReader_destroy(rowReaderP);
-
-    /* Write out a zero length data block (to end the series) */
-    fputc(0, ofP);
-
-    /* Write the GIF file terminator */
-    fputc(';', ofP);
+    writeGifStreamTerminator(ofP);
 }
 
 
 
 static void
-reportTransparent(struct Cmap * const cmapP) {
+reportTransparent(enum TransparencyType const transType,
+                  const struct Cmap *   const cmapP) {
 
     if (verbose) {
+        switch (transType) {
+        case TRANS_NONE:
+            pm_message("Not making transparent pixels");
+            break;
+        case TRANS_COLOR:
+            pm_message("Making pixels of a certain color transparent");
+            break;
+        case TRANS_ALPHA:
+            pm_message("Making pixels transparent per input alpha mask");
+            break;
+        }
+
         if (cmapP->haveTransparent) {
             tuple const color = cmapP->color[cmapP->transparent];
             pm_message("Color %u (%lu, %lu, %lu) is transparent",
@@ -1560,42 +1646,46 @@ reportTransparent(struct Cmap * const cmapP) {
 
 
 static void
-computeTransparent(char          const colorarg[],
-                   bool          const usingFakeTrans,
-                   unsigned int  const fakeTransparent,
-                   struct Cmap * const cmapP) {
+computeTransparent(enum TransparencyType const transType,
+                   char                  const colorarg[],
+                   unsigned int          const fakeTransparent,
+                   struct Cmap *         const cmapP) {
 /*----------------------------------------------------------------------------
    Figure out the color index (index into the colormap) of the color
-   that is to be transparent in the GIF.
+   that is to be transparent in the GIF and set it in the colormap.
 
-   colorarg[] is the string that specifies the color the user wants to
-   be transparent (e.g. "red", "#fefefe").  Its maxval is the maxval
-   of the colormap.  'cmap' is the full colormap except that its
-   'transparent' component isn't valid.
+   'transType' tells what the source of the transparency is.
 
-   colorarg[] is a standard Netpbm color specification, except that
-   may have a "=" prefix, which means it specifies a particular exact
-   color, as opposed to without the "=", which means "the color that
-   is closest to this and actually in the image."
+   If 'transType' says all pixels of a single foreground color are to be
+   transparent:
 
-   colorarg[] null means the color didn't ask for a particular color
-   to be transparent.
+     'colorarg' is the specification of that color.  Its
+     maxval is the maxval of the colormap.
 
-   Establish no transparent color if colorarg[] specifies an exact
-   color and that color is not in the image.  Also issue an
-   informational message.
+     colorarg[] is a standard Netpbm color specification (e.g. "red",
+     "#fefefe"), except that may have a "=" prefix, which means it specifies a
+     particular exact color, as opposed to without the "=", which means "the
+     color that is closest to this and actually in the image."
 
-   'usingFakeTrans' means pixels will be transparent because of something
-   other than their foreground color, and 'fakeTransparent' is the
-   color map index for transparent colors.
+     Establish no transparent color if colorarg[] specifies an exact
+     color and that color is not in the image.  Also issue an
+     informational message.
+
+   If 'transType' says an input alpha channel will dtermine what pixels are
+   transparent:
+
+     'fakeTransparent' is the special color map index for transparent pixels.
 -----------------------------------------------------------------------------*/
-    if (colorarg) {
+    switch (transType) {
+    case TRANS_COLOR: {
         const char * colorspec;
         bool exact;
         tuple transcolor;
         int found;
         int colorindex;
 
+        assert(colorarg);
+
         if (colorarg[0] == '=') {
             colorspec = &colorarg[1];
             exact = TRUE;
@@ -1619,13 +1709,16 @@ computeTransparent(char          const colorarg[],
             pm_message("Warning: specified transparent color "
                        "does not occur in image.");
         }
-    } else if (usingFakeTrans) {
+    } break;
+    case TRANS_ALPHA: {
         cmapP->haveTransparent = TRUE;
         cmapP->transparent = fakeTransparent;
-    } else
+    } break;
+    case TRANS_NONE: {
         cmapP->haveTransparent = FALSE;
-
-    reportTransparent(cmapP);
+    } break;
+    }  /* switch */
+    reportTransparent(transType, cmapP);
 }
 
 
@@ -1841,14 +1934,14 @@ computeColormapFromInput(struct pam *   const pamP,
 
 
 static void
-computeLibnetpbmColormap(struct pam *   const pamP,
-                         bool           const haveAlpha,
-                         const char *   const mapfile,
-                         tuple *        const color,
-                         tuplehash *    const tuplehashP,
-                         struct pam *   const mapPamP,
-                         unsigned int * const colorCountP,
-                         bool           const sort) {
+computeLibnetpbmColormap(struct pam *          const pamP,
+                         enum TransparencyType const transType,
+                         const char *          const mapfile,
+                         tuple *               const color,
+                         tuplehash *           const tuplehashP,
+                         struct pam *          const mapPamP,
+                         unsigned int *        const colorCountP,
+                         bool                  const sort) {
 /*----------------------------------------------------------------------------
    Compute a colormap, libnetpbm style, for the image described by
    'pamP', which is positioned to the raster.
@@ -1862,21 +1955,23 @@ computeLibnetpbmColormap(struct pam *   const pamP,
    The tuples of the color map have a meaningful depth of 1 (grayscale) or 3
    (color) and *mapPamP reflects that.
 
-   While we're at it, count the colors and validate that there aren't
-   too many.  Return the count as *colorCountP.  In determining if there are
-   too many, allow one slot for a fake transparency color if 'haveAlpha'
-   is true.  If there are too many, issue an error message and abort the
+   While we're at it, count the colors and validate that there aren't too
+   many.  Return the count as *colorCountP.  In determining if there are too
+   many, allow one slot for a fake transparency color if 'transType' is
+   'TRANS_ALPHA'.  If there are too many, issue an error message and abort the
    program.
 
    'sort' means to sort the colormap by red intensity, then by green
    intensity, then by blue intensity, as opposed to arbitrary order.
 -----------------------------------------------------------------------------*/
-    unsigned int const maxcolors = haveAlpha ? MAXCMAPSIZE - 1 : MAXCMAPSIZE;
+    unsigned int const maxcolors =
+        transType == TRANS_ALPHA ? MAXCMAPSIZE - 1 : MAXCMAPSIZE;
         /* The most colors we can tolerate in the image.  If we have
            our own made-up entry in the colormap for transparency, it
            isn't included in this count.
         */
-    unsigned int const nInputComp = haveAlpha ? pamP->depth - 1 : pamP->depth;
+    unsigned int const nInputComp =
+        pamAlphaPlane(pamP) ? pamP->depth - 1 : pamP->depth;
         /* Number of color components (not alpha) in the input image */
 
     unsigned int i;
@@ -1932,22 +2027,23 @@ destroyCmap(struct Cmap * const cmapP) {
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
+
     struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam pam;
     unsigned int bitsPerPixel;
     pm_filepos rasterPos;
-
     struct Cmap cmap;
         /* The colormap, with all its accessories */
+    enum TransparencyType transType;
     unsigned int fakeTransparent;
         /* colormap index of the fake transparency color we're using to
-           implement the alpha mask.  Undefined if we're not doing an alpha
-           mask.
+           implement the alpha mask.  Defined only if 'transType' is
+           TRANS_ALPHA.
         */
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -1959,13 +2055,17 @@ main(int argc, char *argv[]) {
 
     pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
 
-    computeLibnetpbmColormap(&pam, !!pamAlphaPlane(&pam), cmdline.mapfile,
+    transType = cmdline.transparent ? TRANS_COLOR :
+        pamAlphaPlane(&pam) ? TRANS_ALPHA :
+        TRANS_NONE;
+
+    computeLibnetpbmColormap(&pam, transType, cmdline.mapfile,
                              cmap.color, &cmap.tuplehash,
                              &cmap.pam, &cmap.cmapSize, cmdline.sort);
 
     assert(cmap.pam.maxval == pam.maxval);
 
-    if (pamAlphaPlane(&pam)) {
+    if (transType == TRANS_ALPHA) {
         /* Add a fake entry to the end of the colormap for transparency.
            Make its color black.
         */
@@ -1974,13 +2074,12 @@ main(int argc, char *argv[]) {
 
     bitsPerPixel = cmap.cmapSize == 1 ? 1 : nSignificantBits(cmap.cmapSize-1);
 
-    computeTransparent(cmdline.transparent,
-                       !!pamAlphaPlane(&pam), fakeTransparent, &cmap);
+    computeTransparent(transType, cmdline.transparent, fakeTransparent, &cmap);
 
-    /* All set, let's do it. */
-    gifEncode(&pam, stdout, rasterPos,
-              cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment,
-              cmdline.aspect, !cmdline.nolzw, cmdline.noclear);
+    writeGif(&pam, stdout, rasterPos,
+             cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment,
+             cmdline.aspect, !cmdline.nolzw, cmdline.noclear,
+             transType==TRANS_ALPHA);
 
     destroyCmap(&cmap);