Imported from libpng-0.96.tar
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;