Imported Upstream version 1.6.21
[platform/upstream/libpng.git] / contrib / libtests / pngvalid.c
index e8401c9..55d0945 100644 (file)
@@ -1,8 +1,8 @@
 
 /* pngvalid.c - validate libpng by constructing then reading png files.
  *
- * Last changed in libpng 1.6.10 [March 6, 2014]
- * Copyright (c) 2014 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.21 [January 15, 2016]
+ * Copyright (c) 2014-2016 Glenn Randers-Pehrson
  * Written by John Cunningham Bowler
  *
  * This code is released under the libpng license.
 #  include <fenv.h>
 #endif
 
+#ifndef FE_DIVBYZERO
+#  define FE_DIVBYZERO 0
+#endif
+#ifndef FE_INVALID
+#  define FE_INVALID 0
+#endif
+#ifndef FE_OVERFLOW
+#  define FE_OVERFLOW 0
+#endif
+
 /* Define the following to use this test against your installed libpng, rather
  * than the one being built here:
  */
@@ -64,7 +74,7 @@
    (defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED))
 
 #if PNG_LIBPNG_VER < 10500
-/* This deliberately lacks the PNG_CONST. */
+/* This deliberately lacks the const. */
 typedef png_byte *png_const_bytep;
 
 /* This is copied from 1.5.1 png.h: */
@@ -106,6 +116,16 @@ typedef png_byte *png_const_bytep;
 #  define png_const_structp png_structp
 #endif
 
+#ifndef RELEASE_BUILD
+   /* RELEASE_BUILD is true for releases and release candidates: */
+#  define RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC)
+#endif
+#if RELEASE_BUILD
+#   define debugonly(something)
+#else /* !RELEASE_BUILD */
+#   define debugonly(something) something
+#endif /* !RELEASE_BUILD */
+
 #include <float.h>  /* For floating point constants */
 #include <stdlib.h> /* For malloc */
 #include <string.h> /* For memcpy, memset */
@@ -147,6 +167,31 @@ define_exception_type(struct png_store*);
    &(ps)->exception_context
 #define context(ps,fault) anon_context(ps); png_store *fault
 
+/* This macro returns the number of elements in an array as an (unsigned int),
+ * it is necessary to avoid the inability of certain versions of GCC to use
+ * the value of a compile-time constant when performing range checks.  It must
+ * be passed an array name.
+ */
+#define ARRAY_SIZE(a) ((unsigned int)((sizeof (a))/(sizeof (a)[0])))
+
+/* GCC BUG 66447 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66447) requires
+ * some broken GCC versions to be fixed up to avoid invalid whining about auto
+ * variables that are *not* changed within the scope of a setjmp being changed.
+ *
+ * Feel free to extend the list of broken versions.
+ */
+#define is_gnu(major,minor)\
+   (defined __GNUC__) && __GNUC__ == (major) && __GNUC_MINOR__ == (minor)
+#define is_gnu_patch(major,minor,patch)\
+   is_gnu(major,minor) && __GNUC_PATCHLEVEL__ == 0
+/* For the moment just do it always; all versions of GCC seem to be broken: */
+#ifdef __GNUC__
+   const void * volatile make_volatile_for_gnu;
+#  define gnu_volatile(x) make_volatile_for_gnu = &x;
+#else /* !GNUC broken versions */
+#  define gnu_volatile(x)
+#endif /* !GNUC broken versions */
+
 /******************************* UTILITIES ************************************/
 /* Error handling is particularly problematic in production code - error
  * handlers often themselves have bugs which lead to programs that detect
@@ -155,7 +200,7 @@ define_exception_type(struct png_store*);
  * warning messages into buffers that are too small.
  */
 static size_t safecat(char *buffer, size_t bufsize, size_t pos,
-   PNG_CONST char *cat)
+   const char *cat)
 {
    while (pos < bufsize && cat != NULL && *cat != 0)
       buffer[pos++] = *cat++;
@@ -184,16 +229,16 @@ static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d,
 }
 #endif
 
-static PNG_CONST char invalid[] = "invalid";
-static PNG_CONST char sep[] = ": ";
+static const char invalid[] = "invalid";
+static const char sep[] = ": ";
 
-static PNG_CONST char *colour_types[8] =
+static const char *colour_types[8] =
 {
    "grayscale", invalid, "truecolour", "indexed-colour",
    "grayscale with alpha", invalid, "truecolour with alpha", invalid
 };
 
-#ifdef PNG_READ_SUPPORTED
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* Convert a double precision value to fixed point. */
 static png_fixed_point
 fix(double d)
@@ -241,7 +286,8 @@ make_four_random_bytes(png_uint_32* seed, png_bytep bytes)
    make_random_bytes(seed, bytes, 4);
 }
 
-#ifdef PNG_READ_SUPPORTED
+#if defined PNG_READ_SUPPORTED || defined PNG_WRITE_tRNS_SUPPORTED ||\
+    defined PNG_WRITE_FILTER_SUPPORTED
 static void
 randomize(void *pv, size_t size)
 {
@@ -249,35 +295,85 @@ randomize(void *pv, size_t size)
    make_random_bytes(random_seed, pv, size);
 }
 
-#define RANDOMIZE(this) randomize(&(this), sizeof (this))
+#define R8(this) randomize(&(this), sizeof (this))
+
+static void r16(png_uint_16p p16, size_t count)
+{
+   size_t i;
+
+   for (i=0; i<count; ++i)
+   {
+      unsigned char b2[2];
+      randomize(b2, sizeof b2);
+      *p16++ = png_get_uint_16(b2);
+   }
+}
+
+#ifdef __COVERITY__
+#  define R16(this)\
+   r16(&(this), (sizeof (this))/2U/*(sizeof (png_uint_16))*/)
+#else
+#  define R16(this)\
+   r16(&(this), (sizeof (this))/(sizeof (png_uint_16)))
+#endif
+
+#if defined PNG_READ_RGB_TO_GRAY_SUPPORTED ||\
+    defined PNG_READ_FILLER_SUPPORTED
+static void r32(png_uint_32p p32, size_t count)
+{
+   size_t i;
+
+   for (i=0; i<count; ++i)
+   {
+      unsigned char b4[4];
+      randomize(b4, sizeof b4);
+      *p32++ = png_get_uint_32(b4);
+   }
+}
+
+#ifdef __COVERITY__
+#  define R32(this)\
+   r32(&(this), (sizeof (this))/4U/*(sizeof (png_uint_32))*/)
+#else
+#  define R32(this)\
+   r32(&(this), (sizeof (this))/(sizeof (png_uint_32)))
+#endif
+
+#endif /* READ_FILLER || READ_RGB_TO_GRAY */
+
+#endif /* READ || WRITE_tRNS || WRITE_FILTER */
 
+#if defined PNG_READ_TRANSFORMS_SUPPORTED ||\
+    defined PNG_WRITE_FILTER_SUPPORTED
 static unsigned int
 random_mod(unsigned int max)
 {
-   unsigned int x;
+   png_uint_16 x;
 
-   RANDOMIZE(x);
+   R16(x);
 
    return x % max; /* 0 .. max-1 */
 }
+#endif /* READ_TRANSFORMS || WRITE_FILTER */
 
-#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+#if (defined PNG_READ_RGB_TO_GRAY_SUPPORTED) ||\
+    (defined PNG_READ_FILLER_SUPPORTED)
 static int
 random_choice(void)
 {
    unsigned char x;
 
-   RANDOMIZE(x);
+   R8(x);
 
    return x & 1;
 }
-#endif
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ_RGB_TO_GRAY || READ_FILLER */
 
 /* A numeric ID based on PNG file characteristics.  The 'do_interlace' field
  * simply records whether pngvalid did the interlace itself or whether it
  * was done by libpng.  Width and height must be less than 256.  'palette' is an
- * index of the palette to use for formats with a palette (0 otherwise.)
+ * index of the palette to use for formats with a palette otherwise a boolean
+ * indicating if a tRNS chunk was generated.
  */
 #define FILEID(col, depth, palette, interlace, width, height, do_interlace) \
    ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \
@@ -286,7 +382,7 @@ random_choice(void)
 #define COL_FROM_ID(id) ((png_byte)((id)& 0x7U))
 #define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU))
 #define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f)
-#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3))
+#define INTERLACE_FROM_ID(id) ((png_byte)(((id) >> 13) & 0x3))
 #define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1))
 #define WIDTH_FROM_ID(id) (((id)>>16) & 0xff)
 #define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff)
@@ -298,12 +394,16 @@ standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type,
     png_uint_32 w, png_uint_32 h, int do_interlace)
 {
    pos = safecat(buffer, bufsize, pos, colour_types[colour_type]);
-   if (npalette > 0)
+   if (colour_type == 3) /* must have a palette */
    {
       pos = safecat(buffer, bufsize, pos, "[");
       pos = safecatn(buffer, bufsize, pos, npalette);
       pos = safecat(buffer, bufsize, pos, "]");
    }
+
+   else if (npalette != 0)
+      pos = safecat(buffer, bufsize, pos, "+tRNS");
+
    pos = safecat(buffer, bufsize, pos, " ");
    pos = safecatn(buffer, bufsize, pos, bit_depth);
    pos = safecat(buffer, bufsize, pos, " bit");
@@ -360,25 +460,32 @@ standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
 
 static int
 next_format(png_bytep colour_type, png_bytep bit_depth,
-   unsigned int* palette_number, int no_low_depth_gray)
+   unsigned int* palette_number, int low_depth_gray, int tRNS)
 {
    if (*bit_depth == 0)
    {
       *colour_type = 0;
-      if (no_low_depth_gray)
-         *bit_depth = 8;
-      else
+      if (low_depth_gray)
          *bit_depth = 1;
+      else
+         *bit_depth = 8;
       *palette_number = 0;
       return 1;
    }
 
-   if (*colour_type == 3)
+   if  (*colour_type < 4/*no alpha channel*/)
    {
-      /* Add multiple palettes for colour type 3. */
-      if (++*palette_number < PALETTE_COUNT(*bit_depth))
+      /* Add multiple palettes for colour type 3, one image with tRNS
+       * and one without for other non-alpha formats:
+       */
+      unsigned int pn = ++*palette_number;
+      png_byte ct = *colour_type;
+
+      if (((ct == 0/*GRAY*/ || ct/*RGB*/ == 2) && tRNS && pn < 2) ||
+          (ct == 3/*PALETTE*/ && pn < PALETTE_COUNT(*bit_depth)))
          return 1;
 
+      /* No: next bit depth */
       *palette_number = 0;
    }
 
@@ -423,7 +530,7 @@ next_format(png_bytep colour_type, png_bytep bit_depth,
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
 static unsigned int
 sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
-    png_uint_32 x, unsigned int sample_index)
+    png_uint_32 x, unsigned int sample_index, int swap16, int littleendian)
 {
    png_uint_32 bit_index, result;
 
@@ -452,11 +559,23 @@ sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
       return result;
 
    else if (bit_depth > 8)
-      return (result << 8) + *++row;
+   {
+      if (swap16)
+         return (*++row << 8) + result;
+      else
+         return (result << 8) + *++row;
+   }
 
-   /* Less than 8 bits per sample. */
+   /* Less than 8 bits per sample.  By default PNG has the big end of
+    * the egg on the left of the screen, but if littleendian is set
+    * then the big end is on the right.
+    */
    bit_index &= 7;
-   return (result >> (8-bit_index-bit_depth)) & ((1U<<bit_depth)-1);
+
+   if (!littleendian)
+      bit_index = 8-bit_index-bit_depth;
+
+   return (result >> bit_index) & ((1U<<bit_depth)-1);
 }
 #endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
@@ -470,7 +589,8 @@ sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
  */
 static void
 pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
-   png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize)
+   png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize,
+   int littleendian)
 {
    /* Assume we can multiply by 'size' without overflow because we are
     * just working in a single buffer.
@@ -480,15 +600,25 @@ pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
    if (pixelSize < 8) /* Sub-byte */
    {
       /* Mask to select the location of the copied pixel: */
-      unsigned int destMask = ((1U<<pixelSize)-1) << (8-pixelSize-(toIndex&7));
+      unsigned int destMask = ((1U<<pixelSize)-1) <<
+         (littleendian ? toIndex&7 : 8-pixelSize-(toIndex&7));
       /* The following read the entire pixels and clears the extra: */
       unsigned int destByte = toBuffer[toIndex >> 3] & ~destMask;
       unsigned int sourceByte = fromBuffer[fromIndex >> 3];
 
       /* Don't rely on << or >> supporting '0' here, just in case: */
       fromIndex &= 7;
-      if (fromIndex > 0) sourceByte <<= fromIndex;
-      if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
+      if (littleendian)
+      {
+         if (fromIndex > 0) sourceByte >>= fromIndex;
+         if ((toIndex & 7) > 0) sourceByte <<= toIndex & 7;
+      }
+
+      else
+      {
+         if (fromIndex > 0) sourceByte <<= fromIndex;
+         if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
+      }
 
       toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask));
    }
@@ -501,7 +631,8 @@ pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
  * bytes at the end.
  */
 static void
-row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
+row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth,
+      int littleendian)
 {
    memcpy(toBuffer, fromBuffer, bitWidth >> 3);
 
@@ -511,10 +642,10 @@ row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
 
       toBuffer += bitWidth >> 3;
       fromBuffer += bitWidth >> 3;
-      /* The remaining bits are in the top of the byte, the mask is the bits to
-       * retain.
-       */
-      mask = 0xff >> (bitWidth & 7);
+      if (littleendian)
+         mask = 0xff << (bitWidth & 7);
+      else
+         mask = 0xff >> (bitWidth & 7);
       *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask));
    }
 }
@@ -678,7 +809,7 @@ store_pool_mark(png_bytep mark)
    make_four_random_bytes(store_seed, mark);
 }
 
-#ifdef PNG_READ_SUPPORTED
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* Use this for random 32 bit values; this function makes sure the result is
  * non-zero.
  */
@@ -686,7 +817,7 @@ static png_uint_32
 random_32(void)
 {
 
-   for(;;)
+   for (;;)
    {
       png_byte mark[4];
       png_uint_32 result;
@@ -836,7 +967,7 @@ store_storefile(png_store *ps, png_uint_32 id)
 /* Generate an error message (in the given buffer) */
 static size_t
 store_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize,
-   size_t pos, PNG_CONST char *msg)
+   size_t pos, const char *msg)
 {
    if (pp != NULL && pp == ps->pread)
    {
@@ -954,7 +1085,7 @@ store_warning(png_structp ppIn, png_const_charp message)
  */
 /* Return a single row from the correct image. */
 static png_bytep
-store_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage,
+store_image_row(const png_store* ps, png_const_structp pp, int nImage,
    png_uint_32 y)
 {
    png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2;
@@ -1058,7 +1189,7 @@ store_ensure_image(png_store *ps, png_const_structp pp, int nImages,
 
 #ifdef PNG_READ_SUPPORTED
 static void
-store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage)
+store_image_check(const png_store* ps, png_const_structp pp, int iImage)
 {
    png_const_bytep image = ps->image;
 
@@ -1275,7 +1406,10 @@ store_current_palette(png_store *ps, int *npalette)
     * operation.)
     */
    if (ps->current == NULL)
+   {
       store_log(ps, ps->pread, "no current stream for palette", 1);
+      return NULL;
+   }
 
    /* The result may be null if there is no palette. */
    *npalette = ps->current->npalette;
@@ -1305,7 +1439,7 @@ typedef struct store_memory
  * all the memory.
  */
 static void
-store_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg)
+store_pool_error(png_store *ps, png_const_structp pp, const char *msg)
 {
    if (pp != NULL)
       png_error(pp, msg);
@@ -1369,7 +1503,7 @@ store_pool_delete(png_store *ps, store_pool *pool)
          next->next = NULL;
 
          fprintf(stderr, "\t%lu bytes @ %p\n",
-             (unsigned long)next->size, (PNG_CONST void*)(next+1));
+             (unsigned long)next->size, (const void*)(next+1));
          /* The NULL means this will always return, even if the memory is
           * corrupted.
           */
@@ -1524,8 +1658,7 @@ store_write_reset(png_store *ps)
  * returned libpng structures as destroyed by store_write_reset above.
  */
 static png_structp
-set_store_for_write(png_store *ps, png_infopp ppi,
-   PNG_CONST char * volatile name)
+set_store_for_write(png_store *ps, png_infopp ppi, const char *name)
 {
    anon_context(ps);
 
@@ -1645,7 +1778,7 @@ store_read_set(png_store *ps, png_uint_32 id)
  */
 static png_structp
 set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id,
-   PNG_CONST char *name)
+   const char *name)
 {
    /* Set the name for png_error */
    safecat(ps->test, sizeof ps->test, 0, name);
@@ -1752,6 +1885,7 @@ typedef struct color_encoding
 } color_encoding;
 
 #ifdef PNG_READ_SUPPORTED
+#if defined PNG_READ_TRANSFORMS_SUPPORTED && defined PNG_READ_cHRM_SUPPORTED
 static double
 chromaticity_x(CIE_color c)
 {
@@ -1765,7 +1899,7 @@ chromaticity_y(CIE_color c)
 }
 
 static CIE_color
-white_point(PNG_CONST color_encoding *encoding)
+white_point(const color_encoding *encoding)
 {
    CIE_color white;
 
@@ -1775,12 +1909,13 @@ white_point(PNG_CONST color_encoding *encoding)
 
    return white;
 }
+#endif /* READ_TRANSFORMS && READ_cHRM */
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 static void
 normalize_color_encoding(color_encoding *encoding)
 {
-   PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y +
+   const double whiteY = encoding->red.Y + encoding->green.Y +
       encoding->blue.Y;
 
    if (whiteY != 1)
@@ -1798,9 +1933,10 @@ normalize_color_encoding(color_encoding *encoding)
 }
 #endif
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 static size_t
 safecat_color_encoding(char *buffer, size_t bufsize, size_t pos,
-   PNG_CONST color_encoding *e, double encoding_gamma)
+   const color_encoding *e, double encoding_gamma)
 {
    if (e != 0)
    {
@@ -1837,6 +1973,7 @@ safecat_color_encoding(char *buffer, size_t bufsize, size_t pos,
 
    return pos;
 }
+#endif /* READ_TRANSFORMS */
 #endif /* PNG_READ_SUPPORTED */
 
 typedef struct png_modifier
@@ -1861,9 +1998,9 @@ typedef struct png_modifier
    unsigned int              ngammas;
    unsigned int              ngamma_tests;     /* Number of gamma tests to run*/
    double                    current_gamma;    /* 0 if not set */
-   PNG_CONST color_encoding *encodings;
+   const color_encoding *encodings;
    unsigned int              nencodings;
-   PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */
+   const color_encoding *current_encoding; /* If an encoding has been set */
    unsigned int              encoding_counter; /* For iteration */
    int                       encoding_ignored; /* Something overwrote it */
 
@@ -1874,7 +2011,7 @@ typedef struct png_modifier
    unsigned int              repeat :1;   /* Repeat this transform test. */
    unsigned int              test_uses_encoding :1;
 
-   /* Lowest sbit to test (libpng fails for sbit < 8) */
+   /* Lowest sbit to test (pre-1.7 libpng fails for sbit < 8) */
    png_byte                 sbitlow;
 
    /* Error control - these are the limits on errors accepted by the gamma tests
@@ -1894,6 +2031,8 @@ typedef struct png_modifier
     * internal check on pngvalid to ensure that the calculated error limits are
     * not ridiculous; without this it is too easy to make a mistake in pngvalid
     * that allows any value through.
+    *
+    * NOTE: this is not checked in release builds.
     */
    double                   limit;    /* limit on error values, normally 4E-3 */
 
@@ -1929,6 +2068,7 @@ typedef struct png_modifier
 
    /* Run tests on reading with a combination of transforms, */
    unsigned int             test_transform :1;
+   unsigned int             test_tRNS :1; /* Includes tRNS images */
 
    /* When to use the use_input_precision option, this controls the gamma
     * validation code checks.  If set any value that is within the transformed
@@ -1960,6 +2100,16 @@ typedef struct png_modifier
    unsigned int             test_gamma_expand16 :1;
    unsigned int             test_exhaustive :1;
 
+   /* Whether or not to run the low-bit-depth grayscale tests.  This fails on
+    * gamma images in some cases because of gross inaccuracies in the grayscale
+    * gamma handling for low bit depth.
+    */
+   unsigned int             test_lbg :1;
+   unsigned int             test_lbg_gamma_threshold :1;
+   unsigned int             test_lbg_gamma_transform :1;
+   unsigned int             test_lbg_gamma_sbit :1;
+   unsigned int             test_lbg_gamma_composition :1;
+
    unsigned int             log :1;   /* Log max error */
 
    /* Buffer information, the buffer size limits the size of the chunks that can
@@ -2012,6 +2162,11 @@ modifier_init(png_modifier *pm)
    pm->test_standard = 0;
    pm->test_size = 0;
    pm->test_transform = 0;
+#  ifdef PNG_WRITE_tRNS_SUPPORTED
+      pm->test_tRNS = 1;
+#  else
+      pm->test_tRNS = 0;
+#  endif
    pm->use_input_precision = 0;
    pm->use_input_precision_sbit = 0;
    pm->use_input_precision_16to8 = 0;
@@ -2024,6 +2179,11 @@ modifier_init(png_modifier *pm)
    pm->test_gamma_background = 0;
    pm->test_gamma_alpha_mode = 0;
    pm->test_gamma_expand16 = 0;
+   pm->test_lbg = 1;
+   pm->test_lbg_gamma_threshold = 1;
+   pm->test_lbg_gamma_transform = 1;
+   pm->test_lbg_gamma_sbit = 1;
+   pm->test_lbg_gamma_composition = 1;
    pm->test_exhaustive = 0;
    pm->log = 0;
 
@@ -2057,7 +2217,7 @@ static double digitize(double value, int depth, int do_round)
     * rounding and 'do_round' should be 1, if it is 0 the digitized value will
     * be truncated.
     */
-   PNG_CONST unsigned int digitization_factor = (1U << depth) -1;
+   const unsigned int digitization_factor = (1U << depth) -1;
 
    /* Limiting the range is done as a convenience to the caller - it's easier to
     * do it once here than every time at the call site.
@@ -2076,7 +2236,7 @@ static double digitize(double value, int depth, int do_round)
 #endif /* RGB_TO_GRAY */
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
-static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double abserr(const png_modifier *pm, int in_depth, int out_depth)
 {
    /* Absolute error permitted in linear values - affected by the bit depth of
     * the calculations.
@@ -2088,7 +2248,7 @@ static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
       return pm->maxabs8;
 }
 
-static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double calcerr(const png_modifier *pm, int in_depth, int out_depth)
 {
    /* Error in the linear composition arithmetic - only relevant when
     * composition actually happens (0 < alpha < 1).
@@ -2101,7 +2261,7 @@ static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
       return pm->maxcalc8;
 }
 
-static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double pcerr(const png_modifier *pm, int in_depth, int out_depth)
 {
    /* Percentage error permitted in the linear values.  Note that the specified
     * value is a percentage but this routine returns a simple number.
@@ -2124,7 +2284,7 @@ static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
  * The specified parameter does *not* include the base .5 digitization error but
  * it is added here.
  */
-static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double outerr(const png_modifier *pm, int in_depth, int out_depth)
 {
    /* There is a serious error in the 2 and 4 bit grayscale transform because
     * the gamma table value (8 bits) is simply shifted, not rounded, so the
@@ -2156,7 +2316,7 @@ static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
  * rather than raising a warning.  This is useful for debugging to track down
  * exactly what set of parameters cause high error values.
  */
-static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double outlog(const png_modifier *pm, int in_depth, int out_depth)
 {
    /* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535)
     * and so must be adjusted for low bit depth grayscale:
@@ -2194,7 +2354,7 @@ static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
  * but in the 8 bit calculation case it's actually quantization to a multiple of
  * 257!
  */
-static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth,
+static int output_quantization_factor(const png_modifier *pm, int in_depth,
    int out_depth)
 {
    if (out_depth == 16 && in_depth != 16 &&
@@ -2258,7 +2418,7 @@ modification_init(png_modification *pmm)
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 static void
-modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce)
+modifier_current_encoding(const png_modifier *pm, color_encoding *ce)
 {
    if (pm->current_encoding != 0)
       *ce = *pm->current_encoding;
@@ -2270,9 +2430,10 @@ modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce)
 }
 #endif
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 static size_t
 safecat_current_encoding(char *buffer, size_t bufsize, size_t pos,
-   PNG_CONST png_modifier *pm)
+   const png_modifier *pm)
 {
    pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding,
       pm->current_gamma);
@@ -2282,6 +2443,7 @@ safecat_current_encoding(char *buffer, size_t bufsize, size_t pos,
 
    return pos;
 }
+#endif
 
 /* Iterate through the usefully testable color encodings.  An encoding is one
  * of:
@@ -2301,7 +2463,7 @@ safecat_current_encoding(char *buffer, size_t bufsize, size_t pos,
  * caller of modifier_reset must reset it at the start of each run of the test!
  */
 static unsigned int
-modifier_total_encodings(PNG_CONST png_modifier *pm)
+modifier_total_encodings(const png_modifier *pm)
 {
    return 1 +                 /* (1) nothing */
       pm->ngammas +           /* (2) gamma values to test */
@@ -2417,14 +2579,14 @@ modifier_set_encoding(png_modifier *pm)
  * assumption below that the first encoding in the list is the one for sRGB.
  */
 static int
-modifier_color_encoding_is_sRGB(PNG_CONST png_modifier *pm)
+modifier_color_encoding_is_sRGB(const png_modifier *pm)
 {
    return pm->current_encoding != 0 && pm->current_encoding == pm->encodings &&
       pm->current_encoding->gamma == pm->current_gamma;
 }
 
 static int
-modifier_color_encoding_is_set(PNG_CONST png_modifier *pm)
+modifier_color_encoding_is_set(const png_modifier *pm)
 {
    return pm->current_gamma != 0;
 }
@@ -2743,7 +2905,7 @@ modifier_progressive_read(png_modifier *pm, png_structp pp, png_infop pi)
 /* Set up a modifier. */
 static png_structp
 set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id,
-    PNG_CONST char *name)
+    const char *name)
 {
    /* Do this first so that the modifier fields are cleared even if an error
     * happens allocating the png_struct.  No allocation is done here so no
@@ -2803,7 +2965,7 @@ gama_modification_init(gama_modification *me, png_modifier *pm, double gammad)
 typedef struct chrm_modification
 {
    png_modification          this;
-   PNG_CONST color_encoding *encoding;
+   const color_encoding *encoding;
    png_fixed_point           wx, wy, rx, ry, gx, gy, bx, by;
 } chrm_modification;
 
@@ -2827,7 +2989,7 @@ chrm_modify(png_modifier *pm, png_modification *me, int add)
 
 static void
 chrm_modification_init(chrm_modification *me, png_modifier *pm,
-   PNG_CONST color_encoding *encoding)
+   const color_encoding *encoding)
 {
    CIE_color white = white_point(encoding);
 
@@ -3155,12 +3317,57 @@ init_standard_palette(png_store *ps, png_structp pp, png_infop pi, int npalette,
       for (; i<256; ++i)
          tRNS[i] = 24;
 
-#  ifdef PNG_WRITE_tRNS_SUPPORTED
+#     ifdef PNG_WRITE_tRNS_SUPPORTED
          if (j > 0)
             png_set_tRNS(pp, pi, tRNS, j, 0/*color*/);
-#  endif
+#     endif
+   }
+}
+
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+static void
+set_random_tRNS(png_structp pp, png_infop pi, const png_byte colour_type,
+   const int bit_depth)
+{
+   /* To make this useful the tRNS color needs to match at least one pixel.
+    * Random values are fine for gray, including the 16-bit case where we know
+    * that the test image contains all the gray values.  For RGB we need more
+    * method as only 65536 different RGB values are generated.
+    */
+   png_color_16 tRNS;
+   const png_uint_16 mask = (png_uint_16)((1U << bit_depth)-1);
+
+   R8(tRNS); /* makes unset fields random */
+
+   if (colour_type & 2/*RGB*/)
+   {
+      if (bit_depth == 8)
+      {
+         R16(tRNS.red);
+         R16(tRNS.green);
+         tRNS.blue = tRNS.red ^ tRNS.green;
+         tRNS.red &= mask;
+         tRNS.green &= mask;
+         tRNS.blue &= mask;
+      }
+
+      else /* bit_depth == 16 */
+      {
+         R16(tRNS.red);
+         tRNS.green = (png_uint_16)(tRNS.red * 257);
+         tRNS.blue = (png_uint_16)(tRNS.green * 17);
+      }
+   }
+
+   else
+   {
+      R16(tRNS.gray);
+      tRNS.gray &= mask;
    }
+
+   png_set_tRNS(pp, pi, NULL, 0, &tRNS);
 }
+#endif
 
 /* The number of passes is related to the interlace type. There was no libpng
  * API to determine this prior to 1.5, so we need an inquiry function:
@@ -3411,13 +3618,17 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX],
 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
 #  define INTERLACE_LAST PNG_INTERLACE_LAST
 #  define check_interlace_type(type) ((void)(type))
-#else
-#  define INTERLACE_LAST (PNG_INTERLACE_NONE+1)
-#  define png_set_interlace_handling(a) (1)
-
+#  define set_write_interlace_handling(pp,type) png_set_interlace_handling(pp)
+#  define do_own_interlace 0
+#elif PNG_LIBPNG_VER < 10700
+#  define set_write_interlace_handling(pp,type) (1)
 static void
-check_interlace_type(int PNG_CONST interlace_type)
+check_interlace_type(int const interlace_type)
 {
+   /* Prior to 1.7.0 libpng does not support the write of an interlaced image
+    * unless PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the
+    * code here does the pixel interlace itself, so:
+    */
    if (interlace_type != PNG_INTERLACE_NONE)
    {
       /* This is an internal error - --interlace tests should be skipped, not
@@ -3427,17 +3638,107 @@ check_interlace_type(int PNG_CONST interlace_type)
       exit(99);
    }
 }
+#  define INTERLACE_LAST (PNG_INTERLACE_NONE+1)
+#  define do_own_interlace 0
+#else /* libpng 1.7+ */
+#  define set_write_interlace_handling(pp,type)\
+      npasses_from_interlace_type(pp,type)
+#  define check_interlace_type(type) ((void)(type))
+#  define INTERLACE_LAST PNG_INTERLACE_LAST
+#  define do_own_interlace 1
+#endif /* WRITE_INTERLACING tests */
+
+#define CAN_WRITE_INTERLACE\
+   PNG_LIBPNG_VER >= 10700 || defined PNG_WRITE_INTERLACING_SUPPORTED
+
+/* Do the same thing for read interlacing; this controls whether read tests do
+ * their own de-interlace or use libpng.
+ */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+#  define do_read_interlace 0
+#else /* no libpng read interlace support */
+#  define do_read_interlace 1
 #endif
+/* The following two routines use the PNG interlace support macros from
+ * png.h to interlace or deinterlace rows.
+ */
+static void
+interlace_row(png_bytep buffer, png_const_bytep imageRow,
+   unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
+{
+   png_uint_32 xin, xout, xstep;
+
+   /* Note that this can, trivially, be optimized to a memcpy on pass 7, the
+    * code is presented this way to make it easier to understand.  In practice
+    * consult the code in the libpng source to see other ways of doing this.
+    *
+    * It is OK for buffer and imageRow to be identical, because 'xin' moves
+    * faster than 'xout' and we copy up.
+    */
+   xin = PNG_PASS_START_COL(pass);
+   xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
+
+   for (xout=0; xin<w; xin+=xstep)
+   {
+      pixel_copy(buffer, xout, imageRow, xin, pixel_size, littleendian);
+      ++xout;
+   }
+}
+
+#ifdef PNG_READ_SUPPORTED
+static void
+deinterlace_row(png_bytep buffer, png_const_bytep row,
+   unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
+{
+   /* The inverse of the above, 'row' is part of row 'y' of the output image,
+    * in 'buffer'.  The image is 'w' wide and this is pass 'pass', distribute
+    * the pixels of row into buffer and return the number written (to allow
+    * this to be checked).
+    */
+   png_uint_32 xin, xout, xstep;
+
+   xout = PNG_PASS_START_COL(pass);
+   xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
+
+   for (xin=0; xout<w; xout+=xstep)
+   {
+      pixel_copy(buffer, xout, row, xin, pixel_size, littleendian);
+      ++xin;
+   }
+}
+#endif /* PNG_READ_SUPPORTED */
 
-/* Make a standardized image given a an image colour type, bit depth and
+/* Make a standardized image given an image colour type, bit depth and
  * interlace type.  The standard images have a very restricted range of
  * rows and heights and are used for testing transforms rather than image
  * layout details.  See make_size_images below for a way to make images
  * that test odd sizes along with the libpng interlace handling.
  */
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+static void
+choose_random_filter(png_structp pp, int start)
+{
+   /* Choose filters randomly except that on the very first row ensure that
+    * there is at least one previous row filter.
+    */
+   int filters = PNG_ALL_FILTERS & random_mod(256U);
+
+   /* There may be no filters; skip the setting. */
+   if (filters != 0)
+   {
+      if (start && filters < PNG_FILTER_UP)
+         filters |= PNG_FILTER_UP;
+
+      png_set_filter(pp, 0/*method*/, filters);
+   }
+}
+#else /* !WRITE_FILTER */
+#  define choose_random_filter(pp, start) ((void)0)
+#endif /* !WRITE_FILTER */
+
 static void
-make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
-    png_byte PNG_CONST bit_depth, unsigned int palette_number,
+make_transform_image(png_store* const ps, png_byte const colour_type,
+    png_byte const bit_depth, unsigned int palette_number,
     int interlace_type, png_const_charp name)
 {
    context(ps, fault);
@@ -3448,7 +3749,7 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
    {
       png_infop pi;
       png_structp pp = set_store_for_write(ps, &pi, name);
-      png_uint_32 h;
+      png_uint_32 h, w;
 
       /* In the event of a problem return control to the Catch statement below
        * to do the clean up - it is not possible to 'return' directly from a Try
@@ -3457,10 +3758,10 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
       if (pp == NULL)
          Throw ps;
 
+      w = transform_width(pp, colour_type, bit_depth);
       h = transform_height(pp, colour_type, bit_depth);
 
-      png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), h,
-         bit_depth, colour_type, interlace_type,
+      png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type,
          PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
 #ifdef PNG_TEXT_SUPPORTED
@@ -3495,11 +3796,16 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
       if (colour_type == 3) /* palette */
          init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/);
 
+#     ifdef PNG_WRITE_tRNS_SUPPORTED
+         else if (palette_number)
+            set_random_tRNS(pp, pi, colour_type, bit_depth);
+#     endif
+
       png_write_info(pp, pi);
 
       if (png_get_rowbytes(pp, pi) !=
           transform_rowsize(pp, colour_type, bit_depth))
-         png_error(pp, "row size incorrect");
+         png_error(pp, "transform row size incorrect");
 
       else
       {
@@ -3507,7 +3813,7 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
           * because if it is called before, the information in *pp has not been
           * updated to reflect the interlaced image.
           */
-         int npasses = png_set_interlace_handling(pp);
+         int npasses = set_write_interlace_handling(pp, interlace_type);
          int pass;
 
          if (npasses != npasses_from_interlace_type(pp, interlace_type))
@@ -3517,11 +3823,38 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
          {
             png_uint_32 y;
 
+            /* do_own_interlace is a pre-defined boolean (a #define) which is
+             * set if we have to work out the interlaced rows here.
+             */
             for (y=0; y<h; ++y)
             {
                png_byte buffer[TRANSFORM_ROWMAX];
 
                transform_row(pp, buffer, colour_type, bit_depth, y);
+
+#              if do_own_interlace
+                  /* If do_own_interlace *and* the image is interlaced we need a
+                   * reduced interlace row; this may be reduced to empty.
+                   */
+                  if (interlace_type == PNG_INTERLACE_ADAM7)
+                  {
+                     /* The row must not be written if it doesn't exist, notice
+                      * that there are two conditions here, either the row isn't
+                      * ever in the pass or the row would be but isn't wide
+                      * enough to contribute any pixels.  In fact the wPass test
+                      * can be used to skip the whole y loop in this case.
+                      */
+                     if (PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
+                         PNG_PASS_COLS(w, pass) > 0)
+                        interlace_row(buffer, buffer,
+                              bit_size(pp, colour_type, bit_depth), w, pass,
+                              0/*data always bigendian*/);
+                     else
+                        continue;
+                  }
+#              endif /* do_own_interlace */
+
+               choose_random_filter(pp, pass == 0 && y == 0);
                png_write_row(pp, buffer);
             }
          }
@@ -3568,19 +3901,20 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
 }
 
 static void
-make_transform_images(png_store *ps)
+make_transform_images(png_modifier *pm)
 {
    png_byte colour_type = 0;
    png_byte bit_depth = 0;
    unsigned int palette_number = 0;
 
    /* This is in case of errors. */
-   safecat(ps->test, sizeof ps->test, 0, "make standard images");
+   safecat(pm->this.test, sizeof pm->this.test, 0, "make standard images");
 
    /* Use next_format to enumerate all the combinations we test, including
-    * generating multiple low bit depth palette images.
+    * generating multiple low bit depth palette images. Non-A images (palette
+    * and direct) are created with and without tRNS chunks.
     */
-   while (next_format(&colour_type, &bit_depth, &palette_number, 0))
+   while (next_format(&colour_type, &bit_depth, &palette_number, 1, 1))
    {
       int interlace_type;
 
@@ -3590,59 +3924,13 @@ make_transform_images(png_store *ps)
          char name[FILE_NAME_SIZE];
 
          standard_name(name, sizeof name, 0, colour_type, bit_depth,
-            palette_number, interlace_type, 0, 0, 0);
-         make_transform_image(ps, colour_type, bit_depth, palette_number,
+            palette_number, interlace_type, 0, 0, do_own_interlace);
+         make_transform_image(&pm->this, colour_type, bit_depth, palette_number,
             interlace_type, name);
       }
    }
 }
 
-/* The following two routines use the PNG interlace support macros from
- * png.h to interlace or deinterlace rows.
- */
-static void
-interlace_row(png_bytep buffer, png_const_bytep imageRow,
-   unsigned int pixel_size, png_uint_32 w, int pass)
-{
-   png_uint_32 xin, xout, xstep;
-
-   /* Note that this can, trivially, be optimized to a memcpy on pass 7, the
-    * code is presented this way to make it easier to understand.  In practice
-    * consult the code in the libpng source to see other ways of doing this.
-    */
-   xin = PNG_PASS_START_COL(pass);
-   xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
-
-   for (xout=0; xin<w; xin+=xstep)
-   {
-      pixel_copy(buffer, xout, imageRow, xin, pixel_size);
-      ++xout;
-   }
-}
-
-#ifdef PNG_READ_SUPPORTED
-static void
-deinterlace_row(png_bytep buffer, png_const_bytep row,
-   unsigned int pixel_size, png_uint_32 w, int pass)
-{
-   /* The inverse of the above, 'row' is part of row 'y' of the output image,
-    * in 'buffer'.  The image is 'w' wide and this is pass 'pass', distribute
-    * the pixels of row into buffer and return the number written (to allow
-    * this to be checked).
-    */
-   png_uint_32 xin, xout, xstep;
-
-   xout = PNG_PASS_START_COL(pass);
-   xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
-
-   for (xin=0; xout<w; xout+=xstep)
-   {
-      pixel_copy(buffer, xout, row, xin, pixel_size);
-      ++xin;
-   }
-}
-#endif /* PNG_READ_SUPPORTED */
-
 /* Build a single row for the 'size' test images; this fills in only the
  * first bit_width bits of the sample row.
  */
@@ -3668,17 +3956,13 @@ size_row(png_byte buffer[SIZE_ROWMAX], png_uint_32 bit_width, png_uint_32 y)
 }
 
 static void
-make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
-    png_byte PNG_CONST bit_depth, int PNG_CONST interlace_type,
-    png_uint_32 PNG_CONST w, png_uint_32 PNG_CONST h,
-    int PNG_CONST do_interlace)
+make_size_image(png_store* const ps, png_byte const colour_type,
+    png_byte const bit_depth, int const interlace_type,
+    png_uint_32 const w, png_uint_32 const h,
+    int const do_interlace)
 {
    context(ps, fault);
 
-   /* At present libpng does not support the write of an interlaced image unless
-    * PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the code here
-    * does the pixel interlace itself, so:
-    */
    check_interlace_type(interlace_type);
 
    Try
@@ -3689,7 +3973,7 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
 
       /* Make a name and get an appropriate id for the store: */
       char name[FILE_NAME_SIZE];
-      PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/,
+      const png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/,
          interlace_type, w, h, do_interlace);
 
       standard_name_from_id(name, sizeof name, 0, id);
@@ -3740,16 +4024,13 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
        */
       pixel_size = bit_size(pp, colour_type, bit_depth);
       if (png_get_rowbytes(pp, pi) != ((w * pixel_size) + 7) / 8)
-         png_error(pp, "row size incorrect");
+         png_error(pp, "size row size incorrect");
 
       else
       {
          int npasses = npasses_from_interlace_type(pp, interlace_type);
          png_uint_32 y;
          int pass;
-#        ifdef PNG_WRITE_FILTER_SUPPORTED
-            int nfilter = PNG_FILTER_VALUE_LAST;
-#        endif
          png_byte image[16][SIZE_ROWMAX];
 
          /* To help consistent error detection make the parts of this buffer
@@ -3757,7 +4038,8 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
           */
          memset(image, 0xff, sizeof image);
 
-         if (!do_interlace && npasses != png_set_interlace_handling(pp))
+         if (!do_interlace &&
+             npasses != set_write_interlace_handling(pp, interlace_type))
             png_error(pp, "write: png_set_interlace_handling failed");
 
          /* Prepare the whole image first to avoid making it 7 times: */
@@ -3767,7 +4049,7 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
          for (pass=0; pass<npasses; ++pass)
          {
             /* The following two are for checking the macros: */
-            PNG_CONST png_uint_32 wPass = PNG_PASS_COLS(w, pass);
+            const png_uint_32 wPass = PNG_PASS_COLS(w, pass);
 
             /* If do_interlace is set we don't call png_write_row for every
              * row because some of them are empty.  In fact, for a 1x1 image,
@@ -3796,7 +4078,8 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
                       * set unset things to 0).
                       */
                      memset(tempRow, 0xff, sizeof tempRow);
-                     interlace_row(tempRow, row, pixel_size, w, pass);
+                     interlace_row(tempRow, row, pixel_size, w, pass,
+                           0/*data always bigendian*/);
                      row = tempRow;
                   }
                   else
@@ -3810,15 +4093,19 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
                 * does accept a filter number (per the spec) as well as a bit
                 * mask.
                 *
-                * The apparent wackiness of decrementing nfilter rather than
-                * incrementing is so that Paeth gets used in all images bigger
-                * than 1 row - it's the tricky one.
+                * The code now uses filters at random, except that on the first
+                * row of an image it ensures that a previous row filter is in
+                * the set so that libpng allocates the row buffer.
                 */
-               png_set_filter(pp, 0/*method*/,
-                  nfilter >= PNG_FILTER_VALUE_LAST ? PNG_ALL_FILTERS : nfilter);
+               {
+                  int filters = 8 << random_mod(PNG_FILTER_VALUE_LAST);
+
+                  if (pass == 0 && y == 0 &&
+                      (filters < PNG_FILTER_UP || w == 1U))
+                     filters |= PNG_FILTER_UP;
 
-               if (nfilter-- == 0)
-                  nfilter = PNG_FILTER_VALUE_LAST-1;
+                  png_set_filter(pp, 0/*method*/, filters);
+               }
 #           endif
 
                png_write_row(pp, row);
@@ -3866,8 +4153,8 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
 }
 
 static void
-make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
-    int PNG_CONST bdhi)
+make_size(png_store* const ps, png_byte const colour_type, int bdlo,
+    int const bdhi)
 {
    for (; bdlo <= bdhi; ++bdlo)
    {
@@ -3890,6 +4177,11 @@ make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
 #        ifdef PNG_WRITE_INTERLACING_SUPPORTED
             make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
                width, height, 0);
+#        endif
+#        if CAN_WRITE_INTERLACE
+            /* 1.7.0 removes the hack that prevented app write of an interlaced
+             * image if WRITE_INTERLACE was not supported
+             */
             make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
                width, height, 1);
 #        endif
@@ -3963,41 +4255,45 @@ sBIT_error_fn(png_structp pp, png_infop pi)
    png_set_sBIT(pp, pi, &bad);
 }
 
-static PNG_CONST struct
+static const struct
 {
    void          (*fn)(png_structp, png_infop);
-   PNG_CONST char *msg;
+   const char *msg;
    unsigned int    warning :1; /* the error is a warning... */
 } error_test[] =
     {
-       /* no warnings makes these errors undetectable. */
-       { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 },
-       { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 },
+       /* no warnings makes these errors undetectable prior to 1.7.0 */
+       { sBIT0_error_fn, "sBIT(0): failed to detect error",
+         PNG_LIBPNG_VER < 10700 },
+
+       { sBIT_error_fn, "sBIT(too big): failed to detect error",
+         PNG_LIBPNG_VER < 10700 },
     };
 
 static void
-make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type,
+make_error(png_store* const ps, png_byte const colour_type,
     png_byte bit_depth, int interlace_type, int test, png_const_charp name)
 {
-   png_store * volatile ps = psIn;
-
    context(ps, fault);
 
    check_interlace_type(interlace_type);
 
    Try
    {
-      png_structp pp;
       png_infop pi;
-
-      pp = set_store_for_write(ps, &pi, name);
+      const png_structp pp = set_store_for_write(ps, &pi, name);
+      png_uint_32 w, h;
+      gnu_volatile(pp)
 
       if (pp == NULL)
          Throw ps;
 
-      png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth),
-         transform_height(pp, colour_type, bit_depth), bit_depth, colour_type,
-         interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+      w = transform_width(pp, colour_type, bit_depth);
+      gnu_volatile(w)
+      h = transform_height(pp, colour_type, bit_depth);
+      gnu_volatile(h)
+      png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type,
+            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
       if (colour_type == 3) /* palette */
          init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/);
@@ -4009,6 +4305,8 @@ make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type,
 #     define exception__env exception_env_1
       Try
       {
+         gnu_volatile(exception__prev)
+
          /* Expect this to throw: */
          ps->expect_error = !error_test[test].warning;
          ps->expect_warning = error_test[test].warning;
@@ -4029,49 +4327,81 @@ make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type,
       }
 
       Catch (fault)
-         ps = fault; /* expected exit, make sure ps is not clobbered */
+      { /* expected exit */
+      }
 #undef exception__prev
 #undef exception__env
 
       /* And clear these flags */
-      ps->expect_error = 0;
       ps->expect_warning = 0;
 
-      /* Now write the whole image, just to make sure that the detected, or
-       * undetected, errro has not created problems inside libpng.
-       */
-      if (png_get_rowbytes(pp, pi) !=
-          transform_rowsize(pp, colour_type, bit_depth))
-         png_error(pp, "row size incorrect");
+      if (ps->expect_error)
+         ps->expect_error = 0;
 
       else
       {
-         png_uint_32 h = transform_height(pp, colour_type, bit_depth);
-         int npasses = png_set_interlace_handling(pp);
-         int pass;
-
-         if (npasses != npasses_from_interlace_type(pp, interlace_type))
-            png_error(pp, "write: png_set_interlace_handling failed");
+         /* Now write the whole image, just to make sure that the detected, or
+          * undetected, errro has not created problems inside libpng.  This
+          * doesn't work if there was a png_error in png_write_info because that
+          * can abort before PLTE was written.
+          */
+         if (png_get_rowbytes(pp, pi) !=
+             transform_rowsize(pp, colour_type, bit_depth))
+            png_error(pp, "row size incorrect");
 
-         for (pass=0; pass<npasses; ++pass)
+         else
          {
-            png_uint_32 y;
+            int npasses = set_write_interlace_handling(pp, interlace_type);
+            int pass;
 
-            for (y=0; y<h; ++y)
+            if (npasses != npasses_from_interlace_type(pp, interlace_type))
+               png_error(pp, "write: png_set_interlace_handling failed");
+
+            for (pass=0; pass<npasses; ++pass)
             {
-               png_byte buffer[TRANSFORM_ROWMAX];
+               png_uint_32 y;
 
-               transform_row(pp, buffer, colour_type, bit_depth, y);
-               png_write_row(pp, buffer);
-            }
-         }
-      }
+               for (y=0; y<h; ++y)
+               {
+                  png_byte buffer[TRANSFORM_ROWMAX];
 
-      png_write_end(pp, pi);
+                  transform_row(pp, buffer, colour_type, bit_depth, y);
 
-      /* The following deletes the file that was just written. */
-      store_write_reset(ps);
-   }
+#                 if do_own_interlace
+                     /* If do_own_interlace *and* the image is interlaced we
+                      * need a reduced interlace row; this may be reduced to
+                      * empty.
+                      */
+                     if (interlace_type == PNG_INTERLACE_ADAM7)
+                     {
+                        /* The row must not be written if it doesn't exist,
+                         * notice that there are two conditions here, either the
+                         * row isn't ever in the pass or the row would be but
+                         * isn't wide enough to contribute any pixels.  In fact
+                         * the wPass test can be used to skip the whole y loop
+                         * in this case.
+                         */
+                        if (PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
+                            PNG_PASS_COLS(w, pass) > 0)
+                           interlace_row(buffer, buffer,
+                                 bit_size(pp, colour_type, bit_depth), w, pass,
+                                 0/*data always bigendian*/);
+                        else
+                           continue;
+                     }
+#                 endif /* do_own_interlace */
+
+                  png_write_row(pp, buffer);
+               }
+            }
+         } /* image writing */
+
+         png_write_end(pp, pi);
+      }
+
+      /* The following deletes the file that was just written. */
+      store_write_reset(ps);
+   }
 
    Catch(fault)
    {
@@ -4080,8 +4410,8 @@ make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type,
 }
 
 static int
-make_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
-    int bdlo, int PNG_CONST bdhi)
+make_errors(png_modifier* const pm, png_byte const colour_type,
+    int bdlo, int const bdhi)
 {
    for (; bdlo <= bdhi; ++bdlo)
    {
@@ -4094,9 +4424,9 @@ make_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
          char name[FILE_NAME_SIZE];
 
          standard_name(name, sizeof name, 0, colour_type, 1<<bdlo, 0,
-            interlace_type, 0, 0, 0);
+            interlace_type, 0, 0, do_own_interlace);
 
-         for (test=0; test<(sizeof error_test)/(sizeof error_test[0]); ++test)
+         for (test=0; test<ARRAY_SIZE(error_test); ++test)
          {
             make_error(&pm->this, colour_type, DEPTH(bdlo), interlace_type,
                test, name);
@@ -4141,7 +4471,7 @@ perform_error_test(png_modifier *pm)
  * then the warning messages the library outputs will probably be garbage.
  */
 static void
-perform_formatting_test(png_store *volatile ps)
+perform_formatting_test(png_store *ps)
 {
 #ifdef PNG_TIME_RFC1123_SUPPORTED
    /* The handle into the formatting code is the RFC1123 support; this test does
@@ -4246,7 +4576,8 @@ typedef struct standard_display
    png_byte    green_sBIT;
    png_byte    blue_sBIT;
    png_byte    alpha_sBIT;
-   int         interlace_type;
+   png_byte    interlace_type;
+   png_byte    filler;         /* Output has a filler */
    png_uint_32 id;             /* Calculated file ID */
    png_uint_32 w;              /* Width of image */
    png_uint_32 h;              /* Height of image */
@@ -4255,7 +4586,9 @@ typedef struct standard_display
    png_uint_32 bit_width;      /* Width of output row in bits */
    size_t      cbRow;          /* Bytes in a row of the output image */
    int         do_interlace;   /* Do interlacing internally */
+   int         littleendian;   /* App (row) data is little endian */
    int         is_transparent; /* Transparency information was present. */
+   int         has_tRNS;       /* color type GRAY or RGB with a tRNS chunk. */
    int         speed;          /* Doing a speed test */
    int         use_update_info;/* Call update_info, not start_image */
    struct
@@ -4296,6 +4629,7 @@ standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id,
    dp->bit_width = 0;
    dp->cbRow = 0;
    dp->do_interlace = do_interlace;
+   dp->littleendian = 0;
    dp->is_transparent = 0;
    dp->speed = ps->speed;
    dp->use_update_info = use_update_info;
@@ -4588,14 +4922,14 @@ standard_info_part1(standard_display *dp, png_structp pp, png_infop pi)
          case 0:
             dp->transparent.red = dp->transparent.green = dp->transparent.blue =
                trans_color->gray;
-            dp->is_transparent = 1;
+            dp->has_tRNS = 1;
             break;
 
          case 2:
             dp->transparent.red = trans_color->red;
             dp->transparent.green = trans_color->green;
             dp->transparent.blue = trans_color->blue;
-            dp->is_transparent = 1;
+            dp->has_tRNS = 1;
             break;
 
          case 3:
@@ -4616,8 +4950,19 @@ standard_info_part1(standard_display *dp, png_structp pp, png_infop pi)
     * turning on interlace handling (if do_interlace is not set.)
     */
    dp->npasses = npasses_from_interlace_type(pp, dp->interlace_type);
-   if (!dp->do_interlace && dp->npasses != png_set_interlace_handling(pp))
-      png_error(pp, "validate: file changed interlace type");
+   if (!dp->do_interlace)
+   {
+#     ifdef PNG_READ_INTERLACING_SUPPORTED
+         if (dp->npasses != png_set_interlace_handling(pp))
+            png_error(pp, "validate: file changed interlace type");
+#     else /* !READ_INTERLACING */
+         /* This should never happen: the relevant tests (!do_interlace) should
+          * not be run.
+          */
+         if (dp->npasses > 1)
+            png_error(pp, "validate: no libpng interlace support");
+#     endif /* !READ_INTERLACING */
+   }
 
    /* Caller calls png_read_update_info or png_start_read_image now, then calls
     * part2.
@@ -4633,8 +4978,16 @@ standard_info_part2(standard_display *dp, png_const_structp pp,
     png_const_infop pi, int nImages)
 {
    /* Record cbRow now that it can be found. */
-   dp->pixel_size = bit_size(pp, png_get_color_type(pp, pi),
-      png_get_bit_depth(pp, pi));
+   {
+      png_byte ct = png_get_color_type(pp, pi);
+      png_byte bd = png_get_bit_depth(pp, pi);
+
+      if (bd >= 8 && (ct == PNG_COLOR_TYPE_RGB || ct == PNG_COLOR_TYPE_GRAY) &&
+          dp->filler)
+          ct |= 4; /* handle filler as faked alpha channel */
+
+      dp->pixel_size = bit_size(pp, ct, bd);
+   }
    dp->bit_width = png_get_image_width(pp, pi) * dp->pixel_size;
    dp->cbRow = png_get_rowbytes(pp, pi);
 
@@ -4691,7 +5044,7 @@ static void PNGCBAPI
 progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass)
 {
    png_const_structp pp = ppIn;
-   PNG_CONST standard_display *dp = voidcast(standard_display*,
+   const standard_display *dp = voidcast(standard_display*,
       png_get_progressive_ptr(pp));
 
    /* When handling interlacing some rows will be absent in each pass, the
@@ -4715,7 +5068,7 @@ progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass)
 
          if (pass != png_get_current_pass_number(pp))
             png_error(pp, "png_get_current_pass_number is broken");
-#endif
+#endif /* USER_TRANSFORM_INFO */
 
          y = PNG_ROW_FROM_PASS_ROW(y, pass);
       }
@@ -4726,38 +5079,39 @@ progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass)
 
       row = store_image_row(dp->ps, pp, 0, y);
 
-#ifdef PNG_READ_INTERLACING_SUPPORTED
       /* Combine the new row into the old: */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
       if (dp->do_interlace)
+#endif /* READ_INTERLACING */
       {
          if (dp->interlace_type == PNG_INTERLACE_ADAM7)
-            deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass);
+            deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass,
+                  dp->littleendian);
          else
-            row_copy(row, new_row, dp->pixel_size * dp->w);
+            row_copy(row, new_row, dp->pixel_size * dp->w, dp->littleendian);
       }
+#ifdef PNG_READ_INTERLACING_SUPPORTED
       else
          png_progressive_combine_row(pp, row, new_row);
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
    }
 
-#ifdef PNG_READ_INTERLACING_SUPPORTED
    else if (dp->interlace_type == PNG_INTERLACE_ADAM7 &&
        PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
        PNG_PASS_COLS(dp->w, pass) > 0)
       png_error(pp, "missing row in progressive de-interlacing");
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
 }
 
 static void
 sequential_row(standard_display *dp, png_structp pp, png_infop pi,
-    PNG_CONST int iImage, PNG_CONST int iDisplay)
+    const int iImage, const int iDisplay)
 {
-   PNG_CONST int         npasses = dp->npasses;
-   PNG_CONST int         do_interlace = dp->do_interlace &&
+   const int         npasses = dp->npasses;
+   const int         do_interlace = dp->do_interlace &&
       dp->interlace_type == PNG_INTERLACE_ADAM7;
-   PNG_CONST png_uint_32 height = standard_height(pp, dp->id);
-   PNG_CONST png_uint_32 width = standard_width(pp, dp->id);
-   PNG_CONST png_store*  ps = dp->ps;
+   const png_uint_32 height = standard_height(pp, dp->id);
+   const png_uint_32 width = standard_width(pp, dp->id);
+   const png_store*  ps = dp->ps;
    int pass;
 
    for (pass=0; pass<npasses; ++pass)
@@ -4792,11 +5146,11 @@ sequential_row(standard_display *dp, png_structp pp, png_infop pi,
 
                if (iImage >= 0)
                   deinterlace_row(store_image_row(ps, pp, iImage, y), row,
-                     dp->pixel_size, dp->w, pass);
+                     dp->pixel_size, dp->w, pass, dp->littleendian);
 
                if (iDisplay >= 0)
                   deinterlace_row(store_image_row(ps, pp, iDisplay, y), display,
-                     dp->pixel_size, dp->w, pass);
+                     dp->pixel_size, dp->w, pass, dp->littleendian);
             }
          }
          else
@@ -4943,14 +5297,6 @@ standard_row_validate(standard_display *dp, png_const_structp pp,
     * In earlier passes 'row' will be partially filled in, with only the pixels
     * that have been read so far, but 'display' will have those pixels
     * replicated to fill the unread pixels while reading an interlaced image.
-#if PNG_LIBPNG_VER < 10506
-    * The side effect inside the libpng sequential reader is that the 'row'
-    * array retains the correct values for unwritten pixels within the row
-    * bytes, while the 'display' array gets bits off the end of the image (in
-    * the last byte) trashed.  Unfortunately in the progressive reader the
-    * row bytes are always trashed, so we always do a pixel_cmp here even though
-    * a memcmp of all cbRow bytes will succeed for the sequential reader.
-#endif
     */
    if (iImage >= 0 &&
       (where = pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y),
@@ -4963,19 +5309,12 @@ standard_row_validate(standard_display *dp, png_const_structp pp,
       png_error(pp, msg);
    }
 
-#if PNG_LIBPNG_VER < 10506
-   /* In this case use pixel_cmp because we need to compare a partial
-    * byte at the end of the row if the row is not an exact multiple
-    * of 8 bits wide.  (This is fixed in libpng-1.5.6 and pixel_cmp is
-    * changed to match!)
-    */
-#endif
    if (iDisplay >= 0 &&
       (where = pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y),
          dp->bit_width)) != 0)
    {
       char msg[64];
-      sprintf(msg, "display  row[%lu][%d] changed from %.2x to %.2x",
+      sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x",
          (unsigned long)y, where-1, std[where-1],
          store_image_row(dp->ps, pp, iDisplay, y)[where-1]);
       png_error(pp, msg);
@@ -5020,7 +5359,7 @@ standard_end(png_structp ppIn, png_infop pi)
 
 /* A single test run checking the standard image to ensure it is not damaged. */
 static void
-standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id,
+standard_test(png_store* const psIn, png_uint_32 const id,
    int do_interlace, int use_update_info)
 {
    standard_display d;
@@ -5108,8 +5447,8 @@ standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id,
 }
 
 static int
-test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
-    int bdlo, int PNG_CONST bdhi)
+test_standard(png_modifier* const pm, png_byte const colour_type,
+    int bdlo, int const bdhi)
 {
    for (; bdlo <= bdhi; ++bdlo)
    {
@@ -5119,7 +5458,7 @@ test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
            interlace_type < INTERLACE_LAST; ++interlace_type)
       {
          standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
-            interlace_type, 0, 0, 0), 0/*do_interlace*/, pm->use_update_info);
+            interlace_type, 0, 0, 0), do_read_interlace, pm->use_update_info);
 
          if (fail(pm))
             return 0;
@@ -5154,8 +5493,8 @@ perform_standard_test(png_modifier *pm)
 
 /********************************** SIZE TESTS ********************************/
 static int
-test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
-    int bdlo, int PNG_CONST bdhi)
+test_size(png_modifier* const pm, png_byte const colour_type,
+    int bdlo, int const bdhi)
 {
    /* Run the tests on each combination.
     *
@@ -5164,8 +5503,10 @@ test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
     * width and height.  This is a waste of time in practice, hence the
     * hinc and winc stuff:
     */
-   static PNG_CONST png_byte hinc[] = {1, 3, 11, 1, 5};
-   static PNG_CONST png_byte winc[] = {1, 9, 5, 7, 1};
+   static const png_byte hinc[] = {1, 3, 11, 1, 5};
+   static const png_byte winc[] = {1, 9, 5, 7, 1};
+   const int save_bdlo = bdlo;
+
    for (; bdlo <= bdhi; ++bdlo)
    {
       png_uint_32 h, w;
@@ -5191,34 +5532,56 @@ test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
          if (fail(pm))
             return 0;
 
-#     ifdef PNG_WRITE_INTERLACING_SUPPORTED
+         /* Now validate the interlaced read side - do_interlace true,
+          * in the progressive case this does actually make a difference
+          * to the code used in the non-interlaced case too.
+          */
          standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
-            PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/,
+            PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/,
             pm->use_update_info);
 
          if (fail(pm))
             return 0;
 
+#     if CAN_WRITE_INTERLACE
+         /* Validate the pngvalid code itself: */
          standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
-            PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/,
+            PNG_INTERLACE_ADAM7, w, h, 1), 1/*do_interlace*/,
             pm->use_update_info);
 
          if (fail(pm))
             return 0;
 #     endif
+      }
+   }
 
-         /* Now validate the interlaced read side - do_interlace true,
-          * in the progressive case this does actually make a difference
-          * to the code used in the non-interlaced case too.
+   /* Now do the tests of libpng interlace handling, after we have made sure
+    * that the pngvalid version works:
+    */
+   for (bdlo = save_bdlo; bdlo <= bdhi; ++bdlo)
+   {
+      png_uint_32 h, w;
+
+      for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo])
+      {
+#     ifdef PNG_READ_INTERLACING_SUPPORTED
+         /* Test with pngvalid generated interlaced images first; we have
+          * already verify these are ok (unless pngvalid has self-consistent
+          * read/write errors, which is unlikely), so this detects errors in the
+          * read side first:
           */
+#     if CAN_WRITE_INTERLACE
          standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
-            PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/,
+            PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/,
             pm->use_update_info);
 
          if (fail(pm))
             return 0;
+#     endif
+#     endif /* READ_INTERLACING */
 
 #     ifdef PNG_WRITE_INTERLACING_SUPPORTED
+         /* Test the libpng write side against the pngvalid read side: */
          standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/,
             pm->use_update_info);
@@ -5226,6 +5589,18 @@ test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
          if (fail(pm))
             return 0;
 #     endif
+
+#     ifdef PNG_READ_INTERLACING_SUPPORTED
+#     ifdef PNG_WRITE_INTERLACING_SUPPORTED
+         /* Test both together: */
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
+            PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/,
+            pm->use_update_info);
+
+         if (fail(pm))
+            return 0;
+#     endif
+#     endif /* READ_INTERLACING */
       }
    }
 
@@ -5274,10 +5649,17 @@ typedef struct image_pixel
     */
    unsigned int red, green, blue, alpha; /* For non-palette images. */
    unsigned int palette_index;           /* For a palette image. */
-   png_byte colour_type;                 /* As in the spec. */
-   png_byte bit_depth;                   /* Defines bit size in row */
-   png_byte sample_depth;                /* Scale of samples */
-   int      have_tRNS;                   /* tRNS chunk may need processing */
+   png_byte     colour_type;             /* As in the spec. */
+   png_byte     bit_depth;               /* Defines bit size in row */
+   png_byte     sample_depth;            /* Scale of samples */
+   unsigned int have_tRNS :1;            /* tRNS chunk may need processing */
+   unsigned int swap_rgb :1;             /* RGB swapped to BGR */
+   unsigned int alpha_first :1;          /* Alpha at start, not end */
+   unsigned int alpha_inverted :1;       /* Alpha channel inverted */
+   unsigned int mono_inverted :1;        /* Gray channel inverted */
+   unsigned int swap16 :1;               /* Byte swap 16-bit components */
+   unsigned int littleendian :1;         /* High bits on right */
+   unsigned int sig_bits :1;             /* Pixel shifted (sig bits only) */
 
    /* For checking the code calculates double precision floating point values
     * along with an error value, accumulated from the transforms.  Because an
@@ -5285,6 +5667,9 @@ typedef struct image_pixel
     * up to just less than +/-1 in the scaled value) the *lowest* sBIT for each
     * channel is stored.  This sBIT value is folded in to the stored error value
     * at the end of the application of the transforms to the pixel.
+    *
+    * If sig_bits is set above the red, green, blue and alpha values have been
+    * scaled so they only contain the significant bits of the component values.
     */
    double   redf, greenf, bluef, alphaf;
    double   rede, greene, bluee, alphae;
@@ -5293,26 +5678,27 @@ typedef struct image_pixel
 
 /* Shared utility function, see below. */
 static void
-image_pixel_setf(image_pixel *this, unsigned int max)
+image_pixel_setf(image_pixel *this, unsigned int rMax, unsigned int gMax,
+        unsigned int bMax, unsigned int aMax)
 {
-   this->redf = this->red / (double)max;
-   this->greenf = this->green / (double)max;
-   this->bluef = this->blue / (double)max;
-   this->alphaf = this->alpha / (double)max;
+   this->redf = this->red / (double)rMax;
+   this->greenf = this->green / (double)gMax;
+   this->bluef = this->blue / (double)bMax;
+   this->alphaf = this->alpha / (double)aMax;
 
-   if (this->red < max)
+   if (this->red < rMax)
       this->rede = this->redf * DBL_EPSILON;
    else
       this->rede = 0;
-   if (this->green < max)
+   if (this->green < gMax)
       this->greene = this->greenf * DBL_EPSILON;
    else
       this->greene = 0;
-   if (this->blue < max)
+   if (this->blue < bMax)
       this->bluee = this->bluef * DBL_EPSILON;
    else
       this->bluee = 0;
-   if (this->alpha < max)
+   if (this->alpha < aMax)
       this->alphae = this->alphaf * DBL_EPSILON;
    else
       this->alphae = 0;
@@ -5324,18 +5710,22 @@ image_pixel_setf(image_pixel *this, unsigned int max)
  */
 static void
 image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
-    png_byte bit_depth, png_uint_32 x, store_palette palette)
+    png_byte bit_depth, png_uint_32 x, store_palette palette,
+    const image_pixel *format /*from pngvalid transform of input*/)
 {
-   PNG_CONST png_byte sample_depth = (png_byte)(colour_type ==
+   const png_byte sample_depth = (png_byte)(colour_type ==
       PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth);
-   PNG_CONST unsigned int max = (1U<<sample_depth)-1;
+   const unsigned int max = (1U<<sample_depth)-1;
+   const int swap16 = (format != 0 && format->swap16);
+   const int littleendian = (format != 0 && format->littleendian);
+   const int sig_bits = (format != 0 && format->sig_bits);
 
    /* Initially just set everything to the same number and the alpha to opaque.
     * Note that this currently assumes a simple palette where entry x has colour
     * rgb(x,x,x)!
     */
    this->palette_index = this->red = this->green = this->blue =
-      sample(row, colour_type, bit_depth, x, 0);
+      sample(row, colour_type, bit_depth, x, 0, swap16, littleendian);
    this->alpha = max;
    this->red_sBIT = this->green_sBIT = this->blue_sBIT = this->alpha_sBIT =
       sample_depth;
@@ -5346,7 +5736,7 @@ image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
       /* This permits the caller to default to the sample value. */
       if (palette != 0)
       {
-         PNG_CONST unsigned int i = this->palette_index;
+         const unsigned int i = this->palette_index;
 
          this->red = palette[i].red;
          this->green = palette[i].green;
@@ -5359,21 +5749,52 @@ image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
    {
       unsigned int i = 0;
 
+      if ((colour_type & 4) != 0 && format != 0 && format->alpha_first)
+      {
+         this->alpha = this->red;
+         /* This handles the gray case for 'AG' pixels */
+         this->palette_index = this->red = this->green = this->blue =
+            sample(row, colour_type, bit_depth, x, 1, swap16, littleendian);
+         i = 1;
+      }
+
       if (colour_type & 2)
       {
-         this->green = sample(row, colour_type, bit_depth, x, 1);
-         this->blue = sample(row, colour_type, bit_depth, x, 2);
-         i = 2;
+         /* Green is second for both BGR and RGB: */
+         this->green = sample(row, colour_type, bit_depth, x, ++i, swap16,
+                 littleendian);
+
+         if (format != 0 && format->swap_rgb) /* BGR */
+             this->red = sample(row, colour_type, bit_depth, x, ++i, swap16,
+                     littleendian);
+         else
+             this->blue = sample(row, colour_type, bit_depth, x, ++i, swap16,
+                     littleendian);
+      }
+
+      else /* grayscale */ if (format != 0 && format->mono_inverted)
+         this->red = this->green = this->blue = this->red ^ max;
+
+      if ((colour_type & 4) != 0) /* alpha */
+      {
+         if (format == 0 || !format->alpha_first)
+             this->alpha = sample(row, colour_type, bit_depth, x, ++i, swap16,
+                     littleendian);
+
+         if (format != 0 && format->alpha_inverted)
+            this->alpha ^= max;
       }
-      if (colour_type & 4)
-         this->alpha = sample(row, colour_type, bit_depth, x, ++i);
    }
 
    /* Calculate the scaled values, these are simply the values divided by
     * 'max' and the error is initialized to the double precision epsilon value
     * from the header file.
     */
-   image_pixel_setf(this, max);
+   image_pixel_setf(this,
+      sig_bits ? (1U << format->red_sBIT)-1 : max,
+      sig_bits ? (1U << format->green_sBIT)-1 : max,
+      sig_bits ? (1U << format->blue_sBIT)-1 : max,
+      sig_bits ? (1U << format->alpha_sBIT)-1 : max);
 
    /* Store the input information for use in the transforms - these will
     * modify the information.
@@ -5382,8 +5803,18 @@ image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
    this->bit_depth = bit_depth;
    this->sample_depth = sample_depth;
    this->have_tRNS = 0;
-}
-
+   this->swap_rgb = 0;
+   this->alpha_first = 0;
+   this->alpha_inverted = 0;
+   this->mono_inverted = 0;
+   this->swap16 = 0;
+   this->littleendian = 0;
+   this->sig_bits = 0;
+}
+
+#if defined PNG_READ_EXPAND_SUPPORTED || defined PNG_READ_GRAY_TO_RGB_SUPPORTED\
+   || defined PNG_READ_EXPAND_SUPPORTED || defined PNG_READ_EXPAND_16_SUPPORTED\
+   || defined PNG_READ_BACKGROUND_SUPPORTED
 /* Convert a palette image to an rgb image.  This necessarily converts the tRNS
  * chunk at the same time, because the tRNS will be in palette form.  The way
  * palette validation works means that the original palette is never updated,
@@ -5413,10 +5844,14 @@ image_pixel_convert_PLTE(image_pixel *this)
 
 /* Add an alpha channel; this will import the tRNS information because tRNS is
  * not valid in an alpha image.  The bit depth will invariably be set to at
- * least 8.  Palette images will be converted to alpha (using the above API).
+ * least 8 prior to 1.7.0.  Palette images will be converted to alpha (using
+ * the above API).  With png_set_background the alpha channel is never expanded
+ * but this routine is used by pngvalid to simplify code; 'for_background'
+ * records this.
  */
 static void
-image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
+image_pixel_add_alpha(image_pixel *this, const standard_display *display,
+   int for_background)
 {
    if (this->colour_type == PNG_COLOR_TYPE_PALETTE)
       image_pixel_convert_PLTE(this);
@@ -5425,11 +5860,21 @@ image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
    {
       if (this->colour_type == PNG_COLOR_TYPE_GRAY)
       {
-         if (this->bit_depth < 8)
-            this->bit_depth = 8;
+#        if PNG_LIBPNG_VER < 10700
+            if (!for_background && this->bit_depth < 8)
+               this->bit_depth = this->sample_depth = 8;
+#        endif
 
          if (this->have_tRNS)
          {
+            /* After 1.7 the expansion of bit depth only happens if there is a
+             * tRNS chunk to expand at this point.
+             */
+#           if PNG_LIBPNG_VER >= 10700
+               if (!for_background && this->bit_depth < 8)
+                  this->bit_depth = this->sample_depth = 8;
+#           endif
+
             this->have_tRNS = 0;
 
             /* Check the input, original, channel value here against the
@@ -5461,9 +5906,11 @@ image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
                this->alphaf = 0;
             else
                this->alphaf = 1;
-
-            this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
          }
+         else
+            this->alphaf = 1;
+
+         this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
       }
 
       /* The error in the alpha is zero and the sBIT value comes from the
@@ -5473,18 +5920,19 @@ image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
       this->alpha_sBIT = display->alpha_sBIT;
    }
 }
+#endif /* transforms that need image_pixel_add_alpha */
 
 struct transform_display;
 typedef struct image_transform
 {
    /* The name of this transform: a string. */
-   PNG_CONST char *name;
+   const char *name;
 
    /* Each transform can be disabled from the command line: */
    int enable;
 
    /* The global list of transforms; read only. */
-   struct image_transform *PNG_CONST list;
+   struct image_transform *const list;
 
    /* The global count of the number of times this transform has been set on an
     * image.
@@ -5497,7 +5945,7 @@ typedef struct image_transform
    /* The next transform in the list, each transform must call its own next
     * transform after it has processed the pixel successfully.
     */
-   PNG_CONST struct image_transform *next;
+   const struct image_transform *next;
 
    /* A single transform for the image, expressed as a series of function
     * callbacks and some space for values.
@@ -5505,12 +5953,12 @@ typedef struct image_transform
     * First a callback to add any required modifications to the png_modifier;
     * this gets called just before the modifier is set up for read.
     */
-   void (*ini)(PNG_CONST struct image_transform *this,
+   void (*ini)(const struct image_transform *this,
       struct transform_display *that);
 
    /* And a callback to set the transform on the current png_read_struct:
     */
-   void (*set)(PNG_CONST struct image_transform *this,
+   void (*set)(const struct image_transform *this,
       struct transform_display *that, png_structp pp, png_infop pi);
 
    /* Then a transform that takes an input pixel in one PNG format or another
@@ -5519,8 +5967,8 @@ typedef struct image_transform
     * in the libpng implementation!)  The png_structp is solely to allow error
     * reporting via png_error and png_warning.
     */
-   void (*mod)(PNG_CONST struct image_transform *this, image_pixel *that,
-      png_const_structp pp, PNG_CONST struct transform_display *display);
+   void (*mod)(const struct image_transform *this, image_pixel *that,
+      png_const_structp pp, const struct transform_display *display);
 
    /* Add this transform to the list and return true if the transform is
     * meaningful for this colour type and bit depth - if false then the
@@ -5528,7 +5976,7 @@ typedef struct image_transform
     * point running it.
     */
    int (*add)(struct image_transform *this,
-      PNG_CONST struct image_transform **that, png_byte colour_type,
+      const struct image_transform **that, png_byte colour_type,
       png_byte bit_depth);
 } image_transform;
 
@@ -5538,11 +5986,13 @@ typedef struct transform_display
 
    /* Parameters */
    png_modifier*              pm;
-   PNG_CONST image_transform* transform_list;
+   const image_transform* transform_list;
+   unsigned int max_gamma_8;
 
    /* Local variables */
    png_byte output_colour_type;
    png_byte output_bit_depth;
+   png_byte unpacked;
 
    /* Modifications (not necessarily used.) */
    gama_modification gama_mod;
@@ -5579,7 +6029,7 @@ transform_set_encoding(transform_display *this)
 
 /* Three functions to end the list: */
 static void
-image_transform_ini_end(PNG_CONST image_transform *this,
+image_transform_ini_end(const image_transform *this,
    transform_display *that)
 {
    UNUSED(this)
@@ -5587,7 +6037,7 @@ image_transform_ini_end(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_set_end(PNG_CONST image_transform *this,
+image_transform_set_end(const image_transform *this,
    transform_display *that, png_structp pp, png_infop pi)
 {
    UNUSED(this)
@@ -5614,10 +6064,11 @@ sample_scale(double sample_value, unsigned int scale)
 }
 
 static void
-image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that,
-    png_const_structp pp, PNG_CONST transform_display *display)
+image_transform_mod_end(const image_transform *this, image_pixel *that,
+    png_const_structp pp, const transform_display *display)
 {
-   PNG_CONST unsigned int scale = (1U<<that->sample_depth)-1;
+   const unsigned int scale = (1U<<that->sample_depth)-1;
+   const int sig_bits = that->sig_bits;
 
    UNUSED(this)
    UNUSED(pp)
@@ -5632,6 +6083,13 @@ image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that,
     */
    that->red = sample_scale(that->redf, scale);
 
+   /* This is a bit bogus; really the above calculation should use the red_sBIT
+    * value, not sample_depth, but because libpng does png_set_shift by just
+    * shifting the bits we get errors if we don't do it the same way.
+    */
+   if (sig_bits && that->red_sBIT < that->sample_depth)
+      that->red >>= that->sample_depth - that->red_sBIT;
+
    /* The error value is increased, at the end, according to the lowest sBIT
     * value seen.  Common sense tells us that the intermediate integer
     * representations are no more accurate than +/- 0.5 in the integral values,
@@ -5647,7 +6105,13 @@ image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that,
    if (that->colour_type & PNG_COLOR_MASK_COLOR)
    {
       that->green = sample_scale(that->greenf, scale);
+      if (sig_bits && that->green_sBIT < that->sample_depth)
+         that->green >>= that->sample_depth - that->green_sBIT;
+
       that->blue = sample_scale(that->bluef, scale);
+      if (sig_bits && that->blue_sBIT < that->sample_depth)
+         that->blue >>= that->sample_depth - that->blue_sBIT;
+
       that->greene += 1./(2*((1U<<that->green_sBIT)-1));
       that->bluee += 1./(2*((1U<<that->blue_sBIT)-1));
    }
@@ -5667,9 +6131,12 @@ image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that,
    else
    {
       that->alpha = scale; /* opaque */
-      that->alpha = 1;     /* Override this. */
+      that->alphaf = 1;    /* Override this. */
       that->alphae = 0;    /* It's exact ;-) */
    }
+
+   if (sig_bits && that->alpha_sBIT < that->sample_depth)
+      that->alpha >>= that->sample_depth - that->alpha_sBIT;
 }
 
 /* Static 'end' structure: */
@@ -5692,21 +6159,23 @@ static image_transform image_transform_end =
  */
 static void
 transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id,
-    PNG_CONST image_transform *transform_list)
+    const image_transform *transform_list)
 {
    memset(dp, 0, sizeof *dp);
 
    /* Standard fields */
-   standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/,
+   standard_display_init(&dp->this, &pm->this, id, do_read_interlace,
       pm->use_update_info);
 
    /* Parameter fields */
    dp->pm = pm;
    dp->transform_list = transform_list;
+   dp->max_gamma_8 = 16;
 
    /* Local variable fields */
    dp->output_colour_type = 255; /* invalid */
    dp->output_bit_depth = 255;  /* invalid */
+   dp->unpacked = 0; /* not unpacked */
 }
 
 static void
@@ -5734,6 +6203,14 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi)
    dp->output_colour_type = png_get_color_type(pp, pi);
    dp->output_bit_depth = png_get_bit_depth(pp, pi);
 
+   /* If png_set_filler is in action then fake the output color type to include
+    * an alpha channel where appropriate.
+    */
+   if (dp->output_bit_depth >= 8 &&
+       (dp->output_colour_type == PNG_COLOR_TYPE_RGB ||
+        dp->output_colour_type == PNG_COLOR_TYPE_GRAY) && dp->this.filler)
+       dp->output_colour_type |= 4;
+
    /* Validate the combination of colour type and bit depth that we are getting
     * out of libpng; the semantics of something not in the PNG spec are, at
     * best, unclear.
@@ -5768,7 +6245,8 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi)
    }
 
    /* Use a test pixel to check that the output agrees with what we expect -
-    * this avoids running the whole test if the output is unexpected.
+    * this avoids running the whole test if the output is unexpected.  This also
+    * checks for internal errors.
     */
    {
       image_pixel test_pixel;
@@ -5783,7 +6261,7 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi)
       /* Don't need sBIT here, but it must be set to non-zero to avoid
        * arithmetic overflows.
        */
-      test_pixel.have_tRNS = dp->this.is_transparent;
+      test_pixel.have_tRNS = dp->this.is_transparent != 0;
       test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT =
          test_pixel.alpha_sBIT = test_pixel.sample_depth;
 
@@ -5814,22 +6292,41 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi)
       }
 
       /* If both bit depth and colour type are correct check the sample depth.
-       * I believe these are both internal errors.
        */
-      if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE)
+      if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE &&
+          test_pixel.sample_depth != 8) /* oops - internal error! */
+         png_error(pp, "pngvalid: internal: palette sample depth not 8");
+      else if (dp->unpacked && test_pixel.bit_depth != 8)
+         png_error(pp, "pngvalid: internal: bad unpacked pixel depth");
+      else if (!dp->unpacked && test_pixel.colour_type != PNG_COLOR_TYPE_PALETTE
+              && test_pixel.bit_depth != test_pixel.sample_depth)
       {
-         if (test_pixel.sample_depth != 8) /* oops - internal error! */
-            png_error(pp, "pngvalid: internal: palette sample depth not 8");
+         char message[128];
+         size_t pos = safecat(message, sizeof message, 0,
+            "internal: sample depth ");
+
+         /* Because unless something has set 'unpacked' or the image is palette
+          * mapped we expect the transform to keep sample depth and bit depth
+          * the same.
+          */
+         pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth);
+         pos = safecat(message, sizeof message, pos, " expected ");
+         pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth);
+
+         png_error(pp, message);
       }
-      else if (test_pixel.sample_depth != dp->output_bit_depth)
+      else if (test_pixel.bit_depth != dp->output_bit_depth)
       {
+         /* This could be a libpng error too; libpng has not produced what we
+          * expect for the output bit depth.
+          */
          char message[128];
          size_t pos = safecat(message, sizeof message, 0,
-            "internal: sample depth ");
+            "internal: bit depth ");
 
          pos = safecatn(message, sizeof message, pos, dp->output_bit_depth);
          pos = safecat(message, sizeof message, pos, " expected ");
-         pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth);
+         pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth);
 
          png_error(pp, message);
       }
@@ -5847,7 +6344,7 @@ static void
 transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
    unsigned int b, unsigned int a, unsigned int in_digitized, double in,
    unsigned int out, png_byte sample_depth, double err, double limit,
-   PNG_CONST char *name, double digitization_error)
+   const char *name, double digitization_error)
 {
    /* Compare the scaled, digitzed, values of our local calculation (in+-err)
     * with the digitized values libpng produced;  'sample_depth' is the actual
@@ -5858,7 +6355,7 @@ transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
    unsigned int max = (1U<<sample_depth)-1;
    double in_min = ceil((in-err)*max - digitization_error);
    double in_max = floor((in+err)*max + digitization_error);
-   if (err > limit || !(out >= in_min && out <= in_max))
+   if (debugonly(err > limit ||) !(out >= in_min && out <= in_max))
    {
       char message[256];
       size_t pos;
@@ -5884,6 +6381,8 @@ transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
 
       png_error(pp, message);
    }
+
+   UNUSED(limit)
 }
 
 static void
@@ -5891,20 +6390,20 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
    png_infop pi)
 {
    /* Constants for the loop below: */
-   PNG_CONST png_store* PNG_CONST ps = dp->this.ps;
-   PNG_CONST png_byte in_ct = dp->this.colour_type;
-   PNG_CONST png_byte in_bd = dp->this.bit_depth;
-   PNG_CONST png_uint_32 w = dp->this.w;
-   PNG_CONST png_uint_32 h = dp->this.h;
-   PNG_CONST png_byte out_ct = dp->output_colour_type;
-   PNG_CONST png_byte out_bd = dp->output_bit_depth;
-   PNG_CONST png_byte sample_depth = (png_byte)(out_ct ==
+   const png_store* const ps = dp->this.ps;
+   const png_byte in_ct = dp->this.colour_type;
+   const png_byte in_bd = dp->this.bit_depth;
+   const png_uint_32 w = dp->this.w;
+   const png_uint_32 h = dp->this.h;
+   const png_byte out_ct = dp->output_colour_type;
+   const png_byte out_bd = dp->output_bit_depth;
+   const png_byte sample_depth = (png_byte)(out_ct ==
       PNG_COLOR_TYPE_PALETTE ? 8 : out_bd);
-   PNG_CONST png_byte red_sBIT = dp->this.red_sBIT;
-   PNG_CONST png_byte green_sBIT = dp->this.green_sBIT;
-   PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT;
-   PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT;
-   PNG_CONST int have_tRNS = dp->this.is_transparent;
+   const png_byte red_sBIT = dp->this.red_sBIT;
+   const png_byte green_sBIT = dp->this.green_sBIT;
+   const png_byte blue_sBIT = dp->this.blue_sBIT;
+   const png_byte alpha_sBIT = dp->this.alpha_sBIT;
+   const int have_tRNS = dp->this.is_transparent;
    double digitization_error;
 
    store_palette out_palette;
@@ -5959,7 +6458,7 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
 
    for (y=0; y<h; ++y)
    {
-      png_const_bytep PNG_CONST pRow = store_image_row(ps, pp, 0, y);
+      png_const_bytep const pRow = store_image_row(ps, pp, 0, y);
       png_uint_32 x;
 
       /* The original, standard, row pre-transforms. */
@@ -5976,13 +6475,14 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
          unsigned int r, g, b, a;
 
          /* Find out what we think the pixel should be: */
-         image_pixel_init(&in_pixel, std, in_ct, in_bd, x, dp->this.palette);
+         image_pixel_init(&in_pixel, std, in_ct, in_bd, x, dp->this.palette,
+                 NULL);
 
          in_pixel.red_sBIT = red_sBIT;
          in_pixel.green_sBIT = green_sBIT;
          in_pixel.blue_sBIT = blue_sBIT;
          in_pixel.alpha_sBIT = alpha_sBIT;
-         in_pixel.have_tRNS = have_tRNS;
+         in_pixel.have_tRNS = have_tRNS != 0;
 
          /* For error detection, below. */
          r = in_pixel.red;
@@ -5990,12 +6490,18 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
          b = in_pixel.blue;
          a = in_pixel.alpha;
 
+         /* This applies the transforms to the input data, including output
+          * format operations which must be used when reading the output
+          * pixel that libpng produces.
+          */
          dp->transform_list->mod(dp->transform_list, &in_pixel, pp, dp);
 
          /* Read the output pixel and compare it to what we got, we don't
-          * use the error field here, so no need to update sBIT.
+          * use the error field here, so no need to update sBIT.  in_pixel
+          * says whether we expect libpng to change the output format.
           */
-         image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette);
+         image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette,
+                 &in_pixel);
 
          /* We don't expect changes to the index here even if the bit depth is
           * changed.
@@ -6058,8 +6564,8 @@ transform_end(png_structp ppIn, png_infop pi)
 
 /* A single test run. */
 static void
-transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
-    PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name)
+transform_test(png_modifier *pmIn, const png_uint_32 idIn,
+    const image_transform* transform_listIn, const char * const name)
 {
    transform_display d;
    context(&pmIn->this, fault);
@@ -6160,8 +6666,11 @@ static image_transform ITSTRUCT(name) =\
 #define PT ITSTRUCT(end) /* stores the previous transform */
 
 /* To save code: */
-static void
-image_transform_default_ini(PNG_CONST image_transform *this,
+extern void image_transform_default_ini(const image_transform *this,
+   transform_display *that); /* silence GCC warnings */
+
+void /* private, but almost always needed */
+image_transform_default_ini(const image_transform *this,
     transform_display *that)
 {
    this->next->ini(this->next, that);
@@ -6170,7 +6679,7 @@ image_transform_default_ini(PNG_CONST image_transform *this,
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
 static int
 image_transform_default_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(colour_type)
    UNUSED(bit_depth)
@@ -6185,7 +6694,7 @@ image_transform_default_add(image_transform *this,
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_palette_to_rgb */
 static void
-image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this,
+image_transform_png_set_palette_to_rgb_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_palette_to_rgb(pp);
@@ -6193,9 +6702,9 @@ image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this,
+image_transform_png_set_palette_to_rgb_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
       image_pixel_convert_PLTE(that);
@@ -6205,7 +6714,7 @@ image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_palette_to_rgb_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -6223,28 +6732,42 @@ IT(palette_to_rgb);
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_tRNS_to_alpha */
 static void
-image_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this,
+image_transform_png_set_tRNS_to_alpha_set(const image_transform *this,
    transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_tRNS_to_alpha(pp);
+
+   /* If there was a tRNS chunk that would get expanded and add an alpha
+    * channel is_transparent must be updated:
+    */
+   if (that->this.has_tRNS)
+      that->this.is_transparent = 1;
+
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_tRNS_to_alpha_mod(const image_transform *this,
    image_pixel *that, png_const_structp pp,
-   PNG_CONST transform_display *display)
+   const transform_display *display)
 {
+#if PNG_LIBPNG_VER < 10700
    /* LIBPNG BUG: this always forces palette images to RGB. */
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
       image_pixel_convert_PLTE(that);
+#endif
 
    /* This effectively does an 'expand' only if there is some transparency to
     * convert to an alpha channel.
     */
    if (that->have_tRNS)
-      image_pixel_add_alpha(that, &display->this);
+#     if PNG_LIBPNG_VER >= 10700
+         if (that->colour_type != PNG_COLOR_TYPE_PALETTE &&
+             (that->colour_type & PNG_COLOR_MASK_ALPHA) == 0)
+#     endif
+      image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
 
+#if PNG_LIBPNG_VER < 10700
    /* LIBPNG BUG: otherwise libpng still expands to 8 bits! */
    else
    {
@@ -6253,13 +6776,14 @@ image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this,
       if (that->sample_depth < 8)
          that->sample_depth = 8;
    }
+#endif
 
    this->next->mod(this->next, that, pp, display);
 }
 
 static int
 image_transform_png_set_tRNS_to_alpha_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -6268,9 +6792,14 @@ image_transform_png_set_tRNS_to_alpha_add(image_transform *this,
 
    /* We don't know yet whether there will be a tRNS chunk, but we know that
     * this transformation should do nothing if there already is an alpha
-    * channel.
+    * channel.  In addition, after the bug fix in 1.7.0, there is no longer
+    * any action on a palette image.
     */
-   return (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
+   return
+#  if PNG_LIBPNG_VER >= 10700
+      colour_type != PNG_COLOR_TYPE_PALETTE &&
+#  endif
+   (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
 }
 
 IT(tRNS_to_alpha);
@@ -6281,17 +6810,18 @@ IT(tRNS_to_alpha);
 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 /* png_set_gray_to_rgb */
 static void
-image_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this,
+image_transform_png_set_gray_to_rgb_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_gray_to_rgb(pp);
+   /* NOTE: this doesn't result in tRNS expansion. */
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this,
+image_transform_png_set_gray_to_rgb_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    /* NOTE: we can actually pend the tRNS processing at this point because we
     * can correctly recognize the original pixel value even though we have
@@ -6299,7 +6829,7 @@ image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this,
     * doesn't do this, so we don't either.
     */
    if ((that->colour_type & PNG_COLOR_MASK_COLOR) == 0 && that->have_tRNS)
-      image_pixel_add_alpha(that, &display->this);
+      image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
 
    /* Simply expand the bit depth and alter the colour type as required. */
    if (that->colour_type == PNG_COLOR_TYPE_GRAY)
@@ -6322,7 +6852,7 @@ image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_gray_to_rgb_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -6340,17 +6870,21 @@ IT(gray_to_rgb);
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_expand */
 static void
-image_transform_png_set_expand_set(PNG_CONST image_transform *this,
+image_transform_png_set_expand_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_expand(pp);
+
+   if (that->this.has_tRNS)
+      that->this.is_transparent = 1;
+
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_expand_mod(PNG_CONST image_transform *this,
+image_transform_png_set_expand_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    /* The general expand case depends on what the colour type is: */
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
@@ -6359,14 +6893,14 @@ image_transform_png_set_expand_mod(PNG_CONST image_transform *this,
       that->sample_depth = that->bit_depth = 8;
 
    if (that->have_tRNS)
-      image_pixel_add_alpha(that, &display->this);
+      image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
 
    this->next->mod(this->next, that, pp, display);
 }
 
 static int
 image_transform_png_set_expand_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -6386,31 +6920,53 @@ IT(expand);
 
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_expand_gray_1_2_4_to_8
- * LIBPNG BUG: this just does an 'expand'
+ * Pre 1.7.0 LIBPNG BUG: this just does an 'expand'
  */
 static void
 image_transform_png_set_expand_gray_1_2_4_to_8_set(
-    PNG_CONST image_transform *this, transform_display *that, png_structp pp,
+    const image_transform *this, transform_display *that, png_structp pp,
     png_infop pi)
 {
    png_set_expand_gray_1_2_4_to_8(pp);
+   /* NOTE: don't expect this to expand tRNS */
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
 image_transform_png_set_expand_gray_1_2_4_to_8_mod(
-    PNG_CONST image_transform *this, image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const image_transform *this, image_pixel *that, png_const_structp pp,
+    const transform_display *display)
 {
+#if PNG_LIBPNG_VER < 10700
    image_transform_png_set_expand_mod(this, that, pp, display);
+#else
+   /* Only expand grayscale of bit depth less than 8: */
+   if (that->colour_type == PNG_COLOR_TYPE_GRAY &&
+       that->bit_depth < 8)
+      that->sample_depth = that->bit_depth = 8;
+
+   this->next->mod(this->next, that, pp, display);
+#endif /* 1.7 or later */
 }
 
 static int
 image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
+#if PNG_LIBPNG_VER < 10700
    return image_transform_png_set_expand_add(this, that, colour_type,
       bit_depth);
+#else
+   UNUSED(bit_depth)
+
+   this->next = *that;
+   *that = this;
+
+   /* This should do nothing unless the color type is gray and the bit depth is
+    * less than 8:
+    */
+   return colour_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8;
+#endif /* 1.7 or later */
 }
 
 IT(expand_gray_1_2_4_to_8);
@@ -6421,17 +6977,24 @@ IT(expand_gray_1_2_4_to_8);
 #ifdef PNG_READ_EXPAND_16_SUPPORTED
 /* png_set_expand_16 */
 static void
-image_transform_png_set_expand_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_expand_16_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_expand_16(pp);
+
+   /* NOTE: prior to 1.7 libpng does SET_EXPAND as well, so tRNS is expanded. */
+#  if PNG_LIBPNG_VER < 10700
+      if (that->this.has_tRNS)
+         that->this.is_transparent = 1;
+#  endif
+
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_expand_16_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    /* Expect expand_16 to expand everything to 16 bits as a result of also
     * causing 'expand' to happen.
@@ -6440,7 +7003,7 @@ image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this,
       image_pixel_convert_PLTE(that);
 
    if (that->have_tRNS)
-      image_pixel_add_alpha(that, &display->this);
+      image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
 
    if (that->bit_depth < 16)
       that->sample_depth = that->bit_depth = 16;
@@ -6450,7 +7013,7 @@ image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_expand_16_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(colour_type)
 
@@ -6469,17 +7032,21 @@ IT(expand_16);
 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED  /* API added in 1.5.4 */
 /* png_set_scale_16 */
 static void
-image_transform_png_set_scale_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_scale_16_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_scale_16(pp);
+#  if PNG_LIBPNG_VER < 10700
+      /* libpng will limit the gamma table size: */
+      that->max_gamma_8 = PNG_MAX_GAMMA_8;
+#  endif
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_scale_16_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    if (that->bit_depth == 16)
    {
@@ -6495,7 +7062,7 @@ image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_scale_16_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(colour_type)
 
@@ -6513,17 +7080,21 @@ IT(scale_16);
 #ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */
 /* png_set_strip_16 */
 static void
-image_transform_png_set_strip_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_strip_16_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_strip_16(pp);
+#  if PNG_LIBPNG_VER < 10700
+      /* libpng will limit the gamma table size: */
+      that->max_gamma_8 = PNG_MAX_GAMMA_8;
+#  endif
    this->next->set(this->next, that, pp, pi);
 }
 
 static void
-image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_strip_16_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    if (that->bit_depth == 16)
    {
@@ -6548,7 +7119,7 @@ image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this,
           * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!)
           */
          {
-            PNG_CONST double d = (255-128.5)/65535;
+            const double d = (255-128.5)/65535;
             that->rede += d;
             that->greene += d;
             that->bluee += d;
@@ -6562,7 +7133,7 @@ image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_strip_16_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(colour_type)
 
@@ -6580,7 +7151,7 @@ IT(strip_16);
 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 /* png_set_strip_alpha */
 static void
-image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this,
+image_transform_png_set_strip_alpha_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_set_strip_alpha(pp);
@@ -6588,9 +7159,9 @@ image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_strip_alpha_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
       that->colour_type = PNG_COLOR_TYPE_GRAY;
@@ -6605,7 +7176,7 @@ image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_strip_alpha_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -6626,7 +7197,8 @@ IT(strip_alpha);
  *    png_fixed_point green)
  * png_get_rgb_to_gray_status
  *
- * The 'default' test here uses values known to be used inside libpng:
+ * The 'default' test here uses values known to be used inside libpng prior to
+ * 1.7.0:
  *
  *   red:    6968
  *   green: 23434
@@ -6663,11 +7235,11 @@ static struct
 #undef image_transform_ini
 #define image_transform_ini image_transform_png_set_rgb_to_gray_ini
 static void
-image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
+image_transform_png_set_rgb_to_gray_ini(const image_transform *this,
     transform_display *that)
 {
    png_modifier *pm = that->pm;
-   PNG_CONST color_encoding *e = pm->current_encoding;
+   const color_encoding *e = pm->current_encoding;
 
    UNUSED(this)
 
@@ -6682,7 +7254,7 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
       /* Coefficients come from the encoding, but may need to be normalized to a
        * white point Y of 1.0
        */
-      PNG_CONST double whiteY = e->red.Y + e->green.Y + e->blue.Y;
+      const double whiteY = e->red.Y + e->green.Y + e->blue.Y;
 
       data.red_coefficient = e->red.Y;
       data.green_coefficient = e->green.Y;
@@ -6699,9 +7271,15 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
    else
    {
       /* The default (built in) coeffcients, as above: */
-      data.red_coefficient = 6968 / 32768.;
-      data.green_coefficient = 23434 / 32768.;
-      data.blue_coefficient = 2366 / 32768.;
+#     if PNG_LIBPNG_VER < 10700
+         data.red_coefficient = 6968 / 32768.;
+         data.green_coefficient = 23434 / 32768.;
+         data.blue_coefficient = 2366 / 32768.;
+#     else
+         data.red_coefficient = .2126;
+         data.green_coefficient = .7152;
+         data.blue_coefficient = .0722;
+#     endif
    }
 
    data.gamma = pm->current_gamma;
@@ -6735,7 +7313,7 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
       png_uint_32 ru;
       double total;
 
-      RANDOMIZE(ru);
+      R32(ru);
       data.green_coefficient = total = (ru & 0xffff) / 65535.;
       ru >>= 16;
       data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.;
@@ -6776,14 +7354,15 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
           *  conversion adds another +/-2 in the 16-bit case and
           *  +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case.
           */
-         that->pm->limit +=
-#        if PNG_MAX_GAMMA_8 < 14
-               pow((that->this.bit_depth == 16 ?
-                  8. : 6. + (1<<(15-PNG_MAX_GAMMA_8)))/65535, data.gamma);
-#        else
-               pow((that->this.bit_depth == 16 ?
-                  8. : 8. + (1<<(15-PNG_MAX_GAMMA_8)))/65535, data.gamma);
+#        if PNG_LIBPNG_VER < 10700
+            if (that->this.bit_depth < 16)
+               that->max_gamma_8 = PNG_MAX_GAMMA_8;
 #        endif
+         that->pm->limit += pow(
+            (that->this.bit_depth == 16 || that->max_gamma_8 > 14 ?
+               8. :
+               6. + (1<<(15-that->max_gamma_8))
+            )/65535, data.gamma);
       }
 
       else
@@ -6795,18 +7374,16 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
           * When DIGITIZE is set because a pre-1.7 version of libpng is being
           * tested allow a bigger slack.
           *
-          * NOTE: this magic number was determined by experiment to be 1.1 (when
-          * using fixed point arithmetic).  There's no great merit to the value
-          * below, however it only affects the limit used for checking for
-          * internal calculation errors, not the actual limit imposed by
-          * pngvalid on the output errors.
+          * NOTE: this number only affects the internal limit check in pngvalid,
+          * it has no effect on the limits applied to the libpng values.
           */
-         that->pm->limit +=
+         that->pm->limit += pow(
 #        if DIGITIZE
-             pow(1.1 /255, data.gamma);
+            2.0
 #        else
-             pow(1.0 /255, data.gamma);
+            1.0
 #        endif
+            /255, data.gamma);
       }
    }
 
@@ -6821,10 +7398,10 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this,
+image_transform_png_set_rgb_to_gray_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
-   PNG_CONST int error_action = 1; /* no error, no defines in png.h */
+   const int error_action = 1; /* no error, no defines in png.h */
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
       png_set_rgb_to_gray(pp, error_action, data.red_to_set, data.green_to_set);
@@ -6861,7 +7438,7 @@ image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this,
                & PNG_INFO_cHRM) != 0)
          {
             double maxe;
-            PNG_CONST char *el;
+            const char *el;
             color_encoding e, o;
 
             /* Expect libpng to return a normalized result, but the original
@@ -6948,26 +7525,32 @@ image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
+image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    if ((that->colour_type & PNG_COLOR_MASK_COLOR) != 0)
    {
       double gray, err;
 
-      if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-         image_pixel_convert_PLTE(that);
+#     if PNG_LIBPNG_VER < 10700
+         if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
+            image_pixel_convert_PLTE(that);
+#     endif
 
       /* Image now has RGB channels... */
 #  if DIGITIZE
       {
-         PNG_CONST png_modifier *pm = display->pm;
+         png_modifier *pm = display->pm;
          const unsigned int sample_depth = that->sample_depth;
          const unsigned int calc_depth = (pm->assume_16_bit_calculations ? 16 :
             sample_depth);
-         const unsigned int gamma_depth = (sample_depth == 16 ? 16 :
-            (pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth));
+         const unsigned int gamma_depth =
+            (sample_depth == 16 ?
+               display->max_gamma_8 :
+               (pm->assume_16_bit_calculations ?
+                  display->max_gamma_8 :
+                  sample_depth));
          int isgray;
          double r, g, b;
          double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi;
@@ -6980,56 +7563,73 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
           * will be identical after this operation if there is only one
           * transform, feel free to delete the png_error checks on this below in
           * the future (this is just me trying to ensure it works!)
+          *
+          * Interval arithmetic is exact, but to implement it it must be
+          * possible to control the floating point implementation rounding mode.
+          * This cannot be done in ANSI-C, so instead I reduce the 'lo' values
+          * by DBL_EPSILON and increase the 'hi' values by the same.
           */
+#        define DD(v,d,r) (digitize(v*(1-DBL_EPSILON), d, r) * (1-DBL_EPSILON))
+#        define DU(v,d,r) (digitize(v*(1+DBL_EPSILON), d, r) * (1+DBL_EPSILON))
+
          r = rlo = rhi = that->redf;
          rlo -= that->rede;
-         rlo = digitize(rlo, calc_depth, 1/*round*/);
+         rlo = DD(rlo, calc_depth, 1/*round*/);
          rhi += that->rede;
-         rhi = digitize(rhi, calc_depth, 1/*round*/);
+         rhi = DU(rhi, calc_depth, 1/*round*/);
 
          g = glo = ghi = that->greenf;
          glo -= that->greene;
-         glo = digitize(glo, calc_depth, 1/*round*/);
+         glo = DD(glo, calc_depth, 1/*round*/);
          ghi += that->greene;
-         ghi = digitize(ghi, calc_depth, 1/*round*/);
+         ghi = DU(ghi, calc_depth, 1/*round*/);
 
          b = blo = bhi = that->bluef;
          blo -= that->bluee;
-         blo = digitize(blo, calc_depth, 1/*round*/);
-         bhi += that->greene;
-         bhi = digitize(bhi, calc_depth, 1/*round*/);
+         blo = DD(blo, calc_depth, 1/*round*/);
+         bhi += that->bluee;
+         bhi = DU(bhi, calc_depth, 1/*round*/);
 
          isgray = r==g && g==b;
 
          if (data.gamma != 1)
          {
-            PNG_CONST double power = 1/data.gamma;
-            PNG_CONST double abse = calc_depth == 16 ? .5/65535 : .5/255;
-
-            /* 'abse' is the absolute error permitted in linear calculations. It
-             * is used here to capture the error permitted in the handling
-             * (undoing) of the gamma encoding.  Once again digitization occurs
-             * to handle the upper and lower bounds of the values.  This is
-             * where the real errors are introduced.
+            const double power = 1/data.gamma;
+            const double abse = .5/(sample_depth == 16 ? 65535 : 255);
+
+            /* If a gamma calculation is done it is done using lookup tables of
+             * precision gamma_depth, so the already digitized value above may
+             * need to be further digitized here.
              */
+            if (gamma_depth != calc_depth)
+            {
+               rlo = DD(rlo, gamma_depth, 0/*truncate*/);
+               rhi = DU(rhi, gamma_depth, 0/*truncate*/);
+               glo = DD(glo, gamma_depth, 0/*truncate*/);
+               ghi = DU(ghi, gamma_depth, 0/*truncate*/);
+               blo = DD(blo, gamma_depth, 0/*truncate*/);
+               bhi = DU(bhi, gamma_depth, 0/*truncate*/);
+            }
+
+            /* 'abse' is the error in the gamma table calculation itself. */
             r = pow(r, power);
-            rlo = digitize(pow(rlo, power)-abse, calc_depth, 1);
-            rhi = digitize(pow(rhi, power)+abse, calc_depth, 1);
+            rlo = DD(pow(rlo, power)-abse, calc_depth, 1);
+            rhi = DU(pow(rhi, power)+abse, calc_depth, 1);
 
             g = pow(g, power);
-            glo = digitize(pow(glo, power)-abse, calc_depth, 1);
-            ghi = digitize(pow(ghi, power)+abse, calc_depth, 1);
+            glo = DD(pow(glo, power)-abse, calc_depth, 1);
+            ghi = DU(pow(ghi, power)+abse, calc_depth, 1);
 
             b = pow(b, power);
-            blo = digitize(pow(blo, power)-abse, calc_depth, 1);
-            bhi = digitize(pow(bhi, power)+abse, calc_depth, 1);
+            blo = DD(pow(blo, power)-abse, calc_depth, 1);
+            bhi = DU(pow(bhi, power)+abse, calc_depth, 1);
          }
 
          /* Now calculate the actual gray values.  Although the error in the
           * coefficients depends on whether they were specified on the command
           * line (in which case truncation to 15 bits happened) or not (rounding
           * was used) the maxium error in an individual coefficient is always
-          * 1/32768, because even in the rounding case the requirement that
+          * 2/32768, because even in the rounding case the requirement that
           * coefficients add up to 32768 can cause a larger rounding error.
           *
           * The only time when rounding doesn't occur in 1.5.5 and later is when
@@ -7039,32 +7639,46 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
             b * data.blue_coefficient;
 
          {
-            PNG_CONST int do_round = data.gamma != 1 || calc_depth == 16;
-            PNG_CONST double ce = 1. / 32768;
+            const int do_round = data.gamma != 1 || calc_depth == 16;
+            const double ce = 2. / 32768;
 
-            graylo = digitize(rlo * (data.red_coefficient-ce) +
+            graylo = DD(rlo * (data.red_coefficient-ce) +
                glo * (data.green_coefficient-ce) +
-               blo * (data.blue_coefficient-ce), gamma_depth, do_round);
-            if (graylo <= 0)
-               graylo = 0;
+               blo * (data.blue_coefficient-ce), calc_depth, do_round);
+            if (graylo > gray) /* always accept the right answer */
+               graylo = gray;
 
-            grayhi = digitize(rhi * (data.red_coefficient+ce) +
+            grayhi = DU(rhi * (data.red_coefficient+ce) +
                ghi * (data.green_coefficient+ce) +
-               bhi * (data.blue_coefficient+ce), gamma_depth, do_round);
-            if (grayhi >= 1)
-               grayhi = 1;
+               bhi * (data.blue_coefficient+ce), calc_depth, do_round);
+            if (grayhi < gray)
+               grayhi = gray;
          }
 
          /* And invert the gamma. */
          if (data.gamma != 1)
          {
-            PNG_CONST double power = data.gamma;
+            const double power = data.gamma;
+
+            /* And this happens yet again, shifting the values once more. */
+            if (gamma_depth != sample_depth)
+            {
+               rlo = DD(rlo, gamma_depth, 0/*truncate*/);
+               rhi = DU(rhi, gamma_depth, 0/*truncate*/);
+               glo = DD(glo, gamma_depth, 0/*truncate*/);
+               ghi = DU(ghi, gamma_depth, 0/*truncate*/);
+               blo = DD(blo, gamma_depth, 0/*truncate*/);
+               bhi = DU(bhi, gamma_depth, 0/*truncate*/);
+            }
 
             gray = pow(gray, power);
-            graylo = digitize(pow(graylo, power), sample_depth, 1);
-            grayhi = digitize(pow(grayhi, power), sample_depth, 1);
+            graylo = DD(pow(graylo, power), sample_depth, 1);
+            grayhi = DU(pow(grayhi, power), sample_depth, 1);
          }
 
+#        undef DD
+#        undef DU
+
          /* Now the error can be calculated.
           *
           * If r==g==b because there is no overall gamma correction libpng
@@ -7076,9 +7690,11 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
          else
          {
             err = fabs(grayhi-gray);
+
             if (fabs(gray - graylo) > err)
                err = fabs(graylo-gray);
 
+#if !RELEASE_BUILD
             /* Check that this worked: */
             if (err > pm->limit)
             {
@@ -7089,11 +7705,13 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
                pos = safecatd(buffer, sizeof buffer, pos, err, 6);
                pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
                pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6);
-               png_error(pp, buffer);
+               png_warning(pp, buffer);
+               pm->limit = err;
             }
+#endif /* !RELEASE_BUILD */
          }
       }
-#  else  /* DIGITIZE */
+#  else  /* !DIGITIZE */
       {
          double r = that->redf;
          double re = that->rede;
@@ -7102,29 +7720,46 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
          double b = that->bluef;
          double be = that->bluee;
 
-         /* The true gray case involves no math. */
-         if (r == g && r == b)
-         {
-            gray = r;
-            err = re;
-            if (err < ge) err = ge;
-            if (err < be) err = be;
-         }
+#        if PNG_LIBPNG_VER < 10700
+            /* The true gray case involves no math in earlier versions (not
+             * true, there was some if gamma correction was happening too.)
+             */
+            if (r == g && r == b)
+            {
+               gray = r;
+               err = re;
+               if (err < ge) err = ge;
+               if (err < be) err = be;
+            }
 
-         else if (data.gamma == 1)
+            else
+#        endif /* before 1.7 */
+         if (data.gamma == 1)
          {
             /* There is no need to do the conversions to and from linear space,
              * so the calculation should be a lot more accurate.  There is a
-             * built in 1/32768 error in the coefficients because they only have
-             * 15 bits and are adjusted to make sure they add up to 32768, so
-             * the result may have an additional error up to 1/32768.  (Note
-             * that adding the 1/32768 here avoids needing to increase the
-             * global error limits to take this into account.)
+             * built in error in the coefficients because they only have 15 bits
+             * and are adjusted to make sure they add up to 32768.  This
+             * involves a integer calculation with truncation of the form:
+             *
+             *     ((int)(coefficient * 100000) * 32768)/100000
+             *
+             * This is done to the red and green coefficients (the ones
+             * provided to the API) then blue is calculated from them so the
+             * result adds up to 32768.  In the worst case this can result in
+             * a -1 error in red and green and a +2 error in blue.  Consequently
+             * the worst case in the calculation below is 2/32768 error.
+             *
+             * TODO: consider fixing this in libpng by rounding the calculation
+             * limiting the error to 1/32768.
+             *
+             * Handling this by adding 2/32768 here avoids needing to increase
+             * the global error limits to take this into account.)
              */
             gray = r * data.red_coefficient + g * data.green_coefficient +
                b * data.blue_coefficient;
             err = re * data.red_coefficient + ge * data.green_coefficient +
-               be * data.blue_coefficient + 1./32768 + gray * 5 * DBL_EPSILON;
+               be * data.blue_coefficient + 2./32768 + gray * 5 * DBL_EPSILON;
          }
 
          else
@@ -7135,10 +7770,10 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
              * lookups in the calculation and each introduces a quantization
              * error defined by the table size.
              */
-            PNG_CONST png_modifier *pm = display->pm;
+            png_modifier *pm = display->pm;
             double in_qe = (that->sample_depth > 8 ? .5/65535 : .5/255);
             double out_qe = (that->sample_depth > 8 ? .5/65535 :
-               (pm->assume_16_bit_calculations ? .5/(1<<PNG_MAX_GAMMA_8) :
+               (pm->assume_16_bit_calculations ? .5/(1<<display->max_gamma_8) :
                .5/255));
             double rhi, ghi, bhi, grayhi;
             double g1 = 1/data.gamma;
@@ -7159,7 +7794,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
              * previously added input quantization error at this point.
              */
             gray = r * data.red_coefficient + g * data.green_coefficient +
-               b * data.blue_coefficient - 1./32768 - out_qe;
+               b * data.blue_coefficient - 2./32768 - out_qe;
             if (gray <= 0)
                gray = 0;
             else
@@ -7169,7 +7804,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
             }
 
             grayhi = rhi * data.red_coefficient + ghi * data.green_coefficient +
-               bhi * data.blue_coefficient + 1./32768 + out_qe;
+               bhi * data.blue_coefficient + 2./32768 + out_qe;
             grayhi *= (1 + 6 * DBL_EPSILON);
             if (grayhi >= 1)
                grayhi = 1;
@@ -7185,6 +7820,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
             else
                err -= in_qe;
 
+#if !RELEASE_BUILD
             /* Validate that the error is within limits (this has caused
              * problems before, it's much easier to detect them here.)
              */
@@ -7197,8 +7833,10 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
                pos = safecatd(buffer, sizeof buffer, pos, err, 6);
                pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
                pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6);
-               png_error(pp, buffer);
+               png_warning(pp, buffer);
+               pm->limit = err;
             }
+#endif /* !RELEASE_BUILD */
          }
       }
 #  endif /* !DIGITIZE */
@@ -7225,7 +7863,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
 
 static int
 image_transform_png_set_rgb_to_gray_add(image_transform *this,
-    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
 {
    UNUSED(bit_depth)
 
@@ -7256,7 +7894,7 @@ IT(rgb_to_gray);
 static image_pixel data;
 
 static void
-image_transform_png_set_background_set(PNG_CONST image_transform *this,
+image_transform_png_set_background_set(const image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
    png_byte colour_type, bit_depth;
@@ -7269,7 +7907,7 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
     * so we need to know what that is!  The background colour is stored in the
     * transform_display.
     */
-   RANDOMIZE(random_bytes);
+   R8(random_bytes);
 
    /* Read the random value, for colour type 3 the background colour is actually
     * expressed as a 24bit rgb, not an index.
@@ -7284,17 +7922,20 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
 
    else
    {
+      if (that->this.has_tRNS)
+         that->this.is_transparent = 1;
+
       bit_depth = that->this.bit_depth;
       expand = 1;
    }
 
    image_pixel_init(&data, random_bytes, colour_type,
-      bit_depth, 0/*x*/, 0/*unused: palette*/);
+      bit_depth, 0/*x*/, 0/*unused: palette*/, NULL/*format*/);
 
    /* Extract the background colour from this image_pixel, but make sure the
     * unused fields of 'back' are garbage.
     */
-   RANDOMIZE(back);
+   R8(back);
 
    if (colour_type & PNG_COLOR_MASK_COLOR)
    {
@@ -7316,13 +7957,13 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
 }
 
 static void
-image_transform_png_set_background_mod(PNG_CONST image_transform *this,
+image_transform_png_set_background_mod(const image_transform *this,
     image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
+    const transform_display *display)
 {
    /* Check for tRNS first: */
    if (that->have_tRNS && that->colour_type != PNG_COLOR_TYPE_PALETTE)
-      image_pixel_add_alpha(that, &display->this);
+      image_pixel_add_alpha(that, &display->this, 1/*for background*/);
 
    /* This is only necessary if the alpha value is less than 1. */
    if (that->alphaf < 1)
@@ -7361,14 +8002,14 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
       /* Remove the alpha type and set the alpha (not in that order.) */
       that->alphaf = 1;
       that->alphae = 0;
-
-      if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA)
-         that->colour_type = PNG_COLOR_TYPE_RGB;
-      else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-         that->colour_type = PNG_COLOR_TYPE_GRAY;
-      /* PNG_COLOR_TYPE_PALETTE is not changed */
    }
 
+   if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA)
+      that->colour_type = PNG_COLOR_TYPE_RGB;
+   else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+      that->colour_type = PNG_COLOR_TYPE_GRAY;
+   /* PNG_COLOR_TYPE_PALETTE is not changed */
+
    this->next->mod(this->next, that, pp, display);
 }
 
@@ -7380,68 +8021,661 @@ IT(background);
 #define PT ITSTRUCT(background)
 #endif /* PNG_READ_BACKGROUND_SUPPORTED */
 
-/* This may just be 'end' if all the transforms are disabled! */
-static image_transform *PNG_CONST image_transform_first = &PT;
+/* png_set_quantize(png_structp, png_colorp palette, int num_palette,
+ *    int maximum_colors, png_const_uint_16p histogram, int full_quantize)
+ *
+ * Very difficult to validate this!
+ */
+/*NOTE: TBD NYI */
 
+/* The data layout transforms are handled by swapping our own channel data,
+ * necessarily these need to happen at the end of the transform list because the
+ * semantic of the channels changes after these are executed.  Some of these,
+ * like set_shift and set_packing, can't be done at present because they change
+ * the layout of the data at the sub-sample level so sample() won't get the
+ * right answer.
+ */
+/* png_set_invert_alpha */
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+/* Invert the alpha channel
+ *
+ *  png_set_invert_alpha(png_structrp png_ptr)
+ */
 static void
-transform_enable(PNG_CONST char *name)
+image_transform_png_set_invert_alpha_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
 {
-   /* Everything starts out enabled, so if we see an 'enable' disabled
-    * everything else the first time round.
-    */
-   static int all_disabled = 0;
-   int found_it = 0;
-   image_transform *list = image_transform_first;
-
-   while (list != &image_transform_end)
-   {
-      if (strcmp(list->name, name) == 0)
-      {
-         list->enable = 1;
-         found_it = 1;
-      }
-      else if (!all_disabled)
-         list->enable = 0;
-
-      list = list->list;
-   }
-
-   all_disabled = 1;
-
-   if (!found_it)
-   {
-      fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n",
-         name);
-      exit(99);
-   }
+   png_set_invert_alpha(pp);
+   this->next->set(this->next, that, pp, pi);
 }
 
 static void
-transform_disable(PNG_CONST char *name)
+image_transform_png_set_invert_alpha_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
 {
-   image_transform *list = image_transform_first;
+   if (that->colour_type & 4)
+      that->alpha_inverted = 1;
 
-   while (list != &image_transform_end)
-   {
-      if (strcmp(list->name, name) == 0)
-      {
-         list->enable = 0;
-         return;
-      }
+   this->next->mod(this->next, that, pp, display);
+}
 
-      list = list->list;
-   }
+static int
+image_transform_png_set_invert_alpha_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(bit_depth)
 
-   fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n",
-      name);
-   exit(99);
+   this->next = *that;
+   *that = this;
+
+   /* Only has an effect on pixels with alpha: */
+   return (colour_type & 4) != 0;
 }
 
+IT(invert_alpha);
+#undef PT
+#define PT ITSTRUCT(invert_alpha)
+
+#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */
+
+/* png_set_bgr */
+#ifdef PNG_READ_BGR_SUPPORTED
+/* Swap R,G,B channels to order B,G,R.
+ *
+ *  png_set_bgr(png_structrp png_ptr)
+ *
+ * This only has an effect on RGB and RGBA pixels.
+ */
 static void
-image_transform_reset_count(void)
+image_transform_png_set_bgr_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
 {
-   image_transform *next = image_transform_first;
-   int count = 0;
+   png_set_bgr(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_bgr_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->colour_type == PNG_COLOR_TYPE_RGB ||
+       that->colour_type == PNG_COLOR_TYPE_RGBA)
+       that->swap_rgb = 1;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_bgr_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(bit_depth)
+
+   this->next = *that;
+   *that = this;
+
+   return colour_type == PNG_COLOR_TYPE_RGB ||
+       colour_type == PNG_COLOR_TYPE_RGBA;
+}
+
+IT(bgr);
+#undef PT
+#define PT ITSTRUCT(bgr)
+
+#endif /* PNG_READ_BGR_SUPPORTED */
+
+/* png_set_swap_alpha */
+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
+/* Put the alpha channel first.
+ *
+ *  png_set_swap_alpha(png_structrp png_ptr)
+ *
+ * This only has an effect on GA and RGBA pixels.
+ */
+static void
+image_transform_png_set_swap_alpha_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_swap_alpha(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_swap_alpha_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->colour_type == PNG_COLOR_TYPE_GA ||
+       that->colour_type == PNG_COLOR_TYPE_RGBA)
+      that->alpha_first = 1;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_swap_alpha_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(bit_depth)
+
+   this->next = *that;
+   *that = this;
+
+   return colour_type == PNG_COLOR_TYPE_GA ||
+       colour_type == PNG_COLOR_TYPE_RGBA;
+}
+
+IT(swap_alpha);
+#undef PT
+#define PT ITSTRUCT(swap_alpha)
+
+#endif /* PNG_READ_SWAP_ALPHA_SUPPORTED */
+
+/* png_set_swap */
+#ifdef PNG_READ_SWAP_SUPPORTED
+/* Byte swap 16-bit components.
+ *
+ *  png_set_swap(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_swap_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_swap(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_swap_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->bit_depth == 16)
+      that->swap16 = 1;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_swap_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(colour_type)
+
+   this->next = *that;
+   *that = this;
+
+   return bit_depth == 16;
+}
+
+IT(swap);
+#undef PT
+#define PT ITSTRUCT(swap)
+
+#endif /* PNG_READ_SWAP_SUPPORTED */
+
+#ifdef PNG_READ_FILLER_SUPPORTED
+/* Add a filler byte to 8-bit Gray or 24-bit RGB images.
+ *
+ *  png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags));
+ *
+ * Flags:
+ *
+ *  PNG_FILLER_BEFORE
+ *  PNG_FILLER_AFTER
+ */
+#define data ITDATA(filler)
+static struct
+{
+   png_uint_32 filler;
+   int         flags;
+} data;
+
+static void
+image_transform_png_set_filler_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   /* Need a random choice for 'before' and 'after' as well as for the
+    * filler.  The 'filler' value has all 32 bits set, but only bit_depth
+    * will be used.  At this point we don't know bit_depth.
+    */
+   R32(data.filler);
+   data.flags = random_choice();
+
+   png_set_filler(pp, data.filler, data.flags);
+
+   /* The standard display handling stuff also needs to know that
+    * there is a filler, so set that here.
+    */
+   that->this.filler = 1;
+
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_filler_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->bit_depth >= 8 &&
+       (that->colour_type == PNG_COLOR_TYPE_RGB ||
+        that->colour_type == PNG_COLOR_TYPE_GRAY))
+   {
+      const unsigned int max = (1U << that->bit_depth)-1;
+      that->alpha = data.filler & max;
+      that->alphaf = ((double)that->alpha) / max;
+      that->alphae = 0;
+
+      /* The filler has been stored in the alpha channel, we must record
+       * that this has been done for the checking later on, the color
+       * type is faked to have an alpha channel, but libpng won't report
+       * this; the app has to know the extra channel is there and this
+       * was recording in standard_display::filler above.
+       */
+      that->colour_type |= 4; /* alpha added */
+      that->alpha_first = data.flags == PNG_FILLER_BEFORE;
+   }
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_filler_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   this->next = *that;
+   *that = this;
+
+   return bit_depth >= 8 && (colour_type == PNG_COLOR_TYPE_RGB ||
+           colour_type == PNG_COLOR_TYPE_GRAY);
+}
+
+#undef data
+IT(filler);
+#undef PT
+#define PT ITSTRUCT(filler)
+
+/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */
+/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */
+#define data ITDATA(add_alpha)
+static struct
+{
+   png_uint_32 filler;
+   int         flags;
+} data;
+
+static void
+image_transform_png_set_add_alpha_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   /* Need a random choice for 'before' and 'after' as well as for the
+    * filler.  The 'filler' value has all 32 bits set, but only bit_depth
+    * will be used.  At this point we don't know bit_depth.
+    */
+   R32(data.filler);
+   data.flags = random_choice();
+
+   png_set_add_alpha(pp, data.filler, data.flags);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_add_alpha_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->bit_depth >= 8 &&
+       (that->colour_type == PNG_COLOR_TYPE_RGB ||
+        that->colour_type == PNG_COLOR_TYPE_GRAY))
+   {
+      const unsigned int max = (1U << that->bit_depth)-1;
+      that->alpha = data.filler & max;
+      that->alphaf = ((double)that->alpha) / max;
+      that->alphae = 0;
+
+      that->colour_type |= 4; /* alpha added */
+      that->alpha_first = data.flags == PNG_FILLER_BEFORE;
+   }
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_add_alpha_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   this->next = *that;
+   *that = this;
+
+   return bit_depth >= 8 && (colour_type == PNG_COLOR_TYPE_RGB ||
+           colour_type == PNG_COLOR_TYPE_GRAY);
+}
+
+#undef data
+IT(add_alpha);
+#undef PT
+#define PT ITSTRUCT(add_alpha)
+
+#endif /* PNG_READ_FILLER_SUPPORTED */
+
+/* png_set_packing */
+#ifdef PNG_READ_PACK_SUPPORTED
+/* Use 1 byte per pixel in 1, 2, or 4-bit depth files.
+ *
+ *  png_set_packing(png_structrp png_ptr)
+ *
+ * This should only affect grayscale and palette images with less than 8 bits
+ * per pixel.
+ */
+static void
+image_transform_png_set_packing_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_packing(pp);
+   that->unpacked = 1;
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_packing_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   /* The general expand case depends on what the colour type is,
+    * low bit-depth pixel values are unpacked into bytes without
+    * scaling, so sample_depth is not changed.
+    */
+   if (that->bit_depth < 8) /* grayscale or palette */
+      that->bit_depth = 8;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_packing_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(colour_type)
+
+   this->next = *that;
+   *that = this;
+
+   /* Nothing should happen unless the bit depth is less than 8: */
+   return bit_depth < 8;
+}
+
+IT(packing);
+#undef PT
+#define PT ITSTRUCT(packing)
+
+#endif /* PNG_READ_PACK_SUPPORTED */
+
+/* png_set_packswap */
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+/* Swap pixels packed into bytes; reverses the order on screen so that
+ * the high order bits correspond to the rightmost pixels.
+ *
+ *  png_set_packswap(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_packswap_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_packswap(pp);
+   that->this.littleendian = 1;
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_packswap_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->bit_depth < 8)
+      that->littleendian = 1;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_packswap_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(colour_type)
+
+   this->next = *that;
+   *that = this;
+
+   return bit_depth < 8;
+}
+
+IT(packswap);
+#undef PT
+#define PT ITSTRUCT(packswap)
+
+#endif /* PNG_READ_PACKSWAP_SUPPORTED */
+
+
+/* png_set_invert_mono */
+#ifdef PNG_READ_INVERT_MONO_SUPPORTED
+/* Invert the gray channel
+ *
+ *  png_set_invert_mono(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_invert_mono_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_invert_mono(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_invert_mono_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   if (that->colour_type & 4)
+      that->mono_inverted = 1;
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_invert_mono_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(bit_depth)
+
+   this->next = *that;
+   *that = this;
+
+   /* Only has an effect on pixels with no colour: */
+   return (colour_type & 2) == 0;
+}
+
+IT(invert_mono);
+#undef PT
+#define PT ITSTRUCT(invert_mono)
+
+#endif /* PNG_READ_INVERT_MONO_SUPPORTED */
+
+#ifdef PNG_READ_SHIFT_SUPPORTED
+/* png_set_shift(png_structp, png_const_color_8p true_bits)
+ *
+ * The output pixels will be shifted by the given true_bits
+ * values.
+ */
+#define data ITDATA(shift)
+static png_color_8 data;
+
+static void
+image_transform_png_set_shift_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   /* Get a random set of shifts.  The shifts need to do something
+    * to test the transform, so they are limited to the bit depth
+    * of the input image.  Notice that in the following the 'gray'
+    * field is randomized independently.  This acts as a check that
+    * libpng does use the correct field.
+    */
+   const unsigned int depth = that->this.bit_depth;
+
+   data.red = (png_byte)/*SAFE*/(random_mod(depth)+1);
+   data.green = (png_byte)/*SAFE*/(random_mod(depth)+1);
+   data.blue = (png_byte)/*SAFE*/(random_mod(depth)+1);
+   data.gray = (png_byte)/*SAFE*/(random_mod(depth)+1);
+   data.alpha = (png_byte)/*SAFE*/(random_mod(depth)+1);
+
+   png_set_shift(pp, &data);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_shift_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   /* Copy the correct values into the sBIT fields, libpng does not do
+    * anything to palette data:
+    */
+   if (that->colour_type != PNG_COLOR_TYPE_PALETTE)
+   {
+       that->sig_bits = 1;
+
+       /* The sBIT fields are reset to the values previously sent to
+        * png_set_shift according to the colour type.
+        * does.
+        */
+       if (that->colour_type & 2) /* RGB channels */
+       {
+          that->red_sBIT = data.red;
+          that->green_sBIT = data.green;
+          that->blue_sBIT = data.blue;
+       }
+
+       else /* One grey channel */
+          that->red_sBIT = that->green_sBIT = that->blue_sBIT = data.gray;
+
+       that->alpha_sBIT = data.alpha;
+   }
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_shift_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(bit_depth)
+
+   this->next = *that;
+   *that = this;
+
+   return colour_type != PNG_COLOR_TYPE_PALETTE;
+}
+
+IT(shift);
+#undef PT
+#define PT ITSTRUCT(shift)
+
+#endif /* PNG_READ_SHIFT_SUPPORTED */
+
+#ifdef THIS_IS_THE_PROFORMA
+static void
+image_transform_png_set_@_set(const image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_@(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_@_mod(const image_transform *this,
+    image_pixel *that, png_const_structp pp,
+    const transform_display *display)
+{
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_@_add(image_transform *this,
+    const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   this->next = *that;
+   *that = this;
+
+   return 1;
+}
+
+IT(@);
+#endif
+
+
+/* This may just be 'end' if all the transforms are disabled! */
+static image_transform *const image_transform_first = &PT;
+
+static void
+transform_enable(const char *name)
+{
+   /* Everything starts out enabled, so if we see an 'enable' disabled
+    * everything else the first time round.
+    */
+   static int all_disabled = 0;
+   int found_it = 0;
+   image_transform *list = image_transform_first;
+
+   while (list != &image_transform_end)
+   {
+      if (strcmp(list->name, name) == 0)
+      {
+         list->enable = 1;
+         found_it = 1;
+      }
+      else if (!all_disabled)
+         list->enable = 0;
+
+      list = list->list;
+   }
+
+   all_disabled = 1;
+
+   if (!found_it)
+   {
+      fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n",
+         name);
+      exit(99);
+   }
+}
+
+static void
+transform_disable(const char *name)
+{
+   image_transform *list = image_transform_first;
+
+   while (list != &image_transform_end)
+   {
+      if (strcmp(list->name, name) == 0)
+      {
+         list->enable = 0;
+         return;
+      }
+
+      list = list->list;
+   }
+
+   fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n",
+      name);
+   exit(99);
+}
+
+static void
+image_transform_reset_count(void)
+{
+   image_transform *next = image_transform_first;
+   int count = 0;
 
    while (next != &image_transform_end)
    {
@@ -7480,7 +8714,7 @@ image_transform_test_counter(png_uint_32 counter, unsigned int max)
 }
 
 static png_uint_32
-image_transform_add(PNG_CONST image_transform **this, unsigned int max,
+image_transform_add(const image_transform **this, unsigned int max,
    png_uint_32 counter, char *name, size_t sizeof_name, size_t *pos,
    png_byte colour_type, png_byte bit_depth)
 {
@@ -7557,83 +8791,6 @@ image_transform_add(PNG_CONST image_transform **this, unsigned int max,
    }
 }
 
-#ifdef THIS_IS_THE_PROFORMA
-static void
-image_transform_png_set_@_set(PNG_CONST image_transform *this,
-    transform_display *that, png_structp pp, png_infop pi)
-{
-   png_set_@(pp);
-   this->next->set(this->next, that, pp, pi);
-}
-
-static void
-image_transform_png_set_@_mod(PNG_CONST image_transform *this,
-    image_pixel *that, png_const_structp pp,
-    PNG_CONST transform_display *display)
-{
-   this->next->mod(this->next, that, pp, display);
-}
-
-static int
-image_transform_png_set_@_add(image_transform *this,
-    PNG_CONST image_transform **that, char *name, size_t sizeof_name,
-    size_t *pos, png_byte colour_type, png_byte bit_depth)
-{
-   this->next = *that;
-   *that = this;
-
-   *pos = safecat(name, sizeof_name, *pos, " +@");
-
-   return 1;
-}
-
-IT(@);
-#endif
-
-/* png_set_quantize(png_structp, png_colorp palette, int num_palette,
- *    int maximum_colors, png_const_uint_16p histogram, int full_quantize)
- *
- * Very difficult to validate this!
- */
-/*NOTE: TBD NYI */
-
-/* The data layout transforms are handled by swapping our own channel data,
- * necessarily these need to happen at the end of the transform list because the
- * semantic of the channels changes after these are executed.  Some of these,
- * like set_shift and set_packing, can't be done at present because they change
- * the layout of the data at the sub-sample level so sample() won't get the
- * right answer.
- */
-/* png_set_invert_alpha */
-/*NOTE: TBD NYI */
-
-/* png_set_bgr */
-/*NOTE: TBD NYI */
-
-/* png_set_swap_alpha */
-/*NOTE: TBD NYI */
-
-/* png_set_swap */
-/*NOTE: TBD NYI */
-
-/* png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags)); */
-/*NOTE: TBD NYI */
-
-/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */
-/*NOTE: TBD NYI */
-
-/* png_set_packing */
-/*NOTE: TBD NYI */
-
-/* png_set_packswap */
-/*NOTE: TBD NYI */
-
-/* png_set_invert_mono */
-/*NOTE: TBD NYI */
-
-/* png_set_shift(png_structp, png_const_color_8p true_bits) */
-/*NOTE: TBD NYI */
-
 static void
 perform_transform_test(png_modifier *pm)
 {
@@ -7641,7 +8798,8 @@ perform_transform_test(png_modifier *pm)
    png_byte bit_depth = 0;
    unsigned int palette_number = 0;
 
-   while (next_format(&colour_type, &bit_depth, &palette_number, 0))
+   while (next_format(&colour_type, &bit_depth, &palette_number, pm->test_lbg,
+            pm->test_tRNS))
    {
       png_uint_32 counter = 0;
       size_t base_pos;
@@ -7652,7 +8810,7 @@ perform_transform_test(png_modifier *pm)
       for (;;)
       {
          size_t pos = base_pos;
-         PNG_CONST image_transform *list = 0;
+         const image_transform *list = 0;
 
          /* 'max' is currently hardwired to '1'; this should be settable on the
           * command line.
@@ -7713,11 +8871,11 @@ static void
 gamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id,
     double file_gamma, double screen_gamma, png_byte sbit, int threshold_test,
     int use_input_precision, int scale16, int expand16,
-    int do_background, PNG_CONST png_color_16 *pointer_to_the_background_color,
+    int do_background, const png_color_16 *pointer_to_the_background_color,
     double background_gamma)
 {
    /* Standard fields */
-   standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/,
+   standard_display_init(&dp->this, &pm->this, id, do_read_interlace,
       pm->use_update_info);
 
    /* Parameter fields */
@@ -7749,7 +8907,7 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
    /* If requested strip 16 to 8 bits - this is handled automagically below
     * because the output bit depth is read from the library.  Note that there
     * are interactions with sBIT but, internally, libpng makes sbit at most
-    * PNG_MAX_GAMMA_8 when doing the following.
+    * PNG_MAX_GAMMA_8 prior to 1.7 when doing the following.
     */
    if (dp->scale16)
 #     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
@@ -7781,9 +8939,9 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
           * non-inverted, represenation.  It provides a default for the PNG file
           * gamma, but since the file has a gAMA chunk this does not matter.
           */
-         PNG_CONST double sg = dp->screen_gamma;
+         const double sg = dp->screen_gamma;
 #        ifndef PNG_FLOATING_POINT_SUPPORTED
-            PNG_CONST png_fixed_point g = fix(sg);
+            const png_fixed_point g = fix(sg);
 #        endif
 
 #        ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -7829,9 +8987,9 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
 #     ifdef PNG_READ_BACKGROUND_SUPPORTED
          /* NOTE: this assumes the caller provided the correct background gamma!
           */
-         PNG_CONST double bg = dp->background_gamma;
+         const double bg = dp->background_gamma;
 #        ifndef PNG_FLOATING_POINT_SUPPORTED
-            PNG_CONST png_fixed_point g = fix(bg);
+            const png_fixed_point g = fix(bg);
 #        endif
 
 #        ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -7905,7 +9063,7 @@ static void
 init_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp,
     int in_depth, int out_depth)
 {
-   PNG_CONST unsigned int outmax = (1U<<out_depth)-1;
+   const unsigned int outmax = (1U<<out_depth)-1;
 
    vi->pp = pp;
    vi->dp = dp;
@@ -7944,13 +9102,15 @@ init_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp,
    vi->outlog = outlog(dp->pm, in_depth, out_depth);
 
    if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 ||
-      (dp->this.colour_type == 3 && dp->this.is_transparent))
+      (dp->this.colour_type == 3 && dp->this.is_transparent) ||
+      ((dp->this.colour_type == 0 || dp->this.colour_type == 2) &&
+       dp->this.has_tRNS))
    {
       vi->do_background = dp->do_background;
 
       if (vi->do_background != 0)
       {
-         PNG_CONST double bg_inverse = 1/dp->background_gamma;
+         const double bg_inverse = 1/dp->background_gamma;
          double r, g, b;
 
          /* Caller must at least put the gray value into the red channel */
@@ -7974,7 +9134,7 @@ init_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp,
          vi->background_blue = b;
       }
    }
-   else
+   else /* Do not expect any background processing */
       vi->do_background = 0;
 
    if (vi->do_background == 0)
@@ -8064,15 +9224,15 @@ gamma_component_compose(int do_background, double input_sample, double alpha,
 
 /* This API returns the encoded *input* component, in the range 0..1 */
 static double
-gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
-    PNG_CONST unsigned int id, PNG_CONST unsigned int od,
-    PNG_CONST double alpha /* <0 for the alpha channel itself */,
-    PNG_CONST double background /* component background value */)
+gamma_component_validate(const char *name, const validate_info *vi,
+    const unsigned int id, const unsigned int od,
+    const double alpha /* <0 for the alpha channel itself */,
+    const double background /* component background value */)
 {
-   PNG_CONST unsigned int isbit = id >> vi->isbit_shift;
-   PNG_CONST unsigned int sbit_max = vi->sbit_max;
-   PNG_CONST unsigned int outmax = vi->outmax;
-   PNG_CONST int do_background = vi->do_background;
+   const unsigned int isbit = id >> vi->isbit_shift;
+   const unsigned int sbit_max = vi->sbit_max;
+   const unsigned int outmax = vi->outmax;
+   const int do_background = vi->do_background;
 
    double i;
 
@@ -8637,14 +9797,14 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
    png_infop pi)
 {
    /* Get some constants derived from the input and output file formats: */
-   PNG_CONST png_store* PNG_CONST ps = dp->this.ps;
-   PNG_CONST png_byte in_ct = dp->this.colour_type;
-   PNG_CONST png_byte in_bd = dp->this.bit_depth;
-   PNG_CONST png_uint_32 w = dp->this.w;
-   PNG_CONST png_uint_32 h = dp->this.h;
-   PNG_CONST size_t cbRow = dp->this.cbRow;
-   PNG_CONST png_byte out_ct = png_get_color_type(pp, pi);
-   PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi);
+   const png_store* const ps = dp->this.ps;
+   const png_byte in_ct = dp->this.colour_type;
+   const png_byte in_bd = dp->this.bit_depth;
+   const png_uint_32 w = dp->this.w;
+   const png_uint_32 h = dp->this.h;
+   const size_t cbRow = dp->this.cbRow;
+   const png_byte out_ct = png_get_color_type(pp, pi);
+   const png_byte out_bd = png_get_bit_depth(pp, pi);
 
    /* There are three sources of error, firstly the quantization in the
     * file encoding, determined by sbit and/or the file depth, secondly
@@ -8685,11 +9845,12 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
     * The basic tests below do not do this, however if 'use_input_precision'
     * is set a subsequent test is performed above.
     */
-   PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U;
+   const unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U;
    int processing;
    png_uint_32 y;
-   PNG_CONST store_palette_entry *in_palette = dp->this.palette;
-   PNG_CONST int in_is_transparent = dp->this.is_transparent;
+   const store_palette_entry *in_palette = dp->this.palette;
+   const int in_is_transparent = dp->this.is_transparent;
+   int process_tRNS;
    int out_npalette = -1;
    int out_is_transparent = 0; /* Just refers to the palette case */
    store_palette out_palette;
@@ -8705,6 +9866,7 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
 
    processing = (vi.gamma_correction > 0 && !dp->threshold_test)
       || in_bd != out_bd || in_ct != out_ct || vi.do_background;
+   process_tRNS = dp->this.has_tRNS && vi.do_background;
 
    /* TODO: FIX THIS: MAJOR BUG!  If the transformations all happen inside
     * the palette there is no way of finding out, because libpng fails to
@@ -8735,20 +9897,20 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
             double alpha = 1; /* serves as a flag value */
 
             /* Record the palette index for index images. */
-            PNG_CONST unsigned int in_index =
-               in_ct == 3 ? sample(std, 3, in_bd, x, 0) : 256;
-            PNG_CONST unsigned int out_index =
-               out_ct == 3 ? sample(std, 3, out_bd, x, 0) : 256;
+            const unsigned int in_index =
+               in_ct == 3 ? sample(std, 3, in_bd, x, 0, 0, 0) : 256;
+            const unsigned int out_index =
+               out_ct == 3 ? sample(std, 3, out_bd, x, 0, 0, 0) : 256;
 
             /* Handle input alpha - png_set_background will cause the output
              * alpha to disappear so there is nothing to check.
              */
-            if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || (in_ct == 3 &&
-               in_is_transparent))
+            if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 ||
+                (in_ct == 3 && in_is_transparent))
             {
-               PNG_CONST unsigned int input_alpha = in_ct == 3 ?
+               const unsigned int input_alpha = in_ct == 3 ?
                   dp->this.palette[in_index].alpha :
-                  sample(std, in_ct, in_bd, x, samples_per_pixel);
+                  sample(std, in_ct, in_bd, x, samples_per_pixel, 0, 0);
 
                unsigned int output_alpha = 65536 /* as a flag value */;
 
@@ -8760,7 +9922,7 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
 
                else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0)
                   output_alpha = sample(pRow, out_ct, out_bd, x,
-                     samples_per_pixel);
+                     samples_per_pixel, 0, 0);
 
                if (output_alpha != 65536)
                   alpha = gamma_component_validate("alpha", &vi, input_alpha,
@@ -8776,33 +9938,62 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
                }
             }
 
+            else if (process_tRNS)
+            {
+               /* alpha needs to be set appropriately for this pixel, it is
+                * currently 1 and needs to be 0 for an input pixel which matches
+                * the values in tRNS.
+                */
+               switch (in_ct)
+               {
+                  case 0: /* gray */
+                     if (sample(std, in_ct, in_bd, x, 0, 0, 0) ==
+                           dp->this.transparent.red)
+                        alpha = 0;
+                     break;
+
+                  case 2: /* RGB */
+                     if (sample(std, in_ct, in_bd, x, 0, 0, 0) ==
+                           dp->this.transparent.red &&
+                         sample(std, in_ct, in_bd, x, 1, 0, 0) ==
+                           dp->this.transparent.green &&
+                         sample(std, in_ct, in_bd, x, 2, 0, 0) ==
+                           dp->this.transparent.blue)
+                        alpha = 0;
+                     break;
+
+                  default:
+                     break;
+               }
+            }
+
             /* Handle grayscale or RGB components. */
             if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* grayscale */
                (void)gamma_component_validate("gray", &vi,
-                  sample(std, in_ct, in_bd, x, 0),
-                  sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/,
-                  vi.background_red);
+                  sample(std, in_ct, in_bd, x, 0, 0, 0),
+                  sample(pRow, out_ct, out_bd, x, 0, 0, 0),
+                  alpha/*component*/, vi.background_red);
             else /* RGB or palette */
             {
                (void)gamma_component_validate("red", &vi,
                   in_ct == 3 ? in_palette[in_index].red :
-                     sample(std, in_ct, in_bd, x, 0),
+                     sample(std, in_ct, in_bd, x, 0, 0, 0),
                   out_ct == 3 ? out_palette[out_index].red :
-                     sample(pRow, out_ct, out_bd, x, 0),
+                     sample(pRow, out_ct, out_bd, x, 0, 0, 0),
                   alpha/*component*/, vi.background_red);
 
                (void)gamma_component_validate("green", &vi,
                   in_ct == 3 ? in_palette[in_index].green :
-                     sample(std, in_ct, in_bd, x, 1),
+                     sample(std, in_ct, in_bd, x, 1, 0, 0),
                   out_ct == 3 ? out_palette[out_index].green :
-                     sample(pRow, out_ct, out_bd, x, 1),
+                     sample(pRow, out_ct, out_bd, x, 1, 0, 0),
                   alpha/*component*/, vi.background_green);
 
                (void)gamma_component_validate("blue", &vi,
                   in_ct == 3 ? in_palette[in_index].blue :
-                     sample(std, in_ct, in_bd, x, 2),
+                     sample(std, in_ct, in_bd, x, 2, 0, 0),
                   out_ct == 3 ? out_palette[out_index].blue :
-                     sample(pRow, out_ct, out_bd, x, 2),
+                     sample(pRow, out_ct, out_bd, x, 2, 0, 0),
                   alpha/*component*/, vi.background_blue);
             }
          }
@@ -8842,15 +10033,15 @@ gamma_end(png_structp ppIn, png_infop pi)
  * maxpc:  maximum percentage error (as a percentage)
  */
 static void
-gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
-    PNG_CONST png_byte bit_depthIn, PNG_CONST int palette_numberIn,
-    PNG_CONST int interlace_typeIn,
-    PNG_CONST double file_gammaIn, PNG_CONST double screen_gammaIn,
-    PNG_CONST png_byte sbitIn, PNG_CONST int threshold_testIn,
-    PNG_CONST char *name,
-    PNG_CONST int use_input_precisionIn, PNG_CONST int scale16In,
-    PNG_CONST int expand16In, PNG_CONST int do_backgroundIn,
-    PNG_CONST png_color_16 *bkgd_colorIn, double bkgd_gammaIn)
+gamma_test(png_modifier *pmIn, const png_byte colour_typeIn,
+    const png_byte bit_depthIn, const int palette_numberIn,
+    const int interlace_typeIn,
+    const double file_gammaIn, const double screen_gammaIn,
+    const png_byte sbitIn, const int threshold_testIn,
+    const char *name,
+    const int use_input_precisionIn, const int scale16In,
+    const int expand16In, const int do_backgroundIn,
+    const png_color_16 *bkgd_colorIn, double bkgd_gammaIn)
 {
    gamma_display d;
    context(&pmIn->this, fault);
@@ -8885,7 +10076,7 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
 
       modification_reset(d.pm->modifications);
 
-      /* Get a png_struct for writing the image. */
+      /* Get a png_struct for reading the image. */
       pp = set_modifier_for_read(d.pm, &pi, d.this.id, name);
       standard_palette_init(&d.this);
 
@@ -9024,9 +10215,13 @@ perform_gamma_threshold_tests(png_modifier *pm)
    /* Don't test more than one instance of each palette - it's pointless, in
     * fact this test is somewhat excessive since libpng doesn't make this
     * decision based on colour type or bit depth!
+    *
+    * CHANGED: now test two palettes and, as a side effect, images with and
+    * without tRNS.
     */
-   while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
-      if (palette_number == 0)
+   while (next_format(&colour_type, &bit_depth, &palette_number,
+                      pm->test_lbg_gamma_threshold, pm->test_tRNS))
+      if (palette_number < 2)
    {
       double test_gamma = 1.0;
       while (test_gamma >= .4)
@@ -9049,11 +10244,11 @@ perform_gamma_threshold_tests(png_modifier *pm)
 }
 
 static void gamma_transform_test(png_modifier *pm,
-   PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth,
-   PNG_CONST int palette_number,
-   PNG_CONST int interlace_type, PNG_CONST double file_gamma,
-   PNG_CONST double screen_gamma, PNG_CONST png_byte sbit,
-   PNG_CONST int use_input_precision, PNG_CONST int scale16)
+   const png_byte colour_type, const png_byte bit_depth,
+   const int palette_number,
+   const int interlace_type, const double file_gamma,
+   const double screen_gamma, const png_byte sbit,
+   const int use_input_precision, const int scale16)
 {
    size_t pos = 0;
    char name[64];
@@ -9086,7 +10281,8 @@ static void perform_gamma_transform_tests(png_modifier *pm)
    png_byte bit_depth = 0;
    unsigned int palette_number = 0;
 
-   while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
+   while (next_format(&colour_type, &bit_depth, &palette_number,
+                      pm->test_lbg_gamma_transform, pm->test_tRNS))
    {
       unsigned int i, j;
 
@@ -9116,7 +10312,8 @@ static void perform_gamma_sbit_tests(png_modifier *pm)
       png_byte colour_type = 0, bit_depth = 0;
       unsigned int npalette = 0;
 
-      while (next_format(&colour_type, &bit_depth, &npalette, 1/*gamma*/))
+      while (next_format(&colour_type, &bit_depth, &npalette,
+                         pm->test_lbg_gamma_sbit, pm->test_tRNS))
          if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 &&
             ((colour_type == 3 && sbit < 8) ||
             (colour_type != 3 && sbit < bit_depth)))
@@ -9151,7 +10348,11 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
 #  ifndef PNG_MAX_GAMMA_8
 #     define PNG_MAX_GAMMA_8 11
 #  endif
-#  define SBIT_16_TO_8 PNG_MAX_GAMMA_8
+#  if defined PNG_MAX_GAMMA_8 || PNG_LIBPNG_VER < 10700
+#     define SBIT_16_TO_8 PNG_MAX_GAMMA_8
+#  else
+#     define SBIT_16_TO_8 16
+#  endif
    /* Include the alpha cases here. Note that sbit matches the internal value
     * used by the library - otherwise we will get spurious errors from the
     * internal sbit style approximation.
@@ -9204,12 +10405,12 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
 #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
 static void gamma_composition_test(png_modifier *pm,
-   PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth,
-   PNG_CONST int palette_number,
-   PNG_CONST int interlace_type, PNG_CONST double file_gamma,
-   PNG_CONST double screen_gamma,
-   PNG_CONST int use_input_precision, PNG_CONST int do_background,
-   PNG_CONST int expand_16)
+   const png_byte colour_type, const png_byte bit_depth,
+   const int palette_number,
+   const int interlace_type, const double file_gamma,
+   const double screen_gamma,
+   const int use_input_precision, const int do_background,
+   const int expand_16)
 {
    size_t pos = 0;
    png_const_charp base;
@@ -9307,8 +10508,17 @@ static void gamma_composition_test(png_modifier *pm,
    }
 
    background.index = 193; /* rgb(193,193,193) to detect errors */
+
    if (!(colour_type & PNG_COLOR_MASK_COLOR))
    {
+      /* Because, currently, png_set_background is always called with
+       * 'need_expand' false in this case and because the gamma test itself
+       * doesn't cause an expand to 8-bit for lower bit depths the colour must
+       * be reduced to the correct range.
+       */
+      if (bit_depth < 8)
+         background.gray &= (png_uint_16)((1U << bit_depth)-1);
+
       /* Grayscale input, we do not convert to RGB (TBD), so we must set the
        * background to gray - else libpng seems to fail.
        */
@@ -9357,9 +10567,18 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
 
    /* Skip the non-alpha cases - there is no setting of a transparency colour at
     * present.
-    */
-   while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
-      if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0)
+    *
+    * TODO: incorrect; the palette case sets tRNS and, now RGB and gray do,
+    * however the palette case fails miserably so is commented out below.
+    */
+   while (next_format(&colour_type, &bit_depth, &palette_number,
+                      pm->test_lbg_gamma_composition, pm->test_tRNS))
+      if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0
+#if 0 /* TODO: FIXME */
+          /*TODO: FIXME: this should work */
+          || colour_type == 3
+#endif
+          || (colour_type != 3 && palette_number != 0))
    {
       unsigned int i, j;
 
@@ -9578,7 +10797,7 @@ perform_gamma_test(png_modifier *pm, int summary)
  * be indexed adam7[y][x] and notice that the pass numbers are based at
  * 1, not 0 - the base libpng uses.
  */
-static PNG_CONST
+static const
 png_byte adam7[8][8] =
 {
    { 1,6,4,6,2,6,4,6 },
@@ -9929,7 +11148,7 @@ perform_interlace_macro_validation(void)
  * The png_modifier code assumes that encodings[0] is sRGB and treats it
  * specially: do not change the first entry in this list!
  */
-static PNG_CONST color_encoding test_encodings[] =
+static const color_encoding test_encodings[] =
 {
 /* sRGB: must be first in this list! */
 /*gamma:*/ { 1/2.2,
@@ -9951,6 +11170,11 @@ static PNG_CONST color_encoding test_encodings[] =
 /*red:  */ { 0.716500716779386, 0.258728243040113, 0.000000000000000 },
 /*green:*/ { 0.101020574397477, 0.724682314948566, 0.051211818965388 },
 /*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} },
+/* Fake encoding which selects just the green channel */
+/*gamma:*/ { 1.45/2.2, /* the 'Mac' gamma */
+/*red:  */ { 0.716500716779386, 0.000000000000000, 0.000000000000000 },
+/*green:*/ { 0.101020574397477, 1.000000000000000, 0.051211818965388 },
+/*blue: */ { 0.146774385252705, 0.000000000000000, 0.773892783545073} },
 };
 
 /* signal handler
@@ -10022,11 +11246,11 @@ static void signal_handler(int signum)
 /* main program */
 int main(int argc, char **argv)
 {
-   volatile int summary = 1;  /* Print the error summary at the end */
-   volatile int memstats = 0; /* Print memory statistics at the end */
+   int summary = 1;  /* Print the error summary at the end */
+   int memstats = 0; /* Print memory statistics at the end */
 
    /* Create the given output file on success: */
-   PNG_CONST char *volatile touch = NULL;
+   const char *touch = NULL;
 
    /* This is an array of standard gamma values (believe it or not I've seen
     * every one of these mentioned somewhere.)
@@ -10042,6 +11266,10 @@ int main(int argc, char **argv)
 
    anon_context(&pm.this);
 
+   gnu_volatile(summary)
+   gnu_volatile(memstats)
+   gnu_volatile(touch)
+
    /* Add appropriate signal handlers, just the ANSI specified ones: */
    signal(SIGABRT, signal_handler);
    signal(SIGFPE, signal_handler);
@@ -10088,14 +11316,30 @@ int main(int argc, char **argv)
 
    /* Store the test gammas */
    pm.gammas = gammas;
-   pm.ngammas = (sizeof gammas) / (sizeof gammas[0]);
+   pm.ngammas = ARRAY_SIZE(gammas);
    pm.ngamma_tests = 0; /* default to off */
 
+   /* Low bit depth gray images don't do well in the gamma tests, until
+    * this is fixed turn them off for some gamma cases:
+    */
+#  ifdef PNG_WRITE_tRNS_SUPPORTED
+      pm.test_tRNS = 1;
+#  endif
+   pm.test_lbg = PNG_LIBPNG_VER >= 10600;
+   pm.test_lbg_gamma_threshold = 1;
+   pm.test_lbg_gamma_transform = PNG_LIBPNG_VER >= 10600;
+   pm.test_lbg_gamma_sbit = 1;
+   pm.test_lbg_gamma_composition = PNG_LIBPNG_VER >= 10700;
+
    /* And the test encodings */
    pm.encodings = test_encodings;
-   pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]);
+   pm.nencodings = ARRAY_SIZE(test_encodings);
 
-   pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
+#  if PNG_LIBPNG_VER < 10700
+      pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
+#  else
+      pm.sbitlow = 1U;
+#  endif
 
    /* The following allows results to pass if they correspond to anything in the
     * transformed range [input-.5,input+.5]; this is is required because of the
@@ -10121,7 +11365,11 @@ int main(int argc, char **argv)
    pm.maxout16 = .499;  /* Error in *encoded* value */
    pm.maxabs16 = .00005;/* 1/20000 */
    pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */
-   pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
+#  if PNG_LIBPNG_VER < 10700
+      pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
+#  else
+      pm.maxcalcG = 1./((1<<16)-1);
+#  endif
 
    /* NOTE: this is a reasonable perceptual limit. We assume that humans can
     * perceive light level differences of 1% over a 100:1 range, so we need to
@@ -10151,7 +11399,11 @@ int main(int argc, char **argv)
       else if (strcmp(*argv, "-q") == 0)
          summary = pm.this.verbose = pm.log = 0;
 
-      else if (strcmp(*argv, "-w") == 0)
+      else if (strcmp(*argv, "-w") == 0 ||
+               strcmp(*argv, "--strict") == 0)
+         pm.this.treat_warnings_as_errors = 1; /* NOTE: this is the default! */
+
+      else if (strcmp(*argv, "--nostrict") == 0)
          pm.this.treat_warnings_as_errors = 0;
 
       else if (strcmp(*argv, "--speed") == 0)
@@ -10203,7 +11455,7 @@ int main(int argc, char **argv)
          pm.test_gamma_transform = 1;
          pm.test_gamma_sbit = 1;
          pm.test_gamma_scale16 = 1;
-         pm.test_gamma_background = 1;
+         pm.test_gamma_background = 1; /* composition */
          pm.test_gamma_alpha_mode = 1;
          }
 
@@ -10252,6 +11504,24 @@ int main(int argc, char **argv)
       else if (strcmp(*argv, "--noexpand16") == 0)
          pm.test_gamma_expand16 = 0;
 
+      else if (strcmp(*argv, "--low-depth-gray") == 0)
+         pm.test_lbg = pm.test_lbg_gamma_threshold =
+            pm.test_lbg_gamma_transform = pm.test_lbg_gamma_sbit =
+            pm.test_lbg_gamma_composition = 1;
+
+      else if (strcmp(*argv, "--nolow-depth-gray") == 0)
+         pm.test_lbg = pm.test_lbg_gamma_threshold =
+            pm.test_lbg_gamma_transform = pm.test_lbg_gamma_sbit =
+            pm.test_lbg_gamma_composition = 0;
+
+#     ifdef PNG_WRITE_tRNS_SUPPORTED
+         else if (strcmp(*argv, "--tRNS") == 0)
+            pm.test_tRNS = 1;
+#     endif
+
+      else if (strcmp(*argv, "--notRNS") == 0)
+         pm.test_tRNS = 0;
+
       else if (strcmp(*argv, "--more-gammas") == 0)
          pm.ngamma_tests = 3U;
 
@@ -10266,12 +11536,12 @@ int main(int argc, char **argv)
 
       else if (strcmp(*argv, "--interlace") == 0)
       {
-#        ifdef PNG_WRITE_INTERLACING_SUPPORTED
+#        if CAN_WRITE_INTERLACE
             pm.interlace_type = PNG_INTERLACE_ADAM7;
-#        else
+#        else /* !CAN_WRITE_INTERLACE */
             fprintf(stderr, "pngvalid: no write interlace support\n");
             return SKIP;
-#        endif
+#        endif /* !CAN_WRITE_INTERLACE */
       }
 
       else if (strcmp(*argv, "--use-input-precision") == 0)
@@ -10349,12 +11619,18 @@ int main(int argc, char **argv)
          const char *arg = 9+*argv;
          unsigned char option=0, setting=0;
 
-#ifdef PNG_ARM_NEON_API_SUPPORTED
+#ifdef PNG_ARM_NEON
          if (strncmp(arg, "arm-neon:", 9) == 0)
             option = PNG_ARM_NEON, arg += 9;
 
          else
 #endif
+#ifdef PNG_EXTENSIONS
+         if (strncmp(arg, "extensions:", 11) == 0)
+            option = PNG_EXTENSIONS, arg += 11;
+
+         else
+#endif
 #ifdef PNG_MAXIMUM_INFLATE_WINDOW
          if (strncmp(arg, "max-inflate-window:", 19) == 0)
             option = PNG_MAXIMUM_INFLATE_WINDOW, arg += 19;
@@ -10442,7 +11718,7 @@ int main(int argc, char **argv)
    Try
    {
       /* Make useful base images */
-      make_transform_images(&pm.this);
+      make_transform_images(&pm);
 
       /* Perform the standard and gamma tests. */
       if (pm.test_standard)