about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/other/Makefile4
-rw-r--r--converter/other/pamtodjvurle.c2
-rw-r--r--converter/other/pamtosvg/fit.c2
-rw-r--r--converter/other/pngtopam.c1265
-rw-r--r--converter/other/pngtopnm.c464
-rw-r--r--converter/other/pnmtopng.c10
-rw-r--r--converter/other/x11wd.h8
-rw-r--r--converter/pbm/g3topbm.c128
-rw-r--r--converter/pbm/pbmtodjvurle.c166
-rw-r--r--converter/ppm/ilbmtoppm.c18
-rw-r--r--converter/ppm/picttoppm.c66
-rw-r--r--converter/ppm/ppmtoarbtxt.c4
-rw-r--r--converter/ppm/ppmtoilbm.c24
-rw-r--r--converter/ppm/ppmtompeg/headers/param.h97
-rw-r--r--converter/ppm/ppmtompeg/param.c31
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c159
-rw-r--r--converter/ppm/ppmtoyuvsplit.c277
17 files changed, 2014 insertions, 711 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 3a6bb2af..592eaac2 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -96,7 +96,7 @@ endif
 BINARIES = $(PORTBINARIES) pnmtorast rasttopnm
 
 ifeq ($(HAVE_PNGLIB),Y)
-  BINARIES += pnmtopng pngtopnm pamrgbatopng
+  BINARIES += pnmtopng pngtopnm pngtopam pamrgbatopng
 endif
 ifneq ($(JPEGLIB),NONE)
   BINARIES += jpegtopnm pnmtojpeg
@@ -155,7 +155,7 @@ else
   PNGLIB_LIBOPTS = $(shell libpng-config --ldflags)
 endif
 
-pngtopnm: %: %.o $(NETPBMLIB) $(LIBOPT)
+pngtopnm pngtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
 	$(LD) $(LDFLAGS) -o $@ $@.o \
 	  $(shell $(LIBOPT) $(NETPBMLIB)) \
 	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
diff --git a/converter/other/pamtodjvurle.c b/converter/other/pamtodjvurle.c
index ae35e81d..fecf410e 100644
--- a/converter/other/pamtodjvurle.c
+++ b/converter/other/pamtodjvurle.c
@@ -179,7 +179,7 @@ writeRleRun(FILE *       const ofP,
   
   'transcolor' is a 3-deep tuple with the same maxval as the image.
 -----------------------------------------------------------------------------*/
-    uint32n rlevalue;         /* RLE-encoded color/valuex */
+    uint32_t rlevalue;         /* RLE-encoded color/valuex */
     int index;
 
     if (count > 0) {
diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c
index ab73e439..5ba7a2f6 100644
--- a/converter/other/pamtosvg/fit.c
+++ b/converter/other/pamtosvg/fit.c
@@ -292,7 +292,7 @@ remove_adjacent_corners(index_list_type *   const list,
    pixel. We need this for checking the adjacency of the last corner.
 
    We need to do this because the adjacent corners turn into
-   two-pixel-long curves, which can only be fit by straight lines.
+   two-pixel-long curves, which can be fit only by straight lines.
 -----------------------------------------------------------------------------*/
   unsigned int j;
   unsigned int last;
diff --git a/converter/other/pngtopam.c b/converter/other/pngtopam.c
new file mode 100644
index 00000000..3039c769
--- /dev/null
+++ b/converter/other/pngtopam.c
@@ -0,0 +1,1265 @@
+/*
+** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+**
+** modeled after giftopnm by David Koblas and
+** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
+*/
+
+#ifndef PNMTOPNG_WARNING_LEVEL
+#  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
+#endif                               /*  2 for warnings (1 == error) */
+
+
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+#include <png.h>    /* includes zlib.h and setjmp.h */
+#define VERSION "2.37.4 (5 December 1999) +netpbm"
+
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+typedef struct _jmpbuf_wrapper {
+  jmp_buf jmpbuf;
+} jmpbuf_wrapper;
+
+enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *inputFilespec;  /* '-' if stdin */
+    unsigned int verbose;
+    enum alpha_handling alpha;
+    const char * background;
+    float gamma;  /* -1.0 means unspecified */
+    const char * text;
+    unsigned int time;
+};
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   A color in a format compatible with the PNG library.
+
+   Note that the PNG library declares types png_color and png_color_16
+   which are similar.
+-----------------------------------------------------------------------------*/
+    png_uint_16 r;
+    png_uint_16 g;
+    png_uint_16 b;
+} pngcolor;
+
+
+static png_uint_16 maxval;
+static bool verbose;
+static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
+
+
+static void
+parseCommandLine(int                  argc, 
+                 const char **        argv,
+                 struct cmdlineInfo * cmdlineP ) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   If command line is internally inconsistent (invalid options, etc.),
+   issue error message to stderr and abort program.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int alphaSpec, alphapamSpec, mixSpec,
+        backgroundSpec, gammaSpec, textSpec;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
+            &cmdlineP->verbose,       0);
+    OPTENT3(0, "alpha",       OPT_FLAG,   NULL,                  
+            &alphaSpec,               0);
+    OPTENT3(0, "alphapam",    OPT_FLAG,   NULL,                  
+            &alphapamSpec,            0);
+    OPTENT3(0, "mix",         OPT_FLAG,   NULL,                  
+            &mixSpec,                 0);
+    OPTENT3(0, "background",  OPT_STRING, &cmdlineP->background,
+            &backgroundSpec,          0);
+    OPTENT3(0, "gamma",       OPT_FLOAT,  &cmdlineP->gamma,
+            &gammaSpec,               0);
+    OPTENT3(0, "text",        OPT_STRING, &cmdlineP->text,
+            &textSpec,                0);
+    OPTENT3(0, "time",        OPT_FLAG,   NULL,                  
+            &cmdlineP->time,          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, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+
+    if (alphaSpec + mixSpec + alphapamSpec > 1)
+        pm_error("You cannot specify more than one of -alpha -alphapam -mix");
+    else if (alphaSpec)
+        cmdlineP->alpha = ALPHA_ONLY;
+    else if (mixSpec)
+        cmdlineP->alpha = ALPHA_MIX;
+    else if (alphapamSpec)
+        cmdlineP->alpha = ALPHA_IN;
+    else
+        cmdlineP->alpha = ALPHA_NONE;
+
+    if (backgroundSpec && !mixSpec)
+        pm_error("-background is useless without -mix");
+
+    if (!backgroundSpec)
+        cmdlineP->background = NULL;
+
+    if (!gammaSpec)
+        cmdlineP->gamma = -1.0;
+
+    if (!textSpec)
+        cmdlineP->text = NULL;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.  "
+            "you specified %d", argc-1);
+}
+
+
+
+static png_uint_16
+get_png_val(const png_byte ** const pp,
+            int               const bit_depth) {
+
+    png_uint_16 c;
+    
+    if (bit_depth == 16)
+        c = (*((*pp)++)) << 8;
+    else
+        c = 0;
+
+    c |= (*((*pp)++));
+    
+    return c;
+}
+
+
+
+static bool
+isGrayscale(pngcolor const color) {
+
+    return color.r == color.g && color.r == color.b;
+}
+
+
+
+static sample
+alphaMix(png_uint_16 const foreground,
+         png_uint_16 const background,
+         png_uint_16 const alpha,
+         sample      const maxval) {
+
+    double const opacity      = (double)alpha / maxval;
+    double const transparency = 1.0 - opacity;
+
+    return ROUNDU(foreground * opacity + background * transparency);
+}
+
+
+
+static void
+setTuple(const struct pam *  const pamP,
+         tuple               const tuple,
+         pngcolor            const foreground,
+         pngcolor            const background,
+         enum alpha_handling const alphaHandling,
+         png_uint_16         const alpha) {
+
+    if (alphaHandling == ALPHA_ONLY)
+        tuple[0] = alpha;
+    else if (alphaHandling == ALPHA_NONE ||
+             (alphaHandling == ALPHA_MIX && alpha == maxval)) {
+        if (pamP->depth < 3)
+            tuple[0] = foreground.r;
+        else {
+            tuple[PAM_RED_PLANE] = foreground.r;
+            tuple[PAM_GRN_PLANE] = foreground.g;
+            tuple[PAM_BLU_PLANE] = foreground.b;
+        }
+    } else if (alphaHandling == ALPHA_IN) {
+        if (pamP->depth < 4) {
+            tuple[0] = foreground.r;
+            tuple[PAM_GRAY_TRN_PLANE] = alpha;
+        } else {
+            tuple[PAM_RED_PLANE] = foreground.r;
+            tuple[PAM_GRN_PLANE] = foreground.g;
+            tuple[PAM_BLU_PLANE] = foreground.b;
+            tuple[PAM_TRN_PLANE] = alpha;
+        }    
+    } else {
+        assert(alphaHandling == ALPHA_MIX);
+
+        if (pamP->depth < 3)
+            tuple[0] =
+                alphaMix(foreground.r, background.r, alpha, maxval);
+        else {
+            tuple[PAM_RED_PLANE] =
+                alphaMix(foreground.r, background.r, alpha, maxval);
+            tuple[PAM_GRN_PLANE] =
+                alphaMix(foreground.g, background.g, alpha, maxval);
+            tuple[PAM_BLU_PLANE] =
+                alphaMix(foreground.b, background.b, alpha, maxval);
+        }
+    }
+}
+
+
+
+static png_uint_16
+gamma_correct(png_uint_16 const v,
+              float       const g) {
+
+    if (g != -1.0)
+        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
+                                    maxval);
+    else
+        return v;
+}
+
+
+
+static int iscolor (png_color c)
+{
+  return c.red != c.green || c.green != c.blue;
+}
+
+static void save_text (png_info *info_ptr, FILE *tfp)
+{
+  int i, j, k;
+
+  for (i = 0 ; i < info_ptr->num_text ; i++) {
+    j = 0;
+    while (info_ptr->text[i].key[j] != '\0' && info_ptr->text[i].key[j] != ' ')
+      j++;    
+    if (info_ptr->text[i].key[j] != ' ') {
+      fprintf (tfp, "%s", info_ptr->text[i].key);
+      for (j = strlen (info_ptr->text[i].key) ; j < 15 ; j++)
+        putc (' ', tfp);
+    } else {
+      fprintf (tfp, "\"%s\"", info_ptr->text[i].key);
+      for (j = strlen (info_ptr->text[i].key) ; j < 13 ; j++)
+        putc (' ', tfp);
+    }
+    putc (' ', tfp); /* at least one space between key and text */
+    
+    for (j = 0 ; j < info_ptr->text[i].text_length ; j++) {
+      putc (info_ptr->text[i].text[j], tfp);
+      if (info_ptr->text[i].text[j] == '\n')
+        for (k = 0 ; k < 16 ; k++)
+          putc ((int)' ', tfp);
+    }
+    putc ((int)'\n', tfp);
+  }
+}
+
+static void show_time (png_info *info_ptr)
+{
+    static const char * const month[] = {
+        "", "January", "February", "March", "April", "May", "June",
+        "July", "August", "September", "October", "November", "December"
+    };
+
+  if (info_ptr->valid & PNG_INFO_tIME) {
+    pm_message ("modification time: %02d %s %d %02d:%02d:%02d",
+                info_ptr->mod_time.day, month[info_ptr->mod_time.month],
+                info_ptr->mod_time.year, info_ptr->mod_time.hour,
+                info_ptr->mod_time.minute, info_ptr->mod_time.second);
+  }
+}
+
+static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
+{
+  jmpbuf_wrapper  *jmpbuf_ptr;
+
+  /* this function, aside from the extra step of retrieving the "error
+   * pointer" (below) and the fact that it exists within the application
+   * rather than within libpng, is essentially identical to libpng's
+   * default error handler.  The second point is critical:  since both
+   * setjmp() and longjmp() are called from the same code, they are
+   * guaranteed to have compatible notions of how big a jmp_buf is,
+   * regardless of whether _BSD_SOURCE or anything else has (or has not)
+   * been defined. */
+
+  pm_message("fatal libpng error: %s", msg);
+
+  jmpbuf_ptr = png_get_error_ptr(png_ptr);
+  if (jmpbuf_ptr == NULL) {
+      /* we are completely hosed now */
+      pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
+  }
+
+  longjmp(jmpbuf_ptr->jmpbuf, 1);
+}
+
+
+
+static void
+dump_png_info(png_info *info_ptr) {
+
+    const char *type_string;
+    const char *filter_string;
+
+    switch (info_ptr->color_type) {
+      case PNG_COLOR_TYPE_GRAY:
+        type_string = "gray";
+        break;
+
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
+        type_string = "gray+alpha";
+        break;
+
+      case PNG_COLOR_TYPE_PALETTE:
+        type_string = "palette";
+        break;
+
+      case PNG_COLOR_TYPE_RGB:
+        type_string = "truecolor";
+        break;
+
+      case PNG_COLOR_TYPE_RGB_ALPHA:
+        type_string = "truecolor+alpha";
+        break;
+    }
+
+    switch (info_ptr->filter_type) {
+    case PNG_FILTER_TYPE_BASE:
+        asprintfN(&filter_string, "base filter");
+        break;
+    default:
+        asprintfN(&filter_string, "unknown filter type %d", 
+                  info_ptr->filter_type);
+    }
+
+    pm_message("reading a %ldw x %ldh image, %d bit%s",
+               info_ptr->width, info_ptr->height,
+               info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : "");
+    pm_message("%s, %s, %s",
+               type_string,
+               info_ptr->interlace_type ? 
+               "Adam7 interlaced" : "not interlaced",
+               filter_string);
+    pm_message("background {index, gray, red, green, blue} = "
+               "{%d, %d, %d, %d, %d}",
+               info_ptr->background.index,
+               info_ptr->background.gray,
+               info_ptr->background.red,
+               info_ptr->background.green,
+               info_ptr->background.blue);
+
+    strfree(filter_string);
+
+    if (info_ptr->valid & PNG_INFO_tRNS)
+        pm_message("tRNS chunk (transparency): %u entries",
+                   info_ptr->num_trans);
+    else
+        pm_message("tRNS chunk (transparency): not present");
+
+    if (info_ptr->valid & PNG_INFO_gAMA)
+        pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma);
+    else
+        pm_message("gAMA chunk (image gamma): not present");
+
+    if (info_ptr->valid & PNG_INFO_sBIT)
+        pm_message("sBIT chunk: present");
+    else
+        pm_message("sBIT chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_cHRM)
+        pm_message("cHRM chunk: present");
+    else
+        pm_message("cHRM chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_PLTE)
+        pm_message("PLTE chunk: %d entries", info_ptr->num_palette);
+    else
+        pm_message("PLTE chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_bKGD)
+        pm_message("bKGD chunk: present");
+    else
+        pm_message("bKGD chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_PLTE)
+        pm_message("hIST chunk: present");
+    else
+        pm_message("hIST chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_pHYs)
+        pm_message("pHYs chunk: present");
+    else
+        pm_message("pHYs chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_oFFs)
+        pm_message("oFFs chunk: present");
+    else
+        pm_message("oFFs chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_tIME)
+        pm_message("tIME chunk: present");
+    else
+        pm_message("tIME chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_pCAL)
+        pm_message("pCAL chunk: present");
+    else
+        pm_message("pCAL chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_sRGB)
+        pm_message("sRGB chunk: present");
+    else
+        pm_message("sRGB chunk: not present");
+}
+
+
+
+static unsigned int
+computePngLineSize(png_info * const pngInfoP) {
+
+    unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngInfoP->color_type) {
+    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
+    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
+    default:                        samplesPerPixel = 1;
+    }
+
+    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngInfoP->width)
+        pm_error("Width %u of PNG is uncomputably large",
+                 (unsigned int)pngInfoP->width);
+       
+    return pngInfoP->width * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(png_info *   const pngInfoP,
+               png_byte *** const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngInfoP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngInfoP->height);
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate space for %u PNG raster rows",
+                 (unsigned int)pngInfoP->height);
+
+    for (row = 0; row < pngInfoP->height; ++row) {
+        MALLOCARRAY(pngImage[row], lineSize);
+        if (pngImage[row] == NULL)
+            pm_error("couldn't allocate space for %uth row of PNG raster",
+                     row);
+    }
+    *pngImageP = pngImage;
+}
+
+
+
+static void
+freePngRaster(png_byte ** const pngRaster,
+              png_info *  const pngInfoP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngInfoP->height; ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
+static bool
+isTransparentColor(pngcolor   const color,
+                   png_info * const pngInfoP,
+                   double     const totalgamma) {
+/*----------------------------------------------------------------------------
+   Return TRUE iff pixels of color 'color' are supposed to be transparent
+   everywhere they occur.  Assume it's an RGB image.
+
+   'color' has been gamma-corrected.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (pngInfoP->valid & PNG_INFO_tRNS) {
+        const png_color_16 * const transColorP = &pngInfoP->trans_values;
+
+        /* It seems odd that libpng lets you get gamma-corrected pixel
+           values, but not gamma-corrected transparency or background
+           values.  But as that is the case, we have to gamma-correct
+           the transparency values.
+
+           Note that because we compare the gamma-corrected values and
+           there may be many-to-one mapping of uncorrected to corrected
+           values, more pixels may be transparent than what the user
+           intended.
+
+           We could fix this by not letting libpng gamma-correct the
+           pixels, and just do it ourselves.
+        */
+    
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
+            break;
+        default:
+            retval = 
+                color.r == gamma_correct(transColorP->red,   totalgamma) &&
+                color.g == gamma_correct(transColorP->green, totalgamma) &&
+                color.b == gamma_correct(transColorP->blue,  totalgamma);
+        }
+    } else 
+        retval = FALSE;
+
+    return retval;
+}
+
+
+
+#define SIG_CHECK_SIZE 4
+
+static void
+read_sig_buf(FILE * const ifP) {
+
+    unsigned char sig_buf[SIG_CHECK_SIZE];
+    size_t bytesRead;
+
+    bytesRead = fread(sig_buf, 1, SIG_CHECK_SIZE, ifP);
+    if (bytesRead != SIG_CHECK_SIZE)
+        pm_error ("input file is empty or too short");
+
+    if (png_sig_cmp(sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE)
+        != 0)
+        pm_error ("input file is not a PNG file");
+}
+
+
+
+static void
+setupGammaCorrection(png_struct * const png_ptr,
+                     png_info *   const info_ptr,
+                     float        const displaygamma,
+                     float *      const totalgammaP) {
+
+    if (displaygamma == -1.0)
+        *totalgammaP = -1.0;
+    else {
+        float imageGamma;
+        if (info_ptr->valid & PNG_INFO_gAMA)
+            imageGamma = info_ptr->gamma;
+        else {
+            if (verbose)
+                pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
+            imageGamma = 1.0;
+        }
+
+        if (fabs(displaygamma * imageGamma - 1.0) < .01) {
+            *totalgammaP = -1.0;
+            if (verbose)
+                pm_message("image gamma %4.2f matches "
+                           "display gamma %4.2f.  No conversion.",
+                           imageGamma, displaygamma);
+        } else {
+            png_set_gamma(png_ptr, displaygamma, imageGamma);
+            *totalgammaP = imageGamma * displaygamma;
+            /* in case of gamma-corrections, sBIT's as in the
+               PNG-file are not valid anymore 
+            */
+            info_ptr->valid &= ~PNG_INFO_sBIT;
+            if (verbose)
+                pm_message("image gamma is %4.2f, "
+                           "converted for display gamma of %4.2f",
+                           imageGamma, displaygamma);
+        }
+    }
+}
+
+
+
+static bool
+paletteHasPartialTransparency(png_info * const info_ptr) {
+
+    bool retval;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (info_ptr->valid & PNG_INFO_tRNS) {
+            bool foundGray;
+            unsigned int i;
+            
+            for (i = 0, foundGray = FALSE;
+                 i < info_ptr->num_trans && !foundGray;
+                 ++i) {
+                if (info_ptr->trans[i] != 0 &&
+                    info_ptr->trans[i] != maxval) {
+                    foundGray = TRUE;
+                }
+            }
+            retval = foundGray;
+        } else
+            retval = FALSE;
+    } else
+        retval = FALSE;
+
+    return retval;
+}
+
+
+
+static void
+getComponentSbitFg(png_info * const pngInfoP,
+                   png_byte * const fgSbitP,
+                   bool *     const notUniformP) {
+
+    if (pngInfoP->color_type == PNG_COLOR_TYPE_RGB ||
+        pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+        pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (pngInfoP->sig_bit.red == pngInfoP->sig_bit.blue &&
+            pngInfoP->sig_bit.red == pngInfoP->sig_bit.green) {
+            *notUniformP = false;
+            *fgSbitP     = pngInfoP->sig_bit.red;
+        } else
+            *notUniformP = true;
+    } else {
+        /* It has only a gray channel so it's obviously uniform */
+        *notUniformP = false;
+        *fgSbitP     = pngInfoP->sig_bit.gray;
+    }
+}
+
+
+
+static void
+getComponentSbit(png_info *          const pngInfoP,
+                 enum alpha_handling const alphaHandling,
+                 png_byte *          const componentSbitP,
+                 bool *              const notUniformP) {
+
+    switch (alphaHandling) {
+
+    case ALPHA_ONLY:
+        /* We care only about the alpha channel, so the uniform Sbit is
+           the alpha Sbit
+        */
+        *notUniformP = false;
+        *componentSbitP = pngInfoP->sig_bit.alpha;
+        break;
+    case ALPHA_NONE:
+    case ALPHA_MIX:
+        /* We aren't going to produce an alpha channel, so we care only
+           about the uniformity of the foreground channels.
+        */
+        getComponentSbitFg(pngInfoP, componentSbitP, notUniformP);
+        break;
+    case ALPHA_IN: {
+        /* We care about both the foreground and the alpha */
+        bool fgNotUniform;
+        png_byte fgSbit;
+        
+        getComponentSbitFg(pngInfoP, &fgSbit, &fgNotUniform);
+
+        if (fgNotUniform)
+            *notUniformP = true;
+        else {
+            if (fgSbit == pngInfoP->sig_bit.alpha) {
+                *notUniformP    = false;
+                *componentSbitP = fgSbit;
+            } else
+                *notUniformP = true;
+        }
+    } break;
+    }
+}
+
+                 
+
+static void
+shiftPalette(png_info *   const pngInfoP,
+             unsigned int const shift) {
+/*----------------------------------------------------------------------------
+   Shift every component of every color in the PNG palette right by
+   'shift' bits because sBIT chunk says only those are significant.
+-----------------------------------------------------------------------------*/
+    if (shift > 7)
+        pm_error("Invalid PNG: paletted image can't have "
+                 "more than 8 significant bits per component, "
+                 "but sBIT chunk says %u bits",
+                 shift);
+    else {
+        unsigned int i;
+        
+        for (i = 0; i < pngInfoP->num_palette; ++i) {
+            pngInfoP->palette[i].red   >>= (8 - shift);
+            pngInfoP->palette[i].green >>= (8 - shift);
+            pngInfoP->palette[i].blue  >>= (8 - shift);
+        }
+    }
+}
+
+
+
+static void
+computeMaxvalFromSbit(png_struct *        const pngP,
+                      png_info *          const pngInfoP,
+                      enum alpha_handling const alphaHandling,
+                      png_uint_16 *       const maxvalP,
+                      bool *              const succeededP,
+                      int *               const errorlevelP) {
+
+    /* sBIT handling is very tricky. If we are extracting only the
+       image, we can use the sBIT info for grayscale and color images,
+       if the three values agree. If we extract the transparency/alpha
+       mask, sBIT is irrelevant for trans and valid for alpha. If we
+       mix both, the multiplication may result in values that require
+       the normal bit depth, so we will use the sBIT info only for
+       transparency, if we know that only solid and fully transparent
+       is used 
+    */
+
+    bool notUniform;
+        /* The sBIT chunk says the number of significant high-order bits
+           in each component varies among the components we care about.
+        */
+    png_byte componentSigBit;
+        /* The number of high-order significant bits in each RGB component.
+           Meaningless if they aren't all the same (i.e. 'notUniform')
+        */
+
+    getComponentSbit(pngInfoP, alphaHandling, &componentSigBit, &notUniform);
+
+    if (notUniform) {
+        pm_message("This program cannot handle "
+                   "different bit depths for color channels");
+        pm_message("writing file with %u bit resolution", pngInfoP->bit_depth);
+        *succeededP = false;
+        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+    } else if (componentSigBit > 15) {
+        pm_message("Invalid PNG: says %u significant bits for a component; "
+                   "max possible is 16.  Ignoring sBIT chunk.",
+                   componentSigBit);
+        *succeededP = false;
+        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+    } else {
+        if (alphaHandling == ALPHA_MIX &&
+            (pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+             pngInfoP->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+             paletteHasPartialTransparency(pngInfoP)))
+            *succeededP = false;
+        else {
+            if (componentSigBit < pngInfoP->bit_depth) {
+                pm_message("Image has fewer significant bits, "
+                           "writing file with %u bits", componentSigBit);
+                *maxvalP = (1l << componentSigBit) - 1;
+                *succeededP = true;
+
+                if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE)
+                    shiftPalette(pngInfoP, componentSigBit);
+                else
+                    png_set_shift(pngP, &pngInfoP->sig_bit);
+            } else
+                *succeededP = false;
+        }
+    }
+}
+
+
+
+static void
+setupSignificantBits(png_struct *        const pngP,
+                     png_info *          const pngInfoP,
+                     enum alpha_handling const alphaHandling,
+                     png_uint_16 *       const maxvalP,
+                     int *               const errorlevelP) {
+/*----------------------------------------------------------------------------
+  Figure out what maxval would best express the information in the PNG
+  described by *pngP and *pngInfoP, with 'alpha' telling which
+  information in the PNG we care about (image or alpha mask).
+
+  Return the result as *maxvalP.
+
+  Also set up *pngP for the corresponding significant bits.
+-----------------------------------------------------------------------------*/
+    bool gotItFromSbit;
+    
+    if (pngInfoP->valid & PNG_INFO_sBIT)
+        computeMaxvalFromSbit(pngP, pngInfoP, alphaHandling,
+                              maxvalP, &gotItFromSbit, errorlevelP);
+    else
+        gotItFromSbit = false;
+
+    if (!gotItFromSbit) {
+        if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
+            if (alphaHandling == ALPHA_ONLY) {
+                if (pngInfoP->color_type == PNG_COLOR_TYPE_GRAY ||
+                    pngInfoP->color_type == PNG_COLOR_TYPE_RGB)
+                    /* The alpha mask will be all opaque, so maxval 1
+                       is plenty
+                    */
+                    *maxvalP = 1;
+                else if (paletteHasPartialTransparency(pngInfoP))
+                    /* Use same maxval as PNG transparency palette for
+                       simplicity
+                    */
+                    *maxvalP = 255;
+                else
+                    /* A common case, so we conserve bits */
+                    *maxvalP = 1;
+            } else
+                /* Use same maxval as PNG palette for simplicity */
+                *maxvalP = 255;
+        } else {
+            *maxvalP = (1l << pngInfoP->bit_depth) - 1;
+        }
+    }
+}
+
+
+
+static bool
+imageHasColor(png_info * const info_ptr) {
+
+    bool retval;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+
+        retval = FALSE;
+    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        bool foundColor;
+        unsigned int i;
+            
+        for (i = 0, foundColor = FALSE;
+             i < info_ptr->num_palette && !foundColor;
+             ++i) {
+            if (iscolor(info_ptr->palette[i]))
+                foundColor = TRUE;
+        }
+        retval = foundColor;
+    } else
+        retval = TRUE;
+
+    return retval;
+}
+
+
+
+static void
+determineOutputType(png_info *          const pngInfoP,
+                    enum alpha_handling const alphaHandling,
+                    pngcolor            const bgColor,
+                    xelval              const maxval,
+                    int *               const formatP,
+                    unsigned int *      const depthP,
+                    char *              const tupleType) {
+
+    if (alphaHandling == ALPHA_ONLY) {
+        /* The output is a old style pseudo-PNM transparency image */
+        *depthP = 1;
+        *formatP = maxval > 1 ? PGM_FORMAT : PBM_FORMAT;
+    } else {            
+        /* The output is a normal Netpbm image */
+        bool const outputIsColor =
+            imageHasColor(pngInfoP) || !isGrayscale(bgColor);
+
+        if (alphaHandling == ALPHA_IN) {
+            *formatP = PAM_FORMAT;
+            if (outputIsColor) {
+                *depthP = 4;
+                strcpy(tupleType, "RGB_ALPHA");
+            } else {
+                *depthP = 1;
+                strcpy(tupleType, "GRAYSCALE_ALPHA");
+            }
+        } else {
+            if (outputIsColor) {
+                *formatP = PPM_FORMAT;
+                *depthP = 3;
+            } else {
+                *depthP = 1;
+                *formatP = maxval > 1 ? PGM_FORMAT : PBM_FORMAT;
+            }
+        }
+    }
+}
+
+
+
+static void
+getBackgroundColor(png_info *   const info_ptr,
+                   const char * const requestedColor,
+                   float        const totalgamma,
+                   xelval       const maxval,
+                   pngcolor *   const bgColorP) {
+/*----------------------------------------------------------------------------
+   Figure out what the background color should be.  If the user requested
+   a particular color ('requestedColor' not null), that's the one.
+   Otherwise, if the PNG specifies a background color, that's the one.
+   And otherwise, it's white.
+-----------------------------------------------------------------------------*/
+    if (requestedColor) {
+        /* Background was specified from the command-line; we always
+           use that.  I chose to do no gamma-correction in this case;
+           which is a bit arbitrary.  
+        */
+        pixel const backcolor = ppm_parsecolor(requestedColor, maxval);
+
+        bgColorP->r = PPM_GETR(backcolor);
+        bgColorP->g = PPM_GETG(backcolor);
+        bgColorP->b = PPM_GETB(backcolor);
+
+    } else if (info_ptr->valid & PNG_INFO_bKGD) {
+        /* didn't manage to get libpng to work (bugs?) concerning background
+           processing, therefore we do our own.
+        */
+        switch (info_ptr->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            bgColorP->r = bgColorP->g = bgColorP->b = 
+                gamma_correct(info_ptr->background.gray, totalgamma);
+            break;
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_color const rawBgcolor = 
+                info_ptr->palette[info_ptr->background.index];
+            bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma);
+            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
+            bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma);
+        }
+        break;
+        case PNG_COLOR_TYPE_RGB:
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            png_color_16 const rawBgcolor = info_ptr->background;
+            
+            bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
+            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
+            bgColorP->b = gamma_correct(rawBgcolor.blue,  totalgamma);
+        }
+        break;
+        }
+    } else 
+        /* when no background given, we use white [from version 2.37] */
+        bgColorP->r = bgColorP->g = bgColorP->b = maxval;
+}
+
+
+
+#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth)
+
+
+
+static void
+makeTupleRow(const struct pam *  const pamP,
+             const tuple *       const tuplerow,
+             png_info *          const pngInfoP,
+             const png_byte *    const pngRasterRow,
+             pngcolor            const bgColor,
+             enum alpha_handling const alphaHandling,
+             double              const totalgamma) {
+
+    const png_byte * pngPixelP;
+    unsigned int col;
+
+    pngPixelP = &pngRasterRow[0];  /* initial value */
+    for (col = 0; col < pngInfoP->width; ++col) {
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY: {
+            pngcolor fgColor;
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_GRAY_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor,
+                     alphaHandling, alpha);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
+            png_color   const paletteColor = pngInfoP->palette[index];
+
+            pngcolor fgColor;
+
+            fgColor.r = paletteColor.red;
+            fgColor.g = paletteColor.green;
+            fgColor.b = paletteColor.blue;
+
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                     (pngInfoP->valid & PNG_INFO_tRNS) &&
+                     index < pngInfoP->num_trans ?
+                     pngInfoP->trans[index] : maxval);
+        }
+        break;
+                
+        case PNG_COLOR_TYPE_RGB: {
+            pngcolor fgColor;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                     isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                     0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha     = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor,
+                     alphaHandling, alpha);
+        }
+        break;
+
+        default:
+            pm_error("unknown PNG color type: %d", pngInfoP->color_type);
+        }
+    }
+}
+
+
+
+static void
+reportOutputFormat(const struct pam * const pamP) {
+
+    switch (pamP->format) {
+
+    case PBM_FORMAT:
+        pm_message("Writing a PBM file");
+        break;
+    case PGM_FORMAT:
+        pm_message("Writing a PGM file with maxval %lu", pamP->maxval);
+        break;
+    case PPM_FORMAT:
+        pm_message("Writing a PPM file with maxval %lu", pamP->maxval);
+        break;
+    case PAM_FORMAT:
+        pm_message("Writing a PAM file with tuple type %s, maxval %u",
+                   pamP->tuple_type, maxval);
+        break;
+    default:
+        assert(false); /* Every possible value handled above */
+    }
+}
+    
+
+
+static void
+writeNetpbm(struct pam *        const pamP,
+            png_info *          const pngInfoP,
+            png_byte **         const pngRaster,
+            pngcolor            const bgColor,
+            enum alpha_handling const alphaHandling,
+            double              const totalgamma) {
+/*----------------------------------------------------------------------------
+   Write a Netpbm image of either the image or the alpha mask, according to
+   'alphaHandling' that is in the PNG image described by 'pngInfoP' and
+   pngRaster.
+
+   *pamP describes the required output image and is consistent with
+   *pngInfoP.
+
+   Use background color 'bgColor' in the output if the PNG is such that a
+   background color is needed.
+-----------------------------------------------------------------------------*/
+    tuple * tuplerow;
+    unsigned int row;
+
+    if (verbose)
+        reportOutputFormat(pamP);
+
+    pnm_writepaminit(pamP);
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    for (row = 0; row < pngInfoP->height; ++row) {
+        makeTupleRow(pamP, tuplerow, pngInfoP, pngRaster[row], bgColor,
+                     alphaHandling, totalgamma);
+
+        pnm_writepamrow(pamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void 
+convertpng(FILE *             const ifp, 
+           FILE *             const tfp, 
+           struct cmdlineInfo const cmdline,
+           int *              const errorlevelP) {
+
+    png_struct * png_ptr;
+    png_info * info_ptr;
+    png_byte ** png_image;
+    pngcolor bgColor;
+    float totalgamma;
+    struct pam pam;
+
+    *errorlevelP = 0;
+
+    read_sig_buf(ifp);
+
+    png_ptr = png_create_read_struct(
+        PNG_LIBPNG_VER_STRING,
+        &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
+    if (png_ptr == NULL)
+        pm_error("cannot allocate main libpng structure (png_ptr)");
+
+    info_ptr = png_create_info_struct (png_ptr);
+    if (info_ptr == NULL)
+        pm_error("cannot allocate LIBPNG structures");
+
+    if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf))
+        pm_error ("setjmp returns error condition");
+
+    png_init_io (png_ptr, ifp);
+    png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
+    png_read_info (png_ptr, info_ptr);
+
+    allocPngRaster(info_ptr, &png_image);
+
+    if (info_ptr->bit_depth < 8)
+        png_set_packing (png_ptr);
+
+    setupGammaCorrection(png_ptr, info_ptr, cmdline.gamma, &totalgamma);
+
+    setupSignificantBits(png_ptr, info_ptr, cmdline.alpha,
+                         &maxval, errorlevelP);
+
+    getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval,
+                       &bgColor);
+
+    png_read_image(png_ptr, png_image);
+    png_read_end(png_ptr, info_ptr);
+
+    if (verbose)
+        /* Note that some of info_ptr is not defined until png_read_end() 
+           completes.  That's because it comes from chunks that are at the
+           end of the stream.
+        */
+        dump_png_info(info_ptr);
+
+    if (cmdline.time)
+        show_time(info_ptr);
+    if (tfp)
+        save_text(info_ptr, tfp);
+
+    if (info_ptr->valid & PNG_INFO_pHYs) {
+        float const r =
+            (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
+        if (r != 1.0) {
+            pm_message ("warning - non-square pixels; "
+                        "to fix do a 'pamscale -%cscale %g'",
+                        r < 1.0 ? 'x' : 'y',
+                        r < 1.0 ? 1.0 / r : r );
+            *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+        }
+    }
+
+    pam.size        = sizeof(pam);
+    pam.len         = PAM_STRUCT_SIZE(maxval);
+    pam.file        = stdout;
+    pam.plainformat = 0;
+    pam.height      = info_ptr->height;
+    pam.width       = info_ptr->width;
+    pam.maxval      = maxval;
+
+    determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval,
+                        &pam.format, &pam.depth, pam.tuple_type);
+
+    writeNetpbm(&pam, info_ptr, png_image, bgColor, cmdline.alpha, totalgamma);
+
+    fflush(stdout);
+
+    freePngRaster(png_image, info_ptr);
+
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+}
+
+
+
+int 
+main(int argc, const char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * tfP;
+    int errorlevel;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    if (cmdline.text)
+        tfP = pm_openw(cmdline.text);
+    else
+        tfP = NULL;
+
+    convertpng(ifP, tfP, cmdline, &errorlevel);
+
+    if (tfP)
+        pm_close(tfP);
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return errorlevel;
+}
diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c
index c7a39df1..8ffff617 100644
--- a/converter/other/pngtopnm.c
+++ b/converter/other/pngtopnm.c
@@ -16,20 +16,6 @@
 ** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
 */
 
-/* 
-   BJH 20000408:  rename PPM_MAXMAXVAL to PPM_OVERALLMAXVAL
-   BJH 20000303:  fix include statement so dependencies work out right.
-*/
-/* GRR 19991203:  moved VERSION to new version.h header file */
-
-/* GRR 19990713:  fixed redundant freeing of png_ptr and info_ptr in setjmp()
- *  blocks and added "pm_close(ifp)" in each.  */
-
-/* GRR 19990317:  declared "clobberable" automatic variables in convertpng()
- *  static to fix Solaris/gcc stack-corruption bug.  Also installed custom
- *  error-handler to avoid jmp_buf size-related problems (i.e., jmp_buf
- *  compiled with one size in libpng and another size here).  */
-
 #ifndef PNMTOPNG_WARNING_LEVEL
 #  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
 #endif                               /*  2 for warnings (1 == error) */
@@ -39,33 +25,15 @@
 #include <png.h>    /* includes zlib.h and setjmp.h */
 #define VERSION "2.37.4 (5 December 1999) +netpbm"
 
-#include "pnm.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
+#include "pnm.h"
 
 typedef struct _jmpbuf_wrapper {
   jmp_buf jmpbuf;
 } jmpbuf_wrapper;
 
-/* GRR 19991205:  this is used as a test for pre-1999 versions of netpbm and
- *   pbmplus vs. 1999 or later (in which pm_close was split into two)
- */
-#ifdef PBMPLUS_RAWBITS
-#  define pm_closer pm_close
-#  define pm_closew pm_close
-#endif
-
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
-#ifndef NONE
-#  define NONE 0
-#endif
-
 enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX};
 
 struct cmdlineInfo {
@@ -82,7 +50,7 @@ struct cmdlineInfo {
 };
 
 
-typedef struct pngcolor {
+typedef struct {
 /*----------------------------------------------------------------------------
    A color in a format compatible with the PNG library.
 
@@ -96,15 +64,14 @@ typedef struct pngcolor {
 
 
 static png_uint_16 maxval;
-static int verbose = FALSE;
-static int mtime;
+static bool verbose;
 static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
 
 
 static void
-parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+parseCommandLine(int                  argc, 
+                 const char **        argv,
+                 struct cmdlineInfo * cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -115,7 +82,7 @@ parseCommandLine(int                 argc,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -124,6 +91,8 @@ parseCommandLine(int                 argc,
 
     unsigned int alphaSpec, mixSpec, backgroundSpec, gammaSpec, textSpec;
 
+    MALLOCARRAY(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
             &cmdlineP->verbose,       0);
@@ -144,7 +113,7 @@ parseCommandLine(int                 argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -180,12 +149,9 @@ parseCommandLine(int                 argc,
 
 
 
-
-#define get_png_val(p) _get_png_val (&(p), info_ptr->bit_depth)
-
 static png_uint_16
-_get_png_val (png_byte ** const pp,
-              int         const bit_depth) {
+get_png_val(const png_byte ** const pp,
+            int               const bit_depth) {
 
     png_uint_16 c;
     
@@ -241,8 +207,8 @@ gamma_correct(png_uint_16 const v,
               float       const g) {
 
     if (g != -1.0)
-        return (png_uint_16) (pow ((double) v / maxval, 
-                                   (1.0 / g)) * maxval + 0.5);
+        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
+                                    maxval);
     else
         return v;
 }
@@ -443,29 +409,108 @@ dump_png_info(png_info *info_ptr) {
 
 
 
+static unsigned int
+computePngLineSize(png_info * const pngInfoP) {
+
+    unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngInfoP->color_type) {
+    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
+    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
+    default:                        samplesPerPixel = 1;
+    }
+
+    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngInfoP->width)
+        pm_error("Width %u of PNG is uncomputably large",
+                 (unsigned int)pngInfoP->width);
+       
+    return pngInfoP->width * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(png_info *   const pngInfoP,
+               png_byte *** const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngInfoP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngInfoP->height);
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate space for %u PNG raster rows",
+                 (unsigned int)pngInfoP->height);
+
+    for (row = 0; row < pngInfoP->height; ++row) {
+        MALLOCARRAY(pngImage[row], lineSize);
+        if (pngImage[row] == NULL)
+            pm_error("couldn't allocate space for %uth row of PNG raster",
+                     row);
+    }
+    *pngImageP = pngImage;
+}
+
+
+
+static void
+freePngRaster(png_byte ** const pngRaster,
+              png_info *  const pngInfoP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngInfoP->height; ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
 static bool
 isTransparentColor(pngcolor   const color,
-                   png_info * const info_ptr,
+                   png_info * const pngInfoP,
                    double     const totalgamma) {
 /*----------------------------------------------------------------------------
    Return TRUE iff pixels of color 'color' are supposed to be transparent
    everywhere they occur.  Assume it's an RGB image.
+
+   'color' has been gamma-corrected.
 -----------------------------------------------------------------------------*/
     bool retval;
 
-    if (info_ptr->valid & PNG_INFO_tRNS) {
-        const png_color_16 * const transColorP = &info_ptr->trans_values;
-    
+    if (pngInfoP->valid & PNG_INFO_tRNS) {
+        const png_color_16 * const transColorP = &pngInfoP->trans_values;
 
-        /* There seems to be a problem here: you can't compare real
-           numbers for equality.  Also, I'm not sure the gamma
-           corrected/uncorrected color spaces are right here.  
-        */
+        /* It seems odd that libpng lets you get gamma-corrected pixel
+           values, but not gamma-corrected transparency or background
+           values.  But as that is the case, we have to gamma-correct
+           the transparency values.
+
+           Note that because we compare the gamma-corrected values and
+           there may be many-to-one mapping of uncorrected to corrected
+           values, more pixels may be transparent than what the user
+           intended.
 
-        retval = 
-            color.r == gamma_correct(transColorP->red,   totalgamma) &&
-            color.g == gamma_correct(transColorP->green, totalgamma) &&
-            color.b == gamma_correct(transColorP->blue,  totalgamma);
+           We could fix this by not letting libpng gamma-correct the
+           pixels, and just do it ourselves.
+        */
+    
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
+            break;
+        default:
+            retval = 
+                color.r == gamma_correct(transColorP->red,   totalgamma) &&
+                color.g == gamma_correct(transColorP->green, totalgamma) &&
+                color.b == gamma_correct(transColorP->blue,  totalgamma);
+        }
     } else 
         retval = FALSE;
 
@@ -752,11 +797,11 @@ determineOutputType(png_info *          const info_ptr,
 
 
 static void
-getBackgroundColor(png_info *        const info_ptr,
-                   const char *      const requestedColor,
-                   float             const totalgamma,
-                   xelval            const maxval,
-                   struct pngcolor * const bgColorP) {
+getBackgroundColor(png_info *   const info_ptr,
+                   const char * const requestedColor,
+                   float        const totalgamma,
+                   xelval       const maxval,
+                   pngcolor *   const bgColorP) {
 /*----------------------------------------------------------------------------
    Figure out what the background color should be.  If the user requested
    a particular color ('requestedColor' not null), that's the one.
@@ -809,21 +854,109 @@ getBackgroundColor(png_info *        const info_ptr,
 
 
 
+#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth)
+
+
+
+static void
+makeXelRow(xel *               const xelrow,
+           xelval              const maxval,
+           int                 const pnmType,
+           png_info *          const pngInfoP,
+           const png_byte *    const pngRasterRow,
+           pngcolor            const bgColor,
+           enum alpha_handling const alphaHandling,
+           double              const totalgamma) {
+
+    const png_byte * pngPixelP;
+    unsigned int col;
+
+    pngPixelP = &pngRasterRow[0];  /* initial value */
+    for (col = 0; col < pngInfoP->width; ++col) {
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY: {
+            pngcolor fgColor;
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_GRAY_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
+            png_color   const paletteColor = pngInfoP->palette[index];
+
+            pngcolor fgColor;
+
+            fgColor.r = paletteColor.red;
+            fgColor.g = paletteColor.green;
+            fgColor.b = paletteColor.blue;
+
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   (pngInfoP->valid & PNG_INFO_tRNS) &&
+                   index < pngInfoP->num_trans ?
+                   pngInfoP->trans[index] : maxval);
+        }
+        break;
+                
+        case PNG_COLOR_TYPE_RGB: {
+            pngcolor fgColor;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha     = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
+        }
+        break;
+
+        default:
+            pm_error("unknown PNG color type: %d", pngInfoP->color_type);
+        }
+    }
+}
+
+
+
 static void
 writePnm(FILE *              const ofP,
          xelval              const maxval,
-         int                 const pnm_type,
-         png_info *          const info_ptr,
-         png_byte **         const png_image,
+         int                 const pnmType,
+         png_info *          const pngInfoP,
+         png_byte **         const pngRaster,
          pngcolor            const bgColor,
-         enum alpha_handling const alpha_handling,
+         enum alpha_handling const alphaHandling,
          double              const totalgamma) {
 /*----------------------------------------------------------------------------
    Write a PNM of either the image or the alpha mask, according to
-   'alpha_handling' that is in the PNG image described by 'info_ptr' and
-   png_image.
+   'alphaHandling' that is in the PNG image described by 'pngInfoP' and
+   pngRaster.
 
-   'pnm_type' and 'maxval' are of the output image.
+   'pnmType' and 'maxval' are of the output image.
 
    Use background color 'bgColor' in the output if the PNG is such that a
    background color is needed.
@@ -832,93 +965,23 @@ writePnm(FILE *              const ofP,
     unsigned int row;
 
     if (verbose)
-        pm_message ("writing a %s file (maxval=%u)",
-                    pnm_type == PBM_TYPE ? "PBM" :
-                    pnm_type == PGM_TYPE ? "PGM" :
-                    pnm_type == PPM_TYPE ? "PPM" :
-                    "UNKNOWN!", 
-                    maxval);
+        pm_message("writing a %s file (maxval=%u)",
+                   pnmType == PBM_TYPE ? "PBM" :
+                   pnmType == PGM_TYPE ? "PGM" :
+                   pnmType == PPM_TYPE ? "PPM" :
+                   "UNKNOWN!", 
+                   maxval);
     
-    xelrow = pnm_allocrow(info_ptr->width);
-
-    pnm_writepnminit(stdout, info_ptr->width, info_ptr->height, maxval,
-                     pnm_type, FALSE);
-
-    for (row = 0; row < info_ptr->height; ++row) {
-        png_byte * png_pixelP;
-        int col;
-
-        png_pixelP = &png_image[row][0];  /* initial value */
-        for (col = 0; col < info_ptr->width; ++col) {
-            switch (info_ptr->color_type) {
-            case PNG_COLOR_TYPE_GRAY: {
-                pngcolor fgColor;
-                fgColor.r = fgColor.g = fgColor.b = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       ((info_ptr->valid & PNG_INFO_tRNS) &&
-                        (fgColor.r == 
-                         gamma_correct(info_ptr->trans_values.gray,
-                                       totalgamma))) ?
-                       0 : maxval);
-            }
-            break;
-
-            case PNG_COLOR_TYPE_GRAY_ALPHA: {
-                pngcolor fgColor;
-                png_uint_16 alpha;
-
-                fgColor.r = fgColor.g = fgColor.b = get_png_val(png_pixelP);
-                alpha = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
-            }
-            break;
-
-            case PNG_COLOR_TYPE_PALETTE: {
-                png_uint_16 const index        = get_png_val(png_pixelP);
-                png_color   const paletteColor = info_ptr->palette[index];
-
-                pngcolor fgColor;
-
-                fgColor.r = paletteColor.red;
-                fgColor.g = paletteColor.green;
-                fgColor.b = paletteColor.blue;
-
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       (info_ptr->valid & PNG_INFO_tRNS) &&
-                       index < info_ptr->num_trans ?
-                       info_ptr->trans[index] : maxval);
-            }
-            break;
-                
-            case PNG_COLOR_TYPE_RGB: {
-                pngcolor fgColor;
-
-                fgColor.r = get_png_val(png_pixelP);
-                fgColor.g = get_png_val(png_pixelP);
-                fgColor.b = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       isTransparentColor(fgColor, info_ptr, totalgamma) ?
-                       0 : maxval);
-            }
-            break;
+    xelrow = pnm_allocrow(pngInfoP->width);
 
-            case PNG_COLOR_TYPE_RGB_ALPHA: {
-                pngcolor fgColor;
-                png_uint_16 alpha;
+    pnm_writepnminit(stdout, pngInfoP->width, pngInfoP->height, maxval,
+                     pnmType, FALSE);
 
-                fgColor.r = get_png_val(png_pixelP);
-                fgColor.g = get_png_val(png_pixelP);
-                fgColor.b = get_png_val(png_pixelP);
-                alpha     = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
-            }
-            break;
+    for (row = 0; row < pngInfoP->height; ++row) {
+        makeXelRow(xelrow, maxval, pnmType, pngInfoP, pngRaster[row], bgColor,
+                   alphaHandling, totalgamma);
 
-            default:
-                pm_error ("unknown PNG color type: %d", info_ptr->color_type);
-            }
-        }
-        pnm_writepnmrow(ofP, xelrow, info_ptr->width, maxval, pnm_type, FALSE);
+        pnm_writepnmrow(ofP, xelrow, pngInfoP->width, maxval, pnmType, FALSE);
     }
     pnm_freerow (xelrow);
 }
@@ -931,11 +994,9 @@ convertpng(FILE *             const ifp,
            struct cmdlineInfo const cmdline,
            int *              const errorlevelP) {
 
-    png_struct *png_ptr;
-    png_info *info_ptr;
-    png_byte **png_image;
-    int x, y;
-    int linesize;
+    png_struct * png_ptr;
+    png_info * info_ptr;
+    png_byte ** png_image;
     int pnm_type;
     pngcolor bgColor;
     float totalgamma;
@@ -961,38 +1022,7 @@ convertpng(FILE *             const ifp,
     png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
     png_read_info (png_ptr, info_ptr);
 
-    MALLOCARRAY(png_image, info_ptr->height);
-    if (png_image == NULL) {
-        png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
-        pm_closer (ifp);
-        pm_error ("couldn't allocate space for image");
-    }
-
-    if (info_ptr->bit_depth == 16)
-        linesize = 2 * info_ptr->width;
-    else
-        linesize = info_ptr->width;
-
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-        linesize *= 2;
-    else
-        if (info_ptr->color_type == PNG_COLOR_TYPE_RGB)
-            linesize *= 3;
-        else
-            if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-                linesize *= 4;
-
-    for (y = 0 ; y < info_ptr->height ; y++) {
-        png_image[y] = malloc (linesize);
-        if (png_image[y] == NULL) {
-            for (x = 0 ; x < y ; x++)
-                free (png_image[x]);
-            free (png_image);
-            png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
-            pm_closer (ifp);
-            pm_error ("couldn't allocate space for image");
-        }
-    }
+    allocPngRaster(info_ptr, &png_image);
 
     if (info_ptr->bit_depth < 8)
         png_set_packing (png_ptr);
@@ -1005,24 +1035,24 @@ convertpng(FILE *             const ifp,
     getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval,
                        &bgColor);
 
-    png_read_image (png_ptr, png_image);
-    png_read_end (png_ptr, info_ptr);
+    png_read_image(png_ptr, png_image);
+    png_read_end(png_ptr, info_ptr);
 
     if (verbose)
         /* Note that some of info_ptr is not defined until png_read_end() 
-       completes.  That's because it comes from chunks that are at the
-       end of the stream.
-    */
+           completes.  That's because it comes from chunks that are at the
+           end of the stream.
+        */
         dump_png_info(info_ptr);
 
-    if (mtime)
-        show_time (info_ptr);
+    if (cmdline.time)
+        show_time(info_ptr);
     if (tfp)
-        save_text (info_ptr, tfp);
+        save_text(info_ptr, tfp);
 
     if (info_ptr->valid & PNG_INFO_pHYs) {
-        float r;
-        r = (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
+        float const r =
+            (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
         if (r != 1.0) {
             pm_message ("warning - non-square pixels; "
                         "to fix do a 'pamscale -%cscale %g'",
@@ -1038,41 +1068,41 @@ convertpng(FILE *             const ifp,
              cmdline.alpha, totalgamma);
 
     fflush(stdout);
-    for (y = 0 ; y < info_ptr->height ; y++)
-        free (png_image[y]);
-    free (png_image);
-    png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
+
+    freePngRaster(png_image, info_ptr);
+
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 }
 
 
 
 int 
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
-    FILE *ifp, *tfp;
+    FILE * ifP;
+    FILE * tfP;
     int errorlevel;
 
-    pnm_init (&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
     verbose = cmdline.verbose;
-    mtime = cmdline.time;
 
-    ifp = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFilespec);
 
     if (cmdline.text)
-        tfp = pm_openw(cmdline.text);
+        tfP = pm_openw(cmdline.text);
     else
-        tfp = NULL;
+        tfP = NULL;
 
-    convertpng (ifp, tfp, cmdline, &errorlevel);
+    convertpng(ifP, tfP, cmdline, &errorlevel);
 
-    if (tfp)
-        pm_close(tfp);
+    if (tfP)
+        pm_close(tfP);
 
-    pm_close(ifp);
+    pm_close(ifP);
     pm_close(stdout);
 
     return errorlevel;
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index b339a1fe..72177507 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -1032,7 +1032,7 @@ findRedundantBits(FILE *         const ifp,
 /*----------------------------------------------------------------------------
    Find out if we can use just a subset of the bits from each input
    sample.  Often, people create an image with e.g. 8 bit samples from
-   one that has e.g. only 4 bit samples by scaling by 256/16, which is
+   one that has e.g. only 4 bit samples by scaling by 255/15, which is
    the same as repeating the bits.  E.g.  1011 becomes 10111011.  We
    detect this case.  We return as *meaningfulBitsP the minimum number
    of bits, starting from the least significant end, that contain
@@ -2014,7 +2014,7 @@ createPngPalette(pixel              palette_pnm[],
     for (i = 0; i < transSize; ++i) {
         unsigned int const newmv = PALETTEMAXVAL;
         unsigned int const oldmv = alpha_maxval;
-        trans[i] = (trans_pnm[i] * newmv + (oldmv/2)) / oldmv;
+        trans[i] = ROUNDDIV(trans_pnm[i] * newmv, oldmv);
     }
 }
 
@@ -2369,7 +2369,7 @@ convertpnm(struct cmdlineInfo const cmdline,
       */
   unsigned int fulldepth;
       /* The total number of bits per pixel in the (uncompressed) png
-         raster, including all channels 
+         raster, including all channels.
       */
   pm_filepos rasterPos;  
       /* file position in input image file of start of image (i.e. after
@@ -2442,8 +2442,8 @@ convertpnm(struct cmdlineInfo const cmdline,
          to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval
          scaling, and this is more precise.
       */
-      PPM_DEPTH (transcolor, ppm_parsecolor(transstring2, maxmaxval),
-                 maxmaxval, maxval);
+      PPM_DEPTH(transcolor, ppm_parsecolor(transstring2, maxmaxval),
+                maxmaxval, maxval);
   }
   if (cmdline.alpha) {
     pixel alpha_transcolor;
diff --git a/converter/other/x11wd.h b/converter/other/x11wd.h
index 711248f5..7161260b 100644
--- a/converter/other/x11wd.h
+++ b/converter/other/x11wd.h
@@ -27,7 +27,7 @@ enum visualclass {StaticGray=0,GrayScale=1,StaticColor=2,PseudoColor=3,
 #define DirectColor 5
 */
 
-typedef uint32n xwdval;
+typedef uint32_t xwdval;
 #define XWDVAL_MAX ((xwdval)(-1))
 #define X11WD_FILE_VERSION 7
 typedef struct {
@@ -67,13 +67,13 @@ typedef struct {
         */
     xwdval window_width;    /* Window width */
     xwdval window_height;   /* Window height */
-    int32n window_x;        /* Window upper left X coordinate */
-    int32n window_y;        /* Window upper left Y coordinate */
+    int32_t window_x;        /* Window upper left X coordinate */
+    int32_t window_y;        /* Window upper left Y coordinate */
     xwdval window_bdrwidth; /* Window border width */
     } X11WDFileHeader;
 
 typedef struct {
-    uint32n num;
+    uint32_t num;
     unsigned short red, green, blue;
     char flags;         /* do_red, do_green, do_blue */
     char pad;
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c
index 261b6c39..2d2c6a42 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -26,6 +26,10 @@
 #include "mallocvar.h"
 #include "g3.h"
 #include "bitreverse.h"
+#include "bitarith.h"
+
+#define LEFTBITS pm_byteLeftBits
+#define RIGHTBITS pm_byteRightBits
 
 #define MAXCOLS 10800
 #define MAXROWS 14400   /* this allows up to two pages of image */
@@ -297,12 +301,12 @@ buildHashes(g3TableEntry * (*whashP)[HASHSIZE],
 
 
 static void
-makeRowWhite(bit *        const bitrow,
-             unsigned int const cols) {
+makeRowWhite(unsigned char * const packedBitrow,
+             unsigned int    const cols) {
 
-    unsigned int col;
-    for (col = 0; col < MAXCOLS; ++col)
-        bitrow[col] = PBM_WHITE;
+    unsigned int colByte;
+    for (colByte = 0; colByte < pbm_packed_bytes(cols); ++colByte)
+        packedBitrow[colByte] = PBM_WHITE * 0xff;
 }
 
 
@@ -335,16 +339,45 @@ g3code(unsigned int const curcode,
 
 
 
-enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK};
+static void
+writeBlackBitSpan(unsigned char * const packedBitrow,
+                  int             const cols,
+                  int             const offset) {
+/*----------------------------------------------------------------------------
+   Write black (="1") bits into packedBitrow[], starting at 'offset',
+   length 'cols'.
+-----------------------------------------------------------------------------*/
+    unsigned char * const dest = & packedBitrow[offset/8];
+    unsigned int const rs  = offset % 8;
+    unsigned int const trs = (cols + rs) % 8;
+    unsigned int const colBytes = pbm_packed_bytes(cols + rs);
+    unsigned int const last = colBytes - 1;
+
+    unsigned char const origHead = dest[0];
+    unsigned char const origEnd =  0x00;
 
+    unsigned int i;
 
+    for( i = 0; i < colBytes; ++i)
+        dest[i] = PBM_BLACK * 0xff;
+
+    if (rs > 0)
+        dest[0] = LEFTBITS(origHead, rs) | RIGHTBITS(dest[0], 8-rs);
+
+    if (trs > 0)
+        dest[last] = LEFTBITS(dest[last], trs) | RIGHTBITS(origEnd, 8-trs);
+}
+
+
+
+enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK};
 
 static void
-processG3Code(g3TableEntry * const teP,
-              bit *          const bitrow,
-              unsigned int * const colP,
-              bit *          const colorP,
-              unsigned int * const countP) {
+processG3Code(const g3TableEntry * const teP,
+              unsigned char *      const packedBitrow,
+              unsigned int *       const colP,
+              bit *                const colorP,
+              unsigned int *       const countP) {
               
     enum g3tableId const teId =
         (teP > mtable ? 2 : 0) + (teP - ttable) % 2;
@@ -368,14 +401,10 @@ processG3Code(g3TableEntry * const teP,
         runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col);
 
         if (runLengthSoFar > 0) {
-            if (*colorP == PBM_WHITE) {
-                /* Row was initialized to white, so we just skip */
-                col += runLengthSoFar;
-            } else {
-                unsigned int i;
-                for (i = 0; i < runLengthSoFar; ++i)
-                    bitrow[col++] = PBM_BLACK;
-            }
+            if (*colorP == PBM_BLACK)
+                writeBlackBitSpan(packedBitrow, runLengthSoFar, col);
+            /* else : Row was initialized to white, so we just skip */
+            col += runLengthSoFar;
         }
         *colorP = !*colorP;
         *countP = 0;
@@ -410,13 +439,13 @@ formatBadCodeException(const char ** const exceptionP,
 
 static void
 readFaxRow(struct bitStream * const bitStreamP,
-           bit *              const bitrow,
+           unsigned char *    const packedBitrow,
            unsigned int *     const lineLengthP,
            const char **      const exceptionP,
            const char **      const errorP) {
 /*----------------------------------------------------------------------------
   Read one line of G3 fax from the bit stream *bitStreamP into 
-  bitrow[].  Return the length of the line, in pixels, as *lineLengthP.
+  packedBitrow[].  Return the length of the line, in pixels, as *lineLengthP.
 
   If there's a problem with the line, return as much of it as we can,
   advance the input stream past the next EOL mark, and put a text
@@ -440,11 +469,9 @@ readFaxRow(struct bitStream * const bitStreamP,
         /* Number of consecutive pixels of the same color */
     bit currentColor;
         /* The color of the current run of pixels */
-    g3TableEntry * te;
-        /* Address of structure that describes the current G3 code */
     bool done;
 
-    makeRowWhite(bitrow, MAXCOLS);  /* initialize row */
+    makeRowWhite(packedBitrow, MAXCOLS);  /* initialize row */
 
     col = 0;
     curlen = 0;
@@ -485,10 +512,14 @@ readFaxRow(struct bitStream * const bitStreamP,
                     formatBadCodeException(exceptionP, col, curlen, curcode);
                     done = TRUE;
                 } else if (curcode != 0) {
-                    te = g3code(curcode, curlen, currentColor);
-                    
-                    if (te) {
-                        processG3Code(te, bitrow, &col, &currentColor, &count);
+                    const g3TableEntry * const teP =
+                        g3code(curcode, curlen, currentColor);
+                        /* Address of structure that describes the 
+                           current G3 code
+                        */
+                    if (teP) {
+                        processG3Code(teP, packedBitrow,
+                                      &col, &currentColor, &count);
                         
                         curcode = 0;
                         curlen = 0;
@@ -506,9 +537,9 @@ readFaxRow(struct bitStream * const bitStreamP,
 
 
 static void
-freeBits(bit **       const bits,
-         unsigned int const rows,
-         bool         const stretched) {
+freeBits(unsigned char ** const packedBits,
+         unsigned int     const rows,
+         bool             const stretched) {
 
     unsigned int row;
 
@@ -518,9 +549,9 @@ freeBits(bit **       const bits,
                free it twice.
             */
         } else 
-            pbm_freerow(bits[row]);
+            pbm_freerow_packed(packedBits[row]);
     }
-    free(bits);
+    free(packedBits);
 }
 
 
@@ -638,17 +669,17 @@ readFax(struct bitStream * const bitStreamP,
         bool               const stretch,
         unsigned int       const expectedLineSize,
         bool               const tolerateErrors,
-        bit ***            const bitsP,
+        unsigned char ***  const packedBitsP,
         unsigned int *     const colsP,
         unsigned int *     const rowsP) {
 
     lineSizeAnalyzer lineSizeAnalyzer;
-    bit ** bits;
+    unsigned char ** packedBits;
     const char * error;
     bool eof;
     unsigned int row;
     
-    MALLOCARRAY_NOFAIL(bits, MAXROWS);
+    MALLOCARRAY_NOFAIL(packedBits, MAXROWS);
 
     initializeLineSizeAnalyzer(&lineSizeAnalyzer,
                                expectedLineSize, tolerateErrors);
@@ -666,8 +697,9 @@ readFax(struct bitStream * const bitStreamP,
         else {
             const char * exception;
 
-            bits[row] = pbm_allocrow(MAXCOLS);
-            readFaxRow(bitStreamP, bits[row], &lineSize, &exception, &error);
+            packedBits[row] = pbm_allocrow_packed(MAXCOLS);
+            readFaxRow(bitStreamP, packedBits[row],
+                       &lineSize, &exception, &error);
 
             handleRowException(exception, error, row, tolerateErrors);
 
@@ -685,16 +717,16 @@ readFax(struct bitStream * const bitStreamP,
                                       "program can handle at most %u rows "
                                       "after stretching", MAXROWS);
                         else
-                            bits[row] = bits[row-1];
+                            packedBits[row] = packedBits[row-1];
                     }
                     ++row;
                 }
             }
         }
     }
-    *rowsP  = row;
-    *colsP  = lineSizeAnalyzer.maxLineSize;
-    *bitsP  = bits;
+    *rowsP        = row;
+    *colsP        = lineSizeAnalyzer.maxLineSize;
+    *packedBitsP  = packedBits;
 }
 
 
@@ -706,7 +738,8 @@ main(int argc, char * argv[]) {
     FILE * ifP;
     struct bitStream bitStream;
     unsigned int rows, cols;
-    bit ** bits;
+    unsigned char ** packedBits;
+    int row;
 
     pbm_init(&argc, argv);
 
@@ -728,14 +761,17 @@ main(int argc, char * argv[]) {
 
     readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize,
             !cmdline.stop_error, 
-            &bits, &cols, &rows);
+            &packedBits, &cols, &rows);
 
     pm_close(ifP);
 
-    pbm_writepbm(stdout, bits, cols, rows, 0);
+    pbm_writepbminit(stdout, cols, rows, 0);
+    for (row = 0; row < rows; ++row)
+        pbm_writepbmrow_packed(stdout, packedBits[row], cols, 0);
+
     pm_close(stdout);
 
-    freeBits(bits, rows, cmdline.stretch);
+    freeBits(packedBits, rows, cmdline.stretch);
 
     return 0;
 }
diff --git a/converter/pbm/pbmtodjvurle.c b/converter/pbm/pbmtodjvurle.c
index dbe96f31..83e99ec4 100644
--- a/converter/pbm/pbmtodjvurle.c
+++ b/converter/pbm/pbmtodjvurle.c
@@ -50,91 +50,97 @@ writebyte(FILE *        const ofP,
 
 /* Write a run length to the RLE file. */
 static void 
-write_rle (FILE *rlefile, uint32n tally)
-{
-  do {
-    /* Output a single run. */
-    if (tally < 192) {
-      /* Single-byte runs */
-      writebyte (rlefile, tally);
-      tally >>= 8;
+write_rle(FILE *   const rlefile,
+          uint32_t const tallyArg) {
+
+    uint32_t remainingTally;
+
+    remainingTally = tallyArg;  /* initial value */
+
+    do {
+        /* Output a single run. */
+        if (remainingTally < 192) {
+            /* Single-byte runs */
+            writebyte (rlefile, remainingTally);
+            remainingTally >>= 8;
+        }
+        else {
+            /* Two-byte runs */
+            writebyte (rlefile, ((remainingTally>>8) & 0x3F) + 0xC0);
+            writebyte (rlefile, remainingTally & 0xFF);
+            remainingTally >>= 14;
+        }
+
+        /* Very large runs need to be split into smaller runs.  We
+           therefore need to toggle back to the same color we had for the
+           previous smaller run.
+        */
+        if (remainingTally > 0)
+            writebyte (rlefile, 0);
     }
-    else {
-      /* Two-byte runs */
-      writebyte (rlefile, ((tally>>8)&0x3F) + 0xC0);
-      writebyte (rlefile, tally&0xFF);
-      tally >>= 14;
-    }
-
-    /* Very large runs need to be split into smaller runs.  We
-     * therefore need to toggle back to the same color we had for the
-     * previous smaller run. */
-    if (tally > 0)
-      writebyte (rlefile, 0);
-  }
-  while (tally > 0);
+    while (remainingTally > 0);
 }
 
 
 
 int 
-main (int argc, char *argv[])
-{
-  FILE * const rlefile = stdout;    /* Generated Bitonal RLE file */
-
-  FILE *pbmfile;             /* PBM file to convert */
-  int numcols, numrows;      /* Width and height in pixels of the PBM file */
-  int format;                /* Original image type before conversion to PBM */
-  bit *pbmrow;               /* One row of the PBM file */
-  uint32n pixeltally = 0;    /* Run length of the current color */
-  int row, col;              /* Row and column loop variables */
-  const char * pbmfilename;  /* Name of input file */
-
-  /* Parse the command line. */
-  pbm_init (&argc, argv);
-
-  if (argc-1 < 1)
-      pbmfilename = "-";
-  else if (argc-1 == 1)
-      pbmfilename = argv[1];
-  else
-      pm_error("Program takes at most 1 argument -- the input file name.  "
-               "You specified %d", argc-1);
-
-  pbmfile = pm_openr(pbmfilename);
-
-  /* Write an RLE header. */
-  pbm_readpbminit (pbmfile, &numcols, &numrows, &format);
-  fprintf (rlefile, "R4\n");
-  fprintf (rlefile, "%d %d\n", numcols, numrows);
-
-  /* Write the RLE data. */
-  pbmrow = pbm_allocrow (numcols);
-  for (row=0; row<numrows; row++) {
-    bit prevpixel;        /* Previous pixel seen */
-
-    pbm_readpbmrow (pbmfile, pbmrow, numcols, format);
-    prevpixel = PBM_WHITE;   /* Bitonal RLE rows always start with white */
-    pixeltally = 0;
-    for (col=0; col<numcols; col++) {
-      bit newpixel = pbmrow[col];      /* Current pixel color */
-
-      if (newpixel == prevpixel)
-        pixeltally++;
-      else {
-        write_rle (rlefile, pixeltally);
-        pixeltally = 1;
-        prevpixel = newpixel;
-      }
+main (int argc, const char * argv[]) {
+
+    FILE * const rlefile = stdout; /* Generated Bitonal RLE file */
+
+    FILE * pbmfile;          /* PBM file to convert */
+    int numcols, numrows;    /* Width and height in pixels of the PBM file */
+    int format;              /* Original image type before conversion to PBM */
+    bit * pbmrow;            /* One row of the PBM file */
+    unsigned int row;
+    const char * pbmfilename;  /* Name of input file */
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        pbmfilename = "-";
+    else if (argc-1 == 1)
+        pbmfilename = argv[1];
+    else
+        pm_error("Program takes at most 1 argument -- the input file name.  "
+                 "You specified %d", argc-1);
+
+    pbmfile = pm_openr(pbmfilename);
+
+    /* Write an RLE header. */
+    pbm_readpbminit(pbmfile, &numcols, &numrows, &format);
+    fprintf(rlefile, "R4\n");
+    fprintf(rlefile, "%d %d\n", numcols, numrows);
+
+    /* Write the RLE data. */
+    pbmrow = pbm_allocrow(numcols);
+    for (row = 0; row < numrows; ++row) {
+        unsigned int col;
+        uint32_t pixeltally;   /* Run length of the current color */
+        bit prevpixel;         /* Previous pixel seen */
+
+        pbm_readpbmrow(pbmfile, pbmrow, numcols, format);
+        prevpixel = PBM_WHITE;   /* Bitonal RLE rows always start with white */
+        pixeltally = 0;
+        for (col = 0; col < numcols; ++col) {
+            bit newpixel = pbmrow[col];      /* Current pixel color */
+
+            if (newpixel == prevpixel)
+                ++pixeltally;
+            else {
+                write_rle(rlefile, pixeltally);
+                pixeltally = 1;
+                prevpixel = newpixel;
+            }
+        }
+        write_rle(rlefile, pixeltally);
     }
-    write_rle (rlefile, pixeltally);
-  }
-
-  /* Finish up cleanly. */
-  pbm_freerow (pbmrow);
-  if (rlefile != stdout)
-    pm_close (rlefile);
-  if (pbmfile != stdin)
-    pm_close (pbmfile);
-  exit (0);
+
+    pbm_freerow(pbmrow);
+    if (rlefile != stdout)
+        pm_close(rlefile);
+    if (pbmfile != stdin)
+        pm_close(pbmfile);
+
+    return 0;
 }
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c
index f9f9bac3..8bb72662 100644
--- a/converter/ppm/ilbmtoppm.c
+++ b/converter/ppm/ilbmtoppm.c
@@ -1252,7 +1252,7 @@ dcol_to_ppm(FILE *         const ifP,
     unsigned int const greenplanes = dcol->g;
     unsigned int const blueplanes  = dcol->b;
     
-    int col, row, i;
+    int col, row;
     rawtype *Rrow, *Grow, *Brow;
     pixval maxval, redmaxval, greenmaxval, bluemaxval;
     pixval *redtable, *greentable, *bluetable;
@@ -1298,13 +1298,15 @@ dcol_to_ppm(FILE *         const ifP,
     MALLOCARRAY_NOFAIL(greentable, greenmaxval +1);
     MALLOCARRAY_NOFAIL(bluetable,  bluemaxval  +1);
 
-    for( i = 0; i <= redmaxval; i++ )
-        redtable[i] = (i * maxval + redmaxval/2)/redmaxval;
-    for( i = 0; i <= greenmaxval; i++ )
-        greentable[i] = (i * maxval + greenmaxval/2)/greenmaxval;
-    for( i = 0; i <= bluemaxval; i++ )
-        bluetable[i] = (i * maxval + bluemaxval/2)/bluemaxval;
-
+    {
+        unsigned int i;
+        for (i = 0; i <= redmaxval; ++i)
+            redtable[i] = ROUNDDIV(i * maxval, redmaxval);
+        for (i = 0; i <= greenmaxval; ++i)
+            greentable[i] = ROUNDDIV(i * maxval, greenmaxval);
+        for (i = 0; i <= bluemaxval; ++i)
+            bluetable[i] = ROUNDDIV(i * maxval, bluemaxval);
+    }
     if( transpName ) {
         MALLOCVAR_NOFAIL(transpColor);
         *transpColor = ppm_parsecolor(transpName, maxval);
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index 079f07ca..6f34dae4 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -727,43 +727,39 @@ load_fontdir(const char * const dirfile) {
    Load the font directory from file named 'dirfile'.  Add its contents
    to the global list of fonts 'fontlist'.
 -----------------------------------------------------------------------------*/
-    int retval;
-    FILE * fp;
+    FILE * ifP;
+    unsigned int nFont;
+    char line[1024]; 
 
-    fp = fopen(dirfile, "rb");
-    if (!fp)
-        retval =  -1;
-    else {
-        unsigned int nFont;
-        char line[1024]; 
-
-        nFont = 0;
-        while (fgets(line, 1024, fp) && nFont < INT_MAX) {
-            const char * token[10];
-            unsigned int nToken;
-
-            tokenize(line, token, ARRAY_SIZE(token), &nToken);
-
-            if (nToken == 0) {
-                /* blank line - ignore */
-            } else if (token[0][0] == '#') {
-                /* comment - ignore */
-            } else if (nToken != 4) {
-                /* Unrecognized format - ignore */
-            } else {
-                struct fontinfo * fontinfoP;
-
-                parseFontLine(token, &fontinfoP);
-
-                fontinfoP->next = 0;
-                *fontlist_ins = fontinfoP;
-                fontlist_ins = &fontinfoP->next;
-                ++nFont;
-            }
+    ifP = pm_openr(dirfile);
+
+    nFont = 0;
+    while (fgets(line, 1024, ifP) && nFont < INT_MAX) {
+        const char * token[10];
+        unsigned int nToken;
+
+        tokenize(line, token, ARRAY_SIZE(token), &nToken);
+
+        if (nToken == 0) {
+            /* blank line - ignore */
+        } else if (token[0][0] == '#') {
+            /* comment - ignore */
+        } else if (nToken != 4) {
+            /* Unrecognized format - ignore */
+        } else {
+            struct fontinfo * fontinfoP;
+
+            parseFontLine(token, &fontinfoP);
+
+            fontinfoP->next = 0;
+            *fontlist_ins = fontinfoP;
+            fontlist_ins = &fontinfoP->next;
+            ++nFont;
         }
-        retval = nFont;
     }
-    return retval;
+    pm_close(ifP);
+
+    return nFont;
 }
 
 
@@ -1112,7 +1108,7 @@ static pixval
 redepth(pixval const c,
         pixval const oldMaxval) {
     
-    return (c * PPM_MAXMAXVAL + oldMaxval / 2) / oldMaxval;
+    return ROUNDDIV(c * PPM_MAXMAXVAL, oldMaxval);
 }
 
 
diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c
index 9817f183..df859c84 100644
--- a/converter/ppm/ppmtoarbtxt.c
+++ b/converter/ppm/ppmtoarbtxt.c
@@ -341,9 +341,7 @@ read_skeleton(const char *   const filename,
     { if (slen > 0 && (skl[nskl] = save_bin_data(slen,line)) != NULL) ++nskl; \
       slen = 0; }
 
-    sklfile = fopen(filename,"r");
-    if (sklfile == NULL)
-        return -1;
+    sklfile = pm_openr(filename);
 
     /* Parse skeleton file */
     nskl = 0;  /* initial value */
diff --git a/converter/ppm/ppmtoilbm.c b/converter/ppm/ppmtoilbm.c
index c0d58edb..4a1b5cb7 100644
--- a/converter/ppm/ppmtoilbm.c
+++ b/converter/ppm/ppmtoilbm.c
@@ -433,14 +433,14 @@ compute_ham_cmap(cols, rows, maxval, maxcolors, colorsP, hbits)
                     tmp = hmap[i].b - b; dist += tmp * tmp;
 
                     if( dist <= maxdist ) {
-                        int sum = hmap[i].count + hmap[col].count;
-
-                        hmap[i].r = (hmap[i].r * hmap[i].count + 
-                                     r * hmap[col].count + sum/2)/sum;
-                        hmap[i].g = (hmap[i].g * hmap[i].count + 
-                                     g * hmap[col].count + sum/2)/sum;
-                        hmap[i].b = (hmap[i].b * hmap[i].count + 
-                                     b * hmap[col].count + sum/2)/sum;
+                        unsigned int sum = hmap[i].count + hmap[col].count;
+
+                        hmap[i].r = ROUNDDIV(hmap[i].r * hmap[i].count + 
+                                             r * hmap[col].count, sum);
+                        hmap[i].g = ROUNDDIV(hmap[i].g * hmap[i].count + 
+                                             g * hmap[col].count, sum);
+                        hmap[i].b = ROUNDDIV(hmap[i].b * hmap[i].count + 
+                                             b * hmap[col].count, sum);
                         hmap[i].count = sum;
 
                         hmap[col] = hmap[i];    /* temp store */
@@ -1776,12 +1776,12 @@ static int *
 make_val_table(oldmaxval, newmaxval)
     int oldmaxval, newmaxval;
 {
-    int i;
-    int *table;
+    unsigned int i;
+    int * table;
 
     MALLOCARRAY_NOFAIL(table, oldmaxval + 1);
-    for(i = 0; i <= oldmaxval; i++ )
-        table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
+    for (i = 0; i <= oldmaxval; ++i)
+        table[i] = ROUNDDIV(i * newmaxval, oldmaxval);
 
     return table;
 }
diff --git a/converter/ppm/ppmtompeg/headers/param.h b/converter/ppm/ppmtompeg/headers/param.h
index 31be61ee..c7f57b44 100644
--- a/converter/ppm/ppmtompeg/headers/param.h
+++ b/converter/ppm/ppmtompeg/headers/param.h
@@ -1,30 +1,4 @@
-/*===========================================================================*
- * param.h								     *
- *									     *
- *	reading the parameter file					     *
- *									     *
- *===========================================================================*/
-
-/*
- * Copyright (c) 1995 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
+/* COPYRIGHT information is at end of file */
 
 #include "pm_c_util.h"
 #include "ansi.h"
@@ -35,14 +9,21 @@
  * CONSTANTS *
  *===========*/
 
-#define MAX_MACHINES	    256
+#define MAX_MACHINES        256
 #ifndef MAXPATHLEN
 #define MAXPATHLEN  1024
 #endif
 
-#define	ENCODE_FRAMES	0
-#define COMBINE_GOPS	1
-#define COMBINE_FRAMES	2
+typedef enum {
+    ENCODE_FRAMES,
+        /* The regular, default function: Input is individual single unencoded
+           frames.
+        */
+    COMBINE_GOPS,
+        /* Input is pre-encoded GOPs */
+    COMBINE_FRAMES
+        /* Input is pre-encoded individual frames */
+} majorProgramFunction;
 
 
 struct params {
@@ -53,9 +34,9 @@ struct params {
 
 
 void
-ReadParamFile(const char *    const fileName, 
-              int             const function,
-              struct params * const paramP);
+ReadParamFile(const char *         const fileName, 
+              majorProgramFunction const function,
+              struct params *      const paramP);
 
 /*==================*
  * GLOBAL VARIABLES *
@@ -63,25 +44,47 @@ ReadParamFile(const char *    const fileName,
 
 /* All this stuff ought to be in a struct param instead */
 
-extern char	outputFileName[256];
-extern int	whichGOP;
+extern char outputFileName[256];
+extern int whichGOP;
 extern int numMachines;
-extern char	machineName[MAX_MACHINES][256];
-extern char	userName[MAX_MACHINES][256];
-extern char	executable[MAX_MACHINES][1024];
-extern char	remoteParamFile[MAX_MACHINES][1024];
-extern boolean	remote[MAX_MACHINES];
-extern char	currentPath[MAXPATHLEN];
-extern char	currentFramePath[MAXPATHLEN];
-extern char	currentGOPPath[MAXPATHLEN];
+extern char machineName[MAX_MACHINES][256];
+extern char userName[MAX_MACHINES][256];
+extern char executable[MAX_MACHINES][1024];
+extern char remoteParamFile[MAX_MACHINES][1024];
+extern boolean remote[MAX_MACHINES];
+extern char currentPath[MAXPATHLEN];
+extern char currentFramePath[MAXPATHLEN];
+extern char currentGOPPath[MAXPATHLEN];
 extern char inputConversion[1024];
 extern char yuvConversion[256];
-extern int  yuvWidth, yuvHeight;
-extern int  realWidth, realHeight;
+extern int yuvWidth, yuvHeight;
+extern int realWidth, realHeight;
 extern char ioConversion[1024];
 extern char slaveConversion[1024];
-extern FILE *bitRateFile;
+extern FILE * bitRateFile;
 extern boolean showBitRatePerFrame;
 extern boolean computeMVHist;
 extern const double VidRateNum[9];
 extern boolean keepTempFiles;
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c
index 502aee5b..bb5bc79a 100644
--- a/converter/ppm/ppmtompeg/param.c
+++ b/converter/ppm/ppmtompeg/param.c
@@ -934,26 +934,21 @@ processParamLine(char const input[],
 
 
 
-/*===========================================================================*
- *
- * ReadParamFile
- *
- *	read the parameter file
- *	function is ENCODE_FRAMES, COMBINE_GOPS, or COMBINE_FRAMES, and
- *	    will slightly modify the procedure's behavior as to what it
- *	    is looking for in the parameter file
- *
- * SIDE EFFECTS:    sets parameters accordingly, as well as machine info for
- *		    parallel execution and input file names
- *
- *===========================================================================*/
 void
-ReadParamFile(const char *    const fileName, 
-              int             const function,
-              struct params * const paramP) {
+ReadParamFile(const char *         const fileName, 
+              majorProgramFunction const function,
+              struct params *      const paramP) {
+/*----------------------------------------------------------------------------
+   Read the parameter file 'fileName' as *paramP.
 
-  FILE *fpointer;
-  char    buffer[256];
+   'function' slightly modifies our behavior as to what it is looking for
+   in the parameter file.
+
+   As a side effect, set machine info for parallel execution and input
+   file names
+-----------------------------------------------------------------------------*/
+  FILE * fpointer;
+  char buffer[256];
   bool yuvUsed;
   struct inputSource * inputSourceP;
       /* Contents of INPUT section */
diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
index f4473e07..f53ffea9 100644
--- a/converter/ppm/ppmtompeg/ppmtompeg.c
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -97,7 +97,7 @@ void init_fdct _ANSI_ARGS_((void));
 
 struct cmdlineInfo {
     bool         childProcess;
-    int          function;
+    majorProgramFunction function;
     const char * masterHostname;
     int          masterPortNumber;
     unsigned int outputFrames;
@@ -129,36 +129,33 @@ parseArgs(int     const argc,
     
     /* parse the arguments */
     idx = 1;
-    while ( idx < argc-1 ) {
-        if ( argv[idx][0] != '-' )
+    while (idx < argc-1) {
+        if (argv[idx][0] != '-')
             pm_error("argument '%s', which must be an option because "
                      "it is not the last argument, "
                      "does not start with '-'", argv[idx]);
 
-        if ( strcmp(argv[idx], "-stat") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        if (streq(argv[idx], "-stat")) {
+            if (idx+1 < argc-1) {
                 SetStatFileName(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -stat option");
-            }
-        } else if ( strcmp(argv[idx], "-gop") == 0 ) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || 
-                (cmdlineP->specificFrames))
+        } else if (streq(argv[idx], "-gop")) {
+            if (cmdlineP->function != ENCODE_FRAMES || 
+                cmdlineP->specificFrames)
                 pm_error("Invalid -gop option");
             
-            if ( idx+1 < argc-1 ) {
+            if (idx+1 < argc-1) {
                 whichGOP = atoi(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -gop option");
-            }
-        } else if ( strcmp(argv[idx], "-frames") == 0 ) {
-            if ( (cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ) {
+        } else if (streq(argv[idx], "-frames")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1)
                 pm_error("invalid -frames option");
-            }
 
-            if ( idx+2 < argc-1 ) {
+            if (idx+2 < argc-1) {
                 int const frameStart = atoi(argv[idx+1]);
                 int const frameEnd = atoi(argv[idx+2]);
 
@@ -176,23 +173,23 @@ parseArgs(int     const argc,
                 idx += 3;
             } else
                 pm_error("-frames needs to be followed by two values");
-        } else if (strcmp(argv[idx], "-combine_gops") == 0) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) || 
-                (cmdlineP->specificFrames)) {
+        } else if (streq(argv[idx], "-combine_gops")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1 || 
+                cmdlineP->specificFrames) {
                 pm_error("Invalid -combine_gops option");
             }
 
             cmdlineP->function = COMBINE_GOPS;
-            idx++;
-        } else if (strcmp(argv[idx], "-combine_frames") == 0) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ||
-                (cmdlineP->specificFrames))
+            ++idx;
+        } else if (streq(argv[idx], "-combine_frames")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1 ||
+                cmdlineP->specificFrames)
                 pm_error("Invalid -combine_frames option");
 
             cmdlineP->function = COMBINE_FRAMES;
-            idx++;
-        } else if ( strcmp(argv[idx], "-child") == 0 ) {
-            if ( idx+7 < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-child")) {
+            if (idx+7 < argc-1) {
                 int combinePortNumber;
                     /* This used to be important information, when the child
                        notified the combine server.  Now the master notifies
@@ -214,104 +211,94 @@ parseArgs(int     const argc,
 
             cmdlineP->childProcess = TRUE;
             idx += 8;
-        } else if ( strcmp(argv[idx], "-io_server") == 0 ) {
-            if ( idx+2 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-io_server")) {
+            if (idx+2 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-            } else {
+            } else
                 pm_error("Invalid -io_server option");
-            }
 
             ioServer = TRUE;
             idx += 3;
-        } else if ( strcmp(argv[idx], "-output_server") == 0 ) {
-            if ( idx+3 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-output_server")) {
+            if (idx+3 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-                cmdlineP->outputFrames = atoi(argv[idx+3]);
-            } else {
+                cmdlineP->outputFrames     = atoi(argv[idx+3]);
+            } else
                 pm_error("-output_server option requires 3 option values.  "
-                         "You specified %d", argc-1 - idx);
-            }
+                         "You specified %u", argc-1 - idx);
 
             outputServer = TRUE;
             idx += 4;
-        } else if ( strcmp(argv[idx], "-decode_server") == 0 ) {
-            if ( idx+3 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-decode_server")) {
+            if (idx+3 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-                cmdlineP->outputFrames = atoi(argv[idx+3]);
-            } else {
+                cmdlineP->outputFrames     = atoi(argv[idx+3]);
+            } else
                 pm_error("Invalid -decode_server option");
-            }
 
             cmdlineP->function = COMBINE_FRAMES;
             decodeServer = TRUE;
             idx += 4;
-        } else if ( strcmp(argv[idx], "-nice") == 0 ) {
+        } else if (streq(argv[idx], "-nice")) {
             niceProcesses = TRUE;
             idx++;
-        } else if ( strcmp(argv[idx], "-max_machines") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        } else if (streq(argv[idx], "-max_machines")) {
+            if (idx+1 < argc-1) {
                 cmdlineP->maxMachines = atoi(argv[idx+1]);
-            } else {
+            } else
                 pm_error("Invalid -max_machines option");
-            }
 
             idx += 2;
-        } else if ( strcmp(argv[idx], "-quiet") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        } else if (streq(argv[idx], "-quiet")) {
+            if (idx+1 < argc-1)
                 quietTime = atoi(argv[idx+1]);
-            } else {
+            else
                 pm_error("Invalid -quiet option");
-            }
 
             idx += 2;
-        } else if ( strcmp(argv[idx], "-realquiet") == 0 ) {
+        } else if (streq(argv[idx], "-realquiet")) {
             realQuiet = TRUE;
-            idx++;
-        } else if (( strcmp(argv[idx], "-float_dct") == 0 ) ||
-                   ( strcmp(argv[idx], "-float-dct") == 0 )) {
+            ++idx;
+        } else if (streq(argv[idx], "-float_dct") ||
+                   streq(argv[idx], "-float-dct")) {
             pureDCT = TRUE;
             init_idctref();
             init_fdct();
-            idx++;
-        } else if ( strcmp(argv[idx], "-no_frame_summary") == 0 ) {
-            if ( idx < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-no_frame_summary")) {
+            if (idx < argc-1)
                 noFrameSummaryOption = TRUE;
-            } else {
+            else
                 pm_error("Invalid -no_frame_summary option");
-            }
-
-            idx++;
-        } else if ( strcmp(argv[idx], "-snr") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-snr")) {
             printSNR = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-mse") == 0 ) {
-            printSNR =  printMSE = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-debug_sockets") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-mse")) {
+            printSNR = printMSE = TRUE;
+            ++idx;
+        } else if (streq(argv[idx], "-debug_sockets")) {
             debugSockets = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-debug_machines") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-debug_machines")) {
             debugMachines = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-bit_rate_info") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-bit_rate_info")) {
+            if (idx+1 < argc-1) {
                 bitRateInfoOption = TRUE;
                 SetBitRateFileName(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -bit_rate_info option");
-            }
-        } else if ( strcmp(argv[idx], "-mv_histogram") == 0 ) {
+        } else if (streq(argv[idx], "-mv_histogram")) {
             computeMVHist = TRUE;
-            idx++;
-        } else {
+            ++idx;
+        } else
             pm_error("Unrecognized option: '%s'", argv[idx]);
-        }
     }
-
     cmdlineP->paramFileName = argv[argc-1];
 }
 
@@ -685,8 +672,8 @@ main(int argc, char **argv) {
         DecodeServer(cmdline.outputFrames, outputFileName, 
                      cmdline.masterHostname, cmdline.masterPortNumber);
     } else {
-        if ((!cmdline.specificFrames) &&
-            ((numMachines == 0) || (cmdline.function != ENCODE_FRAMES)) ) {
+        if (!cmdline.specificFrames &&
+            (numMachines == 0 || cmdline.function != ENCODE_FRAMES) ) {
             ofP = fopen(outputFileName, "wb");
             if (ofP == NULL)
                 pm_error("Could not open output file!");
@@ -694,7 +681,7 @@ main(int argc, char **argv) {
             ofP = NULL;
         
         if (cmdline.function == ENCODE_FRAMES) {
-            if ((numMachines == 0) || (cmdline.specificFrames)) {
+            if (numMachines == 0 || cmdline.specificFrames) {
                 encodeFrames(params.inputSourceP,
                              cmdline.childProcess, 
                              cmdline.masterHostname, cmdline.masterPortNumber,
diff --git a/converter/ppm/ppmtoyuvsplit.c b/converter/ppm/ppmtoyuvsplit.c
index 2dddebfc..e4ffaa3a 100644
--- a/converter/ppm/ppmtoyuvsplit.c
+++ b/converter/ppm/ppmtoyuvsplit.c
@@ -4,7 +4,7 @@
 ** - basename.V : The Chrominance chunk V at 1/4
 ** The subsampled U and V values are made by arithmetic mean.
 **
-** If CCIR601 is defined, the produced YUV triples are scaled again
+** The produced YUV triples are scaled again
 ** to fit into the smaller range of values for this standard.
 **
 ** by A.Beck
@@ -20,12 +20,6 @@
 ** implied warranty.
 */
 
-/* Wether to create YUV in JFIF(JPEG) or CCIR.601(MPEG) scale */
-#define CCIR601
-
-/* Wether to use pm_close() or fake it -- don't ask me why */
-/* #define ORIGINAL */
-
 /* ALPHA Kludge by Franky */
 
 #ifdef __alpha
@@ -38,160 +32,151 @@
 #include "ppm.h"
 
 int
-main(argc, argv)
-char **argv;
-{
-        FILE *ifp,*vf,*uf,*yf;
-        pixel          *pixelrow1,*pixelrow2;
-        register pixel *pP1,*pP2;
-        int             rows, cols, format, row;
-        register int    col;
-        pixval          maxval;
-        myLONG u,v,y0,y1,y2,y3,u0,u1,u2,u3,v0,v1,v2,v3;
-        unsigned char  *y1buf,*y2buf,*ubuf,*vbuf;
-        char            ufname[256],vfname[256],yfname[256];
-
-
-        ppm_init(&argc, argv);
-
-        if ((argc>3)||(argc<2)) pm_usage("basename [ppmfile]");
-
-        if (argc == 3) ifp = pm_openr(argv[2]);
-        else ifp = stdin;
-
-        strcpy(ufname,argv[1]);
-        strcpy(vfname,argv[1]);
-        strcpy(yfname,argv[1]);
-
-        strcat(ufname,".U");
-        strcat(vfname,".V");
-        strcat(yfname,".Y");
-
-        uf = fopen(ufname,"wb");
-        vf = fopen(vfname,"wb");
-        yf = fopen(yfname,"wb");
-
-        if(!(uf && vf && yf)) {
-         perror("error opening output files");
-         exit(0);
-        }
-        ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
-
-        if(cols & 1) fprintf(stderr,
-                             "%s: Warning: odd columns count, exceed ignored\n",
-                             argv[0]);
-        if(rows & 1) fprintf(stderr,
-                             "%s: Warning: odd rows count, exceed ignored\n",
-                             argv[0]);
-
-        pixelrow1 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
-        pixelrow2 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
-
-        y1buf = (unsigned char *) pm_allocrow( cols, 1 );
-        y2buf = (unsigned char *) pm_allocrow( cols, 1 );
-        ubuf = (unsigned char *) pm_allocrow( cols, 1 );
-        vbuf = (unsigned char *) pm_allocrow( cols, 1 );
-
-        for (row = 0; row < (rows & ~1); row += 2) {
-                unsigned char *y1ptr,*y2ptr,*uptr,*vptr;
-
-                ppm_readppmrow(ifp, pixelrow1, cols, maxval, format);
-                ppm_readppmrow(ifp, pixelrow2, cols, maxval, format);
-
-                pP1 = pixelrow1; pP2 = pixelrow2;
-                y1ptr = y1buf; y2ptr = y2buf; vptr = vbuf; uptr = ubuf;
-
-                for (col = 0 ; col < (cols & ~1); col += 2) {
-                        pixval r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3;
-
-                        /* first pixel */
-                        r0 = PPM_GETR(*pP1);
-                        g0 = PPM_GETG(*pP1);
-                        b0 = PPM_GETB(*pP1);
-                        pP1++;
-                        /* 2nd pixel */
-                        r1 = PPM_GETR(*pP1);
-                        g1 = PPM_GETG(*pP1);
-                        b1 = PPM_GETB(*pP1);
-                        pP1++;
-                        /* 3rd pixel */
-                        r2 = PPM_GETR(*pP2);
-                        g2 = PPM_GETG(*pP2);
-                        b2 = PPM_GETB(*pP2);
-                        pP2++;
-                        /* 4th pixel */
-                        r3 = PPM_GETR(*pP2);
-                        g3 = PPM_GETG(*pP2);
-                        b3 = PPM_GETB(*pP2);
-                        pP2++;
-
-
-/* The JFIF RGB to YUV Matrix for $00010000 = 1.0
-
-[Y]   [19595   38469    7471][R]
-[U] = [-11056  -21712  32768][G]
-[V]   [32768   -27440  -5328][B]
+main(int argc, const char ** argv) {
+
+    FILE * ifP;
+    FILE *vf, *uf, *yf;
+    pixel *pixelrow1, *pixelrow2;
+    int rows, cols;
+    int format;
+    unsigned int row;
+    pixval maxval;
+    unsigned char *y1buf, *y2buf, *ubuf, *vbuf;
+    char ufname[256], vfname[256], yfname[256];
+
+    pm_proginit(&argc, argv);
+
+    if ((argc-1 > 2) || (argc-1 < 1))
+        pm_error("Wrong number of arguments: %u.  "
+                 "Arguments are basename for output files "
+                 "and optional input file name", argc-1);
+
+    if (argc-1 == 2)
+        ifP = pm_openr(argv[2]);
+    else
+        ifP = stdin;
+
+    strcpy(ufname,argv[1]);
+    strcpy(vfname,argv[1]);
+    strcpy(yfname,argv[1]);
+
+    strcat(ufname,".U");
+    strcat(vfname,".V");
+    strcat(yfname,".Y");
+
+    uf = pm_openw(ufname);
+    vf = pm_openw(vfname);
+    yf = pm_openw(yfname);
 
-*/
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
 
-                        y0 =  19595 * r0 + 38469 * g0 +  7471 * b0;
-                        u0 = -11056 * r0 - 21712 * g0 + 32768 * b0;
-                        v0 =  32768 * r0 - 27440 * g0 -  5328 * b0;
+    if (cols % 2 == 1)
+        pm_message("Warning: odd columns count %u, excess ignored", cols);
 
-                        y1 =  19595 * r1 + 38469 * g1 +  7471 * b1;
-                        u1 = -11056 * r1 - 21712 * g1 + 32768 * b1;
-                        v1 =  32768 * r1 - 27440 * g1 -  5328 * b1;
+    if (rows % 2 == 1)
+        pm_message("Warning: odd rows count %u, excess ignored", rows);
 
-                        y2 =  19595 * r2 + 38469 * g2 +  7471 * b2;
-                        u2 = -11056 * r2 - 21712 * g2 + 32768 * b2;
-                        v2 =  32768 * r2 - 27440 * g2 -  5328 * b2;
+    pixelrow1 = ((pixel*) pm_allocrow(cols, sizeof(pixel)));
+    pixelrow2 = ((pixel*) pm_allocrow(cols, sizeof(pixel)));
 
-                        y3 =  19595 * r3 + 38469 * g3 +  7471 * b3;
-                        u3 = -11056 * r3 - 21712 * g3 + 32768 * b3;
-                        v3 =  32768 * r3 - 27440 * g3 -  5328 * b3;
+    y1buf = (unsigned char *) pm_allocrow(cols, 1);
+    y2buf = (unsigned char *) pm_allocrow(cols, 1);
+    ubuf = (unsigned char *) pm_allocrow(cols, 1);
+    vbuf = (unsigned char *) pm_allocrow(cols, 1);
 
-                        /* mean the chroma for subsampling */
+    for (row = 0; row < (rows & ~1); row += 2) {
+        unsigned char *y1ptr, *y2ptr, *uptr, *vptr;
+        pixel *pP1, *pP2;
+        unsigned int col;
 
-                        u  = (u0+u1+u2+u3)>>2;
-                        v  = (v0+v1+v2+v3)>>2;
+        ppm_readppmrow(ifP, pixelrow1, cols, maxval, format);
+        ppm_readppmrow(ifP, pixelrow2, cols, maxval, format);
 
-#ifdef CCIR601
+        pP1 = &pixelrow1[0]; pP2 = &pixelrow2[0];
+        y1ptr = y1buf; y2ptr = y2buf; vptr = vbuf; uptr = ubuf;
 
-                        y0 = (y0 * 219)/255 + 1048576;
-                        y1 = (y1 * 219)/255 + 1048576;
-                        y2 = (y2 * 219)/255 + 1048576;
-                        y3 = (y3 * 219)/255 + 1048576;
+        for (col = 0 ; col < (cols & ~1); col += 2) {
+            pixval r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3;
+            myLONG u, v, y0, y1, y2, y3, u0, u1, u2, u3, v0, v1, v2, v3;
 
-                        u  = (u * 224)/255 ;
-                        v  = (v * 224)/255 ;
-#endif
+            /* first pixel */
+            r0 = PPM_GETR(*pP1);
+            g0 = PPM_GETG(*pP1);
+            b0 = PPM_GETB(*pP1);
+            pP1++;
+            /* 2nd pixel */
+            r1 = PPM_GETR(*pP1);
+            g1 = PPM_GETG(*pP1);
+            b1 = PPM_GETB(*pP1);
+            pP1++;
+            /* 3rd pixel */
+            r2 = PPM_GETR(*pP2);
+            g2 = PPM_GETG(*pP2);
+            b2 = PPM_GETB(*pP2);
+            pP2++;
+            /* 4th pixel */
+            r3 = PPM_GETR(*pP2);
+            g3 = PPM_GETG(*pP2);
+            b3 = PPM_GETB(*pP2);
+            pP2++;
 
 
-                        *y1ptr++  = (y0 >> 16) ;
-                        *y1ptr++  = (y1 >> 16) ;
-                        *y2ptr++  = (y2 >> 16) ;
-                        *y2ptr++  = (y3 >> 16) ;
+            /* The JFIF RGB to YUV Matrix for $00010000 = 1.0
 
+               [Y]   [19595   38469    7471][R]
+               [U] = [-11056  -21712  32768][G]
+               [V]   [32768   -27440  -5328][B]
 
-                        *uptr++   = (u >> 16)+128 ;
-                        *vptr++   = (v >> 16)+128 ;
+            */
 
-                }
-                fwrite(y1buf, (cols & ~1), 1, yf);
-                fwrite(y2buf, (cols & ~1), 1, yf);
-                fwrite(ubuf, cols/2, 1, uf);
-                fwrite(vbuf, cols/2, 1, vf);
-        }
+            y0 =  19595 * r0 + 38469 * g0 +  7471 * b0;
+            u0 = -11056 * r0 - 21712 * g0 + 32768 * b0;
+            v0 =  32768 * r0 - 27440 * g0 -  5328 * b0;
 
-/* I dunno why pm_close sees an error... get rid of it */
+            y1 =  19595 * r1 + 38469 * g1 +  7471 * b1;
+            u1 = -11056 * r1 - 21712 * g1 + 32768 * b1;
+            v1 =  32768 * r1 - 27440 * g1 -  5328 * b1;
 
-#ifdef ORIGINAL
-        pm_close(ifp);
-#else
-        if(ifp != stdin) fclose(ifp);
-#endif
-        fclose(yf);
-        fclose(uf);
-        fclose(vf);
-        exit(0);
+            y2 =  19595 * r2 + 38469 * g2 +  7471 * b2;
+            u2 = -11056 * r2 - 21712 * g2 + 32768 * b2;
+            v2 =  32768 * r2 - 27440 * g2 -  5328 * b2;
+
+            y3 =  19595 * r3 + 38469 * g3 +  7471 * b3;
+            u3 = -11056 * r3 - 21712 * g3 + 32768 * b3;
+            v3 =  32768 * r3 - 27440 * g3 -  5328 * b3;
+
+            /* mean the chroma for subsampling */
+
+            u  = (u0+u1+u2+u3)>>2;
+            v  = (v0+v1+v2+v3)>>2;
+
+            y0 = (y0 * 219)/255 + 1048576;
+            y1 = (y1 * 219)/255 + 1048576;
+            y2 = (y2 * 219)/255 + 1048576;
+            y3 = (y3 * 219)/255 + 1048576;
+
+            u  = (u * 224)/255 ;
+            v  = (v * 224)/255 ;
+
+            *y1ptr++  = (y0 >> 16) ;
+            *y1ptr++  = (y1 >> 16) ;
+            *y2ptr++  = (y2 >> 16) ;
+            *y2ptr++  = (y3 >> 16) ;
+
+
+            *uptr++   = (u >> 16)+128 ;
+            *vptr++   = (v >> 16)+128 ;
+
+        }
+        fwrite(y1buf, (cols & ~1), 1, yf);
+        fwrite(y2buf, (cols & ~1), 1, yf);
+        fwrite(ubuf, cols/2, 1, uf);
+        fwrite(vbuf, cols/2, 1, vf);
+    }
+
+    pm_close(ifP);
+    fclose(yf);
+    fclose(uf);
+    fclose(vf);
+    return 0;
 }