[libpng16] Added the ability for contrib/libtests/makepng.c to make a PNG with just one

color. This is useful for debugging pngstest color inaccuracy reports.
diff --git a/ANNOUNCE b/ANNOUNCE
index 941f3a0..69ecf21 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,5 +1,5 @@
 
-Libpng 1.6.0beta32 - November 2, 2012
+Libpng 1.6.0beta32 - November 14, 2012
 
 This is not intended to be a public release.  It will be replaced
 within a few weeks by a public version or by another test version.
@@ -545,8 +545,10 @@
     gain; implementing full ICC color correction may be desireable but is left
     up to applications.
 
-Version 1.6.0beta32 [November 2, 2012]
-  Fixed an intermittent SEGV in pngstest.
+Version 1.6.0beta32 [November 14, 2012]
+  Fixed an intermittent SEGV in pngstest due to an uninitialized array element.
+  Added the ability for contrib/libtests/makepng.c to make a PNG with just one
+    color. This is useful for debugging pngstest color inaccuracy reports.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/CHANGES b/CHANGES
index 9283ec6..b341321 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4297,8 +4297,10 @@
     gain; implementing full ICC color correction may be desireable but is left
     up to applications.
 
-Version 1.6.0beta32 [November 2, 2012]
-  Fixed an intermittent SEGV in pngstest.
+Version 1.6.0beta32 [November 14, 2012]
+  Fixed an intermittent SEGV in pngstest due to an uninitialized array element.
+  Added the ability for contrib/libtests/makepng.c to make a PNG with just one
+    color. This is useful for debugging pngstest color inaccuracy reports.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/contrib/libtests/makepng.c b/contrib/libtests/makepng.c
index 969cbcf..8df01df 100644
--- a/contrib/libtests/makepng.c
+++ b/contrib/libtests/makepng.c
@@ -10,7 +10,8 @@
  *
  * Make a test PNG image.  The arguments are as follows:
  *
- *  makepng [--sRGB|--linear|--1.8] color-type bit-depth [file-name]
+ *  makepng [--sRGB|--linear|--1.8] [--color=<color>] color-type bit-depth \
+ *	[file-name]
  *
  * The color-type may be numeric (and must match the numbers used by the PNG
  * specification) or one of the format names listed below.  The bit-depth is the
@@ -23,7 +24,8 @@
  * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909
  * is written (1.45/2.2).
  *
- * The image data is generated internally.  The images used are as follows:
+ * The image data is generated internally.  Unless --color is given the images
+ * used are as follows:
  *
  * 1 channel: a square image with a diamond, the least luminous colors are on
  *    the edge of the image, the most luminous in the center.
@@ -61,6 +63,11 @@
  * Row filtering is turned off (the 'none' filter is used on every row) and  the
  * images are not interlaced.
  *
+ * If --color is given then the whole image has that color, color-mapped images
+ * will have exactly one palette entry and all image files with be 16x16 in
+ * size.  The color value is 1 to 4 decimal numbers as appropriate for the color
+ * type.
+ *
  * If file-name is given then the PNG is written to that file, else it is
  * written to stdout.  Notice that stdout is not supported on systems where, by
  * default, it assumes text output; this program makes no attempt to change the
@@ -128,18 +135,24 @@
 }
 
 static unsigned int
-image_size_of_type(int color_type, int bit_depth)
+image_size_of_type(int color_type, int bit_depth, unsigned int *colors)
 {
-   int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
-
-   if (pixel_depth < 8)
-      return 64;
-
-   else if (pixel_depth > 16)
-      return 1024;
+   if (*colors)
+      return 16;
 
    else
-      return 256;
+   {
+      int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
+
+      if (pixel_depth < 8)
+         return 64;
+
+      else if (pixel_depth > 16)
+         return 1024;
+
+      else
+         return 256;
+   }
 }
 
 static void
@@ -155,7 +168,7 @@
 
 static int
 generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
-   png_const_bytep gamma_table)
+   png_const_bytep gamma_table, unsigned int *colors)
 {
    /*
     * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
@@ -166,39 +179,69 @@
     * 4-bit: the 16 combinations of the 2-bit case
     * 8-bit: the 256 combinations of the 4-bit case
     */
-   if (bit_depth == 1)
+   switch (colors[0])
    {
-      set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table);
-      set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table);
-      return 2;
-   }
+      default:
+         fprintf(stderr, "makepng: --colors=...: invalid count %u\n",
+            colors[0]);
+         exit(1);
 
-   else
-   {
-      unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */
-      unsigned int x, y, ip;
-
-      for (x=0; x<size; ++x) for (y=0; y<size; ++y)
-      {
-         ip = x + (size * y);
-
-         /* size is at most 16, so the scaled value below fits in 16 bits */
-#        define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
-#        define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
-            (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
-            (size*size))
-
-         set_color(palette+ip, trans+ip,
-            /* color:    green, red,blue,white */
-            xyinterp(x, y,   0, 255,   0, 255),
-            xyinterp(x, y, 255,   0,   0, 255),
-            xyinterp(x, y,   0,   0, 255, 255),
-            /* alpha:        0, 102, 204, 255) */
-            xyinterp(x, y,   0, 102, 204, 255),
+      case 1:
+         set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255,
             gamma_table);
-      }
+         return 1;
 
-      return ip+1;
+      case 2:
+         set_color(palette+0, trans+0, colors[1], colors[1], colors[1],
+            colors[2], gamma_table);
+         return 1;
+
+      case 3:
+         set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255,
+            gamma_table);
+         return 1;
+
+      case 4:
+         set_color(palette+0, trans+0, colors[1], colors[2], colors[3],
+            colors[4], gamma_table);
+         return 1;
+
+      case 0:
+         if (bit_depth == 1)
+         {
+            set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table);
+            set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table);
+            return 2;
+         }
+
+         else
+         {
+            unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */
+            unsigned int x, y, ip;
+
+            for (x=0; x<size; ++x) for (y=0; y<size; ++y)
+            {
+               ip = x + (size * y);
+
+               /* size is at most 16, so the scaled value below fits in 16 bits
+                */
+#              define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
+#              define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
+                  (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
+                  (size*size))
+
+               set_color(palette+ip, trans+ip,
+                  /* color:    green, red,blue,white */
+                  xyinterp(x, y,   0, 255,   0, 255),
+                  xyinterp(x, y, 255,   0,   0, 255),
+                  xyinterp(x, y,   0,   0, 255, 255),
+                  /* alpha:        0, 102, 204, 255) */
+                  xyinterp(x, y,   0, 102, 204, 255),
+                  gamma_table);
+            }
+
+            return ip+1;
+         }
    }
 }
 
@@ -265,12 +308,13 @@
 
 static void
 generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
-   int bit_depth, png_const_bytep gamma_table, double conv)
+   int bit_depth, png_const_bytep gamma_table, double conv,
+   unsigned int *colors)
 {
-   png_uint_32 size_max = image_size_of_type(color_type, bit_depth)-1;
+   png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1;
    png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
 
-   switch (channels_of_type(color_type))
+   if (colors[0] == 0) switch (channels_of_type(color_type))
    {
    /* 1 channel: a square image with a diamond, the least luminous colors are on
     *    the edge of the image, the most luminous in the center.
@@ -390,6 +434,98 @@
          fprintf(stderr, "makepng: internal bad channel count\n");
          exit(2);
    }
+
+   else if (color_type & PNG_COLOR_MASK_PALETTE)
+   {
+      /* Palette with fixed color: the image rows are all 0 and the image width
+       * is 16.
+       */
+      memset(row, rowbytes, 0);
+   }
+
+   else if (colors[0] == channels_of_type(color_type))
+      switch (channels_of_type(color_type))
+      {
+         case 1:
+            {
+               const png_uint_32 luma = colors[1];
+               png_uint_32 x;
+
+               for (x=0; x<=size_max; ++x)
+                  set_value(row, rowbytes, x, bit_depth, luma, gamma_table,
+                     conv);
+            }
+            break;
+
+         case 2:
+            {
+               const png_uint_32 luma = colors[1];
+               const png_uint_32 alpha = colors[2];
+               png_uint_32 x;
+
+               for (x=0; x<size_max; ++x)
+               {
+                  set_value(row, rowbytes, 2*x, bit_depth, luma, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
+                     conv);
+               }
+            }
+            break;
+
+         case 3:
+            {
+               const png_uint_32 red = colors[1];
+               const png_uint_32 green = colors[2];
+               const png_uint_32 blue = colors[3];
+               png_uint_32 x;
+
+               for (x=0; x<=size_max; ++x)
+               {
+                  set_value(row, rowbytes, 3*x+0, bit_depth, red, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 3*x+1, bit_depth, green, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 3*x+2, bit_depth, blue, gamma_table,
+                     conv);
+               }
+            }
+            break;
+
+         case 4:
+            {
+               const png_uint_32 red = colors[1];
+               const png_uint_32 green = colors[2];
+               const png_uint_32 blue = colors[3];
+               const png_uint_32 alpha = colors[4];
+               png_uint_32 x;
+
+               for (x=0; x<=size_max; ++x)
+               {
+                  set_value(row, rowbytes, 4*x+0, bit_depth, red, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 4*x+1, bit_depth, green, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 4*x+2, bit_depth, blue, gamma_table,
+                     conv);
+                  set_value(row, rowbytes, 4*x+3, bit_depth, alpha, gamma_table,
+                     conv);
+               }
+            }
+         break;
+
+         default:
+            fprintf(stderr, "makepng: internal bad channel count\n");
+            exit(2);
+      }
+
+   else
+   {
+      fprintf(stderr,
+         "makepng: --color: count(%u) does not match channels(%u)\n",
+         colors[0], channels_of_type(color_type));
+      exit(1);
+   }
 }
 
 
@@ -418,7 +554,7 @@
 static int /* 0 on success, else an error code */
 write_png(const char **name, FILE *fp, int color_type, int bit_depth,
    volatile png_fixed_point gamma, chunk_insert * volatile insert,
-   unsigned int filters)
+   unsigned int filters, unsigned int *colors)
 {
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
       name, makepng_error, makepng_warning);
@@ -452,7 +588,7 @@
       png_error(png_ptr, "OOM allocating info structure");
 
    {
-      unsigned int size = image_size_of_type(color_type, bit_depth);
+      unsigned int size = image_size_of_type(color_type, bit_depth, colors);
       png_fixed_point real_gamma = 45455; /* For sRGB */
       png_byte gamma_table[256];
       double conv;
@@ -504,7 +640,8 @@
          png_color palette[256];
          png_byte trans[256];
 
-         npalette = generate_palette(palette, trans, bit_depth, gamma_table);
+         npalette = generate_palette(palette, trans, bit_depth, gamma_table,
+            colors);
          png_set_PLTE(png_ptr, info_ptr, palette, npalette);
          png_set_tRNS(png_ptr, info_ptr, trans, npalette-1,
             NULL/*transparent color*/);
@@ -561,7 +698,7 @@
             for (y=0; y<size; ++y)
             {
                generate_row(row, rowbytes, y, color_type, bit_depth,
-                  gamma_table, conv);
+                  gamma_table, conv, colors);
                png_write_row(png_ptr, row);
             }
          }
@@ -1094,6 +1231,48 @@
    return NULL;
 }
 
+/* This is a not-very-good parser for a sequence of numbers (including 0).  It
+ * doesn't accept some apparenly valid things, but it accepts all the sensible
+ * combinations.
+ */
+static void
+parse_color(char *arg, unsigned int *colors)
+{
+   unsigned int ncolors = 0;
+
+   while (*arg && ncolors < 4)
+   {
+      char *ep = arg;
+
+      unsigned long ul = strtoul(arg, &ep, 0);
+
+      if (ul > 65535)
+      {
+         fprintf(stderr, "makepng --color=...'%s': too big\n", arg);
+         exit(1);
+      }
+
+      if (ep == arg)
+      {
+         fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg);
+         exit(1);
+      }
+
+      if (*ep) ++ep; /* skip a separator */
+      arg = ep;
+
+      colors[++ncolors] = (unsigned int)ul; /* checked above */
+   }
+
+   if (*arg)
+   {
+      fprintf(stderr, "makepng --color=...'%s': too many values\n", arg);
+      exit(1);
+   }
+
+   *colors = ncolors;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1101,14 +1280,17 @@
    const char *file_name = NULL;
    int color_type = 8; /* invalid */
    int bit_depth = 32; /* invalid */
+   unsigned int colors[5];
    unsigned int filters = PNG_ALL_FILTERS;
    png_fixed_point gamma = 0; /* not set */
    chunk_insert *head_insert = NULL;
    chunk_insert **insert_ptr = &head_insert;
 
+   memset(colors, 0, sizeof colors);
+
    while (--argc > 0)
    {
-      const char *arg = *++argv;
+      char *arg = *++argv;
 
       if (strcmp(arg, "--sRGB") == 0)
       {
@@ -1134,6 +1316,12 @@
          continue;
       }
 
+      if (strncmp(arg, "--color=", 8) == 0)
+      {
+	  parse_color(arg+8, colors);
+	  continue;
+      }
+
       if (argc >= 3 && strcmp(arg, "--insert") == 0)
       {
          png_const_charp what = *++argv;
@@ -1245,11 +1433,26 @@
    if (color_type == 8 || bit_depth == 32)
    {
       fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] "
-         "color-type bit-depth [file-name]\n"
+         "[--color=...] color-type bit-depth [file-name]\n"
          "  Make a test PNG file, by default writes to stdout.\n");
       exit(1);
    }
 
+   /* Check the colors */
+   {
+      const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U :
+         (1U<<bit_depth)-1);
+      unsigned int i;
+
+      for (i=1; i<=colors[0]; ++i)
+         if (colors[i] > lim)
+         {
+            fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n",
+               colors[i], lim);
+            exit(1);
+         }
+   }
+
    /* Restrict the filters for more speed to those we know are used for the
     * generated images.
     */
@@ -1273,7 +1476,7 @@
 
    {
       int ret = write_png(&file_name, fp, color_type, bit_depth, gamma,
-         head_insert, filters);
+         head_insert, filters, colors);
 
       if (ret != 0 && file_name != NULL)
          remove(file_name);