about summary refs log tree commit diff
path: root/converter/other
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-08-01 20:17:45 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-08-01 20:17:45 +0000
commitf5de3f8f879746d9c845573307666883d2760291 (patch)
treebcc07762d167c801c453d5d4138be6722ccb8e93 /converter/other
parent04300740c30a1b7a704ecdb4fba721ecd915520f (diff)
downloadnetpbm-mirror-f5de3f8f879746d9c845573307666883d2760291.tar.gz
netpbm-mirror-f5de3f8f879746d9c845573307666883d2760291.tar.xz
netpbm-mirror-f5de3f8f879746d9c845573307666883d2760291.zip
cleanup, make compile with libpng 1.4 beta
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@965 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other')
-rw-r--r--converter/other/pngtopam.c717
1 files changed, 419 insertions, 298 deletions
diff --git a/converter/other/pngtopam.c b/converter/other/pngtopam.c
index 563cab3c..67a83c1f 100644
--- a/converter/other/pngtopam.c
+++ b/converter/other/pngtopam.c
@@ -29,10 +29,6 @@
 #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 {
@@ -64,7 +60,6 @@ typedef struct {
 
 static png_uint_16 maxval;
 static bool verbose;
-static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
 
 
 static void
@@ -153,6 +148,212 @@ parseCommandLine(int                  argc,
 
 
 
+static void
+pngtopnmErrorHandler(png_structp     const png_ptr,
+                     png_const_charp const msg) {
+
+    jmp_buf * jmpbufP;
+
+    /* 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);
+
+    jmpbufP = png_get_error_ptr(png_ptr);
+
+    if (!jmpbufP) {
+        /* we are completely hosed now */
+        pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
+    }
+
+    longjmp(*jmpbufP, 1);
+}
+
+
+
+struct pngx {
+    png_structp png_ptr;
+    png_infop info_ptr;
+};
+
+
+
+static void
+pngx_createRead(struct pngx ** const pngxPP,
+                jmp_buf *      const jmpbufP) {
+
+    struct pngx * pngxP;
+
+    MALLOCVAR(pngxP);
+
+    if (!pngxP)
+        pm_error("Failed to allocate memory for PNG object");
+    else {
+        pngxP->png_ptr = png_create_read_struct(
+            PNG_LIBPNG_VER_STRING,
+            jmpbufP, pngtopnmErrorHandler, NULL);
+
+        if (!pngxP->png_ptr)
+            pm_error("cannot allocate main libpng structure (png_ptr)");
+        else {
+            pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr);
+
+            if (!pngxP->info_ptr)
+                pm_error("cannot allocate libpng info structure (info_ptr)");
+            else
+                *pngxPP = pngxP;
+        }
+    }
+}
+
+
+
+static void
+pngx_destroy(struct pngx * const pngxP) {
+
+    png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL);
+
+    free(pngxP);
+}
+
+
+
+static bool
+pngx_chunkIsPresent(struct pngx * const pngxP,
+                    uint32_t      const chunkType) {
+
+    return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType);
+}
+
+
+
+static void
+verifyFileIsPng(FILE *   const ifP,
+                size_t * const consumedByteCtP) {
+
+    unsigned char buffer[4];
+    size_t bytesRead;
+
+    bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+    if (bytesRead != sizeof(buffer))
+        pm_error("input file is empty or too short");
+
+    if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0)
+        pm_error("input file is not a PNG file "
+                 "(does not have the PNG signature in its first 4 bytes)");
+    else
+        *consumedByteCtP = bytesRead;
+}
+
+
+
+static unsigned int
+computePngLineSize(struct pngx * const pngxP) {
+
+    unsigned int const bytesPerSample =
+        pngxP->info_ptr->bit_depth == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngxP->info_ptr->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 < pngxP->info_ptr->width)
+        pm_error("Width %u of PNG is uncomputably large",
+                 (unsigned int)pngxP->info_ptr->width);
+       
+    return pngxP->info_ptr->width * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(struct pngx * const pngxP,
+               png_byte ***  const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngxP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngxP->info_ptr->height);
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate space for %u PNG raster rows",
+                 (unsigned int)pngxP->info_ptr->height);
+
+    for (row = 0; row < pngxP->info_ptr->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,
+              struct pngx * const pngxP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngxP->info_ptr->height; ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
+static void
+readPng(struct pngx * const pngxP,
+        FILE *        const ifP,
+        png_byte ***  const pngRasterP) {
+
+    size_t sigByteCt;
+    png_byte ** pngRaster;
+            
+    verifyFileIsPng(ifP, &sigByteCt);
+
+    /* Declare that we already read the signature bytes */
+    png_set_sig_bytes(pngxP->png_ptr, (int)sigByteCt);
+
+    png_init_io(pngxP->png_ptr, ifP);
+
+    png_read_info(pngxP->png_ptr, pngxP->info_ptr);
+
+    allocPngRaster(pngxP, &pngRaster);
+
+    if (pngxP->info_ptr->bit_depth < 8)
+        png_set_packing(pngxP->png_ptr);
+
+    png_read_image(pngxP->png_ptr, pngRaster);
+
+    png_read_end(pngxP->png_ptr, pngxP->info_ptr);
+
+    /* 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.
+    */
+
+    *pngRasterP = pngRaster;
+}
+
+
+
 static png_uint_16
 get_png_val(const png_byte ** const pp,
             int               const bit_depth) {
@@ -254,84 +455,80 @@ gamma_correct(png_uint_16 const v,
 
 
 
-static int iscolor (png_color c)
-{
-  return c.red != c.green || c.green != c.blue;
+static bool
+iscolor(png_color const 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 */
+
+
+static void
+saveText(struct pngx * const pngxP,
+         FILE *        const tfP) {
+
+    png_info * const info_ptr = pngxP->info_ptr;
+
+    unsigned int i;
+
+    for (i = 0 ; i < info_ptr->num_text; ++i) {
+        unsigned int j;
+        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);
+        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') {
+                unsigned int k;
+                for (k = 0; k < 16; ++k)
+                    putc(' ', tfP);
+            }
+        }
+        putc('\n', tfP);
     }
-    putc ((int)'\n', tfp);
-  }
 }
 
-static void show_time (png_info *info_ptr)
-{
+
+
+static void
+showTime(struct pngx * const pngxP) {
+
     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);
+    if (pngxP->info_ptr->valid & PNG_INFO_tIME) {
+        pm_message("modification time: %02d %s %d %02d:%02d:%02d",
+                   pngxP->info_ptr->mod_time.day,
+                   month[pngxP->info_ptr->mod_time.month],
+                   pngxP->info_ptr->mod_time.year,
+                   pngxP->info_ptr->mod_time.hour,
+                   pngxP->info_ptr->mod_time.minute,
+                   pngxP->info_ptr->mod_time.second);
+    }
 }
 
 
 
 static void
-dump_png_info(png_info *info_ptr) {
+dumpPngInfo(struct pngx * const pngxP) {
 
+    png_info * const info_ptr = pngxP->info_ptr;
     const char *type_string;
     const char *filter_string;
 
@@ -448,73 +645,27 @@ dump_png_info(png_info *info_ptr) {
 
 
 
-static unsigned int
-computePngLineSize(png_info * const pngInfoP) {
+static const png_color_16 *
+transColor(struct pngx * const pngxP) {
 
-    unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1;
+    png_bytep trans;
+    int numTrans;
+    png_color_16 * transColor;
 
-    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]);
+    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS));
+    
+    png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr,
+                 &trans, &numTrans, &transColor);
 
-    free(pngRaster);
+    return transColor;
 }
 
 
 
 static bool
-isTransparentColor(pngcolor   const color,
-                   png_info * const pngInfoP,
-                   double     const totalgamma) {
+isTransparentColor(pngcolor      const color,
+                   struct pngx * const pngxP,
+                   double        const totalgamma) {
 /*----------------------------------------------------------------------------
    Return TRUE iff pixels of color 'color' are supposed to be transparent
    everywhere they occur.  Assume it's an RGB image.
@@ -523,8 +674,8 @@ isTransparentColor(pngcolor   const color,
 -----------------------------------------------------------------------------*/
     bool retval;
 
-    if (pngInfoP->valid & PNG_INFO_tRNS) {
-        const png_color_16 * const transColorP = &pngInfoP->trans_values;
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        const png_color_16 * const transColorP = transColor(pngxP);
 
         /* It seems odd that libpng lets you get gamma-corrected pixel
            values, but not gamma-corrected transparency or background
@@ -540,7 +691,7 @@ isTransparentColor(pngcolor   const color,
            pixels, and just do it ourselves.
         */
     
-        switch (pngInfoP->color_type) {
+        switch (pngxP->info_ptr->color_type) {
         case PNG_COLOR_TYPE_GRAY:
             retval = color.r == gamma_correct(transColorP->gray, totalgamma);
             break;
@@ -558,37 +709,17 @@ isTransparentColor(pngcolor   const color,
 
 
 
-#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) {
+setupGammaCorrection(struct pngx * const pngxP,
+                     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;
+        if (pngxP->info_ptr->valid & PNG_INFO_gAMA)
+            imageGamma = pngxP->info_ptr->gamma;
         else {
             if (verbose)
                 pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
@@ -602,12 +733,12 @@ setupGammaCorrection(png_struct * const png_ptr,
                            "display gamma %4.2f.  No conversion.",
                            imageGamma, displaygamma);
         } else {
-            png_set_gamma(png_ptr, displaygamma, imageGamma);
+            png_set_gamma(pngxP->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;
+            pngxP->info_ptr->valid &= ~PNG_INFO_sBIT;
             if (verbose)
                 pm_message("image gamma is %4.2f, "
                            "converted for display gamma of %4.2f",
@@ -619,20 +750,20 @@ setupGammaCorrection(png_struct * const png_ptr,
 
 
 static bool
-paletteHasPartialTransparency(png_info * const info_ptr) {
+paletteHasPartialTransparency(struct pngx * const pngxP) {
 
     bool retval;
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-        if (info_ptr->valid & PNG_INFO_tRNS) {
+    if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (pngxP->info_ptr->valid & PNG_INFO_tRNS) {
             bool foundGray;
             unsigned int i;
             
             for (i = 0, foundGray = FALSE;
-                 i < info_ptr->num_trans && !foundGray;
+                 i < pngxP->info_ptr->num_trans && !foundGray;
                  ++i) {
-                if (info_ptr->trans[i] != 0 &&
-                    info_ptr->trans[i] != maxval) {
+                if (pngxP->info_ptr->trans[i] != 0 &&
+                    pngxP->info_ptr->trans[i] != maxval) {
                     foundGray = TRUE;
                 }
             }
@@ -648,9 +779,11 @@ paletteHasPartialTransparency(png_info * const info_ptr) {
 
 
 static void
-getComponentSbitFg(png_info * const pngInfoP,
-                   png_byte * const fgSbitP,
-                   bool *     const notUniformP) {
+getComponentSbitFg(struct pngx * const pngxP,
+                   png_byte *    const fgSbitP,
+                   bool *        const notUniformP) {
+
+    png_info * const pngInfoP = pngxP->info_ptr;
 
     if (pngInfoP->color_type == PNG_COLOR_TYPE_RGB ||
         pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
@@ -671,7 +804,7 @@ getComponentSbitFg(png_info * const pngInfoP,
 
 
 static void
-getComponentSbit(png_info *          const pngInfoP,
+getComponentSbit(struct pngx *       const pngxP,
                  enum alpha_handling const alphaHandling,
                  png_byte *          const componentSbitP,
                  bool *              const notUniformP) {
@@ -683,26 +816,26 @@ getComponentSbit(png_info *          const pngInfoP,
            the alpha Sbit
         */
         *notUniformP = false;
-        *componentSbitP = pngInfoP->sig_bit.alpha;
+        *componentSbitP = pngxP->info_ptr->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);
+        getComponentSbitFg(pngxP, componentSbitP, notUniformP);
         break;
     case ALPHA_IN: {
         /* We care about both the foreground and the alpha */
         bool fgNotUniform;
         png_byte fgSbit;
         
-        getComponentSbitFg(pngInfoP, &fgSbit, &fgNotUniform);
+        getComponentSbitFg(pngxP, &fgSbit, &fgNotUniform);
 
         if (fgNotUniform)
             *notUniformP = true;
         else {
-            if (fgSbit == pngInfoP->sig_bit.alpha) {
+            if (fgSbit == pngxP->info_ptr->sig_bit.alpha) {
                 *notUniformP    = false;
                 *componentSbitP = fgSbit;
             } else
@@ -715,8 +848,8 @@ getComponentSbit(png_info *          const pngInfoP,
                  
 
 static void
-shiftPalette(png_info *   const pngInfoP,
-             unsigned int const shift) {
+shiftPalette(struct pngx * const pngxP,
+             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.
@@ -729,10 +862,10 @@ shiftPalette(png_info *   const pngInfoP,
     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);
+        for (i = 0; i < pngxP->info_ptr->num_palette; ++i) {
+            pngxP->info_ptr->palette[i].red   >>= (8 - shift);
+            pngxP->info_ptr->palette[i].green >>= (8 - shift);
+            pngxP->info_ptr->palette[i].blue  >>= (8 - shift);
         }
     }
 }
@@ -740,12 +873,11 @@ shiftPalette(png_info *   const pngInfoP,
 
 
 static void
-computeMaxvalFromSbit(png_struct *        const pngP,
-                      png_info *          const pngInfoP,
+computeMaxvalFromSbit(struct pngx *       const pngxP,
                       enum alpha_handling const alphaHandling,
                       png_uint_16 *       const maxvalP,
                       bool *              const succeededP,
-                      int *               const errorlevelP) {
+                      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,
@@ -766,37 +898,38 @@ computeMaxvalFromSbit(png_struct *        const pngP,
            Meaningless if they aren't all the same (i.e. 'notUniform')
         */
 
-    getComponentSbit(pngInfoP, alphaHandling, &componentSigBit, &notUniform);
+    getComponentSbit(pngxP, 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);
+        pm_message("writing file with %u bit resolution",
+                   pngxP->info_ptr->bit_depth);
         *succeededP = false;
-        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+        *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;
+        *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)))
+            (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+             pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+             paletteHasPartialTransparency(pngxP)))
             *succeededP = false;
         else {
-            if (componentSigBit < pngInfoP->bit_depth) {
+            if (componentSigBit < pngxP->info_ptr->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);
+                if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+                    shiftPalette(pngxP, componentSigBit);
                 else
-                    png_set_shift(pngP, &pngInfoP->sig_bit);
+                    png_set_shift(pngxP->png_ptr, &pngxP->info_ptr->sig_bit);
             } else
                 *succeededP = false;
         }
@@ -806,25 +939,26 @@ computeMaxvalFromSbit(png_struct *        const pngP,
 
 
 static void
-setupSignificantBits(png_struct *        const pngP,
-                     png_info *          const pngInfoP,
+setupSignificantBits(struct pngx *       const pngxP,
                      enum alpha_handling const alphaHandling,
                      png_uint_16 *       const maxvalP,
-                     int *               const errorlevelP) {
+                     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).
+  described by *pngxP, 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.
+  Also set up *pngxP for the corresponding significant bits.
 -----------------------------------------------------------------------------*/
+    png_info * const pngInfoP = pngxP->info_ptr;
+
     bool gotItFromSbit;
     
     if (pngInfoP->valid & PNG_INFO_sBIT)
-        computeMaxvalFromSbit(pngP, pngInfoP, alphaHandling,
-                              maxvalP, &gotItFromSbit, errorlevelP);
+        computeMaxvalFromSbit(pngxP, alphaHandling,
+                              maxvalP, &gotItFromSbit, errorLevelP);
     else
         gotItFromSbit = false;
 
@@ -837,7 +971,7 @@ setupSignificantBits(png_struct *        const pngP,
                        is plenty
                     */
                     *maxvalP = 1;
-                else if (paletteHasPartialTransparency(pngInfoP))
+                else if (paletteHasPartialTransparency(pngxP))
                     /* Use same maxval as PNG transparency palette for
                        simplicity
                     */
@@ -857,22 +991,22 @@ setupSignificantBits(png_struct *        const pngP,
 
 
 static bool
-imageHasColor(png_info * const info_ptr) {
+imageHasColor(struct pngx * const pngxP) {
 
     bool retval;
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
 
         retval = FALSE;
-    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+    else if (pngxP->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 < pngxP->info_ptr->num_palette && !foundColor;
              ++i) {
-            if (iscolor(info_ptr->palette[i]))
+            if (iscolor(pngxP->info_ptr->palette[i]))
                 foundColor = TRUE;
         }
         retval = foundColor;
@@ -885,7 +1019,7 @@ imageHasColor(png_info * const info_ptr) {
 
 
 static void
-determineOutputType(png_info *          const pngInfoP,
+determineOutputType(struct pngx *       const pngxP,
                     enum alpha_handling const alphaHandling,
                     pngcolor            const bgColor,
                     xelval              const maxval,
@@ -900,7 +1034,7 @@ determineOutputType(png_info *          const pngInfoP,
     } else {            
         /* The output is a normal Netpbm image */
         bool const outputIsColor =
-            imageHasColor(pngInfoP) || !isGrayscale(bgColor);
+            imageHasColor(pngxP) || !isGrayscale(bgColor);
 
         if (alphaHandling == ALPHA_IN) {
             *formatP = PAM_FORMAT;
@@ -926,11 +1060,11 @@ determineOutputType(png_info *          const pngInfoP,
 
 
 static void
-getBackgroundColor(png_info *   const info_ptr,
-                   const char * const requestedColor,
-                   float        const totalgamma,
-                   xelval       const maxval,
-                   pngcolor *   const bgColorP) {
+getBackgroundColor(struct pngx * const pngxP,
+                   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.
@@ -948,19 +1082,19 @@ getBackgroundColor(png_info *   const info_ptr,
         bgColorP->g = PPM_GETG(backcolor);
         bgColorP->b = PPM_GETB(backcolor);
 
-    } else if (info_ptr->valid & PNG_INFO_bKGD) {
+    } else if (pngxP->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) {
+        switch (pngxP->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);
+                gamma_correct(pngxP->info_ptr->background.gray, totalgamma);
             break;
         case PNG_COLOR_TYPE_PALETTE: {
             png_color const rawBgcolor = 
-                info_ptr->palette[info_ptr->background.index];
+                pngxP->info_ptr->palette[pngxP->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);
@@ -968,7 +1102,7 @@ getBackgroundColor(png_info *   const info_ptr,
         break;
         case PNG_COLOR_TYPE_RGB:
         case PNG_COLOR_TYPE_RGB_ALPHA: {
-            png_color_16 const rawBgcolor = info_ptr->background;
+            png_color_16 const rawBgcolor = pngxP->info_ptr->background;
             
             bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
             bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
@@ -983,14 +1117,35 @@ getBackgroundColor(png_info *   const info_ptr,
 
 
 
-#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth)
+static void
+warnNonsquarePixels(struct pngx * const pngxP,
+                    int *         const errorLevelP) {
+
+    if (pngxP->info_ptr->valid & PNG_INFO_pHYs) {
+        float const r =
+            (float)pngxP->info_ptr->x_pixels_per_unit /
+            pngxP->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;
+        }
+    }
+}
+
+
+
+#define GET_PNG_VAL(p) get_png_val(&(p), pngxP->info_ptr->bit_depth)
 
 
 
 static void
 makeTupleRow(const struct pam *  const pamP,
              const tuple *       const tuplerow,
-             png_info *          const pngInfoP,
+             struct pngx *       const pngxP,
              const png_byte *    const pngRasterRow,
              pngcolor            const bgColor,
              enum alpha_handling const alphaHandling,
@@ -1000,13 +1155,13 @@ makeTupleRow(const struct pam *  const pamP,
     unsigned int col;
 
     pngPixelP = &pngRasterRow[0];  /* initial value */
-    for (col = 0; col < pngInfoP->width; ++col) {
-        switch (pngInfoP->color_type) {
+    for (col = 0; col < pngxP->info_ptr->width; ++col) {
+        switch (pngxP->info_ptr->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) ?
+                   isTransparentColor(fgColor, pngxP, totalgamma) ?
                    0 : maxval);
         }
         break;
@@ -1024,7 +1179,7 @@ makeTupleRow(const struct pam *  const pamP,
 
         case PNG_COLOR_TYPE_PALETTE: {
             png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
-            png_color   const paletteColor = pngInfoP->palette[index];
+            png_color   const paletteColor = pngxP->info_ptr->palette[index];
 
             pngcolor fgColor;
 
@@ -1033,9 +1188,9 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.b = paletteColor.blue;
 
             setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
-                     (pngInfoP->valid & PNG_INFO_tRNS) &&
-                     index < pngInfoP->num_trans ?
-                     pngInfoP->trans[index] : maxval);
+                     (pngxP->info_ptr->valid & PNG_INFO_tRNS) &&
+                     index < pngxP->info_ptr->num_trans ?
+                     pngxP->info_ptr->trans[index] : maxval);
         }
         break;
                 
@@ -1046,7 +1201,7 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.g = GET_PNG_VAL(pngPixelP);
             fgColor.b = GET_PNG_VAL(pngPixelP);
             setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
-                     isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                     isTransparentColor(fgColor, pngxP, totalgamma) ?
                      0 : maxval);
         }
         break;
@@ -1065,7 +1220,8 @@ makeTupleRow(const struct pam *  const pamP,
         break;
 
         default:
-            pm_error("unknown PNG color type: %d", pngInfoP->color_type);
+            pm_error("unknown PNG color type: %d",
+                     pngxP->info_ptr->color_type);
         }
     }
 }
@@ -1099,15 +1255,15 @@ reportOutputFormat(const struct pam * const pamP) {
 
 static void
 writeNetpbm(struct pam *        const pamP,
-            png_info *          const pngInfoP,
+            struct pngx *       const pngxP,
             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.
+   'alphaHandling' that is in the PNG image described by *pngxP and
+   pngRaster[][].
 
    *pamP describes the required output image and is consistent with
    *pngInfoP.
@@ -1125,8 +1281,8 @@ writeNetpbm(struct pam *        const pamP,
 
     tuplerow = pnm_allocpamrow(pamP);
 
-    for (row = 0; row < pngInfoP->height; ++row) {
-        makeTupleRow(pamP, tuplerow, pngInfoP, pngRaster[row], bgColor,
+    for (row = 0; row < pngxP->info_ptr->height; ++row) {
+        makeTupleRow(pamP, tuplerow, pngxP, pngRaster[row], bgColor,
                      alphaHandling, totalgamma);
 
         pnm_writepamrow(pamP, tuplerow);
@@ -1137,97 +1293,62 @@ writeNetpbm(struct pam *        const pamP,
 
 
 static void 
-convertpng(FILE *             const ifp, 
-           FILE *             const tfp, 
+convertpng(FILE *             const ifP, 
+           FILE *             const tfP, 
            struct cmdlineInfo const cmdline,
-           int *              const errorlevelP) {
+           int *              const errorLevelP) {
 
-    png_struct * png_ptr;
-    png_info * info_ptr;
-    png_byte ** png_image;
+    png_byte ** pngRaster;
     pngcolor bgColor;
     float totalgamma;
     struct pam pam;
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
 
-    *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");
+    *errorLevelP = 0;
 
-    if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf))
+    if (setjmp(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);
+    pngx_createRead(&pngxP, &jmpbuf);
 
-    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);
+    readPng(pngxP, ifP, &pngRaster);
 
     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);
+        dumpPngInfo(pngxP);
 
     if (cmdline.time)
-        show_time(info_ptr);
-    if (tfp)
-        save_text(info_ptr, tfp);
+        showTime(pngxP);
+    if (tfP)
+        saveText(pngxP, 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;
-        }
-    }
+    warnNonsquarePixels(pngxP, errorLevelP);
+
+    setupGammaCorrection(pngxP, cmdline.gamma, &totalgamma);
+
+    setupSignificantBits(pngxP, cmdline.alpha, &maxval, errorLevelP);
 
+    getBackgroundColor(pngxP, cmdline.background, totalgamma, maxval,
+                         &bgColor);
+  
     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.height      = pngxP->info_ptr->height;
+    pam.width       = pngxP->info_ptr->width;
     pam.maxval      = maxval;
 
-    determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval,
+    determineOutputType(pngxP, cmdline.alpha, bgColor, maxval,
                         &pam.format, &pam.depth, pam.tuple_type);
 
-    writeNetpbm(&pam, info_ptr, png_image, bgColor, cmdline.alpha, totalgamma);
+    writeNetpbm(&pam, pngxP, pngRaster, bgColor, cmdline.alpha, totalgamma);
 
     fflush(stdout);
 
-    freePngRaster(png_image, info_ptr);
+    freePngRaster(pngRaster, pngxP);
 
-    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    pngx_destroy(pngxP);
 }
 
 
@@ -1238,7 +1359,7 @@ main(int argc, const char *argv[]) {
     struct cmdlineInfo cmdline;
     FILE * ifP;
     FILE * tfP;
-    int errorlevel;
+    int errorLevel;
 
     pm_proginit(&argc, argv);
 
@@ -1253,7 +1374,7 @@ main(int argc, const char *argv[]) {
     else
         tfP = NULL;
 
-    convertpng(ifP, tfP, cmdline, &errorlevel);
+    convertpng(ifP, tfP, cmdline, &errorLevel);
 
     if (tfP)
         pm_close(tfP);
@@ -1261,5 +1382,5 @@ main(int argc, const char *argv[]) {
     pm_close(ifP);
     pm_close(stdout);
 
-    return errorlevel;
+    return errorLevel;
 }