Imported from libpng-0.96.tar
diff --git a/CHANGES b/CHANGES
index 76e4d5f..11f03a4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -37,7 +37,7 @@
    finished dithering and other stuff
    added test program
    changed name from pnglib to libpng
-version 0.71
+version 0.71 [June, 1995]
    changed pngtest.png for zlib 0.93
    fixed error in libpng.txt and example.c
 version 0.8
@@ -56,26 +56,28 @@
    enabled png_set_shift to work with paletted images on read
    added png_read_update_info() - updates info structure with
       transformations
-version 0.81
+version 0.81 [August, 1995]
    incorporated Tim Wegner's medium model code (thanks, Tim)
-version 0.85
-   added more medium model code (almost everythings a far)
+version 0.82 [September, 1995]
+   [unspecified changes]
+version 0.85 [December, 1995]
+   added more medium model code (almost everything's a far)
    added i/o, error, and memory callback functions
    fixed some bugs (16 bit, 4 bit interlaced, etc.)
    added first run progressive reader (barely tested)
-version 0.86
+version 0.86 [January, 1996]
    fixed bugs
    improved documentation
-version 0.87
+version 0.87 [January, 1996]
    fixed medium model bugs
    fixed other bugs introduced in 0.85 and 0.86
    added some minor documentation
-version 0.88
+version 0.88 [January, 1996]
    fixed progressive bugs
    replaced tabs with spaces
    cleaned up documentation
    added callbacks for read/write and warning/error functions
-version 0.89 
+version 0.89 [July, 1996]
    added new initialization API to make libpng work better with shared libs
       we now have png_create_read_struct(), png_create_write_struct(),
       png_create_info_struct(), png_destroy_read_struct(), and
@@ -101,14 +103,14 @@
       into a binary when only reading or writing functionality is used
    new pngtest image also has interlacing and zTXt
    updated documentation to reflect new API
-version 0.90
+version 0.90 [January, 1997]
    made CRC errors/warnings on critical and ancillary chunks configurable
    libpng will use the zlib CRC routines by (compile-time) default
    changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner)
    added external C++ wrapper statements to png.h (Gilles Dauphin)
    allow PNG file to be read when some or all of file signature has already
-      been read from the beginning of the stream (this affects the size of
-      info_struct and invalidates all programs that use a shared libpng)
+      been read from the beginning of the stream.  ****This affects the size
+      of info_struct and invalidates all programs that use a shared libpng****
    fixed png_filler() declarations
    fixed? background color conversions
    fixed order of error function pointers to match documentation
@@ -120,3 +122,48 @@
         routines can determine if the chunk is in the right place
       - all chunk handling routines have the same prototypes, so we will
         be able to handle all chunks via a callback mechanism
+   try to fix Linux "setjmp" buffer size problems
+version 0.95 [March, 1997]
+   fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never
+   fixed bug in PNG file signature compares when start != 0
+   changed parameter type of png_set_filler(...filler...) from png_byte
+      to png_uint_32
+   added test for MACOS to ensure that both math.h and fp.h are not #included
+   added macros for libpng to be compiled as a Windows DLL (Andreas Kupries)
+   added "packswap" transformation, which changes the endianness of
+      packed-pixel bytes (Kevin Bracey)
+   added "strip_alpha" transformation, which removes the alpha channel of
+      input images without using it (not neccesarily a good idea)
+   added "swap_alpha" transformation, which puts the alpha channel in front
+      of the color bytes instead of after
+   removed all implicit variable tests which assume NULL == 0 (I think)
+   changed several variables to "png_size_t" to show 16/32-bit limitations
+   added new pCAL chunk read/write support
+   added experimental filter selection weighting (Greg Roelofs)
+   removed old png_set_rgbx() and png_set_xrgb() functions that have been
+      obsolete for about 2 years now (use png_set_filler() instead)
+   added macros to read 16- and 32-bit ints directly from buffer, to be
+      used only on those systems that support it (namely PowerPC and 680x0)
+      With some testing, this may become the default for MACOS/PPC systems.
+   only calculate CRC on data if we are going to use it
+   added macros for zTXt compression type PNG_zTXt_COMPRESSION_???
+   added macros for simple libpng debugging output selectable at compile time
+   removed PNG_READ_END_MODE in progressive reader (Smarasderagd)
+   more description of info_struct in libpng.txt and png.h
+   more instructions in example.c
+   more chunk types tested in pngtest.c
+   renamed pngrcb.c to pngset.c, and all png_read_<chunk> functions to be
+      png_set_<chunk>.  We now have corresponding png_get_<chunk>
+      functions in pngget.c to get infomation in info_ptr.  This isolates
+      the application from the internal organization of png_info_struct
+      (good for shared library implementations).
+version 0.96 [May, 1997]
+   fixed serious bug with < 8bpp images introduced in 0.95
+   fixed 256-color transparency bug (Greg Roelofs)
+   fixed up documentation (Greg Roelofs, Laszlo Nyul)
+   fixed "error" in pngconf.h for Linux setjmp() behaviour
+   fixed DOS medium model support (Tim Wegner)
+   fixed png_check_keyword() for case with error in static string text
+   added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul)
+   added typecasts to quiet compiler errors
+   added more debugging info
diff --git a/README b/README
index 000e572..9147674 100644
--- a/README
+++ b/README
@@ -1,55 +1,54 @@
-readme.txt - for libpng 0.90
+README for libpng 0.96
 
-This is the fourth beta version of libpng 1.0.  The changes from
-libpng-0.89 include bug fixes, a C++ wrapper for png.h, some
-additions to the API, as well as internal changes to the library.
+This is the sixth (and hopefully last) beta release of libpng 1.0.
+The changes from libpng-0.90 include bug fixes, a C++ wrapper for
+png.h, some additions to the API, as well as internal changes to
+the library.  See "CHANGES" for a detailed list of differences.
 
-**
-Note that some of the changes to the png_info structure render
-this version of the library binary incompatible with libpng-0.89
-if you are using a shared library.  Re-compiling the application
-should be enough to remove this problem.
-**
+****
+Note that some of the changes to the png_info structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library.  The type of the
+"filler" parameter for png_set_filler() has changed from png_byte to
+png_uint_32, which will affect shared-library applications which use
+this function.
 
-The additions to 0.89 include the ability to read from a PNG stream
-which has had some (or all) of the signature bytes read by the
-calling application.  This also allows the reading of embedded PNG
-streams that do not have the PNG file signature.  As well, it is
-now possible to set the library action on the detection of chunk
-CRC errors.  It is possible to set different actions based on
-whether the error occurred in a critical or an ancillary chunk.
+To avoid problems with changes to the internals of png_info_struct,
+new APIs have been made available in 0.95 to avoid direct application
+access to info_ptr.  These functions are the png_set_<chunk> and
+png_get_<chunk> functions.  These functions should be used when
+accessing/storing the info_struct data, rather than manipulating it
+directly, to avoid such problems in the future.
+****
 
-The callback functions for the error/warning messages have changed
-since the 0.88 release because their implementation was broken,
-and it was thought best to change the API itself (which was only
-introduced in libpng-0.88 itself) to alert the user to the change,
-rather than mislead the user into thinking their application was
-OK after re-compiling.  This means that calls to png_set_message_fn()
-no longer exist, because the previously suggested method of calling
-them before png_read_init() or png_write_init() is now ineffective.
+Additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the info struct.
+Experimental functions include the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16->8 bit color
+conversion.
 
-The preferred method of setting the error and warning callbacks
-has been incorporated into the allocation of the png_struct and
-info_struct itself, which allow them to be safely used during the
-initialization of the structure, as well as to keep the size of
-the png_struct internal to the library, rather than at compile time
-of the application.  This will hopefully remove any problems with
-dynamically linked libraries, and should be considered the preferred
-method of creating these structures, although the previous
-initialization API is still available for compatibility.  See libpng.txt
-for more information on the new API.
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application.  This also allows the reading of embedded PNG streams that
+do not have the PNG file signature.  As well, it is now possible to set
+the library action on the detection of chunk CRC errors.  It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
 
 The changes made to the library, and bugs fixed are based on discussions
 on the PNG implementation mailing list <png-implement@dworking.wustl.edu>
 and not on material submitted to Guy.
 
 For a detailed description on using libpng, read libpng.txt.  For
-usage information and restrictions (what little they are) on libpng,
-see png.h.  For a description on using zlib (the compression library
-used by libpng) and zlib's restrictions, see zlib.h
+examples of libpng in a program, see example.c and pngtest.c.  For usage
+information and restrictions (what little they are) on libpng, see
+png.h.  For a description on using zlib (the compression library used by
+libpng) and zlib's restrictions, see zlib.h
 
-I have included a general makefile, as well as several machine and compiler
-specific ones, but you may have to modify one for your own needs.
+I have included a general makefile, as well as several machine and
+compiler specific ones, but you may have to modify one for your own needs.
 
 You should use zlib 1.0.4 or later to run this, but it MAY work with
 versions as old as zlib 0.95.  Even so, there are bugs in older zlib
@@ -113,7 +112,7 @@
 
 Files in this distribution:
 
-      CHANGES.txt   =>  Description of changes between libpng versions
+      CHANGES       =>  Description of changes between libpng versions
       README        =>  This file
       TODO          =>  Things not implemented in the current library
       ansi2knr.c    =>  Converts files to K&R style function declarations
@@ -121,7 +120,7 @@
       descrip.mms   =>  VMS project file
       example.c     =>  Example code for using libpng functions
       libpng.txt    =>  Description of libpng and its functions
-      makefile      =>  Defualt makefile
+      makefile      =>  Default Unixish makefile
       makefile.aco  =>  ACORN makefile
       makefile.ama  =>  Amiga makefile
       makefile.atr  =>  Atari makefile
@@ -140,11 +139,11 @@
       pngerror.c    =>  Error/warning message I/O functions
       pngmem.c      =>  Memory handling functions
       pngpread.c    =>  Progressive reading functions
-      pngrcb.c      =>  Read callback (data handling) low-level functions
       pngread.c     =>  Read data/helper high-level functions
       pngrio.c      =>  Lowest-level data read I/O functions
       pngrtran.c    =>  Read data transformation functions
       pngrutil.c    =>  Read data utility functions
+      pngset.c      =>  Functions for storing data into the info_struct
       pngtest.c     =>  Library test program
       pngtest.png   =>  Library test sample image
       pngtrans.c    =>  Common data transformation functions
@@ -156,13 +155,12 @@
 Good luck, and happy coding.
 
 -Andreas Eric Dilger
- University of Calgary
  Internet: adilger@enel.ucalgary.ca
- Web: www-mddsp.enel.ucalgary.ca/People/adilger/
+ Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/
 
 -Guy Eric Schalnat
  Group 42, Inc.
  Internet: schalnat@group42.com
  CompuServe: 75501,1625
- Web: www.group42.com
+ Web: http://www.group42.com/
 
diff --git a/TODO b/TODO
index fedeb0f..605e591 100644
--- a/TODO
+++ b/TODO
@@ -1,23 +1,19 @@
 pngtodo.txt - list of things to do for libpng
 
-for 0.9
-   improved dithering
-   final bug fixes
-   cHRM transformation
-   better documentation
-   multi-lingual message support
-
-after 1.0
-   overlaying one image on top of another
-   optional palette creation
-   histogram creation
-   text conversion between different code types
-   support for application-defined chunk handlers
-   support for embedded PNG usage (MNG)
-   pull writer
-   better dithering
-   keep up with public chunks
-   better filter selection (counting huffman bits?  filter type inertia?)
-   C++ wrapper
-   other languages (pascal, for one)
-   comments of > 64K for DOS
+add "grayscale->palette" transformation and "palette->grayscale" detection
+improved dithering
+multi-lingual error and warning message support
+cHRM transformation
+sRGB chunk handling
+man pages for function calls
+high-level API for reading images
+final bug fixes
+better documentation
+better filter selection
+   (counting huffman bits/precompression?  filter inertia?  filter costs?)
+optional palette creation
+histogram creation
+support for application-defined chunk handlers
+keep up with public chunks
+better C++ wrapper/full C++ implementation?
+text conversion between different code pages (Latin-1 -> Mac and DOS)
diff --git a/descrip.mms b/descrip.mms
index 16c7c9b..3584b0d 100644
--- a/descrip.mms
+++ b/descrip.mms
@@ -8,9 +8,9 @@
 
 
 
-OBJS = png.obj, pngrcb.obj, pngrutil.obj, pngtrans.obj, pngwutil.obj,\
-	pngread.obj, pngmem.obj, pngwrite.obj, pngrtran.obj, pngwtran.obj,\
-	pngrio.obj, pngwio.obj, pngerror.obj, pngpread.obj
+OBJS = png.obj, pngset.obj, pngget.obj, pngrutil.obj, pngtrans.obj,\
+	pngwutil.obj, pngread.obj, pngmem.obj, pngwrite.obj, pngrtran.obj,\
+	pngwtran.obj, pngrio.obj, pngwio.obj, pngerror.obj, pngpread.obj
 
 
 CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
@@ -35,7 +35,8 @@
 # Other dependencies.
 png.obj : png.h, pngconf.h
 pngpread.obj : png.h, pngconf.h
-pngrcb.obj : png.h, pngconf.h
+pngset.obj : png.h, pngconf.h
+pngget.obj : png.h, pngconf.h
 pngread.obj : png.h, pngconf.h
 pngrtran.obj : png.h, pngconf.h
 pngrutil.obj : png.h, pngconf.h
diff --git a/example.c b/example.c
index 0903933..20510ad 100644
--- a/example.c
+++ b/example.c
@@ -1,92 +1,107 @@
 /* example.c - an example of using libpng */
 
-/* this is an example of how to use libpng to read and write
-   png files.  The file libpng.txt is much more verbose then
-   this.  If you have not read it, do so first.  This was
-   designed to be a starting point of an implementation.
-   This is not officially part of libpng, and therefore
+/* This is an example of how to use libpng to read and write PNG files.
+   The file libpng.txt is much more verbose then this.  If you have not
+   read it, do so first.  This was designed to be a starting point of an
+   implementation.  This is not officially part of libpng, and therefore
    does not require a copyright notice.
 
-   This file does not currently compile, because it is missing
-   certain parts, like allocating memory to hold an image.
-   You will have to supply these parts to get it to compile.
-   */
+   This file does not currently compile, because it is missing certain
+   parts, like allocating memory to hold an image.  You will have to
+   supply these parts to get it to compile.  For an example of a minimal
+   working PNG reader/writer, see pngtest.c, included in this distribution.
+*/
 
 #include <png.h>
 
-/* Check to see if a file is a png file using png_check_sig().
+/* Check to see if a file is a PNG file using png_check_sig().  Returns
+   non-zero if the image is a PNG, and 0 if it isn't a PNG.
 
-   If this call is successful, and you are going to keep the file
-   open, you should call png_set_sig_bytes_read(png_ptr, 8);
-   once you have created the png_ptr, so that libpng knows it
-   doesn't have to read the signature again.  Make sure you don't
-   call png_set_sig_bytes_read() with more than 8 bytes read or
-   give it an incorrect number of bytes read, or you will either
-   have read too many bytes (your fault), or you are telling libpng
-   to read the wrong number of magic bytes (also your fault). */
-int check_png(char *file_name, FILE **fp)
+   If this call is successful, and you are going to keep the file open,
+   you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
+   you have created the png_ptr, so that libpng knows your application
+   has read that many bytes from the start of the file.  Make sure you
+   don't call png_set_sig_bytes() with more than 8 bytes read or give it
+   an incorrect number of bytes read, or you will either have read too
+   many bytes (your fault), or you are telling libpng to read the wrong
+   number of magic bytes (also your fault).
+
+   Many applications already read the first 2 or 4 bytes from the start
+   of the image to determine the file type, so it would be easiest just
+   to pass the bytes to png_check_sig() or even skip that if you know
+   you have a PNG file, and call png_set_sig_bytes().
+*/
+#define PNG_BYTES_TO_CHECK 4
+int check_if_png(char *file_name, FILE **fp)
 {
-   char buf[8];
-   int ret;
+   char buf[PNG_BYTES_TO_CHECK];
 
-   *fp = fopen(file_name, "rb");
-   if (!fp)
-      return 0;
-   ret = fread(buf, 1, 8, *fp);
-
-   if (ret != 8)
+   /* Open the prospective PNG file. */
+   if ((*fp = fopen(file_name, "rb")) != NULL);
       return 0;
 
-   /* Check the signature starting at byte 0, and check all 8 bytes */
-   ret = png_check_sig(buf, 0, 8);
+   /* Read in the signature bytes */
+   if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
+      return 0;
 
-   return (ret);
+   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */
+   return(png_check_sig(buf, PNG_BYTES_TO_CHECK));
 }
 
-/* read a png file.  You may want to return an error code if the read
+/* Read a PNG file.  You may want to return an error code if the read
    fails (depending upon the failure).  There are two "prototypes" given
    here - one where we are given the filename, and we need to open the
    file, and the other where we are given an open file (possibly with
-   some or all of the magic bytes read - see above) and an opened file
-   for reading. */
-------- prototype 1 ----------
+   some or all of the magic bytes read - see comments above). */
+**** prototype 1 ****
 void read_png(char *file_name)  /* We need to open the file */
 {
    png_structp png_ptr;
    png_infop info_ptr;
+   unsigned int sig_read = 0;
+   png_uint_32 width, height;
+   int bit_depth, color_type, interlace_type;
    FILE *fp;
 
    if ((fp = fopen(file_name, "rb")) == NULL)
       return;
-------- prototype 2 ----------
+**** prototype 2 ****
 void read_png(FILE *fp, unsigned int sig_read)  /* file is already open */
 {
    png_structp png_ptr;
    png_infop info_ptr;
-------- only use one! --------
+   png_uint_32 width, height;
+   int bit_depth, color_type, interlace_type;
+**** only use one prototype! ****
 
    /* Create and initialize the png_struct with the desired error handler
-      functions.  If you want to use the default stderr and longjump method,
-      you can supply NULL for the last three parameters.  We also check that
-      the header file is compatible with the library version.  */
+    * functions.  If you want to use the default stderr and longjump method,
+    * you can supply NULL for the last three parameters.  We also supply the
+    * the compiler header file version, so that we know if the application
+    * was compiled with a compatible version of the library.  REQUIRED
+    */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
       (void *)user_error_ptr, user_error_fn, user_warning_fn);
 
-   if (!png_ptr)
+   if (png_ptr == NULL)
    {
       fclose(fp);
       return;
    }
 
+   /* Allocate/initialize the memory for image information.  REQUIRED. */
    info_ptr = png_create_info_struct();
-   if (!info_ptr)
+   if (info_ptr == NULL)
    {
       fclose(fp);
-      png_destroy_read_struct(&png_ptr,  (png_infopp)NULL, (png_infopp)NULL);
+      png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
       return;
    }
 
-   /* set error handling if you are using the setjmp/longjmp method */
+   /* Set error handling if you are using the setjmp/longjmp method (this is
+    * the normal method of doing things with libpng).  REQUIRED unless you
+    * set up your own error handlers in the png_create_read_struct() earlier.
+    */
    if (setjmp(png_ptr->jmpbuf))
    {
       /* Free all of the memory associated with the png_ptr and info_ptr */
@@ -96,152 +111,221 @@
       return;
    }
 
-   /* set up the input control if you are using standard C streams */
+   /* One of the following I/O initialization methods is REQUIRED */
+**** PNG file I/O method 1 ****
+   /* Set up the input control if you are using standard C streams */
    png_init_io(png_ptr, fp);
 
-   /* if you are using replacement read functions, instead of calling
-      png_init_io() here you would call */
+**** PNG file I/O method 2 ****
+   /* If you are using replacement read functions, instead of calling
+    * png_init_io() here you would call */
    png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
+**** Use only one I/O method! ****
 
-   /* if we have already read some of the signature from the beginning call */
+   /* If we have already read some of the signature */
    png_set_sig_bytes_read(png_ptr, sig_read);
 
-   /* The call to png_read_info() gives us all of the information
-      from the PNG file before the first IDAT (image data chunk). */
+   /* The call to png_read_info() gives us all of the information from the
+    * PNG file before the first IDAT (image data chunk).  REQUIRED
+    */
    png_read_info(png_ptr, info_ptr);
 
-   /* set up the transformations you want.  Note that these are
-      all optional.  Only call them if you want them */
+   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+       &interlace_type, NULL, NULL);
+
+/**** Set up the data transformations you want.  Note that these are all
+ **** optional.  Only call them if you want/need them.  Many of the
+ **** transformations only work on specific types of images, and many
+ **** are mutually exclusive.
+ ****/
+
+   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+   png_set_strip_16(png_ptr);
+
+   /* strip alpha bytes from the input data without combining with th
+    * background (not recommended) */
+   png_set_strip_alpha(png_ptr);
+
+   /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
+    * byte into separate bytes (useful for paletted and grayscale images).
+    */
+   png_set_packing(png_ptr);
+
+   /* change the order of packed pixels to least significant bit first
+    * (not useful if you are using png_set_packing). */
+   png_set_packswap(png_ptr);
 
    /* expand paletted colors into true RGB triplets */
-   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+   if (color_type == PNG_COLOR_TYPE_PALETTE)
       png_set_expand(png_ptr);
 
-   /* expand grayscale images to the full 8 bits */
-   if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8)
+   /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
       png_set_expand(png_ptr);
 
    /* expand paletted or RGB images with transparency to full alpha channels
     * so the data will be available as RGBA quartets */
-   if (info_ptr->valid & PNG_INFO_tRNS)
+   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
       png_set_expand(png_ptr);
 
-   /* Set the background color to draw transparent and alpha
-      images over.  It is possible to set the red, green, and blue
-      components directly for paletted images. */
+   /* Set the background color to draw transparent and alpha images over.
+    * It is possible to set the red, green, and blue components directly
+    * for paletted images instead of supplying a palette index.  Note that
+    * even if the PNG file supplies a background, you are not required to
+    * use it - you should use the (solid) application background if it has one.
+    */
 
-   png_color_16 my_background;
+   png_color_16 my_background, *image_background);
 
-   if (info_ptr->valid & PNG_INFO_bKGD)
-      png_set_background(png_ptr, &(info_ptr->background),
+   if (png_get_bKGD(png_ptr, info_ptr, &image_background);
+      png_set_background(png_ptr, image_background),
                          PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
    else
       png_set_background(png_ptr, &my_background,
                          PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
 
-   /* tell libpng to handle the gamma conversion for you.  We only
-      need the second call if the screen_gamma isn't the usual 2.2
-      or if it is controllable by the user.  It may also be a good
-      idea to allow the user to set the file gamma if it is unknown. */
-   if (info_ptr->valid & PNG_INFO_gAMA)
-      png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
+   /* Some suggestions as to how to get a screen gamma value */
+   if (/* We have a user-defined screen gamma value */)
+   {
+      screen_gamma = user-defined screen_gamma;
+   }
+   /* This is one way that applications share the same screen gamma value */
+   else if ((gamma_str = getenv("DISPLAY_GAMMA")) != NULL)
+   {
+      screen_gamma = atof(gamma_str);
+   }
+   /* If we don't have another value */
+   else
+   {
+      screen_gamma = 2.2;  /* A good guess for PC monitors */
+      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
+   }
+
+   /* Tell libpng to handle the gamma conversion for you.  The second call
+    * is a good guess for PC generated images, but it should be configurable
+    * by the user at run time by the user.  It is strongly suggested that
+    * your application support gamma correction.
+    */
+   if (png_get_gAMA(png_ptr, info_ptr, &image_gamma);
+      png_set_gamma(png_ptr, screen_gamma, image_gamma);
    else
       png_set_gamma(png_ptr, screen_gamma, 0.45);
 
-   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
-   if (info_ptr->bit_depth == 16)
-      png_set_strip_16(png_ptr);
-
-   /* dither rgb files down to 8 bit palette & reduce palettes
+   /* Dither RGB files down to 8 bit palette or reduce palettes
       to the number of colors available on your screen */
-   if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+   if (color_type & PNG_COLOR_MASK_COLOR)
    {
-      if (info_ptr->valid & PNG_INFO_PLTE)
-         png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette,
-                        max_screen_colors, info_ptr->histogram);
-      else
+      png_uint_32 num_palette;
+      png_colorp palette;
+
+      /* This reduces the image to the application supplied palette */
+      if (we have our own palette)
       {
-         png_color std_color_cube[MAX_SCREEN_COLORS] =
-            {/* ... colors ... */};
+         /* An array of colors to which the image should be dithered */
+         png_color std_color_cube[MAX_SCREEN_COLORS];
 
          png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
-            MAX_SCREEN_COLORS, NULL);
+            MAX_SCREEN_COLORS, NULL, 0);
+      }
+      /* This reduces the image to the palette supplied in the file */
+      else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)))
+      {
+         png_color16p histogram;
+
+         png_get_hIST(png_ptr, info_ptr, &histogram);
+
+         png_set_dither(png_ptr, palette, num_palette,
+                        max_screen_colors, histogram, 0);
       }
    }
 
    /* invert monocrome files to have 0 as white and 1 as black */
-   if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY)
-      png_set_invert(png_ptr);
+   png_set_invert(png_ptr);
 
-   /* shift the pixels down to their true bit depth */
-   if (info_ptr->valid & PNG_INFO_sBIT &&
-      info_ptr->bit_depth > info_ptr->sig_bit)
-      png_set_shift(png_ptr, &(info_ptr->sig_bit));
+   /* If you want to shift the pixel values from the range [0,255] or
+    * [0,65535] to the original [0,7] or [0,31], or whatever range the
+    * colors were originally in:
+    */
+   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+   {
+      png_color8p sig_bit;
 
-   /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes
-      (useful only for paletted and grayscale images) */
-   if (info_ptr->bit_depth < 8)
-      png_set_packing(png_ptr);
+      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+      png_set_shift(png_ptr, sig_bit);
+   }
 
-   /* flip the rgb pixels to bgr */
-   if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-      info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-      png_set_bgr(png_ptr);
+   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
+   png_set_bgr(png_ptr);
 
-   /* swap bytes of 16 bit files to least significant bit first */
-   if (info_ptr->bit_depth == 16)
-      png_set_swap(png_ptr);
+   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+   png_set_swap_alpha(png_ptr);
 
-   /* add a filler byte to RGB files (before or after each RGB triplet) */
-   if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB)
-      png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+   /* swap bytes of 16 bit files to least significant byte first */
+   png_set_swap(png_ptr);
 
-   /* turn on interlace handling if you are not using png_read_image() */
+   /* Add filler (or alpha) byte (before/after each RGB triplet) */
+   png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+   /* Turn on interlace handling.  REQUIRED if you are not using
+    * png_read_image().  To see how to handle interlacing passes,
+    * see the png_read_row() method below.
+    */
    number_passes = png_set_interlace_handling(png_ptr);
 
    /* optional call to gamma correct and add the background to the palette
-      and update info structure. */
+    * and update info structure.  REQUIRED if you are expecting libpng to
+    * update the palette for you (ie you selected such a transform above).
+    */
    png_read_update_info(png_ptr, info_ptr);
 
-   /* allocate the memory to hold the image using the fields
-      of png_info. */
+   /* allocate the memory to hold the image using the fields of info_ptr. */
 
    /* the easiest way to read the image */
    png_bytep row_pointers[height];
 
    for (row = 0; row < height; row++)
    {
-     row_pointers[row] = malloc(info_ptr->rowbytes);
+      row_pointers[row] = malloc(png_get_rowbytes(png_ptr, info_ptr));
    }
 
+   /* Now it's time to read the image.  One of these methods is REQUIRED */
+**** Read the entire image in one go ****
    png_read_image(png_ptr, row_pointers);
 
+**** Read the image one or more scanlines at a time ****
    /* the other way to read images - deal with interlacing */
 
    for (pass = 0; pass < number_passes; pass++)
    {
-      /* Read the image using the "sparkle" effect. */
-      png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
-
-      /* If you are only reading on row at a time, this works */
+[[[[[[[ Read the image a single row at a time ]]]]]]]
       for (y = 0; y < height; y++)
       {
          png_bytep row_pointers = row[y];
          png_read_rows(png_ptr, &row_pointers, NULL, 1);
       }
 
-      /* to get the rectangle effect, use the third parameter */
-      png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
-
+[[[[[[[ Read the image several rows at a time ]]]]]]]
+      for (y = 0; y < height; y += number_of_rows)
+      {
+<<<<<<<<<< Read the image using the "sparkle" effect. >>>>>>>>>>
+         png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+        
+<<<<<<<<<< Read the image using the "rectangle" effect >>>>>>>>>>
+         png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
+<<<<<<<<<< use only one of these two methods >>>>>>>>>>
+      }
+     
       /* if you want to display the image after every pass, do
          so here */
+[[[[[[[ use only one of these two methods ]]]]]]]
    }
+**** use only one of these two methods ****
 
-   /* read the rest of the file, getting any additional chunks in info_ptr */
+   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);
 
-   /* clean up after the read, and free any memory allocated */
+   /* clean up after the read, and free any memory allocated - REQUIRED */
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
 
    /* close the file */
@@ -257,15 +341,15 @@
 initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
 {
    /* Create and initialize the png_struct with the desired error handler
-      functions.  If you want to use the default stderr and longjump method,
-      you can supply NULL for the last three parameters.  We also check that
-      the library version is compatible in case we are using dynamically
-      linked libraries.
+    * functions.  If you want to use the default stderr and longjump method,
+    * you can supply NULL for the last three parameters.  We also check that
+    * the library version is compatible in case we are using dynamically
+    * linked libraries.
     */
    *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        (void *)user_error_ptr, user_error_fn, user_warning_fn);
 
-   if (! *png_ptr)
+   if (*png_ptr == NULL)
    {
       *info_ptr = NULL;
       return ERROR;
@@ -273,7 +357,7 @@
 
    *info_ptr = png_create_info_struct(png_ptr);
 
-   if (! *info_ptr)
+   if (*info_ptr == NULL)
    {
       png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
       return ERROR;
@@ -286,13 +370,14 @@
    }
 
    /* this one's new.  You will need to provide all three
-      function callbacks, even if you aren't using them all.
-      These functions shouldn't be dependent on global or
-      static variables if you are decoding several images
-      simultaneously.  You should store stream specific data
-      in a separate struct, given as the second parameter,
-      and retrieve the pointer from inside the callbacks using
-      the function png_get_progressive_ptr(png_ptr). */
+    * function callbacks, even if you aren't using them all.
+    * These functions shouldn't be dependent on global or
+    * static variables if you are decoding several images
+    * simultaneously.  You should store stream specific data
+    * in a separate struct, given as the second parameter,
+    * and retrieve the pointer from inside the callbacks using
+    * the function png_get_progressive_ptr(png_ptr).
+    */
    png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
       info_callback, row_callback, end_callback);
 
@@ -310,15 +395,16 @@
       return ERROR;
    }
 
-   /* this one's new also.  Simply give it chunks of data as
-      they arrive from the data stream (in order, of course).
-      On Segmented machines, don't give it any more than 64K.
-      The library seems to run fine with sizes of 4K, although
-      you can give it much less if necessary (I assume you can
-      give it chunks of 1 byte, but I haven't tried with less
-      than 256 bytes yet).  When this function returns, you may
-      want to display any rows that were generated in the row
-      callback, if you aren't already displaying them there. */
+   /* This one's new also.  Simply give it chunks of data as
+    * they arrive from the data stream (in order, of course).
+    * On Segmented machines, don't give it any more than 64K.
+    * The library seems to run fine with sizes of 4K, although
+    * you can give it much less if necessary (I assume you can
+    * give it chunks of 1 byte, but I haven't tried with less
+    * than 256 bytes yet).  When this function returns, you may
+    * want to display any rows that were generated in the row
+    * callback, if you aren't already displaying them there.
+    */
    png_process_data(*png_ptr, *info_ptr, buffer, length);
    return OK;
 }
@@ -326,52 +412,56 @@
 info_callback(png_structp png_ptr, png_infop info)
 {
 /* do any setup here, including setting any of the transformations
-   mentioned in the Reading PNG files section.  For now, you _must_
-   call either png_start_read_image() or png_read_update_info()
-   after all the transformations are set (even if you don't set
-   any).  You may start getting rows before png_process_data()
-   returns, so this is your last chance to prepare for that. */
+ * mentioned in the Reading PNG files section.  For now, you _must_
+ * call either png_start_read_image() or png_read_update_info()
+ * after all the transformations are set (even if you don't set
+ * any).  You may start getting rows before png_process_data()
+ * returns, so this is your last chance to prepare for that.
+ */
 }
 
 row_callback(png_structp png_ptr, png_bytep new_row,
    png_uint_32 row_num, int pass)
 {
 /* this function is called for every row in the image.  If the
-   image is interlacing, and you turned on the interlace handler,
-   this function will be called for every row in every pass.
-   Some of these rows will not be changed from the previous pass.
-   When the row is not changed, the new_row variable will be NULL.
-   The rows and passes are called in order, so you don't really
-   need the row_num and pass, but I'm supplying them because it
-   may make your life easier.
-
-   For the non-NULL rows of interlaced images, you must call
-   png_progressive_combine_row() passing in the row and the
-   old row.  You can call this function for NULL rows (it will
-   just return) and for non-interlaced images (it just does the
-   memcpy for you) if it will make the code easier.  Thus, you
-   can just do this for all cases: */
+ * image is interlacing, and you turned on the interlace handler,
+ * this function will be called for every row in every pass.
+ * Some of these rows will not be changed from the previous pass.
+ * When the row is not changed, the new_row variable will be NULL.
+ * The rows and passes are called in order, so you don't really
+ * need the row_num and pass, but I'm supplying them because it
+ * may make your life easier.
+ *
+ * For the non-NULL rows of interlaced images, you must call
+ * png_progressive_combine_row() passing in the row and the
+ * old row.  You can call this function for NULL rows (it will
+ * just return) and for non-interlaced images (it just does the
+ * memcpy for you) if it will make the code easier.  Thus, you
+ * can just do this for all cases:
+ */
 
    png_progressive_combine_row(png_ptr, old_row, new_row);
 
 /* where old_row is what was displayed for previous rows.  Note
-   that the first pass (pass == 0 really) will completely cover
-   the old row, so the rows do not have to be initialized.  After
-   the first pass (and only for interlaced images), you will have
-   to pass the current row, and the function will combine the
-   old row and the new row. */
+ * that the first pass (pass == 0 really) will completely cover
+ * the old row, so the rows do not have to be initialized.  After
+ * the first pass (and only for interlaced images), you will have
+ * to pass the current row, and the function will combine the
+ * old row and the new row.
+ */
 }
 
 end_callback(png_structp png_ptr, png_infop info)
 {
 /* this function is called when the whole image has been read,
-   including any chunks after the image (up to and including
-   the IEND).  You will usually have the same info chunk as you
-   had in the header, although some data may have been added
-   to the comments and time fields.
-
-   Most people won't do much here, perhaps setting a flag that
-   marks the image as finished. */
+ * including any chunks after the image (up to and including
+ * the IEND).  You will usually have the same info chunk as you
+ * had in the header, although some data may have been added
+ * to the comments and time fields.
+ *
+ * Most people won't do much here, perhaps setting a flag that
+ * marks the image as finished.
+ */
 }
 
 /* write a png file */
@@ -383,33 +473,36 @@
 
    /* open the file */
    fp = fopen(file_name, "wb");
-   if (!fp)
+   if (fp == NULL)
       return;
 
    /* Create and initialize the png_struct with the desired error handler
-      functions.  If you want to use the default stderr and longjump method,
-      you can supply NULL for the last three parameters.  We also check that
-      the library version is compatible in case we are using dynamically
-      linked libraries.
+    * functions.  If you want to use the default stderr and longjump method,
+    * you can supply NULL for the last three parameters.  We also check that
+    * the library version is compatible with the one used at compile time,
+    * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
       (void *)user_error_ptr, user_error_fn, user_warning_fn);
 
-   if (!png_ptr)
+   if (png_ptr == NULL)
    {
       fclose(fp);
       return;
    }
 
+   /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);
-   if (!info_ptr)
+   if (info_ptr == NULL)
    {
       fclose(fp);
       png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
       return;
    }
 
-   /* set error handling */
+   /* Set error handling.  REQUIRED if you aren't supplying your own
+    * error hadnling functions in the png_create_write_struct() call.
+    */
    if (setjmp(png_ptr->jmpbuf))
    {
       /* If we get here, we had a problem reading the file */
@@ -418,63 +511,101 @@
       return;
    }
 
+   /* One of the following I/O initialization functions is REQUIRED */
+**** I/O initialization method 1 ****
    /* set up the output control if you are using standard C streams */
    png_init_io(png_ptr, fp);
+**** I/O initialization method 2 ****
+   /* If you are using replacement read functions, instead of calling
+    * png_init_io() here you would call */
+   png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
+      user_IO_flush_function);
+   /* where user_io_ptr is a structure you want available to the callbacks */
+**** only use 1 initialization method ****
 
-   /* set the file information here */
-   info_ptr->width = ;
-   info_ptr->height = ;
-   etc.
+   /* Set the image information here.  Width and height are up to 2^31,
+    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
+    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+    */
+   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
+      PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
-   /* set the palette if there is one */
-   info_ptr->valid |= PNG_INFO_PLTE;
-   info_ptr->palette = malloc(256 * sizeof (png_color));
-   info_ptr->num_palette = 256;
+   /* set the palette if there is one.  REQUIRED for indexed-color images */
+   palette = png_malloc(png_ptr, 256 * sizeof (png_color));
    ... set palette colors ...
+   png_set_PLTE(png_ptr, info_ptr, palette, 256);
 
    /* optional significant bit chunk */
-   info_ptr->valid |= PNG_INFO_sBIT;
    /* if we are dealing with a grayscale image then */
-   info_ptr->sig_bit.gray = true_bit_depth;
+   sig_bit.gray = true_bit_depth;
    /* otherwise, if we are dealing with a color image then */
-   info_ptr->sig_bit.red = true_red_bit_depth;
-   info_ptr->sig_bit.green = true_green_bit_depth;
-   info_ptr->sig_bit.blue = true_blue_bit_depth;
+   sig_bit.red = true_red_bit_depth;
+   sig_bit.green = true_green_bit_depth;
+   sig_bit.blue = true_blue_bit_depth;
    /* if the image has an alpha channel then */
-   info_ptr->sig_bit.alpha = true_alpha_bit_depth;
+   sig_bit.alpha = true_alpha_bit_depth;
+   png_set_sBIT(png_ptr, info_ptr, sig_bit);
+
   
-   /* optional gamma chunk is strongly suggested if you have any guess
-      as to the correct gamma of the image */
-   info_ptr->valid |= PNG_INFO_gAMA;
-   info_ptr->gamma = gamma;
+   /* Optional gamma chunk is strongly suggested if you have any guess
+    * as to the correct gamma of the image. */
+   png_set_gAMA(png_ptr, info_ptr, gamma);
 
-   /* other optional chunks like cHRM, bKGD, tRNS, tEXt, tIME, oFFs, pHYs, */
+   /* Optionally write comments into the image */
+   text_ptr[0].key = "Title";
+   text_ptr[0].text = "Mona Lisa";
+   text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+   text_ptr[1].key = "Author";
+   text_ptr[1].text = "Leonardo DaVinci";
+   text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+   text_ptr[2].key = "Description";
+   text_ptr[2].text = "<long text>";
+   text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+   png_set_text(png_ptr, info_ptr, text_ptr, 2);
 
-   /* write the file header information */
+   /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
+
+   /* Write the file header information.  REQUIRED */
    png_write_info(png_ptr, info_ptr);
 
+   /* Once we write out the header, the compression type on the text
+    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+    * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+    * at the end.
+    */
+
    /* set up the transformations you want.  Note that these are
-      all optional.  Only call them if you want them */
+    * all optional.  Only call them if you want them. */
 
    /* invert monocrome pixels */
    png_set_invert(png_ptr);
 
-   /* shift the pixels up to a legal bit depth and fill in
-      as appropriate to correctly scale the image */
-   png_set_shift(png_ptr, &(info_ptr->sig_bit));
+   /* Shift the pixels up to a legal bit depth and fill in
+    * as appropriate to correctly scale the image */
+   png_set_shift(png_ptr, &sig_bit);
 
    /* pack pixels into bytes */
    png_set_packing(png_ptr);
 
-   /* flip bgr pixels to rgb */
+   /* swap location of alpha bytes from ARGB to RGBA */
+   png_set_swap_alpha(png_ptr);
+
+   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+    * RGB (4 channels -> 3 channels). The second parameter is not used. */
+   png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+   /* flip BGR pixels to RGB */
    png_set_bgr(png_ptr);
 
-   /* swap bytes of 16 bit files to most significant bit first */
+   /* swap bytes of 16-bit files to most significant byte first */
    png_set_swap(png_ptr);
 
-   /* get rid of filler bytes, pack rgb into 3 bytes.  The
-      filler number is not used. */
-   png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+   /* swap bits of 1, 2, 4 bit packed pixel formats */
+   png_set_packswap(png_ptr);
 
    /* turn on interlace handling if you are not using png_write_image() */
    if (interlacing)
@@ -482,14 +613,22 @@
    else
       number_passes = 1;
 
-   /* the easiest way to write the image (you may choose to allocate the
-      memory differently, however) */
+   /* The easiest way to write the image (you may have a different memory
+    * layout, however, so choose what fits your needs best).  You need to
+    * use the first method if you aren't handling interlacing yourself.
+    */
    png_byte row_pointers[height][width];
 
+   /* One of the following output methods is REQUIRED */
+**** write out the entire image data in one call ***
    png_write_image(png_ptr, row_pointers);
 
    /* the other way to write the image - deal with interlacing */
 
+**** write out the image data by one or more scanlines ****
+   /* The number of passes is either 1 for non-interlaced images,
+    * or 7 for interlaced images.
+    */
    for (pass = 0; pass < number_passes; pass++)
    {
       /* Write a few rows at a time. */
@@ -502,24 +641,22 @@
          png_write_rows(png_ptr, &row_pointers, 1);
       }
    }
+**** use only one output method ****
 
-   /* You can write optional chunks like tEXt, tIME at the end as well.
-    * Note that if you wrote tEXt or zTXt chunks before the image, and
-    * you aren't writing out more at the end, you have to set
-    * info_ptr->num_text = 0 or they will be written out again.
+   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
+    * as well.
     */
 
-   /* write the rest of the file */
+   /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);
 
    /* if you malloced the palette, free it here */
-   if (info_ptr->palette)
-      free(info_ptr->palette);
+   free(info_ptr->palette);
 
    /* if you allocated any text comments, free them here */
 
    /* clean up after the write, and free any memory allocated */
-   png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
+   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
 
    /* close the file */
    fclose(fp);
diff --git a/libpng.txt b/libpng.txt
index 5ff4d05..a603c3a 100644
--- a/libpng.txt
+++ b/libpng.txt
@@ -1,16 +1,19 @@
 libpng.txt - a description on how to use and modify libpng
 
-    libpng 1.0 beta 3 - version 0.89
-    Updated and distributed by Andreas Dilger <adilger@enel.ucalgary.ca>,
-       based on:
+   libpng 1.0 beta 5 - version 0.95
+   Updated and distributed by Andreas Dilger <adilger@enel.ucalgary.ca>,
+   Copyright (c) 1996, 1997 Andreas Dilger
+   March 15, 1997
+      based on:
 
-    libpng 1.0 beta 2 - version 0.88
-    For conditions of distribution and use, see copyright notice in png.h
-    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-    May 24, 1996
-    Updated/rewritten per request in the libpng FAQ
-    Copyright (c) 1995 Frank J. T. Wojcik
-    December 18, 1995 && January 20, 1996
+   libpng 1.0 beta 2 - version 0.88
+   For conditions of distribution and use, see copyright notice in png.h
+   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+   January 26, 1996
+
+   Updated/rewritten per request in the libpng FAQ
+   Copyright (c) 1995 Frank J. T. Wojcik
+   December 18, 1995 && January 20, 1996
 
 I. Introduction
 
@@ -32,10 +35,10 @@
 
 Libpng has been designed to handle multiple sessions at one time,
 to be easily modifiable, to be portable to the vast majority of
-machines (ANSI, K&R, 16 bit, 32 bit) available, and to be easy to
-use.  The ultimate goal of libpng is to promote the acceptance of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use.  The ultimate goal of libpng is to promote the acceptance of
 the PNG file format in whatever way possible.  While there is still
-work to be done (see the pngtodo.txt file), libpng should cover the
+work to be done (see the TODO file), libpng should cover the
 majority of the needs of it's users.
 
 Libpng uses zlib for its compression and decompression of PNG files.
@@ -59,10 +62,14 @@
 variable passed to every libpng function call.
 
 The png_info structure is designed to provide information about the
-png file.  All of its fields are intended to be examined or modified
-by the user.  See png.h for a good description of the png_info fields.
-png.h is also an invaluable reference for programming with libpng.
+PNG file.  At one time, the fields of png_info were intended to be
+directly accessible to the user.  However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info were delevoped.  The fields
+of png_info are still available for older applications, but it is
+suggested that applications use the new interfaces if at all possible.
 
+The png.h header file is an invaluable reference for programming with libpng.
 And while I'm on the topic, make sure you include the libpng header file:
 
 #include <png.h>
@@ -110,24 +117,27 @@
         return;
     }
 
-Next, png_struct and png_info need to be allocated and initialized.
-In order to ensure that the size of these structures is correct even
-with a dynamically linked libpng, there are functions to initialize
-and allocate the structures.  We also pass the library version, and
-optionally pointers to error handling functions (these can be NULL
-if the default error handlers are to be used).  See the section on
-Changes to Libpng below regarding the old initialization functions.
+Next, png_struct and png_info need to be allocated and initialized.  In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures.  We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used).  See the section
+on Changes to Libpng below regarding the old initialization functions.
 
     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        (void *)user_error_ptr, user_error_fn, user_warning_fn);
     if (!png_ptr)
         return;
+
     png_infop info_ptr = png_create_info_struct(png_ptr);
     if (!info_ptr)
     {
         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
         return;
     }
+
     png_infop end_info = png_create_info_struct(png_ptr);
     if (!end_info)
     {
@@ -160,9 +170,10 @@
 Now you need to set up the input code.  The default for libpng is to
 use the C function fread().  If you use this, you will need to pass a
 valid FILE * in the function png_init_io().  Be sure that the file is
-opened in binary mode.  Again, if you wish to handle reading data in
-another way, see the discussion on libpng I/O handling in the Customizing
-Libpng section below.
+opened in binary mode.  If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
 
     png_init_io(png_ptr, fp);
 
@@ -177,76 +188,127 @@
 
     png_read_info(png_ptr, info_ptr);
 
-The png_info structure is now filled in with all the data necessary
-to read the file.  Some of the more important parts of the info_ptr are:
+Functions are used to get the information from the info_ptr:
 
-    width          - holds the width of the file
-    height         - holds the height of the file
-    bit_depth      - holds the bit depth of one of the image channels
-    color_type     - describes the channels and what they mean
-                     (see the PNG_COLOR_TYPE_ macros for more information)
+    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+       &interlace_type, &compression_type, &filter_type);
+
+    width          - holds the width of the image in pixels (up to 2^31).
+    height         - holds the height of the image in pixels (up to 2^31).
+    bit_depth      - holds the bit depth of one of the image channels.
+                     (valid values are 1, 2, 4, 8, 16 and depend also on the
+                      color_type.  See also significant bits (sBIT) below).
+    color_type     - describes which color/alpha channels are present.
+                     PNG_COLOR_TYPE_GRAY        (bit depths 1, 2, 4, 8, 16)
+                     PNG_COLOR_TYPE_GRAY_ALPHA  (bit depths 8, 16)
+                     PNG_COLOR_TYPE_PALETTE     (bit depths 1, 2, 4, 8)
+                     PNG_COLOR_TYPE_RGB         (bit_depths 8, 16)
+                     PNG_COLOR_TYPE_RGB_ALPHA   (bit_depths 8, 16)
+
+                     PNG_COLOR_MASK_PALETTE
+                     PNG_COLOR_MASK_COLOR
+                     PNG_COLOR_MASK_ALPHA
+
+    interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTERLACE_TYPE_ADAM7
+    compression_type - (must be PNG_COMPRESSION_TYPE_BASE for PNG 1.0)
+    filter_type    - (must be PNG_FILTER_TYPE_BASE for PNG 1.0)
+
+    channels = png_get_channels(png_ptr, info_ptr);
     channels       - number of channels of info for the color type
-    pixel_depth    - bits per pixel, the result of multiplying the 
-                     bit_depth times the channels
+                     (valid values are 1 (GRAY, PALETTE), 2 (GRAY_ALPHA),
+                      3 (RGB), 4 (RGB_ALPHA or RGB + filler byte))
+    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
     rowbytes       - number of bytes needed to hold a row
-    interlace_type - currently 0 for none, 1 for interlaced
+
+    signature = png_get_signature(png_ptr, info_ptr);
     signature      - holds the signature read from the file (if any).  The
                      data is kept in the same offset it would be if the
-                     whole signature were read (ie if you had already read
-                     in 4 bytes of signature, the remaining 4 bytes would
-                     be in signature[4] through signature[7]).
-    valid          - this details which optional chunks were found in the
-                     file.  To see if a chunk was present, AND '&' valid with
-                     the appropriate PNG_INFO_<chunk name> define.
+                     whole signature were read (ie if an application had
+                     already read in 4 bytes of signature before staring
+                     libpng, the remaining 4 bytes would be in signature[4]
+                     through signature[7] (see png_set_sig_bytes())).
 
-These are also important, but their validity depends on whether a
-corresponding chunk exists. Use valid (see above) to ensure that what
-you're doing with these values makes sense.
+These are also important, but their validity depends on whether the chunk
+has been read.  The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing.  The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
 
-    palette        - the palette for the file (PNG_INFO_PLTE)
+    png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+    palette        - the palette for the file (array of png_color)
     num_palette    - number of entries in the palette
+
+    png_get_gAMA(png_ptr, info_ptr, &gamma);
     gamma          - the gamma the file is written at (PNG_INFO_gAMA)
-    sig_bit        - the number of significant bits (PNG_INFO_sBIT)
-                     for the gray, red, green, and blue channels, whichever
-                     are appropriate for the given color type.
+
+    png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+    sig_bit        - the number of significant bits for (PNG_INFO_sBIT)
+                     the gray, red, green, and blue channels, whichever
+                     are appropriate for the given color type (png_color_16)
+
+    png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
+    trans          - array of transparent entries for palette (PNG_INFO_tRNS)
     trans_values   - transparent pixel for non-paletted images (PNG_INFO_tRNS)
-    trans          - array of transparent entries for paletted images
-    num_trans      - number of transparent entries
-    hist           - histogram of palette (PNG_INFO_hIST)
+    num_trans      - number of transparent entries (PNG_INFO_tRNS)
+
+    png_get_hIST(png_ptr, info_ptr, &hist);        (PNG_INFO_hIST)
+    hist           - histogram of palette (array of png_color_16)
+
+    png_get_tIME(png_ptr, info_ptr, &mod_time);
     mod_time       - time image was last modified (PNG_VALID_tIME)
+
+    png_get_bKGD(png_ptr, info_ptr, &background);
     background     - background color (PNG_VALID_bKGD)
-    text           - text comments in the file.
+
+    num_text = png_get_text(png_ptr, info_ptr, &text_ptr);
+    text_ptr       - array of png_text holding image comments
+    text_ptr[i]->key         - keyword for comment.
+    text_ptr[i]->text        - text comments for current keyword.
+    text_ptr[i]->compression - type of compression used on "text"
+                               PNG_TEXT_COMPRESSION_NONE or
+                               PNG_TEXT_COMPRESSION_zTXt
     num_text       - number of comments
 
-for more information, see the png_info definition in png.h and the
+    png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
+    offset_x       - positive offset from the left edge of the screen
+    offset_y       - positive offset from the top edge of the screen
+    unit_type      - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+    png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
+    res_x          - pixels/unit physical resolution in x direction
+    res_y          - pixels/unit physical resolution in x direction
+    unit_type      - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER
+
+For more information, see the png_info definition in png.h and the
 PNG specification for chunk contents.  Be careful with trusting
 rowbytes, as some of the transformations could increase the space
-needed to hold a row (expand, RGBX, XRGB, gray_to_rgb, etc.).
-See png_update_info(), below.
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
 
-A quick word about text and num_text.  PNG stores comments in
-keyword/text pairs, one pair per chunk.  While there are suggested
-keywords, there is no requirement to restrict the use to these
-strings.  There is a requirement to have at least one character for a
-keyword.  It is strongly suggested that keywords be sensible to humans
-(that's the point), so don't use abbreviations.  See the PNG
-specification for more details.  There is also no requirement to have
-text after the keyword.
+A quick word about text_ptr and num_text.  PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size.  While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings.  It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations or non-printing
+symbols.  See the PNG specification for more details.  There is also
+no requirement to have text after the keyword.
 
-Keywords should be limited to 80 characters without leading or trailing
-spaces, but non-consecutive spaces are allowed within the keyword.  It is
-possible to have the same keyword any number of times.  The text field
-is an array of png_text structures, each holding pointer to a keyword
-and a pointer to a text string.  Only the text string may be null.
-The keyword/text pairs are put into the array in the order that
-they are received.  However, some or all of the text chunks may be
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword.  It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding pointer
+to a keyword and a pointer to a text string.  Only the text string may
+be null.  The keyword/text pairs are put into the array in the order
+that they are received.  However, some or all of the text chunks may be
 after the image, so, to make sure you have read all the text chunks,
 don't mess with these until after you read the stuff after the image.
 This will be mentioned again below in the discussion that goes with
 png_read_end().
 
-After you've read the file information, you can set up the library to
-handle any special transformations of the image data.  The various
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data.  The various
 ways to transform the data will be described in the order that they
 should occur.  This is important, as some of these change the color
 type and/or bit depth of the data, and some others only work on
@@ -260,7 +322,7 @@
 are stored in the same format/depth as the image data in a bKGD or tRNS
 chunk, so this is what libpng expects for this data.  The colors are
 transformed to keep in sync with the image data when an application
-calls the png_update_info() routine (see below).
+calls the png_read_update_info() routine (see below).
 
 Data will be decoded into the supplied row buffers packed into bytes
 unless the library has been told to transform it into another format.
@@ -279,97 +341,141 @@
 grayscale images with bit depths of 2 or 4 or if there is a multiple-image
 viewing application that wishes to treat all images in the same way.
 
-   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
-      info_ptr->bit_depth < 8)
+    if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth < 8)
         png_set_expand(png_ptr);
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
-      info_ptr->bit_depth < 8)
-      png_set_expand(png_ptr);
+    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+        png_set_expand(png_ptr);
 
-   if (info_ptr->valid & PNG_INFO_tRNS)
-      png_set_expand(png_ptr);
+    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+        png_set_expand(png_ptr);
 
 PNG can have files with 16 bits per channel.  If you only can handle
 8 bits per channel, this will strip the pixels down to 8 bit.
 
-   if (info_ptr->bit_depth == 16)
-      png_set_strip_16(png_ptr);
+    if (bit_depth == 16)
+        png_set_strip_16(png_ptr);
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background:
+
+    if (color_type & PNG_COLOR_MASK_ALPHA)
+        png_set_strip_alpha(png_ptr);
 
 PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
 they can, resulting in, for example, 8 pixels per byte for 1 bit
 files.  This code expands to 1 pixel per byte without changing the
 values of the pixels:
 
-    if (info_ptr->bit_depth < 8)
+    if (bit_depth < 8)
         png_set_packing(png_ptr);
 
-PNG files have possible bit depths of 1, 2, 4, 8, and 16.  It is then
-required that values be "scaled" or "shifted" up to the bit depth used
-in the file (ie from 5 bits/sample in the range [0,31] to 8 bits/sample
-in the range [0, 255]).  However, they also provide a way to describe
-the true bit depth of the image.  See the PNG specification for details.
-This call reduces the pixels back down to the true bit depth:
+PNG files have possible bit depths of 1, 2, 4, 8, and 16.  All pixels
+stored in a PNG image whave been "scaled" or "shifted" up to the next
+higher possible bit depth (eg from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]).  However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
 
-    if (info_ptr->valid & PNG_INFO_sBIT)
-        png_set_shift(png_ptr, &(info_ptr->sig_bit));
+    png_color_16p sig_bit;
 
-PNG files store 3 color pixels in red, green, blue order.  This code
+    if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+        png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order.  This code
 changes the storage of the pixels to blue, green, red:
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-        info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+    if (color_type == PNG_COLOR_TYPE_RGB ||
+        color_type == PNG_COLOR_TYPE_RGB_ALPHA)
         png_set_bgr(png_ptr);
 
 PNG files store RGB pixels packed into 3 bytes. This code expands them
 into 4 bytes for windowing systems that need them in this format:
 
-   if (info_ptr->bit_depth == 8 &&
-      info_ptr->color_type == PNG_COLOR_TYPE_RGB)
-      png_set_filler(png_ptr, filler_byte, PNG_FILLER_BEFORE);
+    if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB)
+        png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);
 
-where filler_byte is the number to fill with, and the location is
+where "filler" is the number to fill with, and the location is
 either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
-you want the filler before the RGB or after.
+you want the filler before the RGB or after.  This transformation
+does not affect images that already have full alpha channels.
 
-For some uses, you may want a gray-scale image to be represented as
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+        png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
 RGB.  This code will do that conversion:
 
-   if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-         png_set_gray_to_rgb(png_ptr);
+    if (color_type == PNG_COLOR_TYPE_GRAY ||
+        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+          png_set_gray_to_rgb(png_ptr);
 
-The following code handles alpha and transparency by replacing it with
-a background value.  If there was a valid bKGD in the file, you can use
-it if you want.  However, you can replace it with your own if you want
-also.  If there wasn't one in the file, you must supply a color.  If
-libpng is doing gamma correction, you will need to tell libpng where
-the background came from so it can do the appropriate gamma
-correction.  If you have a grayscale and you are using png_set_expand()
-to change to a higher bit-depth you must indicate if the background gray
-needs to be expanded to the new bit-depth.  Similarly, if you are reading
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color.  If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page).  You
+need to tell libpng whether the color is in the gamma space of the
+dispay (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+If you have a grayscale and you are using png_set_expand() to change to
+a higher bit-depth you must indicate if the supplied background gray
+is supplied in the original file bit depth (need_expand = 1) or in the
+expanded bit depth (need_expand = 0).  Similarly, if you are reading
 a paletted image, you must indicate if you have supplied the background
-index that needs to be expanded to RGB values.  You can always specify
-RGB color values directly when setting your background for paletted images.
+as a palette index that needs to be expanded (need_expand = 1).  You can
+also specify an RGB triplet that isn't in the palette when setting your
+background for a paletted image.
 
-   png_color_16 my_background;
+    png_color_16 my_background;
+    png_color_16p image_background;
 
-   if (info_ptr->valid & PNG_INFO_bKGD)
-      png_set_backgrond(png_ptr, &(info_ptr->background),
-            PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+    if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+        png_set_background(png_ptr, image_background),
+             PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+    else
+        png_set_background(png_ptr, &my_background,
+          PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is.  Ideally, the user will know this, and
+the application will allow them to set it.  One method of allowing the user
+to set the display gamma separately for each system is to check for the
+DISPLAY_GAMMA environment variable, which will hopefully be correctly set.
+
+   if (/* We have a user-defined screen gamma value */)
+   {
+      screen_gamma = user_defined_screen_gamma;
+   }
+   /* One way that applications can share the same screen gamma value */
+   else if ((gamma_str = getenv("DISPLAY_GAMMA")) != NULL)
+   {
+      screen_gamma = atof(gamma_str);
+   }
+   /* If we don't have another value */
    else
-      png_set_background(png_ptr, &my_background,
-         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+   {
+      screen_gamma = 2.2;  /* A good guess for PC monitors */
+      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
+   }
 
-The following code handles gamma transformations of the data.  Pass
-both the file gamma and the desired screen gamma.  If the file does
-not have a gamma value, you can pass one anyway if you wish.  Note
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma.  If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45 is a good guess for GIF images on PCs).  Note
 that file gammas are inverted from screen gammas.  See the discussions
-on gamma in the PNG specification for more information.  It is
-strongly recommended that viewers support gamma correction.
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it.  It is strongly
+recommended that PNG viewers support gamma correction.
 
-   if (info_ptr->valid & PNG_INFO_gAMA)
-      png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
+   if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+      png_set_gamma(png_ptr, screen_gamma, gamma);
    else
       png_set_gamma(png_ptr, screen_gamma, 0.45);
 
@@ -384,13 +490,15 @@
 more intelligent choices when reducing the palette.  If there is no
 histogram, it may not do as good a job.
 
-   if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+   if (color_type & PNG_COLOR_MASK_COLOR)
    {
-      if (info_ptr->valid & PNG_INFO_PLTE)
+      if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
       {
-         png_set_dither(png_ptr, info_ptr->palette,
-            info_ptr->num_palette, max_screen_colors,
-            info_ptr->histogram, 1);
+         png_color_16p histogram;
+
+         png_get_hIST(png_ptr, info_ptr, &histogram);
+         png_set_dither(png_ptr, palette, num_palette, max_screen_colors,
+            histogram, 1);
       }
       else
       {
@@ -406,8 +514,7 @@
 The following code will reverse this (make black be one and white be
 zero):
 
-   if (info_ptr->bit_depth == 1 &&
-      info_ptr->color_type == PNG_COLOR_GRAY)
+   if (bit_depth == 1 && color_type == PNG_COLOR_GRAY)
       png_set_invert_mono(png_ptr);
 
 PNG files store 16 bit pixels in network byte order (big-endian,
@@ -415,19 +522,24 @@
 other way (little-endian, ie. least significant bits first, eg. the
 way PCs store them):
 
-    if (info_ptr->bit_depth == 16)
+    if (bit_depth == 16)
         png_set_swap(png_ptr);
 
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+    if (bit_depth < 8)
+       png_set_packswap(png_ptr);
+
 The last thing to handle is interlacing; this is covered in detail below,
 but you must call the function here.
 
-   if (info_ptr->interlace_type)
-      number_passes = png_set_interlace_handling(png_ptr);
+    number_passes = png_set_interlace_handling(png_ptr);
 
 After setting the transformations, libpng can update your png_info
 structure to reflect any transformations you've requested with this
-call.  This is most useful to update the info structures rowbytes
-field, so you can use it to allocate your image memory.  This function
+call.  This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory.  This function
 will also update your palette with the correct display gamma and
 background if these have been given with the calls above.
 
@@ -462,7 +574,7 @@
 
 If you don't want to read int the whole image at once, you can
 use png_read_rows() instead.  If there is no interlacing (check
-info_ptr->interlace_type), this is simple:
+interlace_type == PNG_INTERLACE_TYPE_NONE), this is simple:
 
     png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
 
@@ -475,11 +587,11 @@
     png_read_row(png_ptr, &row_pointers, NULL);
 
 If the file is interlaced (info_ptr->interlace_type != 0), things get
-somewhat harder.  The only currently (as of 6/96 -- PNG
-Specification version 1.0) defined interlacing scheme for PNG files
-(info_ptr->interlace_type == 1) is a someewhat complicated 2D interlace
-scheme, known as Adam7, that breaks down an image into seven smaller
-images of varying size, based on an 8x8 grid.
+somewhat harder.  The only current (PNG Specification version 1.0)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_TYPE_ADAM7)
+is a someewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
 
 libpng can fill out those images or it can give them to you "as is".
 If you want them filled out, there are two ways to do that.  The one
@@ -515,7 +627,7 @@
 If you want libpng to expand the images, call this before calling
 png_start_read_image() or png_read_update_info():
 
-    if (info_ptr->interlace_type)
+    if (interlace_type == PNG_INTERLACE_TYPE_ADAM7)
         number_passes = png_set_interlace_handling(png_ptr);
 
 This will return the number of passes needed.  Currently, this
@@ -755,7 +867,7 @@
         return;
     }
 
-Now you need to set up the input code.  The default for libpng is to
+Now you need to set up the output code.  The default for libpng is to
 use the C function fwrite().  If you use this, you will need to pass a
 valid FILE * in the function png_init_io().  Be sure that the file is
 opened in binary mode.  Again, if you wish to handle writing data in
@@ -810,32 +922,74 @@
 
 Some of the more important parts of the png_info are:
 
-    width          - holds the width of the file
-    height         - holds the height of the file
-    bit_depth      - holds the bit depth of one of the image channels
-    color_type     - describes the channels and what they mean
-                     see the PNG_COLOR_TYPE_ defines for more information
-    interlace_type - allowed values are 0 for none, 1 for interlaced
-    valid          - this describes which optional chunks to write to the
-                     file.  Note that if you are writing a
-                     PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not
-                     optional, but must still be marked for writing.  To
-                     mark chunks for writing, logical OR '|' valid with
-                     the appropriate PNG_INFO_<chunk name> define.
-    palette        - the palette for the file (PNG_INFO_PLTE)
+    png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type,
+       interlace_type,
+    width          - holds the width of the image in pixels (up to 2^31).
+    height         - holds the height of the image in pixels (up to 2^31).
+    bit_depth      - holds the bit depth of one of the image channels.
+                     (valid values are 1, 2, 4, 8, 16 and depend also on the
+                      color_type.  See also significant bits (sBIT) below).
+    color_type     - describes which color/alpha channels are present.
+                     PNG_COLOR_TYPE_GRAY        (bit depths 1, 2, 4, 8, 16)
+                     PNG_COLOR_TYPE_GRAY_ALPHA  (bit depths 8, 16)
+                     PNG_COLOR_TYPE_PALETTE     (bit depths 1, 2, 4, 8)
+                     PNG_COLOR_TYPE_RGB         (bit_depths 8, 16)
+                     PNG_COLOR_TYPE_RGB_ALPHA   (bit_depths 8, 16)
+
+                     PNG_COLOR_MASK_PALETTE
+                     PNG_COLOR_MASK_COLOR
+                     PNG_COLOR_MASK_ALPHA
+
+    interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTER_LACE_TYPE_ADAM7
+    compression_type - (must be PNG_COMPRESSION_TYPE_DEFAULT for PNG 1.0)
+    filter_type    - (must be PNG_FILTER_TYPE_DEFAULT for PNG 1.0)
+    Any or all of interlace_type, compression_type, of filter_type can be
+    NULL if you are not interested in their values.
+
+    png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+    palette        - the palette for the file (array of png_color)
     num_palette    - number of entries in the palette
-    gamma          - the gamma the file is written at (PNG_INFO_gAMA)
-    sig_bit        - the number of significant bits (PNG_INFO_sBIT)
-                     for the gray, red, green, and blue channels, whichever
-                     are appropriate for the given color type.
+
+    png_set_gAMA(png_ptr, info_ptr, gamma);
+    gamma          - the gamma the image was created at (PNG_INFO_gAMA)
+
+    png_set_sBIT(png_ptr, info_ptr, sig_bit);
+    sig_bit        - the number of significant bits for (PNG_INFO_sBIT)
+                     the gray, red, green, and blue channels, whichever
+                     are appropriate for the given color type (png_color_16)
+
+    png_set_tRNS(png_ptr, info_ptr, trans, num_trans, trans_values);
+    trans          - array of transparent entries for palette (PNG_INFO_tRNS)
     trans_values   - transparent pixel for non-paletted images (PNG_INFO_tRNS)
-    trans          - array of transparent entries for paletted images
-    num_trans      - number of transparent entries
-    hist           - histogram of palette (PNG_INFO_hIST)
+    num_trans      - number of transparent entries (PNG_INFO_tRNS)
+
+    png_set_hIST(png_ptr, info_ptr, hist);        (PNG_INFO_hIST)
+    hist           - histogram of palette (array of png_color_16)
+
+    png_set_tIME(png_ptr, info_ptr, mod_time);
     mod_time       - time image was last modified (PNG_VALID_tIME)
+
+    png_set_bKGD(png_ptr, info_ptr, background);
     background     - background color (PNG_VALID_bKGD)
-    text           - text comments in the file.
-    num_text       - number of comments
+
+    png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+    text_ptr       - array of png_text holding image comments
+    text_ptr[i]->key         - keyword for comment.
+    text_ptr[i]->text        - text comments for current keyword.
+    text_ptr[i]->compression - type of compression used on "text"
+                               PNG_TEXT_COMPRESSION_NONE or
+                               PNG_TEXT_COMPRESSION_zTXt
+    num_text       - number of comments in text_ptr
+
+    png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+    offset_x       - positive offset from the left edge of the screen
+    offset_y       - positive offset from the top edge of the screen
+    unit_type      - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+    png_get_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+    res_x          - pixels/unit physical resolution in x direction
+    res_y          - pixels/unit physical resolution in x direction
+    unit_type      - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER
 
 A quick word about text and num_text.  text is an array of png_text
 structures.  num_text is the number of valid structures in the array.
@@ -846,8 +1000,12 @@
 types of the image data.  Currently, the only valid number is zero.
 However, you can store text either compressed or uncompressed, unlike
 images which always have to be compressed.  So if you don't want the
-text compressed, set the compression type to -1.  Until text gets
-around 1000 bytes, it is not worth compressing it.
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
 
 The keywords that are given in the PNG Specification are:
 
@@ -889,7 +1047,8 @@
 these, but if you wish to fill in the png_time structure directly,
 you should provide the time in universal time (GMT) if possible
 instead of your local time.  Note that the year number is the full
-year (ie 1996, rather than 96), and that months start with 1.
+year (ie 1996, rather than 96 - PNG is year 2000 compliant!), and
+that months start with 1.
 
 You are now ready to write all the file information up to the actual
 image data.  You do this with a call to png_write_info().
@@ -926,39 +1085,44 @@
 data is of another bit depth, you can write an sBIT chunk into the
 file so that decoders can get the original data if desired.
     
-    /* Do this before png_write_info() */
-    info_ptr->valid |= PNG_INFO_sBIT;
-
     /* Set the true bit depth of the image data */
-    if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+    if (color_type & PNG_COLOR_MASK_COLOR)
     {
-        info_ptr->sig_bit.red = true_bit_depth;
-        info_ptr->sig_bit.green = true_bit_depth;
-        info_ptr->sig_bit.blue = true_bit_depth;
+        sig_bit.red = true_bit_depth;
+        sig_bit.green = true_bit_depth;
+        sig_bit.blue = true_bit_depth;
     }
     else
     {
-        info_ptr->sig_bit.gray = true_bit_depth;
+        sig_bit.gray = true_bit_depth;
+    }
+    if (color_type & PNG_COLOR_MASK_ALPHA)
+    {
+        sig_bit.alpha = true_bit_depth;
     }
 
-    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
-    {
-        info_ptr->sig_bit.alpha = true_bit_depth;
-    }
+    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
 
 If the data is stored in the row buffer in a bit depth other than
 one supported by PNG (ie 3 bit data in the range 0-7 for a 4-bit PNG),
 this will scale the values to appear to be the correct bit depth as
 is required by PNG.
 
-    png_set_shift(png_ptr, &(info_ptr->sig_bit));
+    png_set_shift(png_ptr, &sig_bit);
 
 PNG files store 16 bit pixels in network byte order (big-endian,
 ie. most significant bits first).  This code would be used if they are
 supplied the other way (little-endian, ie. least significant bits
 first, eg. the way PCs store them):
 
-    png_set_swap(png_ptr);
+    if (bit_depth > 8)
+       png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+    if (bit_depth < 8)
+       png_set_packswap(png_ptr);
 
 PNG files store 3 color pixels in red, green, blue order.  This code
 would be used if they are supplied as blue, green, red:
@@ -1056,9 +1220,7 @@
 After you are finished writing the image, you should finish writing
 the file.  If you are interested in writing comments or time, you should
 pass the an appropriately filled png_info pointer.  If you
-are not interested, you can pass NULL.  If you have written text at
-the beginning and are not writing more at the end, you should set
-info_ptr->num_text = 0, or the text will be written again here.
+are not interested, you can pass NULL.
 
     png_write_end(png_ptr, info_ptr);
 
@@ -1079,26 +1241,27 @@
 The second deals with more complicated things like adding new chunks,
 adding new transformations, and generally changing how libpng works.
 
-All of the memory allocation, input/output, and error handling in
-libpng goes through callbacks which are user setable.  The default
-routines are in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively.
-To change these functions, call the approprate png_set_???_fn() function.
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks which are user setable.  The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively.  To change
+these functions, call the approprate png_set_???_fn() function.
 
 Memory allocation is done through the functions png_large_malloc(),
 png_malloc(), png_realloc(), png_large_free(), and png_free().  These
 currently just call the standard C functions.  The large functions must
 handle exactly 64K, but they don't have to handle more than that.  If
-your pointers can't access more then 64K at a time, you will want to
-set MAXSEG_64K in zlib.h.  Since it is unlikely that the method of
-handling memory allocation on a platform will change between applications,
-these functions must be modified in the library at compile time.
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h.  Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time.
 
-Input/Output in libpng is done throught png_read() and png_write(), which
-currently just call fread() and fwrite().  The FILE * is stored in
-png_struct, and is initialized via png_init_io().  If you wish to change
-the method of I/O, the library supplies callbacks that you can set through
-the function png_set_read_fn() and png_set_write_fn() at run time.  These
-functions also provide a void pointer that can be retrieved via the function
+Input/Output in libpng is done throught png_read() and png_write(),
+which currently just call fread() and fwrite().  The FILE * is stored in
+png_struct and is initialized via png_init_io().  If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function.  These functions
+also provide a void pointer that can be retrieved via the function
 png_get_io_ptr().  For example:
 
     png_set_read_fn(png_structp png_ptr, voidp io_ptr,
@@ -1123,7 +1286,7 @@
 
 Error handling in libpng is done through png_error() and png_warning().
 Errors handled through png_error() are fatal, meaning that png_error()
-should never return to it's caller.  Currently, this is handled via
+should never return to its caller.  Currently, this is handled via
 setjmp() and longjmp(), but you could change this to do things like
 exit() if you should wish.  On non-fatal errors, png_warning() is called
 to print a warning message, and then control returns to the calling code.
@@ -1152,7 +1315,7 @@
 as there is no need to check every return code of every function call.
 However, there are some uncertainties about the status of local variables
 after a longjmp, so the user may want to be careful about doing anything after
-setjmp returns non zero besides returning itself.  Consult your compiler
+setjmp returns non-zero besides returning itself.  Consult your compiler
 documentation for more details.
 
 If you need to read or write custom chunks, you will need to get deeper
@@ -1220,16 +1383,16 @@
 There are special functions to configure the compression.  Perhaps the
 most useful one changes the compression level, which currently uses
 input compression values in the range 0 - 9.  The library normally
-uses the default compression level (Z_DEFAULT_COMPRESSION = 6), but if
-speed is not critical it is possible to configure it for maximum
-compression (Z_BEST_COMPRESSION = 9) to generate smaller PNG files.
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6).  Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress as well as higher levels, and do so much faster.
 For online applications it may be desirable to have maximum speed
 (Z_BEST_SPEED = 1).  With versions of zlib after v0.99, you can also
 specify no compression (Z_NO_COMPRESSION = 0), but this would create
 files larger than just storing the raw bitmap.  You can specify the
 compression level by calling:
 
-    png_set_compression_mem_level(png_ptr, level);
+    png_set_compression_level(png_ptr, level);
 
 Another useful one is to reduce the memory level used by the library.
 The memory level defaults to 8, but it can be lowered if you are
@@ -1237,9 +1400,20 @@
 
     png_set_compression_mem_level(png_ptr, level);
 
-If you want to control whether libpng uses filtering or not, you
-can call this function.  Filtering is enabled by default for RGB
-and grayscale images (with and without alpha), and for 8-bit
+The other functions are for configuring zlib.  They are not recommended
+for normal use and may result in writing an invalid PNG file.  See
+zlib.h for more information on what these mean.
+
+    png_set_compression_strategy(png_ptr, strategy);
+    png_set_compression_window_bits(png_ptr, window_bits);
+    png_set_compression_method(png_ptr, method);
+
+Controlling row filtering:
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions.  Filtering is enabled by default for
+RGB and grayscale images (with and without alpha), and for 8-bit
 paletted images, but not for paletted images with bit depths less
 than 8 bits/pixel.  The 'method' parameter sets the main filtering
 method, which is currently only '0' in the PNG 1.0 specification.
@@ -1255,23 +1429,46 @@
 you intend to use so that libpng can initialize its internal
 structures appropriately for all of the filter types.
 
-    png_set_filter(png_ptr, method, filters);
+    filters = PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP;
+    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
 
-The other functions are for configuring zlib.  They are not recommended
-for normal use and may result in writing an invalid PNG file.  See
-zlib.h for more information on what these mean.
+It is also possible to influence how libpng chooses from among the
+available filters.  This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
 
-    png_set_compression_strategy(png_ptr, strategy);
-    png_set_compression_window_bits(png_ptr, window_bits);
-    png_set_compression_method(png_ptr, method);
+    double weights[3] = {1.5, 1.3, 1.1},
+           costs[PNG_FILTER_VALUE_LAST] = {1.0, 1.3, 1.3, 1.5, 1.7};
 
-Except for png_set_filter(), all of these are just controlling zlib,
-so see the zlib documentation (zlib.h and zconf.h) for more information.
+    png_set_filter_selection(png_ptr, PNG_FILTER_SELECTION_WEIGHTED,
+       3, weights, costs);
+
+The weights are multiplying factors which indicate to libpng that row
+should be the same for successive rows unless another row filter is that
+many times better than the previous filter.  In the above example, if
+the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen.  Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters.  This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduely influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage.  Little testing has
+been done to find optimum values for either the costs or the weights.
 
 Removing unwanted object code:
 
 There are a bunch of #define's in pngconf.h that control what parts of
-libpng are compiled.  All the defines end in _SUPPORT.  If you are
+libpng are compiled.  All the defines end in _SUPPORTED.  If you are
 never going to use an ability, you can change the #define to #undef
 before recompiling libpng and save yourself code and data space.  All
 the reading and writing specific code are in seperate files, so the
@@ -1283,32 +1480,34 @@
 The progressive reader is in pngpread.c
 
 If you are creating or distributing a dynamically linked library (a .so
-or DLL file), you should not remove or disable any parts of the
-library, as this will cause applications linked with different versions
-of the library to fail if they call functions not available in your
-library.  The size of the library itself should not be an issue, because
-only those sections which are actually used will be loaded into memory.
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections which are actually used will be loaded into memory.
 
-Changes to Libpng from version 0.88 to version 0.89
 
-It should be noted that version 0.89 of libpng is not distributed by
-the original author, Guy Schalnat, but rather Andreas Dilger, although
-all of the copyright messages have been left in Guy's name.
+Changes to Libpng from version 0.88
 
-The old libpng functions png_read_init(), png_write_init() and
-png_info_init() still exist in the 0.89 version of the library, as
-do png_read_destroy() and png_write_destroy().  The preferred method
-of creating and initializing the libpng structures is via the
-png_create_read_struct(), png_create_write_struct(), and
+It should be noted that versions of libpng later than 0.88 are not
+distributed by the original libpng author, Guy Schalnat, but rather
+another member of the original PNG Group, Andreas Dilger.  Guy is still
+alive and well, but he has moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destory() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use.  The
+preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
 png_create_info_struct() because they isolate the size of the structures
-from the application, allow version error checking, and also allow
-the use of custom error handling routines during the initialization,
-which the old functions do not.   The functions png_read_destroy() and
-png_write_destroy() do not actually free the memory that libpng allocated
-for these structs, but just reset the data structures, so they can be
-used instead of png_destroy_read_struct() and png_destroy_write_struct()
-if you feel there is too much system overhead allocating and freeing the
-png_struct for each image read.
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not.  The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
 
 Setting the error callbacks via png_set_message_fn() before
 png_read_init() as was suggested in libpng-0.88 is no longer supported
@@ -1316,5 +1515,5 @@
 to fail if the png_ptr was not initialized to zero.  It is still possible
 to set the error callbacks AFTER png_read_init(), or to change them with
 png_set_error_fn(), which is essentially the same function, but with a
-new name to force compilation errors with the new library.
-
+new name to force compilation errors with applications that try to use
+the old method.
diff --git a/makefile b/makefile
index 9d28c56..ebe000b 100644
--- a/makefile
+++ b/makefile
@@ -2,17 +2,23 @@
 # Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
 # For conditions of distribution and use, see copyright notice in png.h
 
-CC=cc
-CFLAGS=-I../zlib -O
-LDFLAGS=-L. -L../zlib/ -lpng -lz -lm
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
 
-#RANLIB=ranlib
-RANLIB=echo
+CC=cc
+CFLAGS=-I$(ZLIBINC) -O # -g -DPNG_DEBUG=1
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+#RANLIB=echo
+RANLIB=ranlib
 
 # where make install puts libpng.a and png.h
 prefix=/usr/local
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
 	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
 	pngwtran.o pngmem.o pngerror.o pngpread.o
 
@@ -48,7 +54,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
 pngrutil.o: png.h pngconf.h
diff --git a/makefile.aco b/makefile.aco
index 27915f3..2cb0898 100644
--- a/makefile.aco
+++ b/makefile.aco
@@ -13,23 +13,25 @@
 
 # Final targets:
 @.libpng-lib:   @.o.png @.o.pngerror @.o.pngrio @.o.pngwio @.o.pngmem \
-        @.o.pngpread @.o.pngrcb @.o.pngread @.o.pngrtran @.o.pngrutil @.o.pngtrans @.o.pngwrite \
-        @.o.pngwtran @.o.pngwutil 
-        LibFile $(LibFileflags) @.o.png @.o.pngerror @.o.pngrio @.o.pngwio \
-        @.o.pngmem @.o.pngpread @.o.pngrcb @.o.pngread @.o.pngrtran @.o.pngrutil @.o.pngtrans \
-        @.o.pngwrite @.o.pngwtran @.o.pngwutil 
+        @.o.pngpread @.o.pngset @.o.pngget @.o.pngread @.o.pngrtran \
+        @.o.pngrutil @.o.pngtrans @.o.pngwrite @.o.pngwtran @.o.pngwutil 
+        LibFile $(LibFileflags) @.o.png @.o.pngerror @.o.pngrio @.o.pngrtran \
+        @.o.pngmem @.o.pngpread @.o.pngset @.o.pngget @.o.pngread @.o.pngwio \
+        @.o.pngrutil @.o.pngtrans  @.o.pngwrite @.o.pngwtran @.o.pngwutil 
 @.mm-libpng-lib:   @.mm.png @.mm.pngerror @.mm.pngrio @.mm.pngwio @.mm.pngmem \
-        @.mm.pngpread @.mm.pngrcb @.mm.pngread @.mm.pngrtran @.mm.pngrutil @.mm.pngtrans \
-        @.mm.pngwrite @.mm.pngwtran @.mm.pngwutil 
-        LibFile $(LibFileflags) @.mm.png @.mm.pngerror @.mm.pngrio @.mm.pngwio \
-        @.mm.pngmem @.mm.pngpread @.mm.pngrcb @.mm.pngread @.mm.pngrtran @.mm.pngrutil \
-        @.mm.pngtrans @.mm.pngwrite @.mm.pngwtran @.mm.pngwutil 
+        @.mm.pngpread @.mm.pngset @.mm.pngget @.mm.pngread @.mm.pngrtran \
+        @.mm.pngrutil @.mm.pngtrans @.mm.pngwrite @.mm.pngwtran @.mm.pngwutil 
+        LibFile $(LibFileflags) @.mm.png @.mm.pngerror @.mm.pngrio \
+        @.mm.pngwio @.mm.pngmem @.mm.pngpread @.mm.pngset @.mm.pngget \
+        @.mm.pngread @.mm.pngrtran @.mm.pngrutil @.mm.pngtrans @.mm.pngwrite \
+        @.mm.pngwtran @.mm.pngwutil 
 
 
 # User-editable dependencies:
+# (C) Copyright 1997 Tom Tanner
 Test: @.pngtest 
-        <Prefix$Dir>.PngTest
-        @remove <Prefix$Dir>.pngout_png
+        <Prefix$Dir>.pngtest
+        @remove <Prefix$Dir>.pngtest
 
 #It would be nice if you could stop "make" listing from here on!
 @.pngtest:   @.o.pngtest @.libpng-lib C:o.Stubs Zlib:zlib_lib 
@@ -47,3 +49,173 @@
 
 
 # Dynamic dependencies:
+o.pngtest:	c.pngtest
+o.pngtest:	h.png
+o.pngtest:	Zlib:h.zlib
+o.pngtest:	Zlib:h.zconf
+o.pngtest:	h.pngconf
+mm.png:		LibPng:c.png
+mm.png:		LibPng:h.png
+mm.png:		Zlib:h.zlib
+mm.png:		Zlib:h.zconf
+mm.png:		LibPng:h.pngconf
+mm.png:		MemCheck:ANSI.h.stdio
+mm.pngerror:	LibPng:c.pngerror
+mm.pngerror:	LibPng:h.png
+mm.pngerror:	Zlib:h.zlib
+mm.pngerror:	Zlib:h.zconf
+mm.pngerror:	LibPng:h.pngconf
+mm.pngerror:	MemCheck:ANSI.h.stdio
+mm.pngrio:	LibPng:c.pngrio
+mm.pngrio:	LibPng:h.png
+mm.pngrio:	Zlib:h.zlib
+mm.pngrio:	Zlib:h.zconf
+mm.pngrio:	LibPng:h.pngconf
+mm.pngrio:	MemCheck:ANSI.h.stdio
+mm.pngwio:	LibPng:c.pngwio
+mm.pngwio:	LibPng:h.png
+mm.pngwio:	Zlib:h.zlib
+mm.pngwio:	Zlib:h.zconf
+mm.pngwio:	LibPng:h.pngconf
+mm.pngwio:	MemCheck:ANSI.h.stdio
+mm.pngmem:	LibPng:c.pngmem
+mm.pngmem:	LibPng:h.png
+mm.pngmem:	Zlib:h.zlib
+mm.pngmem:	Zlib:h.zconf
+mm.pngmem:	LibPng:h.pngconf
+mm.pngmem:	MemCheck:ANSI.h.stdio
+mm.pngpread:	LibPng:c.pngpread
+mm.pngpread:	LibPng:h.png
+mm.pngpread:	Zlib:h.zlib
+mm.pngpread:	Zlib:h.zconf
+mm.pngpread:	LibPng:h.pngconf
+mm.pngpread:	MemCheck:ANSI.h.stdio
+mm.pngset:	LibPng:c.pngset
+mm.pngset:	LibPng:h.png
+mm.pngset:	Zlib:h.zlib
+mm.pngset:	Zlib:h.zconf
+mm.pngset:	LibPng:h.pngconf
+mm.pngset:	MemCheck:ANSI.h.stdio
+mm.pngget:	LibPng:c.pngget
+mm.pngget:	LibPng:h.png
+mm.pngget:	Zlib:h.zlib
+mm.pngget:	Zlib:h.zconf
+mm.pngget:	LibPng:h.pngconf
+mm.pngget:	MemCheck:ANSI.h.stdio
+mm.pngread:	LibPng:c.pngread
+mm.pngread:	LibPng:h.png
+mm.pngread:	Zlib:h.zlib
+mm.pngread:	Zlib:h.zconf
+mm.pngread:	LibPng:h.pngconf
+mm.pngread:	MemCheck:ANSI.h.stdio
+mm.pngrtran:	LibPng:c.pngrtran
+mm.pngrtran:	LibPng:h.png
+mm.pngrtran:	Zlib:h.zlib
+mm.pngrtran:	Zlib:h.zconf
+mm.pngrtran:	LibPng:h.pngconf
+mm.pngrtran:	MemCheck:ANSI.h.stdio
+mm.pngrutil:	LibPng:c.pngrutil
+mm.pngrutil:	LibPng:h.png
+mm.pngrutil:	Zlib:h.zlib
+mm.pngrutil:	Zlib:h.zconf
+mm.pngrutil:	LibPng:h.pngconf
+mm.pngrutil:	MemCheck:ANSI.h.stdio
+mm.pngtrans:	LibPng:c.pngtrans
+mm.pngtrans:	LibPng:h.png
+mm.pngtrans:	Zlib:h.zlib
+mm.pngtrans:	Zlib:h.zconf
+mm.pngtrans:	LibPng:h.pngconf
+mm.pngtrans:	MemCheck:ANSI.h.stdio
+mm.pngwrite:	LibPng:c.pngwrite
+mm.pngwrite:	LibPng:h.png
+mm.pngwrite:	Zlib:h.zlib
+mm.pngwrite:	Zlib:h.zconf
+mm.pngwrite:	LibPng:h.pngconf
+mm.pngwrite:	MemCheck:ANSI.h.stdio
+mm.pngwtran:	LibPng:c.pngwtran
+mm.pngwtran:	LibPng:h.png
+mm.pngwtran:	Zlib:h.zlib
+mm.pngwtran:	Zlib:h.zconf
+mm.pngwtran:	LibPng:h.pngconf
+mm.pngwtran:	MemCheck:ANSI.h.stdio
+mm.pngwutil:	LibPng:c.pngwutil
+mm.pngwutil:	LibPng:h.png
+mm.pngwutil:	Zlib:h.zlib
+mm.pngwutil:	Zlib:h.zconf
+mm.pngwutil:	LibPng:h.pngconf
+mm.pngwutil:	MemCheck:ANSI.h.stdio
+o.png:		c.png
+o.png:		h.png
+o.png:		Zlib:h.zlib
+o.png:		Zlib:h.zconf
+o.png:		h.pngconf
+o.pngerror:	c.pngerror
+o.pngerror:	h.png
+o.pngerror:	Zlib:h.zlib
+o.pngerror:	Zlib:h.zconf
+o.pngerror:	h.pngconf
+o.pngrio:	c.pngrio
+o.pngrio:	h.png
+o.pngrio:	Zlib:h.zlib
+o.pngrio:	Zlib:h.zconf
+o.pngrio:	h.pngconf
+o.pngwio:	c.pngwio
+o.pngwio:	h.png
+o.pngwio:	Zlib:h.zlib
+o.pngwio:	Zlib:h.zconf
+o.pngwio:	h.pngconf
+o.pngmem:	c.pngmem
+o.pngmem:	h.png
+o.pngmem:	Zlib:h.zlib
+o.pngmem:	Zlib:h.zconf
+o.pngmem:	h.pngconf
+o.pngpread:	c.pngpread
+o.pngpread:	h.png
+o.pngpread:	Zlib:h.zlib
+o.pngpread:	Zlib:h.zconf
+o.pngpread:	h.pngconf
+o.pngset:	c.pngset
+o.pngset:	h.png
+o.pngset:	Zlib:h.zlib
+o.pngset:	Zlib:h.zconf
+o.pngset:	h.pngconf
+o.pngget:	c.pngget
+o.pngget:	h.png
+o.pngget:	Zlib:h.zlib
+o.pngget:	Zlib:h.zconf
+o.pngget:	h.pngconf
+o.pngread:	c.pngread
+o.pngread:	h.png
+o.pngread:	Zlib:h.zlib
+o.pngread:	Zlib:h.zconf
+o.pngread:	h.pngconf
+o.pngrtran:	c.pngrtran
+o.pngrtran:	h.png
+o.pngrtran:	Zlib:h.zlib
+o.pngrtran:	Zlib:h.zconf
+o.pngrtran:	h.pngconf
+o.pngrutil:	c.pngrutil
+o.pngrutil:	h.png
+o.pngrutil:	Zlib:h.zlib
+o.pngrutil:	Zlib:h.zconf
+o.pngrutil:	h.pngconf
+o.pngtrans:	c.pngtrans
+o.pngtrans:	h.png
+o.pngtrans:	Zlib:h.zlib
+o.pngtrans:	Zlib:h.zconf
+o.pngtrans:	h.pngconf
+o.pngwrite:	c.pngwrite
+o.pngwrite:	h.png
+o.pngwrite:	Zlib:h.zlib
+o.pngwrite:	Zlib:h.zconf
+o.pngwrite:	h.pngconf
+o.pngwtran:	c.pngwtran
+o.pngwtran:	h.png
+o.pngwtran:	Zlib:h.zlib
+o.pngwtran:	Zlib:h.zconf
+o.pngwtran:	h.pngconf
+o.pngwutil:	c.pngwutil
+o.pngwutil:	h.png
+o.pngwutil:	Zlib:h.zlib
+o.pngwutil:	Zlib:h.zconf
+o.pngwutil:	h.pngconf
diff --git a/makefile.ama b/makefile.ama
index c56ff25..366524d 100644
--- a/makefile.ama
+++ b/makefile.ama
@@ -22,7 +22,7 @@
 # make directory command
 MKDIR= makedir
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o pngpread.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o pngpread.o \
 pngread.o pngerror.o pngwrite.o pngrtran.o pngwtran.o pngrio.o pngwio.o pngmem.o
 
 all: libpng.lib pngtest
diff --git a/makefile.atr b/makefile.atr
index 9adc65a..d490ce1 100644
--- a/makefile.atr
+++ b/makefile.atr
@@ -10,7 +10,7 @@
 
 # where make install puts libpng.a and png.h
 
-OBJS = $(LBR)(png.o) $(LBR)(pngrcb.o) $(LBR)(pngrutil.o)\
+OBJS = $(LBR)(png.o) $(LBR)(pngset.o) $(LBR)(pngget.o) $(LBR)(pngrutil.o)\
 	$(LBR)(pngtrans.o) $(LBR)(pngwutil.o)\
 	$(LBR)(pngread.o) $(LBR)(pngerror.o) $(LBR)(pngwrite.o)\
 	$(LBR)(pngrtran.o) $(LBR)(pngwtran.o)\
diff --git a/makefile.bor b/makefile.bor
index 3b8cf50..0b7c0e6 100644
--- a/makefile.bor
+++ b/makefile.bor
@@ -74,7 +74,8 @@
  pngerror.$(O) \
  pngmem.$(O) \
  pngpread.$(O) \
- pngrcb.$(O) \
+ pngset.$(O) \
+ pngget.$(O) \
  pngread.$(O) \
  pngrio.$(O) \
  pngrtran.$(O) \
@@ -91,7 +92,8 @@
  +pngmem.$(O) \
  +pngpread.$(O) \
  +pngread.$(O) \
- +pngrcb.$(O) \
+ +pngset.$(O) \
+ +pngget.$(O) \
  +pngrio.$(O) \
  +pngrtran.$(O) \
  +pngrutil.$(O) \
@@ -126,7 +128,8 @@
 ## Minor Targets
 
 png.obj: png.c
-pngrcb.obj: pngrcb.c
+pngset.obj: pngset.c
+pngget.obj: pngget.c
 pngread.obj: pngread.c
 pngpread.obj: pngpread.c
 pngrtran.obj: pngrtran.c
diff --git a/makefile.dj2 b/makefile.dj2
index 495c0c6..8ad042e 100644
--- a/makefile.dj2
+++ b/makefile.dj2
@@ -12,7 +12,7 @@
 #prefix=/usr/local
 prefix=.
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
 	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o pngwtran.o \
 	pngmem.o pngerror.o pngpread.o
 
@@ -38,7 +38,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngpread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
diff --git a/makefile.elf b/makefile.elf
index 608172c..f63c359 100644
--- a/makefile.elf
+++ b/makefile.elf
@@ -3,21 +3,32 @@
 # For conditions of distribution and use, see copyright notice in png.h
 
 CC=gcc
-CFLAGS=-I../zlib -Wall -Wwrite-strings -Wpointer-arith \
-       -Wstrict-prototypes -Wmissing-prototypes -O2 -fPIC
-LDFLAGS=-L. -Wl,-rpath,. -L../zlib/ -Wl,-rpath,../zlib/ -lpng -lz -lm
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+WARNMORE=-Wwrite-strings -Wpointer-arith -Wshadow \
+         -Wmissing-declarations -Wtraditional -Wcast-align \
+         -Wstrict-prototypes -Wmissing-prototypes #-Wconversion
+CFLAGS=-I$(ZLIBINC) -Wall -O2 -fPIC # $(WARNMORE) # -g -DPNG_DEBUG=3
+LDFLAGS=-L. -Wl,-rpath,. -L$(ZLIBLIB) -Wl,-rpath,$(ZLIBLIB) -lpng -lz -lm
 
 RANLIB=ranlib
 #RANLIB=echo
 
 PNGMAJ = 0
-PNGMIN = 90
+PNGMIN = 96
 PNGVER = $(PNGMAJ).$(PNGMIN)
 
 # where make install puts libpng.a, libpng.so*, and png.h
 prefix=/usr/local
+INCPATH=$(prefix)/include
+LIBPATH=$(prefix)/lib
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
        pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
        pngwtran.o pngmem.o pngerror.o pngpread.o
 
@@ -37,22 +48,19 @@
 	gcc -shared -Wl,-soname,libpng.so.$(PNGMAJ) -o libpng.so.$(PNGVER) $(OBJS)
 
 pngtest: pngtest.o libpng.so
-	$(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+	$(CC) -o pngtest pngtest.o $(LDFLAGS)
 
 test: pngtest
 	./pngtest
 
 install: libpng.so.$(PNGVER)
-	-@mkdir $(prefix)/include
-	-@mkdir $(prefix)/lib
-	cp png.h $(prefix)/include
-	cp pngconf.h $(prefix)/include
-	chmod 644 $(prefix)/include/png.h
-	chmod 644 $(prefix)/include/pngconf.h
-	cp libpng.so.$(PNGVER) $(prefix)/lib
-	chmod 755 $(prefix)/lib/libpng.so.$(PNGVER)
-	-@/bin/rm $(prefix)/lib/libpng.so.$(PNGMAJ) $(prefix)/lib/libpng.so
-	(cd $(prefix)/lib; ln -sf libpng.so.$(PNGVER) libpng.so.$(PNGMAJ); \
+	-@mkdir $(INCPATH) $(LIBPATH)
+	cp png.h pngconf.h $(INCPATH)
+	chmod 644 $(INCPATH)/png.h $(INCPATH)/pngconf.h
+	cp libpng.so.$(PNGVER) $(LIBPATH)
+	chmod 755 $(LIBPATH)/libpng.so.$(PNGVER)
+	-@/bin/rm $(LIBPATH)/libpng.so.$(PNGMAJ) $(LIBPATH)/libpng.so
+	(cd $(LIBPATH); ln -sf libpng.so.$(PNGVER) libpng.so.$(PNGMAJ); \
 	 ln -sf libpng.so.$(PNGMAJ) libpng.so)
 
 clean:
@@ -65,7 +73,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
 pngrutil.o: png.h pngconf.h
diff --git a/makefile.knr b/makefile.knr
index b4cc37c..13f83db 100644
--- a/makefile.knr
+++ b/makefile.knr
@@ -14,7 +14,7 @@
 # where make install puts libpng.a and png.h
 prefix=/usr/local
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
 	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
 	pngwtran.o pngmem.o pngerror.o pngpread.o
 
@@ -60,7 +60,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngpread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
diff --git a/makefile.mip b/makefile.mip
index 6208d23..fa157a2 100644
--- a/makefile.mip
+++ b/makefile.mip
@@ -13,7 +13,7 @@
 # where make install puts libpng.a and png.h
 prefix=/usr/local
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
 	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
 	pngwtran.o pngmem.o pngerror.o pngpread.o
 
@@ -49,7 +49,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngpread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
diff --git a/makefile.msc b/makefile.msc
index b0c259a..c4ac7db 100644
--- a/makefile.msc
+++ b/makefile.msc
@@ -16,15 +16,19 @@
 ERRFILE= >> pngerrs
 
 # variables
-OBJS1 = png$(O) pngrcb$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O) pngmem$(O) pngpread$(O)
-OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
+OBJS1 = png$(O) pngset$(O) pngget$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O)
+OBJS2 = pngmem$(O) pngpread$(O) pngread$(O) pngerror$(O) pngwrite$(O)
+OBJS3 = pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
 
 all: libpng.lib
 
 png$(O): png.h pngconf.h
 		  $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
 
-pngrcb$(O): png.h pngconf.h
+pngset$(O): png.h pngconf.h
+        $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
+
+pngget$(O): png.h pngconf.h
         $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
 
 pngread$(O): png.h pngconf.h
@@ -66,10 +70,11 @@
 pngwutil$(O): png.h pngconf.h
         $(CC) -c $(CFLAGS) $*.c $(ERRFILE)
 
-libpng.lib: $(OBJS1) $(OBJS2)
+libpng.lib: $(OBJS1) $(OBJS2) $(OBJS3)
         del libpng.lib
 	lib libpng $(OBJS1);
 	lib libpng $(OBJS2);
+	lib libpng $(OBJS3);
 
 pngtest.exe: pngtest.obj libpng.lib 
 	$(LD) $(LDFLAGS) pngtest.obj,,,libpng.lib ..\zlib\zlib.lib ;
diff --git a/makefile.std b/makefile.std
index 9d28c56..ebe000b 100644
--- a/makefile.std
+++ b/makefile.std
@@ -2,17 +2,23 @@
 # Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
 # For conditions of distribution and use, see copyright notice in png.h
 
-CC=cc
-CFLAGS=-I../zlib -O
-LDFLAGS=-L. -L../zlib/ -lpng -lz -lm
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
 
-#RANLIB=ranlib
-RANLIB=echo
+CC=cc
+CFLAGS=-I$(ZLIBINC) -O # -g -DPNG_DEBUG=1
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+#RANLIB=echo
+RANLIB=ranlib
 
 # where make install puts libpng.a and png.h
 prefix=/usr/local
 
-OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
 	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
 	pngwtran.o pngmem.o pngerror.o pngpread.o
 
@@ -48,7 +54,8 @@
 pngrio.o: png.h pngconf.h
 pngwio.o: png.h pngconf.h
 pngmem.o: png.h pngconf.h
-pngrcb.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
 pngread.o: png.h pngconf.h
 pngrtran.o: png.h pngconf.h
 pngrutil.o: png.h pngconf.h
diff --git a/makefile.sun b/makefile.sun
new file mode 100644
index 0000000..ccd0a28
--- /dev/null
+++ b/makefile.sun
@@ -0,0 +1,72 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+# Where the zlib library and include files are located
+#ZLIBLIB=/usr/local/lib
+#ZLIBINC=/usr/local/include
+ZLIBLIB=../zlib
+ZLIBINC=../zlib
+
+
+WARNMORE=-Wwrite-strings -Wpointer-arith -Wshadow -Wconversion \
+         -Wmissing-declarations -Wtraditional -Wcast-align \
+         -Wstrict-prototypes -Wmissing-prototypes
+CC=gcc
+CFLAGS=-I$(ZLIBINC) -O $(WARNMORE) -DPNG_DEBUG=4
+LDFLAGS=-L. -L$(ZLIBLIB) -lpng -lz -lm
+
+RANLIB=ranlib
+#RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngset.o pngget.o pngrutil.o pngtrans.o pngwutil.o \
+	pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \
+	pngwtran.o pngmem.o pngerror.o pngpread.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+	ar rc $@  $(OBJS)
+	$(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+	$(CC) -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+test: pngtest
+	./pngtest
+
+install: libpng.a
+	-@mkdir $(prefix)/include
+	-@mkdir $(prefix)/lib
+	cp png.h $(prefix)/include
+	cp pngconf.h $(prefix)/include
+	chmod 644 $(prefix)/include/png.h
+	chmod 644 $(prefix)/include/pngconf.h
+	cp libpng.a $(prefix)/lib
+	chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+	rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+png.o: png.h pngconf.h
+pngerror.o: png.h pngconf.h
+pngrio.o: png.h pngconf.h
+pngwio.o: png.h pngconf.h
+pngmem.o: png.h pngconf.h
+pngset.o: png.h pngconf.h
+pngget.o: png.h pngconf.h
+pngread.o: png.h pngconf.h
+pngrtran.o: png.h pngconf.h
+pngrutil.o: png.h pngconf.h
+pngtest.o: png.h pngconf.h
+pngtrans.o: png.h pngconf.h
+pngwrite.o: png.h pngconf.h
+pngwtran.o: png.h pngconf.h
+pngwutil.o: png.h pngconf.h
+pngpread.o: png.h pngconf.h
+
diff --git a/makefile.tc b/makefile.tc
index 58d5f55..7e1fc91 100644
--- a/makefile.tc
+++ b/makefile.tc
@@ -13,17 +13,22 @@
 O=.obj
 
 # variables
-OBJS1 = png$(O) pngrcb$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O) pngmem$(O) pngpread$(O)
-OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
-OBJSL1 = +png$(O) +pngrcb$(O) +pngrutil$(O) +pngtrans$(O) +pngwutil$(O) +pngmem$(O) +pngpread$(O)
-OBJSL2 = +pngread$(O) +pngerror$(O) +pngwrite$(O) +pngrtran$(O) +pngwtran$(O) +pngrio$(O) +pngwio$(O)
+OBJS1 = png$(O) pngset$(O) pngget$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O)
+OBJS2 = pngmem$(O) pngpread$(O) pngread$(O) pngerror$(O) pngwrite$(O)
+OBJS3 = pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O)
+OBJSL1 = +png$(O) +pngset$(O) +pngget$(O) +pngrutil$(O) +pngtrans$(O)
+OBJSL2 = +pngwutil$(O) +pngmem$(O) +pngpread$(O) +pngread$(O) +pngerror$(O)
+OBJSL3 = +pngwrite$(O) +pngrtran$(O) +pngwtran$(O) +pngrio$(O) +pngwio$(O)
 
 all: libpng.lib
 
 png$(O): png.h pngconf.h
 		  $(CC) -c $(CFLAGS) $*.c
 
-pngrcb$(O): png.h pngconf.h
+pngset$(O): png.h pngconf.h
+		  $(CC) -c $(CFLAGS) $*.c
+
+pngget$(O): png.h pngconf.h
 		  $(CC) -c $(CFLAGS) $*.c
 
 pngread$(O): png.h pngconf.h
@@ -65,8 +70,9 @@
 pngwutil$(O): png.h pngconf.h
         $(CC) -c $(CFLAGS) $*.c
 
-libpng.lib: $(OBJS1) $(OBJS2)
+libpng.lib: $(OBJS1) $(OBJS2) $(OBJS3)
         $(LIB) libpng +$(OBJSL1)
         $(LIB) libpng +$(OBJSL2)
+        $(LIB) libpng +$(OBJSL3)
 
 # End of makefile for libpng
diff --git a/makevms.com b/makevms.com
index e2b5088..15f305a 100644
--- a/makevms.com
+++ b/makevms.com
@@ -38,8 +38,10 @@
                 png.c png.h pngconf.h   
 $   CALL MAKE pngpread.OBJ "cc ''CCOPT' pngpread" -
 					 pngpread.c png.h pngconf.h
-$   CALL MAKE pngrcb.OBJ "cc ''CCOPT' pngrcb" -
-                pngrcb.c png.h pngconf.h
+$   CALL MAKE pngset.OBJ "cc ''CCOPT' pngset" -
+                pngset.c png.h pngconf.h
+$   CALL MAKE pngget.OBJ "cc ''CCOPT' pngget" -
+                pngget.c png.h pngconf.h
 $   CALL MAKE pngread.OBJ "cc ''CCOPT' pngread" -
                 pngread.c png.h pngconf.h
 $   CALL MAKE pngpread.OBJ "cc ''CCOPT' pngpread" -
diff --git a/png.c b/png.c
index eb69411..797351a 100644
--- a/png.c
+++ b/png.c
@@ -1,41 +1,43 @@
 
 /* png.c - location for general purpose png functions
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
 #define PNG_NO_EXTERN
 #include "png.h"
 
-/* version information for c files.  This better match the version
+/* Version information for C files.  This had better match the version
    string defined in png.h */
-char png_libpng_ver[] = "0.90";
+char png_libpng_ver[] = "0.95";
 
-/* place to hold the signiture string for a png file. */
+/* Place to hold the signiture string for a PNG file. */
 png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
 
 /* constant strings for known chunk types.  If you need to add a chunk,
    add a string holding the name here.  If you want to make the code
    portable to EBCDIC machines, use ASCII numbers, not characters. */
-png_byte FARDATA png_IHDR[4] = { 73,  72,  68,  82};
-png_byte FARDATA png_IDAT[4] = { 73,  68,  65,  84};
-png_byte FARDATA png_IEND[4] = { 73,  69,  78,  68};
-png_byte FARDATA png_PLTE[4] = { 80,  76,  84,  69};
-png_byte FARDATA png_gAMA[4] = {103,  65,  77,  65};
-png_byte FARDATA png_sBIT[4] = {115,  66,  73,  84};
-png_byte FARDATA png_cHRM[4] = { 99,  72,  82,  77};
-png_byte FARDATA png_tRNS[4] = {116,  82,  78,  83};
-png_byte FARDATA png_bKGD[4] = { 98,  75,  71,  68};
-png_byte FARDATA png_hIST[4] = {104,  73,  83,  84};
-png_byte FARDATA png_tEXt[4] = {116,  69,  88, 116};
-png_byte FARDATA png_zTXt[4] = {122,  84,  88, 116};
-png_byte FARDATA png_pHYs[4] = {112,  72,  89, 115};
-png_byte FARDATA png_oFFs[4] = {111,  70,  70, 115};
-png_byte FARDATA png_tIME[4] = {116,  73,  77,  69};
+png_byte FARDATA png_IHDR[5] = { 73,  72,  68,  82, '\0'};
+png_byte FARDATA png_IDAT[5] = { 73,  68,  65,  84, '\0'};
+png_byte FARDATA png_IEND[5] = { 73,  69,  78,  68, '\0'};
+png_byte FARDATA png_PLTE[5] = { 80,  76,  84,  69, '\0'};
+png_byte FARDATA png_bKGD[5] = { 98,  75,  71,  68, '\0'};
+png_byte FARDATA png_cHRM[5] = { 99,  72,  82,  77, '\0'};
+png_byte FARDATA png_gAMA[5] = {103,  65,  77,  65, '\0'};
+png_byte FARDATA png_hIST[5] = {104,  73,  83,  84, '\0'};
+png_byte FARDATA png_oFFs[5] = {111,  70,  70, 115, '\0'};
+png_byte FARDATA png_pCAL[5] = {112,  67,  65,  76, '\0'};
+png_byte FARDATA png_pHYs[5] = {112,  72,  89, 115, '\0'};
+png_byte FARDATA png_sBIT[5] = {115,  66,  73,  84, '\0'};
+png_byte FARDATA png_tEXt[5] = {116,  69,  88, 116, '\0'};
+png_byte FARDATA png_tIME[5] = {116,  73,  77,  69, '\0'};
+png_byte FARDATA png_tRNS[5] = {116,  82,  78,  83, '\0'};
+png_byte FARDATA png_zTXt[5] = {122,  84,  88, 116, '\0'};
 
 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 
@@ -78,6 +80,7 @@
 void
 png_set_sig_bytes(png_structp png_ptr, int num_bytes)
 {
+   png_debug(1, "in png_set_sig_bytes\n");
    if (num_bytes > 8)
       png_error(png_ptr, "Too many bytes for PNG signature.");
 
@@ -93,20 +96,20 @@
  * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
  */
 int
-png_sig_cmp(png_bytep sig, int start, int num_to_check)
+png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
 {
    if (num_to_check > 8)
       num_to_check = 8;
    else if (num_to_check < 1)
       return 0;
 
-   if (start > 7 || start < 0)
+   if (start > 7)
       return 0;
 
    if (start + num_to_check > 8)
       num_to_check = 8 - start;
 
-   return (png_memcmp(sig, &png_sig[start], (unsigned int)num_to_check));
+   return (png_memcmp(&sig[start], &png_sig[start], num_to_check));
 }
 
 /* (Obsolete) function to check signature bytes.  It does not allow one
@@ -115,7 +118,7 @@
 int
 png_check_sig(png_bytep sig, int num)
 {
-  return !png_sig_cmp(sig, 0, num);
+  return !png_sig_cmp(sig, (png_size_t)0, (png_size_t)num);
 }
 
 /* Function to allocate memory for zlib. */
@@ -125,10 +128,9 @@
    png_voidp ptr;
    png_uint_32 num_bytes;
 
-   ptr = png_malloc((png_structp)png_ptr,
-      (png_uint_32)items * (png_uint_32)size);
-   num_bytes = (png_uint_32)items * (png_uint_32)size;
-   if (num_bytes > (png_uint_32)0x7fff)
+   num_bytes = (png_uint_32)items * size;
+   ptr = png_malloc((png_structp)png_ptr, num_bytes);
+   if (num_bytes > (png_uint_32)0x8000)
    {
       png_memset(ptr, 0, (png_size_t)0x8000L);
       png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
@@ -153,7 +155,7 @@
 void
 png_reset_crc(png_structp png_ptr)
 {
-   /* set crc to all 1's */
+   /* set CRC to all 1's */
 #ifdef PNG_USE_OWN_CRC
    png_ptr->crc = 0xffffffffL;
 #else
@@ -162,7 +164,8 @@
 }
 
 #ifdef PNG_USE_OWN_CRC
-/* Table of CRC's of all 8-bit messages.  If you wish to png_malloc this
+/* Table of CRCs of all 8-bit messages.  By default, we use the tables made
+   by zlib, to save some memory.  If you wish to png_malloc() this
    table, turn this into a pointer, and png_malloc() it in make_crc_table().
    You may then want to hook it into png_struct and free it with the
    destroy functions.  Another alternative is to pre-fill the table.  */
@@ -188,11 +191,11 @@
   crc_table_computed = 1;
 }
 
-/* Update a running CRC with the bytes buf[0..len-1]--the crc should be
+/* Update a running CRC with the bytes buf[0..len-1] - the CRC should be
    initialized to all 1's, and the transmitted value is the 1's complement
    of the final running CRC. */
 static png_uint_32
-update_crc(png_uint_32 crc, png_bytep buf, png_uint_32 len)
+update_crc(png_uint_32 crc, png_bytep buf, png_size_t len)
 {
   png_uint_32 c;
   png_bytep p;
@@ -216,18 +219,32 @@
 }
 #endif /* PNG_USE_OWN_CRC */
 
-/* Calculate the crc over a section of data.  Note that while we
-   are passing in a 32 bit value for length, on 16 bit machines, you
-   would need to use huge pointers to access all that data.  If you
-   need this, put huge here and above. */
+/* Calculate the CRC over a section of data.  We can only pass as
+   much data to this routine as the largest single buffer size.  We
+   also check that this data will actually be used before going to the
+   trouble of calculating it. */
 void
-png_calculate_crc(png_structp png_ptr, png_bytep ptr,
-   png_uint_32 length)
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
 {
+   int need_crc = 1;
+
+   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+         need_crc = 0;
+   }
+   else                                                    /* critical */
+   {
+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+         need_crc = 0;
+   }
+
+   if (need_crc)
 #ifdef PNG_USE_OWN_CRC
-   png_ptr->crc = update_crc(png_ptr->crc, ptr, length);
+      png_ptr->crc = update_crc(png_ptr->crc, ptr, length);
 #else
-   png_ptr->crc = crc32(png_ptr->crc, ptr, length);
+      png_ptr->crc = crc32(png_ptr->crc, ptr, length);
 #endif
 }
 
@@ -241,6 +258,7 @@
 {
    png_infop info_ptr;
 
+   png_debug(1, "in png_create_info_struct\n");
    if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL)
    {
       png_info_init(info_ptr);
@@ -250,7 +268,7 @@
 }
 
 /* This function frees the memory associated with a single info struct.
-   Normally, one would use either png_destroy_read_struct() or 
+   Normally, one would use either png_destroy_read_struct() or
    png_destroy_write_struct() to free an info struct, but this may be
    useful for some applications. */
 void
@@ -258,10 +276,11 @@
 {
    png_infop info_ptr = NULL;
 
-   if (info_ptr_ptr)
+   png_debug(1, "in png_destroy_info_struct\n");
+   if (info_ptr_ptr != NULL)
       info_ptr = *info_ptr_ptr;
 
-   if (info_ptr)
+   if (info_ptr != NULL)
    {
       png_info_destroy(png_ptr, info_ptr);
 
@@ -276,24 +295,42 @@
 void
 png_info_init(png_infop info_ptr)
 {
+   png_debug(1, "in png_info_init\n");
    /* set everything to 0 */
    png_memset(info_ptr, 0, sizeof (png_info));
 }
 
 /* This is an internal routine to free any memory that the info struct is
-   pointing to before re-using it or freeing the struct itself. */
+ * pointing to before re-using it or freeing the struct itself.  Recall
+ * that png_free() checks for NULL pointers for us.
+ */
 void
 png_info_destroy(png_structp png_ptr, png_infop info_ptr)
 {
 #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
    int i;
 
-   for (i = 0; i < info_ptr->num_text; i++)
+   png_debug(1, "in png_info_destroy\n");
+   if (info_ptr->text != NULL)
    {
-      png_free(png_ptr, info_ptr->text[i].key);
+      for (i = 0; i < info_ptr->num_text; i++)
+      {
+         png_free(png_ptr, info_ptr->text[i].key);
+      }
+      png_free(png_ptr, info_ptr->text);
    }
-
-   png_free(png_ptr, info_ptr->text);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+   png_free(png_ptr, info_ptr->pcal_purpose);
+   png_free(png_ptr, info_ptr->pcal_units);
+   if (info_ptr->pcal_params != NULL)
+   {
+      for (i = 0; i < info_ptr->pcal_nparams; i++)
+      {
+         png_free(png_ptr, info_ptr->pcal_params[i]);
+      }
+      png_free(png_ptr, info_ptr->pcal_params);
+   }
 #endif
 
    png_info_init(info_ptr);
@@ -307,12 +344,15 @@
 {
    return png_ptr->io_ptr;
 }
- 
-/* Initialize the default input/output functions for the png file.  If you
-   change the read, or write routines, you can call either png_set_read_fn()
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the default input/output functions for the PNG file.  If you
+   use your own read or write routines, you can call either png_set_read_fn()
    or png_set_write_fn() instead of png_init_io(). */
 void
 png_init_io(png_structp png_ptr, FILE *fp)
 {
+   png_debug(1, "in png_init_io\n");
    png_ptr->io_ptr = (png_voidp)fp;
 }
+#endif
diff --git a/png.h b/png.h
index ce841bd..b3338ff 100644
--- a/png.h
+++ b/png.h
@@ -1,40 +1,48 @@
 
-/* png.h - header file for png reference library
+/* png.h - header file for PNG reference library
 
-   libpng 1.0 beta 4 - version 0.90
-   January 10, 1997
+   libpng 1.0 beta 6 - version 0.96
+   For conditions of distribution and use, see copyright notice in png.h
+   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
 
-   Note: This is a beta version.  It reads and writes valid files
-   on the platforms I have, and has had a wide testing program.
-   You may have to modify the includes below to get it to work on
-   your system, and you may have to supply the correct compiler
-   flags in the makefile, if you can't find a makefile suitable for
-   your operating system/compiler combination.  Read the libpng.txt
-   for more information, and how to contact the authors if you have any
-   problems, or if you want your compiler/platform to be supported
-   in the next official libpng release.
+   BETA NOTICE:
+      This is a beta version.  It reads and writes valid files on the
+      platforms I have, and has had a wide testing program.  You may
+      have to modify the includes below to get it to work on your
+      system, and you may have to supply the correct compiler flags in
+      the makefile if you can't find a makefile suitable for your
+      operating system/compiler combination.  Read libpng.txt for more
+      information, including how to contact the authors if you have any
+      problems, or if you want your compiler/platform to be supported in
+      the next official libpng release.
 
    See libpng.txt for more information.
 
-   Copyright (c) 1995, 1996, 1997 Guy Eric Schalnat, Group 42, Inc.
    Contributing Authors:
-      Sam Bushnell
+      John Bowler
+      Sam Bushell
+      Kevin Bracey
       Andreas Dilger
+      Magnus Holmgren
       Dave Martindale
+      Greg Roelofs
       Guy Eric Schalnat
       Paul Schmidt
+      Tom Tanner
       Tim Wegner
 
    The contributing authors would like to thank all those who helped
-   with testing, bug fixes, and patience.  You know who you are.  This
-   wouldn't have been possible without all of you.
+   with testing, bug fixes, and patience.  This wouldn't have been
+   possible without all of you.
 
-   Thanks to Frank J. T. Wojcik for helping with the documentation
+   Thanks to Frank J. T. Wojcik for helping with the documentation.
 
-   The PNG Reference Library is supplied "AS IS". The Contributing Authors
+   The PNG Reference Library is supplied "AS IS".  The Contributing Authors
    and Group 42, Inc. disclaim all warranties, expressed or implied,
    including, without limitation, the warranties of merchantability and of
-   fitness for any purpose. The Contributing Authors and Group 42, Inc.
+   fitness for any purpose.  The Contributing Authors and Group 42, Inc.
    assume no liability for direct, indirect, incidental, special, exemplary,
    or consequential damages, which may result from the use of the PNG
    Reference Library, even if advised of the possibility of such damage.
@@ -50,22 +58,23 @@
 
    The Contributing Authors and Group 42, Inc. specifically permit, without
    fee, and encourage the use of this source code as a component to
-   supporting the PNG file format in commercial products. If you use this
+   supporting the PNG file format in commercial products.  If you use this
    source code in a product, acknowledgment is not required but would be
    appreciated.
-   */
+*/
 
 #ifndef _PNG_H
 #define _PNG_H
 
 #ifdef __cplusplus
 extern "C" {
-#endif
+#endif /* __cplusplus */
 
 /* This is not the place to learn how to use libpng.  The file libpng.txt
-   describes how to use libpng, and the file example.c summarizes it
-   with some code to build around.  This file is useful for looking
-   at the actual function definitions and structure components. */
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build.  This file is useful for looking
+ * at the actual function definitions and structure components.
+ */
 
 /* include the compression library's header */
 #include "zlib.h"
@@ -73,156 +82,254 @@
 /* include all user configurable info */
 #include "pngconf.h"
 
-/* This file is arranged in several sections.  The first section details
-   the functions most users will use.  The third section describes the
-   stub files that users will most likely need to change.  The last
-   section contains functions used internally by the code.  */
+/* This file is arranged in several sections.  The first section contains
+ * structure and type definitions.  The second section contains the external
+ * library functions, while the third has the internal library functions,
+ * which applications aren't expected to use directly.
+ */
 
-/* version information for png.h - this should match the version
-   number in png.c */
-#define PNG_LIBPNG_VER_STRING "0.90"
-/* careful here.  I wanted to use 090, but that would be octal.  Version
-   1.0 will be 100 here, etc. */
-#define PNG_LIBPNG_VER 90
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "0.96"
 
-/* variables defined in png.c - only it needs to define PNG_NO_EXTERN */
+/* careful here.  At one time, I wanted to use 082, but that would be octal.
+ * Version 1.0 will be 100 here, etc.
+ */
+#define PNG_LIBPNG_VER 96
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
 #ifndef PNG_NO_EXTERN
-/* version information for c files, stored in png.c. This better match
-   the version above. */
+/* Version information for C files, stored in png.c.  This had better match
+ * the version above.
+ */
 extern char png_libpng_ver[];
-#endif
 
-/* three color definitions.  The order of the red, green, and blue, (and the
-   exact size) is not important, although the size of the fields need to
-   be png_byte or png_uint_16 (as defined below).  */
+/* Structures to facilitate easy interlacing.  See png.c for more details */
+extern int FARDATA png_pass_start[];
+extern int FARDATA png_pass_inc[];
+extern int FARDATA png_pass_ystart[];
+extern int FARDATA png_pass_yinc[];
+extern int FARDATA png_pass_mask[];
+extern int FARDATA png_pass_dsp_mask[];
+/* These aren't currently used.  If you need them, see png.c for more details
+extern int FARDATA png_pass_width[];
+extern int FARDATA png_pass_height[];
+*/
+#endif /* PNG_NO_EXTERN */
+
+/* Three color definitions.  The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
 typedef struct png_color_struct
 {
    png_byte red;
    png_byte green;
    png_byte blue;
 } png_color;
-typedef png_color       FAR *    png_colorp;
-typedef png_color       FAR * FAR * png_colorpp;
+typedef png_color FAR * png_colorp;
+typedef png_color FAR * FAR * png_colorpp;
 
 typedef struct png_color_16_struct
 {
-   png_byte index; /* used for palette files */
-   png_uint_16 red; /* for use in red green blue files */
+   png_byte index;    /* used for palette files */
+   png_uint_16 red;   /* for use in red green blue files */
    png_uint_16 green;
    png_uint_16 blue;
-   png_uint_16 gray; /* for use in grayscale files */
+   png_uint_16 gray;  /* for use in grayscale files */
 } png_color_16;
-typedef png_color_16    FAR *    png_color_16p;
-typedef png_color_16    FAR * FAR * png_color_16pp;
+typedef png_color_16 FAR * png_color_16p;
+typedef png_color_16 FAR * FAR * png_color_16pp;
 
 typedef struct png_color_8_struct
 {
-   png_byte red; /* for use in red green blue files */
+   png_byte red;   /* for use in red green blue files */
    png_byte green;
    png_byte blue;
-   png_byte gray; /* for use in grayscale files */
+   png_byte gray;  /* for use in grayscale files */
    png_byte alpha; /* for alpha channel files */
 } png_color_8;
-typedef png_color_8     FAR *    png_color_8p;
-typedef png_color_8     FAR * FAR * png_color_8pp;
+typedef png_color_8 FAR * png_color_8p;
+typedef png_color_8 FAR * FAR * png_color_8pp;
 
-/* png_text holds the text in a png file, and whether they are compressed
-   or not.  If compression is -1, the text is not compressed.  */
+/* png_text holds the text in a PNG file, and whether they are compressed
+   in the PNG file or not.  The "text" field points to a regular C string. */
 typedef struct png_text_struct
 {
-   int compression; /* compression value, -1 if uncompressed */
-   png_charp key; /* keyword */
-   png_charp text; /* comment */
-   png_uint_32 text_length; /* length of text field */
+   int compression;        /* compression value, see PNG_TEXT_COMPRESSION_ */
+   png_charp key;          /* keyword, 1-79 character description of "text" */
+   png_charp text;         /* comment, may be an empty string (ie "") */
+   png_size_t text_length; /* length of "text" field */
 } png_text;
-typedef png_text        FAR *    png_textp;
-typedef png_text        FAR * FAR * png_textpp;
+typedef png_text FAR * png_textp;
+typedef png_text FAR * FAR * png_textpp;
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE    -1
+#define PNG_TEXT_COMPRESSION_zTXt     0
+#define PNG_TEXT_COMPRESSION_LAST     1  /* Not a valid value */
 
 /* png_time is a way to hold the time in an machine independent way.
    Two conversions are provided, both from time_t and struct tm.  There
    is no portable way to convert to either of these structures, as far
-   as I know.  If you know of a portable way, send it to me. */
+   as I know.  If you know of a portable way, send it to me.  As a side
+   note - PNG is Year 2000 compliant! */
 typedef struct png_time_struct
 {
    png_uint_16 year; /* full year, as in, 1995 */
-   png_byte month; /* month of year, 1 - 12 */
-   png_byte day; /* day of month, 1 - 31 */
-   png_byte hour; /* hour of day, 0 - 23 */
-   png_byte minute; /* minute of hour, 0 - 59 */
-   png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
+   png_byte month;   /* month of year, 1 - 12 */
+   png_byte day;     /* day of month, 1 - 31 */
+   png_byte hour;    /* hour of day, 0 - 23 */
+   png_byte minute;  /* minute of hour, 0 - 59 */
+   png_byte second;  /* second of minute, 0 - 60 (for leap seconds) */
 } png_time;
-typedef png_time        FAR *    png_timep;
-typedef png_time        FAR * FAR * png_timepp;
+typedef png_time FAR * png_timep;
+typedef png_time FAR * FAR * png_timepp;
 
-/* png_info is a structure that holds the information in a png file.
-   If you are reading the file, This structure will tell you what is
-   in the png file.  If you are writing the file, fill in the information
-   you want to put into the png file, then call png_write_info().
-   The names chosen should be very close to the PNG specification, so
-   consult that document for information about the meaning of each field. */
+/* png_info is a structure that holds the information in a PNG file so
+ * that the application can find out the characteristics of the image.
+ * If you are reading the file, this structure will tell you what is
+ * in the PNG file.  If you are writing the file, fill in the information
+ * you want to put into the PNG file, then call png_write_info().
+ * The names chosen should be very close to the PNG specification, so
+ * consult that document for information about the meaning of each field.
+ *
+ * With libpng < 0.95, it was only possible to directly set and read the
+ * the values in the png_info_struct, which meant that the contents and
+ * order of the values had to remain fixed.  With libpng 0.95 and later,
+ * however, * there are now functions which abstract the contents of
+ * png_info_struct from the application, so this makes it easier to use
+ * libpng with dynamic libraries, and even makes it possible to use
+ * libraries that don't have all of the libpng ancillary chunk-handing
+ * functionality.
+ *
+ * In any case, the order of the parameters in png_info_struct should NOT
+ * be changed for as long as possible to keep compatibility with applications
+ * that use the old direct-access method with png_info_struct.
+ */
 typedef struct png_info_struct
 {
-   /* the following are necessary for every png file */
-   png_uint_32 width; /* with of file */
-   png_uint_32 height; /* height of file */
-   png_uint_32 valid; /* the PNG_INFO_ defines, OR'd together */
-   png_uint_32 rowbytes; /* bytes needed for untransformed row */
-   png_colorp palette; /* palette of file */
-   png_uint_16 num_palette; /* number of values in palette */
-   png_uint_16 num_trans; /* number of trans values */
-   png_byte bit_depth; /* 1, 2, 4, 8, or 16 */
-   png_byte color_type; /* use the PNG_COLOR_TYPE_ defines */
-   png_byte compression_type; /* must be 0 */
-   png_byte filter_type; /* must be 0 */
-   png_byte interlace_type; /* 0 for non-interlaced, 1 for interlaced */
-   /* the following is informational only on read, and not used on
-      writes */
-   png_byte channels; /* number of channels of data per pixel */
-   png_byte pixel_depth; /* number of bits per pixel */
-   png_byte spare_byte;  /* To align the data, and for future use */
-   png_byte signature[8]; /* Signature read from start of file */
+   /* the following are necessary for every PNG file */
+   png_uint_32 width;       /* width of image in pixels (from IHDR) */
+   png_uint_32 height;      /* height of image in pixels (from IHDR) */
+   png_uint_32 valid;       /* valid chunk data (see PNG_INFO_ below) */
+   png_size_t rowbytes;     /* bytes needed to hold an untransformed row */
+   png_colorp palette;      /* array of color values (valid & PNG_INFO_PLTE) */
+   png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+   png_uint_16 num_trans;   /* number of transparent palette color (tRNS) */
+   png_byte bit_depth;      /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+   png_byte color_type;     /* see PNG_COLOR_TYPE_ below (from IHDR) */
+   png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+   png_byte filter_type;    /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+   png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
 
-   /* the rest are optional.  If you are reading, check the valid
-      field to see if the information in these are valid.  If you
-      are writing, set the valid field to those chunks you want
-      written, and initialize the appropriate fields below */
+   /* The following is informational only on read, and not used on writes. */
+   png_byte channels;       /* number of data channels per pixel (1, 3, 4)*/
+   png_byte pixel_depth;    /* number of bits per pixel */
+   png_byte spare_byte;     /* to align the data, and for future use */
+   png_byte signature[8];   /* magic bytes read by libpng from start of file */
+
+   /* The rest of the data is optional.  If you are reading, check the
+    * valid field to see if the information in these are valid.  If you
+    * are writing, set the valid field to those chunks you want written,
+    * and initialize the appropriate fields below.
+    */
+
 #if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
-   float gamma; /* gamma value of file, if gAMA chunk is valid */
-#endif
+   /* The gAMA chunk describes the gamma characteristics of the system
+    * on which the image was created, normally in the range [1.0, 2.5].
+    * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
+    */
+   float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
 #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
     defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
-   int num_text; /* number of comments */
-   int max_text; /* size of text array */
-   png_textp text; /* array of comments */
-#endif
+   /* The tEXt and zTXt chunks contain human-readable textual data in
+    * uncompressed and compressed forms, respectively.  The data in "text"
+    * is an array of pointers to uncompressed, null-terminated C strings.
+    * Each chunk has a keyword which describes the textual data contained
+    * in that chunk.  Keywords are not required to be unique, and the text
+    * string may be empty.  Any number of text chunks may be in an image.
+    */
+   int num_text; /* number of comments read/to write */
+   int max_text; /* current size of text array */
+   png_textp text; /* array of comments read/to write */
+#endif /* PNG_READ_tEXt/zTXt_SUPPORTED || PNG_WRITE_tEXt/zTXt_SUPPORTED */
 #if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
-   png_time mod_time; /* modification time */
-#endif
+   /* The tIME chunk holds the last time the displayed image data was
+    * modified.  See the png_time struct for the contents of this struct.
+    */
+   png_time mod_time;
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
 #if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
-   png_color_8 sig_bit; /* significant bits */
-#endif
+   /* The sBIT chunk specifies the number of significant high-order bits
+    * in the pixel data.  Values are in the range [1, bit_depth], and are
+    * only specified for the channels in the pixel data.  The contents of
+    * the low-order bits is not specified.  Data is valid if
+    * (valid & PNG_INFO_sBIT) is non-zero.
+    */
+   png_color_8 sig_bit; /* significant bits in color channels */
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
 #if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
-   png_bytep trans; /* tRNS values for palette image */
-   png_color_16 trans_values; /* tRNS values for non-palette image */
-#endif
+   /* The tRNS chunk supplies transparency data for paletted images and
+    * other image types that don't need a full alpha channel.  There are
+    * "num_trans" transparency values for a paletted image, stored in the
+    * same order as the palette colors, starting from index 0.  Values
+    * for the data are in the range [0, 255], ranging from fully transparent
+    * to fully opaque, respectively.  For non-paletted images, there is a
+    * single color specified which should be treated as fully transparent.
+    * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+    */
+   png_bytep trans; /* transparent values for paletted image */
+   png_color_16 trans_values; /* transparent color for non-palette image */
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
 #if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
-   png_color_16 background; /* background color of image */
-#endif
+   /* The bKGD chunk gives the suggested image background color if the
+    * display program does not have its own background color and the image
+    * is needs to composited onto a background before display.  The colors
+    * in "background" are normally in the same color space/depth as the
+    * pixel data.  Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+    */
+   png_color_16 background;
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
 #if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+   /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+    * and downwards from the top-left corner of the display, page, or other
+    * application-specific co-ordinate space.  See the PNG_OFFSET_ defines
+    * below for the unit types.  Valid if (valid & PNG_INFO_oFFs) non-zero.
+    */
    png_uint_32 x_offset; /* x offset on page */
    png_uint_32 y_offset; /* y offset on page */
    png_byte offset_unit_type; /* offset units type */
-#endif
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
 #if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
-   png_uint_32 x_pixels_per_unit; /* x resolution */
-   png_uint_32 y_pixels_per_unit; /* y resolution */
-   png_byte phys_unit_type; /* resolution type */
-#endif
+   /* The pHYs chunk gives the physical pixel density of the image for
+    * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+    * defines below).  Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+    */
+   png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+   png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+   png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
 #if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
-   png_uint_16p hist; /* histogram of palette usage */
-#endif
+   /* The hIST chunk contains the relative frequency or importance of the
+    * various palette entries, so that a viewer can intelligently select a
+    * reduced-color palette, if required.  Data is an array of "num_palette"
+    * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+    * is non-zero.
+    */
+   png_uint_16p hist;
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
 #if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
-   float x_white; /* cHRM chunk values */
+   /* The cHRM chunk describes the CIE color characteristics of the monitor
+    * on which the PNG was created.  This data allows the viewer to do gamut
+    * mapping of the input image to ensure that the viewer sees the same
+    * colors in the image as the creator.  Values are in the range
+    * [0.0, 0.8].  Data valid if (valid & PNG_INFO_cHRM) non-zero.
+    */
+   float x_white;
    float y_white;
    float x_red;
    float y_red;
@@ -230,37 +337,80 @@
    float y_green;
    float x_blue;
    float y_blue;
-#endif
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+   /* The pCAL chunk describes a transformation between the stored pixel
+    * values and original physcical data values used to create the image.
+    * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+    * range given by [pcal_X0, pcal_X1], and are further transformed by a
+    * (possibly non-linear) transformation function given by "pcal_type"
+    * and "pcal_params" into "pcal_units".  Please see the PNG_EQUATION_
+    * defines below, and the PNG-Group's Scientific Visualization extension
+    * chunks document png-scivis-19970203 for a complete description of the
+    * transformations and how they should be implemented, as well as the
+    * png-extensions document for a description of the ASCII parameter
+    * strings.  Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+    */
+   png_charp pcal_purpose;  /* pCAL chunk description string */
+   png_int_32 pcal_X0;      /* minimum value */
+   png_int_32 pcal_X1;      /* maximum value */
+   png_charp pcal_units;    /* Latin-1 string giving physical units */
+   png_charpp pcal_params;  /* ASCII strings containing parameter values */
+   png_byte pcal_type;      /* equation type (see PNG_EQUATION_ below) */
+   png_byte pcal_nparams;   /* number of parameters given in pcal_params */
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
 } png_info;
-typedef png_info        FAR *    png_infop;
-typedef png_info        FAR * FAR * png_infopp;
+typedef png_info FAR * png_infop;
+typedef png_info FAR * FAR * png_infopp;
 
-#define PNG_RESOLUTION_UNKNOWN 0
-#define PNG_RESOLUTION_METER   1
-#define PNG_RESOLUTION_LAST    2
-
-#define PNG_OFFSET_PIXEL       0
-#define PNG_OFFSET_MICROMETER  1
-#define PNG_OFFSET_LAST        2
-
-/* these describe the color_type field in png_info */
-
+/* These describe the color_type field in png_info. */
 /* color type masks */
-#define PNG_COLOR_MASK_PALETTE 1
-#define PNG_COLOR_MASK_COLOR   2
-#define PNG_COLOR_MASK_ALPHA   4
+#define PNG_COLOR_MASK_PALETTE    1
+#define PNG_COLOR_MASK_COLOR      2
+#define PNG_COLOR_MASK_ALPHA      4
 
 /* color types.  Note that not all combinations are legal */
 #define PNG_COLOR_TYPE_GRAY 0
-#define PNG_COLOR_TYPE_PALETTE \
-   (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
-#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
-#define PNG_COLOR_TYPE_RGB_ALPHA \
-   (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
 
-/* These determine if a chunks information is present in a read operation, or
-   if the chunk should be written in a write operation.  */
+/* This is for compression type. PNG 1.0 only defines the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0 only defines the single type. */
+#define PNG_FILTER_TYPE_BASE      0 /* Single row per-byte filtering */
+#define PNG_FILTER_TYPE_DEFAULT   PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type.  These values should NOT be changed. */
+#define PNG_INTERLACE_NONE        0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7       1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST        2 /* Not a valid value */
+
+/* These are for the oFFs chunk.  These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL          0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER     1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST           2 /* Not a valid value */
+
+/* These are for the pCAL chunk.  These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR       0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E       1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY    2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC   3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST         4 /* Not a valid value */
+
+/* These are for the pHYs chunk.  These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN    0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER      1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST       2 /* Not a valid value */
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file.  The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
 #define PNG_INFO_gAMA 0x0001
 #define PNG_INFO_sBIT 0x0002
 #define PNG_INFO_cHRM 0x0004
@@ -271,22 +421,24 @@
 #define PNG_INFO_pHYs 0x0080
 #define PNG_INFO_oFFs 0x0100
 #define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
 
-/* this is used for the transformation routines, as some of them
-   change these values for the row.  It also should enable using
-   the routines for other uses. */
+/* This is used for the transformation routines, as some of them
+ * change these values for the row.  It also should enable using
+ * the routines for other purposes.
+ */
 typedef struct png_row_info_struct
 {
    png_uint_32 width; /* width of row */
-   png_uint_32 rowbytes; /* number of bytes in row */
+   png_size_t rowbytes; /* number of bytes in row */
    png_byte color_type; /* color type of row */
    png_byte bit_depth; /* bit depth of row */
    png_byte channels; /* number of channels (1, 2, 3, or 4) */
    png_byte pixel_depth; /* bits per pixel (depth * channels) */
 } png_row_info;
 
-typedef png_row_info    FAR *    png_row_infop;
-typedef png_row_info    FAR * FAR * png_row_infopp;
+typedef png_row_info FAR * png_row_infop;
+typedef png_row_info FAR * FAR * png_row_infopp;
 
 /* These are the function types for the I/O functions, and the functions which
  * modify the default I/O functions to user I/O functions.  The png_error_ptr
@@ -297,141 +449,143 @@
 typedef png_struct FAR * png_structp;
 
 typedef void (*png_error_ptr) PNGARG((png_structp, png_const_charp));
-typedef void (*png_rw_ptr) PNGARG((png_structp, png_bytep, png_uint_32));
+typedef void (*png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
 typedef void (*png_flush_ptr) PNGARG((png_structp));
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 typedef void (*png_progressive_info_ptr) PNGARG((png_structp, png_infop));
 typedef void (*png_progressive_end_ptr) PNGARG((png_structp, png_infop));
 typedef void (*png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
    png_uint_32, int));
-#endif
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 
-/* The structure that holds the information to read and write png files.
-   The only people who need to care about what is inside of this are the
-   people who will be modifying the library for their own special needs.
-   */
+/* The structure that holds the information to read and write PNG files.
+ * The only people who need to care about what is inside of this are the
+ * people who will be modifying the library for their own special needs.
+ * It should NOT be accessed directly by an application, except to store
+ * the jmp_buf.
+ */
 
 struct png_struct_def
 {
-   jmp_buf jmpbuf; /* used in png_error */
+   jmp_buf jmpbuf;            /* used in png_error */
 
-   png_error_ptr error_fn;    /* Function for printing errors and aborting */
-   png_error_ptr warning_fn;  /* Function for printing warnings */
+   png_error_ptr error_fn;    /* function for printing errors and aborting */
+   png_error_ptr warning_fn;  /* function for printing warnings */
    png_voidp error_ptr;       /* user supplied struct for error functions */
-   png_rw_ptr write_data_fn;  /* Function for writing output data */
-   png_rw_ptr read_data_fn;   /* Function for reading input data */
-   png_voidp io_ptr;  /* Pointer to user supplied struct for I/O functions */
+   png_rw_ptr write_data_fn;  /* function for writing output data */
+   png_rw_ptr read_data_fn;   /* function for reading input data */
+   png_voidp io_ptr;          /* ptr to application struct for I/O functions*/
 
-   png_uint_32 mode; /* used to determine where we are in the png file */
-   png_uint_32 flags;  /* flags indicating various things to libpng */
+   png_uint_32 mode;          /* tells us whre we are in the PNG file */
+   png_uint_32 flags;         /* flags indicating various things to libpng */
    png_uint_32 transformations; /* which transformations to perform */
 
-   z_stream zstream; /* pointer to decompression structure (below) */
-   png_bytep zbuf; /* buffer for zlib */
-   png_uint_32 zbuf_size; /* size of zbuf */
-   int zlib_level; /* holds zlib compression level */
-   int zlib_method; /* holds zlib compression method */
-   int zlib_window_bits; /* holds zlib compression window bits */
-   int zlib_mem_level; /* holds zlib compression memory level */
-   int zlib_strategy; /* holds zlib compression strategy */
+   z_stream zstream;          /* pointer to decompression structure (below) */
+   png_bytep zbuf;            /* buffer for zlib */
+   png_size_t zbuf_size;      /* size of zbuf */
+   int zlib_level;            /* holds zlib compression level */
+   int zlib_method;           /* holds zlib compression method */
+   int zlib_window_bits;      /* holds zlib compression window bits */
+   int zlib_mem_level;        /* holds zlib compression memory level */
+   int zlib_strategy;         /* holds zlib compression strategy */
 
-   png_uint_32 width; /* width of file */
-   png_uint_32 height; /* height of file */
-   png_uint_32 num_rows; /* number of rows in current pass */
-   png_uint_32 rowbytes; /* size of row in bytes */
-   png_uint_32 usr_width; /* width of row at start of write */
-   png_uint_32 iwidth; /* interlaced width */
-   png_uint_32 irowbytes; /* interlaced rowbytes */
-   png_uint_32 row_number; /* current row in pass */
-   png_bytep prev_row; /* place to save previous (unfiltered) row */
-   png_bytep row_buf; /* place to save current (unfiltered) row */
-   png_bytep sub_row;  /* place to save "sub" row when filtering */
-   png_bytep up_row;   /* place to save "up" row when filtering */
-   png_bytep avg_row;  /* place to save "avg" row when filtering */
-   png_bytep paeth_row; /* place to save "Paeth" row when filtering */
-   png_row_info row_info; /* used for transformation routines */
+   png_uint_32 width;         /* width of image in pixels */
+   png_uint_32 height;        /* height of image in pixels */
+   png_uint_32 num_rows;      /* number of rows in current pass */
+   png_uint_32 usr_width;     /* width of row at start of write */
+   png_size_t rowbytes;       /* size of row in bytes */
+   png_size_t irowbytes;      /* size of current interlaced row in bytes */
+   png_uint_32 iwidth;        /* width of current interlaced row in pixels */
+   png_uint_32 row_number;    /* current row in interlace pass */
+   png_bytep prev_row;        /* buffer to save previous (unfiltered) row */
+   png_bytep row_buf;         /* buffer to save current (unfiltered) row */
+   png_bytep sub_row;         /* buffer to save "sub" row when filtering */
+   png_bytep up_row;          /* buffer to save "up" row when filtering */
+   png_bytep avg_row;         /* buffer to save "avg" row when filtering */
+   png_bytep paeth_row;       /* buffer to save "Paeth" row when filtering */
+   png_row_info row_info;     /* used for transformation routines */
 
-   png_uint_32 idat_size; /* current idat size for read */
-   png_uint_32 crc; /* current crc value */
-   png_colorp palette; /* files palette */
-   png_uint_16 num_palette; /* number of entries in palette */
-   png_uint_16 num_trans; /* number of transparency values */
-   png_byte chunk_name[5]; /* name of current chunk being processed + '\0' */
-   png_byte compression; /* file compression type (currently only '0' used) */
-   png_byte filter; /* file filter type (currently only '0' used) */
-   png_byte interlaced; /* file interlace type (currently only '0' and '1') */
-   png_byte pass; /* current interlace pass (0 - 6) */
-   png_byte do_filter; /* zero if not row filtering, non-zero if filtering */
-   png_byte color_type; /* color type of file */
-   png_byte bit_depth; /* bit depth of file */
-   png_byte usr_bit_depth; /* bit depth of users row */
-   png_byte pixel_depth; /* number of bits per pixel */
-   png_byte channels; /* number of channels in file */
-   png_byte usr_channels; /* channels at start of write */
-   png_byte sig_bytes; /* signature bytes read/written from start of file */
+   png_uint_32 idat_size;     /* current IDAT size for read */
+   png_uint_32 crc;           /* current chunk CRC value */
+   png_colorp palette;        /* palette from the input file */
+   png_uint_16 num_palette;   /* number of color entries in palette */
+   png_uint_16 num_trans;     /* number of transparency values */
+   png_byte chunk_name[5];    /* null-terminated name of current chunk */
+   png_byte compression;      /* file compression type (always 0) */
+   png_byte filter;           /* file filter type (always 0) */
+   png_byte interlaced;       /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+   png_byte pass;             /* current interlace pass (0 - 6) */
+   png_byte do_filter;        /* row filter flags (see PNG_FILTER_ below ) */
+   png_byte color_type;       /* color type of file */
+   png_byte bit_depth;        /* bit depth of file */
+   png_byte usr_bit_depth;    /* bit depth of users row */
+   png_byte pixel_depth;      /* number of bits per pixel */
+   png_byte channels;         /* number of channels in file */
+   png_byte usr_channels;     /* channels at start of write */
+   png_byte sig_bytes;        /* magic bytes read/written from start of file */
 
 
 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
-   png_byte filler; /* filler byte to be used for 32-bit frame buffers */
-#endif
-#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+   png_byte filler;           /* filler byte for 24->32-bit pixel expansion */
+#endif /* PNG_READ_FILLER_SUPPORTED */
+#if defined(PNG_READ_bKGD_SUPPORTED)
    png_byte background_gamma_type;
    float background_gamma;
-   png_color_16 background; /* background color, gamma corrected for screen */
+   png_color_16 background;   /* background color in screen gamma space */
 #if defined(PNG_READ_GAMMA_SUPPORTED)
    png_color_16 background_1; /* background normalized to gamma 1.0 */
-#endif
-#endif
+#endif /* PNG_READ_GAMMA && PNG_READ_bKGD_SUPPORTED */
+#endif /* PNG_READ_bKGD_SUPPORTED */
 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
    png_flush_ptr output_flush_fn;/* Function for flushing output */
-   png_uint_32 flush_dist;  /* how many rows apart to flush, 0 for no flush */
-   png_uint_32 flush_rows;  /* number of rows written since last flush */
+   png_uint_32 flush_dist;    /* how many rows apart to flush, 0 - no flush */
+   png_uint_32 flush_rows;    /* number of rows written since last flush */
 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-   int gamma_shift; /* amount of shift for 16 bit gammas */
-   float gamma; /* file gamma value */
-   float display_gamma; /* display gamma value */
-#endif
+   int gamma_shift;           /* number of "insignificant" bits 16-bit gamma */
+   float gamma;               /* file gamma value */
+   float display_gamma;       /* display gamma value */
+#endif /* PNG_READ_GAMMA_SUPPORTED */
 #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-   png_bytep gamma_table; /* gamma table for 8 bit depth files */
-   png_bytep gamma_from_1; /* converts from 1.0 to screen */
-   png_bytep gamma_to_1; /* converts from file to 1.0 */
+   png_bytep gamma_table;     /* gamma table for 8 bit depth files */
+   png_bytep gamma_from_1;    /* converts from 1.0 to screen */
+   png_bytep gamma_to_1;      /* converts from file to 1.0 */
    png_uint_16pp gamma_16_table; /* gamma table for 16 bit depth files */
    png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
    png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
-#endif
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_WRITE_GAMMA_SUPPORTED */
 #if defined(PNG_READ_GAMMA_SUPPORTED) || defined (PNG_READ_sBIT_SUPPORTED)
-   png_color_8 sig_bit; /* significant bits in file */
-#endif
-#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-   png_bytep trans; /* transparency values for paletted files */
-   png_color_16 trans_values; /* transparency values for non-paletted files */
-#endif
+   png_color_8 sig_bit;       /* significant bits in each available channel */
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_READ_sBIT_SUPPORTED */
 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
-   png_color_8 shift; /* shift for significant bit tranformation */
-#endif
+   png_color_8 shift;         /* shift for significant bit tranformation */
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+   png_bytep trans;           /* transparency values for paletted files */
+   png_color_16 trans_values; /* transparency values for non-paletted files */
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_READ_BACKGROUND_SUPPORTED */
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-   png_progressive_info_ptr info_fn;
-   png_progressive_row_ptr row_fn;
-   png_progressive_end_ptr end_fn;
-   png_bytep save_buffer_ptr;
-   png_bytep save_buffer;
-   png_bytep current_buffer_ptr;
-   png_bytep current_buffer;
-   png_uint_32 push_length;
-   png_uint_32 skip_length;
-   png_uint_32 save_buffer_size;
-   png_uint_32 save_buffer_max;
-   png_uint_32 buffer_size;
-   png_uint_32 current_buffer_size;
-   int process_mode;
-   int cur_palette;
+   png_progressive_info_ptr info_fn; /* called after header data fully read */
+   png_progressive_row_ptr row_fn;   /* called after each row is decoded */
+   png_progressive_end_ptr end_fn;   /* called after image is complete */
+   png_bytep save_buffer_ptr;        /* current location in save_buffer */
+   png_bytep save_buffer;            /* buffer for previously read data */
+   png_bytep current_buffer_ptr;     /* current location in current_buffer */
+   png_bytep current_buffer;         /* buffer for recently used data */
+   png_uint_32 push_length;          /* size of current input chunk */
+   png_uint_32 skip_length;          /* bytes to skip in input data */
+   png_size_t save_buffer_size;      /* amount of data now in save_buffer */
+   png_size_t save_buffer_max;       /* total size of save_buffer */
+   png_size_t buffer_size;           /* total amount of available input data */
+   png_size_t current_buffer_size;   /* amount of data now in current_buffer */
+   int process_mode;                 /* what push library is currently doing */
+   int cur_palette;                  /* current push library palette index */
 #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
-   png_uint_32 current_text_size;
-   png_uint_32 current_text_left;
-   png_charp current_text;
-   png_charp current_text_ptr;
-#endif
+   png_size_t current_text_size;     /* current size of text input data */
+   png_size_t current_text_left;     /* how much text left to read in input */
+   png_charp current_text;           /* current text chunk buffer */
+   png_charp current_text_ptr;       /* current location in current_text */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_READ_tEXt/zTXt_SUPPORTED */
 #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
 /* for the Borland special 64K segment handler */
    png_bytepp offset_table_ptr;
@@ -439,248 +593,268 @@
    png_uint_16 offset_table_number;
    png_uint_16 offset_table_count;
    png_uint_16 offset_table_count_free;
-#endif
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED&&__TURBOC__&&!_Windows&&!__FLAT__ */
 #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 #if defined(PNG_READ_DITHER_SUPPORTED)
-   png_bytep palette_lookup; /* lookup table for dithering */
-   png_bytep dither_index; /* index translation for palette files */
-   png_uint_16p hist; /* histogram */
-#endif
+   png_bytep palette_lookup;         /* lookup table for dithering */
+   png_bytep dither_index;           /* index translation for palette files */
+   png_uint_16p hist;                /* histogram */
+#endif /* PNG_READ_DITHER_SUPPORTED */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+   png_byte heuristic_method;        /* heuristic for row filter selection */
+   png_byte num_prev_filters;        /* number of weights for previous rows */
+   png_bytep prev_filters;           /* filter type(s) of previous row(s) */
+   png_uint_16p filter_weights;      /* weight(s) for previous line(s) */
+   png_uint_16p inv_filter_weights;  /* 1/weight(s) for previous line(s) */
+   png_uint_16p filter_costs;        /* relative filter calculation cost */
+   png_uint_16p inv_filter_costs;    /* 1/relative filter calculation cost */
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
 };
 
-typedef png_struct      FAR * FAR * png_structpp;
+typedef png_struct FAR * FAR * png_structpp;
 
 /* Here are the function definitions most commonly used.  This is not
-   the place to find out how to use libpng.  See libpng.txt for the
-   full explanation, see example.c for the summary.  This just provides
-   a simple one line of the use of each function. */
+ * the place to find out how to use libpng.  See libpng.txt for the
+ * full explanation, see example.c for the summary.  This just provides
+ * a simple one line of the use of each function.
+ */
 
 /* Tell lib we have already handled the first <num_bytes> magic bytes.
-   Handling more than 8 bytes from the beginning of the file is an error. */
-extern void png_set_sig_bytes PNGARG((png_structp png_ptr, int num_bytes));
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
+   int num_bytes));
 
-/* Check sig[start] through sig[start + num_to_check] to see if it's a PNG
-   file.  Returns zero if the supplied bytes match the 8-byte PNG signature,
-   and non-zero otherwise.  Having num_to_check == 0 or start > 7 will
-   always fail (ie return non-zero). */
-extern int png_sig_cmp PNGARG((png_bytep sig, int start, int num_to_check));
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file.  Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise.  Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
+   png_size_t num_to_check));
 
-/* (Obsolete) signature checking function.  This is the same as calling
-   png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).  To be removed in a
-   future version. */
-extern int png_check_sig PNGARG((png_bytep sig, int num));
+/* Simple signature checking function.  This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
 
-/* Allocate and initialize png structure for reading, and any other memory. */
-extern png_structp png_create_read_struct PNGARG((png_const_charp user_png_ver,
-   voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn));
- 
-/* initialize png structure for reading, and allocate any other memory (old) */
-extern void png_read_init PNGARG((png_structp png_ptr));
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+extern PNG_EXPORT(png_structp,png_create_read_struct)
+   PNGARG((png_charp user_png_ver, voidp error_ptr, png_error_ptr error_fn,
+   png_error_ptr warn_fn));
 
-/* allocate and initialize png structure for reading, and any other memory */
-extern png_structp png_create_write_struct
+/* Allocate and initialize png_ptr struct for reading, and any other memory */
+extern PNG_EXPORT(png_structp,png_create_write_struct)
    PNGARG((png_const_charp user_png_ver, voidp error_ptr,
    png_error_ptr error_fn, png_error_ptr warn_fn));
 
-/* initialize png structure for writing, and allocate any other memory (old) */
-extern void png_write_init PNGARG((png_structp png_ptr));
+/* Allocate and initialize the info structure */
+extern PNG_EXPORT(png_infop,png_create_info_struct)
+   PNGARG((png_structp png_ptr));
 
-/* allocate and initialize the info structure */
-extern png_infop png_create_info_struct PNGARG((png_structp png_ptr));
-
-/* initialize the info structure (old interface) */
+/* Initialize the info structure (old interface - NOT DLL EXPORTED) */
 extern void png_info_init PNGARG((png_infop info_ptr));
 
-/* Writes all the png information before the image. */
-extern void png_write_info PNGARG((png_structp png_ptr, png_infop info_ptr));
+/* Writes all the PNG information before the image. */
+extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 
 /* read the information before the actual image data. */
-extern void png_read_info PNGARG((png_structp png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 
 #if defined(PNG_WRITE_tIME_SUPPORTED)
 /* convert from a struct tm to png_time */
-extern void png_convert_from_struct_tm PNGARG((png_timep ptime,
+extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
    struct tm FAR * ttime));
 
 /* convert from time_t to png_time.  Uses gmtime() */
-extern void png_convert_from_time_t PNGARG((png_timep ptime, time_t ttime));
-#endif
+extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
+   time_t ttime));
+#endif /* PNG_WRITE_tIME_SUPPORTED */
 
 #if defined(PNG_READ_EXPAND_SUPPORTED)
-/* Expand the data to 24 bit RGB, or 8 bit Grayscale,
-   with alpha if necessary. */
-extern void png_set_expand PNGARG((png_structp png_ptr));
-#endif
+/* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha if available. */
+extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_EXPAND_SUPPORTED */
 
 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
 /* Use blue, green, red order for pixels. */
-extern void png_set_bgr PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_BGR_SUPPORTED || PNG_WRITE_BGR_SUPPORTED */
 
 #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
 /* Expand the grayscale to 24 bit RGB if necessary. */
-extern void png_set_gray_to_rgb PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */
 
 #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
 /* Reduce RGB to grayscale. (Not yet implemented) */
-extern void png_set_rgb_to_gray PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */
 
-extern void png_build_grayscale_palette PNGARG((int bit_depth,
+extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
    png_colorp palette));
 
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_ALPHA_SUPPORTED || PNG_WRITE_SWAP_ALPHA_SUPPORTED */
+
 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 24-bit RGB images. */
+extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
+   png_uint_32 filler, int flags));
+
+/* The values of the PNG_FILLER_ defines should NOT be changed */
 #define PNG_FILLER_BEFORE 0
 #define PNG_FILLER_AFTER 1
-/* Add a filler byte to rgb images. */
-extern void png_set_filler PNGARG((png_structp png_ptr, png_byte filler,
-   int flags));
-
-/* Old way of doing this, still supported through 1.x for backwards
-   compatability, but should not be used in new code. */
-
-/* Add a filler byte to rgb images after the colors. */
-extern void png_set_rgbx PNGARG((png_structp png_ptr));
-
-/* Add a filler byte to rgb images before the colors. */
-extern void png_set_xrgb PNGARG((png_structp png_ptr));
-#endif
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
 
 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
 /* Swap bytes in 16 bit depth files. */
-extern void png_set_swap PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_SUPPORTED || PNG_WRITE_SWAP_SUPPORTED */
 
 #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
 /* Use 1 byte per pixel in 1, 2, or 4 bit depth files. */
-extern void png_set_packing PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACK_SUPPORTED || PNG_WRITE_PACK_SUPPORTED */
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPOR)
+/* Swap packing order of pixels in bytes. */
+extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACKSWAP_SUPPORTED || PNG_WRITE_PACKSWAP_SUPPOR */
 
 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
 /* Converts files to legal bit depths. */
-extern void png_set_shift PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
    png_color_8p true_bits));
-#endif
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
 
 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
     defined(PNG_WRITE_INTERLACING_SUPPORTED)
 /* Have the code handle the interlacing.  Returns the number of passes. */
-extern int png_set_interlace_handling PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INTERLACING_SUPPORTED || PNG_WRITE_INTERLACING_SUPPORTED */
 
 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
 /* Invert monocrome files */
-extern void png_set_invert_mono PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INVERT_SUPPORTED || PNG_WRITE_INVERT_SUPPORTED */
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
 /* Handle alpha and tRNS by replacing with a background color. */
+extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
+   png_color_16p background_color, int background_gamma_code,
+   int need_expand, double background_gamma));
 #define PNG_BACKGROUND_GAMMA_UNKNOWN 0
 #define PNG_BACKGROUND_GAMMA_SCREEN  1
 #define PNG_BACKGROUND_GAMMA_FILE    2
 #define PNG_BACKGROUND_GAMMA_UNIQUE  3
-extern void png_set_background PNGARG((png_structp png_ptr,
-   png_color_16p background_color, int background_gamma_code,
-   int need_expand, double background_gamma));
-#endif
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
 
 #if defined(PNG_READ_16_TO_8_SUPPORTED)
 /* strip the second byte of information from a 16 bit depth file. */
-extern void png_set_strip_16 PNGARG((png_structp png_ptr));
-#endif
+extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_16_TO_8_SUPPORTED */
 
 #if defined(PNG_READ_DITHER_SUPPORTED)
 /* Turn on dithering, and reduce the palette to the number of colors available. */
-extern void png_set_dither PNGARG((png_structp png_ptr, png_colorp palette,
-   int num_palette, int maximum_colors, png_uint_16p histogram,
-   int full_dither));
-#endif
+extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
+   png_colorp palette, int num_palette, int maximum_colors,
+   png_uint_16p histogram, int full_dither));
+#endif /* PNG_READ_DITHER_SUPPORTED */
 
 #if defined(PNG_READ_GAMMA_SUPPORTED)
 /* Handle gamma correction. */
-extern void png_set_gamma PNGARG((png_structp png_ptr, double screen_gamma,
-   double default_file_gamma));
-#endif
+extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
+   double screen_gamma, double default_file_gamma));
+#endif /* PNG_READ_GAMMA_SUPPORTED */
 
 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
 /* Set how many lines between output flushes - 0 for no flushing */
-extern void png_set_flush PNGARG((png_structp png_ptr, int nrows));
+extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
 
 /* Flush the current PNG output buffer */
-extern void png_write_flush PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
 
 /* optional update palette with requested transformations */
-extern void png_start_read_image PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
 
 /* optional call to update the users info structure */
-extern void png_read_update_info PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
    png_infop info_ptr));
 
 /* read a one or more rows of image data.*/
-extern void png_read_rows PNGARG((png_structp png_ptr,
-   png_bytepp row,
-   png_bytepp display_row, png_uint_32 num_rows));
+extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
+   png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
 
 /* read a row of data.*/
-extern void png_read_row PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
    png_bytep row,
    png_bytep display_row));
 
 /* read the whole image into memory at once. */
-extern void png_read_image PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
    png_bytepp image));
 
 /* write a row of image data */
-extern void png_write_row PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
    png_bytep row));
 
 /* write a few rows of image data */
-extern void png_write_rows PNGARG((png_structp png_ptr,
-   png_bytepp row,
-   png_uint_32 num_rows));
+extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
+   png_bytepp row, png_uint_32 num_rows));
 
 /* write the image data */
-extern void png_write_image PNGARG((png_structp png_ptr, png_bytepp image));
+extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
+   png_bytepp image));
 
-/* writes the end of the png file. */
-extern void png_write_end PNGARG((png_structp png_ptr, png_infop info_ptr));
+/* writes the end of the PNG file. */
+extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 
-/* read the end of the png file. */
-extern void png_read_end PNGARG((png_structp png_ptr, png_infop info_ptr));
+/* read the end of the PNG file. */
+extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 
-/* free any memory associated with the info_struct */
-extern void png_destroy_info_struct PNGARG((png_structp png_ptr,
+/* free any memory associated with the png_info_struct */
+extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
    png_infopp info_ptr_ptr));
 
-/* free any memory associated with the png_struct and the info_structs */
-extern void png_destroy_read_struct PNGARG((png_structpp png_ptr_ptr,
-   png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
+   png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
 
-/* free all memory used by the read (old method) */
+/* free all memory used by the read (old method - NOT DLL EXPORTED) */
 extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_infop end_info_ptr));
 
-/* free any memory associated with the png_struct and the info_structs */
-extern void png_destroy_write_struct PNGARG((png_structpp png_ptr_ptr,
-   png_infopp info_ptr_ptr));
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_write_struct)
+   PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
 
-/* free any memory used in png struct */
+/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
 extern void png_write_destroy PNGARG((png_structp png_ptr));
 
 /* set the libpng method of handling chunk CRC errors */
-extern void png_set_crc_action PNGARG((png_structp png_ptr, int crit_action,
-   int ancil_action));
+extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
+   int crit_action, int ancil_action));
 
 /* Values for png_set_crc_action() to say how to handle CRC errors in
-   ancillary and critical chunks, and whether to use the data contained
-   therein.  Note that it is impossible to "discard" data in a critical
-   chunk.  For versions prior to 0.90, the action was always error/quit,
-   whereas in version 0.90, the action for CRC errors in ancillary
-   chunks is warn/discard.
-
-        value                       action:critical     action:ancillary
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein.  Note that it is impossible to "discard" data in a critical
+ * chunk.  For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard.  These values should NOT be changed.
+ *
+ *      value                       action:critical     action:ancillary
  */
 #define PNG_CRC_DEFAULT       0  /* error/quit          warn/discard data */
 #define PNG_CRC_ERROR_QUIT    1  /* error/quit          error/quit        */
@@ -689,20 +863,22 @@
 #define PNG_CRC_QUIET_USE     4  /* quiet/use data      quiet/use data    */
 #define PNG_CRC_NO_CHANGE     5  /* use current value   use current value */
 
-/* These functions give the user control over the scan-line filtering
-   in libpng and the compression methods used by zlib.  These functions are
-   mainly useful for testing, as the defaults should work with most users.
-   Those users who are tight on memory, or are wanting faster performance
-   at the expense of compression can modify them.  See the compression
-   library header file for an explination of the compression functions */
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib.  These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them.  See the compression library
+ * header file (zlib.h) for an explination of the compression functions. */
 
-/* set the filtering method(s) used by libpng */
-extern void png_set_filter PNGARG((png_structp png_ptr, int method,
+/* set the filtering method(s) used by libpng.  Currently, the only valid
+ * value for "method" is 0 */
+extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
    int filters));
 
 /* Flags for png_set_filter() to say which filters to use.  The flags
-   are chosen so that they don't conflict with real filter types, in case they
-   are supplied instead of the #defined constants.
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
  */
 #define PNG_NO_FILTERS     0x00
 #define PNG_FILTER_NONE    0x08
@@ -713,95 +889,357 @@
 #define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
                          PNG_FILTER_AVG | PNG_FILTER_PAETH)
 
-extern void png_set_compression_level PNGARG((png_structp png_ptr,
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE  0
+#define PNG_FILTER_VALUE_SUB   1
+#define PNG_FILTER_VALUE_UP    2
+#define PNG_FILTER_VALUE_AVG   3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST  5
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows.  Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters.  This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified.  Weights have no influence on
+ * the selection of the first row filter.  Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type.  Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs.  There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs.  Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found.  If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
+   int heuristic_method, int num_weights, png_doublep filter_weights,
+   png_doublep filter_costs));
+#endif /*  PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection.  These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT    0  /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1  /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED   2  /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST       3  /* Not a valid value */
+
+/* Set the library compression level.  Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression).  Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations.  In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
    int level));
 
-extern void png_set_compression_mem_level PNGARG((png_structp png_ptr,
-   int mem_level));
+extern PNG_EXPORT(void,png_set_compression_mem_level)
+   PNGARG((png_structp png_ptr, int mem_level));
 
-extern void png_set_compression_strategy PNGARG((png_structp png_ptr,
-   int strategy));
+extern PNG_EXPORT(void,png_set_compression_strategy)
+   PNGARG((png_structp png_ptr, int strategy));
 
-extern void png_set_compression_window_bits PNGARG((png_structp png_ptr,
-   int window_bits));
+extern PNG_EXPORT(void,png_set_compression_window_bits)
+   PNGARG((png_structp png_ptr, int window_bits));
 
-extern void png_set_compression_method PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
    int method));
 
 /* These next functions are called for input/output, memory, and error
-   handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,
-   and call standard C I/O routines such as fread(), fwrite(), and
-   fprintf().  These functions can be made to use other I/O routines
-   at run time for those applications that need to handle I/O in a
-   different manner by calling png_set_???_fn().  See libpng.txt for
-   more information */
+ * handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf().  These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn().  See libpng.txt for
+ * more information.
+ */
 
-/* Write the data to whatever output you are using. */
-extern void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
-   png_uint_32 length));
-
-/* Read data from whatever input you are using */
-extern void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
-   png_uint_32 length));
-
-/* Initialize the input/output for the png file to the default functions. */
-extern void png_init_io PNGARG((png_structp png_ptr, FILE *fp));
+/* Initialize the input/output for the PNG file to the default functions. */
+extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, FILE *fp));
 
 /* Replace the (error and abort), and warning functions with user
-   supplied functions.  If no messages are to be printed you must still
-   write and use replacement functions. The replacement error_fn should
-   still do a longjmp to the last setjmp location if you are using this
-   method of error handling.  If error_fn or warning_fn is NULL, the
-   default function will be used. */
-extern void png_set_error_fn PNGARG((png_structp png_ptr, png_voidp error_ptr,
-   png_error_ptr error_fn, png_error_ptr warning_fn));
+ * supplied functions.  If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling.  If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
+   png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
 
 /* Return the user pointer associated with the error functions */
-extern png_voidp png_get_error_ptr PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
 
 /* Replace the default data output functions with a user supplied one(s).
-   If buffered output is not used, then output_flush_fn can be set to NULL.
-   If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
-   output_flush_fn will be ignored (and thus can be NULL). */
-extern void png_set_write_fn PNGARG((png_structp png_ptr, png_voidp io_ptr,
-   png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ */
+extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
+   png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
 
 /* Replace the default data input function with a user supplied one. */
-extern void png_set_read_fn PNGARG((png_structp png_ptr, png_voidp io_ptr,
-   png_rw_ptr read_data_fn));
+extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
+   png_voidp io_ptr, png_rw_ptr read_data_fn));
 
 /* Return the user pointer associated with the I/O functions */
-extern png_voidp png_get_io_ptr PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-/* Replace the default push model read functions */
-extern void png_set_push_fn PNGARG((png_structp png_ptr, png_voidp push_ptr,
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
+   png_voidp progressive_ptr,
    png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
    png_progressive_end_ptr end_fn));
 
 /* returns the user pointer associated with the push read functions */
-extern png_voidp png_get_progressive_ptr PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
+   PNGARG((png_structp png_ptr));
+
+/* function to be called when data becomes available */
+extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* function which combines rows.  Not very much different than the
+ * png_combine_row() call.  Is this even used?????
+ */
+extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
+   png_bytep old_row, png_bytep new_row));
 #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 
-extern png_voidp png_malloc PNGARG((png_structp png_ptr,
+extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
    png_uint_32 size));
 
 /* free's a pointer allocated by png_malloc() */
-extern void png_free PNGARG((png_structp png_ptr, png_voidp ptr));
+extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
 
-/* Fatal error in libpng - can't continue */ 
-extern void png_error PNGARG((png_structp png_ptr, png_const_charp error));
+#if defined(USE_FAR_KEYWORD)  /* memory model conversion function */
+extern void *far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,int check));
+#endif /* USE_FAR_KEYWORD */
+
+/* Fatal error in PNG image of libpng - can't continue */
+extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
+   png_const_charp error));
 
 /* Non-fatal error in libpng.  Can continue, but may have a problem. */
-extern void png_warning PNGARG((png_structp png_ptr, png_const_charp message));
+extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
+   png_const_charp message));
 
-/* These next functions are used internally in the code.  If you use
-   them, make sure you read and understand the png spec.  More information
-   about them can be found in the files where the functions are.
-   Feel free to move any of these outside the PNG_INTERNAL define if
-   you just need a few of them, but if you need access to more, you should
-   define PNG_INTERNAL inside your code, so everyone who includes png.h
-   won't get yet another definition the compiler has to deal with. */
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored.  The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr */
+extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row */
+extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+/* Returns number of color channels in image */
+extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+/* Returns pointer to signature string read from PNG header */
+extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_color_16p *background));
+#endif /* PNG_READ_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_color_16p background));
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, double *white_x, double *white_y, double *red_x,
+   double *red_y, double *green_x, double *green_y, double *blue_x,
+   double *blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, double white_x, double white_y, double red_x,
+   double red_y, double green_x, double green_y, double blue_x, double blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, double *file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, double file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_16p *hist));
+#endif /* PNG_READ_hIST_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_16p hist));
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
+   int *bit_depth, int *color_type, int *interlace_type,
+   int *compression_type, int *filter_type));
+  
+extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+   int color_type, int interlace_type, int compression_type, int filter_type));
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 *offset_x, png_uint_32 *offset_y,
+   int *unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 offset_x, png_uint_32 offset_y,
+   int unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+   int *type, int *nparams, png_charp *units, png_charpp *params));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
+   int type, int nparams, png_charp units, png_charpp params));
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_colorp *palette, int *num_palette));
+
+extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_colorp palette, int num_palette));
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_color_8p *sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_color_8p sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+/* png_get_text also returns the number of text chunks in text_ptr */
+extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_textp *text_ptr, int *num_text));
+#endif /* PNG_READ_tEXt_SUPPORTED || PNG_READ_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+    defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif /* PNG_READ_tEXt_SUPPORTED || PNG_WRITE_tEXt_SUPPORTED ||
+          PNG_READ_zTXt_SUPPORTED || PNG_WRITE_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_timep *mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_timep mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_bytep *trans, int *num_trans,
+   png_color_16p *trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_bytep trans, int num_trans,
+   png_color_16p trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
+
+/* Define PNG_DEBUG at compile time for debugging information.  Higher
+ * numbers for PNG_DEBUG mean more debugging information.  This has
+ * only been added since version 0.95 so it is not implemented throughout
+ * libpng yet, but more support will be added as needed.
+ */
+#if (PNG_DEBUG > 0)
+#ifndef PNG_DEBUG_FILE
+#define PNG_DEBUG_FILE stderr
+#endif /* PNG_DEBUG_FILE */
+
+#define png_debug(l,m)        if (PNG_DEBUG > l) \
+                                 fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+                                    (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))))
+#define png_debug1(l,m,p1)    if (PNG_DEBUG > l) \
+                                 fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+                                    (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))),p1)
+#define png_debug2(l,m,p1,p2) if (PNG_DEBUG > l) \
+                                 fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+                                    (l==2 ? "\t\t":(l==3 ? "\t\t\t":""))),p1,p2)
+#else
+#define png_debug(l, m)
+#define png_debug1(l, m, p1)
+#define png_debug2(l, m, p1, p2)
+#endif /* (PNG_DEBUG > 0) */
+
+/* These next functions are used internally in the code.  They generally
+ * shouldn't be used unless you are writing code to add or replace some
+ * functionality in libpng.  More information about most functions can
+ * be found in the files where the functions are located.
+ */
 
 #if defined(PNG_INTERNAL)
 
@@ -818,14 +1256,13 @@
 #define PNG_READ_SIG_MODE   0
 #define PNG_READ_CHUNK_MODE 1
 #define PNG_READ_IDAT_MODE  2
-#define PNG_READ_END_MODE   3
-#define PNG_SKIP_MODE       4
-#define PNG_READ_tEXt_MODE  5
-#define PNG_READ_zTXt_MODE  6
-#define PNG_READ_DONE_MODE  7
-#define PNG_ERROR_MODE      8
+#define PNG_SKIP_MODE       3
+#define PNG_READ_tEXt_MODE  4
+#define PNG_READ_zTXt_MODE  5
+#define PNG_READ_DONE_MODE  6
+#define PNG_ERROR_MODE      7
 
-/* defines for the transformations the PNG library does on the image data */
+/* flags for the transformations the PNG library does on the image data */
 #define PNG_BGR                0x0001
 #define PNG_INTERLACE          0x0002
 #define PNG_PACK               0x0004
@@ -835,19 +1272,28 @@
 #define PNG_DITHER             0x0040
 #define PNG_BACKGROUND         0x0080
 #define PNG_BACKGROUND_EXPAND  0x0100
-#define PNG_RGB_TO_GRAY        0x0200
+#define PNG_RGB_TO_GRAY        0x0200 /* Not currently implemented */
 #define PNG_16_TO_8            0x0400
 #define PNG_RGBA               0x0800
 #define PNG_EXPAND             0x1000
 #define PNG_GAMMA              0x2000
 #define PNG_GRAY_TO_RGB        0x4000
 #define PNG_FILLER             0x8000
+#define PNG_PACKSWAP          0x10000
+#define PNG_SWAP_ALPHA        0x20000
+#define PNG_STRIP_ALPHA       0x40000
 
 /* flags for png_create_struct */
 #define PNG_STRUCT_PNG   0x0001
 #define PNG_STRUCT_INFO  0x0002
 
-/* flags for the png_ptr->flags rather than declaring a bye for each one */
+/* Scaling factor for filter heuristic weighting calculations */
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
+#define PNG_COST_SHIFT 3
+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
+
+/* flags for the png_ptr->flags rather than declaring a byte for each one */
 #define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001
 #define PNG_FLAG_ZLIB_CUSTOM_LEVEL        0x0002
 #define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL    0x0004
@@ -880,14 +1326,11 @@
    abs((int)((c1).green) - (int)((c2).green)) + \
    abs((int)((c1).blue) - (int)((c2).blue)))
 
-/* variables defined in png.c - only it needs to define PNG_NO_EXTERN */
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
 #ifndef PNG_NO_EXTERN
-/* place to hold the signiture string for a png file. */
+/* place to hold the signiture string for a PNG file. */
 extern png_byte FARDATA png_sig[];
 
-/* version information for c files, stored in png.c. */
-extern char png_libpng_ver[];
-
 /* constant strings for known chunk types.  If you need to add a chunk,
    add a string holding the name here.  See png.c for more details.  We
    can't selectively include these, since we still check for chunk in the
@@ -896,357 +1339,344 @@
 extern png_byte FARDATA png_IDAT[];
 extern png_byte FARDATA png_IEND[];
 extern png_byte FARDATA png_PLTE[];
-extern png_byte FARDATA png_gAMA[];
-extern png_byte FARDATA png_sBIT[];
-extern png_byte FARDATA png_cHRM[];
-extern png_byte FARDATA png_tRNS[];
 extern png_byte FARDATA png_bKGD[];
+extern png_byte FARDATA png_cHRM[];
+extern png_byte FARDATA png_gAMA[];
 extern png_byte FARDATA png_hIST[];
-extern png_byte FARDATA png_tEXt[];
-extern png_byte FARDATA png_zTXt[];
-extern png_byte FARDATA png_pHYs[];
 extern png_byte FARDATA png_oFFs[];
+extern png_byte FARDATA png_pCAL[];
+extern png_byte FARDATA png_pHYs[];
+extern png_byte FARDATA png_sBIT[];
+extern png_byte FARDATA png_tEXt[];
 extern png_byte FARDATA png_tIME[];
-/* Structures to facilitate easy interlacing.  See png.c for more details */
-extern int FARDATA png_pass_start[];
-extern int FARDATA png_pass_inc[];
-extern int FARDATA png_pass_ystart[];
-extern int FARDATA png_pass_yinc[];
-/* these are not currently used.  If you need them, see png.c
-extern int FARDATA png_pass_width[];
-extern int FARDATA png_pass_height[];
-*/
-extern int FARDATA png_pass_mask[];
-extern int FARDATA png_pass_dsp_mask[];
+extern png_byte FARDATA png_tRNS[];
+extern png_byte FARDATA png_zTXt[];
 
 #endif /* PNG_NO_EXTERN */
 
+/* Inline macros to do direct reads of bytes from the input buffer.  These
+ * require that you are using an architecture that uses PNG byte ordering
+ * (MSB first) and supports unaligned data storage.  I think that PowerPC
+ * in big-endian mode and 680x0 are the only ones that will support this.
+ * The x86 line of processors definitely do not.  The png_get_int_32()
+ * routine also assumes we are using two's complement format for negative
+ * values, which is almost certainly true.
+ */
+#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
+#if defined(PNG_READ_pCAL_SUPPORTED)
+#define png_get_int_32(buf) ( *((png_int_32p) (buf)))
+#endif /* PNG_READ_pCAL_SUPPORTED */
+#define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+#define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
+#else
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf));
+PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf));
+#endif /* PNG_BIG_ENDIAN_GET_SUPPORTED */
+
+/* Initialize png_ptr struct for reading, and allocate any other memory
+ * (old interface - NOT DLL EXPORTED) */
+extern void png_read_init PNGARG((png_structp png_ptr));
+
+/* Initialize png_ptr struct for writing, and allocate any other memory
+ * (old interface - NOT DLL EXPORTED) */
+extern void png_write_init PNGARG((png_structp png_ptr));
+
 /* allocate memory for an internal libpng struct */
-extern png_voidp png_create_struct PNGARG((int type));
+PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
 
 /* free memory from internal libpng struct */
-extern void png_destroy_struct PNGARG((png_voidp struct_ptr));
+PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
 
 /* free any memory that info_ptr points to and reset struct. */
-extern void png_info_destroy PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
    png_infop info_ptr));
 
 /* Function to allocate memory for zlib. */
-extern voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
+PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
 
 /* function to free memory for zlib */
-extern void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
+PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
 
 /* reset the CRC variable */
-extern void png_reset_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
+
+/* Write the "data" buffer to whatever output you are using. */
+PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
+   png_size_t length));
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
+   png_size_t length));
 
 /* read bytes into buf, and update png_ptr->crc */
-extern void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
-   png_uint_32 length));
+PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
+   png_size_t length));
 
 /* read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
-extern int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
+PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
 
 /* read the CRC from the file and compare it to the libpng calculated CRC */
-extern int png_crc_error PNGARG((png_structp png_ptr));
+PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
 
-/* calculate the crc over a section of data.  Note that while we
-   are passing in a 32 bit value for length, on 16 bit machines, you
-   would need to use huge pointers to access all that data.  See the
-   code in png.c for more information. */
-extern void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
-   png_uint_32 length));
+/* Calculate the CRC over a section of data.  Note that we are only
+ * passing a maximum of 64K on systems that have this as a memory limit,
+ * since this is the maximum buffer size we can specify.
+ */
+PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
+   png_size_t length));
 
 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
-extern void png_flush PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
 #endif
 
-/* place a 32 bit number into a buffer in png byte order.  We work
-   with unsigned numbers for convenience, you may have to cast
-   signed numbers (if you use any, most png data is unsigned). */
-extern void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i));
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
+ * The only currently known PNG chunk that uses unsigned numbers is
+ * the ancillary extension chunk, pCAL.
+ */
+PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i));
 
-/* place a 16 bit number into a buffer in png byte order */
-extern void png_save_uint_16 PNGARG((png_bytep buf, png_uint_16 i));
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i));
+#endif
 
-/* write a 32 bit number */
-extern void png_write_uint_32 PNGARG((png_structp png_ptr, png_uint_32 i));
+/* place a 16 bit number into a buffer in PNG byte order */
+PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, png_uint_16 i));
 
-/* write a 16 bit number */
-extern void png_write_uint_16 PNGARG((png_structp png_ptr, png_uint_16 i));
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+PNG_EXTERN void png_write_chunk PNGARG((png_structp png_ptr,
+   png_bytep chunk_name, png_bytep data, png_size_t length));
 
-/* Write a png chunk.  */
-extern void png_write_chunk PNGARG((png_structp png_ptr, png_bytep chunk_name,
-   png_bytep data, png_uint_32 length));
+/* Write the start of a PNG chunk - length and chunk name. */
+PNG_EXTERN void png_write_chunk_start PNGARG((png_structp png_ptr,
+   png_bytep chunk_name, png_uint_32 length));
 
-/* Write the start of a png chunk. */
-extern void png_write_chunk_start PNGARG((png_structp png_ptr, png_bytep chunk_name,
-   png_uint_32 length));
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+PNG_EXTERN void png_write_chunk_data PNGARG((png_structp png_ptr,
+   png_bytep data, png_size_t length));
 
-/* write the data of a png chunk started with png_write_chunk_start(). */
-extern void png_write_chunk_data PNGARG((png_structp png_ptr, png_bytep data,
-   png_uint_32 length));
-
-/* finish a chunk started with png_write_chunk_start() */
-extern void png_write_chunk_end PNGARG((png_structp png_ptr));
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+PNG_EXTERN void png_write_chunk_end PNGARG((png_structp png_ptr));
 
 /* simple function to write the signiture */
-extern void png_write_sig PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
 
 /* write various chunks */
 
 /* Write the IHDR chunk, and update the png_struct with the necessary
    information. */
-extern void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
+PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
    png_uint_32 height,
    int bit_depth, int color_type, int compression_type, int filter_type,
    int interlace_type));
 
-extern void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
-   png_uint_32 number));
+PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
+   png_uint_32 num_pal));
 
-extern void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
-   png_uint_32 length));
+PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
+   png_size_t length));
 
-extern void png_write_IEND PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
 
 #if defined(PNG_WRITE_gAMA_SUPPORTED)
-extern void png_write_gAMA PNGARG((png_structp png_ptr, double gamma));
+PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
 #endif
 
 #if defined(PNG_WRITE_sBIT_SUPPORTED)
-extern void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
+PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
    int color_type));
 #endif
 
 #if defined(PNG_WRITE_cHRM_SUPPORTED)
-extern void png_write_cHRM PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr,
    double white_x, double white_y,
    double red_x, double red_y, double green_x, double green_y,
    double blue_x, double blue_y));
 #endif
 
 #if defined(PNG_WRITE_tRNS_SUPPORTED)
-extern void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
+PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
    png_color_16p values, int number, int color_type));
 #endif
 
 #if defined(PNG_WRITE_bKGD_SUPPORTED)
-extern void png_write_bKGD PNGARG((png_structp png_ptr, png_color_16p values,
-   int color_type));
+PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
+   png_color_16p values, int color_type));
 #endif
 
 #if defined(PNG_WRITE_hIST_SUPPORTED)
-extern void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
-   int number));
+PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
+   png_uint_32 num_hist));
 #endif
 
 #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
-extern int png_check_keyword PNGARG((png_structp png_ptr, png_charpp key));
+PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
+   png_charp key, png_bytepp new_key));
 #endif
 
 #if defined(PNG_WRITE_tEXt_SUPPORTED)
-extern void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
-   png_charp text, png_uint_32 text_len));
+PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
+   png_charp text, png_size_t text_len));
 #endif
 
 #if defined(PNG_WRITE_zTXt_SUPPORTED)
-extern void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
-   png_charp text, png_uint_32 text_len, int compression));
-#endif
-
-#if defined(PNG_WRITE_pHYs_SUPPORTED)
-extern void png_write_pHYs PNGARG((png_structp png_ptr,
-   png_uint_32 x_pixels_per_unit,
-   png_uint_32 y_pixels_per_unit,
-   int unit_type));
+PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
+   png_charp text, png_size_t text_len, int compression));
 #endif
 
 #if defined(PNG_WRITE_oFFs_SUPPORTED)
-extern void png_write_oFFs PNGARG((png_structp png_ptr,
-   png_uint_32 x_offset,
-   png_uint_32 y_offset,
+PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
+   png_uint_32 x_offset, png_uint_32 y_offset, int unit_type));
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
+   png_int_32 X0, png_int_32 X1, int type, int nparams,
+   png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
+   png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
    int unit_type));
 #endif
 
 #if defined(PNG_WRITE_tIME_SUPPORTED)
-extern void png_write_tIME PNGARG((png_structp png_ptr, png_timep mod_time));
-#endif
-
-/* Internal use only.   Called when finished processing a row of data */
-extern void png_write_finish_row PNGARG((png_structp png_ptr));
-
-/* Internal use only.   Called before first row of data */
-extern void png_write_start_row PNGARG((png_structp png_ptr));
-
-/* callbacks for png chunks */
-extern void png_read_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 width, png_uint_32 height, int bit_depth,
-   int color_type, int compression_type, int filter_type,
-   int interlace_type));
-
-extern void png_read_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_colorp palette, int num));
-
-#if defined(PNG_READ_gAMA_SUPPORTED)
-extern void png_read_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
-   double gamma));
-#endif
-
-#if defined(PNG_READ_sBIT_SUPPORTED)
-extern void png_read_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_color_8p sig_bit));
-#endif
-
-#if defined(PNG_READ_cHRM_SUPPORTED)
-extern void png_read_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
-   double white_x, double white_y, double red_x, double red_y,
-   double green_x, double green_y, double blue_x, double blue_y));
-#endif
-
-#if defined(PNG_READ_tRNS_SUPPORTED)
-extern void png_read_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_bytep trans, int num_trans,   png_color_16p trans_values));
-#endif
-
-#if defined(PNG_READ_bKGD_SUPPORTED)
-extern void png_read_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_color_16p background));
-#endif
-
-#if defined(PNG_READ_hIST_SUPPORTED)
-extern void png_read_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_16p hist));
-#endif
-
-#if defined(PNG_READ_pHYs_SUPPORTED)
-extern void png_read_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 res_x, png_uint_32 res_y, int unit_type));
-#endif
-
-#if defined(PNG_READ_oFFs_SUPPORTED)
-extern void png_read_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 offset_x, png_uint_32 offset_y, int unit_type));
-#endif
-
-#if defined(PNG_READ_tIME_SUPPORTED)
-extern void png_read_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
    png_timep mod_time));
 #endif
 
-#if defined(PNG_READ_tEXt_SUPPORTED)
-extern void png_read_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_charp key, png_charp text, png_uint_32 text_len));
-#endif
+/* Called when finished processing a row of data */
+PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
 
-#if defined(PNG_READ_zTXt_SUPPORTED)
-extern void png_read_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_charp key, png_charp text, png_uint_32 text_len, int compression));
-#endif
+/* Internal use only.   Called before first row of data */
+PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
 
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-void
-png_build_gamma_table PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
 #endif
 
 /* combine a row of data, dealing with alpha, etc. if requested */
-extern void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
+PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
    int mask));
 
 #if defined(PNG_READ_INTERLACING_SUPPORTED)
 /* expand an interlaced row */
-extern void png_do_read_interlace PNGARG((png_row_infop row_info,
-   png_bytep row, int pass));
+PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
+   png_bytep row, int pass, png_uint_32 transformations));
 #endif
 
 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
 /* grab pixels out of a row for an interlaced pass */
-extern void png_do_write_interlace PNGARG((png_row_infop row_info,
+PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
    png_bytep row, int pass));
 #endif
 
 /* unfilter a row */
-extern void png_read_filter_row PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
    png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
-/* choose the best filter to use and filter the row data */
-extern void png_write_find_filter PNGARG((png_structp png_ptr,
+
+/* Choose the best filter to use and filter the row data */
+PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
    png_row_infop row_info));
-/* write out the filtered row */
-extern void png_write_filtered_row PNGARG((png_structp png_ptr,
+
+/* Write out the filtered row. */
+PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
    png_bytep filtered_row));
 /* finish a row while reading, dealing with interlacing passes, etc. */
-extern void png_read_finish_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
+
 /* initialize the row buffers, etc. */
-extern void png_read_start_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
 /* optional call to update the users info structure */
-extern void png_read_transform_info PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
    png_infop info_ptr));
 
 /* these are the functions that do the transformations */
 #if defined(PNG_READ_FILLER_SUPPORTED)
-extern void png_do_read_filler PNGARG((png_row_infop row_info,
-   png_bytep row, png_byte filler, png_uint_32 filler_loc));
+PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
+   png_bytep row, png_uint_32 filler, png_uint_32 flags));
 #endif
 
-#if defined(PNG_WRITE_FILLER_SUPPORTED)
-extern void png_do_write_filler PNGARG((png_row_infop row_info,
-   png_bytep row, png_uint_32 filler_loc));
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
+   png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
+   png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
+   png_bytep row, png_uint_32 flags));
 #endif
 
 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
-extern void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPOR)
+PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
 #endif
 
 #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-extern void png_do_rgb_to_gray PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_rgb_to_gray PNGARG((png_row_infop row_info,
+   png_bytep row));
 #endif
 
 #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
-extern void png_do_gray_to_rgb PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
+   png_bytep row));
 #endif
 
 #if defined(PNG_READ_PACK_SUPPORTED)
-extern void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
 #endif
 
 #if defined(PNG_READ_SHIFT_SUPPORTED)
-extern void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
+PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
    png_color_8p sig_bits));
 #endif
 
 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
-extern void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
 #endif
 
 #if defined(PNG_READ_16_TO_8_SUPPORTED)
-extern void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
 #endif
 
 #if defined(PNG_READ_DITHER_SUPPORTED)
-extern void png_do_dither PNGARG((png_row_infop row_info,
+PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
    png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
+
 #  if defined(PNG_CORRECT_PALETTE_SUPPORTED)
-extern void png_correct_palette PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
    png_colorp palette, int num_palette));
 #  endif
 #endif
 
 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-extern void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
+PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
 #endif
 
 #if defined(PNG_WRITE_PACK_SUPPORTED)
-extern void png_do_pack PNGARG((png_row_infop row_info,
-   png_bytep row, png_byte bit_depth));
+PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
+   png_bytep row, png_uint_32 bit_depth));
 #endif
 
 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
-extern void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
+PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
    png_color_8p bit_depth));
 #endif
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
-extern void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
    png_color_16p trans_values, png_color_16p background,
    png_color_16p background_1,
    png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
@@ -1255,159 +1685,148 @@
 #endif
 
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-extern void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
+PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
    png_bytep gamma_table, png_uint_16pp gamma_16_table,
    int gamma_shift));
 #endif
 
 #if defined(PNG_READ_EXPAND_SUPPORTED)
-extern void png_do_expand_palette PNGARG((png_row_infop row_info,
+PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
    png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
-extern void png_do_expand PNGARG((png_row_infop row_info,
+PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
    png_bytep row, png_color_16p trans_value));
 #endif
 
-/* unpack 16 and 32 bit values from a string */
-extern png_uint_32 png_get_uint_32 PNGARG((png_bytep buf));
-extern png_uint_16 png_get_uint_16 PNGARG((png_bytep buf));
-
-/* the following decodes the appropriate chunks, and does error correction,
-   then calls the appropriate callback for the chunk if it is valid */
+/* The following decodes the appropriate chunks, and does error correction,
+ * then calls the appropriate callback for the chunk if it is valid */
 
 /* decode the IHDR chunk */
-extern void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
-extern void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
-extern void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
+
 #if defined(PNG_READ_gAMA_SUPPORTED)
-extern void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_sBIT_SUPPORTED)
-extern void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_cHRM_SUPPORTED)
-extern void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_tRNS_SUPPORTED)
-extern void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_bKGD_SUPPORTED)
-extern void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_hIST_SUPPORTED)
-extern void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
-#endif
-
-#if defined(PNG_READ_pHYs_SUPPORTED)
-extern void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_oFFs_SUPPORTED)
-extern void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_tIME_SUPPORTED)
-extern void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_tEXt_SUPPORTED)
-extern void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
 #if defined(PNG_READ_zTXt_SUPPORTED)
-extern void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
    png_uint_32 length));
 #endif
 
-extern void png_handle_unknown PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
+PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 length));
 
-extern void png_check_chunk_name PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
    png_bytep chunk_name));
 
 /* handle the transformations for reading and writing */
-extern void png_do_read_transformations PNGARG((png_structp png_ptr));
-extern void png_do_write_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
 
-extern void png_init_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-extern void png_push_read_chunk PNGARG((png_structp png_ptr, png_infop info_ptr));
-extern void png_push_read_sig PNGARG((png_structp png_ptr, png_infop info_ptr));
-extern void png_push_check_crc PNGARG((png_structp png_ptr));
-extern void png_push_crc_skip PNGARG((png_structp png_ptr, png_uint_32 length));
-extern void png_push_skip PNGARG((png_structp png_ptr));
-extern void png_push_fill_buffer PNGARG((png_structp png_ptr, png_bytep buffer,
-   png_uint_32 length));
-extern void png_push_save_buffer PNGARG((png_structp png_ptr));
-extern void png_push_restore_buffer PNGARG((png_structp png_ptr, png_bytep buffer,
-   png_uint_32 buffer_length));
-extern void png_push_read_IDAT PNGARG((png_structp png_ptr));
-extern void png_process_IDAT_data PNGARG((png_structp png_ptr,
-   png_bytep buffer, png_uint_32 buffer_length));
-extern void png_push_process_row PNGARG((png_structp png_ptr));
-extern void png_push_handle_PLTE PNGARG((png_structp png_ptr,
-   png_uint_32 length));
-extern void png_push_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
-extern void png_push_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
-extern void png_push_handle_unknown PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
-extern void png_push_have_info PNGARG((png_structp png_ptr, png_infop info_ptr));
-extern void png_push_have_end PNGARG((png_structp png_ptr, png_infop info_ptr));
-extern void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
-extern void png_push_read_end PNGARG((png_structp png_ptr, png_infop info_ptr));
-extern void png_process_some_data PNGARG((png_structp png_ptr,
+PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
    png_infop info_ptr));
-extern void png_read_push_finish_row PNGARG((png_structp png_ptr));
-#if defined(PNG_READ_tEXt_SUPPORTED)
-extern void png_push_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
    png_uint_32 length));
-extern void png_push_read_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr));
+PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
+   png_bytep buffer, png_size_t length));
+PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
+   png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
+   png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
+PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
+PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 #endif
 #if defined(PNG_READ_zTXt_SUPPORTED)
-extern void png_push_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_uint_32 length));
-extern void png_push_read_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr));
+PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
+   png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
+   png_infop info_ptr));
 #endif
 
 #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 
 #endif /* PNG_INTERNAL */
 
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-extern void png_process_data PNGARG((png_structp png_ptr, png_infop info_ptr,
-   png_bytep buffer, png_uint_32 buffer_size));
-extern void png_set_progressive_read_fn PNGARG((png_structp png_ptr,
-   png_voidp progressive_ptr,
-   png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
-   png_progressive_end_ptr end_fn));
-extern void png_progressive_combine_row PNGARG((png_structp png_ptr,
-   png_bytep old_row, png_bytep new_row));
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-
-#if defined(USE_FAR_KEYWORD)  /* memory model independent fns */
-extern void *far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,int check));
-#endif /* defined(USE_FAR_KEYWORD) */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/pngconf.h b/pngconf.h
index 03df325..eee01db 100644
--- a/pngconf.h
+++ b/pngconf.h
@@ -1,10 +1,11 @@
 
 /* pngconf.c - machine configurable file for libpng
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   December 3, 1996
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 /* Any machine specific code is near the front of this file, so if you
@@ -29,16 +30,16 @@
 
 #define PNG_ZBUF_SIZE 8192
 
-/* If you are running on a machine where you cannot allocate more then
-   64K of memory, uncomment this.  While libpng will not normally need
-   that much memory in a chunk (unless you load up a very large file),
-   zlib needs to know how big of a chunk it can use, and libpng thus
-   makes sure to check any memory allocation to verify it will fit
-   into memory.
-#define PNG_MAX_ALLOC_64K
+/* If you are running on a machine where you cannot allocate more
+   than 64K of memory at once, uncomment this.  While libpng will not
+   normally need that much memory in a chunk (unless you load up a very
+   large file), zlib needs to know how big of a chunk it can use, and
+   libpng thus makes sure to check any memory allocation to verify it
+   will fit into memory.
+#define PNG_MAX_MALLOC_64K
 */
-#ifdef MAXSEG_64K
-#define PNG_MAX_ALLOC_64K
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+#define PNG_MAX_MALLOC_64K
 #endif
 
 /* This protects us against compilers which run on a windowing system
@@ -56,12 +57,13 @@
 
 /* This macro protects us against machines that don't have function
    prototypes (ie K&R style headers).  If your compiler does not handle
-   function prototypes, define this macro.  I've always been able to use
-   _NO_PROTO as the indicator, but you may need to drag the empty declaration
-   out in front of here, or change the ifdef to suit your own needs. */
+   function prototypes, define this macro and use the included ansi2knr.
+   I've always been able to use _NO_PROTO as the indicator, but you may
+   need to drag the empty declaration out in front of here, or change the
+   ifdef to suit your own needs. */
 #ifndef PNGARG
 
-#ifdef OF /* Zlib prototype munger */
+#ifdef OF /* zlib prototype munger */
 #define PNGARG(arglist) OF(arglist)
 #else
 
@@ -85,17 +87,16 @@
 #include <sys/types.h>
 #endif
 
-/* need the time information for reading tIME chunks */
-#include <time.h>
-
-/* This is an attempt to force a single setjmp behaviour on Linux */
+/* This is an attempt to force a single setjmp behaviour on Linux.  If
+   the X config stuff didn't define _BSD_SOURCE we wouldn't need this. */
 #ifdef linux
 #ifdef _BSD_SOURCE
 #define _PNG_SAVE_BSD_SOURCE
 #undef _BSD_SOURCE
 #endif
 #ifdef _SETJMP_H
-error: png.h already includes setjmp.h
+#error  __png_h_already_includes_setjmp_h__
+#error  __dont_include_it_again__
 #endif
 #endif /* linux */
 
@@ -115,25 +116,39 @@
 #include <string.h>
 #endif
 
-/* Other defines for things like memory and the like can go here.  These
-   are the only files included in libpng, so if you need to change them,
-   change them here.  They are only included if PNG_INTERNAL is defined. */
+/* Other defines for things like memory and the like can go here.  */
 #ifdef PNG_INTERNAL
 #include <stdlib.h>
+/* Where do we need this???
 #include <ctype.h>
+*/
+
+/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
+ * aren't usually used outside the library (as far as I know), so it is
+ * debatable if they should be exported at all.  In the future, when it is
+ * possible to have run-time registry of chunk-handling functions, some of
+ * these will be made available again.
+#define PNG_EXTERN extern
+ */
+#define PNG_EXTERN
 
 /* Other defines specific to compilers can go here.  Try to keep
    them inside an appropriate ifdef/endif pair for portability */
 
-#ifdef MACOS
+#if defined(MACOS)
+/* We need to check that <math.h> hasn't already been included earlier
+   as it seems it doesn't agree with <fp.h>, yet we should really use
+   <fp.h> if possible. */
+#if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
 #include <fp.h>
+#endif
 #else
 #include <math.h>
 #endif
 
 /* For some reason, Borland C++ defines memcmp, etc. in mem.h, not
    stdlib.h like it should (I think).  Or perhaps this is a C++
-   feature? */
+   "feature"? */
 #ifdef __TURBOC__
 #include <mem.h>
 #include "alloc.h"
@@ -159,6 +174,10 @@
 
 #define PNG_MAX_GAMMA_8 11
 
+/* This controls how much a difference in gamma we can tolerate before
+   we actually start doing gamma conversion.  */
+#define PNG_GAMMA_THRESHOLD 0.05
+
 #endif /* PNG_INTERNAL */
 
 /* The following uses const char * instead of char * for error
@@ -167,8 +186,7 @@
    normally defined to make configuration easier, as it is not a
    critical part of the code.
    */
-
-#define PNG_USE_CONST
+#undef PNG_USE_CONST
 
 #ifdef PNG_USE_CONST
 #  define PNG_CONST const
@@ -191,12 +209,14 @@
 
 /* Any transformations you will not be using can be undef'ed here */
 #define PNG_PROGRESSIVE_READ_SUPPORTED
+#define PNG_READ_OPT_PLTE_SUPPORTED
 #define PNG_READ_INTERLACING_SUPPORTED
 #define PNG_READ_EXPAND_SUPPORTED
 #define PNG_READ_SHIFT_SUPPORTED
 #define PNG_READ_PACK_SUPPORTED
 #define PNG_READ_BGR_SUPPORTED
 #define PNG_READ_SWAP_SUPPORTED
+#define PNG_READ_PACKSWAP_SUPPORTED
 #define PNG_READ_INVERT_SUPPORTED
 #define PNG_READ_DITHER_SUPPORTED
 #define PNG_READ_BACKGROUND_SUPPORTED
@@ -204,55 +224,79 @@
 #define PNG_READ_FILLER_SUPPORTED
 #define PNG_READ_GAMMA_SUPPORTED
 #define PNG_READ_GRAY_TO_RGB_SUPPORTED
+#define PNG_READ_SWAP_ALPHA_SUPPORTED
+#define PNG_READ_STRIP_ALPHA_SUPPORTED
 
 #define PNG_WRITE_INTERLACING_SUPPORTED
 #define PNG_WRITE_SHIFT_SUPPORTED
 #define PNG_WRITE_PACK_SUPPORTED
 #define PNG_WRITE_BGR_SUPPORTED
 #define PNG_WRITE_SWAP_SUPPORTED
+#define PNG_WRITE_PACKSWAP_SUPPORTED
 #define PNG_WRITE_INVERT_SUPPORTED
-#define PNG_WRITE_FILLER_SUPPORTED
+#define PNG_WRITE_FILLER_SUPPORTED  /* This is the same as WRITE_STRIP_ALPHA */
 #define PNG_WRITE_FLUSH_SUPPORTED
+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+
+/* These are currently experimental features */
+#undef PNG_READ_16_TO_8_ACCURATE_SHIFT_SUPPORTED /* very little testing */
+#undef PNG_READ_COMPOSITE_NODIV_SUPPORTED        /* very little testing */
+
+/* This is only for PowerPC big-endian and 680x0 systems */
+#undef PNG_READ_BIG_ENDIAN_SUPPORTED             /* some testing */
 
 /* These functions are turned off by default, as they will be phased out. */
 #undef  PNG_USE_OWN_CRC
+#undef  PNG_USELESS_TESTS_SUPPORTED
 #undef  PNG_CORRECT_PALETTE_SUPPORTED
 
-/* any chunks you are not interested in, you can undef here.  The
-   ones that allocate memory may be expecially important (hIST,
-   tEXt, zTXt, tRNS) Others will just save time and make png_info
-   smaller.  OPT_PLTE only disables the optional palette in RGB
-   and RGB Alpha images. */
+/* Any chunks you are not interested in, you can undef here.  The
+ * ones that allocate memory may be expecially important (hIST,
+ * tEXt, zTXt, tRNS, pCAL).  Others will just save time and make png_info
+ * a bit smaller.  OPT_PLTE only disables the optional palette in RGB
+ * and RGBA images.
+ */
 
-#define PNG_READ_gAMA_SUPPORTED
-#define PNG_READ_sBIT_SUPPORTED
-#define PNG_READ_cHRM_SUPPORTED
-#define PNG_READ_tRNS_SUPPORTED
 #define PNG_READ_bKGD_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
 #define PNG_READ_hIST_SUPPORTED
-#define PNG_READ_pHYs_SUPPORTED
 #define PNG_READ_oFFs_SUPPORTED
-#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
 #define PNG_READ_tEXt_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
 #define PNG_READ_zTXt_SUPPORTED
-#define PNG_READ_OPT_PLTE_SUPPORTED
 
-#define PNG_WRITE_gAMA_SUPPORTED
-#define PNG_WRITE_sBIT_SUPPORTED
-#define PNG_WRITE_cHRM_SUPPORTED
-#define PNG_WRITE_tRNS_SUPPORTED
 #define PNG_WRITE_bKGD_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
 #define PNG_WRITE_hIST_SUPPORTED
-#define PNG_WRITE_pHYs_SUPPORTED
 #define PNG_WRITE_oFFs_SUPPORTED
-#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
 #define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_SUPPORTED
 #define PNG_WRITE_zTXt_SUPPORTED
 
+/* need the time information for reading tIME chunks */
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+#include <time.h>
+#endif
+
 /* Some typedefs to get us started.  These should be safe on most of the
-   common platforms.  The typedefs should be at least as large as the
-   numbers suggest (a png_uint_32 must be at least 32 bits long), but they
-   don't have to be exactly that size. */
+ * common platforms.  The typedefs should be at least as large as the
+ * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
+ * don't have to be exactly that size.  Some compilers dislike passing
+ * unsigned shorts as function parameters, so you may be better off using
+ * unsigned int for png_uint_16.  Likewise, for 64-bit systems, you may
+ * want to have unsigned int for png_uint_32 instead of unsigned long.
+ */
 
 typedef unsigned long png_uint_32;
 typedef long png_int_32;
@@ -264,14 +308,14 @@
    change (I'm not sure if you will or not, so I thought I'd be safe) */
 typedef size_t png_size_t;
 
-/* The following is needed for medium model support. It cannot be in the
-   PNG_INTERNAL section. Needs modification for other compilers besides
-   MSC. Model independent support declares all arrays that might be very
-   large using the far keyword. The Zlib version used must also support
-   model independent data. As of version Zlib .95, the necessary changes
-   have been made in Zlib. The USE_FAR_KEYWORD define triggers other
-   changes that are needed. Most of the far keyword changes are hidden
-   inside typedefs with suffix "f". (Tim Wegner) */
+/* The following is needed for medium model support.  It cannot be in the
+ * PNG_INTERNAL section.  Needs modification for other compilers besides
+ * MSC.  Model independent support declares all arrays and pointers to be
+ * large using the far keyword.  The zlib version used must also support
+ * model independent data.  As of version zlib 1.0.4, the necessary changes
+ * have been made in zlib.  The USE_FAR_KEYWORD define triggers other
+ * changes that are needed. (Tim Wegner)
+ */
 
 /* Separate compiler dependencies (problem here is that zlib.h always
    defines FAR. (SJT) */
@@ -319,17 +363,12 @@
 #   define FAR
 #endif
 
-/* SJT: At this point FAR is always defined */
-
-/* SJT: */
+/* At this point FAR is always defined */
 #ifndef FARDATA
 #define FARDATA
 #endif
 
-/* Not used anymore (as of 0.88), but kept for compatability (for now). */
-typedef unsigned char FAR png_bytef;
-
-/* SJT: Add typedefs for pointers */
+/* Add typedefs for pointers */
 typedef void            FAR * png_voidp;
 typedef png_byte        FAR * png_bytep;
 typedef png_uint_32     FAR * png_uint_32p;
@@ -338,8 +377,9 @@
 typedef png_int_16      FAR * png_int_16p;
 typedef PNG_CONST char  FAR * png_const_charp;
 typedef char            FAR * png_charp;
+typedef double          FAR * png_doublep;
 
-/*  SJT: Pointers to pointers; i.e. arrays */
+/* Pointers to pointers; i.e. arrays */
 typedef png_byte        FAR * FAR * png_bytepp;
 typedef png_uint_32     FAR * FAR * png_uint_32pp;
 typedef png_int_32      FAR * FAR * png_int_32pp;
@@ -347,16 +387,29 @@
 typedef png_int_16      FAR * FAR * png_int_16pp;
 typedef PNG_CONST char  FAR * FAR * png_const_charpp;
 typedef char            FAR * FAR * png_charpp;
+typedef double          FAR * FAR * png_doublepp;
 
+/* Pointers to pointers to pointers; i.e. pointer to array */
+typedef char            FAR * FAR * FAR * png_charppp;
 
-/* SJT: libpng typedefs for types in zlib. If Zlib changes
-   or another compression library is used, then change these.
-   Eliminates need to change all the source files.
-*/
+/* libpng typedefs for types in zlib. If zlib changes
+ * or another compression library is used, then change these.
+ * Eliminates need to change all the source files.
+ */
 typedef charf *         png_zcharp;
 typedef charf * FAR *   png_zcharpp;
 typedef z_stream FAR *  png_zstreamp; 
 
+/* allow for compilation as dll under windows */
+#ifdef __WIN32DLL__
+#define PNG_EXPORT(type,symbol) __declspec(dllexport) type symbol
+#endif
+
+#ifndef PNG_EXPORT
+#define PNG_EXPORT(t,s) t s
+#endif
+
+
 /* User may want to use these so not in PNG_INTERNAL. Any library functions
    that are passed far data must be model independent. */
 
@@ -366,25 +419,27 @@
 #   define NOCHECK 0
 #   define CVT_PTR(ptr) (far_to_near(png_ptr,ptr,CHECK))
 #   define CVT_PTR_NOCHECK(ptr) (far_to_near(png_ptr,ptr,NOCHECK))
-#   define png_strcpy _fstrcpy
-#   define png_strcat _fstrcat
 #   define png_strlen _fstrlen
-#   define png_strcmp _fstrcmp
 #   define png_memcmp _fmemcmp      /* SJT: added */
 #   define png_memcpy _fmemcpy
 #   define png_memset _fmemset
 #else /* use the usual functions */
 #   define CVT_PTR(ptr)         (ptr)
 #   define CVT_PTR_NOCHECK(ptr) (ptr)
-#   define png_strcpy strcpy
-#   define png_strcat strcat
 #   define png_strlen strlen
-#   define png_strcmp strcmp
 #   define png_memcmp memcmp     /* SJT: added */
 #   define png_memcpy memcpy
 #   define png_memset memset
 #endif
 /* End of memory model independent support */
 
+/* Just a double check that someone hasn't tried to define something
+ * contradictory. 
+ */
+#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K)
+#undef PNG_ZBUF_SIZE
+#define PNG_ZBUF_SIZE 65536
+#endif
+
 #endif /* PNGCONF_H */
 
diff --git a/pngerror.c b/pngerror.c
index 8ce44c3..70a3ee0 100644
--- a/pngerror.c
+++ b/pngerror.c
@@ -1,10 +1,11 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
 
    This file provides a location for all error handling.  Users which
    need special error handling are expected to write replacement functions
@@ -26,7 +27,7 @@
 void
 png_error(png_structp png_ptr, png_const_charp message)
 {
-   if (png_ptr->error_fn)
+   if (png_ptr->error_fn != NULL)
       (*(png_ptr->error_fn))(png_ptr, message);
 
    /* if the following returns or doesn't exist, use the default function,
@@ -41,7 +42,7 @@
 void
 png_warning(png_structp png_ptr, png_const_charp message)
 {
-   if (png_ptr->warning_fn)
+   if (png_ptr->warning_fn != NULL)
       (*(png_ptr->warning_fn))(png_ptr, message);
    else
       png_default_warning(png_ptr, message);
@@ -76,7 +77,7 @@
 static void
 png_default_warning(png_structp png_ptr, png_const_charp message)
 {
-   if (!png_ptr)
+   if (png_ptr == NULL)
       return;
 
 #ifndef PNG_NO_STDIO
diff --git a/pngget.c b/pngget.c
new file mode 100644
index 0000000..a2f0f86
--- /dev/null
+++ b/pngget.c
@@ -0,0 +1,300 @@
+
+/* pngget.c - retrieval of values from info struct
+
+   libpng 1.0 beta 6 - version 0.96
+   For conditions of distribution and use, see copyright notice in png.h
+   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
+   */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+png_uint_32
+png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+{
+   if (info_ptr != NULL)
+      return(info_ptr->valid & flag);
+   else
+      return(0);
+}
+
+png_uint_32
+png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+{
+   if (info_ptr != NULL)
+      return(info_ptr->rowbytes);
+   else
+      return(0);
+}
+
+png_byte
+png_get_channels(png_structp png_ptr, png_infop info_ptr)
+{
+   if (info_ptr != NULL)
+      return(info_ptr->channels);
+   else
+      return(0);
+}
+
+png_bytep
+png_get_signature(png_structp png_ptr, png_infop info_ptr)
+{
+   if (info_ptr != NULL)
+      return(info_ptr->signature);
+   else
+      return(NULL);
+}
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+png_uint_32
+png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
+   png_color_16p *background)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD &&
+      background != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "bKGD");
+      *background = &(info_ptr->background);
+      return (PNG_INFO_bKGD);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+png_uint_32
+png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
+   double *white_x, double *white_y, double *red_x, double *red_y,
+   double *green_x, double *green_y, double *blue_x, double *blue_y)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM)
+   {
+      png_debug1(1, "in %s retrieval function\n", "cHRM");
+      if (white_x != NULL)
+         *white_x = (double)info_ptr->x_white;
+      if (white_y != NULL)
+         *white_y = (double)info_ptr->y_white;
+      if (red_x != NULL)
+         *red_x = (double)info_ptr->x_red;
+      if (red_y != NULL)
+         *red_y = (double)info_ptr->y_red;
+      if (green_x != NULL)
+         *green_x = (double)info_ptr->x_green;
+      if (green_y != NULL)
+         *green_y = (double)info_ptr->y_green;
+      if (blue_x != NULL)
+         *blue_x = (double)info_ptr->x_blue;
+      if (blue_y != NULL)
+         *blue_y = (double)info_ptr->y_blue;
+      return (PNG_INFO_cHRM);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+png_uint_32
+png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA &&
+      file_gamma != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "gAMA");
+      *file_gamma = (double)info_ptr->gamma;
+      return (PNG_INFO_gAMA);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+png_uint_32
+png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST && hist != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "hIST");
+      *hist = info_ptr->hist;
+      return (PNG_INFO_hIST);
+   }
+   return (0);
+}
+#endif
+
+png_uint_32
+png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+   int *color_type, int *interlace_type, int *compression_type,
+   int *filter_type)
+   
+{
+   if (info_ptr != NULL && width != NULL && height != NULL &&
+      bit_depth != NULL && color_type != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "IHDR");
+      *width = info_ptr->width;
+      *height = info_ptr->height;
+      *bit_depth = info_ptr->bit_depth;
+      *color_type = info_ptr->color_type;
+      if (compression_type != NULL)
+         *compression_type = info_ptr->compression_type;
+      if (filter_type != NULL)
+         *filter_type = info_ptr->filter_type;
+      if (interlace_type != NULL)
+         *interlace_type = info_ptr->interlace_type;
+      return (1);
+   }
+   return (0);
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+png_uint_32
+png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 *offset_x, png_uint_32 *offset_y, int *unit_type)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs &&
+      offset_x != NULL && offset_y != NULL && unit_type != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "oFFs");
+      *offset_x = info_ptr->x_offset;
+      *offset_y = info_ptr->y_offset;
+      *unit_type = (int)info_ptr->offset_unit_type;
+      return (PNG_INFO_oFFs);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+png_uint_32
+png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
+   png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+   png_charp *units, png_charpp *params)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL &&
+      purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+      nparams != NULL && units != NULL && params != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "pCAL");
+      *purpose = info_ptr->pcal_purpose;
+      *X0 = info_ptr->pcal_X0;
+      *X1 = info_ptr->pcal_X1;
+      *type = (int)info_ptr->pcal_type;
+      *nparams = (int)info_ptr->pcal_nparams;
+      *units = info_ptr->pcal_units;
+      *params = info_ptr->pcal_params;
+      return (PNG_INFO_pCAL);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+png_uint_32
+png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs &&
+      res_x != NULL && res_y != NULL && unit_type != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "pHYs");
+      *res_x = info_ptr->x_pixels_per_unit;
+      *res_y = info_ptr->y_pixels_per_unit;
+      *unit_type = (int)info_ptr->phys_unit_type;
+      return (PNG_INFO_pHYs);
+   }
+   return (0);
+}
+#endif
+
+png_uint_32
+png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
+   int *num_palette)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_PLTE && palette != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "PLTE");
+      *palette = info_ptr->palette;
+      *num_palette = info_ptr->num_palette;
+      png_debug1(3, "num_palette = %d\n", *num_palette);
+      return (PNG_INFO_PLTE);
+   }
+   return (0);
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+png_uint_32
+png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT && sig_bit != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "sBIT");
+      *sig_bit = &(info_ptr->sig_bit);
+      return (PNG_INFO_sBIT);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+png_uint_32
+png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
+   int *num_text)
+{
+   if ((info_ptr != NULL) || (info_ptr->num_text > 0))
+   {
+      png_debug1(1, "in %s retrieval function\n",
+         (png_ptr->chunk_name[0] == '\0' ? "text" : png_ptr->chunk_name));
+      if (text_ptr != NULL)
+         *text_ptr = info_ptr->text;
+      if (num_text != NULL)
+         *num_text = info_ptr->num_text;
+      return (info_ptr->num_text);
+   }
+   return(0);
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+png_uint_32
+png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME && mod_time != NULL)
+   {
+      png_debug1(1, "in %s retrieval function\n", "tIME");
+      *mod_time = &(info_ptr->mod_time);
+      return (PNG_INFO_tIME);
+   }
+   return (0);
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+png_uint_32
+png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
+   png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+{
+   if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+   {
+      png_debug1(1, "in %s retrieval function\n", "tRNS");
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && trans != NULL)
+      {
+          *trans = info_ptr->trans;
+      }
+      else if (trans_values != NULL)
+      {
+         *trans_values = &(info_ptr->trans_values);
+      }
+      else
+      {
+         return (0);
+      }
+      *num_trans = info_ptr->num_trans;
+      return (PNG_INFO_tRNS);
+   }
+   return (0);
+}
+#endif
+
diff --git a/pngmem.c b/pngmem.c
index 4c95117..92d2756 100644
--- a/pngmem.c
+++ b/pngmem.c
@@ -1,10 +1,11 @@
 
 /* pngmem.c - stub functions for memory allocation
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
 
    This file provides a location for all memory allocation.  Users which
    need special memory handling are expected to modify the code in this file
@@ -45,30 +46,34 @@
 void
 png_destroy_struct(png_voidp struct_ptr)
 {
-   if (struct_ptr)
+   if (struct_ptr != NULL)
       farfree (struct_ptr);
 }
 
 /* Allocate memory.  For reasonable files, size should never exceed
-   64K.  However, zlib may allocate more then 64K if you don't tell
-   it not to.  See zconf.h and png.h for more information. zlib does
-   need to allocate exactly 64K, so whatever you call here must
-   have the ability to do that. */
-
-/* Borland seems to have a problem in DOS mode for exactly 64K.
-   It gives you a segment with an offset of 8 (perhaps to store it's
-   memory stuff).  zlib doesn't like this at all, so we have to
-   detect and deal with it.  This code should not be needed in
-   Windows or OS/2 modes, and only in 16 bit mode.  This code has
-   been updated by Alexander Lehmann for version 0.89 to waste less
-   memory.
-*/
-
+ * 64K.  However, zlib may allocate more then 64K if you don't tell
+ * it not to.  See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * Borland seems to have a problem in DOS mode for exactly 64K.
+ * It gives you a segment with an offset of 8 (perhaps to store it's
+ * memory stuff).  zlib doesn't like this at all, so we have to
+ * detect and deal with it.  This code should not be needed in
+ * Windows or OS/2 modes, and only in 16 bit mode.  This code has
+ * been updated by Alexander Lehmann for version 0.89 to waste less
+ * memory.
+ *
+ * Note that we can't use png_size_t for the "size" declaration,
+ * since on some systems a png_size_t is a 16-bit quantity, and as a
+ * result, we would be truncating potentially larger memory requests
+ * (which should cause a fatal error) and introducing major problems.
+ */
 png_voidp
 png_malloc(png_structp png_ptr, png_uint_32 size)
 {
    png_voidp ret;
-   if (!png_ptr || !size)
+   if (png_ptr == NULL || size == 0)
       return ((voidp)NULL);
 
 #ifdef PNG_MAX_MALLOC_64K
@@ -78,11 +83,11 @@
 
    if (size == (png_uint_32)(65536L))
    {
-      if (!png_ptr->offset_table)
+      if (png_ptr->offset_table == NULL)
       {
          /* try to see if we need to do any of this fancy stuff */
          ret = farmalloc(size);
-         if (!ret || ((long)ret & 0xffff))
+         if (ret == NULL || ((png_size_t)ret & 0xffff))
          {
             int num_blocks;
             png_uint_32 total_size;
@@ -90,7 +95,7 @@
             int i;
             png_byte huge * hptr;
 
-            if (ret)
+            if (ret != NULL)
                farfree(ret);
             ret = NULL;
 
@@ -106,27 +111,27 @@
 
             table = farmalloc(total_size);
 
-            if (!table)
+            if (table == NULL)
             {
                png_error(png_ptr, "Out of Memory");
             }
 
-            if ((long)table & 0xfff0)
+            if ((png_size_t)table & 0xfff0)
             {
                png_error(png_ptr, "Farmalloc didn't return normalized pointer");
             }
 
             png_ptr->offset_table = table;
-            png_ptr->offset_table_ptr = farmalloc(
-               num_blocks * sizeof (png_bytep));
+            png_ptr->offset_table_ptr = farmalloc(num_blocks *
+               sizeof (png_bytep));
 
-            if (!png_ptr->offset_table_ptr)
+            if (png_ptr->offset_table_ptr == NULL)
             {
                png_error(png_ptr, "Out of memory");
             }
 
             hptr = (png_byte huge *)table;
-            if ((long)hptr & 0xf)
+            if ((png_size_t)hptr & 0xf)
             {
                hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
                hptr += 16L;
@@ -165,36 +170,33 @@
 void
 png_free(png_structp png_ptr, png_voidp ptr)
 {
-   if (!png_ptr)
+   if (png_ptr == NULL || ptr == NULL)
       return;
 
-   if (ptr != NULL)
+   if (png_ptr->offset_table != NULL)
    {
-      if (png_ptr->offset_table)
-      {
-         int i;
+      int i;
 
-         for (i = 0; i < png_ptr->offset_table_count; i++)
+      for (i = 0; i < png_ptr->offset_table_count; i++)
+      {
+         if (ptr == png_ptr->offset_table_ptr[i])
          {
-            if (ptr == png_ptr->offset_table_ptr[i])
-            {
-               ptr = 0;
-               png_ptr->offset_table_count_free++;
-               break;
-            }
-         }
-         if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
-         {
-            farfree(png_ptr->offset_table);
-            farfree(png_ptr->offset_table_ptr);
-            png_ptr->offset_table = 0;
-            png_ptr->offset_table_ptr = 0;
+            ptr = NULL;
+            png_ptr->offset_table_count_free++;
+            break;
          }
       }
-
-      if (ptr)
-         farfree(ptr);
+      if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
+      {
+         farfree(png_ptr->offset_table);
+         farfree(png_ptr->offset_table_ptr);
+         png_ptr->offset_table = NULL;
+         png_ptr->offset_table_ptr = NULL;
+      }
    }
+
+   if (ptr != NULL)
+      farfree(ptr);
 }
 
 #else /* Not the Borland DOS special memory handler */
@@ -205,15 +207,15 @@
 png_voidp
 png_create_struct(int type)
 {
-   size_t size;
+   png_size_t size;
    png_voidp struct_ptr;
 
    if (type == PNG_STRUCT_INFO)
-     size = sizeof(png_info);
+      size = sizeof(png_info);
    else if (type == PNG_STRUCT_PNG)
-     size = sizeof(png_struct);
+      size = sizeof(png_struct);
    else
-     return (png_voidp)NULL;
+      return (png_voidp)NULL;
 
 #if defined(__TURBOC__) && !defined(__FLAT__)
    if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
@@ -236,7 +238,7 @@
 void
 png_destroy_struct(png_voidp struct_ptr)
 {
-   if (struct_ptr)
+   if (struct_ptr != NULL)
 #if defined(__TURBOC__) && !defined(__FLAT__)
       farfree(struct_ptr);
 #else
@@ -251,17 +253,16 @@
 
 /* Allocate memory.  For reasonable files, size should never exceed
    64K.  However, zlib may allocate more then 64K if you don't tell
-   it not to.  See zconf.h and png.h for more information. zlib does
+   it not to.  See zconf.h and png.h for more information.  zlib does
    need to allocate exactly 64K, so whatever you call here must
    have the ability to do that. */
 
-#ifndef FORTIFY
 png_voidp
 png_malloc(png_structp png_ptr, png_uint_32 size)
 {
    png_voidp ret;
-   if (!png_ptr || !size)
-      return ((voidp)0);
+   if (png_ptr == NULL || size == 0)
+      return (NULL);
 
 #ifdef PNG_MAX_MALLOC_64K
    if (size > (png_uint_32)65536L)
@@ -269,7 +270,7 @@
 #endif
 
 #if defined(__TURBOC__) && !defined(__FLAT__)
-   ret = farmalloc(size);
+   ret = farmalloc((png_size_t)size);
 #else
 # if defined(_MSC_VER) && defined(MAXSEG_64K)
    ret = halloc(size, 1);
@@ -286,29 +287,25 @@
    return ret;
 }
 
-/* free a pointer allocated by png_malloc().  In the default
+/* Free a pointer allocated by png_malloc().  In the default
   configuration, png_ptr is not used, but is passed in case it
   is needed.  If ptr is NULL, return without taking any action. */
 void
 png_free(png_structp png_ptr, png_voidp ptr)
 {
-   if (!png_ptr)
+   if (png_ptr == NULL || ptr == NULL)
       return;
 
-   if (ptr != NULL)
-   {
 #if defined(__TURBOC__) && !defined(__FLAT__)
-      farfree(ptr);
+   farfree(ptr);
 #else
 # if defined(_MSC_VER) && defined(MAXSEG_64K)
-      hfree(ptr);
+   hfree(ptr);
 # else
-      free(ptr);
+   free(ptr);
 # endif
 #endif
-   }
 }
 
-#endif /* FORTIFY */
 #endif /* Not Borland DOS special memory handler */
 
diff --git a/pngpread.c b/pngpread.c
index 284b749..2fb1bd6 100644
--- a/pngpread.c
+++ b/pngpread.c
@@ -1,10 +1,11 @@
 
 /* pngpread.c - read a png file in push mode
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
@@ -14,7 +15,7 @@
 
 void
 png_process_data(png_structp png_ptr, png_infop info_ptr,
-   png_bytep buffer, png_uint_32 buffer_size)
+   png_bytep buffer, png_size_t buffer_size)
 {
    png_push_restore_buffer(png_ptr, buffer, buffer_size);
 
@@ -61,14 +62,9 @@
          break;
       }
 #endif
-      case PNG_READ_END_MODE:
-      {
-         png_push_read_chunk(png_ptr, info_ptr);
-         break;
-      }
       case PNG_SKIP_MODE:
       {
-         png_push_skip(png_ptr);
+         png_push_crc_finish(png_ptr);
          break;
       }
       default:
@@ -87,8 +83,8 @@
 void
 png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
 {
-   int num_checked = png_ptr->sig_bytes,
-        num_to_check = 8 - num_checked;
+   png_size_t num_checked = png_ptr->sig_bytes,
+             num_to_check = 8 - num_checked;
 
    if (png_ptr->buffer_size < num_to_check)
    {
@@ -96,7 +92,7 @@
    }
 
    png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), 
-      (png_uint_32)num_to_check);
+      num_to_check);
    png_ptr->sig_bytes += num_to_check;
 
    if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
@@ -137,8 +133,7 @@
       png_push_fill_buffer(png_ptr, chunk_length, 4);
       png_ptr->push_length = png_get_uint_32(chunk_length);
       png_reset_crc(png_ptr);
-      png_push_fill_buffer(png_ptr, png_ptr->chunk_name, 4);
-      png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
+      png_crc_read(png_ptr, png_ptr->chunk_name, 4);
       png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
    }
 
@@ -292,6 +287,18 @@
       png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
    }
 #endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+   else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+   {
+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+      {
+         png_push_save_buffer(png_ptr);
+         return;
+      }
+
+      png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
+   }
+#endif
 #if defined(PNG_READ_tIME_SUPPORTED)
    else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
    {
@@ -325,21 +332,21 @@
 }
 
 void
-png_push_crc_skip(png_structp png_ptr, png_uint_32 length)
+png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
 {
    png_ptr->process_mode = PNG_SKIP_MODE;
-   png_ptr->skip_length = length;
+   png_ptr->skip_length = skip;
 }
 
 void
-png_push_skip(png_structp png_ptr)
+png_push_crc_finish(png_structp png_ptr)
 {
    if (png_ptr->skip_length && png_ptr->save_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
-      if (png_ptr->skip_length < png_ptr->save_buffer_size)
-         save_size = png_ptr->skip_length;
+      if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
+         save_size = (png_size_t)png_ptr->skip_length;
       else
          save_size = png_ptr->save_buffer_size;
 
@@ -348,14 +355,14 @@
       png_ptr->skip_length -= save_size;
       png_ptr->buffer_size -= save_size;
       png_ptr->save_buffer_size -= save_size;
-      png_ptr->save_buffer_ptr += (png_size_t)save_size;
+      png_ptr->save_buffer_ptr += save_size;
    }
    if (png_ptr->skip_length && png_ptr->current_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
-      if (png_ptr->skip_length < png_ptr->current_buffer_size)
-         save_size = png_ptr->skip_length;
+      if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
+         save_size = (png_size_t)png_ptr->skip_length;
       else
          save_size = png_ptr->current_buffer_size;
 
@@ -364,7 +371,7 @@
       png_ptr->skip_length -= save_size;
       png_ptr->buffer_size -= save_size;
       png_ptr->current_buffer_size -= save_size;
-      png_ptr->current_buffer_ptr += (png_size_t)save_size;
+      png_ptr->current_buffer_ptr += save_size;
    }
    if (!png_ptr->skip_length)
    {
@@ -375,50 +382,45 @@
       }
 
       png_crc_finish(png_ptr, 0);
-
-      if (png_ptr->mode & PNG_AFTER_IDAT)
-         png_ptr->process_mode = PNG_READ_END_MODE;
-      else
-         png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+      png_ptr->process_mode = PNG_READ_CHUNK_MODE;
    }
 }
 
 void
-png_push_fill_buffer(png_structp png_ptr, png_bytep buffer,
-   png_uint_32 length)
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
 {
    png_bytep ptr;
 
    ptr = buffer;
    if (png_ptr->save_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
       if (length < png_ptr->save_buffer_size)
          save_size = length;
       else
          save_size = png_ptr->save_buffer_size;
 
-      png_memcpy(ptr, png_ptr->save_buffer_ptr, (png_size_t)save_size);
+      png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
       length -= save_size;
-      ptr += (png_size_t)save_size;
+      ptr += save_size;
       png_ptr->buffer_size -= save_size;
       png_ptr->save_buffer_size -= save_size;
-      png_ptr->save_buffer_ptr += (png_size_t)save_size;
+      png_ptr->save_buffer_ptr += save_size;
    }
    if (length && png_ptr->current_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
       if (length < png_ptr->current_buffer_size)
          save_size = length;
       else
          save_size = png_ptr->current_buffer_size;
 
-      png_memcpy(ptr, png_ptr->current_buffer_ptr, (png_size_t)save_size);
+      png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
       png_ptr->buffer_size -= save_size;
       png_ptr->current_buffer_size -= save_size;
-      png_ptr->current_buffer_ptr += (png_size_t)save_size;
+      png_ptr->current_buffer_ptr += save_size;
    }
 }
 
@@ -429,7 +431,7 @@
    {
       if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
       {
-         int i;
+         png_size_t i;
          png_bytep sp;
          png_bytep dp;
 
@@ -444,25 +446,20 @@
    if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
       png_ptr->save_buffer_max)
    {
-      png_uint_32 new_max;
+      png_size_t new_max;
       png_bytep old_buffer;
 
-      new_max = (int)(png_ptr->save_buffer_size +
-         png_ptr->current_buffer_size + 256);
+      new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
       old_buffer = png_ptr->save_buffer;
-      png_ptr->save_buffer = (png_bytep)
-         png_malloc(png_ptr, new_max);
-      png_memcpy(png_ptr->save_buffer, old_buffer,
-         (png_size_t)png_ptr->save_buffer_size);
+      png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, new_max);
+      png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
       png_free(png_ptr, old_buffer);
-        png_ptr->save_buffer_max = new_max;
+      png_ptr->save_buffer_max = new_max;
    }
    if (png_ptr->current_buffer_size)
    {
-      png_memcpy(png_ptr->save_buffer +
-         (png_size_t)png_ptr->save_buffer_size,
-         png_ptr->current_buffer_ptr,
-         (png_size_t)png_ptr->current_buffer_size);
+      png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+         png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
       png_ptr->save_buffer_size += png_ptr->current_buffer_size;
       png_ptr->current_buffer_size = 0;
    }
@@ -472,7 +469,7 @@
 
 void
 png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
-   png_uint_32 buffer_length)
+   png_size_t buffer_length)
 {
    png_ptr->current_buffer = buffer;
    png_ptr->current_buffer_size = buffer_length;
@@ -497,13 +494,12 @@
       png_ptr->push_length = png_get_uint_32(chunk_length);
 
       png_reset_crc(png_ptr);
-      png_push_fill_buffer(png_ptr, png_ptr->chunk_name, 4);
-      png_calculate_crc(png_ptr, chunk_length, 4);
+      png_crc_read(png_ptr, png_ptr->chunk_name, 4);
       png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
 
       if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
       {
-         png_ptr->process_mode = PNG_READ_END_MODE;
+         png_ptr->process_mode = PNG_READ_CHUNK_MODE;
          if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
             png_error(png_ptr, "Not enough compressed data");
          return;
@@ -513,9 +509,9 @@
    }
    if (png_ptr->idat_size && png_ptr->save_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
-      if (png_ptr->idat_size < png_ptr->save_buffer_size)
+      if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
          save_size = png_ptr->idat_size;
       else
          save_size = png_ptr->save_buffer_size;
@@ -526,13 +522,13 @@
       png_ptr->idat_size -= save_size;
       png_ptr->buffer_size -= save_size;
       png_ptr->save_buffer_size -= save_size;
-      png_ptr->save_buffer_ptr += (png_size_t)save_size;
+      png_ptr->save_buffer_ptr += save_size;
    }
    if (png_ptr->idat_size && png_ptr->current_buffer_size)
    {
-      png_uint_32 save_size;
+      png_size_t save_size;
 
-      if (png_ptr->idat_size < png_ptr->current_buffer_size)
+      if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
          save_size = png_ptr->idat_size;
       else
          save_size = png_ptr->current_buffer_size;
@@ -543,7 +539,7 @@
       png_ptr->idat_size -= save_size;
       png_ptr->buffer_size -= save_size;
       png_ptr->current_buffer_size -= save_size;
-      png_ptr->current_buffer_ptr += (png_size_t)save_size;
+      png_ptr->current_buffer_ptr += save_size;
    }
    if (!png_ptr->idat_size)
    {
@@ -560,7 +556,7 @@
 
 void
 png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
-   png_uint_32 buffer_length)
+   png_size_t buffer_length)
 {
    int ret;
 
@@ -569,22 +565,25 @@
 
    png_ptr->zstream.next_in = buffer;
    png_ptr->zstream.avail_in = (uInt)buffer_length;
-   do
+   while(1)
    {
       ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
       if (ret == Z_STREAM_END)
       {
          if (png_ptr->zstream.avail_in)
             png_error(png_ptr, "Extra compressed data");
-         if (!png_ptr->zstream.avail_out)
+         if (!(png_ptr->zstream.avail_out))
          {
             png_push_process_row(png_ptr);
          }
-         png_ptr->mode = PNG_AFTER_IDAT;
+
+         png_ptr->mode |= PNG_AFTER_IDAT;
          png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
          break;
       }
-      if (ret != Z_OK)
+      else if (ret == Z_BUF_ERROR)
+         break;
+      else if (ret != Z_OK)
          png_error(png_ptr, "Decompression Error");
       if (!(png_ptr->zstream.avail_out))
       {
@@ -592,8 +591,9 @@
          png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
          png_ptr->zstream.next_out = png_ptr->row_buf;
       }
-
-   } while (png_ptr->zstream.avail_in);
+      else
+         break;
+   }
 }
 
 void
@@ -611,19 +611,18 @@
       png_ptr->row_buf + 1, png_ptr->prev_row + 1,
       (int)(png_ptr->row_buf[0]));
 
-   png_memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1);
+   png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
 
    if (png_ptr->transformations)
       png_do_read_transformations(png_ptr);
 
 #if defined(PNG_READ_INTERLACING_SUPPORTED)
    /* blow up interlaced rows to full size */
-   if (png_ptr->interlaced &&
-      (png_ptr->transformations & PNG_INTERLACE))
+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
    {
       if (png_ptr->pass < 6)
          png_do_read_interlace(&(png_ptr->row_info),
-            png_ptr->row_buf + 1, png_ptr->pass);
+            png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
 
       switch (png_ptr->pass)
       {
@@ -747,7 +746,7 @@
    if (png_ptr->interlaced)
    {
       png_ptr->row_number = 0;
-      png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+      png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
       do
       {
          png_ptr->pass++;
@@ -781,8 +780,19 @@
    if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
       png_error(png_ptr, "Out of place tEXt");
 
-   png_ptr->current_text = (png_charp)png_malloc(png_ptr, length + 1);
-   png_ptr->current_text[(png_size_t)length] = '\0';
+#ifdef PNG_MAX_MALLOC_64K
+   png_ptr->skip_length = 0;  /* This may not be necessary */
+
+   if (length > 65535L)  /* We can't hold the entire string in memory */
+   {
+      png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+      png_ptr->skip_length = length - 65535L;
+      length = 65535L;
+   }
+#endif
+
+   png_ptr->current_text = (png_charp)png_malloc(png_ptr, length+1);
+   png_ptr->current_text[length] = '\0';
    png_ptr->current_text_ptr = png_ptr->current_text;
    png_ptr->current_text_size = length;
    png_ptr->current_text_left = length;
@@ -794,21 +804,19 @@
 {
    if (png_ptr->buffer_size && png_ptr->current_text_left)
    {
-      png_uint_32 text_size;
+      png_size_t text_size;
 
       if (png_ptr->buffer_size < png_ptr->current_text_left)
          text_size = png_ptr->buffer_size;
       else
          text_size = png_ptr->current_text_left;
-      png_push_fill_buffer(png_ptr, (png_bytep)png_ptr->current_text_ptr,
-         text_size);
-      png_calculate_crc(png_ptr, (png_bytep)png_ptr->current_text_ptr,
-         text_size);
+      png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
       png_ptr->current_text_left -= text_size;
-      png_ptr->current_text_ptr += (png_size_t)text_size;
+      png_ptr->current_text_ptr += text_size;
    }
    if (!(png_ptr->current_text_left))
    {
+      png_textp text_ptr;
       png_charp text;
       png_charp key;
 
@@ -818,7 +826,12 @@
          return;
       }
 
-      png_crc_finish(png_ptr, 0);
+      png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+      if (png_ptr->skip_length)
+         return;
+#endif
 
       key = png_ptr->current_text;
       png_ptr->current_text = 0;
@@ -826,20 +839,17 @@
       for (text = key; *text; text++)
          /* empty loop */ ;
 
-      if (text != key + (png_size_t)png_ptr->current_text_size)
+      if (text != key + png_ptr->current_text_size)
          text++;
 
-      png_read_tEXt(png_ptr, info_ptr, key, text,
-         png_ptr->current_text_size - (text - key));
+      text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+      text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+      text_ptr->key = key;
+      text_ptr->text = text;
 
-      if (png_ptr->mode == PNG_AFTER_IDAT)
-      {
-         png_ptr->process_mode = PNG_READ_END_MODE;
-      }
-      else
-      {
-         png_ptr->process_mode = PNG_READ_CHUNK_MODE;
-      }
+      png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+      png_free(png_ptr, text_ptr);
    }
 }
 #endif
@@ -851,8 +861,21 @@
    if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
       png_error(png_ptr, "Out of place zTXt");
 
-   png_ptr->current_text = (png_charp)png_malloc(png_ptr, length + 1);
-   png_ptr->current_text[(png_size_t)length] = '\0';
+#ifdef PNG_MAX_MALLOC_64K
+   /* We can't handle zTXt chunks > 64K, since we don't have enough space
+    * to be able to store the uncompressed data.  Actually, the threshold
+    * is probably around 32K, but it isn't as definite as 64K is.
+    */
+   if (length > 65535L)
+   {
+      png_warning(png_ptr, "zTXt chunk too large to fit in memory");
+      png_push_crc_skip(png_ptr, length);
+      return;
+   }
+#endif
+
+   png_ptr->current_text = (png_charp)png_malloc(png_ptr, length+1);
+   png_ptr->current_text[length] = '\0';
    png_ptr->current_text_ptr = png_ptr->current_text;
    png_ptr->current_text_size = length;
    png_ptr->current_text_left = length;
@@ -864,25 +887,23 @@
 {
    if (png_ptr->buffer_size && png_ptr->current_text_left)
    {
-      png_uint_32 text_size;
+      png_size_t text_size;
 
-      if (png_ptr->buffer_size < png_ptr->current_text_left)
+      if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
          text_size = png_ptr->buffer_size;
       else
          text_size = png_ptr->current_text_left;
-      png_push_fill_buffer(png_ptr, (png_bytep)png_ptr->current_text_ptr,
-         text_size);
-      png_calculate_crc(png_ptr, (png_bytep)png_ptr->current_text_ptr,
-         text_size);
+      png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
       png_ptr->current_text_left -= text_size;
-      png_ptr->current_text_ptr += (png_size_t)text_size;
+      png_ptr->current_text_ptr += text_size;
    }
    if (!(png_ptr->current_text_left))
    {
+      png_textp text_ptr;
       png_charp text;
       png_charp key;
       int ret;
-      png_uint_32 text_size, key_size;
+      png_size_t text_size, key_size;
 
       if (png_ptr->buffer_size < 4)
       {
@@ -890,7 +911,7 @@
          return;
       }
 
-      png_crc_finish(png_ptr, 0);
+      png_push_crc_finish(png_ptr);
 
       key = png_ptr->current_text;
       png_ptr->current_text = 0;
@@ -899,7 +920,7 @@
          /* empty loop */ ;
 
       /* zTXt can't have zero text */
-      if (text == key + (png_size_t)png_ptr->current_text_size)
+      if (text == key + png_ptr->current_text_size)
       {
          png_free(png_ptr, key);
          return;
@@ -907,7 +928,7 @@
 
       text++;
 
-      if (*text) /* check compression byte */
+      if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
       {
          png_free(png_ptr, key);
          return;
@@ -919,7 +940,7 @@
       png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
          (text - key));
       png_ptr->zstream.next_out = png_ptr->zbuf;
-      png_ptr->zstream.avail_out = (png_size_t)png_ptr->zbuf_size;
+      png_ptr->zstream.avail_out = png_ptr->zbuf_size;
 
       key_size = text - key;
       text_size = 0;
@@ -937,19 +958,19 @@
             png_free(png_ptr, text);
             return;
          }
-         if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
+         if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
          {
-            if (!text)
+            if (text == NULL)
             {
                text = (png_charp)png_malloc(png_ptr,
                   png_ptr->zbuf_size - png_ptr->zstream.avail_out +
                      key_size + 1);
-               png_memcpy(text + (png_size_t)key_size, png_ptr->zbuf,
-                  (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
-               png_memcpy(text, key, (png_size_t)key_size);
-               text_size = key_size + (png_size_t)png_ptr->zbuf_size -
+               png_memcpy(text + key_size, png_ptr->zbuf,
+                  png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+               png_memcpy(text, key, key_size);
+               text_size = key_size + png_ptr->zbuf_size -
                   png_ptr->zstream.avail_out;
-               *(text + (png_size_t)text_size) = '\0';
+               *(text + text_size) = '\0';
             }
             else
             {
@@ -958,12 +979,12 @@
                tmp = text;
                text = png_malloc(png_ptr, text_size +
                   png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1);
-               png_memcpy(text, tmp, (png_size_t)text_size);
+               png_memcpy(text, tmp, text_size);
                png_free(png_ptr, tmp);
-               png_memcpy(text + (png_size_t)text_size, png_ptr->zbuf,
-                  (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+               png_memcpy(text + text_size, png_ptr->zbuf,
+                  png_ptr->zbuf_size - png_ptr->zstream.avail_out);
                text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
-               *(text + (png_size_t)text_size) = '\0';
+               *(text + text_size) = '\0';
             }
             if (ret != Z_STREAM_END)
             {
@@ -992,18 +1013,17 @@
 
       png_free(png_ptr, key);
       key = text;
-      text += (png_size_t)key_size;
+      text += key_size;
       text_size -= key_size;
 
-      png_read_zTXt(png_ptr, info_ptr, key, text, text_size, 0);
-      if (png_ptr->mode == PNG_AFTER_IDAT)
-      {
-         png_ptr->process_mode = PNG_READ_END_MODE;
-      }
-      else
-      {
-         png_ptr->process_mode = PNG_READ_CHUNK_MODE;
-      }
+      text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+      text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
+      text_ptr->key = key;
+      text_ptr->text = text;
+
+      png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+      png_free(png_ptr, text_ptr);
    }
 }
 #endif
@@ -1033,21 +1053,21 @@
 void
 png_push_have_info(png_structp png_ptr, png_infop info_ptr)
 {
-   if (png_ptr->info_fn)
+   if (png_ptr->info_fn != NULL)
       (*(png_ptr->info_fn))(png_ptr, info_ptr);
 }
 
 void
 png_push_have_end(png_structp png_ptr, png_infop info_ptr)
 {
-   if (png_ptr->end_fn)
+   if (png_ptr->end_fn != NULL)
       (*(png_ptr->end_fn))(png_ptr, info_ptr);
 }
 
 void
 png_push_have_row(png_structp png_ptr, png_bytep row)
 {
-   if (png_ptr->row_fn)
+   if (png_ptr->row_fn != NULL)
       (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
          (int)png_ptr->pass);
 }
@@ -1056,7 +1076,7 @@
 png_progressive_combine_row (png_structp png_ptr,
    png_bytep old_row, png_bytep new_row)
 {
-   if (new_row)
+   if (new_row != NULL)
       png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
 }
 
diff --git a/pngrcb.c b/pngrcb.c
deleted file mode 100644
index 1df3550..0000000
--- a/pngrcb.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/* pngrcb.c - callbacks while reading a png file
-
-   libpng 1.0 beta 4 - version 0.90
-   For conditions of distribution and use, see copyright notice in png.h
-   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
-   */
-
-#define PNG_INTERNAL
-#include "png.h"
-
-void
-png_read_IHDR(png_structp png_ptr, png_infop info,
-   png_uint_32 width, png_uint_32 height, int bit_depth,
-   int color_type, int compression_type, int filter_type,
-   int interlace_type)
-{
-   if (!info)
-      return;
-
-   info->width = width;
-   info->height = height;
-   info->bit_depth = (png_byte)bit_depth;
-   info->color_type =(png_byte) color_type;
-   info->compression_type = (png_byte)compression_type;
-   info->filter_type = (png_byte)filter_type;
-   info->interlace_type = (png_byte)interlace_type;
-   if (info->color_type == PNG_COLOR_TYPE_PALETTE)
-      info->channels = 1;
-   else if (info->color_type & PNG_COLOR_MASK_COLOR)
-      info->channels = 3;
-   else
-      info->channels = 1;
-   if (info->color_type & PNG_COLOR_MASK_ALPHA)
-      info->channels++;
-   info->pixel_depth = (png_byte)(info->channels * info->bit_depth);
-   info->rowbytes = ((info->width * info->pixel_depth + 7) >> 3);
-}
-
-void
-png_read_PLTE(png_structp png_ptr, png_infop info,
-   png_colorp palette, int num)
-{
-   if (!info)
-      return;
-
-   info->palette = palette;
-   info->num_palette = (png_uint_16)num;
-   info->valid |= PNG_INFO_PLTE;
-}
-
-#if defined(PNG_READ_gAMA_SUPPORTED)
-void
-png_read_gAMA(png_structp png_ptr, png_infop info, double gamma)
-{
-   if (!info)
-      return;
-
-   info->gamma = (float)gamma;
-   info->valid |= PNG_INFO_gAMA;
-}
-#endif
-
-#if defined(PNG_READ_sBIT_SUPPORTED)
-void
-png_read_sBIT(png_structp png_ptr, png_infop info,
-   png_color_8p sig_bit)
-{
-   if (!info)
-      return;
-
-   png_memcpy(&(info->sig_bit), sig_bit, sizeof (png_color_8));
-   info->valid |= PNG_INFO_sBIT;
-}
-#endif
-
-#if defined(PNG_READ_cHRM_SUPPORTED)
-void
-png_read_cHRM(png_structp png_ptr, png_infop info,
-   double white_x, double white_y, double red_x, double red_y,
-   double green_x, double green_y, double blue_x, double blue_y)
-{
-   if (!info)
-      return;
-
-   info->x_white = (float)white_x;
-   info->y_white = (float)white_y;
-   info->x_red   = (float)red_x;
-   info->y_red   = (float)red_y;
-   info->x_green = (float)green_x;
-   info->y_green = (float)green_y;
-   info->x_blue  = (float)blue_x;
-   info->y_blue  = (float)blue_y;
-   info->valid |= PNG_INFO_cHRM;
-}
-#endif
-
-#if defined(PNG_READ_tRNS_SUPPORTED)
-void
-png_read_tRNS(png_structp png_ptr, png_infop info,
-   png_bytep trans, int num_trans,   png_color_16p trans_values)
-{
-   if (!info)
-      return;
-
-   if (trans)
-   {
-      info->trans = trans;
-   }
-   else
-   {
-      png_memcpy(&(info->trans_values), trans_values,
-         sizeof(png_color_16));
-   }
-   info->num_trans = (png_uint_16)num_trans;
-   info->valid |= PNG_INFO_tRNS;
-}
-#endif
-
-#if defined(PNG_READ_bKGD_SUPPORTED)
-void
-png_read_bKGD(png_structp png_ptr, png_infop info,
-   png_color_16p background)
-{
-   if (!info)
-      return;
-
-   png_memcpy(&(info->background), background, sizeof(png_color_16));
-   info->valid |= PNG_INFO_bKGD;
-}
-#endif
-
-#if defined(PNG_READ_hIST_SUPPORTED)
-void
-png_read_hIST(png_structp png_ptr, png_infop info, png_uint_16p hist)
-{
-   if (!info)
-      return;
-
-   info->hist = hist;
-   info->valid |= PNG_INFO_hIST;
-}
-#endif
-
-#if defined(PNG_READ_pHYs_SUPPORTED)
-void
-png_read_pHYs(png_structp png_ptr, png_infop info,
-   png_uint_32 res_x, png_uint_32 res_y, int unit_type)
-{
-   if (!info)
-      return;
-
-   info->x_pixels_per_unit = res_x;
-   info->y_pixels_per_unit = res_y;
-   info->phys_unit_type = (png_byte)unit_type;
-   info->valid |= PNG_INFO_pHYs;
-}
-#endif
-
-#if defined(PNG_READ_oFFs_SUPPORTED)
-void
-png_read_oFFs(png_structp png_ptr, png_infop info,
-   png_uint_32 offset_x, png_uint_32 offset_y, int unit_type)
-{
-   if (!info)
-      return;
-
-   info->x_offset = offset_x;
-   info->y_offset = offset_y;
-   info->offset_unit_type = (png_byte)unit_type;
-   info->valid |= PNG_INFO_oFFs;
-}
-#endif
-
-#if defined(PNG_READ_tIME_SUPPORTED)
-void
-png_read_tIME(png_structp png_ptr, png_infop info,
-   png_timep mod_time)
-{
-   if (!info)
-      return;
-
-   png_memcpy(&(info->mod_time), mod_time, sizeof (png_time));
-   info->valid |= PNG_INFO_tIME;
-}
-#endif
-
-#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
-void
-png_read_zTXt(png_structp png_ptr, png_infop info,
-   png_charp key, png_charp text, png_uint_32 text_len, int compression)
-{
-   if (!info)
-      return;
-
-   if (info->max_text <= info->num_text)
-   {
-      if (info->text)
-      {
-         png_uint_32 old_max;
-
-         old_max = info->max_text;
-         info->max_text = info->num_text + 16;
-         {
-            png_textp old_text;
-
-            old_text = info->text;
-            info->text = (png_textp)png_malloc(png_ptr,
-               info->max_text * sizeof (png_text));
-            png_memcpy(info->text, old_text,
-               (png_size_t)(old_max * sizeof (png_text)));
-            png_free(png_ptr, old_text);
-         }
-      }
-      else
-      {
-         info->max_text = 16;
-         info->num_text = 0;
-         info->text = (png_textp)png_malloc(png_ptr,
-            info->max_text * sizeof (png_text));
-      }
-   }
-
-   info->text[info->num_text].key = key;
-   info->text[info->num_text].text = text;
-   info->text[info->num_text].text_length = text_len;
-   info->text[info->num_text].compression = compression;
-   info->num_text++;
-}
-#endif
-
-#if defined(PNG_READ_tEXt_SUPPORTED)
-void
-png_read_tEXt(png_structp png_ptr, png_infop info,
-   png_charp key, png_charp text, png_uint_32 text_len)
-{
-   if (!info)
-      return;
-
-   png_read_zTXt(png_ptr, info, key, text, text_len, -1);
-}
-#endif
-
diff --git a/pngread.c b/pngread.c
index 4ebf805..294ad61 100644
--- a/pngread.c
+++ b/pngread.c
@@ -1,24 +1,26 @@
 
-/* pngread.c - read a png file
+/* pngread.c - read a PNG file
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
 #include "png.h"
 
-/* Create a png structure for reading, and allocate any memory needed. */
+/* Create a PNG structure for reading, and allocate any memory needed. */
 png_structp
-png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+png_create_read_struct(png_charp user_png_ver, png_voidp error_ptr,
    png_error_ptr error_fn, png_error_ptr warn_fn)
 {
    png_structp png_ptr;
 #ifdef USE_FAR_KEYWORD
    jmp_buf jmpbuf;
 #endif
+   png_debug(1, "in png_create_read_struct\n");
    if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
    {
       return (png_structp)NULL;
@@ -38,17 +40,16 @@
 #endif
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   /* This is what will be used for the final version.  For the
-      (ongoing) development library, we know that ALL of the
-      older library versions are out of date because of the
-      change in the info_struct size. */
-   /*
-   if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0])
-   */
-   if (user_png_ver == NULL || atof(user_png_ver) < atof(png_libpng_ver))
+   /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+    * we must recompile any applications that use any older library version.
+    * For versions after libpng 1.0, we will be compatible, so we need
+    * only check the first digit.
+    */
+   if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+       (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
    {
       png_error(png_ptr,
-                "Incompatible libpng version in application and library");
+         "Incompatible libpng version in application and library");
    }
 
    /* initialize zbuf - compression buffer */
@@ -76,7 +77,7 @@
 }
 
 
-/* Initialize png structure for reading, and allocate any memory needed.
+/* Initialize PNG structure for reading, and allocate any memory needed.
    This interface is depreciated in favour of the png_create_read_struct(),
    and it will eventually disappear. */
 void
@@ -84,6 +85,7 @@
 {
    jmp_buf tmp_jmp;  /* to save current jump buffer */
 
+   png_debug(1, "in png_read_init\n");
    /* save jump buffer and error functions */
    png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
 
@@ -126,14 +128,15 @@
 void
 png_read_info(png_structp png_ptr, png_infop info_ptr)
 {
+   png_debug(1, "in png_read_info\n");
+   /* save jump buffer and error functions */
    /* If we haven't checked all of the PNG signature bytes, do so now. */
    if (png_ptr->sig_bytes < 8)
    {
-      int num_checked = png_ptr->sig_bytes,
-          num_to_check = 8 - num_checked;
+      png_size_t num_checked = png_ptr->sig_bytes,
+                 num_to_check = 8 - num_checked;
 
-      png_read_data(png_ptr, &(info_ptr->signature[num_checked]), 
-         (png_uint_32)num_to_check);
+      png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
       png_ptr->sig_bytes = 8;
 
       if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
@@ -157,56 +160,17 @@
       png_reset_crc(png_ptr);
       png_crc_read(png_ptr, png_ptr->chunk_name, 4);
 
+      png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+      /* This should be a binary subdivision search or a hash for
+       * matching the chunk name rather than a linear search.
+       */
       if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
          png_handle_IHDR(png_ptr, info_ptr, length);
       else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
          png_handle_PLTE(png_ptr, info_ptr, length);
       else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
          png_handle_IEND(png_ptr, info_ptr, length);
-#if defined(PNG_READ_gAMA_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
-         png_handle_gAMA(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_sBIT_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
-         png_handle_sBIT(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_cHRM_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
-         png_handle_cHRM(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_tRNS_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
-         png_handle_tRNS(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_bKGD_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
-         png_handle_bKGD(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_hIST_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
-         png_handle_hIST(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_pHYs_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
-         png_handle_pHYs(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_oFFs_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
-         png_handle_oFFs(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_tIME_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
-         png_handle_tIME(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_tEXt_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
-         png_handle_tEXt(png_ptr, info_ptr, length);
-#endif
-#if defined(PNG_READ_zTXt_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
-         png_handle_zTXt(png_ptr, info_ptr, length);
-#endif
       else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
       {
          if (!(png_ptr->mode & PNG_HAVE_IHDR))
@@ -219,6 +183,54 @@
          png_ptr->mode |= PNG_HAVE_IDAT;
          break;
       }
+#if defined(PNG_READ_bKGD_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+         png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+         png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+         png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+         png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+         png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+         png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+         png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+         png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+         png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+         png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+         png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+         png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
       else
          png_handle_unknown(png_ptr, info_ptr, length);
    }
@@ -228,6 +240,8 @@
 void
 png_read_update_info(png_structp png_ptr, png_infop info_ptr)
 {
+   png_debug(1, "in png_read_update_info\n");
+   /* save jump buffer and error functions */
    if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
       png_read_start_row(png_ptr);
    png_read_transform_info(png_ptr, info_ptr);
@@ -240,6 +254,8 @@
 void
 png_start_read_image(png_structp png_ptr)
 {
+   png_debug(1, "in png_start_read_image\n");
+   /* save jump buffer and error functions */
    if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
       png_read_start_row(png_ptr);
 }
@@ -248,6 +264,9 @@
 png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
 {
    int ret;
+   png_debug2(1, "in png_read_row (row %d, pass %d)\n",
+      png_ptr->row_number, png_ptr->pass);
+   /* save jump buffer and error functions */
    if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
       png_read_start_row(png_ptr);
 
@@ -260,7 +279,7 @@
          case 0:
             if (png_ptr->row_number & 7)
             {
-               if (dsp_row)
+               if (dsp_row != NULL)
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -270,7 +289,7 @@
          case 1:
             if ((png_ptr->row_number & 7) || png_ptr->width < 5)
             {
-               if (dsp_row)
+               if (dsp_row != NULL)
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -280,7 +299,7 @@
          case 2:
             if ((png_ptr->row_number & 7) != 4)
             {
-               if (dsp_row && (png_ptr->row_number & 4))
+               if (dsp_row != NULL && (png_ptr->row_number & 4))
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -290,7 +309,7 @@
          case 3:
             if ((png_ptr->row_number & 3) || png_ptr->width < 3)
             {
-               if (dsp_row)
+               if (dsp_row != NULL)
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -300,7 +319,7 @@
          case 4:
             if ((png_ptr->row_number & 3) != 2)
             {
-               if (dsp_row && (png_ptr->row_number & 2))
+               if (dsp_row != NULL && (png_ptr->row_number & 2))
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -310,7 +329,7 @@
          case 5:
             if ((png_ptr->row_number & 1) || png_ptr->width < 2)
             {
-               if (dsp_row)
+               if (dsp_row != NULL)
                   png_combine_row(png_ptr, dsp_row,
                      png_pass_dsp_mask[png_ptr->pass]);
                png_read_finish_row(png_ptr);
@@ -355,7 +374,8 @@
          png_ptr->zstream.next_in = png_ptr->zbuf;
          if (png_ptr->zbuf_size > png_ptr->idat_size)
             png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
-         png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
+         png_crc_read(png_ptr, png_ptr->zbuf,
+            (png_size_t)png_ptr->zstream.avail_in);
          png_ptr->idat_size -= png_ptr->zstream.avail_in;
       }
       ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
@@ -386,7 +406,7 @@
       png_ptr->row_buf + 1, png_ptr->prev_row + 1,
       (int)(png_ptr->row_buf[0]));
 
-   png_memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1);
+   png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
 
    if (png_ptr->transformations)
       png_do_read_transformations(png_ptr);
@@ -398,41 +418,41 @@
    {
       if (png_ptr->pass < 6)
          png_do_read_interlace(&(png_ptr->row_info),
-            png_ptr->row_buf + 1, png_ptr->pass);
+            png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
 
-      if (dsp_row)
+      if (dsp_row != NULL)
          png_combine_row(png_ptr, dsp_row,
             png_pass_dsp_mask[png_ptr->pass]);
-      if (row)
+      if (row != NULL)
          png_combine_row(png_ptr, row,
             png_pass_mask[png_ptr->pass]);
    }
    else
 #endif
    {
-      if (row)
+      if (row != NULL)
          png_combine_row(png_ptr, row, 0xff);
-      if (dsp_row)
+      if (dsp_row != NULL)
          png_combine_row(png_ptr, dsp_row, 0xff);
    }
    png_read_finish_row(png_ptr);
 }
 
-/* read a one or more rows of image data.   If the image is interlaced,
+/* Read one or more rows of image data.  If the image is interlaced,
    and png_set_interlace_handling() has been called, the rows need to
    to contain the contents of the rows from the previous pass.  If
    the image has alpha or transparency, and png_handle_alpha() has been
    called, the rows contents must be initialized to the contents of the
-   screen.  row holds the actual image, and pixels are placed in it
+   screen.  "row" holds the actual image, and pixels are placed in it
    as they arrive.  If the image is displayed after each pass, it will
-   appear to "sparkle" in.  display_row can be used to display a
+   appear to "sparkle" in.  "display_row" can be used to display a
    "chunky" progressive image, with finer detail added as it becomes
    available.  If you do not want this "chunky" display, you may pass
-   NULL for display_rows.  If you do not want the sparkle display, and
+   NULL for display_row.  If you do not want the sparkle display, and
    you have not called png_handle_alpha(), you may pass NULL for rows.
    If you have called png_handle_alpha(), and the image has either an
    alpha channel or a transparency chunk, you must provide a buffer for
-   rows.  In this case, you do not have to provide a display_rows buffer
+   rows.  In this case, you do not have to provide a display_row buffer
    also, but you may.  If the image is not interlaced, or if you have
    not called png_set_interlace_handling(), the display_row buffer will
    be ignored, so pass NULL to it. */
@@ -445,6 +465,8 @@
    png_bytepp rp;
    png_bytepp dp;
 
+   png_debug(1, "in png_read_rows\n");
+   /* save jump buffer and error functions */
    rp = row;
    dp = display_row;
    for (i = 0; i < num_rows; i++)
@@ -452,30 +474,30 @@
       png_bytep rptr;
       png_bytep dptr;
 
-      if (rp)
+      if (rp != NULL)
          rptr = *rp;
       else
          rptr = NULL;
-      if (dp)
+      if (dp != NULL)
          dptr = *dp;
       else
          dptr = NULL;
       png_read_row(png_ptr, rptr, dptr);
-      if (row)
+      if (row != NULL)
          rp++;
-      if (display_row)
+      if (display_row != NULL)
          dp++;
    }
 }
 
-/* read the image.  If the image has an alpha channel or a transparency
+/* Read the entire image.  If the image has an alpha channel or a tRNS
    chunk, and you have called png_handle_alpha(), you will need to
-   initialize the image to the current image that png will be overlaying.
+   initialize the image to the current image that PNG will be overlaying.
    We set the num_rows again here, in case it was incorrectly set in
    png_read_start_row() by a call to png_read_update_info() or
    png_start_read_image() if png_set_interlace_handling() wasn't called
-   prior to either of these functions like it should have been.  You only
-   need to call this function once.  If you desire to have an image for
+   prior to either of these functions like it should have been.  You can
+   only call this function once.  If you desire to have an image for
    each pass of a interlaced image, use png_read_rows() instead */
 void
 png_read_image(png_structp png_ptr, png_bytepp image)
@@ -484,6 +506,8 @@
    int pass, j;
    png_bytepp rp;
 
+   png_debug(1, "in png_read_image\n");
+   /* save jump buffer and error functions */
    pass = png_set_interlace_handling(png_ptr);
 
    png_ptr->num_rows = png_ptr->height; /* Make sure this is set correctly */
@@ -499,7 +523,7 @@
    }
 }
 
-/* read the end of the png file.  Will not read past the end of the
+/* Read the end of the PNG file.  Will not read past the end of the
    file, will verify the end is accurate, and will read any comments
    or time information at the end of the file, if info is not NULL. */
 void
@@ -508,7 +532,9 @@
    png_byte chunk_length[4];
    png_uint_32 length;
 
-   png_crc_finish(png_ptr, 0);
+   png_debug(1, "in png_read_end\n");
+   /* save jump buffer and error functions */
+   png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
 
    do
    {
@@ -518,45 +544,72 @@
       png_reset_crc(png_ptr);
       png_crc_read(png_ptr, png_ptr->chunk_name, 4);
 
+      png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
       if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
          png_handle_IHDR(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
-         png_handle_PLTE(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
-         png_handle_gAMA(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
-         png_handle_sBIT(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
-         png_handle_cHRM(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
-         png_handle_tRNS(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
-         png_handle_bKGD(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
-         png_handle_hIST(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
-         png_handle_pHYs(png_ptr, info_ptr, length);
-      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
-         png_handle_oFFs(png_ptr, info_ptr, length);
       else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
       {
+         /* Zero length IDATs are legal after the last IDAT has been
+          * read, but not after other chunks have been read.
+          */
          if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
             png_error(png_ptr, "Too many IDAT's found");
+         else
+            png_crc_finish(png_ptr, 0);
       }
-#if defined(PNG_READ_tIME_SUPPORTED)
-      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
-         png_handle_tIME(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+         png_handle_PLTE(png_ptr, info_ptr, length);
+      else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+         png_handle_IEND(png_ptr, info_ptr, length);
+#if defined(PNG_READ_bKGD_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+         png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+         png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+         png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+         png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+         png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+         png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+         png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+         png_handle_sBIT(png_ptr, info_ptr, length);
 #endif
 #if defined(PNG_READ_tEXt_SUPPORTED)
       else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
          png_handle_tEXt(png_ptr, info_ptr, length);
 #endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+         png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+         png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
 #if defined(PNG_READ_zTXt_SUPPORTED)
       else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
          png_handle_zTXt(png_ptr, info_ptr, length);
 #endif
-      else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
-         png_handle_IEND(png_ptr, info_ptr, length);
       else
          png_handle_unknown(png_ptr, info_ptr, length);
    } while (!(png_ptr->mode & PNG_HAVE_IEND));
@@ -570,30 +623,32 @@
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL, end_info_ptr = NULL;
 
-   if (png_ptr_ptr)
+   png_debug(1, "in png_destroy_read_struct\n");
+   /* save jump buffer and error functions */
+   if (png_ptr_ptr != NULL)
       png_ptr = *png_ptr_ptr;
 
-   if (info_ptr_ptr)
+   if (info_ptr_ptr != NULL)
       info_ptr = *info_ptr_ptr;
 
-   if (end_info_ptr_ptr)
+   if (end_info_ptr_ptr != NULL)
       end_info_ptr = *end_info_ptr_ptr;
 
    png_read_destroy(png_ptr, info_ptr, end_info_ptr);
 
-   if (info_ptr)
+   if (info_ptr != NULL)
    {
       png_destroy_struct((png_voidp)info_ptr);
       *info_ptr_ptr = (png_infop)NULL;
    }
 
-   if (end_info_ptr)
+   if (end_info_ptr != NULL)
    {
       png_destroy_struct((png_voidp)end_info_ptr);
       *end_info_ptr_ptr = (png_infop)NULL;
    }
 
-   if (png_ptr)
+   if (png_ptr != NULL)
    {
       png_destroy_struct((png_voidp)png_ptr);
       *png_ptr_ptr = (png_structp)NULL;
@@ -610,10 +665,12 @@
    png_error_ptr warning_fn;
    png_voidp error_ptr;
 
-   if (info_ptr)
+   png_debug(1, "in png_read_destroy\n");
+   /* save jump buffer and error functions */
+   if (info_ptr != NULL)
       png_info_destroy(png_ptr, info_ptr);
 
-   if (end_info_ptr)
+   if (end_info_ptr != NULL)
       png_info_destroy(png_ptr, end_info_ptr);
 
    png_free(png_ptr, png_ptr->zbuf);
@@ -641,7 +698,7 @@
       png_free(png_ptr, png_ptr->hist);
 #endif
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-   if (png_ptr->gamma_16_table)
+   if (png_ptr->gamma_16_table != NULL)
    {
       for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
       {
@@ -651,7 +708,7 @@
 #endif
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
    png_free(png_ptr, png_ptr->gamma_16_table);
-   if (png_ptr->gamma_16_from_1)
+   if (png_ptr->gamma_16_from_1 != NULL)
    {
       for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
       {
@@ -659,7 +716,7 @@
       }
    }
    png_free(png_ptr, png_ptr->gamma_16_from_1);
-   if (png_ptr->gamma_16_to_1)
+   if (png_ptr->gamma_16_to_1 != NULL)
    {
       for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
       {
diff --git a/pngrio.c b/pngrio.c
index 96d8290..1a7f038 100644
--- a/pngrio.c
+++ b/pngrio.c
@@ -1,10 +1,11 @@
 
 /* pngrio.c - functions for data input
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
 
    This file provides a location for all input.  Users which need
    special handling are expected to write a function which has the same
@@ -20,12 +21,12 @@
    reads from a file pointer.  Note that this routine sometimes gets called
    with very small lengths, so you should implement some kind of simple
    buffering if you are using unbuffered reads.  This should never be asked
-   to read more then 64K on a 16 bit machine.  The cast to png_size_t is
-   there to quiet some compilers */
+   to read more then 64K on a 16 bit machine. */
 void
-png_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-   if (png_ptr->read_data_fn)
+   png_debug1(4,"reading %d bytes\n", length);
+   if (png_ptr->read_data_fn != NULL)
       (*(png_ptr->read_data_fn))(png_ptr, data, length);
    else
       png_error(png_ptr, "Call to NULL read function");
@@ -37,11 +38,16 @@
    than changing the library. */
 #ifndef USE_FAR_KEYWORD
 static void
-png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-   png_uint_32 check;
+   png_size_t check;
 
-   check = fread(data, 1, (size_t)length, (FILE *)png_ptr->io_ptr);
+   /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+    * instead of an int, which is what fread() actually returns.
+    */
+   check = (png_size_t)fread(data, (png_size_t)1, length,
+      (FILE *)png_ptr->io_ptr);
+
    if (check != length)
    {
       png_error(png_ptr, "Read Error");
@@ -57,9 +63,9 @@
 #define MIN(a,b) (a <= b ? a : b)
  
 static void
-png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-   png_uint_32 check;
+   int check;
    png_byte *n_data;
    FILE *io_ptr;
 
@@ -68,18 +74,18 @@
    io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
    if ((png_bytep)n_data == data)
    {
-      check = fread(n_data, 1, (size_t)length, io_ptr);
+      check = fread(n_data, 1, length, io_ptr);
    }
    else
    {
       png_byte buf[NEAR_BUF_SIZE];
       png_size_t read, remaining, err;
       check = 0;
-      remaining = (png_size_t)length;
+      remaining = length;
       do
       {
          read = MIN(NEAR_BUF_SIZE, remaining);
-         err = fread(buf, 1, read, io_ptr);
+         err = fread(buf, (png_size_t)1, read, io_ptr);
          png_memcpy(data, buf, read); /* copy far buffer to near buffer */
          if(err != read)
             break;
@@ -116,7 +122,7 @@
 {
    png_ptr->io_ptr = io_ptr;
 
-   if (read_data_fn)
+   if (read_data_fn != NULL)
       png_ptr->read_data_fn = read_data_fn;
    else
       png_ptr->read_data_fn = png_default_read_data;
diff --git a/pngrtran.c b/pngrtran.c
index fa9fe95..8df7d1f 100644
--- a/pngrtran.c
+++ b/pngrtran.c
@@ -1,15 +1,50 @@
 
-/* pngrtran.c - transforms the data in a row for png readers
+/* pngrtran.c - transforms the data in a row for PNG readers
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
 #include "png.h"
 
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines, we avoid an integer divide, which will be slower on
+   many machines.  However, it does take more operations than the corresponding
+   divide method, so it may be slower on some RISC systems.  There are two
+   shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+   The results may also be off by one for certain values. */
+
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite(composite, pixel, trans, background) \
+   { png_uint_16 temp = ((png_uint_16)(pixel) * (png_uint_16)(trans) + \
+                      (png_uint_16)(background)*(png_uint_16)(255 - \
+                      (png_uint_16)(trans)) + (png_uint_16)127); \
+     (composite) = (png_byte)(((temp >> 8) + temp) >> 8); }
+
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite_16(composite, pixel, trans, background) \
+   { png_uint_32 temp = ((png_uint_32)(pixel) * (png_uint_32)(trans) + \
+                      (png_uint_32)(background)*(png_uint_32)(65535L - \
+                      (png_uint_32)(trans)) + (png_uint_32)32767); \
+     (composite) = (png_uint_16)(((temp >> 16) + temp) >> 16); }
+#else
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite(composite, pixel, trans, background) \
+   (composite) = (png_byte)(((png_uint_16)(pixel) * (png_uint_16)(trans) + \
+     (png_uint_16)(background) * (png_uint_16)(255 - (png_uint_16)(trans)) + \
+     (png_uint_16)127) / 255)
+ 
+/* pixel and background should be in gamma 1.0 space */
+#define png_composite_16(composite, pixel, trans, background) \
+   (composite) = (png_uint_16)(((png_uint_32)(pixel) * (png_uint_32)(trans) + \
+     (png_uint_32)(background)*(png_uint_32)(65535L - (png_uint_32)(trans)) + \
+     (png_uint_32)32767) / 65535L)
+#endif
+
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
 /* handle alpha and tRNS via a background color */
 void
@@ -17,6 +52,7 @@
    png_color_16p background_color, int background_gamma_code,
    int need_expand, double background_gamma)
 {
+   png_debug(1, "in png_set_background\n");
    if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
    {
       png_warning(png_ptr, "Application must supply a known background gamma");
@@ -37,17 +73,28 @@
 void
 png_set_strip_16(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_strip_16\n");
    png_ptr->transformations |= PNG_16_TO_8;
 }
 #endif
 
-#if defined(PNG_READ_DITHER_SUPPORTED)
-/* dither file to 8 bit.  Supply a palette, the current number
-   of elements in the palette, the maximum number of elements
-   allowed, and a histogram, if possible.  If the current number
-   is greater then the maximum number, the palette will be
-   modified to fit in the maximum number */
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+void
+png_set_strip_alpha(png_structp png_ptr)
+{
+   png_debug(1, "in png_set_strip_alpha\n");
+   png_ptr->transformations |= PNG_STRIP_ALPHA;
+}
+#endif
 
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Dither file to 8 bit.  Supply a palette, the current number
+   of elements in the palette, the maximum number of elements
+   allowed, and a histogram if possible.  If the current number
+   of colors is greater then the maximum number, the palette will be
+   modified to fit in the maximum number.  "full_dither" indicates
+   whether we need a dithering cube set up for RGB images, or if we
+   simply are reducing the number of colors in a paletted image. */
 
 typedef struct png_dsort_struct
 {
@@ -63,6 +110,7 @@
    int num_palette, int maximum_colors, png_uint_16p histogram,
    int full_dither)
 {
+   png_debug(1, "in png_set_dither\n");
    png_ptr->transformations |= PNG_DITHER;
 
    if (!full_dither)
@@ -77,10 +125,10 @@
 
    if (num_palette > maximum_colors)
    {
-      if (histogram)
+      if (histogram != NULL)
       {
-         /* this is easy enough, just throw out the least used colors.
-            perhaps not the best solution, but good enough */
+         /* This is easy enough, just throw out the least used colors.
+            Perhaps not the best solution, but good enough. */
 
          int i;
          png_bytep sort;
@@ -92,7 +140,7 @@
          for (i = 0; i < num_palette; i++)
             sort[i] = (png_byte)i;
 
-         /* find the least used palette entries by starting a
+         /* Find the least used palette entries by starting a
             bubble sort, and running it until we have sorted
             out enough colors.  Note that we don't care about
             sorting all the colors, just finding which are
@@ -127,8 +175,7 @@
 
             /* put all the useful colors within the max, but don't
                move the others */
-            j = num_palette;
-            for (i = 0; i < maximum_colors; i++)
+            for (i = 0, j = num_palette; i < maximum_colors; i++)
             {
                if (sort[i] >= maximum_colors)
                {
@@ -145,8 +192,7 @@
 
             /* move all the used colors inside the max limit, and
                develop a translation table */
-            j = num_palette;
-            for (i = 0; i < maximum_colors; i++)
+            for (i = 0, j = num_palette; i < maximum_colors; i++)
             {
                /* only move the colors we need to */
                if (sort[i] >= maximum_colors)
@@ -165,34 +211,31 @@
                   png_ptr->dither_index[i] = (png_byte)j;
                }
             }
-            /* find closest color for those colors we are not
-               using */
+
+            /* find closest color for those colors we are not using */
             for (i = 0; i < num_palette; i++)
             {
                if (png_ptr->dither_index[i] >= maximum_colors)
                {
-                  int min_d, j, min_j, index;
+                  int min_d, k, min_k, d_index;
 
                   /* find the closest color to one we threw out */
-                  index = png_ptr->dither_index[i];
-                  min_d = PNG_COLOR_DIST(palette[index],
-                        palette[0]);
-                  min_j = 0;
-                  for (j = 1; j < maximum_colors; j++)
+                  d_index = png_ptr->dither_index[i];
+                  min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
+                  for (k = 1, min_k = 0; k < maximum_colors; k++)
                   {
                      int d;
 
-                     d = PNG_COLOR_DIST(palette[index],
-                        palette[j]);
+                     d = PNG_COLOR_DIST(palette[d_index], palette[k]);
 
                      if (d < min_d)
                      {
                         min_d = d;
-                        min_j = j;
+                        min_k = k;
                      }
                   }
                   /* point to closest color */
-                  png_ptr->dither_index[i] = (png_byte)min_j;
+                  png_ptr->dither_index[i] = (png_byte)min_k;
                }
             }
          }
@@ -200,11 +243,13 @@
       }
       else
       {
-         /* this is much harder to do simply (and quickly).  Perhaps
+         /* This is much harder to do simply (and quickly).  Perhaps
             we need to go through a median cut routine, but those
             don't always behave themselves with only a few colors
             as input.  So we will just find the closest two colors,
             and throw out one of them (chosen somewhat randomly).
+            [I don't understand this at all, so if someone wants to
+             work on improving it, be my guest - AED]
             */
          int i;
          int max_d;
@@ -230,7 +275,7 @@
 
          hash = (png_dsortpp)png_malloc(png_ptr, 769 * sizeof (png_dsortp));
          for (i = 0; i < 769; i++)
-            hash[i] = (png_dsortp)0;
+            hash[i] = NULL;
 /*         png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
 
          num_new_palette = num_palette;
@@ -272,7 +317,7 @@
 
             for (i = 0; i <= max_d; i++)
             {
-               if (hash[i])
+               if (hash[i] != NULL)
                {
                   png_dsortp p;
 
@@ -295,8 +340,7 @@
                         }
 
                         num_new_palette--;
-                        palette[index_to_palette[j]] =
-                           palette[num_new_palette];
+                        palette[index_to_palette[j]] = palette[num_new_palette];
                         if (!full_dither)
                         {
                            int k;
@@ -332,7 +376,7 @@
 
             for (i = 0; i < 769; i++)
             {
-               if (hash[i])
+               if (hash[i] != NULL)
                {
                   png_dsortp p;
 
@@ -356,7 +400,7 @@
       }
       num_palette = maximum_colors;
    }
-   if (!(png_ptr->palette))
+   if (png_ptr->palette == NULL)
    {
       png_ptr->palette = palette;
    }
@@ -366,7 +410,7 @@
    {
       int i;
       int total_bits, num_red, num_green, num_blue;
-      png_uint_32 num_entries;
+      png_size_t num_entries;
       png_bytep distance;
 
       total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
@@ -375,17 +419,16 @@
       num_red = (1 << PNG_DITHER_RED_BITS);
       num_green = (1 << PNG_DITHER_GREEN_BITS);
       num_blue = (1 << PNG_DITHER_BLUE_BITS);
-      num_entries = ((png_uint_32)1 << total_bits);
+      num_entries = ((png_size_t)1 << total_bits);
 
       png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
-         (png_size_t)num_entries * sizeof (png_byte));
+         num_entries * sizeof (png_byte));
 
-      png_memset(png_ptr->palette_lookup, 0, (png_size_t)num_entries * sizeof (png_byte));
+      png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
 
-      distance = (png_bytep )png_malloc(png_ptr,
-         (png_size_t)num_entries * sizeof (png_byte));
+      distance = (png_bytep)png_malloc(png_ptr, num_entries * sizeof(png_byte));
 
-      png_memset(distance, 0xff, (png_size_t)num_entries * sizeof (png_byte));
+      png_memset(distance, 0xff, num_entries * sizeof(png_byte));
 
       for (i = 0; i < num_palette; i++)
       {
@@ -411,17 +454,17 @@
                index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
                for (ib = 0; ib < num_blue; ib++)
                {
-                  int index, db, dmax, d;
+                  int d_index, db, dmax, d;
 
-                  index = index_g | ib;
+                  d_index = index_g | ib;
                   db = abs(ib - b);
                   dmax = ((dm > db) ? dm : db);
                   d = dmax + dt + db;
 
-                  if (d < distance[index])
+                  if (d < distance[d_index])
                   {
-                     distance[index] = (png_byte)d;
-                     png_ptr->palette_lookup[index] = (png_byte)i;
+                     distance[d_index] = (png_byte)d;
+                     png_ptr->palette_lookup[d_index] = (png_byte)i;
                   }
                }
             }
@@ -437,11 +480,12 @@
 /* Transform the image from the file_gamma to the screen_gamma.  We
    only do transformations on images where the file_gamma and screen_gamma
    are not close reciprocals, otherwise it slows things down slightly, and
-   also introduces small errors. */
+   also needlessly introduces small errors. */
 void
 png_set_gamma(png_structp png_ptr, double screen_gamma, double file_gamma)
 {
-   if (fabs(screen_gamma * file_gamma - 1.0) > 0.05)
+   png_debug(1, "in png_set_gamma\n");
+   if (fabs(screen_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
       png_ptr->transformations |= PNG_GAMMA;
    png_ptr->gamma = (float)file_gamma;
    png_ptr->display_gamma = (float)screen_gamma;
@@ -455,6 +499,7 @@
 void
 png_set_expand(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_expand\n");
    png_ptr->transformations |= PNG_EXPAND;
 }
 #endif
@@ -463,6 +508,7 @@
 void
 png_set_gray_to_rgb(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_gray_to_rgb\n");
    png_ptr->transformations |= PNG_GRAY_TO_RGB;
 }
 #endif
@@ -474,18 +520,20 @@
 void
 png_set_rgb_to_gray(png_structp png_ptr, int gray_bits)
 {
+   png_debug(1, "in png_set_rgb_to_gray\n");
    png_ptr->transformations |= PNG_RGB_TO_GRAY;
    /* Need to do something with gray_bits here. */
 }
 #endif
 
-/* initialize everything needed for the read.  This includes modifying
+/* Initialize everything needed for the read.  This includes modifying
    the palette */
 void
 png_init_read_transformations(png_structp png_ptr)
 {
    int color_type;
 
+   png_debug(1, "in png_init_read_transformations\n");
    color_type = png_ptr->color_type;
 
 #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
@@ -549,48 +597,77 @@
             palette = png_ptr->palette;
             num_palette = png_ptr->num_palette;
 
-            back.red = png_ptr->gamma_table[png_ptr->background.red];
-            back.green = png_ptr->gamma_table[png_ptr->background.green];
-            back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+            if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+            {
+               back.red = png_ptr->gamma_table[png_ptr->background.red];
+               back.green = png_ptr->gamma_table[png_ptr->background.green];
+               back.blue = png_ptr->gamma_table[png_ptr->background.blue];
 
-            back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
-            back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
-            back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+               back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+               back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+               back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+            }
+            else
+            {
+               double g;
+
+               g = 1.0 / (png_ptr->background_gamma * png_ptr->display_gamma);
+
+               if (png_ptr->background_gamma_type==PNG_BACKGROUND_GAMMA_SCREEN||
+                   fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+               {
+                  back.red = (png_byte)png_ptr->background.red;
+                  back.green = (png_byte)png_ptr->background.green;
+                  back.blue = (png_byte)png_ptr->background.blue;
+               }
+               else
+               {
+                  back.red =
+                     (png_byte)(pow((double)png_ptr->background.red/255, g) *
+                      255.0 + 0.5);
+                  back.green =
+                     (png_byte)(pow((double)png_ptr->background.green/255, g) *
+                      255.0 + 0.5);
+                  back.blue =
+                     (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+                      255.0 + 0.5);
+               }
+
+               g = 1.0 / png_ptr->background_gamma;
+
+               back_1.red =
+                  (png_byte)(pow((double)png_ptr->background.red/255, g) *
+                   255.0 + 0.5);
+               back_1.green =
+                  (png_byte)(pow((double)png_ptr->background.green/255, g) *
+                   255.0 + 0.5);
+               back_1.blue =
+                  (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+                   255.0 + 0.5);
+            }
 
             for (i = 0; i < num_palette; i++)
             {
-               if (i < (int)png_ptr->num_trans)
+               if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
                {
                   if (png_ptr->trans[i] == 0)
                   {
                      palette[i] = back;
                   }
-                  else if (png_ptr->trans[i] != 0xff)
+                  else /* if (png_ptr->trans[i] != 0xff) */
                   {
-                     int v, w;
+                     png_byte v, w;
 
                      v = png_ptr->gamma_to_1[palette[i].red];
-                     w = (int)(((png_uint_32)(v) *
-                        (png_uint_32)(png_ptr->trans[i]) +
-                        (png_uint_32)(back_1.red) *
-                        (png_uint_32)(255 - png_ptr->trans[i]) +
-                        127) / 255);
+                     png_composite(w, v, png_ptr->trans[i], back_1.red);
                      palette[i].red = png_ptr->gamma_from_1[w];
 
                      v = png_ptr->gamma_to_1[palette[i].green];
-                     w = (int)(((png_uint_32)(v) *
-                        (png_uint_32)(png_ptr->trans[i]) +
-                        (png_uint_32)(back_1.green) *
-                        (png_uint_32)(255 - png_ptr->trans[i]) +
-                        127) / 255);
+                     png_composite(w, v, png_ptr->trans[i], back_1.green);
                      palette[i].green = png_ptr->gamma_from_1[w];
 
                      v = png_ptr->gamma_to_1[palette[i].blue];
-                     w = (int)(((png_uint_32)(v) *
-                        (png_uint_32)(png_ptr->trans[i]) +
-                        (png_uint_32)(back_1.blue) *
-                        (png_uint_32)(255 - png_ptr->trans[i]) +
-                        127) / 255);
+                     png_composite(w, v, png_ptr->trans[i], back_1.blue);
                      palette[i].blue = png_ptr->gamma_from_1[w];
                   }
                }
@@ -602,7 +679,8 @@
                }
             }
          }
-         else if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)
+         else
+         /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
          {
             double g, gs, m;
 
@@ -694,24 +772,12 @@
          }
          else if (png_ptr->trans[i] != 0xff)
          {
-            palette[i].red = (png_byte)((
-               (png_uint_32)(palette[i].red) *
-               (png_uint_32)(png_ptr->trans[i]) +
-               (png_uint_32)(back.red) *
-               (png_uint_32)(255 - png_ptr->trans[i]) +
-               127) / 255);
-            palette[i].green = (png_byte)((
-               (png_uint_32)(palette[i].green) *
-               (png_uint_32)(png_ptr->trans[i]) +
-               (png_uint_32)(back.green) *
-               (png_uint_32)(255 - png_ptr->trans[i]) +
-               127) / 255);
-            palette[i].blue = (png_byte)((
-               (png_uint_32)(palette[i].blue) *
-               (png_uint_32)(png_ptr->trans[i]) +
-               (png_uint_32)(back.blue) *
-               (png_uint_32)(255 - png_ptr->trans[i]) +
-               127) / 255);
+            png_composite(palette[i].red, palette[i].red,
+               png_ptr->trans[i], back.red);
+            png_composite(palette[i].green, palette[i].green,
+               png_ptr->trans[i], back.green);
+            png_composite(palette[i].blue, palette[i].blue,
+               png_ptr->trans[i], back.blue);
          }
       }
    }
@@ -743,30 +809,33 @@
 #endif
 }
 
-/* modify the info structure to reflect the transformations.  The
-   info should be updated so a png file could be written with it,
-   assuming the transformations result in valid png data */
+/* Modify the info structure to reflect the transformations.  The
+   info should be updated so a PNG file could be written with it,
+   assuming the transformations result in valid PNG data. */
 void
 png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
 {
+   png_debug(1, "in png_read_transform_info\n");
 #if defined(PNG_READ_EXPAND_SUPPORTED)
-   if ((png_ptr->transformations & PNG_EXPAND) &&
-      info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+   if (png_ptr->transformations & PNG_EXPAND)
    {
-      if (png_ptr->num_trans)
-         info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-      else
-         info_ptr->color_type = PNG_COLOR_TYPE_RGB;
-      info_ptr->bit_depth = 8;
-      info_ptr->num_trans = 0;
-   }
-   else if (png_ptr->transformations & PNG_EXPAND)
-   {
-      if (png_ptr->num_trans)
-         info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
-      if (info_ptr->bit_depth < 8)
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      {
+         if (png_ptr->num_trans)
+            info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+         else
+            info_ptr->color_type = PNG_COLOR_TYPE_RGB;
          info_ptr->bit_depth = 8;
-      info_ptr->num_trans = 0;
+         info_ptr->num_trans = 0;
+      }
+      else
+      {
+         if (png_ptr->num_trans)
+            info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+         if (info_ptr->bit_depth < 8)
+            info_ptr->bit_depth = 8;
+         info_ptr->num_trans = 0;
+      }
    }
 #endif
 
@@ -806,42 +875,83 @@
       !(info_ptr->color_type & PNG_COLOR_MASK_COLOR))
       info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
 #endif
+
    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       info_ptr->channels = 1;
    else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
       info_ptr->channels = 3;
    else
       info_ptr->channels = 1;
+
+#if defined(PNG_STRIP_ALPHA_SUPPORTED)
+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
+       info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+   {
+      info_ptr->channels--;
+      info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+   }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+   if ((png_ptr->transformations & PNG_FILLER) &&
+       info_ptr->color_type & PNG_COLOR_TYPE_RGB &&
+       info_ptr->channels == 3)
+   {
+      info_ptr->channels = 4;
+   }
+#endif
+
    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
       info_ptr->channels++;
    info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
       info_ptr->bit_depth);
-   info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+
+   info_ptr->rowbytes = 
+      (png_size_t)((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
 }
 
 /* transform the row.  The order of transformations is significant,
    and is very touchy.  If you add a transformation, take care to
-   decide how it fits in with the other transformations here */
+   decide how it fits in with the other transformations here. */
 void
 png_do_read_transformations(png_structp png_ptr)
 {
+   png_debug(1, "in png_do_read_transformations\n");
+#if !defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (png_ptr->row_buf == NULL)
+   {
+      char msg[50];
+
+      sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
+         png_ptr->pass);
+      png_error(png_ptr, msg);
+   }
+#endif
 
 #if defined(PNG_READ_EXPAND_SUPPORTED)
-   if ((png_ptr->transformations & PNG_EXPAND) &&
-      png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+   if (png_ptr->transformations & PNG_EXPAND)
    {
-      png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
-         png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+      if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+      {
+         png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
+            png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+      }
+      else if (png_ptr->transformations & PNG_EXPAND)
+      {
+         if (png_ptr->num_trans)
+            png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+               &(png_ptr->trans_values));
+         else
+            png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+               NULL);
+      }
    }
-   else if (png_ptr->transformations & PNG_EXPAND)
-   {
-      if (png_ptr->num_trans)
-         png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
-            &(png_ptr->trans_values));
-      else
-         png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
-            NULL);
-   }
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+   if (png_ptr->transformations & PNG_STRIP_ALPHA)
+      png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+         PNG_FLAG_FILLER_AFTER);
 #endif
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
@@ -877,11 +987,9 @@
 #if defined(PNG_READ_DITHER_SUPPORTED)
    if (png_ptr->transformations & PNG_DITHER)
    {
-      png_do_dither((png_row_infop)&(png_ptr->row_info), 
-         png_ptr->row_buf + 1,
-         png_ptr->palette_lookup,
-         png_ptr->dither_index);
-   }      
+      png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
+         png_ptr->palette_lookup, png_ptr->dither_index);
+   }
 #endif
 
 #if defined(PNG_READ_INVERT_SUPPORTED)
@@ -905,20 +1013,30 @@
       png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
 
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+   if (png_ptr->transformations & PNG_PACKSWAP)
+      png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
 #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
    if (png_ptr->transformations & PNG_GRAY_TO_RGB)
       png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
 
-#if defined(PNG_READ_SWAP_SUPPORTED)
-   if (png_ptr->transformations & PNG_SWAP_BYTES)
-      png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
 #if defined(PNG_READ_FILLER_SUPPORTED)
    if (png_ptr->transformations & PNG_FILLER)
       png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
-         png_ptr->filler, png_ptr->flags);
+         (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+   if (png_ptr->transformations & PNG_SWAP_ALPHA)
+      png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+   if (png_ptr->transformations & PNG_SWAP_BYTES)
+      png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
 }
 
@@ -931,12 +1049,16 @@
 void
 png_do_unpack(png_row_infop row_info, png_bytep row)
 {
-   int shift;
-   png_bytep sp, dp;
-   png_uint_32 i;
-   
-   if (row && row_info && row_info->bit_depth < 8)
+   png_debug(1, "in png_do_unpack\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
+#else
+   if (row_info->bit_depth < 8)
+#endif
    {
+      png_uint_32 shift, i;
+      png_bytep sp, dp;
+
       switch (row_info->bit_depth)
       {
          case 1:
@@ -1003,7 +1125,7 @@
       }
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (png_size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -1014,17 +1136,18 @@
    a row of bit depth 8, but only 5 are significant, this will shift
    the values back to 0 through 31 */
 void
-png_do_unshift(png_row_infop row_info, png_bytep row,
-   png_color_8p sig_bits)
+png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
 {
-   png_bytep bp;
-   png_uint_16 value;
-   png_uint_32 i;
-   if (row && row_info && sig_bits &&
-      row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+   png_debug(1, "in png_do_unshift\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL && sig_bits != NULL &&
+#endif
+       row_info->color_type != PNG_COLOR_TYPE_PALETTE)
    {
       int shift[4];
-      int channels;
+      int channels, c;
+      png_uint_16 value;
 
       channels = 0;
       if (row_info->color_type & PNG_COLOR_MASK_COLOR)
@@ -1044,10 +1167,10 @@
 
       value = 0;
 
-      for (i = 0; i < channels; i++)
+      for (c = 0; c < channels; c++)
       {
-         if (shift[(png_size_t)i] <= 0)
-            shift[(png_size_t)i] = 0;
+         if (shift[c] <= 0)
+            shift[c] = 0;
          else
             value = 1;
       }
@@ -1059,9 +1182,10 @@
       {
          case 2:
          {
-            for (bp = row, i = 0;
-               i < row_info->rowbytes;
-               i++, bp++)
+            png_bytep bp;
+            png_size_t i;
+
+            for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
             {
                *bp >>= 1;
                *bp &= 0x55;
@@ -1070,12 +1194,13 @@
          }
          case 4:
          {
-            png_byte  mask;
+            png_bytep bp;
+            png_byte mask;
+            png_size_t i;
+
             mask = (png_byte)(((int)0xf0 >> shift[0]) & (int)0xf0) |
                (png_byte)((int)0xf >> shift[0]);
-            for (bp = row, i = 0;
-               i < row_info->rowbytes;
-               i++, bp++)
+            for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
             {
                *bp >>= shift[0];
                *bp &= mask;
@@ -1084,11 +1209,11 @@
          }
          case 8:
          {
-            for (bp = row, i = 0;
-               i < row_info->width; i++)
-            {
-               int c;
+            png_bytep bp;
+            png_size_t i;
 
+            for (bp = row, i = 0; i < row_info->width; i++)
+            {
                for (c = 0; c < row_info->channels; c++, bp++)
                {
                   *bp >>= shift[c];
@@ -1098,11 +1223,11 @@
          }
          case 16:
          {
-            for (bp = row, i = 0;
-               i < row_info->width; i++)
-            {
-               int c;
+            png_bytep bp;
+            png_size_t i;
 
+            for (bp = row, i = 0; i < row_info->width; i++)
+            {
                for (c = 0; c < row_info->channels; c++, bp += 2)
                {
                   value = (png_uint_16)((*bp << 8) + *(bp + 1));
@@ -1123,42 +1248,153 @@
 void
 png_do_chop(png_row_infop row_info, png_bytep row)
 {
-   png_bytep sp, dp;
-   png_uint_32 i;
-
-   if (row && row_info && row_info->bit_depth == 16)
+   png_debug(1, "in png_do_chop\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
+#else
+   if (row_info->bit_depth == 16)
+#endif
    {
+      png_bytep sp, dp;
+      png_uint_32 i;
+
       sp = row;
       dp = row;
-      for (i = 0; i < row_info->width * row_info->channels; i++)
+      for (i = 0; i < row_info->width * row_info->channels; i++, sp += 2, dp++)
       {
+#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
+         /* This does a more accurate scaling of the 16-bit color
+          * value, rather than a simple low-byte truncation.
+          *
+          * What the ideal calculation should be:
+         *dp = (((((png_uint_32)(*sp) << 8) |
+                   (png_uint_32)(*(sp + 1))) * 255 + 127) / 65535;
+
+          * Approximate calculation with shift/add instead of multiply/divide:
+         *dp = ((((png_uint_32)(*sp) << 8) |
+                  (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
+
+          * What we actually do to avoid extra shifting and conversion: */
+         *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
+#else
          *dp = *sp;
-/* not yet, as I'm afraid of overflow here
-         *dp = ((((((png_uint_16)(*sp) << 8)) |
-            (png_uint_16)((*(sp + 1) - *sp) & 0xff) +
-            0x7f) >> 8) & 0xff);
-*/
-         sp += 2;
-         dp++;
+#endif
       }
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (png_size_t)row_info->width * row_info->channels;
+   }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+void
+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+   png_debug(1, "in png_do_read_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL)
+#endif
+   {
+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+      {
+         /* This converts from RGBA to ARGB */
+         if (row_info->bit_depth == 8)
+         {
+            png_bytep sp, dp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row + row_info->rowbytes;
+               i < row_info->width; i++)
+            {
+               save = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = save;
+            }
+         }
+         /* This converts from RRGGBBAA to AARRGGBB */
+         else
+         {
+            png_bytep sp, dp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row + row_info->rowbytes;
+               i < row_info->width; i++)
+            {
+               save[0] = *(--sp);
+               save[1] = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = save[0];
+               *(--dp) = save[1];
+            }
+         }
+      }
+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+      {
+         /* This converts from GA to AG */
+         if (row_info->bit_depth == 8)
+         {
+            png_bytep sp, dp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row + row_info->rowbytes;
+               i < row_info->width; i++)
+            {
+               save = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = save;
+            }
+         }
+         /* This converts from GGAA to AAGG */
+         else
+         {
+            png_bytep sp, dp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row + row_info->rowbytes;
+               i < row_info->width; i++)
+            {
+               save[0] = *(--sp);
+               save[1] = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = *(--sp);
+               *(--dp) = save[0];
+               *(--dp) = save[1];
+            }
+         }
+      }
    }
 }
 #endif
 
 #if defined(PNG_READ_FILLER_SUPPORTED)
-/* add filler byte */
+/* Add filler channel if we have RGB color */
 void
 png_do_read_filler(png_row_infop row_info, png_bytep row,
-   png_byte filler, png_uint_32 flags)
+   png_uint_32 filler, png_uint_32 flags)
 {
    png_bytep sp, dp;
    png_uint_32 i;
-   if (row && row_info && row_info->color_type == 2 &&
-      row_info->bit_depth == 8)
+
+   png_debug(1, "in png_do_read_filler\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL  && row_info != NULL &&
+#endif
+       row_info->color_type == PNG_COLOR_TYPE_RGB && row_info->bit_depth == 8)
    {
+      /* This changes the data from RGB to RGBX */
       if (flags & PNG_FLAG_FILLER_AFTER)
       {
          for (i = 1, sp = row + (png_size_t)row_info->width * 3,
@@ -1166,16 +1402,17 @@
             i < row_info->width;
             i++)
          {
-            *(--dp) = filler;
+            *(--dp) = (png_byte)filler;
             *(--dp) = *(--sp);
             *(--dp) = *(--sp);
             *(--dp) = *(--sp);
          }
-         *(--dp) = filler;
+         *(--dp) = (png_byte)filler;
          row_info->channels = 4;
          row_info->pixel_depth = 32;
-         row_info->rowbytes = row_info->width * 4;
+         row_info->rowbytes = (png_size_t)row_info->width * 4;
       }
+      /* This changes the data from RGB to XRGB */
       else
       {
          for (i = 0, sp = row + (png_size_t)row_info->width * 3,
@@ -1186,25 +1423,29 @@
             *(--dp) = *(--sp);
             *(--dp) = *(--sp);
             *(--dp) = *(--sp);
-            *(--dp) = filler;
+            *(--dp) = (png_byte)filler;
          }
          row_info->channels = 4;
          row_info->pixel_depth = 32;
-         row_info->rowbytes = row_info->width * 4;
+         row_info->rowbytes = (png_size_t)row_info->width * 4;
       }
    }
 }
 #endif
 
 #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
-/* expand grayscale files to rgb, with or without alpha */
+/* expand grayscale files to RGB, with or without alpha */
 void
 png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
 {
    png_bytep sp, dp;
    png_uint_32 i;
 
-   if (row && row_info && row_info->bit_depth >= 8 &&
+   png_debug(1, "in png_do_gray_to_rgb\n");
+   if (row_info->bit_depth >= 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
       !(row_info->color_type & PNG_COLOR_MASK_COLOR))
    {
       if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
@@ -1280,7 +1521,7 @@
       row_info->color_type |= PNG_COLOR_MASK_COLOR;
       row_info->pixel_depth = (png_byte)(row_info->channels *
          row_info->bit_depth);
-      row_info->rowbytes = ((row_info->width *
+      row_info->rowbytes = (png_size_t)((row_info->width *
          row_info->pixel_depth + 7) >> 3);
    }
 }
@@ -1298,7 +1539,8 @@
    int i;
    int v;
 
-   if (!palette)
+   png_debug(1, "in png_do_build_grayscale_palette\n");
+   if (palette == NULL)
       return;
 
    switch (bit_depth)
@@ -1339,15 +1581,15 @@
 png_correct_palette(png_structp png_ptr, png_colorp palette,
    int num_palette)
 {
+   png_debug(1, "in png_correct_palette\n");
 #if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
    if ((png_ptr->transformations & (PNG_GAMMA)) &&
       (png_ptr->transformations & (PNG_BACKGROUND)))
    {
-      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-      {
-         int i;
-         png_color back, back_1;
+      png_color back, back_1;
 
+      if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+      {
          back.red = png_ptr->gamma_table[png_ptr->background.red];
          back.green = png_ptr->gamma_table[png_ptr->background.green];
          back.blue = png_ptr->gamma_table[png_ptr->background.blue];
@@ -1355,42 +1597,71 @@
          back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
          back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
          back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+      }
+      else
+      {
+         double g;
 
-         for (i = 0; i < num_palette; i++)
+         g = 1.0 / (png_ptr->background_gamma * png_ptr->display_gamma);
+
+         if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
+             fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
          {
-            if (i < (int)png_ptr->num_trans &&
-               png_ptr->trans[i] == 0)
+            back.red = png_ptr->background.red;
+            back.green = png_ptr->background.green;
+            back.blue = png_ptr->background.blue;
+         }
+         else
+         {
+            back.red =
+               (png_byte)(pow((double)png_ptr->background.red/255, g) *
+                255.0 + 0.5);
+            back.green =
+               (png_byte)(pow((double)png_ptr->background.green/255, g) *
+                255.0 + 0.5);
+            back.blue =
+               (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+                255.0 + 0.5);
+         }
+
+         g = 1.0 / png_ptr->background_gamma;
+
+         back_1.red =
+            (png_byte)(pow((double)png_ptr->background.red/255, g) *
+             255.0 + 0.5);
+         back_1.green =
+            (png_byte)(pow((double)png_ptr->background.green/255, g) *
+             255.0 + 0.5);
+         back_1.blue =
+            (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+             255.0 + 0.5);
+      }
+
+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      {
+         png_uint_32 i;
+
+         for (i = 0; i < (png_uint_32)num_palette; i++)
+         {
+            if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
             {
                palette[i] = back;
             }
-            else if (i < (int)png_ptr->num_trans &&
-               png_ptr->trans[i] != 0xff)
+            else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
             {
-               int v;
+               png_byte v, w;
 
                v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
-               v = (int)(((png_uint_32)(v) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back_1.red) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
-               palette[i].red = png_ptr->gamma_from_1[v];
+               png_composite(w, v, png_ptr->trans[i], back_1.red);
+               palette[i].red = png_ptr->gamma_from_1[w];
 
                v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
-               v = (int)(((png_uint_32)(v) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back_1.green) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
-               palette[i].green = png_ptr->gamma_from_1[v];
+               png_composite(w, v, png_ptr->trans[i], back_1.green);
+               palette[i].green = png_ptr->gamma_from_1[w];
 
                v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
-               v = (int)(((png_uint_32)(v) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back_1.blue) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
-               palette[i].blue = png_ptr->gamma_from_1[v];
+               png_composite(w, v, png_ptr->trans[i], back_1.blue);
+               palette[i].blue = png_ptr->gamma_from_1[w];
             }
             else
             {
@@ -1403,15 +1674,10 @@
       else
       {
          int i;
-         png_color back;
-
-         back.red = png_ptr->gamma_table[png_ptr->background.red];
-         back.green = png_ptr->gamma_table[png_ptr->background.green];
-         back.blue = png_ptr->gamma_table[png_ptr->background.blue];
 
          for (i = 0; i < num_palette; i++)
          {
-            if (palette[i].red == png_ptr->trans_values.gray)
+            if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
             {
                palette[i] = back;
             }
@@ -1427,7 +1693,7 @@
    else
 #endif
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-   if (png_ptr->transformations & (PNG_GAMMA))
+   if (png_ptr->transformations & PNG_GAMMA)
    {
       int i;
 
@@ -1443,7 +1709,7 @@
 #endif
 #endif
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
-   if (png_ptr->transformations & (PNG_BACKGROUND))
+   if (png_ptr->transformations & PNG_BACKGROUND)
    {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
@@ -1466,24 +1732,12 @@
             else if (i < (int)png_ptr->num_trans ||
                png_ptr->trans[i] != 0xff)
             {
-               palette[i].red = (png_byte)((
-                  (png_uint_32)(png_ptr->palette[i].red) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back.red) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
-               palette[i].green = (png_byte)((
-                  (png_uint_32)(png_ptr->palette[i].green) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back.green) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
-               palette[i].blue = (png_byte)((
-                  (png_uint_32)(png_ptr->palette[i].blue) *
-                  (png_uint_32)(png_ptr->trans[i]) +
-                  (png_uint_32)(back.blue) *
-                  (png_uint_32)(255 - png_ptr->trans[i]) +
-                  127) / 255);
+               png_composite(palette[i].red, png_ptr->palette[i].red,
+                  png_ptr->trans[i], back.red);
+               png_composite(palette[i].green, png_ptr->palette[i].green,
+                  png_ptr->trans[i], back.green);
+               png_composite(palette[i].blue, png_ptr->palette[i].blue,
+                  png_ptr->trans[i], back.blue);
             }
          }
       }
@@ -1493,7 +1747,7 @@
 
          for (i = 0; i < num_palette; i++)
          {
-            if (i == (int)png_ptr->trans_values.gray)
+            if (i == (png_byte)png_ptr->trans_values.gray)
             {
                palette[i].red = (png_byte)png_ptr->background.red;
                palette[i].green = (png_byte)png_ptr->background.green;
@@ -1507,9 +1761,9 @@
 #endif
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
-/* replace any alpha or transparency with the supplied background color.
-   background is the color.  note that paletted files are taken care of
-   elsewhere */
+/* Replace any alpha or transparency with the supplied background color.
+   "background" is already in the screen gamma, while "background_1" is
+   at a gamma of 1.0.  Paletted files have already been taken care of. */
 void
 png_do_background(png_row_infop row_info, png_bytep row,
    png_color_16p trans_values, png_color_16p background,
@@ -1522,15 +1776,19 @@
    png_uint_32 i;
    int shift;
 
-   if (row && row_info && background &&
+   png_debug(1, "in png_do_background\n");
+   if (background != NULL &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
       (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
-      (row_info->color_type != PNG_COLOR_TYPE_PALETTE &&
-      trans_values)))
+      (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
    {
       switch (row_info->color_type)
       {
          case PNG_COLOR_TYPE_GRAY:
          {
+            /* We currently don't do gamma correction for 2 and 4 bit */
             switch (row_info->bit_depth)
             {
                case 1:
@@ -1539,8 +1797,7 @@
                   shift = 7;
                   for (i = 0; i < row_info->width; i++)
                   {
-                     if (((*sp >> shift) & 0x1) ==
-                        trans_values->gray)
+                     if (((*sp >> shift) & 0x1) == trans_values->gray)
                      {
                         *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
                         *sp |= (png_byte)(background->gray << shift);
@@ -1561,8 +1818,7 @@
                   shift = 6;
                   for (i = 0; i < row_info->width; i++)
                   {
-                     if (((*sp >> shift) & 0x3) ==
-                        trans_values->gray)
+                     if (((*sp >> shift) & 0x3) == trans_values->gray)
                      {
                         *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
                         *sp |= (png_byte)(background->gray << shift);
@@ -1583,8 +1839,7 @@
                   shift = 4;
                   for (i = 0; i < row_info->width; i++)
                   {
-                     if (((*sp >> shift) & 0xf) ==
-                        trans_values->gray)
+                     if (((*sp >> shift) & 0xf) == trans_values->gray)
                      {
                         *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
                         *sp |= (png_byte)(background->gray << shift);
@@ -1602,15 +1857,13 @@
                case 8:
                {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-                  if (gamma_table)
+                  if (gamma_table != NULL)
                   {
-
-                     for (i = 0, sp = row;
-                        i < row_info->width; i++, sp++)
+                     for (i = 0, sp = row; i < row_info->width; i++, sp++)
                      {
                         if (*sp == trans_values->gray)
                         {
-                           *sp = background->gray;
+                           *sp = (png_byte)background->gray;
                         }
                         else
                         {
@@ -1621,12 +1874,11 @@
                   else
 #endif
                   {
-                     for (i = 0, sp = row;
-                        i < row_info->width; i++, sp++)
+                     for (i = 0, sp = row; i < row_info->width; i++, sp++)
                      {
                         if (*sp == trans_values->gray)
                         {
-                           *sp = background->gray;
+                           *sp = (png_byte)background->gray;
                         }
                      }
                   }
@@ -1635,24 +1887,22 @@
                case 16:
                {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-                  if (gamma_16)
+                  if (gamma_16 != NULL)
                   {
-                     for (i = 0, sp = row;
-                        i < row_info->width; i++, sp += 2)
+                     for (i = 0, sp = row; i < row_info->width; i++, sp += 2)
                      {
                         png_uint_16 v;
 
-                        v = (png_uint_16)(((png_uint_16)(*sp) << 8) +
-                           (png_uint_16)(*(sp + 1)));
+                        v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
                         if (v == trans_values->gray)
                         {
+                           /* background is already in screen gamma */
                            *sp = (png_byte)((background->gray >> 8) & 0xff);
                            *(sp + 1) = (png_byte)(background->gray & 0xff);
                         }
                         else
                         {
-                           v = gamma_16[
-                              *(sp + 1) >> gamma_shift][*sp];
+                           v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
                            *sp = (png_byte)((v >> 8) & 0xff);
                            *(sp + 1) = (png_byte)(v & 0xff);
                         }
@@ -1661,13 +1911,11 @@
                   else
 #endif
                   {
-                     for (i = 0, sp = row;
-                        i < row_info->width; i++, sp += 2)
+                     for (i = 0, sp = row; i < row_info->width; i++, sp += 2)
                      {
                         png_uint_16 v;
 
-                        v = (png_uint_16)(((png_uint_16)(*sp) << 8) +
-                           (png_uint_16)(*(sp + 1)));
+                        v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
                         if (v == trans_values->gray)
                         {
                            *sp = (png_byte)((background->gray >> 8) & 0xff);
@@ -1685,18 +1933,17 @@
             if (row_info->bit_depth == 8)
             {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-               if (gamma_table)
+               if (gamma_table != NULL)
                {
-                  for (i = 0, sp = row;
-                     i < row_info->width; i++, sp += 3)
+                  for (i = 0, sp = row; i < row_info->width; i++, sp += 3)
                   {
                      if (*sp == trans_values->red &&
                         *(sp + 1) == trans_values->green &&
                         *(sp + 2) == trans_values->blue)
                      {
-                        *sp = background->red;
-                        *(sp + 1) = background->green;
-                        *(sp + 2) = background->blue;
+                        *sp = (png_byte)background->red;
+                        *(sp + 1) = (png_byte)background->green;
+                        *(sp + 2) = (png_byte)background->blue;
                      }
                      else
                      {
@@ -1709,40 +1956,35 @@
                else
 #endif
                {
-                  for (i = 0, sp = row;
-                     i < row_info->width; i++, sp += 3)
+                  for (i = 0, sp = row; i < row_info->width; i++, sp += 3)
                   {
                      if (*sp == trans_values->red &&
                         *(sp + 1) == trans_values->green &&
                         *(sp + 2) == trans_values->blue)
                      {
-                        *sp = background->red;
-                        *(sp + 1) = background->green;
-                        *(sp + 2) = background->blue;
+                        *sp = (png_byte)background->red;
+                        *(sp + 1) = (png_byte)background->green;
+                        *(sp + 2) = (png_byte)background->blue;
                      }
                   }
                }
             }
-            else if (row_info->bit_depth == 16)
+            else /* if (row_info->bit_depth == 16) */
             {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-               if (gamma_16)
+               if (gamma_16 != NULL)
                {
-                  for (i = 0, sp = row;
-                     i < row_info->width; i++, sp += 6)
+                  for (i = 0, sp = row; i < row_info->width; i++, sp += 6)
                   {
                      png_uint_16 r, g, b;
 
-                     r = (png_uint_16)(((png_uint_16)(*sp) << 8) +
-                        (png_uint_16)(*(sp + 1)));
-                     g = (png_uint_16)(((png_uint_16)(*(sp + 2)) << 8) +
-                        (png_uint_16)(*(sp + 3)));
-                     b = (png_uint_16)(((png_uint_16)(*(sp + 4)) << 8) +
-                        (png_uint_16)(*(sp + 5)));
-                     if (r == trans_values->red &&
-                        g == trans_values->green &&
+                     r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+                     g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+                     b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+                     if (r == trans_values->red && g == trans_values->green &&
                         b == trans_values->blue)
                      {
+                        /* background is already in screen gamma */
                         *sp = (png_byte)((background->red >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(background->red & 0xff);
                         *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
@@ -1753,16 +1995,13 @@
                      else
                      {
                         png_uint_16 v;
-                        v = gamma_16[
-                           *(sp + 1) >> gamma_shift][*sp];
+                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
                         *sp = (png_byte)((v >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(v & 0xff);
-                        v = gamma_16[
-                           *(sp + 3) >> gamma_shift][*(sp + 2)];
+                        v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
                         *(sp + 2) = (png_byte)((v >> 8) & 0xff);
                         *(sp + 3) = (png_byte)(v & 0xff);
-                        v = gamma_16[
-                           *(sp + 5) >> gamma_shift][*(sp + 4)];
+                        v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
                         *(sp + 4) = (png_byte)((v >> 8) & 0xff);
                         *(sp + 5) = (png_byte)(v & 0xff);
                      }
@@ -1771,19 +2010,14 @@
                else
 #endif
                {
-                  for (i = 0, sp = row;
-                     i < row_info->width; i++, sp += 6)
+                  for (i = 0, sp = row; i < row_info->width; i++, sp += 6)
                   {
                      png_uint_16 r, g, b;
 
-                     r = (png_uint_16)(((png_uint_16)(*sp) << 8) +
-                        (png_uint_16)(*(sp + 1)));
-                     g = (png_uint_16)(((png_uint_16)(*(sp + 2)) << 8) +
-                        (png_uint_16)(*(sp + 3)));
-                     b = (png_uint_16)(((png_uint_16)(*(sp + 4)) << 8) +
-                        (png_uint_16)(*(sp + 5)));
-                     if (r == trans_values->red &&
-                        g == trans_values->green &&
+                     r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+                     g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+                     b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+                     if (r == trans_values->red && g == trans_values->green &&
                         b == trans_values->blue)
                      {
                         *sp = (png_byte)((background->red >> 8) & 0xff);
@@ -1800,148 +2034,127 @@
          }
          case PNG_COLOR_TYPE_GRAY_ALPHA:
          {
-            switch (row_info->bit_depth)
+            if (row_info->bit_depth == 8)
             {
-               case 8:
-               {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-                  if (gamma_to_1 && gamma_from_1 && gamma_table)
+               if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+                   gamma_table != NULL)
+               {
+                  for (i = 0, sp = row, dp = row;
+                     i < row_info->width; i++, sp += 2, dp++)
                   {
-                     for (i = 0, sp = row,
-                        dp = row;
-                        i < row_info->width; i++, sp += 2, dp++)
+                     png_uint_16 a;
+
+                     a = *(sp + 1);
+                     if (a == 0xff)
                      {
-                        png_uint_16 a;
+                        *dp = gamma_table[*sp];
+                     }
+                     else if (a == 0)
+                     {
+                        /* background is already in screen gamma */
+                        *dp = (png_byte)background->gray;
+                     }
+                     else
+                     {
+                        png_byte v, w;
 
-                        a = *(sp + 1);
-                        if (a == 0xff)
-                        {
-                           *dp = gamma_table[*sp];
-                        }
-                        else if (a == 0)
-                        {
-                           *dp = background->gray;
-                        }
-                        else
-                        {
-                           png_uint_16 v;
-
-                           v = gamma_to_1[*sp];
-                           v = (png_uint_16)(((png_uint_16)(v) * a +
-                              (png_uint_16)background_1->gray *
-                              (255 - a) + 127) / 255);
-                           *dp = gamma_from_1[v];
-                        }
+                        v = gamma_to_1[*sp];
+                        png_composite(w, v, a, background_1->gray);
+                        *dp = gamma_from_1[w];
                      }
                   }
-                  else
-#endif
-                  {
-                     for (i = 0, sp = row,
-                        dp = row;
-                        i < row_info->width; i++, sp += 2, dp++)
-                     {
-                        png_uint_16 a;
-
-                        a = *(sp + 1);
-                        if (a == 0xff)
-                        {
-                           *dp = *sp;
-                        }
-                        else if (a == 0)
-                        {
-                           *dp = background->gray;
-                        }
-                        else
-                        {
-                           *dp = (png_byte)(((png_uint_16)(*sp) * a +
-                              (png_uint_16)background_1->gray *
-                              (255 - a) + 127) / 255);
-                        }
-                     }
-                  }
-                  break;
                }
-               case 16:
-               {
-#if defined(PNG_READ_GAMMA_SUPPORTED)
-                  if (gamma_16 && gamma_16_from_1 && gamma_16_to_1)
-                  {
-                     for (i = 0, sp = row,
-                        dp = row;
-                        i < row_info->width; i++, sp += 4, dp += 2)
-                     {
-                        png_uint_16 a;
-
-                        a = (png_uint_16)(((png_uint_16)(*(sp + 2)) << 8) +
-                           (png_uint_16)(*(sp + 3)));
-                        if (a == (png_uint_16)0xffff)
-                        {
-                           png_uint_32 v;
-
-                           v = gamma_16[
-                              *(sp + 1) >> gamma_shift][*sp];
-                           *dp = (png_byte)((v >> 8) & 0xff);
-                           *(dp + 1) = (png_byte)(v & 0xff);
-                        }
-                        else if (a == 0)
-                        {
-                           *dp = (png_byte)((background->gray >> 8) & 0xff);
-                           *(dp + 1) = (png_byte)(background->gray & 0xff);
-                        }
-                        else
-                        {
-                           png_uint_32 g, v;
-
-                           g = gamma_16_to_1[
-                              *(sp + 1) >> gamma_shift][*sp];
-                           v = (g * (png_uint_32)a +
-                              (png_uint_32)background_1->gray *
-                              (png_uint_32)((png_uint_16)65535L - a) +
-                              (png_uint_16)32767) / (png_uint_16)65535L;
-                           v = gamma_16_from_1[(size_t)(
-                              (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
-                           *dp = (png_byte)((v >> 8) & 0xff);
-                           *(dp + 1) = (png_byte)(v & 0xff);
-                        }
-                     }
-                  }
-                  else
+               else
 #endif
+               {
+                  for (i = 0, sp = row, dp = row;
+                     i < row_info->width; i++, sp += 2, dp++)
                   {
-                     for (i = 0, sp = row,
-                        dp = row;
-                        i < row_info->width; i++, sp += 4, dp += 2)
+                     png_byte a;
+
+                     a = *(sp + 1);
+                     if (a == 0xff)
                      {
-                        png_uint_16 a;
-
-                        a = (png_uint_16)(((png_uint_16)(*(sp + 2)) << 8) +
-                           (png_uint_16)(*(sp + 3)));
-                        if (a == (png_uint_16)0xffff)
-                        {
-                           png_memcpy(dp, sp, 2);
-                        }
-                        else if (a == 0)
-                        {
-                           *dp = (png_byte)((background->gray >> 8) & 0xff);
-                           *(dp + 1) = (png_byte)(background->gray & 0xff);
-                        }
-                        else
-                        {
-                           png_uint_32 g, v;
-
-                           g = ((png_uint_32)(*sp) << 8) +
-                              (png_uint_32)(*(sp + 1));
-                           v = (g * (png_uint_32)a +
-                              (png_uint_32)background_1->gray *
-                              (png_uint_32)((png_uint_16)65535L - a) +
-                              (png_uint_16)32767) / (png_uint_16)65535L;
-                           *dp = (png_byte)((v >> 8) & 0xff);
-                           *(dp + 1) = (png_byte)(v & 0xff);
-                        }
+                        *dp = *sp;
+                     }
+                     else if (a == 0)
+                     {
+                        *dp = (png_byte)background->gray;
+                     }
+                     else
+                     {
+                        png_composite(*dp, *sp, a, background_1->gray);
                      }
                   }
-                  break;
+               }
+            }
+            else /* if (png_ptr->bit_depth == 16) */
+            {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+               if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+                   gamma_16_to_1 != NULL)
+               {
+                  for (i = 0, sp = row, dp = row;
+                     i < row_info->width; i++, sp += 4, dp += 2)
+                  {
+                     png_uint_16 a;
+
+                     a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+                     if (a == (png_uint_16)0xffff)
+                     {
+                        png_uint_16 v;
+
+                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+                        *dp = (png_byte)((v >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(v & 0xff);
+                     }
+                     else if (a == 0)
+                     {
+                        /* background is already in screen gamma */
+                        *dp = (png_byte)((background->gray >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(background->gray & 0xff);
+                     }
+                     else
+                     {
+                        png_uint_16 g, v, w;
+
+                        g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+                        png_composite_16(v, g, a, background_1->gray);
+                        w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+                        *dp = (png_byte)((w >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(w & 0xff);
+                     }
+                  }
+               }
+               else
+#endif
+               {
+                  for (i = 0, sp = row, dp = row;
+                     i < row_info->width; i++, sp += 4, dp += 2)
+                  {
+                     png_uint_16 a;
+
+                     a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+                     if (a == (png_uint_16)0xffff)
+                     {
+                        png_memcpy(dp, sp, 2);
+                     }
+                     else if (a == 0)
+                     {
+                        *dp = (png_byte)((background->gray >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(background->gray & 0xff);
+                     }
+                     else
+                     {
+                        png_uint_16 g, v;
+
+                        g = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+                        png_composite_16(v, g, a, background_1->gray);
+                        *dp = (png_byte)((v >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(v & 0xff);
+                     }
+                  }
                }
             }
             break;
@@ -1951,13 +2164,13 @@
             if (row_info->bit_depth == 8)
             {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-               if (gamma_to_1 && gamma_from_1 && gamma_table)
+               if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+                   gamma_table != NULL)
                {
-                  for (i = 0, sp = row,
-                     dp = row;
+                  for (i = 0, sp = row, dp = row;
                      i < row_info->width; i++, sp += 4, dp += 3)
                   {
-                     png_uint_16 a;
+                     png_byte a;
 
                      a = *(sp + 3);
                      if (a == 0xff)
@@ -1968,40 +2181,34 @@
                      }
                      else if (a == 0)
                      {
-                        *dp = background->red;
-                        *(dp + 1) = background->green;
-                        *(dp + 2) = background->blue;
+                        /* background is already in screen gamma */
+                        *dp = (png_byte)background->red;
+                        *(dp + 1) = (png_byte)background->green;
+                        *(dp + 2) = (png_byte)background->blue;
                      }
                      else
                      {
-                        png_uint_16 v;
+                        png_byte v, w;
 
                         v = gamma_to_1[*sp];
-                        v = (png_uint_16)(((png_uint_16)(v) * a +
-                           (png_uint_16)background_1->red *
-                           (255 - a) + 127) / 255);
-                        *dp = gamma_from_1[v];
+                        png_composite(w, v, a, background_1->red);
+                        *dp = gamma_from_1[w];
                         v = gamma_to_1[*(sp + 1)];
-                        v = (png_uint_16)(((png_uint_16)(v) * a +
-                           (png_uint_16)background_1->green *
-                           (255 - a) + 127) / 255);
-                        *(dp + 1) = gamma_from_1[v];
+                        png_composite(w, v, a, background_1->green);
+                        *(dp + 1) = gamma_from_1[w];
                         v = gamma_to_1[*(sp + 2)];
-                        v = (png_uint_16)(((png_uint_16)(v) * a +
-                           (png_uint_16)background_1->blue *
-                           (255 - a) + 127) / 255);
-                        *(dp + 2) = gamma_from_1[v];
+                        png_composite(w, v, a, background_1->blue);
+                        *(dp + 2) = gamma_from_1[w];
                      }
                   }
                }
                else
 #endif
                {
-                  for (i = 0, sp = row,
-                     dp = row;
+                  for (i = 0, sp = row, dp = row;
                      i < row_info->width; i++, sp += 4, dp += 3)
                   {
-                     png_uint_16 a;
+                     png_byte a;
 
                      a = *(sp + 3);
                      if (a == 0xff)
@@ -2012,57 +2219,51 @@
                      }
                      else if (a == 0)
                      {
-                        *dp = background->red;
-                        *(dp + 1) = background->green;
-                        *(dp + 2) = background->blue;
+                        *dp = (png_byte)background->red;
+                        *(dp + 1) = (png_byte)background->green;
+                        *(dp + 2) = (png_byte)background->blue;
                      }
                      else
                      {
-                        *dp = (png_byte)(((png_uint_16)(*sp) * a +
-                           (png_uint_16)background->red *
-                           (255 - a) + 127) / 255);
-                        *(dp + 1) = (png_byte)(((png_uint_16)(*(sp + 1)) * a +
-                           (png_uint_16)background->green *
-                           (255 - a) + 127) / 255);
-                        *(dp + 2) = (png_byte)(((png_uint_16)(*(sp + 2)) * a +
-                           (png_uint_16)background->blue *
-                           (255 - a) + 127) / 255);
+                        png_composite(*dp, *sp, a, background->red);
+                        png_composite(*(dp + 1), *(sp + 1), a,
+                           background->green);
+                        png_composite(*(dp + 2), *(sp + 2), a,
+                           background->blue);
                      }
                   }
                }
             }
-            else if (row_info->bit_depth == 16)
+            else /* if (row_info->bit_depth == 16) */
             {
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-               if (gamma_16 && gamma_16_from_1 && gamma_16_to_1)
+               if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+                   gamma_16_to_1 != NULL)
                {
-                  for (i = 0, sp = row,
-                     dp = row;
+                  for (i = 0, sp = row, dp = row;
                      i < row_info->width; i++, sp += 8, dp += 6)
                   {
                      png_uint_16 a;
 
                      a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) +
-                        (png_uint_16)(*(sp + 7)));
+                         (png_uint_16)(*(sp + 7)));
                      if (a == (png_uint_16)0xffff)
                      {
                         png_uint_16 v;
 
-                        v = gamma_16[
-                           *(sp + 1) >> gamma_shift][*sp];
+                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
                         *dp = (png_byte)((v >> 8) & 0xff);
                         *(dp + 1) = (png_byte)(v & 0xff);
-                        v = gamma_16[
-                           *(sp + 3) >> gamma_shift][*(sp + 2)];
+                        v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
                         *(dp + 2) = (png_byte)((v >> 8) & 0xff);
                         *(dp + 3) = (png_byte)(v & 0xff);
-                        v = gamma_16[
-                           *(sp + 5) >> gamma_shift][*(sp + 4)];
+                        v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
                         *(dp + 4) = (png_byte)((v >> 8) & 0xff);
                         *(dp + 5) = (png_byte)(v & 0xff);
                      }
                      else if (a == 0)
                      {
+                        /* background is already in screen gamma */
                         *dp = (png_byte)((background->red >> 8) & 0xff);
                         *(dp + 1) = (png_byte)(background->red & 0xff);
                         *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
@@ -2072,46 +2273,30 @@
                      }
                      else
                      {
-                        png_uint_32 v;
+                        png_uint_16 v, w, x;
 
-                        v = gamma_16_to_1[
-                           *(sp + 1) >> gamma_shift][*sp];
-                        v = (v * (png_uint_32)a +
-                           (png_uint_32)background->red *
-                           (png_uint_32)((png_uint_16)65535L - a) +
-                           (png_uint_16)32767) / (png_uint_16)65535L;
-                        v = gamma_16_from_1[(size_t)(
-                           (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
-                        *dp = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(v & 0xff);
-                        v = gamma_16_to_1[
-                           *(sp + 3) >> gamma_shift][*(sp + 2)];
-                        v = (v * (png_uint_32)a +
-                           (png_uint_32)background->green *
-                           (png_uint_32)((png_uint_16)65535L - a) +
-                           (png_uint_16)32767) / (png_uint_16)65535L;
-                        v = gamma_16_from_1[(size_t)(
-                           (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
-                        *(dp + 2) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(v & 0xff);
-                        v = gamma_16_to_1[
-                           *(sp + 5) >> gamma_shift][*(sp + 4)];
-                        v = (v * (png_uint_32)a +
-                           (png_uint_32)background->blue *
-                           (png_uint_32)((png_uint_16)65535L - a) +
-                           (png_uint_16)32767) / (png_uint_16)65535L;
-                        v = gamma_16_from_1[(size_t)(
-                           (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
-                        *(dp + 4) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(v & 0xff);
+                        v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+                        png_composite_16(w, v, a, background->red);
+                        x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        *dp = (png_byte)((x >> 8) & 0xff);
+                        *(dp + 1) = (png_byte)(x & 0xff);
+                        v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+                        png_composite_16(w, v, a, background->green);
+                        x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        *(dp + 2) = (png_byte)((x >> 8) & 0xff);
+                        *(dp + 3) = (png_byte)(x & 0xff);
+                        v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+                        png_composite_16(w, v, a, background->blue);
+                        x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
+                        *(dp + 4) = (png_byte)((x >> 8) & 0xff);
+                        *(dp + 5) = (png_byte)(x & 0xff);
                      }
                   }
                }
                else
 #endif
                {
-                  for (i = 0, sp = row,
-                     dp = row;
+                  for (i = 0, sp = row, dp = row;
                      i < row_info->width; i++, sp += 8, dp += 6)
                   {
                      png_uint_16 a;
@@ -2133,30 +2318,19 @@
                      }
                      else
                      {
-                        png_uint_32 r, g, b, v;
+                        png_uint_16 r, g, b, v;
 
-                        r = ((png_uint_32)(*sp) << 8) +
-                           (png_uint_32)(*(sp + 1));
-                        g = ((png_uint_32)(*(sp + 2)) << 8) +
-                           (png_uint_32)(*(sp + 3));
-                        b = ((png_uint_32)(*(sp + 4)) << 8) +
-                           (png_uint_32)(*(sp + 5));
-                        v = (r * (png_uint_32)a +
-                           (png_uint_32)background->red *
-                           (png_uint_32)((png_uint_32)65535L - a) +
-                           (png_uint_32)32767) / (png_uint_32)65535L;
+                        r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+                        g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+                        b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+
+                        png_composite_16(v, r, a, background->red);
                         *dp = (png_byte)((v >> 8) & 0xff);
                         *(dp + 1) = (png_byte)(v & 0xff);
-                        v = (g * (png_uint_32)a +
-                           (png_uint_32)background->green *
-                           (png_uint_32)((png_uint_32)65535L - a) +
-                           (png_uint_32)32767) / (png_uint_32)65535L;
+                        png_composite_16(v, g, a, background->green);
                         *(dp + 2) = (png_byte)((v >> 8) & 0xff);
                         *(dp + 3) = (png_byte)(v & 0xff);
-                        v = (b * (png_uint_32)a +
-                           (png_uint_32)background->blue *
-                           (png_uint_32)((png_uint_32)65535L - a) +
-                           (png_uint_32)32767) / (png_uint_32)65535L;
+                        png_composite_16(v, g, a, background->green);
                         *(dp + 4) = (png_byte)((v >> 8) & 0xff);
                         *(dp + 5) = (png_byte)(v & 0xff);
                      }
@@ -2173,7 +2347,7 @@
          row_info->channels--;
          row_info->pixel_depth = (png_byte)(row_info->channels *
             row_info->bit_depth);
-         row_info->rowbytes = ((row_info->width *
+         row_info->rowbytes = (png_size_t)((row_info->width *
             row_info->pixel_depth + 7) >> 3);
       }
    }
@@ -2181,12 +2355,11 @@
 #endif
 
 #if defined(PNG_READ_GAMMA_SUPPORTED)
-/* gamma correct the image, avoiding the alpha channel.  Make sure
+/* Gamma correct the image, avoiding the alpha channel.  Make sure
    you do this after you deal with the trasparency issue on grayscale
-   or rgb images. If your bit depth is 8, use gamma_table, if it is 16,
-   use gamma_16_table and gamma_shift.  Build these with
-   build_gamma_table().  If your bit depth <= 8, gamma correct a
-   palette, not the data.  */
+   or rgb images. If your bit depth is 8, use gamma_table, if it
+   is 16, use gamma_16_table and gamma_shift.  Build these with
+   build_gamma_table(). */
 void
 png_do_gamma(png_row_infop row_info, png_bytep row,
    png_bytep gamma_table, png_uint_16pp gamma_16_table,
@@ -2195,8 +2368,13 @@
    png_bytep sp;
    png_uint_32 i;
 
-   if (row && row_info && ((row_info->bit_depth <= 8 && gamma_table) ||
-      (row_info->bit_depth == 16 && gamma_16_table)))
+   png_debug(1, "in png_do_gamma\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
+       ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+        (row_info->bit_depth == 16 && gamma_16_table != NULL)))
    {
       switch (row_info->color_type)
       {
@@ -2204,8 +2382,7 @@
          {
             if (row_info->bit_depth == 8)
             {
-               for (i = 0, sp = row;
-                  i < row_info->width; i++)
+               for (i = 0, sp = row; i < row_info->width; i++)
                {
                   *sp = gamma_table[*sp];
                   sp++;
@@ -2215,25 +2392,21 @@
                   sp++;
                }
             }
-            else if (row_info->bit_depth == 16)
+            else /* if (row_info->bit_depth == 16) */
             {
-               for (i = 0, sp = row;
-                  i < row_info->width; i++)
+               for (i = 0, sp = row; i < row_info->width; i++)
                {
                   png_uint_16 v;
 
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
@@ -2257,25 +2430,22 @@
                   sp++;
                }
             }
-            else if (row_info->bit_depth == 16)
+            else /* if (row_info->bit_depth == 16) */
             {
                for (i = 0, sp = row;
                   i < row_info->width; i++)
                {
                   png_uint_16 v;
 
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 4;
@@ -2291,19 +2461,17 @@
                   i < row_info->width; i++)
                {
                   *sp = gamma_table[*sp];
-                  sp++;
-                  sp++;
+                  sp += 2;
                }
             }
-            else if (row_info->bit_depth == 16)
+            else /* if (row_info->bit_depth == 16) */
             {
                for (i = 0, sp = row;
                   i < row_info->width; i++)
                {
                   png_uint_16 v;
 
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 4;
@@ -2313,10 +2481,21 @@
          }
          case PNG_COLOR_TYPE_GRAY:
          {
-            if (row_info->bit_depth == 8)
+            if (row_info->bit_depth == 4)
             {
-               for (i = 0, sp = row;
-                  i < row_info->width; i++)
+               for (i = 0, sp = row; i < row_info->width; i += 2)
+               {
+                  int msb = *sp & 0xf0;
+                  int lsb = *sp & 0x0f;
+
+                  *sp = (((int)gamma_table[msb | msb >> 4] + 8) & 0xf0) |
+                        (((int)gamma_table[lsb << 4 | lsb] + 8) >> 4);
+                  sp++;
+               }
+            }
+            else if (row_info->bit_depth == 8)
+            {
+               for (i = 0, sp = row; i < row_info->width; i++)
                {
                   *sp = gamma_table[*sp];
                   sp++;
@@ -2324,13 +2503,11 @@
             }
             else if (row_info->bit_depth == 16)
             {
-               for (i = 0, sp = row;
-                  i < row_info->width; i++)
+               for (i = 0, sp = row; i < row_info->width; i++)
                {
                   png_uint_16 v;
 
-                  v = gamma_16_table[*(sp + 1) >>
-                     gamma_shift][*sp];
+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
                   *sp = (png_byte)((v >> 8) & 0xff);
                   *(sp + 1) = (png_byte)(v & 0xff);
                   sp += 2;
@@ -2348,14 +2525,18 @@
    upon whether you supply trans and num_trans */
 void
 png_do_expand_palette(png_row_infop row_info, png_bytep row,
-   png_colorp palette,
-   png_bytep trans, int num_trans)
+   png_colorp palette, png_bytep trans, int num_trans)
 {
    int shift, value;
    png_bytep sp, dp;
    png_uint_32 i;
 
-   if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+   png_debug(1, "in png_do_expand_palette\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
+       row_info->color_type == PNG_COLOR_TYPE_PALETTE)
    {
       if (row_info->bit_depth < 8)
       {
@@ -2429,20 +2610,20 @@
          }
          row_info->bit_depth = 8;
          row_info->pixel_depth = 8;
-         row_info->rowbytes = row_info->width;
+         row_info->rowbytes = (png_size_t)row_info->width;
       }
       switch (row_info->bit_depth)
       {
          case 8:
          {
-            if (trans)
+            if (trans != NULL)
             {
                sp = row + (png_size_t)row_info->width - 1;
                dp = row + (png_size_t)(row_info->width << 2) - 1;
 
                for (i = 0; i < row_info->width; i++)
                {
-                  if (*sp >= (png_byte)num_trans)
+                  if ((int)(*sp) >= num_trans)
                      *dp-- = 0xff;
                   else
                      *dp-- = trans[*sp];
@@ -2453,7 +2634,7 @@
                }
                row_info->bit_depth = 8;
                row_info->pixel_depth = 32;
-               row_info->rowbytes = row_info->width * 4;
+               row_info->rowbytes = (png_size_t)row_info->width * 4;
                row_info->color_type = 6;
                row_info->channels = 4;
             }
@@ -2471,7 +2652,7 @@
                }
                row_info->bit_depth = 8;
                row_info->pixel_depth = 24;
-               row_info->rowbytes = row_info->width * 3;
+               row_info->rowbytes = (png_size_t)row_info->width * 3;
                row_info->color_type = 2;
                row_info->channels = 3;
             }
@@ -2491,9 +2672,12 @@
    png_bytep sp, dp;
    png_uint_32 i;
 
-   if (row && row_info)
+   png_debug(1, "in png_do_expand\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL)
+#endif
    {
-      if (row_info->color_type == PNG_COLOR_TYPE_GRAY )
+      if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
       {
          png_uint_16 gray = trans_value ? trans_value->gray : 0;
 
@@ -2573,10 +2757,10 @@
             }
             row_info->bit_depth = 8;
             row_info->pixel_depth = 8;
-            row_info->rowbytes = row_info->width;
+            row_info->rowbytes = (png_size_t)row_info->width;
          }
 
-         if (trans_value)
+         if (trans_value != NULL)
          {
             if (row_info->bit_depth == 8)
             {
@@ -2593,8 +2777,8 @@
             }
             else if (row_info->bit_depth == 16)
             {
-               sp = row + (png_size_t)row_info->rowbytes - 1;
-               dp = row + (png_size_t)(row_info->rowbytes << 1) - 1;
+               sp = row + row_info->rowbytes - 1;
+               dp = row + (row_info->rowbytes << 1) - 1;
                for (i = 0; i < row_info->width; i++)
                {
                   if (((png_uint_16)*(sp) |
@@ -2616,7 +2800,7 @@
             row_info->channels = 2;
             row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
             row_info->rowbytes =
-               ((row_info->width * row_info->pixel_depth) >> 3);
+               (png_size_t)((row_info->width * row_info->pixel_depth) >> 3);
          }
       }
       else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
@@ -2640,7 +2824,7 @@
          }
          else if (row_info->bit_depth == 16)
          {
-            sp = row + (png_size_t)row_info->rowbytes - 1;
+            sp = row + row_info->rowbytes - 1;
             dp = row + (png_size_t)(row_info->width << 3) - 1;
             for (i = 0; i < row_info->width; i++)
             {
@@ -2671,7 +2855,7 @@
          row_info->channels = 4;
          row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
          row_info->rowbytes =
-            ((row_info->width * row_info->pixel_depth) >> 3);
+            (png_size_t)((row_info->width * row_info->pixel_depth) >> 3);
       }
    }
 }
@@ -2685,7 +2869,10 @@
    png_bytep sp, dp;
    png_uint_32 i;
 
-   if (row && row_info)
+   png_debug(1, "in png_do_dither\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL)
+#endif
    {
       if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
          palette_lookup && row_info->bit_depth == 8)
@@ -2724,7 +2911,7 @@
             ((row_info->width * row_info->pixel_depth + 7) >> 3);
       }
       else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
-         palette_lookup && row_info->bit_depth == 8)
+         palette_lookup != NULL && row_info->bit_depth == 8)
       {
          int r, g, b, p;
          sp = row;
@@ -2751,7 +2938,7 @@
          row_info->channels = 1;
          row_info->pixel_depth = row_info->bit_depth;
          row_info->rowbytes =
-            ((row_info->width * row_info->pixel_depth + 7) >> 3);
+            (png_size_t)((row_info->width * row_info->pixel_depth + 7) >> 3);
       }
       else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
          dither_lookup && row_info->bit_depth == 8)
@@ -2770,9 +2957,14 @@
 static int png_gamma_shift[] =
    {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
 
+/* We build the 8- or 16-bit gamma tables here.  Note that for 16-bit
+   tables, we don't make a full table if we are reducing to 8-bit in
+   the future.  Note also how the gamma_16 tables are segmented so that
+   we don't need to allocate > 64K chunks for a full 16-bit table. */
 void
 png_build_gamma_table(png_structp png_ptr)
 {
+   png_debug(1, "in png_build_gamma_table\n");
    if (png_ptr->bit_depth <= 8)
    {
       int i;
@@ -2789,6 +2981,7 @@
             g) * 255.0 + .5);
       }
 
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
       if (png_ptr->transformations & PNG_BACKGROUND)
       {
          g = 1.0 / (png_ptr->gamma);
@@ -2813,6 +3006,7 @@
                g) * 255.0 + .5);
          }
       }
+#endif /* PNG_BACKGROUND_SUPPORTED */
    }
    else
    {
@@ -2857,7 +3051,7 @@
       g = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
 
       png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
-         num * sizeof (png_uint_16p ));
+         num * sizeof (png_uint_16p));
 
       if ((png_ptr->transformations & PNG_16_TO_8) &&
          !(png_ptr->transformations & PNG_BACKGROUND))
@@ -2889,8 +3083,7 @@
          while (last < ((png_uint_32)num << 8))
          {
             png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
-               [(int)(last >> (8 - shift))] =
-               (png_uint_16)65535L;
+               [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
             last++;
          }
       }
@@ -2901,8 +3094,7 @@
             png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
                256 * sizeof (png_uint_16));
 
-            ig = (((png_uint_32)i *
-               (png_uint_32)png_gamma_shift[shift]) >> 4);
+            ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
             for (j = 0; j < 256; j++)
             {
                png_ptr->gamma_16_table[i][j] =
@@ -2912,6 +3104,7 @@
          }
       }
 
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
       if (png_ptr->transformations & PNG_BACKGROUND)
       {
          g = 1.0 / (png_ptr->gamma);
@@ -2953,6 +3146,7 @@
             }
          }
       }
+#endif /* PNG_BACKGROUND_SUPPORTED */
    }
 }
 #endif
diff --git a/pngrutil.c b/pngrutil.c
index 08ca9d7..f018526 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -1,16 +1,18 @@
 
-/* pngrutil.c - utilities to read a png file
+/* pngrutil.c - utilities to read a PNG file
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
 #include "png.h"
 
-/* grab an uint 32 from a buffer */
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big endian format. */
 png_uint_32
 png_get_uint_32(png_bytep buf)
 {
@@ -24,7 +26,25 @@
    return i;
 }
 
-/* grab an uint 16 from a buffer */
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* Grab a signed 32-bit integer from a buffer in big endian format.  The
+ * data is stored in the PNG file in two's complement format, and it is
+ * assumed that the machine format for signed integers is the same. */
+png_int_32
+png_get_int_32(png_bytep buf)
+{
+   png_int_32 i;
+
+   i = ((png_int_32)(*buf) << 24) +
+      ((png_int_32)(*(buf + 1)) << 16) +
+      ((png_int_32)(*(buf + 2)) << 8) +
+      (png_int_32)(*(buf + 3));
+
+   return i;
+}
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+/* Grab an unsigned 16-bit integer from a buffer in big endian format. */
 png_uint_16
 png_get_uint_16(png_bytep buf)
 {
@@ -35,11 +55,13 @@
 
    return i;
 }
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
 
 /* Set the action on getting a CRC error for an ancillary or critical chunk. */
 void
 png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
 {
+   png_debug(1, "in png_set_crc_action\n");
    /* Tell libpng how we react to CRC errors in critical chunks */
    switch (crit_action)
    {
@@ -90,66 +112,31 @@
 
 /* Read data, and (optionally) run it through the CRC. */
 void
-png_crc_read(png_structp png_ptr, png_bytep buf, png_uint_32 length)
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
 {
-   int need_crc = 1;
-
-   if (png_ptr->chunk_name[0] & 0x20)                    /* ancillary */
-   {
-      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
-          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
-         need_crc = 0;
-   }
-   else                                                   /* critical */
-   {
-      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
-         need_crc = 0;
-   }
-
    png_read_data(png_ptr, buf, length);
-
-   if (need_crc)
-      png_calculate_crc(png_ptr, buf, length);
+   png_calculate_crc(png_ptr, buf, length);
 }
 
 /* Optionally skip data and then check the CRC.  Depending on whether we
    are reading a ancillary or critical chunk, and how the program has set
-   things up, we may calculate the CRC on the data and print a message. */
+   things up, we may calculate the CRC on the data and print a message.
+   Returns '1' if there was a CRC error, '0' otherwise. */
 int
 png_crc_finish(png_structp png_ptr, png_uint_32 skip)
 {
-   int need_crc = 1;
-   int crc_error;
    png_uint_32 i;
 
-   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   for (i = skip; i > (png_uint_32)png_ptr->zbuf_size; i -= png_ptr->zbuf_size)
    {
-      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
-          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
-         need_crc = 0;
-   }
-   else                                                    /* critical */
-   {
-      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
-         need_crc = 0;
-   }
-
-   for (i = skip; i > png_ptr->zbuf_size; i -= png_ptr->zbuf_size)
-   {
-      png_read_data(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
-      if (need_crc)
-         png_calculate_crc(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+      png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
    }
    if (i)
    {
-      png_read_data(png_ptr, png_ptr->zbuf, i);
-      if (need_crc)
-         png_calculate_crc(png_ptr, png_ptr->zbuf, i);
+      png_crc_read(png_ptr, png_ptr->zbuf, (png_size_t)i);
    }
 
-   crc_error = png_crc_error(png_ptr);
-
-   if (need_crc && crc_error)
+   if (png_crc_error(png_ptr))
    {
       char msg[80];
 
@@ -179,16 +166,33 @@
 {
    png_byte crc_bytes[4];
    png_uint_32 crc;
+   int need_crc = 1;
+
+   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+         need_crc = 0;
+   }
+   else                                                    /* critical */
+   {
+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+         need_crc = 0;
+   }
 
    png_read_data(png_ptr, crc_bytes, 4);
 
-   crc = png_get_uint_32(crc_bytes);
-
+   if (need_crc)
+   {
+      crc = png_get_uint_32(crc_bytes);
 #ifdef PNG_USE_OWN_CRC
-   return (((crc^0xffffffffL) & 0xffffffffL) != (png_ptr->crc & 0xffffffffL));
+      return (((crc^0xffffffffL)&0xffffffffL) != (png_ptr->crc&0xffffffffL));
 #else
-   return (crc != png_ptr->crc);
+      return (crc != png_ptr->crc);
 #endif
+   }
+   else
+      return 0;
 }
 
 
@@ -201,6 +205,8 @@
    int bit_depth, color_type, compression_type, filter_type;
    int interlace_type;
 
+   png_debug(1, "in png_handle_IHDR\n");
+
    if (png_ptr->mode != PNG_BEFORE_IHDR)
       png_error(png_ptr, "Out of place IHDR");
 
@@ -226,9 +232,8 @@
       png_error(png_ptr, "Invalid image size in IHDR");
 
    /* check other values */
-   if (bit_depth != 1 && bit_depth != 2 &&
-      bit_depth != 4 && bit_depth != 8 &&
-      bit_depth != 16)
+   if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+      bit_depth != 8 && bit_depth != 16)
       png_error(png_ptr, "Invalid bit depth in IHDR");
 
    if (color_type < 0 || color_type == 1 ||
@@ -241,13 +246,13 @@
          color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
       png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
 
-   if (interlace_type > 1)
+   if (interlace_type > PNG_INTERLACE_ADAM7)
       png_error(png_ptr, "Unknown interlace method in IHDR");
 
-   if (compression_type > 0)
+   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
       png_error(png_ptr, "Unknown compression method in IHDR");
 
-   if (filter_type > 0)
+   if (filter_type != PNG_FILTER_TYPE_BASE)
       png_error(png_ptr, "Unknown filter method in IHDR");
 
    /* set internal variables */
@@ -260,17 +265,17 @@
    /* find number of channels */
    switch (png_ptr->color_type)
    {
-      case 0:
-      case 3:
+      case PNG_COLOR_TYPE_GRAY:
+      case PNG_COLOR_TYPE_PALETTE:
          png_ptr->channels = 1;
          break;
-      case 2:
+      case PNG_COLOR_TYPE_RGB:
          png_ptr->channels = 3;
          break;
-      case 4:
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
          png_ptr->channels = 2;
          break;
-      case 6:
+      case PNG_COLOR_TYPE_RGB_ALPHA:
          png_ptr->channels = 4;
          break;
    }
@@ -280,8 +285,11 @@
       png_ptr->channels);
    png_ptr->rowbytes = ((png_ptr->width *
       (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
-   png_read_IHDR(png_ptr, info_ptr, width, height, bit_depth,
-      color_type, compression_type, filter_type, interlace_type);
+   png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
+   png_debug1(3,"channels = %d\n", png_ptr->channels);
+   png_debug1(3,"rowbytes = %d\n", png_ptr->rowbytes);
+   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
+      color_type, interlace_type, compression_type, filter_type);
 }
 
 /* read and check the palette */
@@ -291,6 +299,8 @@
    png_colorp palette;
    int num, i;
 
+   png_debug(1, "in png_handle_PLTE\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before PLTE");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -346,8 +356,7 @@
       we will act as though it is. */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
-      if (png_crc_finish(png_ptr, 0))
-         return;
+      png_crc_finish(png_ptr, 0);
    }
    else if (png_crc_error(png_ptr))  /* Only if we have a CRC error */
    {
@@ -368,9 +377,12 @@
          else
          {
             png_warning(png_ptr, msg);
+            png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
+            png_free(png_ptr, palette);
             return;
          }
       }
+      /* Otherwise, we (optionally) emit a warning and use the chunk. */
       else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
       {
          png_warning(png_ptr, msg);
@@ -379,12 +391,14 @@
 
    png_ptr->palette = palette;
    png_ptr->num_palette = (png_uint_16)num;
-   png_read_PLTE(png_ptr, info_ptr, palette, num);
+   png_set_PLTE(png_ptr, info_ptr, palette, num);
 }
 
 void
 png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
+   png_debug(1, "in png_handle_IEND\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
    {
       png_error(png_ptr, "No image in file");
@@ -395,8 +409,8 @@
    if (length != 0)
    {
       png_warning(png_ptr, "Incorrect IEND chunk length");
-      png_crc_finish(png_ptr, length);
    }
+   png_crc_finish(png_ptr, length);
 }
 
 #if defined(PNG_READ_gAMA_SUPPORTED)
@@ -404,9 +418,11 @@
 png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
    png_uint_32 igamma;
-   float gamma;
+   float file_gamma;
    png_byte buf[4];
 
+   png_debug(1, "in png_handle_gAMA\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before gAMA");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -418,7 +434,7 @@
    else if (png_ptr->mode & PNG_HAVE_PLTE)
       /* Should be an error, but we can cope with it */
       png_warning(png_ptr, "Out of place gAMA chunk");
-   else if (info_ptr && info_ptr->valid & PNG_INFO_gAMA)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA)
    {
       png_warning(png_ptr, "Duplicate gAMA chunk");
       png_crc_finish(png_ptr, length);
@@ -438,12 +454,12 @@
 
    igamma = png_get_uint_32(buf);
    /* check for zero gamma */
-   if (!igamma)
+   if (igamma == 0)
       return;
 
-   gamma = (float)igamma / (float)100000.0;
-   png_ptr->gamma = gamma;
-   png_read_gAMA(png_ptr, info_ptr, gamma);
+   file_gamma = (float)igamma / (float)100000.0;
+   png_ptr->gamma = file_gamma;
+   png_set_gAMA(png_ptr, info_ptr, file_gamma);
 }
 #endif
 
@@ -451,9 +467,11 @@
 void
 png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
-   png_uint_32 truelen;
+   png_size_t truelen;
    png_byte buf[4];
 
+   png_debug(1, "in png_handle_sBIT\n");
+
    buf[0] = buf[1] = buf[2] = buf[3] = 0;
 
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
@@ -467,7 +485,7 @@
    else if (png_ptr->mode & PNG_HAVE_PLTE)
       /* Should be an error, but we can cope with it */
       png_warning(png_ptr, "Out of place sBIT chunk");
-   else if (info_ptr && info_ptr->valid & PNG_INFO_sBIT)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT)
    {
       png_warning(png_ptr, "Duplicate sBIT chunk");
       png_crc_finish(png_ptr, length);
@@ -477,7 +495,7 @@
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       truelen = 3;
    else
-      truelen = png_ptr->channels;
+      truelen = (png_size_t)png_ptr->channels;
 
    if (length != truelen)
    {
@@ -486,7 +504,7 @@
       return;
    }
 
-   png_crc_read(png_ptr, buf, length);
+   png_crc_read(png_ptr, buf, truelen);
    if (png_crc_finish(png_ptr, 0))
       return;
 
@@ -502,7 +520,7 @@
       png_ptr->sig_bit.gray = buf[0];
       png_ptr->sig_bit.alpha = buf[1];
    }
-   png_read_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+   png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
 }
 #endif
 
@@ -514,6 +532,8 @@
    png_uint_32 val;
    float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
 
+   png_debug(1, "in png_handle_cHRM\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before sBIT");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -525,7 +545,7 @@
    else if (png_ptr->mode & PNG_HAVE_PLTE)
       /* Should be an error, but we can cope with it */
       png_warning(png_ptr, "Missing PLTE before cHRM");
-   else if (info_ptr && info_ptr->valid & PNG_INFO_cHRM)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM)
    {
       png_warning(png_ptr, "Duplicate cHRM chunk");
       png_crc_finish(png_ptr, length);
@@ -606,7 +626,7 @@
    if (png_crc_finish(png_ptr, 0))
       return;
 
-   png_read_cHRM(png_ptr, info_ptr,
+   png_set_cHRM(png_ptr, info_ptr,
       white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
 }
 #endif
@@ -615,6 +635,8 @@
 void
 png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
+   png_debug(1, "in png_handle_tRNS\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before tRNS");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -623,7 +645,7 @@
       png_crc_finish(png_ptr, length);
       return;
    }
-   else if (info_ptr && info_ptr->valid & PNG_INFO_tRNS)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
    {
       png_warning(png_ptr, "Duplcate tRNS chunk");
       png_crc_finish(png_ptr, length);
@@ -646,7 +668,7 @@
 
       png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
       png_ptr->flags |= PNG_FLAG_FREE_TRANS;
-      png_crc_read(png_ptr, png_ptr->trans, length);
+      png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
       png_ptr->num_trans = (png_uint_16)length;
    }
    else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
@@ -660,7 +682,7 @@
          return;
       }
 
-      png_crc_read(png_ptr, buf, length);
+      png_crc_read(png_ptr, buf, (png_size_t)length);
       png_ptr->num_trans = 3;
       png_ptr->trans_values.red = png_get_uint_16(buf);
       png_ptr->trans_values.green = png_get_uint_16(buf + 2);
@@ -691,7 +713,7 @@
    if (png_crc_finish(png_ptr, 0))
       return;
 
-   png_read_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
+   png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
       &(png_ptr->trans_values));
 }
 #endif
@@ -700,9 +722,11 @@
 void
 png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
-   png_uint_32 truelen;
+   png_size_t truelen;
    png_byte buf[6];
 
+   png_debug(1, "in png_handle_bKGD\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before bKGD");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -718,7 +742,7 @@
       png_crc_finish(png_ptr, length);
       return;
    }
-   else if (info_ptr && info_ptr->valid & PNG_INFO_bKGD)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD)
    {
       png_warning(png_ptr, "Duplicate bKGD chunk");
       png_crc_finish(png_ptr, length);
@@ -739,7 +763,7 @@
       return;
    }
 
-   png_crc_read(png_ptr, buf, length);
+   png_crc_read(png_ptr, buf, truelen);
    if (png_crc_finish(png_ptr, 0))
       return;
 
@@ -754,7 +778,7 @@
       png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
       png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
    }
-   else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
+   else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
    {
       png_ptr->background.red =
       png_ptr->background.green =
@@ -768,7 +792,7 @@
       png_ptr->background.blue = png_get_uint_16(buf + 4);
    }
 
-   png_read_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+   png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
 }
 #endif
 
@@ -778,6 +802,8 @@
 {
    int num, i;
 
+   png_debug(1, "in png_handle_hIST\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before hIST");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -792,14 +818,14 @@
       png_crc_finish(png_ptr, length);
       return;
    }
-   else if (info_ptr && info_ptr->valid & PNG_INFO_hIST)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST)
    {
       png_warning(png_ptr, "Duplicate hIST chunk");
       png_crc_finish(png_ptr, length);
       return;
    }
 
-   if (length != 2 * png_ptr->num_palette)
+   if (length != (png_uint_32)(2 * png_ptr->num_palette))
    {
       png_warning(png_ptr, "Incorrect hIST chunk length");
       png_crc_finish(png_ptr, length);
@@ -821,7 +847,7 @@
    if (png_crc_finish(png_ptr, 0))
       return;
 
-   png_read_hIST(png_ptr, info_ptr, png_ptr->hist);
+   png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
 }
 #endif
 
@@ -833,6 +859,8 @@
    png_uint_32 res_x, res_y;
    int unit_type;
 
+   png_debug(1, "in png_handle_pHYs\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before pHYS");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -841,7 +869,7 @@
       png_crc_finish(png_ptr, length);
       return;
    }
-   else if (info_ptr && info_ptr->valid & PNG_INFO_pHYs)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
    {
       png_warning(png_ptr, "Duplicate pHYS chunk");
       png_crc_finish(png_ptr, length);
@@ -862,7 +890,7 @@
    res_x = png_get_uint_32(buf);
    res_y = png_get_uint_32(buf + 4);
    unit_type = buf[8];
-   png_read_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+   png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
 }
 #endif
 
@@ -874,6 +902,8 @@
    png_uint_32 offset_x, offset_y;
    int unit_type;
 
+   png_debug(1, "in png_handle_oFFs\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before oFFs");
    else if (png_ptr->mode & PNG_HAVE_IDAT)
@@ -882,7 +912,7 @@
       png_crc_finish(png_ptr, length);
       return;
    }
-   else if (info_ptr && info_ptr->valid & PNG_INFO_oFFs)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs)
    {
       png_warning(png_ptr, "Duplicate oFFs chunk");
       png_crc_finish(png_ptr, length);
@@ -903,7 +933,121 @@
    offset_x = png_get_uint_32(buf);
    offset_y = png_get_uint_32(buf + 4);
    unit_type = buf[8];
-   png_read_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+   png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* read the pCAL chunk (png-scivis-19970203) */
+void
+png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+   png_charp purpose;
+   png_int_32 X0, X1;
+   png_byte type, nparams;
+   png_charp buf, units, endptr;
+   png_charpp params;
+   int i;
+
+   png_debug(1, "in png_handle_pCAL\n");
+
+   if (!(png_ptr->mode & PNG_HAVE_IHDR))
+      png_error(png_ptr, "Missing IHDR before pCAL");
+   else if (png_ptr->mode & PNG_HAVE_IDAT)
+   {
+      png_warning(png_ptr, "Invalid pCAL after IDAT");
+      png_crc_finish(png_ptr, length);
+      return;
+   }
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL)
+   {
+      png_warning(png_ptr, "Duplicate pCAL chunk");
+      png_crc_finish(png_ptr, length);
+      return;
+   }
+
+   png_debug1(2, "Allocating and reading pCAL chunk data (%d bytes)\n",
+      length + 1);
+   purpose = (png_charp)png_malloc(png_ptr, length + 1);
+   png_crc_read(png_ptr, (png_bytep)purpose, (png_size_t)length);
+
+   if (png_crc_finish(png_ptr, 0))
+   {
+      png_free(png_ptr, purpose);
+      return;
+   }
+
+   purpose[length] = '\0'; /* null terminate the last string */
+
+   png_debug(3, "Finding end of pCAL purpose string\n");
+   for (buf = purpose; *buf != '\0'; buf++)
+      /* empty loop */;
+
+   endptr = purpose + length;
+
+   /* We need to have at least 12 bytes after the purpose string
+      in order to get the parameter information. */
+   if (endptr <= buf + 12)
+   {
+      png_warning(png_ptr, "Invalid pCAL data");
+      png_free(png_ptr, purpose);
+      return;
+   }
+
+   png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+   X0 = png_get_int_32((png_bytep)buf+1);
+   X1 = png_get_int_32((png_bytep)buf+5);
+   type = buf[9];
+   nparams = buf[10];
+   units = buf + 11;
+
+   png_debug(3, "Checking pCAL equation type and number of parameters\n");
+   /* Check that we have the right number of parameters for known
+      equation types. */
+   if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
+       (type == PNG_EQUATION_BASE_E && nparams != 3) ||
+       (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
+       (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
+   {
+      png_warning(png_ptr, "Invalid pCAL parameters for equation type");
+      png_free(png_ptr, purpose);
+      return;
+   }
+   else if (type >= PNG_EQUATION_LAST)
+   {
+      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+   }
+
+   /* Empty loop to move past the units string. */
+   for (buf = units; *buf != '\0'; buf++);
+
+   png_debug(3, "Allocating pCAL parameters array\n");
+   params = (png_charpp)png_malloc(png_ptr, nparams*sizeof(png_charp)) ;
+
+   /* Get pointers to the start of each parameter string. */
+   for (i = 0; i < nparams; i++)
+   {
+      buf++; /* Skip the null string terminator from previous parameter. */
+
+      png_debug1(3, "Reading pCAL parameter %d\n", i);
+      /* Empty loop to move past each paramter string */
+      for (params[i] = buf; *buf != '\0' && buf <= endptr; buf++);
+
+      /* Make sure we haven't run out of data yet */
+      if (buf > endptr)
+      {
+         png_warning(png_ptr, "Invalid pCAL data");
+         png_free(png_ptr, purpose);
+         png_free(png_ptr, params);
+         return;
+      }
+   }
+
+   png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
+      units, params);
+
+   png_free(png_ptr, purpose);
+   png_free(png_ptr, params);
 }
 #endif
 
@@ -914,9 +1058,11 @@
    png_byte buf[7];
    png_time mod_time;
 
+   png_debug(1, "in png_handle_tIME\n");
+
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Out of place tIME chunk");
-   else if (info_ptr && info_ptr->valid & PNG_INFO_tIME)
+   else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME)
    {
       png_warning(png_ptr, "Duplicate tIME chunk");
       png_crc_finish(png_ptr, length);
@@ -944,17 +1090,21 @@
    mod_time.month = buf[2];
    mod_time.year = png_get_uint_16(buf);
 
-   png_read_tIME(png_ptr, info_ptr, &mod_time);
+   png_set_tIME(png_ptr, info_ptr, &mod_time);
 }
 #endif
 
 #if defined(PNG_READ_tEXt_SUPPORTED)
-/* note: this does not correctly handle chunks that are > 64K */
+/* Note: this does not properly handle chunks that are > 64K under DOS */
 void
 png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
+   png_textp text_ptr;
    png_charp key;
    png_charp text;
+   png_uint_32 skip = 0;
+
+   png_debug(1, "in png_handle_tEXt\n");
 
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before tEXt");
@@ -962,36 +1112,55 @@
    if (png_ptr->mode & PNG_HAVE_IDAT)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
-   key = (png_charp )png_malloc(png_ptr, length + 1);
-   png_crc_read(png_ptr, (png_bytep )key, length);
-   if (png_crc_finish(png_ptr, 0))
+#ifdef PNG_MAX_MALLOC_64K
+   if (length > 65535L)
+   {
+      png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+      skip = length - 65535L;
+      length = 65535L;
+   }
+#endif
+
+   key = (png_charp)png_malloc(png_ptr, length + 1);
+   png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
+
+   if (png_crc_finish(png_ptr, skip))
    {
       png_free(png_ptr, key);
       return;
    }
 
-   key[(png_size_t)length] = '\0';
+   key[length] = '\0';
 
    for (text = key; *text; text++)
-      /* empty loop to check key length */ ;
+      /* empty loop to find end of key */ ;
 
    if (text != key + (png_size_t)length)
       text++;
 
-   png_read_tEXt(png_ptr, info_ptr, key, text, length - (text - key));
+   text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+   text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+   text_ptr->key = key;
+   text_ptr->text = text;
+
+   png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+   png_free(png_ptr, text_ptr);
 }
 #endif
 
 #if defined(PNG_READ_zTXt_SUPPORTED)
-/* note: this does not correctly handle chunks that are > 64K compressed
-   on those systems that can't malloc more than 64KB at a time. */
+/* note: this does not correctly handle chunks that are > 64K under DOS */
 void
 png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
    static char msg[] = "Error decoding zTXt chunk";
+   png_textp text_ptr;
    png_charp key;
    png_charp text;
-   png_uint_32 text_size, key_size;
+   int comp_type = PNG_TEXT_COMPRESSION_NONE;
+
+   png_debug(1, "in png_handle_zTXt\n");
 
    if (!(png_ptr->mode & PNG_HAVE_IHDR))
       png_error(png_ptr, "Missing IHDR before zTXt");
@@ -999,42 +1168,44 @@
    if (png_ptr->mode & PNG_HAVE_IDAT)
       png_ptr->mode |= PNG_AFTER_IDAT;
 
-   key = png_malloc(png_ptr, length + 1);
-   png_crc_read(png_ptr, (png_bytep )key, length);
+#ifdef PNG_MAX_MALLOC_64K
+   /* We will no doubt have problems with chunks even half this size, but
+      there is no hard and fast rule to tell us where to stop. */
+   if (length > 65535L)
+   {
+     png_warning(png_ptr,"zTXt chunk too large to fit in memory");
+     png_crc_finish(png_ptr, length);
+     return;
+   }
+#endif
+
+   key = (png_charp)png_malloc(png_ptr, length + 1);
+   png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
    if (png_crc_finish(png_ptr, 0))
    {
       png_free(png_ptr, key);
       return;
    }
 
-   key[(png_size_t)length] = '\0';
+   key[length] = '\0';
 
    for (text = key; *text; text++)
       /* empty loop */ ;
 
-   /* zTXt can't have zero text */
+   /* zTXt must have some text after the keyword */
    if (text == key + (png_size_t)length)
    {
       png_warning(png_ptr, "Zero length zTXt chunk");
-      text_size = 0;
    }
-   else if (*(++text)) /* check compression type byte */
+   else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt)
    {
-      png_warning(png_ptr, "Unknown zTXt compression type");
-
-      /* Copy what we can of the error message into the text chunk */
-      text_size = length - (text - key) - 1;
-      text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
-      png_memcpy(text, msg, (png_size_t)(text_size + 1));
-   }
-   else
-   {
+      png_size_t text_size, key_size;
       text++;
 
-      png_ptr->zstream.next_in = (png_bytep )text;
+      png_ptr->zstream.next_in = (png_bytep)text;
       png_ptr->zstream.avail_in = (uInt)(length - (text - key));
       png_ptr->zstream.next_out = png_ptr->zbuf;
-      png_ptr->zstream.avail_out = (png_size_t)png_ptr->zbuf_size;
+      png_ptr->zstream.avail_out = png_ptr->zbuf_size;
 
       key_size = text - key;
       text_size = 0;
@@ -1047,18 +1218,18 @@
          ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
          if (ret != Z_OK && ret != Z_STREAM_END)
          {
-            if (png_ptr->zstream.msg)
+            if (png_ptr->zstream.msg != NULL)
                png_warning(png_ptr, png_ptr->zstream.msg);
             else
-               png_warning(png_ptr, "zTXt decompression error");
+               png_warning(png_ptr, msg);
             inflateReset(&png_ptr->zstream);
             png_ptr->zstream.avail_in = 0;
 
-            if (!text)
+            if (text ==  NULL)
             {
                text_size = key_size + sizeof(msg) + 1;
                text = (png_charp)png_malloc(png_ptr, text_size);
-               png_memcpy(text, key, (png_size_t)key_size);
+               png_memcpy(text, key, key_size);
             }
 
             text[text_size - 1] = '\0';
@@ -1066,22 +1237,22 @@
             /* Copy what we can of the error message into the text chunk */
             text_size = length - (text - key) - 1;
             text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
-            png_memcpy(text + key_size, msg, (png_size_t)(text_size + 1));
+            png_memcpy(text + key_size, msg, text_size + 1);
             break;
          }
          if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
          {
-            if (!text)
+            if (text == NULL)
             {
                text = (png_charp)png_malloc(png_ptr,
                   png_ptr->zbuf_size - png_ptr->zstream.avail_out +
                      key_size + 1);
-               png_memcpy(text + (png_size_t)key_size, png_ptr->zbuf,
-                  (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
-               png_memcpy(text, key, (png_size_t)key_size);
-               text_size = key_size + (png_size_t)png_ptr->zbuf_size -
+               png_memcpy(text + key_size, png_ptr->zbuf,
+                  png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+               png_memcpy(text, key, key_size);
+               text_size = key_size + png_ptr->zbuf_size -
                   png_ptr->zstream.avail_out;
-               *(text + (png_size_t)text_size) = '\0';
+               *(text + text_size) = '\0';
             }
             else
             {
@@ -1090,12 +1261,12 @@
                tmp = text;
                text = png_malloc(png_ptr, text_size +
                   png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1);
-               png_memcpy(text, tmp, (png_size_t)text_size);
+               png_memcpy(text, tmp, text_size);
                png_free(png_ptr, tmp);
-               png_memcpy(text + (png_size_t)text_size, png_ptr->zbuf,
-                  (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+               png_memcpy(text + text_size, png_ptr->zbuf,
+                  (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
                text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
-               *(text + (png_size_t)text_size) = '\0';
+               *(text + text_size) = '\0';
             }
             if (ret != Z_STREAM_END)
             {
@@ -1114,20 +1285,42 @@
 
       png_free(png_ptr, key);
       key = text;
-      text += (png_size_t)key_size;
+      text += key_size;
       text_size -= key_size;
    }
+   else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */
+   {
+      png_size_t text_size;
+      char umsg[50];
 
-   png_read_zTXt(png_ptr, info_ptr, key, text, text_size, 0);
+      sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
+      png_warning(png_ptr, umsg);
+
+      /* Copy what we can of the error message into the text chunk */
+      text_size = (png_size_t)length - (text - key) - 1;
+      text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+      png_memcpy(text, msg, text_size + 1);
+   }
+
+   text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
+   text_ptr->compression = comp_type;
+   text_ptr->key = key;
+   text_ptr->text = text;
+
+   png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+   png_free(png_ptr, text_ptr);
 }
 #endif
 
 /* This function is called when we haven't found a handler for a
    chunk.  If there isn't a problem with the chunk itself (ie bad
-   chunk name or a critical chunk), the chunk is silently ignored. */
+   chunk name, CRC, or a critical chunk), the chunk is silently ignored. */
 void
 png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
+   png_debug(1, "in png_handle_unknown\n");
+
    /* In the future we can have code here that calls user-supplied
     * callback functions for unknown chunks before they are ignored or
     * cause an error.
@@ -1150,20 +1343,18 @@
 
 /* This function is called to verify that a chunk name is valid.
    This function can't have the "critical chunk check" incorporated
-   into it, as in the future, we will need to be able to call user
+   into it, since in the future we will need to be able to call user
    functions to handle unknown critical chunks after we check that
    the chunk name itself is valid. */
+
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+
 void
 png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
 {
-   if (chunk_name[0] < 41 || chunk_name[0] > 122  ||
-       (chunk_name[0] > 90 && chunk_name[0] < 97) ||
-       chunk_name[1] < 41 || chunk_name[1] > 122  ||
-       (chunk_name[1] > 90 && chunk_name[1] < 97) ||
-       chunk_name[2] < 41 || chunk_name[2] > 122  ||
-       (chunk_name[2] > 90 && chunk_name[2] < 97) ||
-       chunk_name[3] < 41 || chunk_name[3] > 122  ||
-       (chunk_name[3] > 90 && chunk_name[3] < 97))
+   png_debug(1, "in png_check_chunk_name\n");
+   if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
+       isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
    {
       char msg[45];
 
@@ -1187,6 +1378,7 @@
 png_combine_row(png_structp png_ptr, png_bytep row,
    int mask)
 {
+   png_debug(1,"in png_combine_row\n");
    if (mask == 0xff)
    {
       png_memcpy(row, png_ptr->row_buf + 1,
@@ -1201,32 +1393,50 @@
          {
             png_bytep sp;
             png_bytep dp;
+            int s_inc, s_start, s_end;
             int m;
             int shift;
             png_uint_32 i;
-            int value;
 
             sp = png_ptr->row_buf + 1;
             dp = row;
-            shift = 7;
             m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (png_ptr->transformations & PNG_PACKSWAP)
+            {
+                s_start = 0;
+                s_end = 7;
+                s_inc = 1;
+            }
+            else
+#endif
+            {
+                s_start = 7;
+                s_end = 0;
+                s_inc = -1;
+            }
+
+            shift = s_start;
+
             for (i = 0; i < png_ptr->width; i++)
             {
                if (m & mask)
                {
+                  int value;
+
                   value = (*sp >> shift) & 0x1;
                   *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
                   *dp |= (png_byte)(value << shift);
                }
 
-               if (shift == 0)
+               if (shift == s_end)
                {
-                  shift = 7;
+                  shift = s_start;
                   sp++;
                   dp++;
                }
                else
-                  shift--;
+                  shift += s_inc;
 
                if (m == 1)
                   m = 0x80;
@@ -1239,6 +1449,7 @@
          {
             png_bytep sp;
             png_bytep dp;
+            int s_start, s_end, s_inc;
             int m;
             int shift;
             png_uint_32 i;
@@ -1246,8 +1457,24 @@
 
             sp = png_ptr->row_buf + 1;
             dp = row;
-            shift = 6;
             m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (png_ptr->transformations & PNG_PACKSWAP)
+            {
+               s_start = 0;
+               s_end = 6;
+               s_inc = 2;
+            }
+            else
+#endif
+            {
+               s_start = 6;
+               s_end = 0;
+               s_inc = -2;
+            }
+
+            shift = s_start;
+
             for (i = 0; i < png_ptr->width; i++)
             {
                if (m & mask)
@@ -1257,14 +1484,14 @@
                   *dp |= (png_byte)(value << shift);
                }
 
-               if (shift == 0)
+               if (shift == s_end)
                {
-                  shift = 6;
+                  shift = s_start;
                   sp++;
                   dp++;
                }
                else
-                  shift -= 2;
+                  shift += s_inc;
                if (m == 1)
                   m = 0x80;
                else
@@ -1276,6 +1503,7 @@
          {
             png_bytep sp;
             png_bytep dp;
+            int s_start, s_end, s_inc;
             int m;
             int shift;
             png_uint_32 i;
@@ -1283,8 +1511,23 @@
 
             sp = png_ptr->row_buf + 1;
             dp = row;
-            shift = 4;
             m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (png_ptr->transformations & PNG_PACKSWAP)
+            {
+               s_start = 0;
+               s_end = 4;
+               s_inc = 4;
+            }
+            else
+#endif
+            {
+               s_start = 4;
+               s_end = 0;
+               s_inc = -4;
+            }
+            shift = s_start;
+
             for (i = 0; i < png_ptr->width; i++)
             {
                if (m & mask)
@@ -1294,14 +1537,14 @@
                   *dp |= (png_byte)(value << shift);
                }
 
-               if (shift == 0)
+               if (shift == s_end)
                {
-                  shift = 4;
+                  shift = s_start;
                   sp++;
                   dp++;
                }
                else
-                  shift -= 4;
+                  shift += s_inc;
                if (m == 1)
                   m = 0x80;
                else
@@ -1313,7 +1556,8 @@
          {
             png_bytep sp;
             png_bytep dp;
-            png_uint_32 i, pixel_bytes;
+            png_size_t pixel_bytes;
+            png_uint_32 i;
             png_byte m;
 
             pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
@@ -1344,9 +1588,11 @@
 
 #if defined(PNG_READ_INTERLACING_SUPPORTED)
 void
-png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass)
+png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+   png_uint_32 transformations)
 {
-   if (row && row_info)
+   png_debug(1,"in png_do_read_interlace\n");
+   if (row != NULL && row_info != NULL)
    {
       png_uint_32 final_width;
 
@@ -1358,14 +1604,32 @@
          {
             png_bytep sp, dp;
             int sshift, dshift;
+            int s_start, s_end, s_inc;
             png_byte v;
             png_uint_32 i;
             int j;
 
             sp = row + (png_size_t)((row_info->width - 1) >> 3);
-            sshift = 7 - (int)((row_info->width + 7) & 7);
             dp = row + (png_size_t)((final_width - 1) >> 3);
-            dshift = 7 - (int)((final_width + 7) & 7);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (transformations & PNG_PACKSWAP)
+            {
+                sshift = (int)((row_info->width + 7) & 7);
+                dshift = (int)((final_width + 7) & 7);
+                s_start = 7;
+                s_end = 0;
+                s_inc = -1;
+            }
+            else
+#endif
+            {
+                sshift = 7 - (int)((row_info->width + 7) & 7);
+                dshift = 7 - (int)((final_width + 7) & 7);
+                s_start = 0;
+                s_end = 7;
+                s_inc = 1;
+            }
+
             for (i = row_info->width; i; i--)
             {
                v = (png_byte)((*sp >> sshift) & 0x1);
@@ -1373,21 +1637,21 @@
                {
                   *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
                   *dp |= (png_byte)(v << dshift);
-                  if (dshift == 7)
+                  if (dshift == s_end)
                   {
-                     dshift = 0;
+                     dshift = s_start;
                      dp--;
                   }
                   else
-                     dshift++;
+                     dshift += s_inc;
                }
-               if (sshift == 7)
+               if (sshift == s_end)
                {
-                  sshift = 0;
+                  sshift = s_start;
                   sp--;
                }
                else
-                  sshift++;
+                  sshift += s_inc;
             }
             break;
          }
@@ -1395,35 +1659,55 @@
          {
             png_bytep sp, dp;
             int sshift, dshift;
-            png_byte v;
-            png_uint_32 i, j;
+            int s_start, s_end, s_inc;
+            png_uint_32 i;
 
             sp = row + (png_size_t)((row_info->width - 1) >> 2);
-            sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
             dp = row + (png_size_t)((final_width - 1) >> 2);
-            dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (transformations & PNG_PACKSWAP)
+            {
+               sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+               dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+               s_start = 6;
+               s_end = 0;
+               s_inc = -2;
+            }
+            else
+#endif
+            {
+               sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+               dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+               s_start = 0;
+               s_end = 6;
+               s_inc = 2;
+            }
+
             for (i = row_info->width; i; i--)
             {
+               png_byte v;
+               int j;
+
                v = (png_byte)((*sp >> sshift) & 0x3);
                for (j = 0; j < png_pass_inc[pass]; j++)
                {
                   *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
                   *dp |= (png_byte)(v << dshift);
-                  if (dshift == 6)
+                  if (dshift == s_end)
                   {
-                     dshift = 0;
+                     dshift = s_start;
                      dp--;
                   }
                   else
-                     dshift += 2;
+                     dshift += s_inc;
                }
-               if (sshift == 6)
+               if (sshift == s_end)
                {
-                  sshift = 0;
+                  sshift = s_start;
                   sp--;
                }
                else
-                  sshift += 2;
+                  sshift += s_inc;
             }
             break;
          }
@@ -1431,52 +1715,73 @@
          {
             png_bytep sp, dp;
             int sshift, dshift;
-            png_byte v;
+            int s_start, s_end, s_inc;
             png_uint_32 i;
-            int j;
 
             sp = row + (png_size_t)((row_info->width - 1) >> 1);
-            sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
             dp = row + (png_size_t)((final_width - 1) >> 1);
-            dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+            if (transformations & PNG_PACKSWAP)
+            {
+               sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+               dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+               s_start = 4;
+               s_end = 0;
+               s_inc = -4;
+            }
+            else
+#endif
+            {
+               sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+               dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+               s_start = 0;
+               s_end = 4;
+               s_inc = 4;
+            }
+
             for (i = row_info->width; i; i--)
             {
+               png_byte v;
+               int j;
+
                v = (png_byte)((*sp >> sshift) & 0xf);
                for (j = 0; j < png_pass_inc[pass]; j++)
                {
                   *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
                   *dp |= (png_byte)(v << dshift);
-                  if (dshift == 4)
+                  if (dshift == s_end)
                   {
-                     dshift = 0;
+                     dshift = s_start;
                      dp--;
                   }
                   else
-                     dshift = 4;
+                     dshift += s_inc;
                }
-               if (sshift == 4)
+               if (sshift == s_end)
                {
-                  sshift = 0;
+                  sshift = s_start;
                   sp--;
                }
                else
-                  sshift = 4;
+                  sshift += s_inc;
             }
             break;
          }
          default:
          {
             png_bytep sp, dp;
-            png_byte v[8];
-            png_uint_32 i, pixel_bytes;
-            int j;
+            png_uint_32 i;
+            png_size_t pixel_bytes;
 
             pixel_bytes = (row_info->pixel_depth >> 3);
 
-            sp = row + (png_size_t)((row_info->width - 1) * pixel_bytes);
-            dp = row + (png_size_t)((final_width - 1) * pixel_bytes);
+            sp = row + (row_info->width - 1) * pixel_bytes;
+            dp = row + (final_width - 1) * pixel_bytes;
             for (i = row_info->width; i; i--)
             {
+               png_byte v[8];
+               int j;
+
                png_memcpy(v, sp, pixel_bytes);
                for (j = 0; j < png_pass_inc[pass]; j++)
                {
@@ -1499,11 +1804,14 @@
 png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
    png_bytep prev_row, int filter)
 {
+   png_debug(1, "in png_read_filter_row\n");
+   png_debug2(2,"row = %d, filter = %d\n", png_ptr->row_number, filter);
+
    switch (filter)
    {
-      case 0:
+      case PNG_FILTER_VALUE_NONE:
          break;
-      case 1:
+      case PNG_FILTER_VALUE_SUB:
       {
          png_uint_32 i;
          int bpp;
@@ -1518,7 +1826,7 @@
          }
          break;
       }
-      case 2:
+      case PNG_FILTER_VALUE_UP:
       {
          png_uint_32 i;
          png_bytep rp;
@@ -1531,7 +1839,7 @@
          }
          break;
       }
-      case 3:
+      case PNG_FILTER_VALUE_AVG:
       {
          png_uint_32 i;
          int bpp;
@@ -1553,7 +1861,7 @@
          }
          break;
       }
-      case 4:
+      case PNG_FILTER_VALUE_PAETH:
       {
          int bpp;
          png_uint_32 i;
@@ -1604,6 +1912,7 @@
 void
 png_read_finish_row(png_structp png_ptr)
 {
+   png_debug(1, "in png_read_finish_row\n");
    png_ptr->row_number++;
    if (png_ptr->row_number < png_ptr->num_rows)
       return;
@@ -1611,7 +1920,7 @@
    if (png_ptr->interlaced)
    {
       png_ptr->row_number = 0;
-      png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+      png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
       do
       {
          png_ptr->pass++;
@@ -1708,6 +2017,7 @@
    int max_pixel_depth;
    png_uint_32 rowbytes;
 
+   png_debug(1, "in png_read_start_row\n");
    png_ptr->zstream.avail_in = 0;
    png_init_read_transformations(png_ptr);
    if (png_ptr->interlaced)
@@ -1731,7 +2041,6 @@
       png_ptr->iwidth = png_ptr->width;
       png_ptr->irowbytes = png_ptr->rowbytes + 1;
    }
-
    max_pixel_depth = png_ptr->pixel_depth;
 
 #if defined(PNG_READ_PACK_SUPPORTED)
@@ -1807,15 +2116,22 @@
    if (rowbytes > 65536L)
       png_error(png_ptr, "This image requires a row greater than 64KB");
 #endif
-   png_ptr->row_buf = (png_bytep )png_malloc(png_ptr, rowbytes);
+   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, rowbytes);
 
 #ifdef PNG_MAX_MALLOC_64K
    if (png_ptr->rowbytes + 1 > 65536L)
       png_error(png_ptr, "This image requires a row greater than 64KB");
 #endif
-   png_ptr->prev_row = png_malloc(png_ptr, png_ptr->rowbytes + 1);
+   png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
 
-   png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+   png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
+   png_debug1(3, "width = %d,\n", png_ptr->width);
+   png_debug1(3, "height = %d,\n", png_ptr->height);
+   png_debug1(3, "iwidth = %d,\n", png_ptr->iwidth);
+   png_debug1(3, "num_rows = %d\n", png_ptr->num_rows);
+   png_debug1(3, "rowbytes = %d,\n", png_ptr->rowbytes);
+   png_debug1(3, "irowbytes = %d,\n", png_ptr->irowbytes);
 
    png_ptr->flags |= PNG_FLAG_ROW_INIT;
 }
diff --git a/pngset.c b/pngset.c
new file mode 100644
index 0000000..b079164
--- /dev/null
+++ b/pngset.c
@@ -0,0 +1,312 @@
+
+/* pngset.c - storage of image information into info struct
+
+   libpng 1.0 beta 6 - version 0.96
+   For conditions of distribution and use, see copyright notice in png.h
+   Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
+   */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+void
+png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+{
+   png_debug1(1, "in %s storage function\n", "bKGD");
+   if (info_ptr == NULL)
+      return;
+
+   png_memcpy(&(info_ptr->background), background, sizeof(png_color_16));
+   info_ptr->valid |= PNG_INFO_bKGD;
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+void
+png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
+   double white_x, double white_y, double red_x, double red_y,
+   double green_x, double green_y, double blue_x, double blue_y)
+{
+   png_debug1(1, "in %s storage function\n", "cHRM");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->x_white = (float)white_x;
+   info_ptr->y_white = (float)white_y;
+   info_ptr->x_red   = (float)red_x;
+   info_ptr->y_red   = (float)red_y;
+   info_ptr->x_green = (float)green_x;
+   info_ptr->y_green = (float)green_y;
+   info_ptr->x_blue  = (float)blue_x;
+   info_ptr->y_blue  = (float)blue_y;
+   info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+void
+png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+{
+   png_debug1(1, "in %s storage function\n", "gAMA");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->gamma = (float)file_gamma;
+   info_ptr->valid |= PNG_INFO_gAMA;
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+void
+png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+{
+   png_debug1(1, "in %s storage function\n", "hIST");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->hist = hist;
+   info_ptr->valid |= PNG_INFO_hIST;
+}
+#endif
+
+void
+png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 width, png_uint_32 height, int bit_depth,
+   int color_type, int interlace_type, int compression_type,
+   int filter_type)
+{
+   png_debug1(1, "in %s storage function\n", "IHDR");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->width = width;
+   info_ptr->height = height;
+   info_ptr->bit_depth = (png_byte)bit_depth;
+   info_ptr->color_type =(png_byte) color_type;
+   info_ptr->compression_type = (png_byte)compression_type;
+   info_ptr->filter_type = (png_byte)filter_type;
+   info_ptr->interlace_type = (png_byte)interlace_type;
+   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      info_ptr->channels = 1;
+   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+      info_ptr->channels = 3;
+   else
+      info_ptr->channels = 1;
+   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+      info_ptr->channels++;
+   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+   info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+void
+png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 offset_x, png_uint_32 offset_y, int unit_type)
+{
+   png_debug1(1, "in %s storage function\n", "oFFs");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->x_offset = offset_x;
+   info_ptr->y_offset = offset_y;
+   info_ptr->offset_unit_type = (png_byte)unit_type;
+   info_ptr->valid |= PNG_INFO_oFFs;
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+void
+png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
+   png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+   png_charp units, png_charpp params)
+{
+   png_size_t length;
+   int i;
+
+   png_debug1(1, "in %s storage function\n", "pCAL");
+   if (info_ptr == NULL)
+      return;
+
+   length = png_strlen(purpose) + 1;
+   png_debug1(3, "allocating purpose for info (%d bytes)\n", length);
+   info_ptr->pcal_purpose = (png_charp)png_malloc(png_ptr, length);
+   png_memcpy(info_ptr->pcal_purpose, purpose, length);
+
+   png_debug(3, "storing X0, X1, type, and nparams in info\n");
+   info_ptr->pcal_X0 = X0;
+   info_ptr->pcal_X1 = X1;
+   info_ptr->pcal_type = (png_byte)type;
+   info_ptr->pcal_nparams = (png_byte)nparams;
+
+   length = png_strlen(units) + 1;
+   png_debug1(3, "allocating units for info (%d bytes)\n", length);
+   info_ptr->pcal_units = (png_charp)png_malloc(png_ptr, length);
+   png_memcpy(info_ptr->pcal_units, units, length);
+
+   info_ptr->pcal_params = (png_charpp)png_malloc(png_ptr,
+      (nparams + 1) * sizeof(png_charp));
+   info_ptr->pcal_params[nparams] = NULL;
+
+   for (i = 0; i < nparams; i++)
+   {
+      length = png_strlen(params[i]) + 1;
+      png_debug2(3, "allocating parameter %d for info (%d bytes)\n", i, length);
+      info_ptr->pcal_params[i] = (png_charp)png_malloc(png_ptr, length);
+      png_memcpy(info_ptr->pcal_params[i], params[i], length);
+   }
+
+   info_ptr->valid |= PNG_INFO_pCAL;
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+void
+png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
+   png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+   png_debug1(1, "in %s storage function\n", "pHYs");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->x_pixels_per_unit = res_x;
+   info_ptr->y_pixels_per_unit = res_y;
+   info_ptr->phys_unit_type = (png_byte)unit_type;
+   info_ptr->valid |= PNG_INFO_pHYs;
+}
+#endif
+
+void
+png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
+   png_colorp palette, int num_palette)
+{
+   png_debug1(1, "in %s storage function\n", "PLTE");
+   if (info_ptr == NULL)
+      return;
+
+   info_ptr->palette = palette;
+   info_ptr->num_palette = (png_uint_16)num_palette;
+   info_ptr->valid |= PNG_INFO_PLTE;
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+void
+png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
+   png_color_8p sig_bit)
+{
+   png_debug1(1, "in %s storage function\n", "sBIT");
+   if (info_ptr == NULL)
+      return;
+
+   png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8));
+   info_ptr->valid |= PNG_INFO_sBIT;
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) || \
+    defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+void
+png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+   int num_text)
+{
+   int i;
+
+   png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
+      "text" : png_ptr->chunk_name));
+
+   if (info_ptr == NULL || num_text == 0)
+      return;
+
+   /* Make sure we have enough space in the "text" array in info_struct
+    * to hold all of the incoming text_ptr objects.
+    */
+   if (info_ptr->num_text + num_text > info_ptr->max_text)
+   {
+      if (info_ptr->text != NULL)
+      {
+         png_textp old_text;
+         int old_max;
+
+         old_max = info_ptr->max_text;
+         info_ptr->max_text = info_ptr->num_text + num_text + 8;
+         old_text = info_ptr->text;
+         info_ptr->text = (png_textp)png_malloc(png_ptr,
+            info_ptr->max_text * sizeof (png_text));
+         png_memcpy(info_ptr->text, old_text, old_max * sizeof(png_text));
+         png_free(png_ptr, old_text);
+      }
+      else
+      {
+         info_ptr->max_text = num_text + 8;
+         info_ptr->num_text = 0;
+         info_ptr->text = (png_textp)png_malloc(png_ptr,
+            info_ptr->max_text * sizeof (png_text));
+      }
+      png_debug1(3, "allocated %d entries for info_ptr->text\n",
+         info_ptr->max_text);
+   }
+
+   for (i = 0; i < num_text; i++)
+   {
+      png_textp textp = &(info_ptr->text[info_ptr->num_text]);
+
+      if (text_ptr[i].text == NULL)
+         text_ptr[i].text = "";
+
+      if (text_ptr[i].text[0] == '\0')
+      {
+         textp->text_length = 0;
+         textp->compression = PNG_TEXT_COMPRESSION_NONE;
+      }
+      else
+      {
+         textp->text_length = png_strlen(text_ptr[i].text);
+         textp->compression = text_ptr[i].compression;
+      }
+      textp->text = text_ptr[i].text;
+      textp->key = text_ptr[i].key;
+      info_ptr->num_text++;
+      png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+   }
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+void
+png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+{
+   png_debug1(1, "in %s storage function\n", "tIME");
+   if (info_ptr == NULL)
+      return;
+
+   png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time));
+   info_ptr->valid |= PNG_INFO_tIME;
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+void
+png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
+   png_bytep trans, int num_trans, png_color_16p trans_values)
+{
+   png_debug1(1, "in %s storage function\n", "tRNS");
+   if (info_ptr == NULL)
+      return;
+
+   if (trans != NULL)
+   {
+      info_ptr->trans = trans;
+   }
+
+   if (trans_values != NULL)
+   {
+      png_memcpy(&(info_ptr->trans_values), trans_values,
+         sizeof(png_color_16));
+   }
+   info_ptr->num_trans = (png_uint_16)num_trans;
+   info_ptr->valid |= PNG_INFO_tRNS;
+}
+#endif
+
diff --git a/pngtest.c b/pngtest.c
index 76804e6..c266233 100644
--- a/pngtest.c
+++ b/pngtest.c
@@ -1,14 +1,21 @@
 
 /* pngtest.c - a simple test program to test libpng
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
-*/
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
+   */
 
 #include <stdio.h>
 #include <stdlib.h>
+
+/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+#define PNG_DEBUG 0
+#endif
+
 #include "png.h"
 
 #ifdef __TURBOC__
@@ -30,23 +37,21 @@
 
 char inbuf[256], outbuf[256];
 
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
 {
    FILE *fpin, *fpout;
-   png_structp read_ptr;
-   png_structp write_ptr;
-   png_infop info_ptr;
-   png_infop end_info;
+   png_structp read_ptr, write_ptr;
+   png_infop read_info_ptr, write_info_ptr, end_info_ptr;
    png_bytep row_buf;
-   png_byte *near_row_buf;
-   png_uint_32 rowbytes;
    png_uint_32 y;
-   int channels, num_pass, pass;
+   png_uint_32 width, height;
+   int num_pass, pass;
+   int bit_depth, color_type;
 #ifdef USE_FAR_KEYWORD
    jmp_buf jmpbuf;
 #endif   
    row_buf = (png_bytep)NULL;
-   near_row_buf = (png_byte *)NULL;
 
    fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
 
@@ -70,28 +75,30 @@
      exit(1);
    }
 
-   fpin = fopen(inname, "rb");
-   if (!fpin)
+   if ((fpin = fopen(inname, "rb")) == NULL)
    {
       fprintf(STDERR, "Could not find input file %s\n", inname);
       return 1;
    }
 
-   fpout = fopen(outname, "wb");
-   if (!fpout)
+   if ((fpout = fopen(outname, "wb")) == NULL)
    {
       fprintf(STDERR, "Could not open output file %s\n", outname);
       fclose(fpin);
       return 1;
    }
 
+   png_debug(0, "Allocating read and write structures\n");
    read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
-      (png_error_ptr)NULL,  (png_error_ptr)NULL);
+      (png_error_ptr)NULL, (png_error_ptr)NULL);
    write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
       (png_error_ptr)NULL, (png_error_ptr)NULL);
-   info_ptr = png_create_info_struct(read_ptr);
-   end_info = png_create_info_struct(read_ptr);
+   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
+   read_info_ptr = png_create_info_struct(read_ptr);
+   write_info_ptr = png_create_info_struct(read_ptr);
+   end_info_ptr = png_create_info_struct(read_ptr);
 
+   png_debug(0, "Setting jmpbuf for read struct\n");
 #ifdef USE_FAR_KEYWORD
    if (setjmp(jmpbuf))
 #else
@@ -99,12 +106,14 @@
 #endif
    {
       fprintf(STDERR, "libpng read error\n");
-      png_destroy_read_struct(&read_ptr, &info_ptr, &end_info);
-      png_destroy_write_struct(&write_ptr, (png_infopp)NULL);
+      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+      png_destroy_write_struct(&write_ptr, &write_info_ptr);
       fclose(fpin);
       fclose(fpout);
       return 1;
    }
+
+   png_debug(0, "Setting jmpbuf for write struct\n");
 #ifdef USE_FAR_KEYWORD
    png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
    if (setjmp(jmpbuf))
@@ -113,92 +122,227 @@
 #endif
    {
       fprintf(STDERR, "libpng write error\n");
-      png_destroy_read_struct(&read_ptr, &info_ptr, &end_info);
-      png_destroy_write_struct(&write_ptr, (png_infopp)NULL);
+      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+      png_destroy_write_struct(&write_ptr, &write_info_ptr);
       fclose(fpin);
       fclose(fpout);
       return 1;
    }
+
 #ifdef USE_FAR_KEYWORD
    png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
 #endif
+   png_debug(0, "Initializing input and output streams\n");
    png_init_io(read_ptr, fpin);
    png_init_io(write_ptr, fpout);
 
-   png_read_info(read_ptr, info_ptr);
-   png_write_info(write_ptr, info_ptr);
+   png_debug(0, "Reading info struct\n");
+   png_read_info(read_ptr, read_info_ptr);
 
-   if ((info_ptr->color_type & PNG_COLOR_TYPE_PALETTE)==PNG_COLOR_TYPE_PALETTE)
-      channels = 1;
-   else
-      channels = 3;
-   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
-      channels++;
+   png_debug(0, "Transferring info struct\n");
+   {
+      int interlace_type, compression_type, filter_type;
 
-   rowbytes = ((info_ptr->width * info_ptr->bit_depth * channels + 7) >> 3);
-   near_row_buf = (png_byte *)malloc((size_t)rowbytes);
-   row_buf = (png_bytep)near_row_buf;
-   if (!row_buf)
+      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
+          &color_type, &interlace_type, &compression_type, &filter_type))
+      {
+         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
+            color_type, interlace_type, compression_type, filter_type);
+      }
+   }
+#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
+   {
+      png_color_16p background;
+
+      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
+      {
+         png_set_bKGD(write_ptr, write_info_ptr, background);
+      }
+   }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
+   {
+      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
+         &red_y, &green_x, &green_y, &blue_x, &blue_y))
+      {
+         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
+            red_y, green_x, green_y, blue_x, blue_y);
+      }
+   }
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
+   {
+      double gamma;
+
+      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
+      {
+         png_set_gAMA(write_ptr, write_info_ptr, gamma);
+      }
+   }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
+   {
+      png_uint_16p hist;
+
+      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
+      {
+         png_set_hIST(write_ptr, write_info_ptr, hist);
+      }
+   }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
+   {
+      png_uint_32 offset_x, offset_y;
+      int unit_type;
+
+      if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
+      {
+         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
+      }
+   }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
+   {
+      png_charp purpose, units;
+      png_charpp params;
+      png_int_32 X0, X1;
+      int type, nparams;
+
+      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
+         &nparams, &units, &params))
+      {
+         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
+            nparams, units, params);
+      }
+   }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
+   {
+      png_uint_32 res_x, res_y;
+      int unit_type;
+
+      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
+      {
+         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
+      }
+   }
+#endif
+   {
+      png_colorp palette;
+      int num_palette;
+
+      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
+      {
+         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
+      }
+   }
+#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
+   {
+      png_color_8p sig_bit;
+
+      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
+      {
+         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
+      }
+   }
+#endif
+#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \
+    (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
+   {
+      png_textp text_ptr;
+      int num_text;
+
+      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
+      {
+         png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text);
+         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
+      }
+   }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
+   {
+      png_timep mod_time;
+
+      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
+      {
+         png_set_tIME(write_ptr, write_info_ptr, mod_time);
+      }
+   }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
+   {
+      png_bytep trans;
+      int num_trans;
+      png_color_16p trans_values;
+
+      if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
+         &trans_values))
+      {
+         png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
+            trans_values);
+      }
+   }
+#endif
+
+   png_debug(0, "\nWriting info struct\n");
+   png_write_info(write_ptr, write_info_ptr);
+
+   row_buf = (png_bytep)png_malloc(read_ptr, 
+      png_get_rowbytes(read_ptr, read_info_ptr));
+   if (row_buf == NULL)
    {
       fprintf(STDERR, "No memory to allocate row buffer\n");
-      png_destroy_read_struct(&read_ptr, &info_ptr, &end_info);
-      png_destroy_write_struct(&write_ptr, (png_infopp)NULL);
+      png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
+      png_destroy_write_struct(&write_ptr, &write_info_ptr);
       fclose(fpin);
       fclose(fpout);
       return 1;
    }
 
-   if (info_ptr->interlace_type)
-   {
-      num_pass = png_set_interlace_handling(read_ptr);
-      num_pass = png_set_interlace_handling(write_ptr);
-   }
-   else
-   {
-      num_pass = 1;
-   }
+   num_pass = png_set_interlace_handling(read_ptr);
+   png_set_interlace_handling(write_ptr);
 
    for (pass = 0; pass < num_pass; pass++)
    {
-      for (y = 0; y < info_ptr->height; y++)
+      for (y = 0; y < height; y++)
       {
-#ifdef TESTING
-         fprintf(STDERR, "Processing line #%ld\n", y);
-#endif
-         png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)0, 1);
+         png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
          png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
       }
    }
 
-   png_read_end(read_ptr, end_info);
-   png_write_end(write_ptr, end_info);
+   png_debug(0, "Reading and writing end_info data\n");
+   png_read_end(read_ptr, end_info_ptr);
+   png_write_end(write_ptr, end_info_ptr);
 
-   png_destroy_read_struct(&read_ptr, &info_ptr, &end_info);
-   png_destroy_write_struct(&write_ptr, (png_infopp)NULL);
+   png_debug(0, "Destroying data structs\n");
+   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+   png_destroy_write_struct(&write_ptr, &write_info_ptr);
 
    fclose(fpin);
    fclose(fpout);
 
-   free((png_byte *)near_row_buf);
+   png_free(read_ptr, row_buf);
 
-   fpin = fopen(inname, "rb");
-
-   if (!fpin)
+   png_debug(0, "Opening files for comparison\n");
+   if ((fpin = fopen(inname, "rb")) == NULL)
    {
       fprintf(STDERR, "Could not find file %s\n", inname);
       return 1;
    }
 
-   fpout = fopen(outname, "rb");
-   if (!fpout)
+   if ((fpout = fopen(outname, "rb")) == NULL)
    {
       fprintf(STDERR, "Could not find file %s\n", outname);
       fclose(fpin);
       return 1;
    }
+
    while (1)
    {
-      int num_in, num_out;
+      png_size_t num_in, num_out;
 
       num_in = fread(inbuf, 1, 1, fpin);
       num_out = fread(outbuf, 1, 1, fpout);
@@ -215,7 +359,7 @@
       if (!num_in)
          break;
 
-      if (memcmp(inbuf, outbuf, num_in))
+      if (png_memcmp(inbuf, outbuf, num_in))
       {
          fprintf(STDERR, "Files %s and %s are different\n", inname, outname);
          fclose(fpin);
diff --git a/pngtest.png b/pngtest.png
index 69383a6..3bbeaee 100644
--- a/pngtest.png
+++ b/pngtest.png
Binary files differ
diff --git a/pngtrans.c b/pngtrans.c
index 608c2ea..05e4185 100644
--- a/pngtrans.c
+++ b/pngtrans.c
@@ -1,11 +1,11 @@
 
-/* pngtrans.c - transforms the data in a row
-   routines used by both readers and writers
+/* pngtrans.c - transforms the data in a row (used by both readers and writers)
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
@@ -16,6 +16,7 @@
 void
 png_set_bgr(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_bgr\n");
    png_ptr->transformations |= PNG_BGR;
 }
 #endif
@@ -25,6 +26,7 @@
 void
 png_set_swap(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_swap\n");
    if (png_ptr->bit_depth == 16)
       png_ptr->transformations |= PNG_SWAP_BYTES;
 }
@@ -35,6 +37,7 @@
 void
 png_set_packing(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_packing\n");
    if (png_ptr->bit_depth < 8)
    {
       png_ptr->transformations |= PNG_PACK;
@@ -43,10 +46,22 @@
 }
 #endif
 
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* turn on packed pixel swapping */
+void
+png_set_packswap(png_structp png_ptr)
+{
+   png_debug(1, "in png_set_packswap\n");
+   if (png_ptr->bit_depth < 8)
+      png_ptr->transformations |= PNG_PACKSWAP;
+}
+#endif
+
 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
 void
 png_set_shift(png_structp png_ptr, png_color_8p true_bits)
 {
+   png_debug(1, "in png_set_shift\n");
    png_ptr->transformations |= PNG_SHIFT;
    png_ptr->shift = *true_bits;
 }
@@ -56,6 +71,7 @@
 int
 png_set_interlace_handling(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_interlace handling\n");
    if (png_ptr->interlaced)
    {
       png_ptr->transformations |= PNG_INTERLACE;
@@ -67,35 +83,37 @@
 #endif
 
 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte on read, or remove a filler or alpha byte on write.
+ * The filler type has changed in v0.95 to allow future 2-byte fillers
+ * for 48-bit input data, as well as avoiding problems with some compilers
+ * which don't like bytes as parameters.
+ */
 void
-png_set_filler(png_structp png_ptr, png_byte filler, int filler_loc)
+png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
 {
+   png_debug(1, "in png_set_filler\n");
    png_ptr->transformations |= PNG_FILLER;
-   png_ptr->filler = filler;
+   png_ptr->filler = (png_byte)filler;
    if (filler_loc == PNG_FILLER_AFTER)
       png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
    else
       png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
 
-   if (png_ptr->color_type == PNG_COLOR_TYPE_RGB &&
-      png_ptr->bit_depth == 8)
+   /* This should probably go in the "do_filler" routine */
+   if (png_ptr->color_type == PNG_COLOR_TYPE_RGB && png_ptr->bit_depth == 8)
+   {
       png_ptr->usr_channels = 4;
+   }
 }
+#endif
 
-/* Old functions kept around for compatability purposes.  They will be
- * removed at some time in the future, so don't use them.  You should
- * use png_set_filler() above instead.  We set filler bytes to 0xff in
- * case they are mistakenly used as PNG alpha (0xff is fully opaque). */
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
 void
-png_set_rgbx(png_structp png_ptr)
+png_set_swap_alpha(png_structp png_ptr)
 {
-   png_set_filler(png_ptr, (png_byte)0xff, PNG_FILLER_AFTER);
-}
-
-void
-png_set_xrgb(png_structp png_ptr)
-{
-   png_set_filler(png_ptr, (png_byte)0xff, PNG_FILLER_BEFORE);
+   png_debug(1, "in png_set_swap_alpha\n");
+   png_ptr->transformations |= PNG_SWAP_ALPHA;
 }
 #endif
 
@@ -103,6 +121,7 @@
 void
 png_set_invert_mono(png_structp png_ptr)
 {
+   png_debug(1, "in png_set_invert_mono\n");
    png_ptr->transformations |= PNG_INVERT_MONO;
 }
 
@@ -110,15 +129,17 @@
 void
 png_do_invert(png_row_infop row_info, png_bytep row)
 {
-   if (row && row_info && row_info->bit_depth == 1 &&
-      row_info->color_type == PNG_COLOR_TYPE_GRAY)
+   png_debug(1, "in png_do_invert\n");
+   if (row_info->bit_depth == 1 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
+       row_info->color_type == PNG_COLOR_TYPE_GRAY)
    {
       png_bytep rp;
       png_uint_32 i;
 
-      for (i = 0, rp = row;
-         i < row_info->rowbytes;
-         i++, rp++)
+      for (i = 0, rp = row; i < row_info->rowbytes; i++, rp++)
       {
          *rp = (png_byte)(~(*rp));
       }
@@ -131,7 +152,12 @@
 void
 png_do_swap(png_row_infop row_info, png_bytep row)
 {
-   if (row && row_info && row_info->bit_depth == 16)
+   png_debug(1, "in png_do_swap\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
+       row_info->bit_depth == 16)
    {
       png_bytep rp;
       png_byte t;
@@ -149,80 +175,391 @@
 }
 #endif
 
-#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-/* swaps red and blue */
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+static png_byte onebppswaptable[256] = {
+   0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+   0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+   0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+   0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+   0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+   0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+   0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+   0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+   0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+   0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+   0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+   0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+   0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+   0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+   0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+   0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+   0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+   0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+   0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+   0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+   0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+   0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+   0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+   0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+   0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+   0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+   0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+   0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+   0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+   0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+   0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+   0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+static png_byte twobppswaptable[256] = {
+   0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
+   0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
+   0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
+   0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
+   0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
+   0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
+   0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
+   0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+   0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
+   0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
+   0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
+   0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
+   0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
+   0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
+   0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
+   0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
+   0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
+   0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
+   0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
+   0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
+   0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
+   0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
+   0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
+   0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
+   0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
+   0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
+   0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
+   0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
+   0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
+   0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
+   0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
+   0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
+};
+
+static png_byte fourbppswaptable[256] = {
+   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
+   0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+   0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+   0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+   0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
+   0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+   0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
+   0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+   0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
+   0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+   0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
+   0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+   0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
+   0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+   0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
+   0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+   0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
+   0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+   0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
+   0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
+   0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+   0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
+   0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
+   0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
+   0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
+   0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
+   0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
+   0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+   0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+   0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+   0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
+};
+
+/* swaps pixel packing order within bytes */
 void
-png_do_bgr(png_row_infop row_info, png_bytep row)
+png_do_packswap(png_row_infop row_info, png_bytep row)
 {
-   if (row && row_info && (row_info->color_type & 2))
+   png_debug(1, "in png_do_packswap\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL
+#endif
+       row_info->bit_depth < 8)
    {
-      if (row_info->color_type == 2 && row_info->bit_depth == 8)
-      {
-         png_bytep rp;
-         png_byte t;
-         png_uint_32 i;
+      png_bytep rp, end, table;
 
-         for (i = 0, rp = row;
-            i < row_info->width;
-            i++, rp += 3)
+      end = row + row_info->rowbytes;
+
+      if (row_info->bit_depth == 1)
+         table = onebppswaptable;
+      else if (row_info->bit_depth == 2)
+         table = twobppswaptable;
+      else if (row_info->bit_depth == 4)
+         table = fourbppswaptable;
+      else
+         return;
+
+      for (rp = row; rp < end; rp++)
+         *rp = table[*rp];
+   }
+}
+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+/* remove filler or alpha byte(s) */
+void
+png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+{
+   png_debug(1, "in png_do_strip_filler\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL)
+#endif
+   {
+/*
+      if (row_info->color_type == PNG_COLOR_TYPE_RGB ||
+          row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+*/
+      if (row_info->channels == 4)
+      {
+         if (row_info->bit_depth == 8)
          {
-            t = *rp;
-            *rp = *(rp + 2);
-            *(rp + 2) = t;
+            /* This converts from RGBX or RGBA to RGB */
+            if (flags & PNG_FLAG_FILLER_AFTER)
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               for (i = 1, sp = row + 4, dp = row + 3; i < row_info->width; i++)
+               {
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  sp++;
+               }
+            }
+            /* This converts from XRGB or ARGB to RGB */
+            else
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+               {
+                  sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+               }
+            }
+            row_info->pixel_depth = 24;
+            row_info->rowbytes = row_info->width * 3;
          }
+         else /* if (row_info->bit_depth == 16) */
+         {
+            if (flags & PNG_FLAG_FILLER_AFTER)
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
+               for (i = 1, sp = row + 8, dp = row + 6; i < row_info->width; i++)
+               {
+                  /* This could be (although memcpy is probably slower):
+                  png_memcpy(dp, sp, 6);
+                  sp += 8;
+                  dp += 6;
+                  */
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  sp += 2;
+               }
+            }
+            else
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
+               for (i = 0, sp = row + 2, dp = row; i < row_info->width; i++)
+               {
+                  /* This could be (although memcpy is probably slower):
+                  png_memcpy(dp, sp, 6);
+                  sp += 8;
+                  dp += 6;
+                  */
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+               }
+            }
+            row_info->pixel_depth = 48;
+            row_info->rowbytes = row_info->width * 6;
+         }
+         row_info->channels = 3;
       }
-      else if (row_info->color_type == 6 && row_info->bit_depth == 8)
+/*
+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY ||
+               row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+*/
+      else if (row_info->channels == 2)
       {
-         png_bytep rp;
-         png_byte t;
-         png_uint_32 i;
-
-         for (i = 0, rp = row;
-            i < row_info->width;
-            i++, rp += 4)
+         if (row_info->bit_depth == 8)
          {
-            t = *rp;
-            *rp = *(rp + 2);
-            *(rp + 2) = t;
-         }
-      }
-      else if (row_info->color_type == 2 && row_info->bit_depth == 16)
-      {
-         png_bytep rp;
-         png_byte t[2];
-         png_uint_32 i;
+            /* This converts from GX or GA to G */
+            if (flags & PNG_FLAG_FILLER_AFTER)
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
 
-         for (i = 0, rp = row;
-            i < row_info->width;
-            i++, rp += 6)
-         {
-            t[0] = *rp;
-            t[1] = *(rp + 1);
-            *rp = *(rp + 4);
-            *(rp + 1) = *(rp + 5);
-            *(rp + 4) = t[0];
-            *(rp + 5) = t[1];
-         }
-      }
-      else if (row_info->color_type == 6 && row_info->bit_depth == 16)
-      {
-         png_bytep rp;
-         png_byte t[2];
-         png_uint_32 i;
+               for (i = 1, sp = row + 2, dp = row + 1; i < row_info->width; i++)
+               {
+                  *dp++ = *sp++;
+                  sp++;
+               }
+            }
+            /* This converts from XG or AG to G */
+            else
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
 
-         for (i = 0, rp = row;
-            i < row_info->width;
-            i++, rp += 8)
-         {
-            t[0] = *rp;
-            t[1] = *(rp + 1);
-            *rp = *(rp + 4);
-            *(rp + 1) = *(rp + 5);
-            *(rp + 4) = t[0];
-            *(rp + 5) = t[1];
+               for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+               {
+                  sp++;
+                  *dp++ = *sp++;
+               }
+            }
+            row_info->pixel_depth = 8;
+            row_info->rowbytes = row_info->width;
          }
+         else /* if (row_info->bit_depth == 16) */
+         {
+            if (flags & PNG_FLAG_FILLER_AFTER)
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               /* This converts from GGXX or GGAA to GG */
+               for (i = 1, sp = row + 4, dp = row + 2; i < row_info->width; i++)
+               {
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+                  sp += 2;
+               }
+            }
+            else
+            {
+               png_bytep sp, dp;
+               png_uint_32 i;
+
+               /* This converts from XXGG or AAGG to GG */
+               for (i = 0, sp = row, dp = row; i < row_info->width; i++)
+               {
+                  sp += 2;
+                  *dp++ = *sp++;
+                  *dp++ = *sp++;
+               }
+            }
+            row_info->pixel_depth = 16;
+            row_info->rowbytes = row_info->width * 2;
+         }
+         row_info->channels = 1;
       }
    }
 }
 #endif
 
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* swaps red and blue bytes within a pixel */
+void
+png_do_bgr(png_row_infop row_info, png_bytep row)
+{
+   png_debug(1, "in png_do_bgr\n");
+   if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
+       (row_info->color_type & PNG_COLOR_MASK_COLOR))
+   {
+      if (row_info->bit_depth == 8)
+      {
+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+         {
+            png_bytep rp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, rp = row; i < row_info->width; i++, rp += 3)
+            {
+               save = *rp;
+               *rp = *(rp + 2);
+               *(rp + 2) = save;
+            }
+         }
+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+         {
+            png_bytep rp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, rp = row; i < row_info->width; i++, rp += 4)
+            {
+               save = *rp;
+               *rp = *(rp + 2);
+               *(rp + 2) = save;
+            }
+         }
+      }
+      else if (row_info->bit_depth == 16)
+      {
+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+         {
+            png_bytep rp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, rp = row; i < row_info->width; i++, rp += 6)
+            {
+               save[0] = *rp;
+               save[1] = *(rp + 1);
+               *rp = *(rp + 4);
+               *(rp + 1) = *(rp + 5);
+               *(rp + 4) = save[0];
+               *(rp + 5) = save[1];
+            }
+         }
+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+         {
+            png_bytep rp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, rp = row; i < row_info->width; i++, rp += 8)
+            {
+               save[0] = *rp;
+               save[1] = *(rp + 1);
+               *rp = *(rp + 4);
+               *(rp + 1) = *(rp + 5);
+               *(rp + 4) = save[0];
+               *(rp + 5) = save[1];
+            }
+         }
+      }
+   }
+}
+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+
diff --git a/pngwio.c b/pngwio.c
index 9d6b413..e4c96a7 100644
--- a/pngwio.c
+++ b/pngwio.c
@@ -1,10 +1,11 @@
 
 /* pngwio.c - functions for data output
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
 
    This file provides a location for all output.  Users which need
    special handling are expected to write functions which have the same
@@ -20,13 +21,12 @@
    writes to a file pointer.  Note that this routine sometimes gets called
    with very small lengths, so you should implement some kind of simple
    buffering if you are using unbuffered writes.  This should never be asked
-   to write more then 64K on a 16 bit machine.  The cast to png_size_t is
-   there to quiet warnings of certain compilers. */
+   to write more then 64K on a 16 bit machine.  */
 
 void
-png_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-   if (png_ptr->write_data_fn)
+   if (png_ptr->write_data_fn != NULL )
       (*(png_ptr->write_data_fn))(png_ptr, data, length);
    else
       png_error(png_ptr, "Call to NULL write function");
@@ -38,11 +38,11 @@
    than changing the library. */
 #ifndef USE_FAR_KEYWORD
 static void
-png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
    png_uint_32 check;
 
-   check = fwrite(data, 1, (png_size_t)length, (FILE *)(png_ptr->io_ptr));
+   check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
    if (check != length)
    {
       png_error(png_ptr, "Write Error");
@@ -58,25 +58,25 @@
 #define MIN(a,b) (a <= b ? a : b)
 
 static void
-png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
    png_uint_32 check;
-   png_byte *n_data;
+   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
    FILE *io_ptr;
 
    /* Check if data really is near. If so, use usual code. */
-   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
    io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
-   if ((png_bytep)n_data == data)
+   if ((png_bytep)near_data == data)
    {
-      check = fwrite(n_data, 1, (png_size_t)length, io_ptr);
+      check = fwrite(near_data, 1, length, io_ptr);
    }
    else
    {
       png_byte buf[NEAR_BUF_SIZE];
       png_size_t written, remaining, err;
       check = 0;
-      remaining = (png_size_t)length;
+      remaining = length;
       do
       {
          written = MIN(NEAR_BUF_SIZE, remaining);
@@ -106,7 +106,7 @@
 void
 png_flush(png_structp png_ptr)
 {
-   if (png_ptr->output_flush_fn)
+   if (png_ptr->output_flush_fn != NULL)
       (*(png_ptr->output_flush_fn))(png_ptr);
 }
 
@@ -115,7 +115,7 @@
 {
    FILE *io_ptr;
    io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
-   if (io_ptr)
+   if (io_ptr != NULL)
       fflush(io_ptr);
 }
 #endif
@@ -148,13 +148,13 @@
 {
    png_ptr->io_ptr = io_ptr;
 
-   if (write_data_fn)
+   if (write_data_fn != NULL)
       png_ptr->write_data_fn = write_data_fn;
    else
       png_ptr->write_data_fn = png_default_write_data;
 
 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
-   if (output_flush_fn)
+   if (output_flush_fn != NULL)
       png_ptr->output_flush_fn = output_flush_fn;
    else
       png_ptr->output_flush_fn = png_default_flush;
diff --git a/pngwrite.c b/pngwrite.c
index e455368..b571b0f 100644
--- a/pngwrite.c
+++ b/pngwrite.c
@@ -1,28 +1,32 @@
+   
+/* pngwrite.c - general routines to write a PNG file
 
-/* pngwrite.c - general routines to write a png file
-
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 /* get internal access to png.h */
 #define PNG_INTERNAL
 #include "png.h"
 
-/* Writes all the png information.  This is the suggested way to use
-   the library.  If you have a new chunk to add, make a function to
-   write it, and put it in the correct location here.  If you want
-   the chunk written after the image data, put it in png_write_end().
-   I strongly encurage you to supply a PNG_INFO_ flag, and check
-   info_ptr->valid before writing the chunk, as that will keep the code
-   from breaking if you want to just write a plain png file.
-   If you have long comments, I suggest writing them in png_write_end(),
-   and compressing them. */
+/* Writes all the PNG information.  This is the suggested way to use the
+ * library.  If you have a new chunk to add, make a function to write it,
+ * and put it in the correct location here.  If you want the chunk written
+ * after the image data, put it in png_write_end().  I strongly encurage
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
+ * the chunk, as that will keep the code from breaking if you want to just
+ * write a plain PNG file.  If you have long comments, I suggest writing
+ * them in png_write_end(), and compressing them.
+ */
 void
 png_write_info(png_structp png_ptr, png_infop info_ptr)
 {
+   int i;
+
+   png_debug(1, "in png_write_info\n");
    png_write_sig(png_ptr); /* write PNG signature */
    /* write IHDR information. */
    png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
@@ -47,7 +51,8 @@
          info_ptr->x_blue, info_ptr->y_blue);
 #endif
    if (info_ptr->valid & PNG_INFO_PLTE)
-      png_write_PLTE(png_ptr, info_ptr->palette, info_ptr->num_palette);
+      png_write_PLTE(png_ptr, info_ptr->palette,
+         (png_uint_32)info_ptr->num_palette);
    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       png_error(png_ptr, "Valid palette required for paletted images\n");
 #if defined(PNG_WRITE_tRNS_SUPPORTED)
@@ -63,16 +68,22 @@
    if (info_ptr->valid & PNG_INFO_hIST)
       png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
 #endif
-#if defined(PNG_WRITE_pHYs_SUPPORTED)
-   if (info_ptr->valid & PNG_INFO_pHYs)
-      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
-         info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
-#endif
 #if defined(PNG_WRITE_oFFs_SUPPORTED)
    if (info_ptr->valid & PNG_INFO_oFFs)
       png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
          info_ptr->offset_unit_type);
 #endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+   if (info_ptr->valid & PNG_INFO_pCAL)
+      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
+         info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+         info_ptr->pcal_units, info_ptr->pcal_params);
+#endif
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+   if (info_ptr->valid & PNG_INFO_pHYs)
+      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
+         info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif
 #if defined(PNG_WRITE_tIME_SUPPORTED)
    if (info_ptr->valid & PNG_INFO_tIME)
    {
@@ -82,15 +93,68 @@
 #endif
 #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
    /* Check to see if we need to write text chunks */
-   if (info_ptr->num_text)
+   for (i = 0; i < info_ptr->num_text; i++)
    {
-      int i; /* local counter */
+      png_debug2(2, "Writing header text chunk %d, type %d\n", i,
+         info_ptr->text[i].compression);
+      /* If we want a compressed text chunk */
+      if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+      {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+         /* write compressed chunk */
+         png_write_zTXt(png_ptr, info_ptr->text[i].key,
+            info_ptr->text[i].text, info_ptr->text[i].text_length,
+            info_ptr->text[i].compression);
+#else
+         png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+         /* Mark this chunk as written */
+         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+      }
+      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+      {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+         /* write uncompressed chunk */
+         png_write_tEXt(png_ptr, info_ptr->text[i].key,
+            info_ptr->text[i].text, info_ptr->text[i].text_length);
+#else
+         png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+         /* Mark this chunk as written */
+         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+      }
+   }
+#endif
+}
 
-      /* loop through the text chunks */
+/* Writes the end of the PNG file.  If you don't want to write comments or
+   time information, you can pass NULL for info.  If you already wrote these
+   in png_write_info(), do not write them again here.  If you have long
+   comments, I suggest writing them here, and compressing them. */
+void
+png_write_end(png_structp png_ptr, png_infop info_ptr)
+{
+   png_debug(1, "in png_write_end\n");
+   if (!(png_ptr->mode & PNG_HAVE_IDAT))
+      png_error(png_ptr, "No IDATs written into file");
+
+   /* see if user wants us to write information chunks */
+   if (info_ptr != NULL)
+   {
+      int i; /* local index variable */
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+      /* check to see if user has supplied a time chunk */
+      if (info_ptr->valid & PNG_INFO_tIME &&
+         !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
+         png_write_tIME(png_ptr, &(info_ptr->mod_time));
+#endif
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+      /* loop through comment chunks */
       for (i = 0; i < info_ptr->num_text; i++)
       {
-         /* if chunk is compressed */
-         if (info_ptr->text[i].compression >= 0)
+         png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
+            info_ptr->text[i].compression);
+         if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
          {
 #if defined(PNG_WRITE_zTXt_SUPPORTED)
             /* write compressed chunk */
@@ -100,8 +164,10 @@
 #else
             png_warning(png_ptr, "Unable to write compressed text\n");
 #endif
+            /* Mark this chunk as written */
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
          }
-         else
+         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
          {
 #if defined(PNG_WRITE_tEXt_SUPPORTED)
             /* write uncompressed chunk */
@@ -110,60 +176,9 @@
 #else
             png_warning(png_ptr, "Unable to write uncompressed text\n");
 #endif
-         }
-      }
-   }
-#endif
-}
 
-/* writes the end of the png file.  If you don't want to write comments or
-   time information, you can pass NULL for info.  If you already wrote these
-   in png_write_info(), do not write them again here.  If you have long
-   comments, I suggest writing them here, and compressing them. */
-void
-png_write_end(png_structp png_ptr, png_infop info_ptr)
-{
-   if (!(png_ptr->mode & PNG_HAVE_IDAT))
-      png_error(png_ptr, "No IDATs written into file");
-
-   /* see if user wants us to write information chunks */
-   if (info_ptr)
-   {
-#if defined(PNG_WRITE_tIME_SUPPORTED)
-      /* check to see if user has supplied a time chunk */
-      if (info_ptr->valid & PNG_INFO_tIME &&
-         !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
-         png_write_tIME(png_ptr, &(info_ptr->mod_time));
-#endif
-#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
-      /* check to see if we need to write comment chunks */
-      if (info_ptr->num_text)
-      {
-         int i; /* local index variable */
-
-         /* loop through comment chunks */
-         for (i = 0; i < info_ptr->num_text; i++)
-         {
-#if defined(PNG_WRITE_zTXt_SUPPORTED)
-            /* check to see if comment is to be compressed */
-            if (info_ptr->text[i].compression >= 0)
-            {
-               /* write compressed chunk */
-               png_write_zTXt(png_ptr, info_ptr->text[i].key,
-                  info_ptr->text[i].text, info_ptr->text[i].text_length,
-                  info_ptr->text[i].compression);
-            }
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
-            else
-#endif
-#endif
-#if defined(PNG_WRITE_tEXt_SUPPORTED)
-            {
-               /* write uncompressed chunk */
-               png_write_tEXt(png_ptr, info_ptr->text[i].key,
-                  info_ptr->text[i].text, info_ptr->text[i].text_length);
-            }
-#endif
+            /* Mark this chunk as written */
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
          }
       }
 #endif
@@ -171,7 +186,7 @@
 
    png_ptr->mode |= PNG_AFTER_IDAT;
 
-   /* write end of png file */
+   /* write end of PNG file */
    png_write_IEND(png_ptr);
 }
 
@@ -179,6 +194,7 @@
 void
 png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
 {
+   png_debug(1, "in png_convert_from_struct_tm\n");
    ptime->year = (png_uint_16)(1900 + ttime->tm_year);
    ptime->month = (png_byte)(ttime->tm_mon + 1);
    ptime->day = (png_byte)ttime->tm_mday;
@@ -192,12 +208,13 @@
 {
    struct tm *tbuf;
 
+   png_debug(1, "in png_convert_from_time_t\n");
    tbuf = gmtime(&ttime);
    png_convert_from_struct_tm(ptime, tbuf);
 }
 #endif
 
-/* initialize png structure, and allocate any memory needed */
+/* Initialize png_ptr structure, and allocate any memory needed */
 png_structp
 png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
    png_error_ptr error_fn, png_error_ptr warn_fn)
@@ -206,6 +223,7 @@
 #ifdef USE_FAR_KEYWORD
    jmp_buf jmpbuf;
 #endif
+   png_debug(1, "in png_create_write_struct\n");
    if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
    {
       return (png_structp)NULL;
@@ -225,16 +243,16 @@
 #endif
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   if (user_png_ver == NULL || png_strcmp(user_png_ver, png_libpng_ver))
+   /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+    * we must recompile any applications that use any older library version.
+    * For versions after libpng 1.0, we will be compatible, so we need
+    * only check the first digit.
+    */
+   if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+       (png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
    {
-      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0])
-      {
-         png_error(png_ptr, "Incompatible libpng versions");
-      }
-      else
-      {
-         png_warning(png_ptr, "Different libpng versions");
-      }
+      png_error(png_ptr,
+         "Incompatible libpng version in application and library");
    }
 
    /* initialize zbuf - compression buffer */
@@ -247,12 +265,13 @@
 }
 
 
-/* initialize png structure, and allocate any memory needed */
+/* Initialize png_ptr structure, and allocate any memory needed */
 void
 png_write_init(png_structp png_ptr)
 {
    jmp_buf tmp_jmp; /* to save current jump buffer */
 
+   png_debug(1, "in png_write_init\n");
    /* save jump buffer and error functions */
    png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
 
@@ -266,6 +285,11 @@
    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
    png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
    png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+      1, NULL, NULL);
+#endif
 }
 
 /* write a few rows of image data.  If the image is interlaced,
@@ -279,6 +303,7 @@
    png_uint_32 i; /* row counter */
    png_bytepp rp; /* row pointer */
 
+   png_debug(1, "in png_write_rows\n");
    /* loop through the rows */
    for (i = 0, rp = row; i < num_rows; i++, rp++)
    {
@@ -295,6 +320,7 @@
    int pass, num_pass; /* pass variables */
    png_bytepp rp; /* points to current row */
 
+   png_debug(1, "in png_write_image\n");
    /* intialize interlace handling.  If image is not interlaced,
       this will set pass to 1 */
    num_pass = png_set_interlace_handling(png_ptr);
@@ -313,6 +339,7 @@
 void
 png_write_row(png_structp png_ptr, png_bytep row)
 {
+   png_debug(1, "in png_write_row\n");
    /* initialize transformations and other stuff if first time */
    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
    {
@@ -388,8 +415,15 @@
    png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
       (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
 
-   /* copy users row into buffer, leaving room for filter byte */
-   png_memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
+   png_debug1(4, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
+   png_debug1(4, "row_info->width = %d\n", png_ptr->row_info.width);
+   png_debug1(4, "row_info->channels = %d\n", png_ptr->row_info.channels);
+   png_debug1(4, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
+   png_debug1(4, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
+   png_debug1(4, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
+
+   /* Copy user's row into buffer, leaving room for filter byte. */
+   png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
 
 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
    /* handle interlacing */
@@ -411,7 +445,7 @@
    if (png_ptr->transformations)
       png_do_write_transformations(png_ptr);
 
-   /* find a filter if necessary, filter the row and write it out */
+   /* Find a filter if necessary, filter the row and write it out. */
    png_write_find_filter(png_ptr, &(png_ptr->row_info));
 }
 
@@ -420,6 +454,7 @@
 void
 png_set_flush(png_structp png_ptr, int nrows)
 {
+   png_debug(1, "in png_set_flush\n");
    png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
 }
 
@@ -429,6 +464,7 @@
 {
    int wrote_IDAT;
 
+   png_debug(1, "in png_write_flush\n");
    /* We have already written out all of the data */
    if (png_ptr->row_number >= png_ptr->num_rows)
      return;
@@ -444,13 +480,13 @@
       /* check for compression errors */
       if (ret != Z_OK)
       {
-         if (png_ptr->zstream.msg)
+         if (png_ptr->zstream.msg != NULL)
             png_error(png_ptr, png_ptr->zstream.msg);
          else
             png_error(png_ptr, "zlib error");
       }
 
-      if (!png_ptr->zstream.avail_out)
+      if (!(png_ptr->zstream.avail_out))
       {
          /* write the IDAT and reset the zlib output buffer */
          png_write_IDAT(png_ptr, png_ptr->zbuf,
@@ -482,19 +518,20 @@
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
 
-   if (png_ptr_ptr)
+   png_debug(1, "in png_destroy_write_struct\n");
+   if (png_ptr_ptr != NULL)
       png_ptr = *png_ptr_ptr;
 
-   if (info_ptr_ptr)
+   if (info_ptr_ptr != NULL)
       info_ptr = *info_ptr_ptr;
 
-   if (info_ptr)
+   if (info_ptr != NULL)
    {
       png_destroy_struct((png_voidp)info_ptr);
       *info_ptr_ptr = (png_infop)NULL;
    }
 
-   if (png_ptr)
+   if (png_ptr != NULL)
    {
       png_write_destroy(png_ptr);
       png_destroy_struct((png_voidp)png_ptr);
@@ -503,7 +540,7 @@
 }
 
 
-/* free any memory used in png struct (old method) */
+/* Free any memory used in png_ptr struct (old method) */
 void
 png_write_destroy(png_structp png_ptr)
 {
@@ -512,6 +549,7 @@
    png_error_ptr warning_fn;
    png_voidp error_ptr;
 
+   png_debug(1, "in png_write_destroy\n");
    /* free any memory zlib uses */
    deflateEnd(&png_ptr->zstream);
 
@@ -523,6 +561,13 @@
    png_free(png_ptr, png_ptr->up_row);
    png_free(png_ptr, png_ptr->avg_row);
    png_free(png_ptr, png_ptr->paeth_row);
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+   png_free(png_ptr, png_ptr->prev_filters);
+   png_free(png_ptr, png_ptr->filter_weights);
+   png_free(png_ptr, png_ptr->inv_filter_weights);
+   png_free(png_ptr, png_ptr->filter_costs);
+   png_free(png_ptr, png_ptr->inv_filter_costs);
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
 
    /* reset structure */
    png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
@@ -540,71 +585,79 @@
    png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
 }
 
-/* Allow the application to select one or more filters to use */
+/* Allow the application to select one or more row filters to use. */
 void
 png_set_filter(png_structp png_ptr, int method, int filters)
 {
-   /* We allow 'method' only for future expansion of the base filter method */
-   if (method == 0)
+   png_debug(1, "in png_set_filter\n");
+   /* We allow 'method' only for future expansion of the base filter method. */
+   if (method == PNG_FILTER_TYPE_BASE)
    {
       switch (filters & (PNG_ALL_FILTERS | 0x07))
       {
          case 5:
          case 6:
-         case 7: png_warning(png_ptr, "Unknown custom row filter for method 0");
-         case 0: png_ptr->do_filter = PNG_FILTER_NONE; break;
-         case 1: png_ptr->do_filter = PNG_FILTER_SUB; break;
-         case 2: png_ptr->do_filter = PNG_FILTER_UP; break;
-         case 3: png_ptr->do_filter = PNG_FILTER_AVG; break;
-         case 4: png_ptr->do_filter = PNG_FILTER_PAETH; break;
+         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+         case PNG_FILTER_VALUE_NONE:  png_ptr->do_filter=PNG_FILTER_NONE; break;
+         case PNG_FILTER_VALUE_SUB:   png_ptr->do_filter=PNG_FILTER_SUB;  break;
+         case PNG_FILTER_VALUE_UP:    png_ptr->do_filter=PNG_FILTER_UP;   break;
+         case PNG_FILTER_VALUE_AVG:   png_ptr->do_filter=PNG_FILTER_AVG;  break;
+         case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
          default: png_ptr->do_filter = (png_byte)filters; break;
       }
 
-      /* If we have allocated the row_buf, then we should have also allocated
-       * all of the filter buffers that have been selected.
+      /* If we have allocated the row_buf, this means we have already started
+       * with the image and we should have allocated all of the filter buffers
+       * that have been selected.  If prev_row isn't already allocated, then
+       * it is too late to start using the filters that need it, since we
+       * will be missing the data in the previous row.  If an application
+       * wants to start and stop using particular filters during compression,
+       * it should start out with all of the filters, and then add and
+       * remove them after the start of compression.
        */
-      if (png_ptr->row_buf)
+      if (png_ptr->row_buf != NULL)
       {
-         if (png_ptr->do_filter & PNG_FILTER_SUB && !(png_ptr->sub_row))
+         if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
          {
-            png_ptr->sub_row = (png_bytep )png_malloc(png_ptr,
+            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
                png_ptr->rowbytes + 1);
-            png_ptr->sub_row[0] = 1;  /* Set the row filter type */
+            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
          }
 
-         if (png_ptr->do_filter & PNG_FILTER_UP && !(png_ptr->up_row))
+         if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
          {
-            if (!(png_ptr->prev_row))
+            if (png_ptr->prev_row == NULL)
             {
-               png_warning(png_ptr, "Can't to add up filter after starting");
+               png_warning(png_ptr, "Can't add Up filter after starting");
                png_ptr->do_filter &= ~PNG_FILTER_UP;
             }
             else
             {
-               png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
                   png_ptr->rowbytes + 1);
-               png_ptr->up_row[0] = 2;  /* Set the row filter type */
+               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
             }
          }
 
-         if (png_ptr->do_filter & PNG_FILTER_AVG && !(png_ptr->avg_row))
+         if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
          {
-            if (!(png_ptr->prev_row))
+            if (png_ptr->prev_row == NULL)
             {
-               png_warning(png_ptr, "Can't add average filter after starting");
+               png_warning(png_ptr, "Can't add Average filter after starting");
                png_ptr->do_filter &= ~PNG_FILTER_AVG;
             }
             else
             {
-               png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
                   png_ptr->rowbytes + 1);
-               png_ptr->up_row[0] = 3;  /* Set the row filter type */
+               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
             }
          }
 
-         if (png_ptr->do_filter & PNG_FILTER_PAETH && !(png_ptr->paeth_row))
+         if (png_ptr->do_filter & PNG_FILTER_PAETH &&
+             png_ptr->paeth_row == NULL)
          {
-            if (!(png_ptr->prev_row))
+            if (png_ptr->prev_row == NULL)
             {
                png_warning(png_ptr, "Can't add Paeth filter after starting");
                png_ptr->do_filter &= ~PNG_FILTER_PAETH;
@@ -613,7 +666,7 @@
             {
                png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
                   png_ptr->rowbytes + 1);
-               png_ptr->paeth_row[0] = 4;  /* Set the row filter type */
+               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
             }
          }
 
@@ -622,12 +675,137 @@
       }
    }
    else
-     png_error(png_ptr, "Unknown custom filter method");
+      png_error(png_ptr, "Unknown custom filter method");
 }
 
+/* This allows us to influence the way in which libpng chooses the "best"
+ * filter for the current scanline.  While the "minimum-sum-of-absolute-
+ * differences metric is relatively fast and effective, there is some
+ * question as to whether it can be improved upon by trying to keep the
+ * filtered data going to zlib more consistent, hopefully resulting in
+ * better compression. */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
+void
+png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
+   int num_weights, png_doublep filter_weights,
+   png_doublep filter_costs)
+{
+   int i;
+
+   png_debug(1, "in png_set_filter_heuristics\n");
+   if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
+   {
+      png_warning(png_ptr, "Unknown filter heuristic method");
+      return;
+   }
+
+   if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
+   {
+      heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
+   }
+
+   if (num_weights < 0 || filter_weights == NULL ||
+      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
+   {
+      num_weights = 0;
+   }
+
+   png_ptr->num_prev_filters = num_weights;
+   png_ptr->heuristic_method = heuristic_method;
+
+   if (num_weights > 0)
+   {
+      if (png_ptr->prev_filters == NULL)
+      {
+         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
+            sizeof(png_byte) * num_weights);
+
+         /* To make sure that the weighting starts out fairly */
+         for (i = 0; i < num_weights; i++)
+         {
+            png_ptr->prev_filters[i] = 255;
+         }
+      }
+
+      if (png_ptr->filter_weights == NULL)
+      {
+         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
+            sizeof(png_uint_16) * num_weights);
+
+         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
+            sizeof(png_uint_16) * num_weights);
+
+         for (i = 0; i < num_weights; i++)
+         {
+            png_ptr->inv_filter_weights[i] =
+            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+         }
+      }
+
+      for (i = 0; i < num_weights; i++)
+      {
+         if (filter_weights[i] < 0.0)
+         {
+            png_ptr->inv_filter_weights[i] =
+            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+         }
+         else
+         {
+            png_ptr->inv_filter_weights[i] =
+               (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
+            png_ptr->filter_weights[i] =
+               (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
+         }
+      }
+   }
+
+   /* If, in the future, there are other filter methods, this would
+    * need to be based on png_ptr->filter.
+    */
+   if (png_ptr->filter_costs == NULL)
+   {
+      png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
+         sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
+
+      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
+         sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
+
+      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+      {
+         png_ptr->inv_filter_costs[i] =
+         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+      }
+   }
+
+   /* Here is where we set the relative costs of the different filters.  We
+    * should take the desired compression level into account when setting
+    * the costs, so that Paeth, for instance, has a high relative cost at low
+    * compression levels, while it has a lower relative cost at higher
+    * compression settings.  The filter types are in order of increasing
+    * relative cost, so it would be possible to do this with an algorithm.
+    */
+   for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+   {
+      if (filter_costs == NULL || filter_costs[i] < 0.0)
+      {
+         png_ptr->inv_filter_costs[i] =
+         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+      }
+      else if (filter_costs[i] >= 1.0)
+      {
+         png_ptr->inv_filter_costs[i] =
+            (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
+         png_ptr->filter_costs[i] =
+            (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
+      }
+   }
+}
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
 void
 png_set_compression_level(png_structp png_ptr, int level)
 {
+   png_debug(1, "in png_set_compression_level\n");
    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
    png_ptr->zlib_level = level;
 }
@@ -635,6 +813,7 @@
 void
 png_set_compression_mem_level(png_structp png_ptr, int mem_level)
 {
+   png_debug(1, "in png_set_compression_mem_level\n");
    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
    png_ptr->zlib_mem_level = mem_level;
 }
@@ -642,6 +821,7 @@
 void
 png_set_compression_strategy(png_structp png_ptr, int strategy)
 {
+   png_debug(1, "in png_set_compression_strategy\n");
    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
    png_ptr->zlib_strategy = strategy;
 }
@@ -658,6 +838,7 @@
 void
 png_set_compression_method(png_structp png_ptr, int method)
 {
+   png_debug(1, "in png_set_compression_method\n");
    if (method != 8)
       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
diff --git a/pngwtran.c b/pngwtran.c
index b31d24c..99d32a4 100644
--- a/pngwtran.c
+++ b/pngwtran.c
@@ -1,10 +1,11 @@
 
-/* pngwtran.c - transforms the data in a row for png writers
+/* pngwtran.c - transforms the data in a row for PNG writers
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   January 10, 1997
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
 
 #define PNG_INTERNAL
@@ -15,15 +16,16 @@
 void
 png_do_write_transformations(png_structp png_ptr)
 {
+   png_debug(1, "in png_do_write_transformations\n");
 #if defined(PNG_WRITE_FILLER_SUPPORTED)
    if (png_ptr->transformations & PNG_FILLER)
-      png_do_write_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+      png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
          png_ptr->flags);
 #endif
 #if defined(PNG_WRITE_PACK_SUPPORTED)
    if (png_ptr->transformations & PNG_PACK)
       png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
-         png_ptr->bit_depth);
+         (png_uint_32)png_ptr->bit_depth);
 #endif
 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
    if (png_ptr->transformations & PNG_SHIFT)
@@ -34,6 +36,10 @@
    if (png_ptr->transformations & PNG_SWAP_BYTES)
       png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+   if (png_ptr->transformations & PNG_SWAP_ALPHA)
+      png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
 #if defined(PNG_WRITE_BGR_SUPPORTED)
    if (png_ptr->transformations & PNG_BGR)
       png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
@@ -49,20 +55,22 @@
    row_info bit depth should be 8 (one pixel per byte).  The channels
    should be 1 (this only happens on grayscale and paletted images) */
 void
-png_do_pack(png_row_infop row_info, png_bytep row, png_byte bit_depth)
+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
 {
-   if (row_info && row && row_info->bit_depth == 8 &&
+   png_debug(1, "in png_do_pack\n");
+   if (row_info->bit_depth == 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+       row != NULL && row_info != NULL &&
+#endif
       row_info->channels == 1)
    {
-      switch (bit_depth)
+      switch ((int)bit_depth)
       {
          case 1:
          {
-            png_bytep sp;
-            png_bytep dp;
-            int mask;
-            png_int_32 i;
-            int v;
+            png_bytep sp, dp;
+            int mask, v;
+            png_uint_32 i;
 
             sp = row;
             dp = row;
@@ -70,7 +78,7 @@
             v = 0;
             for (i = 0; i < row_info->width; i++)
             {
-               if (*sp)
+               if (*sp != 0)
                   v |= mask;
                sp++;
                if (mask > 1)
@@ -89,12 +97,9 @@
          }
          case 2:
          {
-            png_bytep sp;
-            png_bytep dp;
-            int shift;
-            png_int_32 i;
-            int v;
-            png_byte value;
+            png_bytep sp, dp;
+            int shift, v;
+            png_uint_32 i;
 
             sp = row;
             dp = row;
@@ -102,6 +107,8 @@
             v = 0;
             for (i = 0; i < row_info->width; i++)
             {
+               png_byte value;
+
                value = (png_byte)(*sp & 0x3);
                v |= (value << shift);
                if (shift == 0)
@@ -121,12 +128,9 @@
          }
          case 4:
          {
-            png_bytep sp;
-            png_bytep dp;
-            int shift;
-            png_int_32 i;
-            int v;
-            png_byte value;
+            png_bytep sp, dp;
+            int shift, v;
+            png_uint_32 i;
 
             sp = row;
             dp = row;
@@ -134,6 +138,8 @@
             v = 0;
             for (i = 0; i < row_info->width; i++)
             {
+               png_byte value;
+
                value = (png_byte)(*sp & 0xf);
                v |= (value << shift);
 
@@ -154,8 +160,8 @@
             break;
          }
       }
-      row_info->bit_depth = bit_depth;
-      row_info->pixel_depth = (png_uint_16)(bit_depth * row_info->channels);
+      row_info->bit_depth = (png_byte)bit_depth;
+      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
       row_info->rowbytes =
          ((row_info->width * row_info->pixel_depth + 7) >> 3);
    }
@@ -172,11 +178,16 @@
 void
 png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
 {
-   if (row && row_info &&
+   png_debug(1, "in png_do_shift\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL &&
+#else
+   if (
+#endif
       row_info->color_type != PNG_COLOR_TYPE_PALETTE)
    {
       int shift_start[4], shift_dec[4];
-      int channels;
+      png_uint_32 channels;
 
       channels = 0;
       if (row_info->color_type & PNG_COLOR_MASK_COLOR)
@@ -209,7 +220,6 @@
       {
          png_bytep bp;
          png_uint_32 i;
-         int j;
          png_byte mask;
 
          if (bit_depth->gray == 1 && row_info->bit_depth == 2)
@@ -221,7 +231,8 @@
 
          for (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
          {
-            int v;
+            png_uint_16 v;
+            int j;
 
             v = *bp;
             *bp = 0;
@@ -238,7 +249,6 @@
       {
          png_bytep bp;
          png_uint_32 i;
-         int j;
 
          for (bp = row, i = 0; i < row_info->width; i++)
          {
@@ -246,7 +256,8 @@
 
             for (c = 0; c < channels; c++, bp++)
             {
-               int v;
+               png_uint_16 v;
+               int j;
 
                v = *bp;
                *bp = 0;
@@ -264,20 +275,17 @@
       {
          png_bytep bp;
          png_uint_32 i;
-         int j;
 
-         for (bp = row, i = 0;
-            i < row_info->width * row_info->channels;
-            i++)
+         for (bp = row, i = 0; i < row_info->width * row_info->channels; i++)
          {
             int c;
 
             for (c = 0; c < channels; c++, bp += 2)
             {
                png_uint_16 value, v;
+               int j;
 
-               v = (png_uint_16)(((png_uint_16)(*bp) << 8) +
-                  (png_uint_16)(*(bp + 1)));
+               v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
                value = 0;
                for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
                {
@@ -295,51 +303,88 @@
 }
 #endif
 
-#ifdef PNG_WRITE_FILLER_SUPPORTED
-/* remove filler byte */
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
 void
-png_do_write_filler(png_row_infop row_info, png_bytep row,
-   png_uint_32 flags)
+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
 {
-   if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
-      row_info->bit_depth == 8)
+   png_debug(1, "in png_do_write_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL)
+#endif
    {
-      if (flags & PNG_FLAG_FILLER_AFTER)
+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
       {
-         png_bytep sp, dp;
-
-         png_uint_32 i;
-
-         for (i = 1, sp = row + 4, dp = row + 3;
-            i < row_info->width;
-            i++)
+         /* This converts from ARGB to RGBA */
+         if (row_info->bit_depth == 8)
          {
-            *dp++ = *sp++;
-            *dp++ = *sp++;
-            *dp++ = *sp++;
-            sp++;
+            png_bytep sp, dp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row; i < row_info->width; i++)
+            {
+               save = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = save;
+            }
          }
-         row_info->channels = 3;
-         row_info->pixel_depth = 24;
-         row_info->rowbytes = row_info->width * 3;
+         /* This converts from AARRGGBB to RRGGBBAA */
+         else
+         {
+            png_bytep sp, dp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row; i < row_info->width; i++)
+            {
+               save[0] = *(sp++);
+               save[1] = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = save[0];
+               *(dp++) = save[1];
+            }
+         }
       }
-      else
+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
       {
-         png_bytep sp, dp;
-         png_uint_32 i;
-
-         for (i = 0, sp = row, dp = row;
-            i < row_info->width;
-            i++)
+         /* This converts from AG to GA */
+         if (row_info->bit_depth == 8)
          {
-            sp++;
-            *dp++ = *sp++;
-            *dp++ = *sp++;
-            *dp++ = *sp++;
+            png_bytep sp, dp;
+            png_byte save;
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row; i < row_info->width; i++)
+            {
+               save = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = save;
+            }
          }
-         row_info->channels = 3;
-         row_info->pixel_depth = 24;
-         row_info->rowbytes = row_info->width * 3;
+         /* This converts from AAGG to GGAA */
+         else
+         {
+            png_bytep sp, dp;
+            png_byte save[2];
+            png_uint_32 i;
+
+            for (i = 0, sp = dp = row; i < row_info->width; i++)
+            {
+               save[0] = *(sp++);
+               save[1] = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = *(sp++);
+               *(dp++) = save[0];
+               *(dp++) = save[1];
+            }
+         }
       }
    }
 }
diff --git a/pngwutil.c b/pngwutil.c
index 4adc1c9..5aec80c 100644
--- a/pngwutil.c
+++ b/pngwutil.c
@@ -1,17 +1,20 @@
 
-/* pngwutil.c - utilities to write a png file
+/* pngwutil.c - utilities to write a PNG file
 
-   libpng 1.0 beta 4 - version 0.90
+   libpng 1.0 beta 6 - version 0.96
    For conditions of distribution and use, see copyright notice in png.h
    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-   December 3, 1996
+   Copyright (c) 1996, 1997 Andreas Dilger
+   May 12, 1997
    */
+
 #define PNG_INTERNAL
 #include "png.h"
 
-/* place a 32 bit number into a buffer in png byte order.  We work
-   with unsigned numbers for convenience, you may have to cast
-   signed numbers (if you use any, most png data is unsigned). */
+/* Place a 32-bit number into a buffer in PNG byte order.  We work
+ * with unsigned numbers for convenience, although one supported
+ * ancillary chunk uses signed (two's complement) numbers.
+ */
 void
 png_save_uint_32(png_bytep buf, png_uint_32 i)
 {
@@ -21,7 +24,21 @@
    buf[3] = (png_byte)(i & 0xff);
 }
 
-/* place a 16 bit number into a buffer in png byte order */
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* The png_save_int_32 function assumes integers are stored in two's
+   complement format.  If this isn't the case, then this routine needs to
+   be modified to write data in two's complement format. */
+void
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+   buf[0] = (png_byte)((i >> 24) & 0xff);
+   buf[1] = (png_byte)((i >> 16) & 0xff);
+   buf[2] = (png_byte)((i >> 8) & 0xff);
+   buf[3] = (png_byte)(i & 0xff);
+}
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order. */
 void
 png_save_uint_16(png_bytep buf, png_uint_16 i)
 {
@@ -29,31 +46,7 @@
    buf[1] = (png_byte)(i & 0xff);
 }
 
-/* write a 32 bit number */
-void
-png_write_uint_32(png_structp png_ptr, png_uint_32 i)
-{
-   png_byte buf[4];
-
-   buf[0] = (png_byte)((i >> 24) & 0xff);
-   buf[1] = (png_byte)((i >> 16) & 0xff);
-   buf[2] = (png_byte)((i >> 8) & 0xff);
-   buf[3] = (png_byte)(i & 0xff);
-   png_write_data(png_ptr, buf, 4);
-}
-
-/* write a 16 bit number */
-void
-png_write_uint_16(png_structp png_ptr, png_uint_16 i)
-{
-   png_byte buf[2];
-
-   buf[0] = (png_byte)((i >> 8) & 0xff);
-   buf[1] = (png_byte)(i & 0xff);
-   png_write_data(png_ptr, buf, 2);
-}
-
-/* Write a png chunk all at once.  The type is an array of ASCII characters
+/* Write a PNG chunk all at once.  The type is an array of ASCII characters
    representing the chunk name.  The array must be at least 4 bytes in
    length, and does not need to be null terminated.  To be safe, pass the
    pre-defined chunk names here, and if you need a new one, define it
@@ -63,54 +56,63 @@
    functions instead.  */
 void
 png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
-   png_bytep data, png_uint_32 length)
+   png_bytep data, png_size_t length)
 {
-   png_write_chunk_start(png_ptr, chunk_name, length);
+   png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
    png_write_chunk_data(png_ptr, data, length);
    png_write_chunk_end(png_ptr);
 }
 
-/* Write the start of a png chunk.  The type is the chunk type.
+/* Write the start of a PNG chunk.  The type is the chunk type.
    The total_length is the sum of the lengths of all the data you will be
    passing in png_write_chunk_data() */
 void
 png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
    png_uint_32 length)
 {
+   png_byte buf[4];
+   png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);
+
    /* write the length */
-   png_write_uint_32(png_ptr, length);
+   png_save_uint_32(buf, length);
+   png_write_data(png_ptr, buf, (png_size_t)4);
+
    /* write the chunk name */
-   png_write_data(png_ptr, chunk_name, (png_uint_32)4);
+   png_write_data(png_ptr, chunk_name, (png_size_t)4);
    /* reset the crc and run it over the chunk name */
    png_reset_crc(png_ptr);
-   png_calculate_crc(png_ptr, chunk_name, (png_uint_32)4);
+   png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
 }
 
-/* write the data of a png chunk started with png_write_chunk_start().
+/* Write the data of a PNG chunk started with png_write_chunk_start().
    Note that multiple calls to this function are allowed, and that the
    sum of the lengths from these calls *must* add up to the total_length
-   given to png_write_chunk_start() */
+   given to png_write_chunk_start(). */
 void
-png_write_chunk_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-   /* write the data, and run the crc over it */
-   if (length)
+   /* write the data, and run the CRC over it */
+   if (data != NULL && length > 0)
    {
       png_calculate_crc(png_ptr, data, length);
       png_write_data(png_ptr, data, length);
    }
 }
 
-/* finish a chunk started with png_write_chunk_start() */
+/* Finish a chunk started with png_write_chunk_start(). */
 void
 png_write_chunk_end(png_structp png_ptr)
 {
+   png_byte buf[4];
+
    /* write the crc */
 #ifdef PNG_USE_OWN_CRC
-   png_write_uint_32(png_ptr, ~png_ptr->crc);
+   png_save_uint_32(buf, ~png_ptr->crc);
 #else
-   png_write_uint_32(png_ptr, png_ptr->crc);
+   png_save_uint_32(buf, png_ptr->crc);
 #endif
+
+   png_write_data(png_ptr, buf, (png_size_t)4);
 }
 
 /* Simple function to write the signature.  If we have already written
@@ -123,7 +125,7 @@
 {
    /* write the rest of the 8 byte signature */
    png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
-      (png_uint_32)8 - png_ptr->sig_bytes);
+      (png_size_t)8 - png_ptr->sig_bytes);
 }
 
 /* Write the IHDR chunk, and update the png_struct with the necessary
@@ -136,10 +138,11 @@
 {
    png_byte buf[13]; /* buffer to store the IHDR info */
 
+   png_debug(1, "in png_write_IHDR\n");
    /* Check that we have valid input data from the application info */
    switch (color_type)
    {
-      case 0:
+      case PNG_COLOR_TYPE_GRAY:
          switch (bit_depth)
          {
             case 1:
@@ -147,15 +150,15 @@
             case 4:
             case 8:
             case 16: png_ptr->channels = 1; break;
-            default: png_error(png_ptr, "Invalid bit depth for grayscale image");
+            default: png_error(png_ptr,"Invalid bit depth for grayscale image");
          }
          break;
-      case 2:
+      case PNG_COLOR_TYPE_RGB:
          if (bit_depth != 8 && bit_depth != 16)
             png_error(png_ptr, "Invalid bit depth for RGB image");
          png_ptr->channels = 3;
          break;
-      case 3:
+      case PNG_COLOR_TYPE_PALETTE:
          switch (bit_depth)
          {
             case 1:
@@ -165,12 +168,12 @@
             default: png_error(png_ptr, "Invalid bit depth for paletted image");
          }
          break;
-      case 4:
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
          if (bit_depth != 8 && bit_depth != 16)
             png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
          png_ptr->channels = 2;
          break;
-      case 6:
+      case PNG_COLOR_TYPE_RGB_ALPHA:
          if (bit_depth != 8 && bit_depth != 16)
             png_error(png_ptr, "Invalid bit depth for RGBA image");
          png_ptr->channels = 4;
@@ -179,22 +182,23 @@
          png_error(png_ptr, "Invalid image color type specified");
    }
 
-   if (compression_type != 0)
+   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
    {
       png_warning(png_ptr, "Invalid compression type specified");
-      compression_type = 0;
+      compression_type = PNG_COMPRESSION_TYPE_BASE;
    }
 
-   if (filter_type != 0)
+   if (filter_type != PNG_FILTER_TYPE_BASE)
    {
       png_warning(png_ptr, "Invalid filter type specified");
-      filter_type = 0;
+      filter_type = PNG_FILTER_TYPE_BASE;
    }
 
-   if (interlace_type != 0 && interlace_type != 1)
+   if (interlace_type != PNG_INTERLACE_NONE &&
+      interlace_type != PNG_INTERLACE_ADAM7)
    {
       png_warning(png_ptr, "Invalid interlace type specified");
-      interlace_type = 1;
+      interlace_type = PNG_INTERLACE_ADAM7;
    }
 
    /* save off the relevent information */
@@ -205,7 +209,7 @@
    png_ptr->height = height;
 
    png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
-   png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
+   png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
    /* set the usr info, so any transformations can modify it */
    png_ptr->usr_width = png_ptr->width;
    png_ptr->usr_bit_depth = png_ptr->bit_depth;
@@ -221,15 +225,16 @@
    buf[12] = (png_byte)interlace_type;
 
    /* write the chunk */
-   png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
+   png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
 
-   /* initialize zlib with png info */
+   /* initialize zlib with PNG info */
    png_ptr->zstream.zalloc = png_zalloc;
    png_ptr->zstream.zfree = png_zfree;
    png_ptr->zstream.opaque = (voidpf)png_ptr;
    if (!(png_ptr->do_filter))
    {
-      if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8)
+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+         png_ptr->bit_depth < 8)
          png_ptr->do_filter = PNG_FILTER_NONE;
       else
          png_ptr->do_filter = PNG_ALL_FILTERS;
@@ -250,10 +255,8 @@
    if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
       png_ptr->zlib_method = 8;
    deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
-      png_ptr->zlib_method,
-      png_ptr->zlib_window_bits,
-      png_ptr->zlib_mem_level,
-      png_ptr->zlib_strategy);
+      png_ptr->zlib_method, png_ptr->zlib_window_bits,
+      png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
    png_ptr->zstream.next_out = png_ptr->zbuf;
    png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
 
@@ -264,13 +267,14 @@
    correct order for PNG, so people can redefine it to any convient
    structure. */
 void
-png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 number)
+png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
 {
-   int i;
+   png_uint_32 i;
    png_colorp pal_ptr;
    png_byte buf[3];
 
-   if (number == 0 || number > 256)
+   png_debug(1, "in png_write_PLTE\n");
+   if (num_pal == 0 || num_pal > 256)
    {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
@@ -283,15 +287,16 @@
       }
    }
 
-   png_ptr->num_palette = number;
+   png_ptr->num_palette = (png_uint_16)num_pal;
+   png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
 
-   png_write_chunk_start(png_ptr, png_PLTE, number * 3);
-   for (i = 0, pal_ptr = palette; i < number; i++, pal_ptr++)
+   png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
+   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
    {
       buf[0] = pal_ptr->red;
       buf[1] = pal_ptr->green;
       buf[2] = pal_ptr->blue;
-      png_write_chunk_data(png_ptr, buf, (png_uint_32)3);
+      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
    }
    png_write_chunk_end(png_ptr);
    png_ptr->mode |= PNG_HAVE_PLTE;
@@ -299,8 +304,9 @@
 
 /* write an IDAT chunk */
 void
-png_write_IDAT(png_structp png_ptr, png_bytep data, png_uint_32 length)
+png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
 {
+   png_debug(1, "in png_write_IDAT\n");
    png_write_chunk(png_ptr, png_IDAT, data, length);
    png_ptr->mode |= PNG_HAVE_IDAT;
 }
@@ -309,22 +315,24 @@
 void
 png_write_IEND(png_structp png_ptr)
 {
-   png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
+   png_debug(1, "in png_write_IEND\n");
+   png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
    png_ptr->mode |= PNG_HAVE_IEND;
 }
 
 #if defined(PNG_WRITE_gAMA_SUPPORTED)
 /* write a gAMA chunk */
 void
-png_write_gAMA(png_structp png_ptr, double gamma)
+png_write_gAMA(png_structp png_ptr, double file_gamma)
 {
    png_uint_32 igamma;
    png_byte buf[4];
 
-   /* gamma is saved in 1/100,000ths */
-   igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
+   png_debug(1, "in png_write_gAMA\n");
+   /* file_gamma is saved in 1/100,000ths */
+   igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
    png_save_uint_32(buf, igamma);
-   png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
+   png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
 }
 #endif
 
@@ -334,8 +342,9 @@
 png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
 {
    png_byte buf[4];
-   int size;
+   png_size_t size;
 
+   png_debug(1, "in png_write_sBIT\n");
    /* make sure we don't depend upon the order of PNG_COLOR_8 */
    if (color_type & PNG_COLOR_MASK_COLOR)
    {
@@ -375,20 +384,21 @@
       buf[size++] = sbit->alpha;
    }
 
-   png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
+   png_write_chunk(png_ptr, png_sBIT, buf, size);
 }
 #endif
 
 #if defined(PNG_WRITE_cHRM_SUPPORTED)
 /* write the cHRM chunk */
 void
-png_write_cHRM ( png_structp png_ptr, double white_x, double white_y,
+png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
    double red_x, double red_y, double green_x, double green_y,
    double blue_x, double blue_y)
 {
    png_uint_32 itemp;
    png_byte buf[32];
 
+   png_debug(1, "in png_write_cHRM\n");
    /* each value is saved int 1/100,000ths */
    if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
        white_x + white_y > 1.0)
@@ -434,7 +444,7 @@
    itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
    png_save_uint_32(buf + 28, itemp);
 
-   png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32);
+   png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
 }
 #endif
 
@@ -446,6 +456,7 @@
 {
    png_byte buf[6];
 
+   png_debug(1, "in png_write_tRNS\n");
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
       if (num_trans <= 0 || num_trans > png_ptr->num_palette)
@@ -454,13 +465,13 @@
          return;
       }
       /* write the chunk out as it is */
-      png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)num_trans);
+      png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
    }
    else if (color_type == PNG_COLOR_TYPE_GRAY)
    {
       /* one 16 bit value */
       png_save_uint_16(buf, tran->gray);
-      png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)2);
+      png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
    }
    else if (color_type == PNG_COLOR_TYPE_RGB)
    {
@@ -468,7 +479,7 @@
       png_save_uint_16(buf, tran->red);
       png_save_uint_16(buf + 2, tran->green);
       png_save_uint_16(buf + 4, tran->blue);
-      png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)6);
+      png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
    }
    else
    {
@@ -484,6 +495,7 @@
 {
    png_byte buf[6];
 
+   png_debug(1, "in png_write_bKGD\n");
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
       if (back->index > png_ptr->num_palette)
@@ -492,19 +504,19 @@
          return;
       }
       buf[0] = back->index;
-      png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)1);
+      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
    }
    else if (color_type & PNG_COLOR_MASK_COLOR)
    {
       png_save_uint_16(buf, back->red);
       png_save_uint_16(buf + 2, back->green);
       png_save_uint_16(buf + 4, back->blue);
-      png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)6);
+      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
    }
    else
    {
       png_save_uint_16(buf, back->gray);
-      png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)2);
+      png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
    }
 }
 #endif
@@ -512,22 +524,25 @@
 #if defined(PNG_WRITE_hIST_SUPPORTED)
 /* write the histogram */
 void
-png_write_hIST(png_structp png_ptr, png_uint_16p hist, int number)
+png_write_hIST(png_structp png_ptr, png_uint_16p hist, png_uint_32 num_hist)
 {
-   int i;
+   png_uint_32 i;
    png_byte buf[3];
 
-   if (number <= 0 || number > png_ptr->num_palette)
+   png_debug(1, "in png_write_hIST\n");
+   if (num_hist > png_ptr->num_palette)
    {
+      png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
+         png_ptr->num_palette);
       png_warning(png_ptr, "Invalid number of histogram entries specified");
       return;
    }
 
-   png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2));
-   for (i = 0; i < number; i++)
+   png_write_chunk_start(png_ptr, png_hIST, num_hist * 2);
+   for (i = 0; i < num_hist; i++)
    {
       png_save_uint_16(buf, hist[i]);
-      png_write_chunk_data(png_ptr, buf, (png_uint_32)2);
+      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
    }
    png_write_chunk_end(png_ptr);
 }
@@ -539,20 +554,23 @@
  * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
  * length, forbids leading or trailing whitespace, multiple internal spaces,
  * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
+ *
+ * The new_key is allocated to hold the corrected keyword and must be freed
+ * by the calling routine.  This avoids problems with trying to write to
+ * static keywords without having to have duplicate copies of the strings.
  */
-#undef BROKEN_CHECK
-int
-png_check_keyword(png_structp png_ptr, png_charpp key)
+png_size_t
+png_check_keyword(png_structp png_ptr, png_charp key, png_bytepp new_key)
 {
+   png_size_t key_len;
    png_charp kp;
-   int key_len;
-#ifdef BROKEN_CHECK
-   png_charp np;
+   png_bytep dp;
    int kflag;
-   char newkey[80];
-#endif
 
-   if (*key == NULL || (key_len = png_strlen(*key)) == 0)
+   png_debug(1, "in png_check_keyword\n");
+   *new_key = NULL;
+
+   if (key == NULL || (key_len = png_strlen(key)) == 0)
    {
       char msg[40];
 
@@ -560,70 +578,104 @@
       png_warning(png_ptr, msg);
       return 0;
    }
-   else if (key_len > 79)
-   {
-      char msg[40];
 
-      sprintf(msg, "%s keyword length must be 1 - 79 characters",
-         png_ptr->chunk_name);
-      png_warning(png_ptr, msg);
-      (*key)[79] = '\0';
-      key_len = 79;
-   }
+   png_debug1(2, "Keyword to be checked is '%s'\n", key);
+
+   *new_key = (png_bytep)png_malloc(png_ptr, key_len + 1);
 
    /* Replace non-printing characters with a blank and print a warning */
-   for (kp = *key; *kp != '\0'; kp++)
+   for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
    {
-     if (*kp < 0x20 || ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
-     {
-       char msg[40];
+      if (*kp < 0x20 || ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
+      {
+         char msg[40];
 
-       sprintf(msg, "Invalid %s keyword character 0x%02X",
-          png_ptr->chunk_name, *kp);
-       png_warning(png_ptr, msg);
-       *kp = ' ';
-     }
+         sprintf(msg, "Invalid %s keyword character 0x%02X",
+            png_ptr->chunk_name, *kp);
+         png_warning(png_ptr, msg);
+         *dp = ' ';
+      }
+      else
+      {
+         *dp = *kp;
+      }
+   }
+   *dp = '\0';
+
+   /* Remove any trailing white space. */
+   kp = *new_key + key_len - 1;
+   if (*kp == ' ')
+   {
+      char msg[50];
+      sprintf(msg, "Trailing spaces removed from %s keyword",
+         png_ptr->chunk_name);
+
+      png_warning(png_ptr, msg);
+
+      while (*kp == ' ')
+      {
+        *(kp--) = '\0';
+        key_len--;
+      }
    }
 
    /* Remove any leading white space. */
-   while (**key == ' ')
+   kp = *new_key;
+   if (*kp == ' ')
    {
-     (*key)++;
-     key_len--;
+      char msg[50];
+      sprintf(msg, "Leading spaces removed from %s keyword",
+         png_ptr->chunk_name);
+
+      png_warning(png_ptr, msg);
+
+      while (*kp == ' ')
+      {
+        kp++;
+        key_len--;
+      }
    }
 
-   /* Remove any trailing white space. */
-   for (kp = *key + key_len - 1; *kp == ' '; key_len--)
-     *kp-- = '\0';
+   png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
 
-#ifdef BROKEN_CHECK
-   /* Remove multiple internal spaces.  This is currently broken for
-    * an unknown reason, and I didn't want to hold up the release of
-    * libpng-0.90 even longer to fix it. */
-   kflag = 0;
-   for (kp = *key, np = newkey; *kp; kp++)
+   /* Remove multiple internal spaces. */
+   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
    {
-      if (*kp != ' ')
+      if (*kp == ' ' && kflag == 0)
       {
-         *np++ = *kp;
-         kflag = 0;
+         *(dp++) = *kp;
+         kflag = 1;
       }
-      else if (kflag)
+      else if (*kp == ' ')
       {
          key_len--;
       }
       else
       {
-         *np++ = *kp;
-         kflag = 1;
+         *(dp++) = *kp;
+         kflag = 0;
       }
    }
-   *np = *kp;
-   png_strcpy(kp, np);
-#endif
+   *dp = '\0';
 
    if (key_len == 0)
-      png_warning(png_ptr, "Zero length tEXt keyword");
+   {
+      char msg[40];
+
+      sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
+      png_warning(png_ptr, msg);
+   }
+
+   if (key_len > 79)
+   {
+      char msg[50];
+
+      sprintf(msg, "%s keyword length must be 1 - 79 characters",
+         png_ptr->chunk_name);
+      png_warning(png_ptr, msg);
+      new_key[79] = '\0';
+      key_len = 79;
+   }
 
    return key_len;
 }
@@ -633,57 +685,91 @@
 /* write a tEXt chunk */
 void
 png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
-   png_uint_32 text_len)
+   png_size_t text_len)
 {
-   int key_len;
+   png_size_t key_len;
+   png_bytep new_key;
 
-   if (key == NULL || (key_len = png_check_keyword(png_ptr, &key)) == 0)
+   png_debug(1, "in png_write_tEXt\n");
+   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+   {
+      char msg[40];
+
+      sprintf(msg, "Empty keyword in %s chunk", "tEXt");
+      png_warning(png_ptr, msg);
       return;
+   }
 
-   if (text == NULL)
+   if (text == NULL || *text == '\0')
       text_len = 0;
 
    /* make sure we include the 0 after the key */
-   png_write_chunk_start(png_ptr, png_tEXt,
-      (png_uint_32)(key_len + text_len + 1));
-   png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
+   png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
+   png_write_chunk_data(png_ptr, new_key, key_len + 1);
    if (text_len)
-      png_write_chunk_data(png_ptr, (png_bytep )text, (png_uint_32)text_len);
+      png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
 
    png_write_chunk_end(png_ptr);
+   png_free(png_ptr, new_key);
 }
 #endif
 
 #if defined(PNG_WRITE_zTXt_SUPPORTED)
-/* write a compressed chunk */
+/* write a compressed text chunk */
 void
 png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
-   png_uint_32 text_len, int compression)
+   png_size_t text_len, int compression)
 {
-   int key_len;
+   png_size_t key_len;
    char buf[1];
+   png_bytep new_key;
    int i, ret;
    png_charpp output_ptr = NULL; /* array of pointers to output */
    int num_output_ptr = 0; /* number of output pointers used */
    int max_output_ptr = 0; /* size of output_ptr */
 
-   if (key == NULL || (key_len = png_check_keyword(png_ptr, &key)) == 0)
-      return;
+   png_debug(1, "in png_write_zTXt\n");
 
-   if (text == NULL)
-      text_len = 0;
-
-   if (compression != 0)
+   if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
    {
-      png_warning(png_ptr, "Only type 0 compression allowed for text\n");
-      compression = 0;
+      char msg[40];
+
+      sprintf(msg, "Empty keyword in %s chunk", "zTXt");
+      png_warning(png_ptr, msg);
+      return;
    }
 
-   /* we can't write the chunk until we find out how much data we have,
-      which means we need to run the compresser first, and save the
-      output.  This shouldn't be a problem, as the vast majority of
-      comments should be reasonable, but we will set up an array of
-      malloced pointers to be sure. */
+   if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
+   {
+      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
+      png_free(png_ptr, new_key);
+      return;
+   }
+
+   png_free(png_ptr, new_key);
+
+   if (compression >= PNG_TEXT_COMPRESSION_LAST)
+   {
+      char msg[50];
+      sprintf(msg, "Unknown zTXt compression type %d", compression);
+      png_warning(png_ptr, msg);
+      compression = PNG_TEXT_COMPRESSION_zTXt;
+   }
+
+   /* We can't write the chunk until we find out how much data we have,
+    * which means we need to run the compressor first, and save the
+    * output.  This shouldn't be a problem, as the vast majority of
+    * comments should be reasonable, but we will set up an array of
+    * malloc'd pointers to be sure.
+    *
+    * If we knew the application was well behaved, we could simplify this
+    * greatly by assuming we can always malloc an output buffer large
+    * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
+    * and malloc this directly.  The only time this would be a bad idea is
+    * if we can't malloc more than 64K and we have 64K of random input
+    * data, or if the input string is incredibly large (although this
+    * wouldn't cause a failure, just a slowdown due to swapping).
+    */
 
    /* set up the compression buffers */
    png_ptr->zstream.avail_in = (uInt)text_len;
@@ -699,7 +785,7 @@
       if (ret != Z_OK)
       {
          /* error */
-         if (png_ptr->zstream.msg)
+         if (png_ptr->zstream.msg != NULL)
             png_error(png_ptr, png_ptr->zstream.msg);
          else
             png_error(png_ptr, "zlib error");
@@ -710,19 +796,18 @@
          /* make sure the output array has room */
          if (num_output_ptr >= max_output_ptr)
          {
-            png_uint_32 old_max;
+            int old_max;
 
             old_max = max_output_ptr;
             max_output_ptr = num_output_ptr + 4;
-            if (output_ptr)
+            if (output_ptr != NULL)
             {
                png_charpp old_ptr;
 
                old_ptr = output_ptr;
                output_ptr = (png_charpp)png_malloc(png_ptr,
                   max_output_ptr * sizeof (png_charpp));
-               png_memcpy(output_ptr, old_ptr,
-                  (png_size_t)(old_max * sizeof (png_charp)));
+               png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
                png_free(png_ptr, old_ptr);
             }
             else
@@ -731,10 +816,9 @@
          }
 
          /* save the data */
-         output_ptr[num_output_ptr] = png_malloc(png_ptr,
-            png_ptr->zbuf_size);
+         output_ptr[num_output_ptr] = png_malloc(png_ptr, png_ptr->zbuf_size);
          png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
-            (png_size_t)png_ptr->zbuf_size);
+            png_ptr->zbuf_size);
          num_output_ptr++;
 
          /* and reset the buffer */
@@ -752,31 +836,31 @@
       if (ret != Z_OK && ret != Z_STREAM_END)
       {
          /* we got an error */
-         if (png_ptr->zstream.msg)
+         if (png_ptr->zstream.msg != NULL)
             png_error(png_ptr, png_ptr->zstream.msg);
          else
             png_error(png_ptr, "zlib error");
       }
 
       /* check to see if we need more room */
-      if (!png_ptr->zstream.avail_out && ret == Z_OK)
+      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
       {
          /* check to make sure our output array has room */
          if (num_output_ptr >= max_output_ptr)
          {
-            png_uint_32 old_max;
+            int old_max;
 
             old_max = max_output_ptr;
             max_output_ptr = num_output_ptr + 4;
-            if (output_ptr)
+            if (output_ptr != NULL)
             {
                png_charpp old_ptr;
 
                old_ptr = output_ptr;
+               /* This could be optimized to realloc() */
                output_ptr = (png_charpp)png_malloc(png_ptr,
                   max_output_ptr * sizeof (png_charpp));
-               png_memcpy(output_ptr, old_ptr,
-                  (png_size_t)(old_max * sizeof (png_charp)));
+               png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
                png_free(png_ptr, old_ptr);
             }
             else
@@ -788,7 +872,7 @@
          output_ptr[num_output_ptr] = png_malloc(png_ptr,
             png_ptr->zbuf_size);
          png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
-            (png_size_t)png_ptr->zbuf_size);
+            png_ptr->zbuf_size);
          num_output_ptr++;
 
          /* and reset the buffer pointers */
@@ -800,28 +884,26 @@
    /* text length is number of buffers plus last buffer */
    text_len = png_ptr->zbuf_size * num_output_ptr;
    if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
-      text_len += (png_uint_32)(png_ptr->zbuf_size -
-         png_ptr->zstream.avail_out);
+      text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
 
    /* write start of chunk */
-   png_write_chunk_start(png_ptr, png_zTXt,
-      (png_uint_32)(key_len + text_len + 2));
+   png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)(key_len+text_len+2));
    /* write key */
-   png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
+   png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
    buf[0] = (png_byte)compression;
    /* write compression */
-   png_write_chunk_data(png_ptr, (png_bytep )buf, (png_uint_32)1);
+   png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
 
    /* write saved output buffers, if any */
    for (i = 0; i < num_output_ptr; i++)
    {
-      png_write_chunk_data(png_ptr, (png_bytep )output_ptr[i], png_ptr->zbuf_size);
+      png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
       png_free(png_ptr, output_ptr[i]);
    }
-   if (max_output_ptr)
+   if (max_output_ptr != 0)
       png_free(png_ptr, output_ptr);
    /* write anything left in zbuf */
-   if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+   if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
       png_write_chunk_data(png_ptr, png_ptr->zbuf,
          png_ptr->zbuf_size - png_ptr->zstream.avail_out);
    /* close the chunk */
@@ -832,6 +914,83 @@
 }
 #endif
 
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+/* write the oFFs chunk */
+void
+png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
+   png_uint_32 y_offset,
+   int unit_type)
+{
+   png_byte buf[9];
+
+   png_debug(1, "in png_write_oFFs\n");
+   if (unit_type >= PNG_OFFSET_LAST)
+      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
+
+   png_save_uint_32(buf, x_offset);
+   png_save_uint_32(buf + 4, y_offset);
+   buf[8] = (png_byte)unit_type;
+
+   png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* write the pCAL chunk (png-scivis-19970203) */
+void
+png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
+   png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+{
+   png_size_t purpose_len, units_len, total_len; 
+   png_uint_32p params_len;
+   png_byte buf[10];
+   png_bytep new_purpose;
+   int i;
+
+   png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
+   if (type >= PNG_EQUATION_LAST)
+      png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+   png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
+   units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
+   png_debug1(3, "pCAL units length = %d\n", units_len);
+   total_len = purpose_len + units_len + 10;
+
+   params_len = (png_uint_32p)png_malloc(png_ptr, nparams*sizeof(png_uint_32));
+
+   /* Find the length of each parameter, making sure we don't count the
+      null terminator for the last parameter. */
+   for (i = 0; i < nparams; i++)
+   {
+      params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+      png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
+      total_len += (png_size_t)params_len[i];
+   }
+
+   png_debug1(3, "pCAL total length = %d\n", total_len);
+   png_write_chunk_start(png_ptr, png_pCAL, total_len);
+   png_write_chunk_data(png_ptr, new_purpose, purpose_len);
+   png_save_int_32(buf, X0);
+   png_save_int_32(buf + 4, X1);
+   buf[8] = (png_byte)type;
+   buf[9] = (png_byte)nparams;
+   png_write_chunk_data(png_ptr, buf, (png_size_t)10);
+   png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
+
+   png_free(png_ptr, new_purpose);
+
+   for (i = 0; i < nparams; i++)
+   {
+      png_write_chunk_data(png_ptr, (png_bytep)params[i],
+         (png_size_t)params_len[i]);
+   }
+
+   png_write_chunk_end(png_ptr);
+}
+#endif
+
 #if defined(PNG_WRITE_pHYs_SUPPORTED)
 /* write the pHYs chunk */
 void
@@ -841,6 +1000,7 @@
 {
    png_byte buf[9];
 
+   png_debug(1, "in png_write_pHYs\n");
    if (unit_type >= PNG_RESOLUTION_LAST)
       png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
 
@@ -848,27 +1008,7 @@
    png_save_uint_32(buf + 4, y_pixels_per_unit);
    buf[8] = (png_byte)unit_type;
 
-   png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
-}
-#endif
-
-#if defined(PNG_WRITE_oFFs_SUPPORTED)
-/* write the oFFs chunk */
-void
-png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
-   png_uint_32 y_offset,
-   int unit_type)
-{
-   png_byte buf[9];
-
-   if (unit_type >= PNG_OFFSET_LAST)
-      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
-
-   png_save_uint_32(buf, x_offset);
-   png_save_uint_32(buf + 4, y_offset);
-   buf[8] = (png_byte)unit_type;
-
-   png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
+   png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
 }
 #endif
 
@@ -880,6 +1020,7 @@
 {
    png_byte buf[7];
 
+   png_debug(1, "in png_write_tIME\n");
    if (mod_time->month  > 12 || mod_time->month  < 1 ||
        mod_time->day    > 31 || mod_time->day    < 1 ||
        mod_time->hour   > 23 || mod_time->second > 60)
@@ -895,7 +1036,7 @@
    buf[5] = mod_time->minute;
    buf[6] = mod_time->second;
 
-   png_write_chunk(png_ptr, png_tIME, buf, (png_uint_32)7);
+   png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
 }
 #endif
 
@@ -903,53 +1044,50 @@
 void
 png_write_start_row(png_structp png_ptr)
 {
+   png_size_t buf_size;
+
+   png_debug(1, "in png_write_start_row\n");
+   buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
+                            png_ptr->usr_bit_depth + 7) >> 3) + 1);
+
    /* set up row buffer */
-   png_ptr->row_buf = (png_bytep )png_malloc(png_ptr,
-      (((png_uint_32)png_ptr->usr_channels *
-      (png_uint_32)png_ptr->usr_bit_depth *
-      png_ptr->width + 7) >> 3) + 1);
-   png_ptr->row_buf[0] = 0;
+   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
+   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
 
    /* set up filtering buffer, if using this filter */
    if (png_ptr->do_filter & PNG_FILTER_SUB)
    {
-      png_ptr->sub_row = (png_bytep )png_malloc(png_ptr,
+      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
          png_ptr->rowbytes + 1);
-      png_ptr->sub_row[0] = 1;  /* Set the row filter type */
+      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
    }
 
-   /* We only need to keep the previous row if we are using one of these */
+   /* We only need to keep the previous row if we are using one of these. */
    if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
    {
      /* set up previous row buffer */
-      png_ptr->prev_row = (png_bytep )png_malloc(png_ptr,
-         (((png_uint_32)png_ptr->usr_channels *
-         (png_uint_32)png_ptr->usr_bit_depth *
-         png_ptr->width + 7) >> 3) + 1);
-      png_memset(png_ptr->prev_row, 0, 
-         (png_size_t)(((png_uint_32)png_ptr->usr_channels *
-         (png_uint_32)png_ptr->usr_bit_depth * 
-         png_ptr->width + 7) >> 3) + 1);
+      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, buf_size);
+      png_memset(png_ptr->prev_row, 0, buf_size);
 
       if (png_ptr->do_filter & PNG_FILTER_UP)
       {
          png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
             png_ptr->rowbytes + 1);
-         png_ptr->up_row[0] = 2;  /* Set the row filter type */
+         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
       }
 
       if (png_ptr->do_filter & PNG_FILTER_AVG)
       {
          png_ptr->avg_row = (png_bytep )png_malloc(png_ptr,
             png_ptr->rowbytes + 1);
-         png_ptr->avg_row[0] = 3;  /* Set the row filter type */
+         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
       }
 
       if (png_ptr->do_filter & PNG_FILTER_PAETH)
       {
          png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
             png_ptr->rowbytes + 1);
-         png_ptr->paeth_row[0] = 4;  /* Set the row filter type */
+         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
       }
    }
 
@@ -960,10 +1098,8 @@
       {
          png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
             png_pass_ystart[0]) / png_pass_yinc[0];
-         png_ptr->usr_width = (png_ptr->width +
-            png_pass_inc[0] - 1 -
-            png_pass_start[0]) /
-            png_pass_inc[0];
+         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
+            png_pass_start[0]) / png_pass_inc[0];
       }
       else
       {
@@ -980,12 +1116,13 @@
    png_ptr->zstream.next_out = png_ptr->zbuf;
 }
 
-/* Internal use only.   Called when finished processing a row of data */
+/* Internal use only.  Called when finished processing a row of data. */
 void
 png_write_finish_row(png_structp png_ptr)
 {
    int ret;
 
+   png_debug(1, "in png_write_finish_row\n");
    /* next row */
    png_ptr->row_number++;
 
@@ -1026,7 +1163,7 @@
       /* reset the row above the image for the next pass */
       if (png_ptr->pass < 7)
       {
-         if (png_ptr->prev_row)
+         if (png_ptr->prev_row != NULL)
             png_memset(png_ptr->prev_row, 0, 
                (png_size_t) (((png_uint_32)png_ptr->usr_channels *
                (png_uint_32)png_ptr->usr_bit_depth *
@@ -1044,13 +1181,13 @@
       /* check for an error */
       if (ret != Z_OK && ret != Z_STREAM_END)
       {
-         if (png_ptr->zstream.msg)
+         if (png_ptr->zstream.msg != NULL)
             png_error(png_ptr, png_ptr->zstream.msg);
          else
             png_error(png_ptr, "zlib error");
       }
       /* check to see if we need more room */
-      if (!png_ptr->zstream.avail_out && ret == Z_OK)
+      if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
       {
          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
          png_ptr->zstream.next_out = png_ptr->zbuf;
@@ -1080,8 +1217,13 @@
 void
 png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
 {
+   png_debug(1, "in png_do_write_interlace\n");
    /* we don't have to do anything on the last pass (6) */
-   if (row && row_info && pass < 6)
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+   if (row != NULL && row_info != NULL && pass < 6)
+#else
+   if (pass < 6)
+#endif
    {
       /* each pixel depth is handled seperately */
       switch (row_info->pixel_depth)
@@ -1098,8 +1240,7 @@
             dp = row;
             d = 0;
             shift = 7;
-            for (i = png_pass_start[pass];
-               i < row_info->width;
+            for (i = png_pass_start[pass]; i < row_info->width;
                i += png_pass_inc[pass])
             {
                sp = row + (png_size_t)(i >> 3);
@@ -1132,8 +1273,7 @@
             dp = row;
             shift = 6;
             d = 0;
-            for (i = png_pass_start[pass];
-               i < row_info->width;
+            for (i = png_pass_start[pass]; i < row_info->width;
                i += png_pass_inc[pass])
             {
                sp = row + (png_size_t)(i >> 2);
@@ -1165,8 +1305,7 @@
             dp = row;
             shift = 4;
             d = 0;
-            for (i = png_pass_start[pass];
-               i < row_info->width;
+            for (i = png_pass_start[pass]; i < row_info->width;
                i += png_pass_inc[pass])
             {
                sp = row + (png_size_t)(i >> 1);
@@ -1190,7 +1329,8 @@
          {
             png_bytep sp;
             png_bytep dp;
-            png_uint_32 i, pixel_bytes;
+            png_uint_32 i;
+            png_size_t pixel_bytes;
 
             /* start at the beginning */
             dp = row;
@@ -1198,12 +1338,11 @@
             pixel_bytes = (row_info->pixel_depth >> 3);
             /* loop through the row, only looking at the pixels that
                matter */
-            for (i = png_pass_start[pass];
-               i < row_info->width;
+            for (i = png_pass_start[pass]; i < row_info->width;
                i += png_pass_inc[pass])
             {
                /* find out where the original pixel is */
-               sp = row + (png_size_t)(i * pixel_bytes);
+               sp = row + i * pixel_bytes;
                /* move the pixel */
                if (dp != sp)
                   png_memcpy(dp, sp, pixel_bytes);
@@ -1225,41 +1364,90 @@
 }
 #endif
 
-/* this filters the row, chooses which filter to use, if it has not already
- * been given by the application, and then writes the row out with the
- * chosen filter */
+/* This filters the row, chooses which filter to use, if it has not already
+ * been specified by the application, and then writes the row out with the
+ * chosen filter. */
+#define PNG_MAXSUM (~0x0UL >> 1)
+#define PNG_HISHIFT 10
+#define PNG_LOMASK 0xffffL
+#define PNG_HIMASK (~PNG_LOMASK >> PNG_HISHIFT)
 void
 png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
 {
    png_bytep prev_row, best_row, row_buf;
-   png_uint_32 mins;
-   int bpp;
+   png_uint_32 mins, bpp;
 
+   png_debug(1, "in png_write_find_filter\n");
    /* find out how many bytes offset each pixel is */
    bpp = (row_info->pixel_depth + 7) / 8;
 
    prev_row = png_ptr->prev_row;
    best_row = row_buf = png_ptr->row_buf;
-   mins = 0xffffffff;
+   mins = PNG_MAXSUM;
 
-   /* the prediction method we use is to find which method provides
-      the smallest value when summing the abs of the distances from
-      zero using anything >= 128 as negitive numbers. */
+   /* The prediction method we use is to find which method provides the
+    * smallest value when summing the absolute values of the distances
+    * from zero using anything >= 128 as negative numbers.  This is known
+    * as the "minimum sum of absolute differences" heuristic.  Other
+    * heruistics are the "weighted minumum sum of absolute differences"
+    * (experimental and can in theory improve compression), and the "zlib
+    * predictive" method (not implemented in libpng 0.95), which does test
+    * compressions of lines using different filter methods, and then chooses
+    * the (series of) filter(s) which give minimum compressed data size (VERY
+    * computationally expensive).
+    */
 
    /* We don't need to test the 'no filter' case if this is the only filter
-    * that has been chosen, as it doesn't actually do anything to the data. */
+    * that has been chosen, as it doesn't actually do anything to the data.
+    */
    if (png_ptr->do_filter & PNG_FILTER_NONE &&
        png_ptr->do_filter != PNG_FILTER_NONE)
    {
       png_bytep rp;
       png_uint_32 sum = 0;
-      int i, v;
+      png_size_t i;
+      int v;
 
       for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
       {
          v = *rp;
          sum += (v < 128) ? v : 256 - v;
       }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 sumhi, sumlo;
+         sumlo = sum & PNG_LOMASK;
+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
+
+         /* Reduce the sum if we match any of the previous rows */
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
+            {
+               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         /* Factor in the cost of this filter (this is here for completeness,
+          * but it makes no sense to have a "cost" for the NONE filter, as
+          * it has the minimum possible computational cost - none).
+          */
+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+            PNG_COST_SHIFT;
+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+            PNG_COST_SHIFT;
+
+         if (sumhi > PNG_HIMASK)
+            sum = PNG_MAXSUM;
+         else
+            sum = (sumhi << PNG_HISHIFT) + sumlo;
+      }
+#endif
       mins = sum;
    }
 
@@ -1267,8 +1455,43 @@
    if (png_ptr->do_filter & PNG_FILTER_SUB)
    {
       png_bytep rp, dp, lp;
-      png_uint_32 sum = 0;
-      int i, v;
+      png_uint_32 sum = 0, lmins = mins;
+      png_size_t i;
+      int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      /* We temporarily increase the "minumum sum" by the factor we
+       * would reduce the sum of this filter, so that we can do the
+       * early exit comparison without scaling the sum each time.
+       */
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 lmhi, lmlo;
+         lmlo = lmins & PNG_LOMASK;
+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
+            {
+               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+            PNG_COST_SHIFT;
+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+            PNG_COST_SHIFT;
+
+         if (lmhi > PNG_HIMASK)
+            lmins = PNG_MAXSUM;
+         else
+            lmins = (lmhi << PNG_HISHIFT) + lmlo;
+      }
+#endif
 
       for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
            i++, rp++, dp++)
@@ -1282,7 +1505,41 @@
          v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
 
          sum += (v < 128) ? v : 256 - v;
+
+         if (sum > lmins)  /* We are already worse, don't continue. */
+            break;
       }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 sumhi, sumlo;
+         sumlo = sum & PNG_LOMASK;
+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
+            {
+               sumlo = (sumlo * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               sumhi = (sumhi * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+            PNG_COST_SHIFT;
+         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+            PNG_COST_SHIFT;
+
+         if (sumhi > PNG_HIMASK)
+            sum = PNG_MAXSUM;
+         else
+            sum = (sumhi << PNG_HISHIFT) + sumlo;
+      }
+#endif
+
       if (sum < mins)
       {
          mins = sum;
@@ -1294,8 +1551,39 @@
    if (png_ptr->do_filter & PNG_FILTER_UP)
    {
       png_bytep rp, dp, pp;
-      png_uint_32 sum = 0;
-      int i, v;
+      png_uint_32 sum = 0, lmins = mins;
+      png_size_t i;
+      int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 lmhi, lmlo;
+         lmlo = lmins & PNG_LOMASK;
+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_UP)
+            {
+               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+            PNG_COST_SHIFT;
+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+            PNG_COST_SHIFT;
+
+         if (lmhi > PNG_HIMASK)
+            lmins = PNG_MAXSUM;
+         else
+            lmins = (lmhi << PNG_HISHIFT) + lmlo;
+      }
+#endif
 
       for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
            pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
@@ -1303,7 +1591,41 @@
          v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
 
          sum += (v < 128) ? v : 256 - v;
+
+         if (sum > lmins)  /* We are already worse, don't continue. */
+            break;
       }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 sumhi, sumlo;
+         sumlo = sum & PNG_LOMASK;
+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_UP)
+            {
+               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+            PNG_COST_SHIFT;
+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+            PNG_COST_SHIFT;
+
+         if (sumhi > PNG_HIMASK)
+            sum = PNG_MAXSUM;
+         else
+            sum = (sumhi << PNG_HISHIFT) + sumlo;
+      }
+#endif
+
       if (sum < mins)
       {
          mins = sum;
@@ -1315,8 +1637,39 @@
    if (png_ptr->do_filter & PNG_FILTER_AVG)
    {
       png_bytep rp, dp, pp, lp;
-      png_uint_32 sum = 0;
-      int i, v;
+      png_uint_32 sum = 0, lmins = mins;
+      png_size_t i;
+      int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 lmhi, lmlo;
+         lmlo = lmins & PNG_LOMASK;
+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_AVG)
+            {
+               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+            PNG_COST_SHIFT;
+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+            PNG_COST_SHIFT;
+
+         if (lmhi > PNG_HIMASK)
+            lmins = PNG_MAXSUM;
+         else
+            lmins = (lmhi << PNG_HISHIFT) + lmlo;
+      }
+#endif
 
       for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
            pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
@@ -1331,7 +1684,41 @@
          v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
 
          sum += (v < 128) ? v : 256 - v;
+
+         if (sum > lmins)  /* We are already worse, don't continue. */
+            break;
       }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 sumhi, sumlo;
+         sumlo = sum & PNG_LOMASK;
+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
+            {
+               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+            PNG_COST_SHIFT;
+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+            PNG_COST_SHIFT;
+
+         if (sumhi > PNG_HIMASK)
+            sum = PNG_MAXSUM;
+         else
+            sum = (sumhi << PNG_HISHIFT) + sumlo;
+      }
+#endif
+
       if (sum < mins)
       {
          mins = sum;
@@ -1339,12 +1726,43 @@
       }
    }
 
-   /* paeth filter */
+   /* Paeth filter */
    if (png_ptr->do_filter & PNG_FILTER_PAETH)
    {
       png_bytep rp, dp, pp, cp, lp;
-      png_uint_32 sum = 0;
-      int i, v;
+      png_uint_32 sum = 0, lmins = mins;
+      png_size_t i;
+      int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 lmhi, lmlo;
+         lmlo = lmins & PNG_LOMASK;
+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_PAETH)
+            {
+               lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+            PNG_COST_SHIFT;
+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+            PNG_COST_SHIFT;
+
+         if (lmhi > PNG_HIMASK)
+            lmins = PNG_MAXSUM;
+         else
+            lmins = (lmhi << PNG_HISHIFT) + lmlo;
+      }
+#endif
 
       for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
            pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
@@ -1377,22 +1795,72 @@
          v = *dp = (png_byte)(((int)*rp - p) & 0xff);
 
          sum += (v < 128) ? v : 256 - v;
+
+         if (sum > lmins)  /* We are already worse, don't continue. */
+            break;
       }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+      {
+         png_uint_32 sumhi, sumlo;
+         sumlo = sum & PNG_LOMASK;
+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+         for (i = 0; i < png_ptr->num_prev_filters; i++)
+         {
+            if (png_ptr->prev_filters[i] == PNG_FILTER_PAETH)
+            {
+               sumlo = (sumlo * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+               sumhi = (sumhi * png_ptr->filter_weights[i]) >>
+                  PNG_WEIGHT_SHIFT;
+            }
+         }
+
+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+            PNG_COST_SHIFT;
+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+            PNG_COST_SHIFT;
+
+         if (sumhi > PNG_HIMASK)
+            sum = PNG_MAXSUM;
+         else
+            sum = (sumhi << PNG_HISHIFT) + sumlo;
+      }
+#endif
+
       if (sum < mins)
       {
          best_row = png_ptr->paeth_row;
       }
    }
 
-   /* Do the actual writing of the filtered row data from the chosen filter */
+   /* Do the actual writing of the filtered row data from the chosen filter. */
    png_write_filtered_row(png_ptr, best_row);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+   /* Save the type of filter we picked this time for future calculations */
+   if (png_ptr->num_prev_filters > 0)
+   {
+      png_byte i;
+
+      for (i = 1; i < png_ptr->num_prev_filters; i++)
+      {
+         png_ptr->prev_filters[i] = png_ptr->prev_filters[i - 1];
+      }
+      png_ptr->prev_filters[i] = best_row[0];
+   }
+#endif
 }
 
 
-/* do the actual writing of a filtered row */
+/* Do the actual writing of a previously filtered row. */
 void
 png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
 {
+   png_debug(1, "in png_write_filtered_row\n");
+   png_debug1(2, "filter = %d\n", filtered_row[0]);
    /* set up the zlib input buffer */
    png_ptr->zstream.next_in = filtered_row;
    png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
@@ -1406,14 +1874,14 @@
       /* check for compression errors */
       if (ret != Z_OK)
       {
-         if (png_ptr->zstream.msg)
+         if (png_ptr->zstream.msg != NULL)
             png_error(png_ptr, png_ptr->zstream.msg);
          else
             png_error(png_ptr, "zlib error");
       }
 
       /* see if it is time to write another IDAT */
-      if (!png_ptr->zstream.avail_out)
+      if (!(png_ptr->zstream.avail_out))
       {
          /* write the IDAT and reset the zlib output buffer */
          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
@@ -1424,7 +1892,7 @@
    } while (png_ptr->zstream.avail_in);
 
    /* swap the current and previous rows */
-   if (png_ptr->prev_row)
+   if (png_ptr->prev_row != NULL)
    {
       png_bytep tptr;