[Feature][ZXW-88]merge P50 version

Only Configure: No
Affected branch: master
Affected module: unknown
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: I34667719d9e0e7e29e8e4368848601cde0a48408
diff --git a/ap/lib/libpng/libpng-1.6.37/contrib/examples/README.txt b/ap/lib/libpng/libpng-1.6.37/contrib/examples/README.txt
new file mode 100755
index 0000000..48dab4f
--- /dev/null
+++ b/ap/lib/libpng/libpng-1.6.37/contrib/examples/README.txt
@@ -0,0 +1,24 @@
+
+This directory (contrib/examples) contains examples of libpng usage.
+
+NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY.
+
+To the extent possible under law, the authors have waived all copyright and
+related or neighboring rights to this work.  This work is published from:
+United States.
+
+The files may be used freely in any way.  The intention is that appropriate
+parts of the files be used in other libpng-using programs without any need for
+the authors of the using code to seek copyright or license from the original
+authors.
+
+The source code and comments in this directory are the original work of the
+people named below.  No other person or organization has made contributions to
+the work in this directory.
+
+ORIGINAL AUTHORS
+    The following people have contributed to the code in this directory.  None
+    of the people below claim any rights with regard to the contents of this
+    directory.
+
+    John Bowler <jbowler at acm.org>
diff --git a/ap/lib/libpng/libpng-1.6.37/contrib/examples/iccfrompng.c b/ap/lib/libpng/libpng-1.6.37/contrib/examples/iccfrompng.c
new file mode 100755
index 0000000..00056ab
--- /dev/null
+++ b/ap/lib/libpng/libpng-1.6.37/contrib/examples/iccfrompng.c
@@ -0,0 +1,185 @@
+/*- iccfrompng
+ *
+ * COPYRIGHT: Written by John Cunningham Bowler, 2011.
+ * To the extent possible under law, the author has waived all copyright and
+ * related or neighboring rights to this work.  This work is published from:
+ * United States.
+ *
+ * Extract any icc profiles found in the given PNG files.  This is a simple
+ * example of a program that extracts information from the header of a PNG file
+ * without processing the image.  Notice that some header information may occur
+ * after the image data. Textual data and comments are an example; the approach
+ * in this file won't work reliably for such data because it only looks for the
+ * information in the section of the file that precedes the image data.
+ *
+ * Compile and link against libpng and zlib, plus anything else required on the
+ * system you use.
+ *
+ * To use supply a list of PNG files containing iCCP chunks, the chunks will be
+ * extracted to a similarly named file with the extension replaced by 'icc',
+ * which will be overwritten without warning.
+ */
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <png.h>
+
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \
+    defined (PNG_iCCP_SUPPORTED)
+
+
+static int verbose = 1;
+static png_byte no_profile[] = "no profile";
+
+static png_bytep
+extract(FILE *fp, png_uint_32 *proflen)
+{
+   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
+   png_infop info_ptr = NULL;
+   png_bytep result = NULL;
+
+   /* Initialize for error or no profile: */
+   *proflen = 0;
+
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "iccfrompng: version library mismatch?\n");
+      return 0;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+      return 0;
+   }
+
+   png_init_io(png_ptr, fp);
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+      png_error(png_ptr, "OOM allocating info structure");
+
+   png_read_info(png_ptr, info_ptr);
+
+   {
+      png_charp name;
+      int compression_type;
+      png_bytep profile;
+
+      if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
+         proflen) & PNG_INFO_iCCP)
+      {
+         result = malloc(*proflen);
+         if (result != NULL)
+            memcpy(result, profile, *proflen);
+
+         else
+            png_error(png_ptr, "OOM allocating profile buffer");
+      }
+
+      else
+	result = no_profile;
+   }
+
+   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+   return result;
+}
+
+static int
+extract_one_file(const char *filename)
+{
+   int result = 0;
+   FILE *fp = fopen(filename, "rb");
+
+   if (fp != NULL)
+   {
+      png_uint_32 proflen = 0;
+      png_bytep profile = extract(fp, &proflen);
+
+      if (profile != NULL && profile != no_profile)
+      {
+         size_t len;
+         char *output;
+
+         {
+            const char *ep = strrchr(filename, '.');
+
+            if (ep != NULL)
+               len = ep-filename;
+
+            else
+               len = strlen(filename);
+         }
+
+         output = malloc(len + 5);
+         if (output != NULL)
+         {
+            FILE *of;
+
+            memcpy(output, filename, len);
+            strcpy(output+len, ".icc");
+
+            of = fopen(output, "wb");
+            if (of != NULL)
+            {
+               if (fwrite(profile, proflen, 1, of) == 1 &&
+                  fflush(of) == 0 &&
+                  fclose(of) == 0)
+               {
+                  if (verbose)
+                     printf("%s -> %s\n", filename, output);
+                  /* Success return */
+                  result = 1;
+               }
+
+               else
+               {
+                  fprintf(stderr, "%s: error writing profile\n", output);
+                  if (remove(output))
+                     fprintf(stderr, "%s: could not remove file\n", output);
+               }
+            }
+
+            else
+               fprintf(stderr, "%s: failed to open output file\n", output);
+
+            free(output);
+         }
+
+         else
+            fprintf(stderr, "%s: OOM allocating string!\n", filename);
+
+         free(profile);
+      }
+
+      else if (verbose && profile == no_profile)
+	printf("%s has no profile\n", filename);
+   }
+
+   else
+      fprintf(stderr, "%s: could not open file\n", filename);
+
+   return result;
+}
+
+int
+main(int argc, char **argv)
+{
+   int i;
+   int extracted = 0;
+
+   for (i=1; i<argc; ++i)
+   {
+      if (strcmp(argv[i], "-q") == 0)
+         verbose = 0;
+
+      else if (extract_one_file(argv[i]))
+         extracted = 1;
+   }
+
+   /* Exit code is true if any extract succeeds */
+   return extracted == 0;
+}
+#endif /* READ && STDIO && iCCP */
diff --git a/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngpixel.c b/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngpixel.c
new file mode 100755
index 0000000..9185d51
--- /dev/null
+++ b/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngpixel.c
@@ -0,0 +1,371 @@
+/*- pngpixel
+ *
+ * COPYRIGHT: Written by John Cunningham Bowler, 2011.
+ * To the extent possible under law, the author has waived all copyright and
+ * related or neighboring rights to this work.  This work is published from:
+ * United States.
+ *
+ * Read a single pixel value from a PNG file.
+ *
+ * This code illustrates basic 'by-row' reading of a PNG file using libpng.
+ * Rows are read until a particular pixel is found; the value of this pixel is
+ * then printed on stdout.
+ *
+ * The code illustrates how to do this on interlaced as well as non-interlaced
+ * images.  Normally you would call png_set_interlace_handling() to have libpng
+ * deal with the interlace for you, but that obliges you to buffer half of the
+ * image to assemble the interlaced rows.  In this code
+ * png_set_interlace_handling() is not called and, instead, the code handles the
+ * interlace passes directly looking for the required pixel.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <setjmp.h> /* required for error handling */
+
+/* Normally use <png.h> here to get the installed libpng, but this is done to
+ * ensure the code picks up the local libpng implementation:
+ */
+#include "../../png.h"
+
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
+
+/* Return component 'c' of pixel 'x' from the given row. */
+static unsigned int
+component(png_const_bytep row, png_uint_32 x, unsigned int c,
+   unsigned int bit_depth, unsigned int channels)
+{
+   /* PNG images can be up to 2^31 pixels wide, but this means they can be up to
+    * 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34
+    * bytes wide.  Since the row fitted into memory, however, the following must
+    * work:
+    */
+   png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels);
+   png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c);
+
+   row = (png_const_bytep)(((const png_byte (*)[8])row) + bit_offset_hi);
+   row += bit_offset_lo >> 3;
+   bit_offset_lo &= 0x07;
+
+   /* PNG pixels are packed into bytes to put the first pixel in the highest
+    * bits of the byte and into two bytes for 16-bit values with the high 8 bits
+    * first, so:
+    */
+   switch (bit_depth)
+   {
+      case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01;
+      case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03;
+      case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f;
+      case 8: return row[0];
+      case 16: return (row[0] << 8) + row[1];
+      default:
+         /* This should never happen; it indicates a bug in this program or in
+          * libpng itself:
+          */
+         fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth);
+         exit(1);
+   }
+}
+
+/* Print a pixel from a row returned by libpng; determine the row format, find
+ * the pixel, and print the relevant information to stdout.
+ */
+static void
+print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
+   png_uint_32 x)
+{
+   unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+
+   switch (png_get_color_type(png_ptr, info_ptr))
+   {
+      case PNG_COLOR_TYPE_GRAY:
+         printf("GRAY %u\n", component(row, x, 0, bit_depth, 1));
+         return;
+
+      /* The palette case is slightly more difficult - the palette and, if
+       * present, the tRNS ('transparency', though the values are really
+       * opacity) data must be read to give the full picture:
+       */
+      case PNG_COLOR_TYPE_PALETTE:
+         {
+            int index = component(row, x, 0, bit_depth, 1);
+            png_colorp palette = NULL;
+            int num_palette = 0;
+
+            if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) &
+               PNG_INFO_PLTE) && num_palette > 0 && palette != NULL)
+            {
+               png_bytep trans_alpha = NULL;
+               int num_trans = 0;
+               if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans,
+                  NULL) & PNG_INFO_tRNS) && num_trans > 0 &&
+                  trans_alpha != NULL)
+                  printf("INDEXED %u = %d %d %d %d\n", index,
+                     palette[index].red, palette[index].green,
+                     palette[index].blue,
+                     index < num_trans ? trans_alpha[index] : 255);
+
+               else /* no transparency */
+                  printf("INDEXED %u = %d %d %d\n", index,
+                     palette[index].red, palette[index].green,
+                     palette[index].blue);
+            }
+
+            else
+               printf("INDEXED %u = invalid index\n", index);
+         }
+         return;
+
+      case PNG_COLOR_TYPE_RGB:
+         printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3),
+            component(row, x, 1, bit_depth, 3),
+            component(row, x, 2, bit_depth, 3));
+         return;
+
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
+         printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2),
+            component(row, x, 1, bit_depth, 2));
+         return;
+
+      case PNG_COLOR_TYPE_RGB_ALPHA:
+         printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4),
+            component(row, x, 1, bit_depth, 4),
+            component(row, x, 2, bit_depth, 4),
+            component(row, x, 3, bit_depth, 4));
+         return;
+
+      default:
+         png_error(png_ptr, "pngpixel: invalid color type");
+   }
+}
+
+int main(int argc, const char **argv)
+{
+   /* This program uses the default, <setjmp.h> based, libpng error handling
+    * mechanism, therefore any local variable that exists before the call to
+    * setjmp and is changed after the call to setjmp returns successfully must
+    * be declared with 'volatile' to ensure that their values don't get
+    * destroyed by longjmp:
+    */
+   volatile int result = 1/*fail*/;
+
+   if (argc == 4)
+   {
+      long x = atol(argv[1]);
+      long y = atol(argv[2]);
+      FILE *f = fopen(argv[3], "rb");
+      volatile png_bytep row = NULL;
+
+      if (f != NULL)
+      {
+         /* libpng requires a callback function for handling errors; this
+          * callback must not return.  The default callback function uses a
+          * stored <setjmp.h> style jmp_buf which is held in a png_struct and
+          * writes error messages to stderr.  Creating the png_struct is a
+          * little tricky; just copy the following code.
+          */
+         png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+            NULL, NULL, NULL);
+
+         if (png_ptr != NULL)
+         {
+            png_infop info_ptr = png_create_info_struct(png_ptr);
+
+            if (info_ptr != NULL)
+            {
+               /* Declare stack variables to hold pointers to locally allocated
+                * data.
+                */
+
+               /* Initialize the error control buffer: */
+               if (setjmp(png_jmpbuf(png_ptr)) == 0)
+               {
+                  png_uint_32 width, height;
+                  int bit_depth, color_type, interlace_method,
+                     compression_method, filter_method;
+                  png_bytep row_tmp;
+
+                  /* Now associate the recently opened (FILE*) with the default
+                   * libpng initialization functions.  Sometimes libpng is
+                   * compiled without stdio support (it can be difficult to do
+                   * in some environments); in that case you will have to write
+                   * your own read callback to read data from the (FILE*).
+                   */
+                  png_init_io(png_ptr, f);
+
+                  /* And read the first part of the PNG file - the header and
+                   * all the information up to the first pixel.
+                   */
+                  png_read_info(png_ptr, info_ptr);
+
+                  /* This fills in enough information to tell us the width of
+                   * each row in bytes, allocate the appropriate amount of
+                   * space.  In this case png_malloc is used - it will not
+                   * return if memory isn't available.
+                   */
+                  row = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
+                     info_ptr));
+
+                  /* To avoid the overhead of using a volatile auto copy row_tmp
+                   * to a local here - just use row for the png_free below.
+                   */
+                  row_tmp = row;
+
+                  /* All the information we need is in the header is returned by
+                   * png_get_IHDR, if this fails we can now use 'png_error' to
+                   * signal the error and return control to the setjmp above.
+                   */
+                  if (png_get_IHDR(png_ptr, info_ptr, &width, &height,
+                     &bit_depth, &color_type, &interlace_method,
+                     &compression_method, &filter_method))
+                  {
+                     int passes, pass;
+
+                     /* png_set_interlace_handling returns the number of
+                      * passes required as well as turning on libpng's
+                      * handling, but since we do it ourselves this is
+                      * necessary:
+                      */
+                     switch (interlace_method)
+                     {
+                        case PNG_INTERLACE_NONE:
+                           passes = 1;
+                           break;
+
+                        case PNG_INTERLACE_ADAM7:
+                           passes = PNG_INTERLACE_ADAM7_PASSES;
+                           break;
+
+                        default:
+                           png_error(png_ptr, "pngpixel: unknown interlace");
+                     }
+
+                     /* Now read the pixels, pass-by-pass, row-by-row: */
+                     png_start_read_image(png_ptr);
+
+                     for (pass=0; pass<passes; ++pass)
+                     {
+                        png_uint_32 ystart, xstart, ystep, xstep;
+                        png_uint_32 py;
+
+                        if (interlace_method == PNG_INTERLACE_ADAM7)
+                        {
+                           /* Sometimes the whole pass is empty because the
+                            * image is too narrow or too short.  libpng
+                            * expects to be called for each row that is
+                            * present in the pass, so it may be necessary to
+                            * skip the loop below (over py) if the image is
+                            * too narrow.
+                            */
+                           if (PNG_PASS_COLS(width, pass) == 0)
+                              continue;
+
+                           /* We need the starting pixel and the offset
+                            * between each pixel in this pass; use the macros
+                            * in png.h:
+                            */
+                           xstart = PNG_PASS_START_COL(pass);
+                           ystart = PNG_PASS_START_ROW(pass);
+                           xstep = PNG_PASS_COL_OFFSET(pass);
+                           ystep = PNG_PASS_ROW_OFFSET(pass);
+                        }
+
+                        else
+                        {
+                           ystart = xstart = 0;
+                           ystep = xstep = 1;
+                        }
+
+                        /* To find the pixel, loop over 'py' for each pass
+                         * reading a row and then checking to see if it
+                         * contains the pixel.
+                         */
+                        for (py = ystart; py < height; py += ystep)
+                        {
+                           png_uint_32 px, ppx;
+
+                           /* png_read_row takes two pointers.  When libpng
+                            * handles the interlace the first is filled in
+                            * pixel-by-pixel, and the second receives the same
+                            * pixels but they are replicated across the
+                            * unwritten pixels so far for each pass.  When we
+                            * do the interlace, however, they just contain
+                            * the pixels from the interlace pass - giving
+                            * both is wasteful and pointless, so we pass a
+                            * NULL pointer.
+                            */
+                           png_read_row(png_ptr, row_tmp, NULL);
+
+                           /* Now find the pixel if it is in this row; there
+                            * are, of course, much better ways of doing this
+                            * than using a for loop:
+                            */
+                           if (y == py) for (px = xstart, ppx = 0;
+                              px < width; px += xstep, ++ppx) if (x == px)
+                           {
+                              /* 'ppx' is the index of the pixel in the row
+                               * buffer.
+                               */
+                              print_pixel(png_ptr, info_ptr, row_tmp, ppx);
+
+                              /* Now terminate the loops early - we have
+                               * found and handled the required data.
+                               */
+                              goto pass_loop_end;
+                           } /* x loop */
+                        } /* y loop */
+                     } /* pass loop */
+
+                     /* Finally free the temporary buffer: */
+                  pass_loop_end:
+                     row = NULL;
+                     png_free(png_ptr, row_tmp);
+                  }
+
+                  else
+                     png_error(png_ptr, "pngpixel: png_get_IHDR failed");
+
+               }
+
+               else
+               {
+                  /* Else libpng has raised an error.  An error message has
+                   * already been output, so it is only necessary to clean up
+                   * locally allocated data:
+                   */
+                  if (row != NULL)
+                  {
+                     /* The default implementation of png_free never errors out
+                      * (it just crashes if something goes wrong), but the safe
+                      * way of using it is still to clear 'row' before calling
+                      * png_free:
+                      */
+                     png_bytep row_tmp = row;
+                     row = NULL;
+                     png_free(png_ptr, row_tmp);
+                  }
+               }
+
+               png_destroy_info_struct(png_ptr, &info_ptr);
+            }
+
+            else
+               fprintf(stderr, "pngpixel: out of memory allocating png_info\n");
+
+            png_destroy_read_struct(&png_ptr, NULL, NULL);
+         }
+
+         else
+            fprintf(stderr, "pngpixel: out of memory allocating png_struct\n");
+      }
+
+      else
+         fprintf(stderr, "pngpixel: %s: could not open file\n", argv[3]);
+   }
+
+   else
+      /* Wrong number of arguments */
+      fprintf(stderr, "pngpixel: usage: pngpixel x y png-file\n");
+
+   return result;
+}
+#endif /* READ && SEQUENTIAL_READ */
diff --git a/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngtopng.c b/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngtopng.c
new file mode 100755
index 0000000..904b972
--- /dev/null
+++ b/ap/lib/libpng/libpng-1.6.37/contrib/examples/pngtopng.c
@@ -0,0 +1,98 @@
+/*- pngtopng
+ *
+ * COPYRIGHT: Written by John Cunningham Bowler, 2011, 2017.
+ * To the extent possible under law, the author has waived all copyright and
+ * related or neighboring rights to this work.  This work is published from:
+ * United States.
+ *
+ * Last changed in libpng 1.6.29 [March 16, 2017]
+ *
+ * Read a PNG and write it out in a fixed format, using the 'simplified API'
+ * that was introduced in libpng-1.6.0.
+ *
+ * This sample code is just the code from the top of 'example.c' with some error
+ * handling added.  See example.c for more comments.
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/* Normally use <png.h> here to get the installed libpng, but this is done to
+ * ensure the code picks up the local libpng implementation:
+ */
+#include "../../png.h"
+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && \
+    defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+
+int main(int argc, const char **argv)
+{
+   int result = 1;
+
+   if (argc == 3)
+   {
+      png_image image;
+
+      /* Only the image structure version number needs to be set. */
+      memset(&image, 0, sizeof image);
+      image.version = PNG_IMAGE_VERSION;
+
+      if (png_image_begin_read_from_file(&image, argv[1]))
+      {
+         png_bytep buffer;
+
+         /* Change this to try different formats!  If you set a colormap format
+          * then you must also supply a colormap below.
+          */
+         image.format = PNG_FORMAT_RGBA;
+
+         buffer = malloc(PNG_IMAGE_SIZE(image));
+
+         if (buffer != NULL)
+         {
+            if (png_image_finish_read(&image, NULL/*background*/, buffer,
+               0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */))
+            {
+               if (png_image_write_to_file(&image, argv[2],
+                  0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
+                  NULL/*colormap*/))
+                  result = 0;
+
+               else
+                  fprintf(stderr, "pngtopng: write %s: %s\n", argv[2],
+                      image.message);
+            }
+
+            else
+               fprintf(stderr, "pngtopng: read %s: %s\n", argv[1],
+                   image.message);
+
+            free(buffer);
+         }
+
+         else
+         {
+            fprintf(stderr, "pngtopng: out of memory: %lu bytes\n",
+               (unsigned long)PNG_IMAGE_SIZE(image));
+
+            /* This is the only place where a 'free' is required; libpng does
+             * the cleanup on error and success, but in this case we couldn't
+             * complete the read because of running out of memory and so libpng
+             * has not got to the point where it can do cleanup.
+             */
+            png_image_free(&image);
+         }
+      }
+
+      else
+         /* Failed to read the first argument: */
+         fprintf(stderr, "pngtopng: %s: %s\n", argv[1], image.message);
+   }
+
+   else
+      /* Wrong number of arguments */
+      fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n");
+
+   return result;
+}
+#endif /* READ && WRITE */
diff --git a/ap/lib/libpng/libpng-1.6.37/contrib/examples/simpleover.c b/ap/lib/libpng/libpng-1.6.37/contrib/examples/simpleover.c
new file mode 100755
index 0000000..59dd313
--- /dev/null
+++ b/ap/lib/libpng/libpng-1.6.37/contrib/examples/simpleover.c
@@ -0,0 +1,648 @@
+/*- simpleover
+ *
+ * COPYRIGHT: Written by John Cunningham Bowler, 2015.
+ * To the extent possible under law, the author has waived all copyright and
+ * related or neighboring rights to this work.  This work is published from:
+ * United States.
+ *
+ * Read several PNG files, which should have an alpha channel or transparency
+ * information, and composite them together to produce one or more 16-bit linear
+ * RGBA intermediates.  This involves doing the correct 'over' composition to
+ * combine the alpha channels and corresponding data.
+ *
+ * Finally read an output (background) PNG using the 24-bit RGB format (the
+ * PNG will be composited on green (#00ff00) by default if it has an alpha
+ * channel), and apply the intermediate image generated above to specified
+ * locations in the image.
+ *
+ * The command line has the general format:
+ *
+ *    simpleover <background.png> [output.png]
+ *        {--sprite=width,height,name {[--at=x,y] {sprite.png}}}
+ *        {--add=name {x,y}}
+ *
+ * The --sprite and --add options may occur multiple times. They are executed
+ * in order.  --add may refer to any sprite already read.
+ *
+ * This code is intended to show how to composite multiple images together
+ * correctly.  Apart from the libpng Simplified API the only work done in here
+ * is to combine multiple input PNG images into a single sprite; this involves
+ * a Porter-Duff 'over' operation and the input PNG images may, as a result,
+ * be regarded as being layered one on top of the other with the first (leftmost
+ * on the command line) being at the bottom and the last on the top.
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* Normally use <png.h> here to get the installed libpng, but this is done to
+ * ensure the code picks up the local libpng implementation, so long as this
+ * file is linked against a sufficiently recent libpng (1.6+) it is ok to
+ * change this to <png.h>:
+ */
+#include "../../png.h"
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+
+#define sprite_name_chars 15
+struct sprite {
+   FILE         *file;
+   png_uint_16p  buffer;
+   unsigned int  width;
+   unsigned int  height;
+   char          name[sprite_name_chars+1];
+};
+
+#if 0 /* div by 65535 test program */
+#include <math.h>
+#include <stdio.h>
+
+int main(void) {
+   double err = 0;
+   unsigned int xerr = 0;
+   unsigned int r = 32769;
+   {
+      unsigned int x = 0;
+
+      do {
+         unsigned int t = x + (x >> 16) /*+ (x >> 31)*/ + r;
+         double v = x, errtest;
+
+         if (t < x) {
+            fprintf(stderr, "overflow: %u+%u -> %u\n", x, r, t);
+            return 1;
+         }
+
+         v /= 65535;
+         errtest = v;
+         t >>= 16;
+         errtest -= t;
+
+         if (errtest > err) {
+            err = errtest;
+            xerr = x;
+
+            if (errtest >= .5) {
+               fprintf(stderr, "error: %u/65535 = %f, not %u, error %f\n",
+                     x, v, t, errtest);
+               return 0;
+            }
+         }
+      } while (++x <= 65535U*65535U);
+   }
+
+   printf("error %f @ %u\n", err, xerr);
+
+   return 0;
+}
+#endif /* div by 65535 test program */
+
+static void
+sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
+   png_imagep image, const png_uint_16 *buffer)
+{
+   /* This is where the Porter-Duff 'Over' operator is evaluated; change this
+    * code to change the operator (this could be parameterized).  Any other
+    * image processing operation could be used here.
+    */
+
+
+   /* Check for an x or y offset that pushes any part of the image beyond the
+    * right or bottom of the sprite:
+    */
+   if ((y_offset < 0 || (unsigned)/*SAFE*/y_offset < sprite->height) &&
+       (x_offset < 0 || (unsigned)/*SAFE*/x_offset < sprite->width))
+   {
+      unsigned int y = 0;
+
+      if (y_offset < 0)
+         y = -y_offset; /* Skip to first visible row */
+
+      do
+      {
+         unsigned int x = 0;
+
+         if (x_offset < 0)
+            x = -x_offset;
+
+         do
+         {
+            /* In and out are RGBA values, so: */
+            const png_uint_16 *in_pixel = buffer + (y * image->width + x)*4;
+            png_uint_32 in_alpha = in_pixel[3];
+
+            /* This is the optimized Porter-Duff 'Over' operation, when the
+             * input alpha is 0 the output is not changed.
+             */
+            if (in_alpha > 0)
+            {
+               png_uint_16 *out_pixel = sprite->buffer +
+                  ((y+y_offset) * sprite->width + (x+x_offset))*4;
+
+               /* This is the weight to apply to the output: */
+               in_alpha = 65535-in_alpha;
+
+               if (in_alpha > 0)
+               {
+                  /* The input must be composed onto the output. This means
+                   * multiplying the current output pixel value by the inverse
+                   * of the input alpha (1-alpha). A division is required but
+                   * it is by the constant 65535.  Approximate this as:
+                   *
+                   *     (x + (x >> 16) + 32769) >> 16;
+                   *
+                   * This is exact (and does not overflow) for all values of
+                   * x in the range 0..65535*65535.  (Note that the calculation
+                   * produces the closest integer; the maximum error is <0.5).
+                   */
+                  png_uint_32 tmp;
+
+#                 define compose(c)\
+                     tmp = out_pixel[c] * in_alpha;\
+                     tmp = (tmp + (tmp >> 16) + 32769) >> 16;\
+                     out_pixel[c] = tmp + in_pixel[c]
+
+                  /* The following is very vectorizable... */
+                  compose(0);
+                  compose(1);
+                  compose(2);
+                  compose(3);
+               }
+
+               else
+                  out_pixel[0] = in_pixel[0],
+                  out_pixel[1] = in_pixel[1],
+                  out_pixel[2] = in_pixel[2],
+                  out_pixel[3] = in_pixel[3];
+            }
+         }
+         while (++x < image->width);
+      }
+      while (++y < image->height);
+   }
+}
+
+static int
+create_sprite(struct sprite *sprite, int *argc, const char ***argv)
+{
+   /* Read the arguments and create this sprite. The sprite buffer has already
+    * been allocated. This reads the input PNGs one by one in linear format,
+    * composes them onto the sprite buffer (the code in the function above)
+    * then saves the result, converting it on the fly to PNG RGBA 8-bit format.
+    */
+   while (*argc > 0)
+   {
+      char tombstone;
+      int x = 0, y = 0;
+
+      if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
+      {
+         /* The only supported option is --at. */
+         if (sscanf((*argv)[0], "--at=%d,%d%c", &x, &y, &tombstone) != 2)
+            break; /* success; caller will parse this option */
+
+         ++*argv, --*argc;
+      }
+
+      else
+      {
+         /* The argument has to be a file name */
+         png_image image;
+
+         image.version = PNG_IMAGE_VERSION;
+         image.opaque = NULL;
+
+         if (png_image_begin_read_from_file(&image, (*argv)[0]))
+         {
+            png_uint_16p buffer;
+
+            image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
+
+            buffer = malloc(PNG_IMAGE_SIZE(image));
+
+            if (buffer != NULL)
+            {
+               if (png_image_finish_read(&image, NULL/*background*/, buffer,
+                  0/*row_stride*/,
+                  NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
+               {
+                  /* This is the place where the Porter-Duff 'Over' operator
+                   * needs to be done by this code.  In fact, any image
+                   * processing required can be done here; the data is in
+                   * the correct format (linear, 16-bit) and source and
+                   * destination are in memory.
+                   */
+                  sprite_op(sprite, x, y, &image, buffer);
+                  free(buffer);
+                  ++*argv, --*argc;
+                  /* And continue to the next argument */
+                  continue;
+               }
+
+               else
+               {
+                  free(buffer);
+                  fprintf(stderr, "simpleover: read %s: %s\n", (*argv)[0],
+                      image.message);
+               }
+            }
+
+            else
+            {
+               fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
+                  (unsigned long)PNG_IMAGE_SIZE(image));
+
+               /* png_image_free must be called if we abort the Simplified API
+                * read because of a problem detected in this code.  If problems
+                * are detected in the Simplified API it cleans up itself.
+                */
+               png_image_free(&image);
+            }
+         }
+
+         else
+         {
+            /* Failed to read the first argument: */
+            fprintf(stderr, "simpleover: %s: %s\n", (*argv)[0], image.message);
+         }
+
+         return 0; /* failure */
+      }
+   }
+
+   /* All the sprite operations have completed successfully. Save the RGBA
+    * buffer as a PNG using the simplified write API.
+    */
+   sprite->file = tmpfile();
+
+   if (sprite->file != NULL)
+   {
+      png_image save;
+
+      memset(&save, 0, sizeof save);
+      save.version = PNG_IMAGE_VERSION;
+      save.opaque = NULL;
+      save.width = sprite->width;
+      save.height = sprite->height;
+      save.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
+      save.flags = PNG_IMAGE_FLAG_FAST;
+      save.colormap_entries = 0;
+
+      if (png_image_write_to_stdio(&save, sprite->file, 1/*convert_to_8_bit*/,
+          sprite->buffer, 0/*row_stride*/, NULL/*colormap*/))
+      {
+         /* Success; the buffer is no longer needed: */
+         free(sprite->buffer);
+         sprite->buffer = NULL;
+         return 1; /* ok */
+      }
+
+      else
+         fprintf(stderr, "simpleover: write sprite %s: %s\n", sprite->name,
+            save.message);
+   }
+
+   else
+      fprintf(stderr, "simpleover: sprite %s: could not allocate tmpfile: %s\n",
+         sprite->name, strerror(errno));
+
+   return 0; /* fail */
+}
+
+static int
+add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
+   int *argc, const char ***argv)
+{
+   /* Given a --add argument naming this sprite, perform the operations listed
+    * in the following arguments.  The arguments are expected to have the form
+    * (x,y), which is just an offset at which to add the sprite to the
+    * output.
+    */
+   while (*argc > 0)
+   {
+      char tombstone;
+      int x, y;
+
+      if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
+         return 1; /* success */
+
+      if (sscanf((*argv)[0], "%d,%d%c", &x, &y, &tombstone) == 2)
+      {
+         /* Now add the new image into the sprite data, but only if it
+          * will fit.
+          */
+         if (x < 0 || y < 0 ||
+             (unsigned)/*SAFE*/x >= output->width ||
+             (unsigned)/*SAFE*/y >= output->height ||
+             sprite->width > output->width-x ||
+             sprite->height > output->height-y)
+         {
+            fprintf(stderr, "simpleover: sprite %s @ (%d,%d) outside image\n",
+               sprite->name, x, y);
+            /* Could just skip this, but for the moment it is an error */
+            return 0; /* error */
+         }
+
+         else
+         {
+            /* Since we know the sprite fits we can just read it into the
+             * output using the simplified API.
+             */
+            png_image in;
+
+            in.version = PNG_IMAGE_VERSION;
+            rewind(sprite->file);
+
+            if (png_image_begin_read_from_stdio(&in, sprite->file))
+            {
+               in.format = PNG_FORMAT_RGB; /* force compose */
+
+               if (png_image_finish_read(&in, NULL/*background*/,
+                  out_buf + (y*output->width + x)*3/*RGB*/,
+                  output->width*3/*row_stride*/,
+                  NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
+               {
+                  ++*argv, --*argc;
+                  continue;
+               }
+            }
+
+            /* The read failed: */
+            fprintf(stderr, "simpleover: add sprite %s: %s\n", sprite->name,
+                in.message);
+            return 0; /* error */
+         }
+      }
+
+      else
+      {
+         fprintf(stderr, "simpleover: --add='%s': invalid position %s\n",
+               sprite->name, (*argv)[0]);
+         return 0; /* error */
+      }
+   }
+
+   return 1; /* ok */
+}
+
+static int
+simpleover_process(png_imagep output, png_bytep out_buf, int argc,
+   const char **argv)
+{
+   int result = 1; /* success */
+#  define csprites 10/*limit*/
+#  define str(a) #a
+   int nsprites = 0;
+   struct sprite sprites[csprites];
+
+   while (argc > 0)
+   {
+      result = 0; /* fail */
+
+      if (strncmp(argv[0], "--sprite=", 9) == 0)
+      {
+         char tombstone;
+
+         if (nsprites < csprites)
+         {
+            int n;
+
+            sprites[nsprites].width = sprites[nsprites].height = 0;
+            sprites[nsprites].name[0] = 0;
+
+            n = sscanf(argv[0], "--sprite=%u,%u,%" str(sprite_name_chars) "s%c",
+                &sprites[nsprites].width, &sprites[nsprites].height,
+                sprites[nsprites].name, &tombstone);
+
+            if ((n == 2 || n == 3) &&
+                sprites[nsprites].width > 0 && sprites[nsprites].height > 0)
+            {
+               size_t buf_size, tmp;
+
+               /* Default a name if not given. */
+               if (sprites[nsprites].name[0] == 0)
+                  sprintf(sprites[nsprites].name, "sprite-%d", nsprites+1);
+
+               /* Allocate a buffer for the sprite and calculate the buffer
+                * size:
+                */
+               buf_size = sizeof (png_uint_16 [4]);
+               buf_size *= sprites[nsprites].width;
+               buf_size *= sprites[nsprites].height;
+
+               /* This can overflow a (size_t); check for this: */
+               tmp = buf_size;
+               tmp /= sprites[nsprites].width;
+               tmp /= sprites[nsprites].height;
+
+               if (tmp == sizeof (png_uint_16 [4]))
+               {
+                  sprites[nsprites].buffer = malloc(buf_size);
+                  /* This buffer must be initialized to transparent: */
+                  memset(sprites[nsprites].buffer, 0, buf_size);
+
+                  if (sprites[nsprites].buffer != NULL)
+                  {
+                     sprites[nsprites].file = NULL;
+                     ++argv, --argc;
+
+                     if (create_sprite(sprites+nsprites++, &argc, &argv))
+                     {
+                        result = 1; /* still ok */
+                        continue;
+                     }
+
+                     break; /* error */
+                  }
+               }
+
+               /* Overflow, or OOM */
+               fprintf(stderr, "simpleover: %s: sprite too large\n", argv[0]);
+               break;
+            }
+
+            else
+            {
+               fprintf(stderr, "simpleover: %s: invalid sprite (%u,%u)\n",
+                  argv[0], sprites[nsprites].width, sprites[nsprites].height);
+               break;
+            }
+         }
+
+         else
+         {
+            fprintf(stderr, "simpleover: %s: too many sprites\n", argv[0]);
+            break;
+         }
+      }
+
+      else if (strncmp(argv[0], "--add=", 6) == 0)
+      {
+         const char *name = argv[0]+6;
+         int isprite = nsprites;
+
+         ++argv, --argc;
+
+         while (--isprite >= 0)
+         {
+            if (strcmp(sprites[isprite].name, name) == 0)
+            {
+               if (!add_sprite(output, out_buf, sprites+isprite, &argc, &argv))
+                  goto out; /* error in add_sprite */
+
+               break;
+            }
+         }
+
+         if (isprite < 0) /* sprite not found */
+         {
+            fprintf(stderr, "simpleover: --add='%s': sprite not found\n", name);
+            break;
+         }
+      }
+
+      else
+      {
+         fprintf(stderr, "simpleover: %s: unrecognized operation\n", argv[0]);
+         break;
+      }
+
+      result = 1; /* ok  */
+   }
+
+   /* Clean up the cache of sprites: */
+out:
+   while (--nsprites >= 0)
+   {
+      if (sprites[nsprites].buffer != NULL)
+         free(sprites[nsprites].buffer);
+
+      if (sprites[nsprites].file != NULL)
+         (void)fclose(sprites[nsprites].file);
+   }
+
+   return result;
+}
+
+int main(int argc, const char **argv)
+{
+   int result = 1; /* default to fail */
+
+   if (argc >= 2)
+   {
+      int argi = 2;
+      const char *output = NULL;
+      png_image image;
+
+      if (argc > 2 && argv[2][0] != '-'/*an operation*/)
+      {
+         output = argv[2];
+         argi = 3;
+      }
+
+      image.version = PNG_IMAGE_VERSION;
+      image.opaque = NULL;
+
+      if (png_image_begin_read_from_file(&image, argv[1]))
+      {
+         png_bytep buffer;
+
+         image.format = PNG_FORMAT_RGB; /* 24-bit RGB */
+
+         buffer = malloc(PNG_IMAGE_SIZE(image));
+
+         if (buffer != NULL)
+         {
+            png_color background = {0, 0xff, 0}; /* fully saturated green */
+
+            if (png_image_finish_read(&image, &background, buffer,
+               0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */))
+            {
+               /* At this point png_image_finish_read has cleaned up the
+                * allocated data in png_image, and only the buffer needs to be
+                * freed.
+                *
+                * Perform the remaining operations:
+                */
+               if (simpleover_process(&image, buffer, argc-argi, argv+argi))
+               {
+                  /* Write the output: */
+                  if ((output != NULL &&
+                       png_image_write_to_file(&image, output,
+                        0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
+                        NULL/*colormap*/)) ||
+                      (output == NULL &&
+                       png_image_write_to_stdio(&image, stdout,
+                        0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
+                        NULL/*colormap*/)))
+                     result = 0;
+
+                  else
+                     fprintf(stderr, "simpleover: write %s: %s\n",
+                        output == NULL ? "stdout" : output, image.message);
+               }
+
+               /* else simpleover_process writes an error message */
+            }
+
+            else
+               fprintf(stderr, "simpleover: read %s: %s\n", argv[1],
+                   image.message);
+
+            free(buffer);
+         }
+
+         else
+         {
+            fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
+               (unsigned long)PNG_IMAGE_SIZE(image));
+
+            /* This is the only place where a 'free' is required; libpng does
+             * the cleanup on error and success, but in this case we couldn't
+             * complete the read because of running out of memory.
+             */
+            png_image_free(&image);
+         }
+      }
+
+      else
+      {
+         /* Failed to read the first argument: */
+         fprintf(stderr, "simpleover: %s: %s\n", argv[1], image.message);
+      }
+   }
+
+   else
+   {
+      /* Usage message */
+      fprintf(stderr,
+         "simpleover: usage: simpleover background.png [output.png]\n"
+         "  Output 'background.png' as a 24-bit RGB PNG file in 'output.png'\n"
+         "   or, if not given, stdout.  'background.png' will be composited\n"
+         "   on fully saturated green.\n"
+         "\n"
+         "  Optionally, before output, process additional PNG files:\n"
+         "\n"
+         "   --sprite=width,height,name {[--at=x,y] {sprite.png}}\n"
+         "    Produce a transparent sprite of size (width,height) and with\n"
+         "     name 'name'.\n"
+         "    For each sprite.png composite it using a Porter-Duff 'Over'\n"
+         "     operation at offset (x,y) in the sprite (defaulting to (0,0)).\n"
+         "     Input PNGs will be truncated to the area of the sprite.\n"
+         "\n"
+         "   --add='name' {x,y}\n"
+         "    Optionally, before output, composite a sprite, 'name', which\n"
+         "     must have been previously produced using --sprite, at each\n"
+         "     offset (x,y) in the output image.  Each sprite must fit\n"
+         "     completely within the output image.\n"
+         "\n"
+         "  PNG files are processed in the order they occur on the command\n"
+         "  line and thus the first PNG processed appears as the bottommost\n"
+         "  in the output image.\n");
+   }
+
+   return result;
+}
+#endif /* SIMPLIFIED_READ */