summaryrefslogtreecommitdiff
path: root/libpng/contrib
diff options
context:
space:
mode:
authorChris Liddell <chris.liddell@artifex.com>2016-11-07 10:42:05 +0000
committerChris Liddell <chris.liddell@artifex.com>2016-11-22 09:49:30 +0000
commit64ad2a92195fd05e9ba34995ae994eb250fc9c7c (patch)
treeb555966016539e3d21c73d245b97c226ff2d7787 /libpng/contrib
parent1b1e7f3f4abf7a97101ff7f4e2389ca2edd9af0a (diff)
downloadghostpdl-64ad2a92195fd05e9ba34995ae994eb250fc9c7c.tar.gz
Update libpng to 1.6.26
Diffstat (limited to 'libpng/contrib')
-rw-r--r--libpng/contrib/README.txt3
-rw-r--r--libpng/contrib/arm-neon/README2
-rw-r--r--libpng/contrib/arm-neon/linux-auxv.c2
-rw-r--r--libpng/contrib/arm-neon/linux.c2
-rw-r--r--libpng/contrib/conftest/pngcp.dfa57
-rw-r--r--libpng/contrib/examples/README.txt2
-rw-r--r--libpng/contrib/examples/iccfrompng.c5
-rw-r--r--libpng/contrib/examples/pngpixel.c5
-rw-r--r--libpng/contrib/examples/pngtopng.c3
-rw-r--r--libpng/contrib/examples/simpleover.c648
-rw-r--r--libpng/contrib/gregbook/README2
-rw-r--r--libpng/contrib/gregbook/readpng2.c57
-rw-r--r--libpng/contrib/gregbook/rpng-win.c2
-rw-r--r--libpng/contrib/gregbook/rpng2-win.c4
-rw-r--r--libpng/contrib/gregbook/rpng2-x.c11
-rw-r--r--libpng/contrib/intel/INSTALL158
-rw-r--r--libpng/contrib/intel/filter_sse2_intrinsics.c379
-rw-r--r--libpng/contrib/intel/intel_init.c54
-rw-r--r--libpng/contrib/intel/intel_sse.patch190
-rw-r--r--libpng/contrib/libtests/fakepng.c10
-rw-r--r--libpng/contrib/libtests/makepng.c539
-rw-r--r--libpng/contrib/libtests/pngimage.c114
-rw-r--r--libpng/contrib/libtests/pngstest-errors.h165
-rw-r--r--libpng/contrib/libtests/pngstest.c345
-rw-r--r--libpng/contrib/libtests/pngunknown.c79
-rw-r--r--libpng/contrib/libtests/pngvalid.c2293
-rw-r--r--libpng/contrib/libtests/readpng.c13
-rw-r--r--libpng/contrib/libtests/tarith.c28
-rw-r--r--libpng/contrib/libtests/timepng.c467
-rw-r--r--libpng/contrib/mips-msa/README83
-rw-r--r--libpng/contrib/mips-msa/linux.c64
-rw-r--r--libpng/contrib/pngminus/README2
-rw-r--r--libpng/contrib/pngminus/png2pnm.c4
-rw-r--r--libpng/contrib/pngminus/pnm2png.c31
-rw-r--r--libpng/contrib/pngsuite/README6
-rw-r--r--libpng/contrib/tools/README.txt3
-rwxr-xr-xlibpng/contrib/tools/chkfmt7
-rw-r--r--libpng/contrib/tools/genpng.c867
-rw-r--r--libpng/contrib/tools/png-fix-itxt.c69
-rw-r--r--libpng/contrib/tools/pngcp.c2453
-rw-r--r--libpng/contrib/tools/pngfix.c81
-rwxr-xr-xlibpng/contrib/tools/reindent25
-rw-r--r--libpng/contrib/visupng/PngFile.c4
43 files changed, 8203 insertions, 1135 deletions
diff --git a/libpng/contrib/README.txt b/libpng/contrib/README.txt
index bcd433d35..97963c6d5 100644
--- a/libpng/contrib/README.txt
+++ b/libpng/contrib/README.txt
@@ -1,4 +1,5 @@
This "contrib" directory contains contributions which are not necessarily under
the libpng license, although all are open source. They are not part of
-libpng proper and are not used for building the library.
+libpng proper and are not used for building the library, although some are used
+for testing the library via "make check".
diff --git a/libpng/contrib/arm-neon/README b/libpng/contrib/arm-neon/README
index 535c8d3f7..b4248cf28 100644
--- a/libpng/contrib/arm-neon/README
+++ b/libpng/contrib/arm-neon/README
@@ -1,7 +1,7 @@
OPERATING SYSTEM SPECIFIC ARM NEON DETECTION
--------------------------------------------
-Detection of the ability to exexcute ARM NEON on an ARM processor requires
+Detection of the ability to execute ARM NEON on an ARM processor requires
operating system support. (The information is not available in user mode.)
HOW TO USE THIS
diff --git a/libpng/contrib/arm-neon/linux-auxv.c b/libpng/contrib/arm-neon/linux-auxv.c
index 696e297ef..4d26bd3b3 100644
--- a/libpng/contrib/arm-neon/linux-auxv.c
+++ b/libpng/contrib/arm-neon/linux-auxv.c
@@ -7,7 +7,7 @@
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
- *
+ *
* SEE contrib/arm-neon/README before reporting bugs
*
* STATUS: COMPILED, TESTED
diff --git a/libpng/contrib/arm-neon/linux.c b/libpng/contrib/arm-neon/linux.c
index abae9e33b..94f9bb1e0 100644
--- a/libpng/contrib/arm-neon/linux.c
+++ b/libpng/contrib/arm-neon/linux.c
@@ -72,7 +72,7 @@ png_have_neon(png_structp png_ptr)
state = Colon;
break;
}
-
+
/* did not match 'feature' */
state = SkipLine;
/* FALL THROUGH */
diff --git a/libpng/contrib/conftest/pngcp.dfa b/libpng/contrib/conftest/pngcp.dfa
new file mode 100644
index 000000000..15a856e2f
--- /dev/null
+++ b/libpng/contrib/conftest/pngcp.dfa
@@ -0,0 +1,57 @@
+# pngcp.dfa
+# Build time configuration of libpng
+#
+# Author: John Bowler
+# Copyright: (c) John Bowler, 2016
+# Usage rights:
+# 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.
+#
+# Build libpng with support for pngcp. This means just png_read_png,
+# png_write_png and small number of configuration settings.
+#
+everything = off
+
+# This option is specific to this configuration; it adds a #define to the
+# generated pnglibconf.h which turns on the (not portable) timing option for
+# pngcp. Note that any option is automatically preceded by PNG_; there is no
+# way round this and this is deliberate.
+option PNGCP_TIMING
+
+# Because of the everything off above the option must also be turned on. This
+# may not be done in one step because it is safer and avoids mis-spelled options
+# in user .dfa files to error out if an unrecognized option is turned on.
+option PNGCP_TIMING on
+
+# Options to turn on png_read_png and png_write_png:
+option INFO_IMAGE on
+option SEQUENTIAL_READ on
+option EASY_ACCESS on
+option WRITE on
+option WRITE_16BIT on
+option WRITE_FILTER on
+
+# pngcp needs this to preserve unknown chunks, switching all these on means that
+# pngcp can work without explicit known chunk reading suppport
+option UNKNOWN_CHUNKS on
+option SET_UNKNOWN_CHUNKS on
+option HANDLE_AS_UNKNOWN on
+option SAVE_UNKNOWN_CHUNKS on
+option WRITE_UNKNOWN_CHUNKS on
+
+# pngcp needs this to handle palette files with invalid indices:
+option CHECK_FOR_INVALID_INDEX on
+option GET_PALETTE_MAX on
+
+# Pre-libpng 1.7 pngcp has to stash text chunks manually, post 1.7 without this
+# text chunks should be handled as unknown ok.
+option TEXT on
+
+# this is used to turn off limits:
+option USER_LIMITS on
+option SET_USER_LIMITS on
+
+# these are are just required for specific customizations
+option WRITE_CUSTOMIZE_ZTXT_COMPRESSION on
+option WRITE_CUSTOMIZE_COMPRESSION on
diff --git a/libpng/contrib/examples/README.txt b/libpng/contrib/examples/README.txt
index 0525c9d36..48dab4f0f 100644
--- a/libpng/contrib/examples/README.txt
+++ b/libpng/contrib/examples/README.txt
@@ -21,4 +21,4 @@ ORIGINAL AUTHORS
of the people below claim any rights with regard to the contents of this
directory.
- John Bowler <jbowler@acm.org>
+ John Bowler <jbowler at acm.org>
diff --git a/libpng/contrib/examples/iccfrompng.c b/libpng/contrib/examples/iccfrompng.c
index 386e522a3..603037e70 100644
--- a/libpng/contrib/examples/iccfrompng.c
+++ b/libpng/contrib/examples/iccfrompng.c
@@ -26,6 +26,10 @@
#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";
@@ -178,3 +182,4 @@ main(int argc, char **argv)
/* Exit code is true if any extract succeeds */
return extracted == 0;
}
+#endif /* READ && STDIO && iCCP */
diff --git a/libpng/contrib/examples/pngpixel.c b/libpng/contrib/examples/pngpixel.c
index e0d43e3f0..f762379ed 100644
--- a/libpng/contrib/examples/pngpixel.c
+++ b/libpng/contrib/examples/pngpixel.c
@@ -27,6 +27,8 @@
*/
#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,
@@ -85,7 +87,7 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
*/
case PNG_COLOR_TYPE_PALETTE:
{
- PNG_CONST unsigned int index = component(row, x, 0, bit_depth, 1);
+ PNG_CONST int index = component(row, x, 0, bit_depth, 1);
png_colorp palette = NULL;
int num_palette = 0;
@@ -366,3 +368,4 @@ int main(int argc, const char **argv)
return result;
}
+#endif /* READ && SEQUENTIAL_READ */
diff --git a/libpng/contrib/examples/pngtopng.c b/libpng/contrib/examples/pngtopng.c
index b1b3be677..4acf6b3ad 100644
--- a/libpng/contrib/examples/pngtopng.c
+++ b/libpng/contrib/examples/pngtopng.c
@@ -20,6 +20,8 @@
* 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)
{
@@ -90,3 +92,4 @@ int main(int argc, const char **argv)
return result;
}
+#endif /* READ && WRITE */
diff --git a/libpng/contrib/examples/simpleover.c b/libpng/contrib/examples/simpleover.c
new file mode 100644
index 000000000..59dd31368
--- /dev/null
+++ b/libpng/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 */
diff --git a/libpng/contrib/gregbook/README b/libpng/contrib/gregbook/README
index 7b1f6a3ea..fd30f0581 100644
--- a/libpng/contrib/gregbook/README
+++ b/libpng/contrib/gregbook/README
@@ -15,7 +15,7 @@ of PBMPLUS/NetPBM) and converts them to PNG.
The source code for all three demo programs currently compiles under
Unix, OpenVMS, and 32-bit Windows. (Special thanks to Martin Zinser,
-zinser@decus.de, for making the necessary changes for OpenVMS and for
+zinser at decus.de, for making the necessary changes for OpenVMS and for
providing an appropriate build script.) Build instructions can be found
below.
diff --git a/libpng/contrib/gregbook/readpng2.c b/libpng/contrib/gregbook/readpng2.c
index 4cf2600a4..4d5e38fe2 100644
--- a/libpng/contrib/gregbook/readpng2.c
+++ b/libpng/contrib/gregbook/readpng2.c
@@ -4,7 +4,7 @@
---------------------------------------------------------------------------
- Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+ Copyright (c) 1998-2015 Greg Roelofs. All rights reserved.
This software is provided "as is," without warranty of any kind,
express or implied. In no event shall the author or contributors
@@ -51,6 +51,11 @@
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ 2015-11-12 - Check return value of png_get_bKGD() (Glenn R-P)
+
---------------------------------------------------------------------------*/
@@ -261,36 +266,38 @@ static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr)
/* since we know we've read all of the PNG file's "header" (i.e., up
* to IDAT), we can check for a background color here */
- if (mainprog_ptr->need_bgcolor &&
- png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
+ if (mainprog_ptr->need_bgcolor)
{
png_color_16p pBackground;
/* it is not obvious from the libpng documentation, but this function
* takes a pointer to a pointer, and it always returns valid red,
* green and blue values, regardless of color_type: */
- png_get_bKGD(png_ptr, info_ptr, &pBackground);
-
- /* however, it always returns the raw bKGD data, regardless of any
- * bit-depth transformations, so check depth and adjust if necessary */
- if (bit_depth == 16) {
- mainprog_ptr->bg_red = pBackground->red >> 8;
- mainprog_ptr->bg_green = pBackground->green >> 8;
- mainprog_ptr->bg_blue = pBackground->blue >> 8;
- } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
- if (bit_depth == 1)
- mainprog_ptr->bg_red = mainprog_ptr->bg_green =
- mainprog_ptr->bg_blue = pBackground->gray? 255 : 0;
- else if (bit_depth == 2)
- mainprog_ptr->bg_red = mainprog_ptr->bg_green =
- mainprog_ptr->bg_blue = (255/3) * pBackground->gray;
- else /* bit_depth == 4 */
- mainprog_ptr->bg_red = mainprog_ptr->bg_green =
- mainprog_ptr->bg_blue = (255/15) * pBackground->gray;
- } else {
- mainprog_ptr->bg_red = (uch)pBackground->red;
- mainprog_ptr->bg_green = (uch)pBackground->green;
- mainprog_ptr->bg_blue = (uch)pBackground->blue;
+ if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
+ {
+
+ /* however, it always returns the raw bKGD data, regardless of any
+ * bit-depth transformations, so check depth and adjust if necessary
+ */
+ if (bit_depth == 16) {
+ mainprog_ptr->bg_red = pBackground->red >> 8;
+ mainprog_ptr->bg_green = pBackground->green >> 8;
+ mainprog_ptr->bg_blue = pBackground->blue >> 8;
+ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
+ if (bit_depth == 1)
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = pBackground->gray? 255 : 0;
+ else if (bit_depth == 2)
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = (255/3) * pBackground->gray;
+ else /* bit_depth == 4 */
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = (255/15) * pBackground->gray;
+ } else {
+ mainprog_ptr->bg_red = (uch)pBackground->red;
+ mainprog_ptr->bg_green = (uch)pBackground->green;
+ mainprog_ptr->bg_blue = (uch)pBackground->blue;
+ }
}
}
diff --git a/libpng/contrib/gregbook/rpng-win.c b/libpng/contrib/gregbook/rpng-win.c
index f53ddc8ec..cd5543937 100644
--- a/libpng/contrib/gregbook/rpng-win.c
+++ b/libpng/contrib/gregbook/rpng-win.c
@@ -182,7 +182,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
#ifndef __CYGWIN__
/* First reenable console output, which normally goes to the bit bucket
* for windowed apps. Closing the console window will terminate the
- * app. Thanks to David.Geldreich@realviz.com for supplying the magical
+ * app. Thanks to David.Geldreich at realviz.com for supplying the magical
* incantation. */
AllocConsole();
diff --git a/libpng/contrib/gregbook/rpng2-win.c b/libpng/contrib/gregbook/rpng2-win.c
index eda176eee..c924c1c6c 100644
--- a/libpng/contrib/gregbook/rpng2-win.c
+++ b/libpng/contrib/gregbook/rpng2-win.c
@@ -33,7 +33,7 @@
- 2.02: fixed improper display of usage screen on PNG error(s); fixed
unexpected-EOF and file-read-error cases
- 2.03: removed runtime MMX-enabling/disabling and obsolete -mmx* options
- - 2.04:
+ - 2.04:
(GR-P)
---------------------------------------------------------------------------
@@ -301,7 +301,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
#ifndef __CYGWIN__
/* Next reenable console output, which normally goes to the bit bucket
* for windowed apps. Closing the console window will terminate the
- * app. Thanks to David.Geldreich@realviz.com for supplying the magical
+ * app. Thanks to David.Geldreich at realviz.com for supplying the magical
* incantation. */
AllocConsole();
diff --git a/libpng/contrib/gregbook/rpng2-x.c b/libpng/contrib/gregbook/rpng2-x.c
index cf371014c..0c8ddeba2 100644
--- a/libpng/contrib/gregbook/rpng2-x.c
+++ b/libpng/contrib/gregbook/rpng2-x.c
@@ -43,12 +43,10 @@
- 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options
- 2.04: Added "void(foo);" statements to quiet pedantic compiler warnings
about unused variables (GR-P)
-
- TO DO:
- use nanosleep() instead of usleep(), which is obsolete/deprecated.
+ - 2.05: Use nanosleep() instead of usleep(), which is deprecated (GR-P).
---------------------------------------------------------------------------
- Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+ Copyright (c) 1998-2010, 2014-2015 Greg Roelofs. All rights reserved.
This software is provided "as is," without warranty of any kind,
express or implied. In no event shall the author or contributors
@@ -119,6 +117,7 @@
# undef usleep
# define usleep(usec) { \
struct timespec ts; \
+ ts.tv_sec = 0; \
ts.tv_nsec = (usec) * 1000; \
nanosleep(&ts, NULL); }
# endif
@@ -497,12 +496,12 @@ int main(int argc, char **argv)
"\t\t transparent images; overrides -bgcolor\n",
num_bgpat-1);
#ifdef FEATURE_LOOP
- fprintf(stderr,
+ fprintf(stderr,
" -loop\tloops through background images after initial display\n"
"\t\t is complete (depends on -bgpat)\n"
" sec \tseconds to display each background image (default = 2)\n");
#endif
- fprintf(stderr,
+ fprintf(stderr,
" dur \tduration in microseconds to wait after displaying each\n"
"\t\t row (for demo purposes)\n"
" -timing\tenables delay for every block read, to simulate modem\n"
diff --git a/libpng/contrib/intel/INSTALL b/libpng/contrib/intel/INSTALL
new file mode 100644
index 000000000..cd5cdd94e
--- /dev/null
+++ b/libpng/contrib/intel/INSTALL
@@ -0,0 +1,158 @@
+Enabling SSE support
+
+Copyright (c) 2016 Google, Inc.
+Written by Mike Klein, Matt Sarett
+
+This INSTALL file written by Glenn Randers-Pehrson, 2016.
+
+If you have moved intel_init.c and filter_sse2_intrinsics.c to a different
+directory, be sure to update the '#include "../../pngpriv.h"' line in both
+files if necessary to point to the correct relative location of pngpriv.h
+with respect to the new location of those files.
+
+To enable SSE support in libpng, follow the instructions in I, II, or III,
+below:
+
+I. Using patched "configure" scripts:
+
+First, apply intel_sse.patch in your build directory.
+
+ patch -i contrib/intel/intel_sse.patch -p1
+
+Then, if you are not building in a new GIT clone, e.g., in a tar
+distribution, remove any existing pre-built configure scripts:
+
+ ./configure --enable-maintainer-mode
+ make maintainer-clean
+ ./autogen.sh --maintainer --clean
+
+Finally, configure libpng with -DPNG_INTEL_SSE in CPPFLAGS:
+
+ ./autogen.sh --maintainer
+ CPPFLAGS="-DPNG_INTEL_SSE" ./configure [options]
+ make CPPFLAGS="-DPNG_INTEL_SSE" [options]
+ make
+
+II. Using a custom makefile:
+
+If you are using a custom makefile makefile, you will have to update it
+manually to include contrib/intel/*.o in the dependencies, and to define
+PNG_INTEL_SSE.
+
+III. Using manually updated "configure" scripts:
+
+If you prefer, manually edit pngpriv.h, configure.ac, and Makefile.am,
+following the instructions below, then follow the instructions in
+section II of INSTALL in the main libpng directory, then configure libpng
+with -DPNG_INTEL_SSE in CPPFLAGS.
+
+1. Add the following code to configure.ac under HOST SPECIFIC OPTIONS
+directly beneath the section for ARM:
+
+-----------------cut----------------
+# INTEL
+# =====
+#
+# INTEL SSE (SIMD) support.
+
+AC_ARG_ENABLE([intel-sse],
+ AS_HELP_STRING([[[--enable-intel-sse]]],
+ [Enable Intel SSE optimizations: =no/off, yes/on:]
+ [no/off: disable the optimizations;]
+ [yes/on: enable the optimizations.]
+ [If not specified: determined by the compiler.]),
+ [case "$enableval" in
+ no|off)
+ # disable the default enabling:
+ AC_DEFINE([PNG_INTEL_SSE_OPT], [0],
+ [Disable Intel SSE optimizations])
+ # Prevent inclusion of the assembler files below:
+ enable_intel_sse=no;;
+ yes|on)
+ AC_DEFINE([PNG_INTEL_SSE_OPT], [1],
+ [Enable Intel SSE optimizations]);;
+ *)
+ AC_MSG_ERROR([--enable-intel-sse=${enable_intel_sse}: invalid value])
+ esac])
+
+# Add Intel specific files to all builds where the host_cpu is Intel ('x86*')
+# or where Intel optimizations were explicitly requested (this allows a
+# fallback if a future host CPU does not match 'x86*')
+AM_CONDITIONAL([PNG_INTEL_SSE],
+ [test "$enable_intel_sse" != 'no' &&
+ case "$host_cpu" in
+ i?86|x86_64) :;;
+ *) test "$enable_intel_sse" != '';;
+ esac])
+-----------------cut----------------
+
+2. Add the following code to Makefile.am under HOST SPECIFIC OPTIONS
+directly beneath the "if PNG_ARM_NEON ... endif" statement:
+
+-----------------cut----------------
+if PNG_INTEL_SSE
+libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES += contrib/intel/intel_init.c\
+ contrib/intel/filter_sse2_intrinsics.c
+endif
+-----------------cut----------------
+
+3. Add the following lines to pngpriv.h, following the PNG_ARM_NEON_OPT
+code:
+
+-----------------cut----------------
+#ifndef PNG_INTEL_SSE_OPT
+# ifdef PNG_INTEL_SSE
+ /* Only check for SSE if the build configuration has been modified to
+ * enable SSE optimizations. This means that these optimizations will
+ * be off by default. See contrib/intel for more details.
+ */
+# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
+ defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
+ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+# define PNG_INTEL_SSE_OPT 1
+# endif
+# endif
+#endif
+
+#if PNG_INTEL_SSE_OPT > 0
+# ifndef PNG_INTEL_SSE_IMPLEMENTATION
+# if defined(__SSE4_1__) || defined(__AVX__)
+ /* We are not actually using AVX, but checking for AVX is the best
+ way we can detect SSE4.1 and SSSE3 on MSVC.
+ */
+# define PNG_INTEL_SSE_IMPLEMENTATION 3
+# elif defined(__SSSE3__)
+# define PNG_INTEL_SSE_IMPLEMENTATION 2
+# elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
+ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+# define PNG_INTEL_SSE_IMPLEMENTATION 1
+# else
+# define PNG_INTEL_SSE_IMPLEMENTATION 0
+# endif
+# endif
+
+# if PNG_INTEL_SSE_IMPLEMENTATION > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2
+# endif
+#endif
+
+-----------------cut----------------
+
+4. Add the following lines to pngpriv.h, following the prototype for
+png_read_filter_row_paeth4_neon:
+
+-----------------cut----------------
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+
+-----------------cut----------------
diff --git a/libpng/contrib/intel/filter_sse2_intrinsics.c b/libpng/contrib/intel/filter_sse2_intrinsics.c
new file mode 100644
index 000000000..b02840c55
--- /dev/null
+++ b/libpng/contrib/intel/filter_sse2_intrinsics.c
@@ -0,0 +1,379 @@
+
+/* filter_sse2_intrinsics.c - SSE2 optimized filter functions
+ *
+ * Copyright (c) 2016 Google, Inc.
+ * Written by Mike Klein and Matt Sarett
+ * Derived from arm/filter_neon_intrinsics.c, which was
+ * Copyright (c) 2014,2016 Glenn Randers-Pehrson
+ *
+ * Last changed in libpng 1.6.24 [August 4, 2016]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+
+#include "../../pngpriv.h"
+
+#ifdef PNG_READ_SUPPORTED
+
+#if PNG_INTEL_SSE_IMPLEMENTATION > 0
+
+#include <immintrin.h>
+
+/* Functions in this file look at most 3 pixels (a,b,c) to predict the 4th (d).
+ * They're positioned like this:
+ * prev: c b
+ * row: a d
+ * The Sub filter predicts d=a, Avg d=(a+b)/2, and Paeth predicts d to be
+ * whichever of a, b, or c is closest to p=a+b-c.
+ */
+
+static __m128i load4(const void* p) {
+ return _mm_cvtsi32_si128(*(const int*)p);
+}
+
+static void store4(void* p, __m128i v) {
+ *(int*)p = _mm_cvtsi128_si32(v);
+}
+
+static __m128i load3(const void* p) {
+ /* We'll load 2 bytes, then 1 byte,
+ * then mask them together, and finally load into SSE.
+ */
+ const png_uint_16* p01 = p;
+ const png_byte* p2 = (const png_byte*)(p01+1);
+
+ png_uint_32 v012 = (png_uint_32)(*p01)
+ | (png_uint_32)(*p2) << 16;
+ return load4(&v012);
+}
+
+static void store3(void* p, __m128i v) {
+ /* We'll pull from SSE as a 32-bit int, then write
+ * its bottom two bytes, then its third byte.
+ */
+ png_uint_32 v012;
+ store4(&v012, v);
+
+ png_uint_16* p01 = p;
+ png_byte* p2 = (png_byte*)(p01+1);
+ *p01 = v012;
+ *p2 = v012 >> 16;
+}
+
+void png_read_filter_row_sub3_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* The Sub filter predicts each pixel as the previous pixel, a.
+ * There is no pixel to the left of the first pixel. It's encoded directly.
+ * That works with our main loop if we just say that left pixel was zero.
+ */
+ png_debug(1, "in png_read_filter_row_sub3_sse2");
+ __m128i a, d = _mm_setzero_si128();
+
+ int rb = row_info->rowbytes;
+ while (rb >= 4) {
+ a = d; d = load4(row);
+ d = _mm_add_epi8(d, a);
+ store3(row, d);
+
+ row += 3;
+ rb -= 3;
+ }
+ if (rb > 0) {
+ a = d; d = load3(row);
+ d = _mm_add_epi8(d, a);
+ store3(row, d);
+
+ row += 3;
+ rb -= 3;
+ }
+}
+
+void png_read_filter_row_sub4_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* The Sub filter predicts each pixel as the previous pixel, a.
+ * There is no pixel to the left of the first pixel. It's encoded directly.
+ * That works with our main loop if we just say that left pixel was zero.
+ */
+ png_debug(1, "in png_read_filter_row_sub4_sse2");
+ __m128i a, d = _mm_setzero_si128();
+
+ int rb = row_info->rowbytes;
+ while (rb > 0) {
+ a = d; d = load4(row);
+ d = _mm_add_epi8(d, a);
+ store4(row, d);
+
+ row += 4;
+ rb -= 4;
+ }
+}
+
+void png_read_filter_row_avg3_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* The Avg filter predicts each pixel as the (truncated) average of a and b.
+ * There's no pixel to the left of the first pixel. Luckily, it's
+ * predicted to be half of the pixel above it. So again, this works
+ * perfectly with our loop if we make sure a starts at zero.
+ */
+ png_debug(1, "in png_read_filter_row_avg3_sse2");
+ const __m128i zero = _mm_setzero_si128();
+ __m128i b;
+ __m128i a, d = zero;
+
+ int rb = row_info->rowbytes;
+ while (rb >= 4) {
+ b = load4(prev);
+ a = d; d = load4(row );
+
+ /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
+ __m128i avg = _mm_avg_epu8(a,b);
+ /* ...but we can fix it up by subtracting off 1 if it rounded up. */
+ avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b),
+ _mm_set1_epi8(1)));
+ d = _mm_add_epi8(d, avg);
+ store3(row, d);
+
+ prev += 3;
+ row += 3;
+ rb -= 3;
+ }
+ if (rb > 0) {
+ b = load3(prev);
+ a = d; d = load3(row );
+
+ /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
+ __m128i avg = _mm_avg_epu8(a,b);
+ /* ...but we can fix it up by subtracting off 1 if it rounded up. */
+ avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b),
+ _mm_set1_epi8(1)));
+
+ d = _mm_add_epi8(d, avg);
+ store3(row, d);
+
+ prev += 3;
+ row += 3;
+ rb -= 3;
+ }
+}
+
+void png_read_filter_row_avg4_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* The Avg filter predicts each pixel as the (truncated) average of a and b.
+ * There's no pixel to the left of the first pixel. Luckily, it's
+ * predicted to be half of the pixel above it. So again, this works
+ * perfectly with our loop if we make sure a starts at zero.
+ */
+ png_debug(1, "in png_read_filter_row_avg4_sse2");
+ const __m128i zero = _mm_setzero_si128();
+ __m128i b;
+ __m128i a, d = zero;
+
+ int rb = row_info->rowbytes;
+ while (rb > 0) {
+ b = load4(prev);
+ a = d; d = load4(row );
+
+ /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
+ __m128i avg = _mm_avg_epu8(a,b);
+ /* ...but we can fix it up by subtracting off 1 if it rounded up. */
+ avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b),
+ _mm_set1_epi8(1)));
+
+ d = _mm_add_epi8(d, avg);
+ store4(row, d);
+
+ prev += 4;
+ row += 4;
+ rb -= 4;
+ }
+}
+
+/* Returns |x| for 16-bit lanes. */
+static __m128i abs_i16(__m128i x) {
+#if PNG_INTEL_SSE_IMPLEMENTATION >= 2
+ return _mm_abs_epi16(x);
+#else
+ /* Read this all as, return x<0 ? -x : x.
+ * To negate two's complement, you flip all the bits then add 1.
+ */
+ __m128i is_negative = _mm_cmplt_epi16(x, _mm_setzero_si128());
+
+ /* Flip negative lanes. */
+ x = _mm_xor_si128(x, is_negative);
+
+ /* +1 to negative lanes, else +0. */
+ x = _mm_sub_epi16(x, is_negative);
+ return x;
+#endif
+}
+
+/* Bytewise c ? t : e. */
+static __m128i if_then_else(__m128i c, __m128i t, __m128i e) {
+#if PNG_INTEL_SSE_IMPLEMENTATION >= 3
+ return _mm_blendv_epi8(e,t,c);
+#else
+ return _mm_or_si128(_mm_and_si128(c, t), _mm_andnot_si128(c, e));
+#endif
+}
+
+void png_read_filter_row_paeth3_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* Paeth tries to predict pixel d using the pixel to the left of it, a,
+ * and two pixels from the previous row, b and c:
+ * prev: c b
+ * row: a d
+ * The Paeth function predicts d to be whichever of a, b, or c is nearest to
+ * p=a+b-c.
+ *
+ * The first pixel has no left context, and so uses an Up filter, p = b.
+ * This works naturally with our main loop's p = a+b-c if we force a and c
+ * to zero.
+ * Here we zero b and d, which become c and a respectively at the start of
+ * the loop.
+ */
+ png_debug(1, "in png_read_filter_row_paeth3_sse2");
+ const __m128i zero = _mm_setzero_si128();
+ __m128i c, b = zero,
+ a, d = zero;
+
+ int rb = row_info->rowbytes;
+ while (rb >= 4) {
+ /* It's easiest to do this math (particularly, deal with pc) with 16-bit
+ * intermediates.
+ */
+ c = b; b = _mm_unpacklo_epi8(load4(prev), zero);
+ a = d; d = _mm_unpacklo_epi8(load4(row ), zero);
+
+ /* (p-a) == (a+b-c - a) == (b-c) */
+ __m128i pa = _mm_sub_epi16(b,c);
+
+ /* (p-b) == (a+b-c - b) == (a-c) */
+ __m128i pb = _mm_sub_epi16(a,c);
+
+ /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
+ __m128i pc = _mm_add_epi16(pa,pb);
+
+ pa = abs_i16(pa); /* |p-a| */
+ pb = abs_i16(pb); /* |p-b| */
+ pc = abs_i16(pc); /* |p-c| */
+
+ __m128i smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
+
+ /* Paeth breaks ties favoring a over b over c. */
+ __m128i nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
+ if_then_else(_mm_cmpeq_epi16(smallest, pb), b,
+ c));
+
+ /* Note `_epi8`: we need addition to wrap modulo 255. */
+ d = _mm_add_epi8(d, nearest);
+ store3(row, _mm_packus_epi16(d,d));
+
+ prev += 3;
+ row += 3;
+ rb -= 3;
+ }
+ if (rb > 0) {
+ /* It's easiest to do this math (particularly, deal with pc) with 16-bit
+ * intermediates.
+ */
+ c = b; b = _mm_unpacklo_epi8(load3(prev), zero);
+ a = d; d = _mm_unpacklo_epi8(load3(row ), zero);
+
+ /* (p-a) == (a+b-c - a) == (b-c) */
+ __m128i pa = _mm_sub_epi16(b,c);
+
+ /* (p-b) == (a+b-c - b) == (a-c) */
+ __m128i pb = _mm_sub_epi16(a,c);
+
+ /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
+ __m128i pc = _mm_add_epi16(pa,pb);
+
+ pa = abs_i16(pa); /* |p-a| */
+ pb = abs_i16(pb); /* |p-b| */
+ pc = abs_i16(pc); /* |p-c| */
+
+ __m128i smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
+
+ /* Paeth breaks ties favoring a over b over c. */
+ __m128i nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
+ if_then_else(_mm_cmpeq_epi16(smallest, pb), b,
+ c));
+
+ /* Note `_epi8`: we need addition to wrap modulo 255. */
+ d = _mm_add_epi8(d, nearest);
+ store3(row, _mm_packus_epi16(d,d));
+
+ prev += 3;
+ row += 3;
+ rb -= 3;
+ }
+}
+
+void png_read_filter_row_paeth4_sse2(png_row_infop row_info, png_bytep row,
+ png_const_bytep prev)
+{
+ /* Paeth tries to predict pixel d using the pixel to the left of it, a,
+ * and two pixels from the previous row, b and c:
+ * prev: c b
+ * row: a d
+ * The Paeth function predicts d to be whichever of a, b, or c is nearest to
+ * p=a+b-c.
+ *
+ * The first pixel has no left context, and so uses an Up filter, p = b.
+ * This works naturally with our main loop's p = a+b-c if we force a and c
+ * to zero.
+ * Here we zero b and d, which become c and a respectively at the start of
+ * the loop.
+ */
+ png_debug(1, "in png_read_filter_row_paeth4_sse2");
+ const __m128i zero = _mm_setzero_si128();
+ __m128i c, b = zero,
+ a, d = zero;
+
+ int rb = row_info->rowbytes;
+ while (rb > 0) {
+ /* It's easiest to do this math (particularly, deal with pc) with 16-bit
+ * intermediates.
+ */
+ c = b; b = _mm_unpacklo_epi8(load4(prev), zero);
+ a = d; d = _mm_unpacklo_epi8(load4(row ), zero);
+
+ /* (p-a) == (a+b-c - a) == (b-c) */
+ __m128i pa = _mm_sub_epi16(b,c);
+
+ /* (p-b) == (a+b-c - b) == (a-c) */
+ __m128i pb = _mm_sub_epi16(a,c);
+
+ /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
+ __m128i pc = _mm_add_epi16(pa,pb);
+
+ pa = abs_i16(pa); /* |p-a| */
+ pb = abs_i16(pb); /* |p-b| */
+ pc = abs_i16(pc); /* |p-c| */
+
+ __m128i smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
+
+ /* Paeth breaks ties favoring a over b over c. */
+ __m128i nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
+ if_then_else(_mm_cmpeq_epi16(smallest, pb), b,
+ c));
+
+ /* Note `_epi8`: we need addition to wrap modulo 255. */
+ d = _mm_add_epi8(d, nearest);
+ store4(row, _mm_packus_epi16(d,d));
+
+ prev += 4;
+ row += 4;
+ rb -= 4;
+ }
+}
+
+#endif /* PNG_INTEL_SSE_IMPLEMENTATION > 0 */
+#endif /* READ */
diff --git a/libpng/contrib/intel/intel_init.c b/libpng/contrib/intel/intel_init.c
new file mode 100644
index 000000000..328e90e9a
--- /dev/null
+++ b/libpng/contrib/intel/intel_init.c
@@ -0,0 +1,54 @@
+
+/* intel_init.c - SSE2 optimized filter functions
+ *
+ * Copyright (c) 2016 Google, Inc.
+ * Written by Mike Klein and Matt Sarett
+ * Derived from arm/arm_init.c, which was
+ * Copyright (c) 2014,2016 Glenn Randers-Pehrson
+ *
+ * Last changed in libpng 1.6.22 [May 26, 2016]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+
+#include "../../pngpriv.h"
+
+#ifdef PNG_READ_SUPPORTED
+#if PNG_INTEL_SSE_IMPLEMENTATION > 0
+
+void
+png_init_filter_functions_sse2(png_structp pp, unsigned int bpp)
+{
+ /* The techniques used to implement each of these filters in SSE operate on
+ * one pixel at a time.
+ * So they generally speed up 3bpp images about 3x, 4bpp images about 4x.
+ * They can scale up to 6 and 8 bpp images and down to 2 bpp images,
+ * but they'd not likely have any benefit for 1bpp images.
+ * Most of these can be implemented using only MMX and 64-bit registers,
+ * but they end up a bit slower than using the equally-ubiquitous SSE2.
+ */
+ png_debug(1, "in png_init_filter_functions_sse2");
+ if (bpp == 3)
+ {
+ pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_sse2;
+ pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_sse2;
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth3_sse2;
+ }
+ else if (bpp == 4)
+ {
+ pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_sse2;
+ pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_sse2;
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth4_sse2;
+ }
+
+ /* No need optimize PNG_FILTER_VALUE_UP. The compiler should
+ * autovectorize.
+ */
+}
+
+#endif /* PNG_INTEL_SSE_IMPLEMENTATION > 0 */
+#endif /* PNG_READ_SUPPORTED */
diff --git a/libpng/contrib/intel/intel_sse.patch b/libpng/contrib/intel/intel_sse.patch
new file mode 100644
index 000000000..24d4883c7
--- /dev/null
+++ b/libpng/contrib/intel/intel_sse.patch
@@ -0,0 +1,190 @@
+diff --git a/configure.ac b/configure.ac
+--- a/configure.ac 2016-08-29 11:46:27.000000000 -0400
++++ b/configure.ac 2016-08-29 16:57:03.866355018 -0400
+@@ -386,16 +386,51 @@ AC_ARG_ENABLE([mips-msa],
+ # future host CPU does not match 'mips*')
+
+ AM_CONDITIONAL([PNG_MIPS_MSA],
+ [test "$enable_mips_msa" != 'no' &&
+ case "$host_cpu" in
+ mipsel*|mips64el*) :;;
+ esac])
+
++# INTEL
++# =====
++#
++# INTEL SSE (SIMD) support.
++
++AC_ARG_ENABLE([intel-sse],
++ AS_HELP_STRING([[[--enable-intel-sse]]],
++ [Enable Intel SSE optimizations: =no/off, yes/on:]
++ [no/off: disable the optimizations;]
++ [yes/on: enable the optimizations.]
++ [If not specified: determined by the compiler.]),
++ [case "$enableval" in
++ no|off)
++ # disable the default enabling:
++ AC_DEFINE([PNG_INTEL_SSE_OPT], [0],
++ [Disable Intel SSE optimizations])
++ # Prevent inclusion of the assembler files below:
++ enable_intel_sse=no;;
++ yes|on)
++ AC_DEFINE([PNG_INTEL_SSE_OPT], [1],
++ [Enable Intel SSE optimizations]);;
++ *)
++ AC_MSG_ERROR([--enable-intel-sse=${enable_intel_sse}: invalid value])
++ esac])
++
++# Add Intel specific files to all builds where the host_cpu is Intel ('x86*')
++# or where Intel optimizations were explicitly requested (this allows a
++# fallback if a future host CPU does not match 'x86*')
++AM_CONDITIONAL([PNG_INTEL_SSE],
++ [test "$enable_intel_sse" != 'no' &&
++ case "$host_cpu" in
++ i?86|x86_64) :;;
++ *) test "$enable_intel_sse" != '';;
++ esac])
++
+ AC_MSG_NOTICE([[Extra options for compiler: $PNG_COPTS]])
+
+ # Config files, substituting as above
+ AC_CONFIG_FILES([Makefile libpng.pc:libpng.pc.in])
+ AC_CONFIG_FILES([libpng-config:libpng-config.in],
+ [chmod +x libpng-config])
+
+ AC_OUTPUT
+diff --git a/Makefile.am b/Makefile.am
+--- a/Makefile.am 2016-08-29 11:46:27.000000000 -0400
++++ b/Makefile.am 2016-08-29 16:57:45.955528215 -0400
+@@ -97,16 +97,21 @@ libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SO
+ arm/filter_neon.S arm/filter_neon_intrinsics.c
+ endif
+
+ if PNG_MIPS_MSA
+ libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES += mips/mips_init.c\
+ mips/filter_msa_intrinsics.c
+ endif
+
++if PNG_INTEL_SSE
++libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES += contrib/intel/intel_init.c\
++ contrib/intel/filter_sse2_intrinsics.c
++endif
++
+ nodist_libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES = pnglibconf.h
+
+ libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LDFLAGS = -no-undefined -export-dynamic \
+ -version-number @PNGLIB_MAJOR@@PNGLIB_MINOR@:@PNGLIB_RELEASE@:0
+
+ if HAVE_LD_VERSION_SCRIPT
+ # Versioned symbols and restricted exports
+ if HAVE_SOLARIS_LD
+diff --git a/pngpriv.h b/pngpriv.h
+--- debug16/pngpriv.h 2016-08-30 10:46:36.000000000 -0400
++++ libpng16/pngpriv.h 2016-08-30 11:57:25.672280202 -0400
+@@ -185,16 +185,52 @@
+ #ifndef PNG_MIPS_MSA_OPT
+ # if defined(__mips_msa) && (__mips_isa_rev >= 5) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+ # define PNG_MIPS_MSA_OPT 2
+ # else
+ # define PNG_MIPS_MSA_OPT 0
+ # endif
+ #endif
+
++#ifndef PNG_INTEL_SSE_OPT
++# ifdef PNG_INTEL_SSE
++ /* Only check for SSE if the build configuration has been modified to
++ * enable SSE optimizations. This means that these optimizations will
++ * be off by default. See contrib/intel for more details.
++ */
++# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
++ defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
++ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
++# define PNG_INTEL_SSE_OPT 1
++# endif
++# endif
++#endif
++
++#if PNG_INTEL_SSE_OPT > 0
++# ifndef PNG_INTEL_SSE_IMPLEMENTATION
++# if defined(__SSE4_1__) || defined(__AVX__)
++ /* We are not actually using AVX, but checking for AVX is the best
++ way we can detect SSE4.1 and SSSE3 on MSVC.
++ */
++# define PNG_INTEL_SSE_IMPLEMENTATION 3
++# elif defined(__SSSE3__)
++# define PNG_INTEL_SSE_IMPLEMENTATION 2
++# elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
++ (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
++# define PNG_INTEL_SSE_IMPLEMENTATION 1
++# else
++# define PNG_INTEL_SSE_IMPLEMENTATION 0
++# endif
++# endif
++
++# if PNG_INTEL_SSE_IMPLEMENTATION > 0
++# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2
++# endif
++#endif
++
+ #if PNG_MIPS_MSA_OPT > 0
+ # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_msa
+ # ifndef PNG_MIPS_MSA_IMPLEMENTATION
+ # if defined(__mips_msa)
+ # if defined(__clang__)
+ # elif defined(__GNUC__)
+ # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
+ # define PNG_MIPS_MSA_IMPLEMENTATION 2
+@@ -1251,16 +1287,31 @@ PNG_INTERNAL_FUNCTION(void,png_read_filt
+ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+ #endif
+
++#if PNG_INTEL_SSE_IMPLEMENTATION > 0
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
++ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
++#endif
++
+ /* Choose the best filter to use and filter the row data */
+ PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
+ png_row_infop row_info),PNG_EMPTY);
+
+ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+ PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr,
+ png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY);
+ /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer
+@@ -1986,16 +2037,21 @@ PNG_INTERNAL_FUNCTION(void, PNG_FILTER_O
+ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+ #endif
+
+ #if PNG_MIPS_MSA_OPT > 0
+ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+ #endif
++
++# if PNG_INTEL_SSE_IMPLEMENTATION > 0
++PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,
++ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
++# endif
+ #endif
+
+ PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
+ png_const_charp key, png_bytep new_key), PNG_EMPTY);
+
+ /* Maintainer: Put new private prototypes here ^ */
+
+ #include "pngdebug.h"
diff --git a/libpng/contrib/libtests/fakepng.c b/libpng/contrib/libtests/fakepng.c
index fcc111286..6512c1401 100644
--- a/libpng/contrib/libtests/fakepng.c
+++ b/libpng/contrib/libtests/fakepng.c
@@ -1,4 +1,12 @@
-/* Fake a PNG - just write it out directly. */
+/* Fake a PNG - just write it out directly.
+ *
+ * COPYRIGHT: Written by John Cunningham Bowler, 2014.
+ * 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.
+ *
+ */
+
#include <stdio.h>
#include <zlib.h> /* for crc32 */
diff --git a/libpng/contrib/libtests/makepng.c b/libpng/contrib/libtests/makepng.c
index 9f11b2964..9dff04846 100644
--- a/libpng/contrib/libtests/makepng.c
+++ b/libpng/contrib/libtests/makepng.c
@@ -1,8 +1,9 @@
-/* makepng.c
- *
- * Copyright (c) 2013 John Cunningham Bowler
- *
- * Last changed in libpng 1.6.1 [March 28, 2013]
+/* makepng.c */
+#define _ISOC99_SOURCE
+/* Copyright: */
+#define COPYRIGHT "\251 2013,2015 John Cunningham Bowler"
+/*
+ * Last changed in libpng 1.6.20 [November 24, 2015]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -10,8 +11,8 @@
*
* Make a test PNG image. The arguments are as follows:
*
- * makepng [--sRGB|--linear|--1.8] [--color=<color>] color-type bit-depth \
- * [file-name]
+ * makepng [--sRGB|--linear|--1.8] [--tRNS] [--nofilters] \
+ * 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
@@ -39,8 +40,8 @@
* 4 channels: linear combinations of, from the top-left corner clockwise,
* transparent, red, green, blue.
*
- * For color-mapped images a four channel color-map is used and the PNG file has
- * a tRNS chunk, as follows:
+ * For color-mapped images a four channel color-map is used and if --tRNS is
+ * given the PNG file has a tRNS chunk, as follows:
*
* 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
* 2-bit: entry 0: transparent-green
@@ -53,6 +54,9 @@
* The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The
* image is the 1-channel diamond, but using palette index, not luminosity.
*
+ * For formats other than color-mapped ones if --tRNS is specified a tRNS chunk
+ * is generated with all channels equal to the low bits of 0x0101.
+ *
* Image size is determined by the final pixel depth in bits, i.e. channels x
* bit-depth, as follows:
*
@@ -60,20 +64,64 @@
* 16 bits: 256x256
* More than 16 bits: 1024x1024
*
- * Row filtering is turned off (the 'none' filter is used on every row) and the
- * images are not interlaced.
+ * Row filtering is the libpng default but may be turned off (the 'none' filter
+ * is used on every row) with the --nofilters option.
*
- * 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.
+ * The images are not interlaced.
*
* 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
* text mode of stdout!
+ *
+ * makepng --color=<color> ...
+ *
+ * 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.
+ *
+ * makepng --small ...
+ *
+ * If --small is given the images are no larger than required to include every
+ * possible pixel value for the format.
+ *
+ * For formats with pixels 8 bits or fewer in size the images consist of a
+ * single row with 2^pixel-depth pixels, one of every possible value.
+ *
+ * For formats with 16-bit pixels a 256x256 image is generated containing every
+ * possible pixel value.
+ *
+ * For larger pixel sizes a 256x256 image is generated where the first row
+ * consists of each pixel that has identical byte values throughout the pixel
+ * followed by rows where the byte values differ within the pixel.
+ *
+ * In all cases the pixel values are arranged in such a way that the SUB and UP
+ * filters give byte sequences for maximal zlib compression. By default (if
+ * --nofilters is not given) the SUB filter is used on the first row and the UP
+ * filter on all following rows.
+ *
+ * The --small option is meant to provide good test-case coverage, however the
+ * images are not easy to examine visually. Without the --small option the
+ * images contain identical color values; the pixel values are adjusted
+ * according to the gamma encoding with no gamma encoding being interpreted as
+ * sRGB.
+ *
+ * LICENSING
+ * =========
+ *
+ * This code is copyright of the authors, see the COPYRIGHT define above. The
+ * code is licensed as above, using the libpng license. The code generates
+ * images which are solely the product of the code; the options choose which of
+ * the many possibilities to generate. The images that result (but not the code
+ * which generates them) are licensed as defined here:
+ *
+ * IMPORTANT: the COPYRIGHT #define must contain ISO-Latin-1 characters, the
+ * IMAGE_LICENSING #define must contain UTF-8 characters. The 'copyright'
+ * symbol 0xA9U (\251) in ISO-Latin-1 encoding and 0xC20xA9 (\302\251) in UTF-8.
*/
-#define _ISOC99_SOURCE /* for strtoull */
+#define IMAGE_LICENSING "Dedicated to the public domain per Creative Commons "\
+ "license \"CC0 1.0\"; https://creativecommons.org/publicdomain/zero/1.0/"
#include <stddef.h> /* for offsetof */
#include <stdlib.h>
@@ -82,6 +130,8 @@
#include <ctype.h>
#include <math.h>
#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
# include <config.h>
@@ -96,6 +146,25 @@
# include "../../png.h"
#endif
+#include <zlib.h>
+
+/* Work round for GCC complaints about casting a (double) function result to
+ * an unsigned:
+ */
+static unsigned int
+flooru(double d)
+{
+ d = floor(d);
+ return (unsigned int)d;
+}
+
+static png_byte
+floorb(double d)
+{
+ d = floor(d);
+ return (png_byte)d;
+}
+
/* This structure is used for inserting extra chunks (the --insert argument, not
* documented above.)
*/
@@ -107,7 +176,7 @@ typedef struct chunk_insert
png_charp parameters[1];
} chunk_insert;
-static int
+static unsigned int
channels_of_type(int color_type)
{
if (color_type & PNG_COLOR_MASK_PALETTE)
@@ -128,14 +197,15 @@ channels_of_type(int color_type)
}
}
-static int
+static unsigned int
pixel_depth_of_type(int color_type, int bit_depth)
{
return channels_of_type(color_type) * bit_depth;
}
static unsigned int
-image_size_of_type(int color_type, int bit_depth, unsigned int *colors)
+image_size_of_type(int color_type, int bit_depth, unsigned int *colors,
+ int small)
{
if (*colors)
return 16;
@@ -144,7 +214,16 @@ 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)
+ if (small)
+ {
+ if (pixel_depth <= 8) /* there will be one row */
+ return 1 << pixel_depth;
+
+ else
+ return 256;
+ }
+
+ else if (pixel_depth < 8)
return 64;
else if (pixel_depth > 16)
@@ -217,7 +296,8 @@ generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
else
{
unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */
- unsigned int x, y, ip;
+ unsigned int x, y;
+ volatile unsigned int ip = 0;
for (x=0; x<size; ++x) for (y=0; y<size; ++y)
{
@@ -281,7 +361,7 @@ set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
exit(1);
case 16:
- value = (unsigned int)floor(65535*pow(value/65535.,conv)+.5);
+ value = flooru(65535*pow(value/65535.,conv)+.5);
*row++ = (png_byte)(value >> 8);
*row = (png_byte)value;
return;
@@ -306,15 +386,148 @@ set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
}
}
-static void
+static int /* filter mask for row */
generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
int bit_depth, png_const_bytep gamma_table, double conv,
- unsigned int *colors)
+ unsigned int *colors, int small)
{
- png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1;
+ int filters = 0; /* file *MASK*, 0 means the default, not NONE */
+ png_uint_32 size_max =
+ image_size_of_type(color_type, bit_depth, colors, small)-1;
png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
- if (colors[0] == 0) switch (channels_of_type(color_type))
+ if (colors[0] == 0) if (small)
+ {
+ unsigned int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
+
+ /* For pixel depths less than 16 generate a single row containing all the
+ * possible pixel values. For 16 generate all 65536 byte pair
+ * combinations in a 256x256 pixel array.
+ */
+ switch (pixel_depth)
+ {
+ case 1:
+ assert(y == 0 && rowbytes == 1 && size_max == 1);
+ row[0] = 0x6CU; /* binary: 01101100, only top 2 bits used */
+ filters = PNG_FILTER_NONE;
+ break;
+
+ case 2:
+ assert(y == 0 && rowbytes == 1 && size_max == 3);
+ row[0] = 0x1BU; /* binary 00011011, all bits used */
+ filters = PNG_FILTER_NONE;
+ break;
+
+ case 4:
+ assert(y == 0 && rowbytes == 8 && size_max == 15);
+ row[0] = 0x01U;
+ row[1] = 0x23U; /* SUB gives 0x22U for all following bytes */
+ row[2] = 0x45U;
+ row[3] = 0x67U;
+ row[4] = 0x89U;
+ row[5] = 0xABU;
+ row[6] = 0xCDU;
+ row[7] = 0xEFU;
+ filters = PNG_FILTER_SUB;
+ break;
+
+ case 8:
+ /* The row will have all the pixel values in order starting with
+ * '1', the SUB filter will change every byte into '1' (including
+ * the last, which generates pixel value '0'). Since the SUB filter
+ * has value 1 this should result in maximum compression.
+ */
+ assert(y == 0 && rowbytes == 256 && size_max == 255);
+ for (;;)
+ {
+ row[size_max] = 0xFFU & (size_max+1);
+ if (size_max == 0)
+ break;
+ --size_max;
+ }
+ filters = PNG_FILTER_SUB;
+ break;
+
+ case 16:
+ /* Rows are generated such that each row has a constant difference
+ * between the first and second byte of each pixel and so that the
+ * difference increases by 1 at each row. The rows start with the
+ * first byte value of 0 and the value increases to 255 across the
+ * row.
+ *
+ * The difference starts at 1, so the first row is:
+ *
+ * 0 1 1 2 2 3 3 4 ... 254 255 255 0
+ *
+ * This means that running the SUB filter on the first row produces:
+ *
+ * [SUB==1] 0 1 0 1 0 1...
+ *
+ * Then the difference is 2 on the next row, giving:
+ *
+ * 0 2 1 3 2 4 3 5 ... 254 0 255 1
+ *
+ * When the UP filter is run on this libpng produces:
+ *
+ * [UP ==2] 0 1 0 1 0 1...
+ *
+ * And so on for all the remain rows to the final two * rows:
+ *
+ * row 254: 0 255 1 0 2 1 3 2 4 3 ... 254 253 255 254
+ * row 255: 0 0 1 1 2 2 3 3 4 4 ... 254 254 255 255
+ */
+ assert(rowbytes == 512 && size_max == 255);
+ for (;;)
+ {
+ row[2*size_max ] = 0xFFU & size_max;
+ row[2*size_max+1] = 0xFFU & (size_max+y+1);
+ if (size_max == 0)
+ break;
+ --size_max;
+ }
+ /* The first row must include PNG_FILTER_UP so that libpng knows we
+ * need to keep it for the following row:
+ */
+ filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
+ break;
+
+ case 24:
+ case 32:
+ case 48:
+ case 64:
+ /* The rows are filled by an alogorithm similar to the above, in the
+ * first row pixel bytes are all equal, increasing from 0 by 1 for
+ * each pixel. In the second row the bytes within a pixel are
+ * incremented 1,3,5,7,... from the previous row byte. Using an odd
+ * number ensures all the possible byte values are used.
+ */
+ assert(size_max == 255 && rowbytes == 256*(pixel_depth>>3));
+ pixel_depth >>= 3; /* now in bytes */
+ while (rowbytes > 0)
+ {
+ const size_t pixel_index = --rowbytes/pixel_depth;
+
+ if (y == 0)
+ row[rowbytes] = 0xFFU & pixel_index;
+
+ else
+ {
+ const size_t byte_offset =
+ rowbytes - pixel_index * pixel_depth;
+
+ row[rowbytes] =
+ 0xFFU & (pixel_index + (byte_offset * 2*y) + 1);
+ }
+ }
+ filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
+ break;
+
+ default:
+ assert(0/*NOT REACHED*/);
+ }
+ }
+
+ else 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.
@@ -526,6 +739,8 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
colors[0], channels_of_type(color_type));
exit(1);
}
+
+ return filters;
}
@@ -554,7 +769,7 @@ makepng_error(png_structp png_ptr, png_const_charp message)
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 *colors)
+ unsigned int filters, unsigned int *colors, int small, int tRNS)
{
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
name, makepng_error, makepng_warning);
@@ -581,6 +796,15 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
/* Allow benign errors so that we can write PNGs with errors */
png_set_benign_errors(png_ptr, 1/*allowed*/);
+
+ /* Max out the text compression level in an attempt to make the license
+ * small. If --small then do the same for the IDAT.
+ */
+ if (small)
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+
+ png_set_text_compression_level(png_ptr, Z_BEST_COMPRESSION);
+
png_init_io(png_ptr, fp);
info_ptr = png_create_info_struct(png_ptr);
@@ -588,11 +812,37 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
png_error(png_ptr, "OOM allocating info structure");
{
- unsigned int size = image_size_of_type(color_type, bit_depth, colors);
+ const unsigned int size =
+ image_size_of_type(color_type, bit_depth, colors, small);
+ unsigned int ysize;
png_fixed_point real_gamma = 45455; /* For sRGB */
png_byte gamma_table[256];
double conv;
+ /* Normally images are square, but with 'small' we want to simply generate
+ * all the pixel values, or all that we reasonably can:
+ */
+ if (small)
+ {
+ const unsigned int pixel_depth =
+ pixel_depth_of_type(color_type, bit_depth);
+
+ if (pixel_depth <= 8U)
+ {
+ assert(size == (1U<<pixel_depth));
+ ysize = 1U;
+ }
+
+ else
+ {
+ assert(size == 256U);
+ ysize = 256U;
+ }
+ }
+
+ else
+ ysize = size;
+
/* This function uses the libpng values used on read to carry extra
* information about the gamma:
*/
@@ -625,13 +875,13 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
gamma_table[0] = 0;
for (i=1; i<255; ++i)
- gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + .5);
+ gamma_table[i] = floorb(pow(i/255.,conv) * 255 + .5);
gamma_table[255] = 255;
}
}
- png_set_IHDR(png_ptr, info_ptr, size, size, bit_depth, color_type,
+ png_set_IHDR(png_ptr, info_ptr, size, ysize, bit_depth, color_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (color_type & PNG_COLOR_MASK_PALETTE)
@@ -643,14 +893,26 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
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*/);
+
+ if (tRNS)
+ png_set_tRNS(png_ptr, info_ptr, trans, npalette-1,
+ NULL/*transparent color*/);
/* Reset gamma_table to prevent the image rows being changed */
for (npalette=0; npalette<256; ++npalette)
gamma_table[npalette] = (png_byte)npalette;
}
+ else if (tRNS)
+ {
+ png_color_16 col;
+
+ col.red = col.green = col.blue = col.gray =
+ 0x0101U & ((1U<<bit_depth)-1U);
+ col.index = 0U;
+ png_set_tRNS(png_ptr, info_ptr, NULL/*trans*/, 1U, &col);
+ }
+
if (gamma == PNG_DEFAULT_sRGB)
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
@@ -682,7 +944,11 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
{
- int passes = png_set_interlace_handling(png_ptr);
+# ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ int passes = png_set_interlace_handling(png_ptr);
+# else /* !WRITE_INTERLACING */
+ int passes = 1;
+# endif /* !WRITE_INTERLACING */
int pass;
png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
@@ -695,10 +961,15 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
{
unsigned int y;
- for (y=0; y<size; ++y)
+ for (y=0; y<ysize; ++y)
{
- generate_row(row, rowbytes, y, color_type, bit_depth,
- gamma_table, conv, colors);
+ unsigned int row_filters =
+ generate_row(row, rowbytes, y, color_type, bit_depth,
+ gamma_table, conv, colors, small);
+
+ if (row_filters != 0 && filters == PNG_ALL_FILTERS)
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, row_filters);
+
png_write_row(png_ptr, row);
}
}
@@ -827,7 +1098,7 @@ static png_size_t
load_fake(png_charp param, png_bytepp profile)
{
char *endptr = NULL;
- unsigned long long int size = strtoull(param, &endptr, 0/*base*/);
+ uint64_t size = strtoull(param, &endptr, 0/*base*/);
/* The 'fake' format is <number>*[string] */
if (endptr != NULL && *endptr == '*')
@@ -1062,7 +1333,8 @@ insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams,
}
static void
-insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params)
+insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams,
+ png_charpp params)
{
int i;
png_uint_16 freq[256];
@@ -1089,6 +1361,56 @@ insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp par
png_set_hIST(png_ptr, info_ptr, freq);
}
+static png_byte
+bval(png_const_structrp png_ptr, png_charp param, unsigned int maxval)
+{
+ char *endptr = NULL;
+ unsigned long int l = strtoul(param, &endptr, 0/*base*/);
+
+ if (param[0] && *endptr == 0 && l <= maxval)
+ return (png_byte)l;
+
+ else
+ png_error(png_ptr, "sBIT: invalid sBIT value");
+}
+
+static void
+insert_sBIT(png_structp png_ptr, png_infop info_ptr, int nparams,
+ png_charpp params)
+{
+ const int ct = png_get_color_type(png_ptr, info_ptr);
+ const int c = (ct & PNG_COLOR_MASK_COLOR ? 3 : 1) +
+ (ct & PNG_COLOR_MASK_ALPHA ? 1 : 0);
+ const unsigned int maxval =
+ ct & PNG_COLOR_MASK_PALETTE ? 8U : png_get_bit_depth(png_ptr, info_ptr);
+ png_color_8 sBIT;
+
+ if (nparams != c)
+ png_error(png_ptr, "sBIT: incorrect parameter count");
+
+ if (ct & PNG_COLOR_MASK_COLOR)
+ {
+ sBIT.red = bval(png_ptr, params[0], maxval);
+ sBIT.green = bval(png_ptr, params[1], maxval);
+ sBIT.blue = bval(png_ptr, params[2], maxval);
+ sBIT.gray = 42;
+ }
+
+ else
+ {
+ sBIT.red = sBIT.green = sBIT.blue = 42;
+ sBIT.gray = bval(png_ptr, params[0], maxval);
+ }
+
+ if (ct & PNG_COLOR_MASK_ALPHA)
+ sBIT.alpha = bval(png_ptr, params[nparams-1], maxval);
+
+ else
+ sBIT.alpha = 42;
+
+ png_set_sBIT(png_ptr, info_ptr, &sBIT);
+}
+
#if 0
static void
insert_sPLT(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params)
@@ -1216,6 +1538,11 @@ find_insert(png_const_charp what, png_charp param)
return make_insert(what, insert_hIST, nparams, parameter_list);
break;
+ case CHUNK(115,66,73,84): /* sBIT */
+ if (nparams <= 4)
+ return make_insert(what, insert_sBIT, nparams, parameter_list);
+ break;
+
#if 0
case CHUNK(115,80,76,84): /* sPLT */
return make_insert(what, insert_sPLT, nparams, parameter_list);
@@ -1231,6 +1558,80 @@ find_insert(png_const_charp what, png_charp param)
return NULL;
}
+/* This is necessary because libpng expects writeable strings for things like
+ * text chunks (maybe this should be fixed...)
+ */
+static png_charp
+strstash(png_const_charp foo)
+{
+ /* The program indicates a memory allocation error by crashing, this is by
+ * design.
+ */
+ if (foo != NULL)
+ {
+ png_charp bar = malloc(strlen(foo)+1);
+ return strcpy(bar, foo);
+ }
+
+ return NULL;
+}
+
+static png_charp
+strstash_list(const png_const_charp *text)
+{
+ size_t foo = 0;
+ png_charp result, bar;
+ const png_const_charp *line = text;
+
+ while (*line != NULL)
+ foo += strlen(*line++);
+
+ result = bar = malloc(foo+1);
+
+ line = text;
+ while (*line != NULL)
+ {
+ foo = strlen(*line);
+ memcpy(bar, *line++, foo);
+ bar += foo;
+ }
+
+ *bar = 0;
+ return result;
+}
+
+/* These are used to insert Copyright and Licence fields, they allow the text to
+ * have \n unlike the --insert option.
+ */
+static chunk_insert *
+add_tEXt(const char *key, const png_const_charp *text)
+{
+ static char what[5] = { 116, 69, 88, 116, 0 };
+ png_charp parameter_list[3];
+
+ parameter_list[0] = strstash(key);
+ parameter_list[1] = strstash_list(text);
+ parameter_list[2] = NULL;
+
+ return make_insert(what, insert_tEXt, 2, parameter_list);
+}
+
+static chunk_insert *
+add_iTXt(const char *key, const char *language, const char *language_key,
+ const png_const_charp *text)
+{
+ static char what[5] = { 105, 84, 88, 116, 0 };
+ png_charp parameter_list[5];
+
+ parameter_list[0] = strstash(key);
+ parameter_list[1] = strstash(language);
+ parameter_list[2] = strstash(language_key);
+ parameter_list[3] = strstash_list(text);
+ parameter_list[4] = NULL;
+
+ return make_insert(what, insert_iTXt, 4, parameter_list);
+}
+
/* This is a not-very-good parser for a sequence of numbers (including 0). It
* doesn't accept some apparently valid things, but it accepts all the sensible
* combinations.
@@ -1280,6 +1681,8 @@ main(int argc, char **argv)
const char *file_name = NULL;
int color_type = 8; /* invalid */
int bit_depth = 32; /* invalid */
+ int small = 0; /* make full size images */
+ int tRNS = 0; /* don't output a tRNS chunk */
unsigned int colors[5];
unsigned int filters = PNG_ALL_FILTERS;
png_fixed_point gamma = 0; /* not set */
@@ -1292,6 +1695,18 @@ main(int argc, char **argv)
{
char *arg = *++argv;
+ if (strcmp(arg, "--small") == 0)
+ {
+ small = 1;
+ continue;
+ }
+
+ if (strcmp(arg, "--tRNS") == 0)
+ {
+ tRNS = 1;
+ continue;
+ }
+
if (strcmp(arg, "--sRGB") == 0)
{
gamma = PNG_DEFAULT_sRGB;
@@ -1432,9 +1847,10 @@ main(int argc, char **argv)
if (color_type == 8 || bit_depth == 32)
{
- fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] "
+ fprintf(stderr, "usage: makepng [--small] [--sRGB|--linear|--1.8] "
"[--color=...] color-type bit-depth [file-name]\n"
- " Make a test PNG file, by default writes to stdout.\n");
+ " Make a test PNG file, by default writes to stdout.\n"
+ " Other options are available, UTSL.\n");
exit(1);
}
@@ -1453,10 +1869,19 @@ main(int argc, char **argv)
}
}
+ /* small and colors are incomparible (will probably crash if both are used at
+ * the same time!)
+ */
+ if (small && colors[0] != 0)
+ {
+ fprintf(stderr, "makepng: --color --small: only one at a time!\n");
+ exit(1);
+ }
+
/* Restrict the filters for more speed to those we know are used for the
* generated images.
*/
- if (filters == PNG_ALL_FILTERS)
+ if (filters == PNG_ALL_FILTERS && !small/*small provides defaults*/)
{
if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8)
filters = PNG_FILTER_NONE;
@@ -1474,9 +1899,39 @@ main(int argc, char **argv)
filters &= ~PNG_FILTER_NONE;
}
+ /* Insert standard copyright and licence text. */
+ {
+ static png_const_charp copyright[] =
+ {
+ COPYRIGHT, /* ISO-Latin-1 */
+ NULL
+ };
+ static png_const_charp licensing[] =
+ {
+ IMAGE_LICENSING, /* UTF-8 */
+ NULL
+ };
+
+ chunk_insert *new_insert;
+
+ new_insert = add_tEXt("Copyright", copyright);
+ if (new_insert != NULL)
+ {
+ *insert_ptr = new_insert;
+ insert_ptr = &new_insert->next;
+ }
+
+ new_insert = add_iTXt("Licensing", "en", NULL, licensing);
+ if (new_insert != NULL)
+ {
+ *insert_ptr = new_insert;
+ insert_ptr = &new_insert->next;
+ }
+ }
+
{
int ret = write_png(&file_name, fp, color_type, bit_depth, gamma,
- head_insert, filters, colors);
+ head_insert, filters, colors, small, tRNS);
if (ret != 0 && file_name != NULL)
remove(file_name);
diff --git a/libpng/contrib/libtests/pngimage.c b/libpng/contrib/libtests/pngimage.c
index dccfbce12..9ae402cc4 100644
--- a/libpng/contrib/libtests/pngimage.c
+++ b/libpng/contrib/libtests/pngimage.c
@@ -1,8 +1,8 @@
/* pngimage.c
*
- * Copyright (c) 2014 John Cunningham Bowler
+ * Copyright (c) 2015,2016 John Cunningham Bowler
*
- * Last changed in libpng 1.6.10 [March 6, 2014]
+ * Last changed in libpng 1.6.24 [August 4, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -36,7 +36,28 @@
# include <setjmp.h> /* because png.h did *not* include this */
#endif
-#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
+/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
+ * a skipped test, in earlier versions we need to succeed on a skipped test, so:
+ */
+#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
+# define SKIP 77
+#else
+# define SKIP 0
+#endif
+
+#if PNG_LIBPNG_VER < 10700
+ /* READ_PNG and WRITE_PNG were not defined, so: */
+# ifdef PNG_INFO_IMAGE_SUPPORTED
+# ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+# define PNG_READ_PNG_SUPPORTED
+# endif /* SEQUENTIAL_READ */
+# ifdef PNG_WRITE_SUPPORTED
+# define PNG_WRITE_PNG_SUPPORTED
+# endif /* WRITE */
+# endif /* INFO_IMAGE */
+#endif /* pre 1.7.0 */
+
+#ifdef PNG_READ_PNG_SUPPORTED
/* If a transform is valid on both read and write this implies that if the
* transform is applied to read it must also be applied on write to produce
* meaningful data. This is because these transforms when performed on read
@@ -236,10 +257,12 @@ static struct transform_info
*/
#endif
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
- T(SCALE_16, NONE, X, X, 16, R)
+ T(SCALE_16, NONE, X, X, 16, R),
/* scales 16-bit components to 8-bits. */
#endif
+ { NULL /*name*/, 0, 0, 0, 0, 0, 0, 0/*!tested*/ }
+
#undef T
};
@@ -294,7 +317,7 @@ transform_name(int t)
t &= -t; /* first set bit */
- for (i=0; i<TTABLE_SIZE; ++i)
+ for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
{
if ((transform_info[i].transform & t) != 0)
return transform_info[i].name;
@@ -315,7 +338,7 @@ validate_T(void)
{
unsigned int i;
- for (i=0; i<TTABLE_SIZE; ++i)
+ for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
{
if (transform_info[i].when & TRANSFORM_R)
read_transforms |= transform_info[i].transform;
@@ -383,7 +406,7 @@ buffer_destroy(struct buffer *buffer)
buffer_destroy_list(list);
}
-#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_PNG_SUPPORTED
static void
buffer_start_write(struct buffer *buffer)
{
@@ -505,6 +528,7 @@ typedef enum
#define SKIP_BUGS 0x100 /* Skip over known bugs */
#define LOG_SKIPPED 0x200 /* Log skipped bugs */
#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */
+#define LIST_COMBOS 0x800 /* List combos by name */
/* Result masks apply to the result bits in the 'results' field below; these
* bits are simple 1U<<error_level. A pass requires either nothing worse than
@@ -552,7 +576,7 @@ struct display
png_structp read_pp;
png_infop read_ip;
-# ifdef PNG_WRITE_SUPPORTED
+# ifdef PNG_WRITE_PNG_SUPPORTED
/* Used to write a new image (the original info_ptr is used) */
png_structp write_pp;
struct buffer written_file; /* where the file gets written */
@@ -579,7 +603,7 @@ display_init(struct display *dp)
dp->read_ip = NULL;
buffer_init(&dp->original_file);
-# ifdef PNG_WRITE_SUPPORTED
+# ifdef PNG_WRITE_PNG_SUPPORTED
dp->write_pp = NULL;
buffer_init(&dp->written_file);
# endif
@@ -592,7 +616,7 @@ display_clean_read(struct display *dp)
png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL);
}
-#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_PNG_SUPPORTED
static void
display_clean_write(struct display *dp)
{
@@ -604,7 +628,7 @@ display_clean_write(struct display *dp)
static void
display_clean(struct display *dp)
{
-# ifdef PNG_WRITE_SUPPORTED
+# ifdef PNG_WRITE_PNG_SUPPORTED
display_clean_write(dp);
# endif
display_clean_read(dp);
@@ -622,7 +646,7 @@ static void
display_destroy(struct display *dp)
{
/* Release any memory held in the display. */
-# ifdef PNG_WRITE_SUPPORTED
+# ifdef PNG_WRITE_PNG_SUPPORTED
buffer_destroy(&dp->written_file);
# endif
@@ -690,7 +714,35 @@ display_log(struct display *dp, error_level level, const char *fmt, ...)
int tr = dp->transforms;
if (is_combo(tr))
- fprintf(stderr, "(0x%x)", tr);
+ {
+ if (dp->options & LIST_COMBOS)
+ {
+ int trx = tr;
+
+ fprintf(stderr, "(");
+ if (trx)
+ {
+ int start = 0;
+
+ while (trx)
+ {
+ int trz = trx & -trx;
+
+ if (start) fprintf(stderr, "+");
+ fprintf(stderr, "%s", transform_name(trz));
+ start = 1;
+ trx &= ~trz;
+ }
+ }
+
+ else
+ fprintf(stderr, "-");
+ fprintf(stderr, ")");
+ }
+
+ else
+ fprintf(stderr, "(0x%x)", tr);
+ }
else
fprintf(stderr, "(%s)", transform_name(tr));
@@ -910,13 +962,13 @@ update_display(struct display *dp)
int bd = dp->bit_depth;
unsigned int i;
- for (i=0; i<TTABLE_SIZE; ++i)
+ for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
{
int transform = transform_info[i].transform;
if ((transform_info[i].valid_chunks == 0 ||
(transform_info[i].valid_chunks & chunks) != 0) &&
- (transform_info[i].color_mask_required & ct) ==
+ (transform_info[i].color_mask_required & ct) ==
transform_info[i].color_mask_required &&
(transform_info[i].color_mask_absent & ct) == 0 &&
(transform_info[i].bit_depths & bd) != 0 &&
@@ -935,9 +987,6 @@ update_display(struct display *dp)
dp->active_transforms = active;
dp->ignored_transforms = inactive; /* excluding write-only transforms */
-
- if (active == 0)
- display_log(dp, INTERNAL_ERROR, "bad transform table");
}
}
@@ -977,7 +1026,7 @@ compare_read(struct display *dp, int applied_transforms)
{
unsigned long chunks =
png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff);
-
+
if (chunks != dp->chunks)
display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx",
(unsigned long)dp->chunks, chunks);
@@ -1044,6 +1093,7 @@ compare_read(struct display *dp, int applied_transforms)
}
else
+# ifdef PNG_sBIT_SUPPORTED
{
unsigned long y;
int bpp; /* bits-per-pixel then bytes-per-pixel */
@@ -1120,8 +1170,8 @@ compare_read(struct display *dp, int applied_transforms)
{
int b;
- case 16: /* Two bytes per component, bit-endian */
- for (b = (bpp >> 4); b > 0; )
+ case 16: /* Two bytes per component, big-endian */
+ for (b = (bpp >> 4); b > 0; --b)
{
unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]);
@@ -1205,12 +1255,16 @@ compare_read(struct display *dp, int applied_transforms)
}
} /* for y */
}
+# else /* !sBIT */
+ display_log(dp, INTERNAL_ERROR,
+ "active shift transform but no sBIT support");
+# endif /* !sBIT */
}
return 1; /* compare succeeded */
}
-#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_PNG_SUPPORTED
static void
buffer_write(struct display *dp, struct buffer *buffer, png_bytep data,
png_size_t size)
@@ -1309,7 +1363,7 @@ write_png(struct display *dp, png_infop ip, int transforms)
*/
display_clean_write(dp);
}
-#endif /* WRITE_SUPPORTED */
+#endif /* WRITE_PNG */
static int
skip_transform(struct display *dp, int tr)
@@ -1371,7 +1425,7 @@ test_one_file(struct display *dp, const char *filename)
return; /* no point testing more */
}
-#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_PNG_SUPPORTED
/* Second test: write the original PNG data out to a new file (to test the
* write side) then read the result back in and make sure that it hasn't
* changed.
@@ -1412,7 +1466,7 @@ test_one_file(struct display *dp, const char *filename)
* out and read it back in again (without the reversible transforms)
* we should get back to the place where we started.
*/
-#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_PNG_SUPPORTED
if ((current & write_transforms) == current)
{
/* All transforms reversible: write the PNG with the transformations
@@ -1588,6 +1642,12 @@ main(const int argc, const char * const * const argv)
else if (strcmp(name, "--nofind-bad-combos") == 0)
d.options &= ~FIND_BAD_COMBOS;
+ else if (strcmp(name, "--list-combos") == 0)
+ d.options |= LIST_COMBOS;
+
+ else if (strcmp(name, "--nolist-combos") == 0)
+ d.options &= ~LIST_COMBOS;
+
else if (name[0] == '-' && name[1] == '-')
{
fprintf(stderr, "pngimage: %s: unknown option\n", name);
@@ -1642,11 +1702,11 @@ main(const int argc, const char * const * const argv)
return errors != 0;
}
}
-#else /* !PNG_INFO_IMAGE_SUPPORTED || !PNG_READ_SUPPORTED */
+#else /* !READ_PNG */
int
main(void)
{
fprintf(stderr, "pngimage: no support for png_read/write_image\n");
- return 77;
+ return SKIP;
}
#endif
diff --git a/libpng/contrib/libtests/pngstest-errors.h b/libpng/contrib/libtests/pngstest-errors.h
new file mode 100644
index 000000000..3356f1c46
--- /dev/null
+++ b/libpng/contrib/libtests/pngstest-errors.h
@@ -0,0 +1,165 @@
+/* contrib/libtests/pngstest-errors.h
+ *
+ * BUILT USING: libpng version 1.6.19beta03 - September 25, 2015
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * THIS IS A MACHINE GENERATED FILE: do not edit it directly!
+ * Instead run:
+ *
+ * pngstest --accumulate
+ *
+ * on as many PNG files as possible; at least PNGSuite and
+ * contrib/libtests/testpngs.
+ */
+static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =
+{
+ { /* input: sRGB-gray */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: sRGB-gray+alpha */
+ { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: sRGB-rgb */
+ { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: sRGB-rgb+alpha */
+ { 0, 16, 17, 0 }, { 0, 17, 17, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 850, 875, 0 }, { 0, 850, 875, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: linear-gray */
+ { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: linear-gray+alpha */
+ { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 },
+ { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: linear-rgb */
+ { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
+ { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: linear-rgb+alpha */
+ { 0, 126, 143, 0 }, { 0, 11, 7, 0 }, { 0, 74, 9, 0 }, { 0, 17, 9, 0 },
+ { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-sRGB-gray */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-sRGB-gray+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-sRGB-rgb */
+ { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
+ { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 },
+ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 }
+ }, { /* input: color-mapped-sRGB-rgb+alpha */
+ { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 9, 0 }, { 0, 9, 9, 0 },
+ { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 514, 0 }, { 0, 717, 514, 0 },
+ { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 13323, 460, 0 }, { 0, 427, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 }
+ }, { /* input: color-mapped-linear-gray */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-gray+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-rgb */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-rgb+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 }
+ }
+};
+static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =
+{
+ { /* input: sRGB-gray */
+ { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }
+ }, { /* input: sRGB-gray+alpha */
+ { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 }
+ }, { /* input: sRGB-rgb */
+ { 0, 0, 20, 0 }, { 0, 0, 20, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 }
+ }, { /* input: sRGB-rgb+alpha */
+ { 0, 16, 17, 0 }, { 0, 187, 17, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 }
+ }, { /* input: linear-gray */
+ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
+ }, { /* input: linear-gray+alpha */
+ { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
+ }, { /* input: linear-rgb */
+ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
+ }, { /* input: linear-rgb+alpha */
+ { 0, 1, 1, 0 }, { 0, 9, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
+ }, { /* input: color-mapped-sRGB-gray */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-sRGB-gray+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-sRGB-rgb */
+ { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 }
+ }, { /* input: color-mapped-sRGB-rgb+alpha */
+ { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 9, 5, 0 }, { 0, 32, 5, 0 }
+ }, { /* input: color-mapped-linear-gray */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-gray+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-rgb */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }, { /* input: color-mapped-linear-rgb+alpha */
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
+ }
+};
+static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =
+{
+ { /* input: sRGB-gray */
+ { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
+ { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }
+ }, { /* input: sRGB-gray+alpha */
+ { 0, 19, 9, 0 }, { 0, 255, 9, 25 }, { 0, 88, 9, 0 }, { 0, 255, 9, 25 },
+ { 0, 1012, 928, 0 }, { 0, 16026, 928, 6425 }, { 0, 1012, 928, 0 }, { 0, 16026, 928, 6425 }
+ }, { /* input: sRGB-rgb */
+ { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 },
+ { 0, 0, 962, 0 }, { 0, 0, 962, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 }
+ }, { /* input: sRGB-rgb+alpha */
+ { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 225, 25, 0 }, { 0, 255, 25, 67 },
+ { 0, 17534, 18491, 0 }, { 0, 15736, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 50115, 13677, 17219 }
+ }, { /* input: linear-gray */
+ { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 },
+ { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }
+ }, { /* input: linear-gray+alpha */
+ { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 99, 74, 0 }, { 0, 255, 74, 25 },
+ { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6553 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6553 }
+ }, { /* input: linear-rgb */
+ { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 },
+ { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 }
+ }, { /* input: linear-rgb+alpha */
+ { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 },
+ { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 49172, 24992, 17347 }
+ }
+};
+/* END MACHINE GENERATED */
diff --git a/libpng/contrib/libtests/pngstest.c b/libpng/contrib/libtests/pngstest.c
index d7c1c1e79..30f57a966 100644
--- a/libpng/contrib/libtests/pngstest.c
+++ b/libpng/contrib/libtests/pngstest.c
@@ -1,9 +1,9 @@
/*-
* pngstest.c
*
- * Copyright (c) 2013-2014 John Cunningham Bowler
+ * Copyright (c) 2013-2016 John Cunningham Bowler
*
- * Last changed in libpng 1.6.16 [December 22, 2014]
+ * Last changed in libpng 1.6.24 [August 4, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -35,6 +35,15 @@
# include "../../png.h"
#endif
+/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
+ * a skipped test, in earlier versions we need to succeed on a skipped test, so:
+ */
+#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
+# define SKIP 77
+#else
+# define SKIP 0
+#endif
+
#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */
#include "../tools/sRGB.h"
@@ -99,10 +108,18 @@ make_random_bytes(png_uint_32* seed, void* pv, size_t size)
seed[1] = u1;
}
+static png_uint_32 color_seed[2];
+
+static void
+reseed(void)
+{
+ color_seed[0] = 0x12345678U;
+ color_seed[1] = 0x9abcdefU;
+}
+
static void
random_color(png_colorp color)
{
- static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef };
make_random_bytes(color_seed, color, sizeof *color);
}
@@ -307,7 +324,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms)
}
#endif /* unused */
-#define READ_FILE 1 /* else memory */
+#define USE_FILE 1 /* else memory */
#define USE_STDIO 2 /* else use file name */
#define STRICT 4 /* fail on warnings too */
#define VERBOSE 8
@@ -316,16 +333,19 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms)
#define ACCUMULATE 64
#define FAST_WRITE 128
#define sRGB_16BIT 256
+#define NO_RESEED 512 /* do not reseed on each new file */
+#define GBG_ERROR 1024 /* do not ignore the gamma+background_rgb_to_gray
+ * libpng warning. */
static void
print_opts(png_uint_32 opts)
{
- if (opts & READ_FILE)
+ if (opts & USE_FILE)
printf(" --file");
if (opts & USE_STDIO)
printf(" --stdio");
- if (opts & STRICT)
- printf(" --strict");
+ if (!(opts & STRICT))
+ printf(" --nostrict");
if (opts & VERBOSE)
printf(" --verbose");
if (opts & KEEP_TMPFILES)
@@ -338,6 +358,12 @@ print_opts(png_uint_32 opts)
printf(" --slow");
if (opts & sRGB_16BIT)
printf(" --sRGB-16bit");
+ if (opts & NO_RESEED)
+ printf(" --noreseed");
+#if PNG_LIBPNG_VER < 10700 /* else on by default */
+ if (opts & GBG_ERROR)
+ printf(" --fault-gbg-warning");
+#endif
}
#define FORMAT_NO_CHANGE 0x80000000 /* additional flag */
@@ -615,7 +641,7 @@ freeimage(Image *image)
if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0)
{
- remove(image->tmpfile_name);
+ (void)remove(image->tmpfile_name);
image->tmpfile_name[0] = 0;
}
}
@@ -741,8 +767,15 @@ checkopaque(Image *image)
return logerror(image, image->file_name, ": opaque not NULL", "");
}
- else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0)
- return logerror(image, image->file_name, " --strict", "");
+ /* Separate out the gamma+background_rgb_to_gray warning because it may
+ * produce opaque component errors:
+ */
+ else if (image->image.warning_or_error != 0 &&
+ (strcmp(image->image.message,
+ "libpng does not support gamma+background+rgb_to_gray") == 0 ?
+ (image->opts & GBG_ERROR) != 0 : (image->opts & STRICT) != 0))
+ return logerror(image, image->file_name, (image->opts & GBG_ERROR) != 0 ?
+ " --fault-gbg-warning" : " --strict", "");
else
return 1;
@@ -1984,156 +2017,7 @@ static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/])
* gpc_error_to_colormap.
*/
#if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */
-/* START MACHINE GENERATED */
-static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =
-{
- { /* input: sRGB-gray */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: sRGB-gray+alpha */
- { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: sRGB-rgb */
- { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: sRGB-rgb+alpha */
- { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: linear-gray */
- { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: linear-gray+alpha */
- { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 },
- { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: linear-rgb */
- { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
- { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: linear-rgb+alpha */
- { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 },
- { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-sRGB-gray */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-sRGB-gray+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-sRGB-rgb */
- { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 },
- { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 },
- { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 }
- }, { /* input: color-mapped-sRGB-rgb+alpha */
- { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 },
- { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 },
- { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 }
- }, { /* input: color-mapped-linear-gray */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-gray+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-rgb */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-rgb+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 }
- }
-};
-static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =
-{
- { /* input: sRGB-gray */
- { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }
- }, { /* input: sRGB-gray+alpha */
- { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 }
- }, { /* input: sRGB-rgb */
- { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 }
- }, { /* input: sRGB-rgb+alpha */
- { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 }
- }, { /* input: linear-gray */
- { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
- }, { /* input: linear-gray+alpha */
- { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
- }, { /* input: linear-rgb */
- { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
- }, { /* input: linear-rgb+alpha */
- { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
- }, { /* input: color-mapped-sRGB-gray */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-sRGB-gray+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-sRGB-rgb */
- { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 }
- }, { /* input: color-mapped-sRGB-rgb+alpha */
- { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 }
- }, { /* input: color-mapped-linear-gray */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-gray+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-rgb */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }, { /* input: color-mapped-linear-rgb+alpha */
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }
-};
-static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =
-{
- { /* input: sRGB-gray */
- { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
- { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }
- }, { /* input: sRGB-gray+alpha */
- { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 },
- { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }
- }, { /* input: sRGB-rgb */
- { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 },
- { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 }
- }, { /* input: sRGB-rgb+alpha */
- { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 },
- { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 }
- }, { /* input: linear-gray */
- { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 },
- { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }
- }, { /* input: linear-gray+alpha */
- { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 },
- { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }
- }, { /* input: linear-rgb */
- { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 },
- { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 }
- }, { /* input: linear-rgb+alpha */
- { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 },
- { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 }
- }
-};
-/* END MACHINE GENERATED */
+# include "pngstest-errors.h" /* machine generated */
#endif /* COLORMAP flag check */
#endif /* flag checks */
@@ -2154,7 +2038,7 @@ typedef struct
int in_opaque; /* Value of input alpha that is opaque */
int is_palette; /* Sample values come from the palette */
int accumulate; /* Accumlate component errors (don't log) */
- int output_8bit; /* Output is 8 bit (else 16 bit) */
+ int output_8bit; /* Output is 8-bit (else 16-bit) */
void (*in_gp)(Pixel*, png_const_voidp);
void (*out_gp)(Pixel*, png_const_voidp);
@@ -2828,7 +2712,7 @@ compare_two_images(Image *a, Image *b, int via_linear,
else if (y >= b->image.colormap_entries)
{
- if ((a->opts & ACCUMULATE) == 0)
+ if ((b->opts & ACCUMULATE) == 0)
{
char pindex[9];
sprintf(pindex, "%lu[%lu]", (unsigned long)y,
@@ -3157,14 +3041,14 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background)
static int
read_one_file(Image *image)
{
- if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO))
+ if (!(image->opts & USE_FILE) || (image->opts & USE_STDIO))
{
/* memory or stdio. */
FILE *f = fopen(image->file_name, "rb");
if (f != NULL)
{
- if (image->opts & READ_FILE)
+ if (image->opts & USE_FILE)
image->input_file = f;
else /* memory */
@@ -3175,7 +3059,9 @@ read_one_file(Image *image)
if (cb > 0)
{
+#ifndef __COVERITY__
if ((unsigned long int)cb <= (size_t)~(size_t)0)
+#endif
{
png_bytep b = voidcast(png_bytep, malloc((size_t)cb));
@@ -3243,7 +3129,41 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
if (image->opts & USE_STDIO)
{
+#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
+#ifndef __COVERITY__
FILE *f = tmpfile();
+#else
+ /* Experimental. Coverity says tmpfile() is insecure because it
+ * generates predictable names.
+ *
+ * It is possible to satisfy Coverity by using mkstemp(); however,
+ * any platform supporting mkstemp() undoubtedly has a secure tmpfile()
+ * implementation as well, and doesn't need the fix. Note that
+ * the fix won't work on platforms that don't support mkstemp().
+ *
+ * https://www.securecoding.cert.org/confluence/display/c/
+ * FIO21-C.+Do+not+create+temporary+files+in+shared+directories
+ * says that most historic implementations of tmpfile() provide
+ * only a limited number of possible temporary file names
+ * (usually 26) before file names are recycled. That article also
+ * provides a secure solution that unfortunately depends upon mkstemp().
+ */
+ char tmpfile[] = "pngstest-XXXXXX";
+ int filedes;
+ FILE *f;
+ umask(0177);
+ filedes = mkstemp(tmpfile);
+ if (filedes < 0)
+ f = NULL;
+ else
+ {
+ f = fdopen(filedes,"w+");
+ /* Hide the filename immediately and ensure that the file does
+ * not exist after the program ends
+ */
+ (void) unlink(tmpfile);
+ }
+#endif
if (f != NULL)
{
@@ -3272,10 +3192,14 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
else
return logerror(image, "tmpfile", ": open: ", strerror(errno));
+#else /* SIMPLIFIED_WRITE_STDIO */
+ return logerror(image, "tmpfile", ": open: unsupported", "");
+#endif /* SIMPLIFIED_WRITE_STDIO */
}
- else
+ else if (image->opts & USE_FILE)
{
+#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
static int counter = 0;
char name[32];
@@ -3295,6 +3219,51 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
else
return logerror(image, name, ": write failed", "");
+#else /* SIMPLIFIED_WRITE_STDIO */
+ return logerror(image, "stdio", ": open: unsupported", "");
+#endif /* SIMPLIFIED_WRITE_STDIO */
+ }
+
+ else /* use memory */
+ {
+ png_alloc_size_t size;
+
+ if (png_image_write_get_memory_size(image->image, size, convert_to_8bit,
+ image->buffer+16, (png_int_32)image->stride, image->colormap))
+ {
+ /* This is non-fatal but ignoring it was causing serious problems in
+ * the macro to be ignored:
+ */
+ if (size > PNG_IMAGE_PNG_SIZE_MAX(image->image))
+ return logerror(image, "memory", ": PNG_IMAGE_SIZE_MAX wrong", "");
+
+ initimage(output, image->opts, "memory", image->stride_extra);
+ output->input_memory = malloc(size);
+
+ if (output->input_memory != NULL)
+ {
+ output->input_memory_size = size;
+
+ if (png_image_write_to_memory(&image->image, output->input_memory,
+ &output->input_memory_size, convert_to_8bit, image->buffer+16,
+ (png_int_32)image->stride, image->colormap))
+ {
+ /* This is also non-fatal but it safes safer to error out anyway:
+ */
+ if (size != output->input_memory_size)
+ return logerror(image, "memory", ": memory size wrong", "");
+ }
+
+ else
+ return logerror(image, "memory", ": write failed", "");
+ }
+
+ else
+ return logerror(image, "memory", ": out of memory", "");
+ }
+
+ else
+ return logerror(image, "memory", ": get size:", "");
}
/* 'output' has an initialized temporary image, read this back in and compare
@@ -3470,6 +3439,8 @@ test_one_file(const char *file_name, format_list *formats, png_uint_32 opts,
int result;
Image image;
+ if (!(opts & NO_RESEED))
+ reseed(); /* ensure that the random numbers don't depend on file order */
newimage(&image);
initimage(&image, opts, file_name, stride_extra);
result = read_one_file(&image);
@@ -3507,7 +3478,7 @@ test_one_file(const char *file_name, format_list *formats, png_uint_32 opts,
int
main(int argc, char **argv)
{
- png_uint_32 opts = FAST_WRITE;
+ png_uint_32 opts = FAST_WRITE | STRICT;
format_list formats;
const char *touch = NULL;
int log_pass = 0;
@@ -3516,11 +3487,17 @@ main(int argc, char **argv)
int retval = 0;
int c;
+#if PNG_LIBPNG_VER >= 10700
+ /* This error should not exist in 1.7 or later: */
+ opts |= GBG_ERROR;
+#endif
+
init_sRGB_to_d();
#if 0
init_error_via_linear();
#endif
format_init(&formats);
+ reseed(); /* initialize random number seeds */
for (c=1; c<argc; ++c)
{
@@ -3535,17 +3512,17 @@ main(int argc, char **argv)
}
else if (strcmp(arg, "--file") == 0)
# ifdef PNG_STDIO_SUPPORTED
- opts |= READ_FILE;
+ opts |= USE_FILE;
# else
- return 77; /* skipped: no support */
+ return SKIP; /* skipped: no support */
# endif
else if (strcmp(arg, "--memory") == 0)
- opts &= ~READ_FILE;
+ opts &= ~USE_FILE;
else if (strcmp(arg, "--stdio") == 0)
# ifdef PNG_STDIO_SUPPORTED
opts |= USE_STDIO;
# else
- return 77; /* skipped: no support */
+ return SKIP; /* skipped: no support */
# endif
else if (strcmp(arg, "--name") == 0)
opts &= ~USE_STDIO;
@@ -3571,10 +3548,16 @@ main(int argc, char **argv)
opts &= ~KEEP_GOING;
else if (strcmp(arg, "--strict") == 0)
opts |= STRICT;
+ else if (strcmp(arg, "--nostrict") == 0)
+ opts &= ~STRICT;
else if (strcmp(arg, "--sRGB-16bit") == 0)
opts |= sRGB_16BIT;
else if (strcmp(arg, "--linear-16bit") == 0)
opts &= ~sRGB_16BIT;
+ else if (strcmp(arg, "--noreseed") == 0)
+ opts |= NO_RESEED;
+ else if (strcmp(arg, "--fault-gbg-warning") == 0)
+ opts |= GBG_ERROR;
else if (strcmp(arg, "--tmpfile") == 0)
{
if (c+1 < argc)
@@ -3588,7 +3571,7 @@ main(int argc, char **argv)
}
/* Safe: checked above */
- strcpy(tmpf, argv[c]);
+ strncpy(tmpf, argv[c], sizeof (tmpf)-1);
}
else
@@ -3687,6 +3670,23 @@ main(int argc, char **argv)
{
unsigned int in;
+ printf("/* contrib/libtests/pngstest-errors.h\n");
+ printf(" *\n");
+ printf(" * BUILT USING:" PNG_HEADER_VERSION_STRING);
+ printf(" *\n");
+ printf(" * This code is released under the libpng license.\n");
+ printf(" * For conditions of distribution and use, see the disclaimer\n");
+ printf(" * and license in png.h\n");
+ printf(" *\n");
+ printf(" * THIS IS A MACHINE GENERATED FILE: do not edit it directly!\n");
+ printf(" * Instead run:\n");
+ printf(" *\n");
+ printf(" * pngstest --accumulate\n");
+ printf(" *\n");
+ printf(" * on as many PNG files as possible; at least PNGSuite and\n");
+ printf(" * contrib/libtests/testpngs.\n");
+ printf(" */\n");
+
printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n");
printf("{\n");
for (in=0; in<16; ++in)
@@ -3776,6 +3776,7 @@ main(int argc, char **argv)
putchar('\n');
}
printf("};\n");
+ printf("/* END MACHINE GENERATED */\n");
}
if (retval == 0 && touch != NULL)
@@ -3813,6 +3814,6 @@ int main(void)
{
fprintf(stderr, "pngstest: no read support in libpng, test skipped\n");
/* So the test is skipped: */
- return 77;
+ return SKIP;
}
#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */
diff --git a/libpng/contrib/libtests/pngunknown.c b/libpng/contrib/libtests/pngunknown.c
index 309ee604e..aba605e2d 100644
--- a/libpng/contrib/libtests/pngunknown.c
+++ b/libpng/contrib/libtests/pngunknown.c
@@ -1,8 +1,8 @@
/* pngunknown.c - test the read side unknown chunk handling
*
- * Last changed in libpng 1.6.10 [March 6, 2014]
- * Copyright (c) 2014 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.26 [October 20, 2016]
+ * Copyright (c) 2015,2016 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
* This code is released under the libpng license.
@@ -30,10 +30,21 @@
# include "../../png.h"
#endif
+/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
+ * a skipped test, in earlier versions we need to succeed on a skipped test, so:
+ */
+#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
+# define SKIP 77
+#else
+# define SKIP 0
+#endif
+
+
/* Since this program tests the ability to change the unknown chunk handling
* these must be defined:
*/
#if defined(PNG_SET_UNKNOWN_CHUNKS_SUPPORTED) &&\
+ defined(PNG_STDIO_SUPPORTED) &&\
defined(PNG_READ_SUPPORTED)
/* One of these must be defined to allow us to find out what happened. It is
@@ -363,7 +374,7 @@ ancillary(const char *name)
return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3]));
}
-#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
static int
ancillaryb(const png_byte *name)
{
@@ -467,7 +478,7 @@ get_valid(display *d, png_infop info_ptr)
png_textp text;
png_uint_32 ntext = png_get_text(d->png_ptr, info_ptr, &text, NULL);
- while (ntext-- > 0) switch (text[ntext].compression)
+ while (ntext > 0) switch (text[--ntext].compression)
{
case -1:
flags |= PNG_INFO_tEXt;
@@ -554,7 +565,7 @@ read_callback(png_structp pp, png_unknown_chunkp pc)
/* However if there is no support to store unknown chunks don't ask libpng to
* do it; there will be an png_error.
*/
-# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
return discard;
# else
return 1; /*handled; discard*/
@@ -562,7 +573,7 @@ read_callback(png_structp pp, png_unknown_chunkp pc)
}
#endif /* READ_USER_CHUNKS_SUPPORTED */
-#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
static png_uint_32
get_unknown(display *d, png_infop info_ptr, int after_IDAT)
{
@@ -615,7 +626,7 @@ get_unknown(display *d, png_infop info_ptr, int after_IDAT)
return flags;
}
-#else
+#else /* SAVE_UNKNOWN_CHUNKS */
static png_uint_32
get_unknown(display *d, png_infop info_ptr, int after_IDAT)
/* Otherwise this will return the cached values set by any user callback */
@@ -634,8 +645,8 @@ get_unknown(display *d, png_infop info_ptr, int after_IDAT)
* a check to ensure the logic is correct.
*/
# error No store support and no user chunk support, this will not work
-# endif
-#endif
+# endif /* READ_USER_CHUNKS */
+#endif /* SAVE_UNKNOWN_CHUNKS */
static int
check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
@@ -722,11 +733,17 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
* in this case, so we just check the arguments! This could
* be improved in the future by using the read callback.
*/
- png_byte name[5];
-
- memcpy(name, chunk_info[chunk].name, 5);
- png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
- chunk_info[chunk].keep = option;
+# if PNG_LIBPNG_VER >= 10700 &&\
+ !defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (option < PNG_HANDLE_CHUNK_IF_SAFE)
+# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
+ {
+ png_byte name[5];
+
+ memcpy(name, chunk_info[chunk].name, 5);
+ png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
+ chunk_info[chunk].keep = option;
+ }
continue;
}
@@ -735,7 +752,12 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
case 7: /* default */
if (memcmp(argv[i], "default", 7) == 0)
{
- png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
+# if PNG_LIBPNG_VER >= 10700 &&\
+ !defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (option < PNG_HANDLE_CHUNK_IF_SAFE)
+# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
+ png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
+
d->keep = option;
continue;
}
@@ -745,7 +767,12 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
case 3: /* all */
if (memcmp(argv[i], "all", 3) == 0)
{
- png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
+# if PNG_LIBPNG_VER >= 10700 &&\
+ !defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (option < PNG_HANDLE_CHUNK_IF_SAFE)
+# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
+ png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
+
d->keep = option;
for (chunk = 0; chunk < NINFO; ++chunk)
@@ -985,6 +1012,20 @@ perform_one_test(FILE *fp, int argc, const char **argv,
def = check(fp, argc, argv, flags[1], d, set_callback);
+ /* If IDAT is being handled as unknown the image read is skipped and all the
+ * IDATs after the first end up in the end info struct, so in this case add
+ * IDAT to the list of unknowns. (Do this after 'check' above sets the
+ * chunk_info 'keep' fields.)
+ *
+ * Note that the flag setting has to be in the 'known' field to avoid
+ * triggering the consistency check below and the flag must only be set if
+ * there are multiple IDATs, so if the check above did find an unknown IDAT
+ * after IDAT.
+ */
+ if (chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT &&
+ (flags[1][3] & PNG_INFO_IDAT) != 0)
+ flags[0][2] |= PNG_INFO_IDAT;
+
/* Chunks should either be known or unknown, never both and this should apply
* whether the chunk is before or after the IDAT (actually, the app can
* probably change this by swapping the handling after the image, but this
@@ -1229,7 +1270,7 @@ main(void)
fprintf(stderr,
" test ignored: no support to find out about unknown chunks\n");
/* So the test is skipped: */
- return 77;
+ return SKIP;
}
#endif /* READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS */
@@ -1240,6 +1281,6 @@ main(void)
fprintf(stderr,
" test ignored: no support to modify unknown chunk handling\n");
/* So the test is skipped: */
- return 77;
+ return SKIP;
}
-#endif /* SET_UNKNOWN_CHUNKS && READ */
+#endif /* SET_UNKNOWN_CHUNKS && READ*/
diff --git a/libpng/contrib/libtests/pngvalid.c b/libpng/contrib/libtests/pngvalid.c
index 79de125da..9b85c3ef3 100644
--- a/libpng/contrib/libtests/pngvalid.c
+++ b/libpng/contrib/libtests/pngvalid.c
@@ -1,9 +1,8 @@
/* pngvalid.c - validate libpng by constructing then reading png files.
*
- * Last changed in libpng 1.6.17 [March 26, 2015]
- * Copyright (c) 2014-2015 Glenn Randers-Pehrson
- * Written by John Cunningham Bowler
+ * Last changed in libpng 1.6.26 [October 20, 2016]
+ * Copyright (c) 2014-2016 John Cunningham Bowler
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -62,10 +61,10 @@
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
* a skipped test, in earlier versions we need to succeed on a skipped test, so:
*/
-#if PNG_LIBPNG_VER < 10601
-# define SKIP 0
-#else
+#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
# define SKIP 77
+#else
+# define SKIP 0
#endif
/* pngvalid requires write support and one of the fixed or floating point APIs.
@@ -74,7 +73,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: */
@@ -116,11 +115,32 @@ 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 */
#include <math.h> /* For floor */
+/* Convenience macros. */
+#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
+#define CHUNK_IHDR CHUNK(73,72,68,82)
+#define CHUNK_PLTE CHUNK(80,76,84,69)
+#define CHUNK_IDAT CHUNK(73,68,65,84)
+#define CHUNK_IEND CHUNK(73,69,78,68)
+#define CHUNK_cHRM CHUNK(99,72,82,77)
+#define CHUNK_gAMA CHUNK(103,65,77,65)
+#define CHUNK_sBIT CHUNK(115,66,73,84)
+#define CHUNK_sRGB CHUNK(115,82,71,66)
+
/* Unused formal parameter errors are removed using the following macro which is
* expected to have no bad effects on performance.
*/
@@ -164,6 +184,24 @@ define_exception_type(struct png_store*);
*/
#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
@@ -172,7 +210,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++;
@@ -201,16 +239,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)
@@ -258,7 +296,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)
{
@@ -266,36 +305,62 @@ 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 unsigned int
-random_mod(unsigned int max)
+#ifdef PNG_READ_SUPPORTED
+static png_byte
+random_byte(void)
{
- unsigned int x;
+ unsigned char b1[1];
+ randomize(b1, sizeof b1);
+ return b1[0];
+}
+#endif /* READ */
- RANDOMIZE(x);
+static png_uint_16
+random_u16(void)
+{
+ unsigned char b2[2];
+ randomize(b2, sizeof b2);
+ return png_get_uint_16(b2);
+}
- return x % max; /* 0 .. max-1 */
+#if defined PNG_READ_RGB_TO_GRAY_SUPPORTED ||\
+ defined PNG_READ_FILLER_SUPPORTED
+static png_uint_32
+random_u32(void)
+{
+ unsigned char b4[4];
+ randomize(b4, sizeof b4);
+ return png_get_uint_32(b4);
}
+#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)
+{
+ return random_u16() % max; /* 0 .. max-1 */
+}
+#endif /* READ_TRANSFORMS || WRITE_FILTER */
#if (defined PNG_READ_RGB_TO_GRAY_SUPPORTED) ||\
(defined PNG_READ_FILLER_SUPPORTED)
static int
random_choice(void)
{
- unsigned char x;
-
- RANDOMIZE(x);
-
- return x & 1;
+ return random_byte() & 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) + \
@@ -316,12 +381,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");
@@ -378,25 +447,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;
}
@@ -500,7 +576,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.
@@ -510,15 +587,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));
}
@@ -531,7 +618,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);
@@ -541,10 +629,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));
}
}
@@ -620,6 +708,8 @@ typedef struct png_store_file
{
struct png_store_file* next; /* as many as you like... */
char name[FILE_NAME_SIZE];
+ unsigned int IDAT_bits; /* Number of bits in IDAT size */
+ png_uint_32 IDAT_size; /* Total size of IDAT data */
png_uint_32 id; /* must be correct (see FILEID) */
png_size_t datacount; /* In this (the last) buffer */
png_store_buffer data; /* Last buffer in file */
@@ -675,6 +765,13 @@ typedef struct png_store
char test[128]; /* Name of test */
char error[256];
+ /* Share fields */
+ png_uint_32 chunklen; /* Length of chunk+overhead (chunkpos >= 8) */
+ png_uint_32 chunktype;/* Type of chunk (valid if chunkpos >= 4) */
+ png_uint_32 chunkpos; /* Position in chunk */
+ png_uint_32 IDAT_size;/* Accumulated IDAT size in .new */
+ unsigned int IDAT_bits;/* Cache of the file store value */
+
/* Read fields */
png_structp pread; /* Used to read a saved file */
png_infop piread;
@@ -684,6 +781,9 @@ typedef struct png_store
png_byte* image; /* Buffer for reading interlaced images */
png_size_t cb_image; /* Size of this buffer */
png_size_t cb_row; /* Row size of the image(s) */
+ uLong IDAT_crc;
+ png_uint_32 IDAT_len; /* Used when re-chunking IDAT chunks */
+ png_uint_32 IDAT_pos; /* Used when re-chunking IDAT chunks */
png_uint_32 image_h; /* Number of rows in a single image */
store_pool read_memory_pool;
@@ -708,7 +808,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.
*/
@@ -770,6 +870,11 @@ store_init(png_store* ps)
ps->pwrite = NULL;
ps->piwrite = NULL;
ps->writepos = 0;
+ ps->chunkpos = 8;
+ ps->chunktype = 0;
+ ps->chunklen = 16;
+ ps->IDAT_size = 0;
+ ps->IDAT_bits = 0;
ps->new.prev = NULL;
ps->palette = NULL;
ps->npalette = 0;
@@ -792,6 +897,11 @@ store_freenew(png_store *ps)
{
store_freebuffer(&ps->new);
ps->writepos = 0;
+ ps->chunkpos = 8;
+ ps->chunktype = 0;
+ ps->chunklen = 16;
+ ps->IDAT_size = 0;
+ ps->IDAT_bits = 0;
if (ps->palette != NULL)
{
free(ps->palette);
@@ -805,9 +915,6 @@ store_storenew(png_store *ps)
{
png_store_buffer *pb;
- if (ps->writepos != STORE_BUFFER_SIZE)
- png_error(ps->pwrite, "invalid store call");
-
pb = voidcast(png_store_buffer*, malloc(sizeof *pb));
if (pb == NULL)
@@ -838,21 +945,52 @@ store_freefile(png_store_file **ppf)
}
}
+static unsigned int
+bits_of(png_uint_32 num)
+{
+ /* Return the number of bits in 'num' */
+ unsigned int b = 0;
+
+ if (num & 0xffff0000U) b += 16U, num >>= 16;
+ if (num & 0xff00U) b += 8U, num >>= 8;
+ if (num & 0xf0U) b += 4U, num >>= 4;
+ if (num & 0xcU) b += 2U, num >>= 2;
+ if (num & 0x2U) ++b, num >>= 1;
+ if (num) ++b;
+
+ return b; /* 0..32 */
+}
+
/* Main interface to file storeage, after writing a new PNG file (see the API
* below) call store_storefile to store the result with the given name and id.
*/
static void
store_storefile(png_store *ps, png_uint_32 id)
{
- png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf));
+ png_store_file *pf;
+
+ if (ps->chunkpos != 0U || ps->chunktype != 0U || ps->chunklen != 0U ||
+ ps->IDAT_size == 0)
+ png_error(ps->pwrite, "storefile: incomplete write");
+
+ pf = voidcast(png_store_file*, malloc(sizeof *pf));
if (pf == NULL)
png_error(ps->pwrite, "storefile: OOM");
safecat(pf->name, sizeof pf->name, 0, ps->wname);
pf->id = id;
pf->data = ps->new;
pf->datacount = ps->writepos;
+ pf->IDAT_size = ps->IDAT_size;
+ pf->IDAT_bits = bits_of(ps->IDAT_size);
+ /* Because the IDAT always has zlib header stuff this must be true: */
+ if (pf->IDAT_bits == 0U)
+ png_error(ps->pwrite, "storefile: 0 sized IDAT");
ps->new.prev = NULL;
ps->writepos = 0;
+ ps->chunkpos = 8;
+ ps->chunktype = 0;
+ ps->chunklen = 16;
+ ps->IDAT_size = 0;
pf->palette = ps->palette;
pf->npalette = ps->npalette;
ps->palette = 0;
@@ -866,7 +1004,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)
{
@@ -984,7 +1122,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;
@@ -1088,7 +1226,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;
@@ -1103,7 +1241,7 @@ store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage)
image += 2; /* skip image first row markers */
- while (rows-- > 0)
+ for (; rows > 0; --rows)
{
if (image[-2] != 190 || image[-1] != 239)
png_error(pp, "row start overwritten");
@@ -1118,32 +1256,119 @@ store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage)
}
#endif /* PNG_READ_SUPPORTED */
+static int
+valid_chunktype(png_uint_32 chunktype)
+{
+ /* Each byte in the chunk type must be in one of the ranges 65..90, 97..122
+ * (both inclusive), so:
+ */
+ unsigned int i;
+
+ for (i=0; i<4; ++i)
+ {
+ unsigned int c = chunktype & 0xffU;
+
+ if (!((c >= 65U && c <= 90U) || (c >= 97U && c <= 122U)))
+ return 0;
+
+ chunktype >>= 8;
+ }
+
+ return 1; /* It's valid */
+}
+
static void PNGCBAPI
store_write(png_structp ppIn, png_bytep pb, png_size_t st)
{
png_const_structp pp = ppIn;
png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
+ size_t writepos = ps->writepos;
+ png_uint_32 chunkpos = ps->chunkpos;
+ png_uint_32 chunktype = ps->chunktype;
+ png_uint_32 chunklen = ps->chunklen;
if (ps->pwrite != pp)
png_error(pp, "store state damaged");
+ /* Technically this is legal, but in practice libpng never writes more than
+ * the maximum chunk size at once so if it happens something weird has
+ * changed inside libpng (probably).
+ */
+ if (st > 0x7fffffffU)
+ png_error(pp, "unexpected write size");
+
+ /* Now process the bytes to be written. Do this in units of the space in the
+ * output (write) buffer or, at the start 4 bytes for the chunk type and
+ * length limited in any case by the amount of data.
+ */
while (st > 0)
{
- size_t cb;
+ if (writepos >= STORE_BUFFER_SIZE)
+ store_storenew(ps), writepos = 0;
- if (ps->writepos >= STORE_BUFFER_SIZE)
- store_storenew(ps);
+ if (chunkpos < 4)
+ {
+ png_byte b = *pb++;
+ --st;
+ chunklen = (chunklen << 8) + b;
+ ps->new.buffer[writepos++] = b;
+ ++chunkpos;
+ }
- cb = st;
+ else if (chunkpos < 8)
+ {
+ png_byte b = *pb++;
+ --st;
+ chunktype = (chunktype << 8) + b;
+ ps->new.buffer[writepos++] = b;
- if (cb > STORE_BUFFER_SIZE - ps->writepos)
- cb = STORE_BUFFER_SIZE - ps->writepos;
+ if (++chunkpos == 8)
+ {
+ chunklen &= 0xffffffffU;
+ if (chunklen > 0x7fffffffU)
+ png_error(pp, "chunk length too great");
- memcpy(ps->new.buffer + ps->writepos, pb, cb);
- pb += cb;
- st -= cb;
- ps->writepos += cb;
- }
+ chunktype &= 0xffffffffU;
+ if (chunktype == CHUNK_IDAT)
+ {
+ if (chunklen > ~ps->IDAT_size)
+ png_error(pp, "pngvalid internal image too large");
+
+ ps->IDAT_size += chunklen;
+ }
+
+ else if (!valid_chunktype(chunktype))
+ png_error(pp, "invalid chunk type");
+
+ chunklen += 12; /* for header and CRC */
+ }
+ }
+
+ else /* chunkpos >= 8 */
+ {
+ png_size_t cb = st;
+
+ if (cb > STORE_BUFFER_SIZE - writepos)
+ cb = STORE_BUFFER_SIZE - writepos;
+
+ if (cb > chunklen - chunkpos/* bytes left in chunk*/)
+ cb = (png_size_t)/*SAFE*/(chunklen - chunkpos);
+
+ memcpy(ps->new.buffer + writepos, pb, cb);
+ chunkpos += (png_uint_32)/*SAFE*/cb;
+ pb += cb;
+ writepos += cb;
+ st -= cb;
+
+ if (chunkpos >= chunklen) /* must be equal */
+ chunkpos = chunktype = chunklen = 0;
+ }
+ } /* while (st > 0) */
+
+ ps->writepos = writepos;
+ ps->chunkpos = chunkpos;
+ ps->chunktype = chunktype;
+ ps->chunklen = chunklen;
}
static void PNGCBAPI
@@ -1163,7 +1388,6 @@ store_read_buffer_size(png_store *ps)
return ps->current->datacount;
}
-#ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Return total bytes available for read. */
static size_t
store_read_buffer_avail(png_store *ps)
@@ -1188,7 +1412,6 @@ store_read_buffer_avail(png_store *ps)
return 0;
}
-#endif
static int
store_read_buffer_next(png_store *ps)
@@ -1240,6 +1463,240 @@ store_read_imp(png_store *ps, png_bytep pb, png_size_t st)
}
}
+static png_size_t
+store_read_chunk(png_store *ps, png_bytep pb, const png_size_t max,
+ const png_size_t min)
+{
+ png_uint_32 chunklen = ps->chunklen;
+ png_uint_32 chunktype = ps->chunktype;
+ png_uint_32 chunkpos = ps->chunkpos;
+ png_size_t st = max;
+
+ if (st > 0) do
+ {
+ if (chunkpos >= chunklen) /* end of last chunk */
+ {
+ png_byte buffer[8];
+
+ /* Read the header of the next chunk: */
+ store_read_imp(ps, buffer, 8U);
+ chunklen = png_get_uint_32(buffer) + 12U;
+ chunktype = png_get_uint_32(buffer+4U);
+ chunkpos = 0U; /* Position read so far */
+ }
+
+ if (chunktype == CHUNK_IDAT)
+ {
+ png_uint_32 IDAT_pos = ps->IDAT_pos;
+ png_uint_32 IDAT_len = ps->IDAT_len;
+ png_uint_32 IDAT_size = ps->IDAT_size;
+
+ /* The IDAT headers are constructed here; skip the input header. */
+ if (chunkpos < 8U)
+ chunkpos = 8U;
+
+ if (IDAT_pos == IDAT_len)
+ {
+ png_byte random = random_byte();
+
+ /* Make a new IDAT chunk, if IDAT_len is 0 this is the first IDAT,
+ * if IDAT_size is 0 this is the end. At present this is set up
+ * using a random number so that there is a 25% chance before
+ * the start of the first IDAT chunk being 0 length.
+ */
+ if (IDAT_len == 0U) /* First IDAT */
+ {
+ switch (random & 3U)
+ {
+ case 0U: IDAT_len = 12U; break; /* 0 bytes */
+ case 1U: IDAT_len = 13U; break; /* 1 byte */
+ default: IDAT_len = random_u32();
+ IDAT_len %= IDAT_size;
+ IDAT_len += 13U; /* 1..IDAT_size bytes */
+ break;
+ }
+ }
+
+ else if (IDAT_size == 0U) /* all IDAT data read */
+ {
+ /* The last (IDAT) chunk should be positioned at the CRC now: */
+ if (chunkpos != chunklen-4U)
+ png_error(ps->pread, "internal: IDAT size mismatch");
+
+ /* The only option here is to add a zero length IDAT, this
+ * happens 25% of the time. Because of the check above
+ * chunklen-4U-chunkpos must be zero, we just need to skip the
+ * CRC now.
+ */
+ if ((random & 3U) == 0U)
+ IDAT_len = 12U; /* Output another 0 length IDAT */
+
+ else
+ {
+ /* End of IDATs, skip the CRC to make the code above load the
+ * next chunk header next time round.
+ */
+ png_byte buffer[4];
+
+ store_read_imp(ps, buffer, 4U);
+ chunkpos += 4U;
+ ps->IDAT_pos = IDAT_pos;
+ ps->IDAT_len = IDAT_len;
+ ps->IDAT_size = 0U;
+ continue; /* Read the next chunk */
+ }
+ }
+
+ else
+ {
+ /* Middle of IDATs, use 'random' to determine the number of bits
+ * to use in the IDAT length.
+ */
+ IDAT_len = random_u32();
+ IDAT_len &= (1U << (1U + random % ps->IDAT_bits)) - 1U;
+ if (IDAT_len > IDAT_size)
+ IDAT_len = IDAT_size;
+ IDAT_len += 12U; /* zero bytes may occur */
+ }
+
+ IDAT_pos = 0U;
+ ps->IDAT_crc = 0x35af061e; /* Ie: crc32(0UL, "IDAT", 4) */
+ } /* IDAT_pos == IDAT_len */
+
+ if (IDAT_pos < 8U) /* Return the header */ do
+ {
+ png_uint_32 b;
+ unsigned int shift;
+
+ if (IDAT_pos < 4U)
+ b = IDAT_len - 12U;
+
+ else
+ b = CHUNK_IDAT;
+
+ shift = 3U & IDAT_pos;
+ ++IDAT_pos;
+
+ if (shift < 3U)
+ b >>= 8U*(3U-shift);
+
+ *pb++ = 0xffU & b;
+ }
+ while (--st > 0 && IDAT_pos < 8);
+
+ else if (IDAT_pos < IDAT_len - 4U) /* I.e not the CRC */
+ {
+ if (chunkpos < chunklen-4U)
+ {
+ uInt avail = (uInt)-1;
+
+ if (avail > (IDAT_len-4U) - IDAT_pos)
+ avail = (uInt)/*SAFE*/((IDAT_len-4U) - IDAT_pos);
+
+ if (avail > st)
+ avail = (uInt)/*SAFE*/st;
+
+ if (avail > (chunklen-4U) - chunkpos)
+ avail = (uInt)/*SAFE*/((chunklen-4U) - chunkpos);
+
+ store_read_imp(ps, pb, avail);
+ ps->IDAT_crc = crc32(ps->IDAT_crc, pb, avail);
+ pb += (png_size_t)/*SAFE*/avail;
+ st -= (png_size_t)/*SAFE*/avail;
+ chunkpos += (png_uint_32)/*SAFE*/avail;
+ IDAT_size -= (png_uint_32)/*SAFE*/avail;
+ IDAT_pos += (png_uint_32)/*SAFE*/avail;
+ }
+
+ else /* skip the input CRC */
+ {
+ png_byte buffer[4];
+
+ store_read_imp(ps, buffer, 4U);
+ chunkpos += 4U;
+ }
+ }
+
+ else /* IDAT crc */ do
+ {
+ uLong b = ps->IDAT_crc;
+ unsigned int shift = (IDAT_len - IDAT_pos); /* 4..1 */
+ ++IDAT_pos;
+
+ if (shift > 1U)
+ b >>= 8U*(shift-1U);
+
+ *pb++ = 0xffU & b;
+ }
+ while (--st > 0 && IDAT_pos < IDAT_len);
+
+ ps->IDAT_pos = IDAT_pos;
+ ps->IDAT_len = IDAT_len;
+ ps->IDAT_size = IDAT_size;
+ }
+
+ else /* !IDAT */
+ {
+ /* If there is still some pending IDAT data after the IDAT chunks have
+ * been processed there is a problem:
+ */
+ if (ps->IDAT_len > 0 && ps->IDAT_size > 0)
+ png_error(ps->pread, "internal: missing IDAT data");
+
+ if (chunktype == CHUNK_IEND && ps->IDAT_len == 0U)
+ png_error(ps->pread, "internal: missing IDAT");
+
+ if (chunkpos < 8U) /* Return the header */ do
+ {
+ png_uint_32 b;
+ unsigned int shift;
+
+ if (chunkpos < 4U)
+ b = chunklen - 12U;
+
+ else
+ b = chunktype;
+
+ shift = 3U & chunkpos;
+ ++chunkpos;
+
+ if (shift < 3U)
+ b >>= 8U*(3U-shift);
+
+ *pb++ = 0xffU & b;
+ }
+ while (--st > 0 && chunkpos < 8);
+
+ else /* Return chunk bytes, including the CRC */
+ {
+ png_size_t avail = st;
+
+ if (avail > chunklen - chunkpos)
+ avail = (png_size_t)/*SAFE*/(chunklen - chunkpos);
+
+ store_read_imp(ps, pb, avail);
+ pb += avail;
+ st -= avail;
+ chunkpos += (png_uint_32)/*SAFE*/avail;
+
+ /* Check for end of chunk and end-of-file; don't try to read a new
+ * chunk header at this point unless instructed to do so by 'min'.
+ */
+ if (chunkpos >= chunklen && max-st >= min &&
+ store_read_buffer_avail(ps) == 0)
+ break;
+ }
+ } /* !IDAT */
+ }
+ while (st > 0);
+
+ ps->chunklen = chunklen;
+ ps->chunktype = chunktype;
+ ps->chunkpos = chunkpos;
+
+ return st; /* space left */
+}
+
static void PNGCBAPI
store_read(png_structp ppIn, png_bytep pb, png_size_t st)
{
@@ -1249,26 +1706,33 @@ store_read(png_structp ppIn, png_bytep pb, png_size_t st)
if (ps == NULL || ps->pread != pp)
png_error(pp, "bad store read call");
- store_read_imp(ps, pb, st);
+ store_read_chunk(ps, pb, st, st);
}
static void
store_progressive_read(png_store *ps, png_structp pp, png_infop pi)
{
- /* Notice that a call to store_read will cause this function to fail because
- * readpos will be set.
- */
if (ps->pread != pp || ps->current == NULL || ps->next == NULL)
png_error(pp, "store state damaged (progressive)");
- do
+ /* This is another Horowitz and Hill random noise generator. In this case
+ * the aim is to stress the progressive reader with truly horrible variable
+ * buffer sizes in the range 1..500, so a sequence of 9 bit random numbers
+ * is generated. We could probably just count from 1 to 32767 and get as
+ * good a result.
+ */
+ while (store_read_buffer_avail(ps) > 0)
{
- if (ps->readpos != 0)
- png_error(pp, "store_read called during progressive read");
+ static png_uint_32 noise = 2;
+ png_size_t cb;
+ png_byte buffer[512];
- png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps));
+ /* Generate 15 more bits of stuff: */
+ noise = (noise << 9) | ((noise ^ (noise >> (9-5))) & 0x1ff);
+ cb = noise & 0x1ff;
+ cb -= store_read_chunk(ps, buffer, cb, 1);
+ png_process_data(pp, pi, buffer, cb);
}
- while (store_read_buffer_next(ps));
}
#endif /* PNG_READ_SUPPORTED */
@@ -1305,7 +1769,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;
@@ -1335,7 +1802,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);
@@ -1399,7 +1866,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.
*/
@@ -1554,8 +2021,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);
@@ -1637,6 +2103,11 @@ store_read_reset(png_store *ps)
ps->next = NULL;
ps->readpos = 0;
ps->validated = 0;
+
+ ps->chunkpos = 8;
+ ps->chunktype = 0;
+ ps->chunklen = 16;
+ ps->IDAT_size = 0;
}
#ifdef PNG_READ_SUPPORTED
@@ -1651,6 +2122,11 @@ store_read_set(png_store *ps, png_uint_32 id)
{
ps->current = pf;
ps->next = NULL;
+ ps->IDAT_size = pf->IDAT_size;
+ ps->IDAT_bits = pf->IDAT_bits; /* just a cache */
+ ps->IDAT_len = 0;
+ ps->IDAT_pos = 0;
+ ps->IDAT_crc = 0UL;
store_read_buffer_next(ps);
return;
}
@@ -1675,7 +2151,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);
@@ -1782,6 +2258,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)
{
@@ -1795,7 +2272,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;
@@ -1805,12 +2282,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)
@@ -1828,9 +2306,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)
{
@@ -1867,6 +2346,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
@@ -1891,9 +2371,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 */
@@ -1904,7 +2384,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
@@ -1924,6 +2404,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 */
@@ -1959,6 +2441,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
@@ -1990,6 +2473,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
@@ -2042,6 +2535,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;
@@ -2054,6 +2552,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;
@@ -2087,7 +2590,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.
@@ -2106,7 +2609,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.
@@ -2118,7 +2621,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).
@@ -2131,7 +2634,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.
@@ -2154,7 +2657,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
@@ -2186,7 +2689,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:
@@ -2224,7 +2727,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 &&
@@ -2288,7 +2791,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;
@@ -2300,9 +2803,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);
@@ -2312,6 +2816,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:
@@ -2331,7 +2836,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 */
@@ -2447,29 +2952,18 @@ 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;
}
-/* Convenience macros. */
-#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
-#define CHUNK_IHDR CHUNK(73,72,68,82)
-#define CHUNK_PLTE CHUNK(80,76,84,69)
-#define CHUNK_IDAT CHUNK(73,68,65,84)
-#define CHUNK_IEND CHUNK(73,69,78,68)
-#define CHUNK_cHRM CHUNK(99,72,82,77)
-#define CHUNK_gAMA CHUNK(103,65,77,65)
-#define CHUNK_sBIT CHUNK(115,66,73,84)
-#define CHUNK_sRGB CHUNK(115,82,71,66)
-
/* The guts of modification are performed during a read. */
static void
modifier_crc(png_bytep buffer)
@@ -2509,7 +3003,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
{
static png_byte sign[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
case modifier_start:
- store_read_imp(&pm->this, pm->buffer, 8); /* size of signature. */
+ store_read_chunk(&pm->this, pm->buffer, 8, 8); /* signature. */
pm->buffer_count = 8;
pm->buffer_position = 0;
@@ -2519,7 +3013,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
break;
case modifier_signature:
- store_read_imp(&pm->this, pm->buffer, 13+12); /* size of IHDR */
+ store_read_chunk(&pm->this, pm->buffer, 13+12, 13+12); /* IHDR */
pm->buffer_count = 13+12;
pm->buffer_position = 0;
@@ -2560,7 +3054,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
{
if (cb > st) cb = st;
pm->flush -= cb;
- store_read_imp(&pm->this, pb, cb);
+ store_read_chunk(&pm->this, pb, cb, cb);
pb += cb;
st -= cb;
if (st == 0) return;
@@ -2577,7 +3071,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
pm->pending_chunk = 0;
}
else
- store_read_imp(&pm->this, pm->buffer, 8);
+ store_read_chunk(&pm->this, pm->buffer, 8, 8);
pm->buffer_count = 8;
pm->buffer_position = 0;
@@ -2643,8 +3137,8 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
*/
if (len+12 <= sizeof pm->buffer)
{
- store_read_imp(&pm->this, pm->buffer+pm->buffer_count,
- len+12-pm->buffer_count);
+ png_size_t s = len+12-pm->buffer_count;
+ store_read_chunk(&pm->this, pm->buffer+pm->buffer_count, s, s);
pm->buffer_count = len+12;
/* Check for a modification, else leave it be. */
@@ -2773,7 +3267,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
@@ -2833,7 +3327,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;
@@ -2857,7 +3351,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);
@@ -3185,13 +3679,58 @@ 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
- if (j > 0)
- png_set_tRNS(pp, pi, tRNS, j, 0/*color*/);
-# endif
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+ if (j > 0)
+ png_set_tRNS(pp, pi, tRNS, j, 0/*color*/);
+#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)
+ {
+ tRNS.red = random_u16();
+ tRNS.green = random_u16();
+ tRNS.blue = tRNS.red ^ tRNS.green;
+ tRNS.red &= mask;
+ tRNS.green &= mask;
+ tRNS.blue &= mask;
+ }
+
+ else /* bit_depth == 16 */
+ {
+ tRNS.red = random_u16();
+ tRNS.green = (png_uint_16)(tRNS.red * 257);
+ tRNS.blue = (png_uint_16)(tRNS.green * 17);
+ }
+ }
+
+ else
+ {
+ tRNS.gray = random_u16();
+ 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:
*/
@@ -3441,13 +3980,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
@@ -3457,17 +4000,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;
-/* Make a standardized image given a an image colour type, bit depth and
+ 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 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);
@@ -3478,7 +4111,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
@@ -3487,10 +4120,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
@@ -3525,11 +4158,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
{
@@ -3537,7 +4175,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))
@@ -3547,11 +4185,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);
}
}
@@ -3598,19 +4263,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;
@@ -3620,59 +4286,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.
*/
@@ -3698,17 +4318,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
@@ -3719,7 +4335,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);
@@ -3770,16 +4386,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
@@ -3787,7 +4400,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: */
@@ -3797,7 +4411,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,
@@ -3826,7 +4440,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
@@ -3840,15 +4455,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 (nfilter-- == 0)
- nfilter = PNG_FILTER_VALUE_LAST-1;
+ if (pass == 0 && y == 0 &&
+ (filters < PNG_FILTER_UP || w == 1U))
+ filters |= PNG_FILTER_UP;
+
+ png_set_filter(pp, 0/*method*/, filters);
+ }
# endif
png_write_row(pp, row);
@@ -3896,8 +4515,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)
{
@@ -3920,6 +4539,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
@@ -3993,41 +4617,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*/);
@@ -4039,6 +4667,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;
@@ -4059,45 +4689,77 @@ 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];
+
+ 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 */
+
+ png_write_row(pp, buffer);
+ }
}
- }
- }
+ } /* image writing */
- png_write_end(pp, pi);
+ png_write_end(pp, pi);
+ }
/* The following deletes the file that was just written. */
store_write_reset(ps);
@@ -4110,8 +4772,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)
{
@@ -4124,7 +4786,7 @@ 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<ARRAY_SIZE(error_test); ++test)
{
@@ -4171,7 +4833,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
@@ -4286,7 +4948,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
@@ -4327,6 +4991,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;
@@ -4619,14 +5284,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:
@@ -4647,8 +5312,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.
@@ -4730,7 +5406,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
@@ -4754,7 +5430,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);
}
@@ -4765,38 +5441,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)
@@ -4831,11 +5508,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
@@ -4982,14 +5659,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),
@@ -5002,19 +5671,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);
@@ -5059,7 +5721,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;
@@ -5147,8 +5809,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)
{
@@ -5158,7 +5820,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;
@@ -5193,8 +5855,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.
*
@@ -5203,8 +5865,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;
@@ -5230,34 +5894,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);
@@ -5265,6 +5951,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 */
}
}
@@ -5375,14 +6073,14 @@ image_pixel_setf(image_pixel *this, unsigned int rMax, unsigned int gMax,
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_CONST image_pixel *format /*from pngvalid transform of input*/)
+ 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;
- PNG_CONST int swap16 = (format != 0 && format->swap16);
- PNG_CONST int littleendian = (format != 0 && format->littleendian);
- PNG_CONST int sig_bits = (format != 0 && format->sig_bits);
+ 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
@@ -5400,7 +6098,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;
@@ -5476,6 +6174,9 @@ image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
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,
@@ -5505,10 +6206,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);
@@ -5517,11 +6222,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
@@ -5553,9 +6268,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
@@ -5565,18 +6282,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.
@@ -5589,7 +6307,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.
@@ -5597,12 +6315,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
@@ -5611,8 +6329,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
@@ -5620,7 +6338,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;
@@ -5630,7 +6348,8 @@ 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;
@@ -5672,7 +6391,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)
@@ -5680,7 +6399,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)
@@ -5707,11 +6426,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;
- PNG_CONST int sig_bits = that->sig_bits;
+ const unsigned int scale = (1U<<that->sample_depth)-1;
+ const int sig_bits = that->sig_bits;
UNUSED(this)
UNUSED(pp)
@@ -5802,17 +6521,18 @@ 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 */
@@ -5848,8 +6568,9 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop 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)
+ 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
@@ -5985,7 +6706,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
@@ -5996,7 +6717,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;
@@ -6022,6 +6743,8 @@ transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
png_error(pp, message);
}
+
+ UNUSED(limit)
}
static void
@@ -6029,20 +6752,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;
@@ -6097,7 +6820,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. */
@@ -6129,7 +6852,7 @@ 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 date, including output
+ /* This applies the transforms to the input data, including output
* format operations which must be used when reading the output
* pixel that libpng produces.
*/
@@ -6203,8 +6926,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);
@@ -6305,8 +7028,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);
@@ -6315,7 +7041,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)
@@ -6330,7 +7056,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);
@@ -6338,9 +7064,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);
@@ -6350,7 +7076,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)
@@ -6368,28 +7094,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
{
@@ -6398,13 +7138,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)
@@ -6413,9 +7154,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);
@@ -6426,17 +7172,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
@@ -6444,7 +7191,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)
@@ -6467,7 +7214,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)
@@ -6485,17 +7232,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)
@@ -6504,14 +7255,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)
@@ -6531,31 +7282,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);
@@ -6566,17 +7339,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.
@@ -6585,7 +7365,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;
@@ -6595,7 +7375,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)
@@ -6614,17 +7394,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)
{
@@ -6640,7 +7424,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)
@@ -6658,17 +7442,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)
{
@@ -6693,7 +7481,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;
@@ -6707,7 +7495,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)
@@ -6725,7 +7513,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);
@@ -6733,9 +7521,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;
@@ -6750,7 +7538,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)
@@ -6771,7 +7559,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
@@ -6808,11 +7597,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)
@@ -6827,7 +7616,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;
@@ -6844,9 +7633,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;
@@ -6880,7 +7675,7 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
png_uint_32 ru;
double total;
- RANDOMIZE(ru);
+ ru = random_u32();
data.green_coefficient = total = (ru & 0xffff) / 65535.;
ru >>= 16;
data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.;
@@ -6921,14 +7716,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.
*/
+# if PNG_LIBPNG_VER < 10700
+ if (that->this.bit_depth < 16)
+ that->max_gamma_8 = PNG_MAX_GAMMA_8;
+# endif
that->pm->limit += pow(
-# if PNG_MAX_GAMMA_8 < 14
- (that->this.bit_depth == 16 ? 8. :
- 6. + (1<<(15-PNG_MAX_GAMMA_8)))
-# else
- 8.
-# endif
- /65535, data.gamma);
+ (that->this.bit_depth == 16 || that->max_gamma_8 > 14 ?
+ 8. :
+ 6. + (1<<(15-that->max_gamma_8))
+ )/65535, data.gamma);
}
else
@@ -6940,14 +7736,12 @@ 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.25.
- * 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 += pow(
# if DIGITIZE
- 1.25
+ 2.0
# else
1.0
# endif
@@ -6966,10 +7760,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);
@@ -7006,7 +7800,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
@@ -7093,26 +7887,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;
@@ -7125,56 +7925,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
@@ -7184,32 +8001,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
@@ -7221,9 +8052,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)
{
@@ -7234,11 +8067,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;
@@ -7247,29 +8082,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
@@ -7280,10 +8132,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;
@@ -7304,7 +8156,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
@@ -7314,7 +8166,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;
@@ -7330,6 +8182,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.)
*/
@@ -7342,8 +8195,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 */
@@ -7370,7 +8225,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)
@@ -7401,7 +8256,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;
@@ -7414,7 +8269,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.
@@ -7429,6 +8284,9 @@ 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;
}
@@ -7439,7 +8297,7 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
/* 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)
{
@@ -7451,23 +8309,23 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
else
back.gray = (png_uint_16)data.red;
-# ifdef PNG_FLOATING_POINT_SUPPORTED
- png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
-# else
- png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
-# endif
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
+#else
+ png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
+#endif
this->next->set(this->next, that, pp, pi);
}
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)
@@ -7506,14 +8364,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);
}
@@ -7546,7 +8404,7 @@ IT(background);
* png_set_invert_alpha(png_structrp png_ptr)
*/
static void
-image_transform_png_set_invert_alpha_set(PNG_CONST image_transform *this,
+image_transform_png_set_invert_alpha_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_invert_alpha(pp);
@@ -7554,9 +8412,9 @@ image_transform_png_set_invert_alpha_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_invert_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_invert_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 & 4)
that->alpha_inverted = 1;
@@ -7566,7 +8424,7 @@ image_transform_png_set_invert_alpha_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_invert_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)
@@ -7592,7 +8450,7 @@ IT(invert_alpha);
* This only has an effect on RGB and RGBA pixels.
*/
static void
-image_transform_png_set_bgr_set(PNG_CONST image_transform *this,
+image_transform_png_set_bgr_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_bgr(pp);
@@ -7600,9 +8458,9 @@ image_transform_png_set_bgr_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_bgr_mod(PNG_CONST image_transform *this,
+image_transform_png_set_bgr_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_RGB ||
that->colour_type == PNG_COLOR_TYPE_RGBA)
@@ -7613,7 +8471,7 @@ image_transform_png_set_bgr_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_bgr_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)
@@ -7639,7 +8497,7 @@ IT(bgr);
* This only has an effect on GA and RGBA pixels.
*/
static void
-image_transform_png_set_swap_alpha_set(PNG_CONST image_transform *this,
+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);
@@ -7647,9 +8505,9 @@ image_transform_png_set_swap_alpha_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_swap_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_swap_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_GA ||
that->colour_type == PNG_COLOR_TYPE_RGBA)
@@ -7660,7 +8518,7 @@ image_transform_png_set_swap_alpha_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_swap_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)
@@ -7684,7 +8542,7 @@ IT(swap_alpha);
* png_set_swap(png_structrp png_ptr)
*/
static void
-image_transform_png_set_swap_set(PNG_CONST image_transform *this,
+image_transform_png_set_swap_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_swap(pp);
@@ -7692,9 +8550,9 @@ image_transform_png_set_swap_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_swap_mod(PNG_CONST image_transform *this,
+image_transform_png_set_swap_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)
that->swap16 = 1;
@@ -7704,7 +8562,7 @@ image_transform_png_set_swap_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_swap_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)
@@ -7738,14 +8596,14 @@ static struct
} data;
static void
-image_transform_png_set_filler_set(PNG_CONST image_transform *this,
+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.
*/
- RANDOMIZE(data.filler);
+ data.filler = random_u32();
data.flags = random_choice();
png_set_filler(pp, data.filler, data.flags);
@@ -7759,15 +8617,15 @@ image_transform_png_set_filler_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_filler_mod(PNG_CONST image_transform *this,
+image_transform_png_set_filler_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 >= 8 &&
(that->colour_type == PNG_COLOR_TYPE_RGB ||
that->colour_type == PNG_COLOR_TYPE_GRAY))
{
- PNG_CONST unsigned int max = (1U << that->bit_depth)-1;
+ const unsigned int max = (1U << that->bit_depth)-1;
that->alpha = data.filler & max;
that->alphaf = ((double)that->alpha) / max;
that->alphae = 0;
@@ -7787,7 +8645,7 @@ image_transform_png_set_filler_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_filler_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)
{
this->next = *that;
*that = this;
@@ -7811,14 +8669,14 @@ static struct
} data;
static void
-image_transform_png_set_add_alpha_set(PNG_CONST image_transform *this,
+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.
*/
- RANDOMIZE(data.filler);
+ data.filler = random_u32();
data.flags = random_choice();
png_set_add_alpha(pp, data.filler, data.flags);
@@ -7826,15 +8684,15 @@ image_transform_png_set_add_alpha_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_add_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_add_alpha_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 >= 8 &&
(that->colour_type == PNG_COLOR_TYPE_RGB ||
that->colour_type == PNG_COLOR_TYPE_GRAY))
{
- PNG_CONST unsigned int max = (1U << that->bit_depth)-1;
+ const unsigned int max = (1U << that->bit_depth)-1;
that->alpha = data.filler & max;
that->alphaf = ((double)that->alpha) / max;
that->alphae = 0;
@@ -7848,7 +8706,7 @@ image_transform_png_set_add_alpha_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_add_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)
{
this->next = *that;
*that = this;
@@ -7874,7 +8732,7 @@ IT(add_alpha);
* per pixel.
*/
static void
-image_transform_png_set_packing_set(PNG_CONST image_transform *this,
+image_transform_png_set_packing_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_packing(pp);
@@ -7883,9 +8741,9 @@ image_transform_png_set_packing_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_packing_mod(PNG_CONST image_transform *this,
+image_transform_png_set_packing_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,
* low bit-depth pixel values are unpacked into bytes without
@@ -7899,7 +8757,7 @@ image_transform_png_set_packing_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_packing_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)
@@ -7924,17 +8782,18 @@ IT(packing);
* png_set_packswap(png_structrp png_ptr)
*/
static void
-image_transform_png_set_packswap_set(PNG_CONST image_transform *this,
+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(PNG_CONST image_transform *this,
+image_transform_png_set_packswap_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 < 8)
that->littleendian = 1;
@@ -7944,7 +8803,7 @@ image_transform_png_set_packswap_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_packswap_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)
@@ -7968,7 +8827,7 @@ IT(packswap);
* png_set_invert_mono(png_structrp png_ptr)
*/
static void
-image_transform_png_set_invert_mono_set(PNG_CONST image_transform *this,
+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);
@@ -7976,9 +8835,9 @@ image_transform_png_set_invert_mono_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_invert_mono_mod(PNG_CONST image_transform *this,
+image_transform_png_set_invert_mono_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 & 4)
that->mono_inverted = 1;
@@ -7988,7 +8847,7 @@ image_transform_png_set_invert_mono_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_invert_mono_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)
@@ -8015,7 +8874,7 @@ IT(invert_mono);
static png_color_8 data;
static void
-image_transform_png_set_shift_set(PNG_CONST image_transform *this,
+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
@@ -8024,7 +8883,7 @@ image_transform_png_set_shift_set(PNG_CONST image_transform *this,
* field is randomized independently. This acts as a check that
* libpng does use the correct field.
*/
- PNG_CONST unsigned int depth = that->this.bit_depth;
+ 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);
@@ -8037,9 +8896,9 @@ image_transform_png_set_shift_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_shift_mod(PNG_CONST image_transform *this,
+image_transform_png_set_shift_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
/* Copy the correct values into the sBIT fields, libpng does not do
* anything to palette data:
@@ -8070,7 +8929,7 @@ image_transform_png_set_shift_mod(PNG_CONST image_transform *this,
static int
image_transform_png_set_shift_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)
@@ -8088,7 +8947,7 @@ IT(shift);
#ifdef THIS_IS_THE_PROFORMA
static void
-image_transform_png_set_@_set(PNG_CONST image_transform *this,
+image_transform_png_set_@_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_@(pp);
@@ -8096,16 +8955,16 @@ image_transform_png_set_@_set(PNG_CONST image_transform *this,
}
static void
-image_transform_png_set_@_mod(PNG_CONST image_transform *this,
+image_transform_png_set_@_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ 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, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
this->next = *that;
*that = this;
@@ -8118,10 +8977,10 @@ IT(@);
/* This may just be 'end' if all the transforms are disabled! */
-static image_transform *PNG_CONST image_transform_first = &PT;
+static image_transform *const image_transform_first = &PT;
static void
-transform_enable(PNG_CONST char *name)
+transform_enable(const char *name)
{
/* Everything starts out enabled, so if we see an 'enable' disabled
* everything else the first time round.
@@ -8154,7 +9013,7 @@ transform_enable(PNG_CONST char *name)
}
static void
-transform_disable(PNG_CONST char *name)
+transform_disable(const char *name)
{
image_transform *list = image_transform_first;
@@ -8217,7 +9076,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)
{
@@ -8301,7 +9160,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;
@@ -8312,7 +9172,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.
@@ -8373,11 +9233,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 */
@@ -8409,7 +9269,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
@@ -8441,9 +9301,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
@@ -8489,9 +9349,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
@@ -8565,7 +9425,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;
@@ -8604,13 +9464,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 */
@@ -8634,7 +9496,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)
@@ -8724,15 +9586,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;
@@ -9297,14 +10159,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
@@ -9345,11 +10207,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;
@@ -9365,6 +10228,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
@@ -9395,18 +10259,18 @@ 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 =
+ const unsigned int in_index =
in_ct == 3 ? sample(std, 3, in_bd, x, 0, 0, 0) : 256;
- PNG_CONST unsigned int out_index =
+ 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, 0, 0);
@@ -9436,6 +10300,35 @@ 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,
@@ -9502,15 +10395,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);
@@ -9545,7 +10438,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);
@@ -9684,9 +10577,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)
@@ -9709,11 +10606,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];
@@ -9746,7 +10643,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;
@@ -9776,7 +10674,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)))
@@ -9811,7 +10710,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.
@@ -9864,12 +10767,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;
@@ -9967,8 +10870,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.
*/
@@ -10017,9 +10929,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;
@@ -10238,7 +11159,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 },
@@ -10505,23 +11426,36 @@ perform_interlace_macro_validation(void)
*/
for (v=0;;)
{
+ /* The first two tests overflow if the pass row or column is outside
+ * the possible range for a 32-bit result. In fact the values should
+ * never be outside the range for a 31-bit result, but checking for 32
+ * bits here ensures that if an app uses a bogus pass row or column
+ * (just so long as it fits in a 32 bit integer) it won't get a
+ * possibly dangerous overflow.
+ */
/* First the base 0 stuff: */
- m = PNG_ROW_FROM_PASS_ROW(v, pass);
- f = png_row_from_pass_row(v, pass);
- if (m != f)
+ if (v < png_pass_rows(0xFFFFFFFFU, pass))
{
- fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n",
- v, pass, m, f);
- exit(99);
+ m = PNG_ROW_FROM_PASS_ROW(v, pass);
+ f = png_row_from_pass_row(v, pass);
+ if (m != f)
+ {
+ fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n",
+ v, pass, m, f);
+ exit(99);
+ }
}
- m = PNG_COL_FROM_PASS_COL(v, pass);
- f = png_col_from_pass_col(v, pass);
- if (m != f)
+ if (v < png_pass_cols(0xFFFFFFFFU, pass))
{
- fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n",
- v, pass, m, f);
- exit(99);
+ m = PNG_COL_FROM_PASS_COL(v, pass);
+ f = png_col_from_pass_col(v, pass);
+ if (m != f)
+ {
+ fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n",
+ v, pass, m, f);
+ exit(99);
+ }
}
m = PNG_ROW_IN_INTERLACE_PASS(v, pass);
@@ -10589,7 +11523,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,
@@ -10611,6 +11545,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
@@ -10682,11 +11621,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.)
@@ -10702,6 +11641,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);
@@ -10751,11 +11694,27 @@ int main(int argc, char **argv)
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 = 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
@@ -10781,7 +11740,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
@@ -10811,7 +11774,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)
@@ -10863,7 +11830,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;
}
@@ -10912,6 +11879,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;
@@ -10926,12 +11911,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)
@@ -11009,12 +11994,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;
@@ -11102,7 +12093,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)
diff --git a/libpng/contrib/libtests/readpng.c b/libpng/contrib/libtests/readpng.c
index 7ba46d0b9..3336d4e21 100644
--- a/libpng/contrib/libtests/readpng.c
+++ b/libpng/contrib/libtests/readpng.c
@@ -62,6 +62,7 @@ read_png(FILE *fp)
{
png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ /* Failure to initialize these is harmless */
row = malloc(rowbytes);
display = malloc(rowbytes);
@@ -70,7 +71,12 @@ read_png(FILE *fp)
{
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
- int passes = png_set_interlace_handling(png_ptr);
+# ifdef PNG_READ_INTERLACING_SUPPORTED
+ int passes = png_set_interlace_handling(png_ptr);
+# else /* !READ_INTERLACING */
+ int passes = png_get_interlace_type(png_ptr, info_ptr) ==
+ PNG_INTERLACE_ADAM7 ? PNG_INTERLACE_ADAM7_PASSES : 1;
+# endif /* !READ_INTERLACING */
int pass;
png_start_read_image(png_ptr);
@@ -79,6 +85,11 @@ read_png(FILE *fp)
{
png_uint_32 y = height;
+# ifndef PNG_READ_INTERLACING_SUPPORTED
+ if (passes == PNG_INTERLACE_ADAM7_PASSES)
+ y = PNG_PASS_ROWS(y, pass);
+# endif /* READ_INTERLACING */
+
/* NOTE: this trashes the row each time; interlace handling won't
* work, but this avoids memory thrashing for speed testing.
*/
diff --git a/libpng/contrib/libtests/tarith.c b/libpng/contrib/libtests/tarith.c
index cdb00dbf7..cb17ffa76 100644
--- a/libpng/contrib/libtests/tarith.c
+++ b/libpng/contrib/libtests/tarith.c
@@ -634,7 +634,7 @@ int validation_muldiv(int count, int argc, char **argv)
{
png_fixed_point result;
/* NOTE: your mileage may vary, a type is required below that can
- * hold 64 bits or more, if floating point is used a 64 bit or
+ * hold 64 bits or more, if floating point is used a 64-bit or
* better mantissa is required.
*/
long long int fp, fpround;
@@ -721,7 +721,7 @@ int validation_muldiv(int count, int argc, char **argv)
}
while (--count > 0);
- printf("%d tests including %d overflows, %d passed, %d failed (%d 64 bit "
+ printf("%d tests including %d overflows, %d passed, %d failed (%d 64-bit "
"errors)\n", tested, overflow, passed, error, error64);
return 0;
}
@@ -799,13 +799,13 @@ int validation_gamma(int argc, char **argv)
if (i == 0 && png_log8bit(i) != 0xffffffff ||
i != 0 && png_log8bit(i) != floor(correct+.5))
{
- fprintf(stderr, "8 bit log error: %d: got %u, expected %f\n",
+ fprintf(stderr, "8-bit log error: %d: got %u, expected %f\n",
i, png_log8bit(i), correct);
}
}
if (!silent)
- printf("maximum 8 bit log error = %f\n", maxerr);
+ printf("maximum 8-bit log error = %f\n", maxerr);
maxerr = 0;
for (i=0; i<65536; ++i)
@@ -821,14 +821,14 @@ int validation_gamma(int argc, char **argv)
{
if (error > .68) /* By experiment error is less than .68 */
{
- fprintf(stderr, "16 bit log error: %d: got %u, expected %f"
+ fprintf(stderr, "16-bit log error: %d: got %u, expected %f"
" error: %f\n", i, png_log16bit(i), correct, error);
}
}
}
if (!silent)
- printf("maximum 16 bit log error = %f\n", maxerr);
+ printf("maximum 16-bit log error = %f\n", maxerr);
/* Now exponentiations. */
maxerr = 0;
@@ -841,13 +841,13 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > 1883) /* By experiment. */
{
- fprintf(stderr, "32 bit exp error: %d: got %u, expected %f"
+ fprintf(stderr, "32-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp(i), correct, error);
}
}
if (!silent)
- printf("maximum 32 bit exp error = %f\n", maxerr);
+ printf("maximum 32-bit exp error = %f\n", maxerr);
maxerr = 0;
for (i=0; i<=0xfffff; ++i)
@@ -859,13 +859,13 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > .50002) /* By experiment */
{
- fprintf(stderr, "8 bit exp error: %d: got %u, expected %f"
+ fprintf(stderr, "8-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp8bit(i), correct, error);
}
}
if (!silent)
- printf("maximum 8 bit exp error = %f\n", maxerr);
+ printf("maximum 8-bit exp error = %f\n", maxerr);
maxerr = 0;
for (i=0; i<=0xfffff; ++i)
@@ -877,13 +877,13 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > .524) /* By experiment */
{
- fprintf(stderr, "16 bit exp error: %d: got %u, expected %f"
+ fprintf(stderr, "16-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp16bit(i), correct, error);
}
}
if (!silent)
- printf("maximum 16 bit exp error = %f\n", maxerr);
+ printf("maximum 16-bit exp error = %f\n", maxerr);
} /* !onlygamma */
/* Test the overall gamma correction. */
@@ -913,7 +913,7 @@ int validation_gamma(int argc, char **argv)
}
if (!silent)
- printf("gamma %f: maximum 8 bit error %f\n", g, maxerr);
+ printf("gamma %f: maximum 8-bit error %f\n", g, maxerr);
maxerr = 0;
for (j=0; j<65536; ++j)
@@ -932,7 +932,7 @@ int validation_gamma(int argc, char **argv)
}
if (!silent)
- printf("gamma %f: maximum 16 bit error %f\n", g, maxerr);
+ printf("gamma %f: maximum 16-bit error %f\n", g, maxerr);
}
return 0;
diff --git a/libpng/contrib/libtests/timepng.c b/libpng/contrib/libtests/timepng.c
index 7c937971c..3bcfde5a3 100644
--- a/libpng/contrib/libtests/timepng.c
+++ b/libpng/contrib/libtests/timepng.c
@@ -1,8 +1,8 @@
/* timepng.c
*
- * Copyright (c) 2013 John Cunningham Bowler
+ * Copyright (c) 2013,2016 John Cunningham Bowler
*
- * Last changed in libpng 1.6.1 [March 28, 2013]
+ * Last changed in libpng 1.6.22 [May 26, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -10,15 +10,17 @@
*
* Load an arbitrary number of PNG files (from the command line, or, if there
* are no arguments on the command line, from stdin) then run a time test by
- * reading each file by row. The test does nothing with the read result and
- * does no transforms. The only output is a time as a floating point number of
- * seconds with 9 decimal digits.
+ * reading each file by row or by image (possibly with transforms in the latter
+ * case). The only output is a time as a floating point number of seconds with
+ * 9 decimal digits.
*/
#define _POSIX_C_SOURCE 199309L /* for clock_gettime */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
+#include <limits.h>
#include <time.h>
@@ -35,36 +37,73 @@
# include "../../png.h"
#endif
-static int read_png(FILE *fp)
+/* The following is to support direct compilation of this file as C++ */
+#ifdef __cplusplus
+# define voidcast(type, value) static_cast<type>(value)
+#else
+# define voidcast(type, value) (value)
+#endif /* __cplusplus */
+
+/* 'CLOCK_PROCESS_CPUTIME_ID' is one of the clock timers for clock_gettime. It
+ * need not be supported even when clock_gettime is available. It returns the
+ * 'CPU' time the process has consumed. 'CPU' time is assumed to include time
+ * when the CPU is actually blocked by a pending cache fill but not time
+ * waiting for page faults. The attempt is to get a measure of the actual time
+ * the implementation takes to read a PNG ignoring the potentially very large IO
+ * overhead.
+ */
+#if defined (CLOCK_PROCESS_CPUTIME_ID) && defined(PNG_STDIO_SUPPORTED) &&\
+ defined(PNG_EASY_ACCESS_SUPPORTED) &&\
+ (PNG_LIBPNG_VER >= 10700 ? defined(PNG_READ_PNG_SUPPORTED) :\
+ defined (PNG_SEQUENTIAL_READ_SUPPORTED) &&\
+ defined(PNG_INFO_IMAGE_SUPPORTED))
+
+typedef struct
{
- png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
- png_infop info_ptr = NULL;
- png_bytep row = NULL, display = NULL;
+ FILE *input;
+ FILE *output;
+} io_data;
- if (png_ptr == NULL)
- return 0;
+static PNG_CALLBACK(void, read_and_copy,
+ (png_structp png_ptr, png_bytep buffer, png_size_t cb))
+{
+ io_data *io = (io_data*)png_get_io_ptr(png_ptr);
- if (setjmp(png_jmpbuf(png_ptr)))
+ if (fread(buffer, cb, 1, io->input) != 1)
+ png_error(png_ptr, strerror(errno));
+
+ if (fwrite(buffer, cb, 1, io->output) != 1)
{
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (row != NULL) free(row);
- if (display != NULL) free(display);
- return 0;
+ perror("temporary file");
+ fprintf(stderr, "temporary file PNG write failed\n");
+ exit(1);
}
+}
- png_init_io(png_ptr, fp);
+static void read_by_row(png_structp png_ptr, png_infop info_ptr,
+ FILE *write_ptr, FILE *read_ptr)
+{
+ /* These don't get freed on error, this is fine; the program immediately
+ * exits.
+ */
+ png_bytep row = NULL, display = NULL;
+ io_data io_copy;
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL)
- png_error(png_ptr, "OOM allocating info structure");
+ if (write_ptr != NULL)
+ {
+ /* Set up for a copy to the temporary file: */
+ io_copy.input = read_ptr;
+ io_copy.output = write_ptr;
+ png_set_read_fn(png_ptr, &io_copy, read_and_copy);
+ }
png_read_info(png_ptr, info_ptr);
{
png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
- row = malloc(rowbytes);
- display = malloc(rowbytes);
+ row = voidcast(png_bytep,malloc(rowbytes));
+ display = voidcast(png_bytep,malloc(rowbytes));
if (row == NULL || display == NULL)
png_error(png_ptr, "OOM allocating row buffers");
@@ -81,7 +120,8 @@ static int read_png(FILE *fp)
png_uint_32 y = height;
/* NOTE: this trashes the row each time; interlace handling won't
- * work, but this avoids memory thrashing for speed testing.
+ * work, but this avoids memory thrashing for speed testing and is
+ * somewhat representative of an application that works row-by-row.
*/
while (y-- > 0)
png_read_row(png_ptr, row, display);
@@ -91,9 +131,51 @@ static int read_png(FILE *fp)
/* Make sure to read to the end of the file: */
png_read_end(png_ptr, info_ptr);
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ /* Free this up: */
free(row);
free(display);
+}
+
+static PNG_CALLBACK(void, no_warnings, (png_structp png_ptr,
+ png_const_charp warning))
+{
+ (void)png_ptr;
+ (void)warning;
+}
+
+static int read_png(FILE *fp, png_int_32 transforms, FILE *write_file)
+{
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,
+ no_warnings);
+ png_infop info_ptr = NULL;
+
+ if (png_ptr == NULL)
+ return 0;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return 0;
+ }
+
+# ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ png_set_benign_errors(png_ptr, 1/*allowed*/);
+# endif
+ 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");
+
+ if (transforms < 0)
+ read_by_row(png_ptr, info_ptr, write_file, fp);
+
+ else
+ png_read_png(png_ptr, info_ptr, transforms, NULL/*params*/);
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 1;
}
@@ -108,7 +190,7 @@ static int mytime(struct timespec *t)
return 0;
}
-static int perform_one_test(FILE *fp, int nfiles)
+static int perform_one_test(FILE *fp, int nfiles, png_int_32 transforms)
{
int i;
struct timespec before, after;
@@ -120,7 +202,7 @@ static int perform_one_test(FILE *fp, int nfiles)
{
for (i=0; i<nfiles; ++i)
{
- if (read_png(fp))
+ if (read_png(fp, transforms, NULL/*write*/))
{
if (ferror(fp))
{
@@ -184,120 +266,343 @@ static int add_one_file(FILE *fp, char *name)
if (ip != NULL)
{
- int ch;
- for (;;)
+ /* Read the file using libpng; this detects errors and also deals with
+ * files which contain data beyond the end of the file.
+ */
+ int ok = 0;
+ fpos_t pos;
+
+ if (fgetpos(fp, &pos))
{
- ch = getc(ip);
- if (ch == EOF) break;
- putc(ch, fp);
+ /* Fatal error reading the start: */
+ perror("temporary file");
+ fprintf(stderr, "temporary file fgetpos error\n");
+ exit(1);
}
- if (ferror(ip))
+ if (read_png(ip, -1/*by row*/, fp/*output*/))
{
- perror(name);
- fprintf(stderr, "%s: read error\n", name);
- return 0;
+ if (ferror(ip))
+ {
+ perror(name);
+ fprintf(stderr, "%s: read error\n", name);
+ }
+
+ else
+ ok = 1; /* read ok */
}
+ else
+ fprintf(stderr, "%s: file not added\n", name);
+
(void)fclose(ip);
+ /* An error in the output is fatal; exit immediately: */
if (ferror(fp))
{
perror("temporary file");
fprintf(stderr, "temporary file write error\n");
- return 0;
+ exit(1);
+ }
+
+ if (ok)
+ return 1;
+
+ /* Did not read the file successfully, simply rewind the temporary
+ * file. This must happen after the ferror check above to avoid clearing
+ * the error.
+ */
+ if (fsetpos(fp, &pos))
+ {
+ perror("temporary file");
+ fprintf(stderr, "temporary file fsetpos error\n");
+ exit(1);
}
}
else
{
+ /* file open error: */
perror(name);
fprintf(stderr, "%s: open failed\n", name);
- return 0;
}
- return 1;
+ return 0; /* file not added */
+}
+
+static void
+usage(FILE *fp)
+{
+ if (fp != NULL) fclose(fp);
+
+ fprintf(stderr,
+"Usage:\n"
+" timepng --assemble <assembly> {files}\n"
+" Read the files into <assembly>, output the count. Options are ignored.\n"
+" timepng --dissemble <assembly> <count> [options]\n"
+" Time <count> files from <assembly>, additional files may not be given.\n"
+" Otherwise:\n"
+" Read the files into a temporary file and time the decode\n"
+"Transforms:\n"
+" --by-image: read by image with png_read_png\n"
+" --<transform>: implies by-image, use PNG_TRANSFORM_<transform>\n"
+" Otherwise: read by row using png_read_row (to a single row buffer)\n"
+ /* ISO C90 string length max 509 */);fprintf(stderr,
+"{files}:\n"
+" PNG files to copy into the assembly and time. Invalid files are skipped\n"
+" with appropriate error messages. If no files are given the list of files\n"
+" is read from stdin with each file name terminated by a newline\n"
+"Output:\n"
+" For --assemble the output is the name of the assembly file followed by the\n"
+" count of the files it contains; the arguments for --dissemble. Otherwise\n"
+" the output is the total decode time in seconds.\n");
+
+ exit(99);
}
int main(int argc, char **argv)
{
int ok = 0;
- FILE *fp = tmpfile();
+ int err = 0;
+ int nfiles = 0;
+ int transforms = -1; /* by row */
+ const char *assembly = NULL;
+ FILE *fp;
+
+ if (argc > 2 && strcmp(argv[1], "--assemble") == 0)
+ {
+ /* Just build the test file, argv[2] is the file name. */
+ assembly = argv[2];
+ fp = fopen(assembly, "wb");
+ if (fp == NULL)
+ {
+ perror(assembly);
+ fprintf(stderr, "timepng --assemble %s: could not open for write\n",
+ assembly);
+ usage(NULL);
+ }
+
+ argv += 2;
+ argc -= 2;
+ }
- if (fp != NULL)
+ else if (argc > 3 && strcmp(argv[1], "--dissemble") == 0)
{
- int err = 0;
- int nfiles = 0;
+ fp = fopen(argv[2], "rb");
- if (argc > 1)
+ if (fp == NULL)
{
- int i;
+ perror(argv[2]);
+ fprintf(stderr, "timepng --dissemble %s: could not open for read\n",
+ argv[2]);
+ usage(NULL);
+ }
- for (i=1; i<argc; ++i)
- {
- if (add_one_file(fp, argv[i]))
- ++nfiles;
+ nfiles = atoi(argv[3]);
+ if (nfiles <= 0)
+ {
+ fprintf(stderr,
+ "timepng --dissemble <file> <count>: %s is not a count\n",
+ argv[3]);
+ exit(99);
+ }
+#ifdef __COVERITY__
+ else
+ {
+ nfiles &= PNG_UINT_31_MAX;
+ }
+#endif
- else
- {
- err = 1;
- break;
- }
- }
+ argv += 3;
+ argc -= 3;
+ }
+
+ else /* Else use a temporary file */
+ {
+#ifndef __COVERITY__
+ fp = tmpfile();
+#else
+ /* Experimental. Coverity says tmpfile() is insecure because it
+ * generates predictable names.
+ *
+ * It is possible to satisfy Coverity by using mkstemp(); however,
+ * any platform supporting mkstemp() undoubtedly has a secure tmpfile()
+ * implementation as well, and doesn't need the fix. Note that
+ * the fix won't work on platforms that don't support mkstemp().
+ *
+ * https://www.securecoding.cert.org/confluence/display/c/
+ * FIO21-C.+Do+not+create+temporary+files+in+shared+directories
+ * says that most historic implementations of tmpfile() provide
+ * only a limited number of possible temporary file names
+ * (usually 26) before file names are recycled. That article also
+ * provides a secure solution that unfortunately depends upon mkstemp().
+ */
+ char tmpfile[] = "timepng-XXXXXX";
+ int filedes;
+ umask(0177);
+ filedes = mkstemp(tmpfile);
+ if (filedes < 0)
+ fp = NULL;
+ else
+ {
+ fp = fdopen(filedes,"w+");
+ /* Hide the filename immediately and ensure that the file does
+ * not exist after the program ends
+ */
+ (void) unlink(tmpfile);
}
+#endif
+
+ if (fp == NULL)
+ {
+ perror("tmpfile");
+ fprintf(stderr, "timepng: could not open the temporary file\n");
+ exit(1); /* not a user error */
+ }
+ }
+
+ /* Handle the transforms: */
+ while (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-')
+ {
+ const char *opt = *++argv + 2;
+
+ --argc;
+
+ /* Transforms turn on the by-image processing and maybe set some
+ * transforms:
+ */
+ if (transforms == -1)
+ transforms = PNG_TRANSFORM_IDENTITY;
+
+ if (strcmp(opt, "by-image") == 0)
+ {
+ /* handled above */
+ }
+
+# define OPT(name) else if (strcmp(opt, #name) == 0)\
+ transforms |= PNG_TRANSFORM_ ## name
+
+ OPT(STRIP_16);
+ OPT(STRIP_ALPHA);
+ OPT(PACKING);
+ OPT(PACKSWAP);
+ OPT(EXPAND);
+ OPT(INVERT_MONO);
+ OPT(SHIFT);
+ OPT(BGR);
+ OPT(SWAP_ALPHA);
+ OPT(SWAP_ENDIAN);
+ OPT(INVERT_ALPHA);
+ OPT(STRIP_FILLER);
+ OPT(STRIP_FILLER_BEFORE);
+ OPT(STRIP_FILLER_AFTER);
+ OPT(GRAY_TO_RGB);
+ OPT(EXPAND_16);
+ OPT(SCALE_16);
else
{
- char filename[FILENAME_MAX+1];
+ fprintf(stderr, "timepng %s: unrecognized transform\n", opt);
+ usage(fp);
+ }
+ }
+
+ /* Handle the files: */
+ if (argc > 1 && nfiles > 0)
+ usage(fp); /* Additional files not valid with --dissemble */
+
+ else if (argc > 1)
+ {
+ int i;
- while (fgets(filename, FILENAME_MAX+1, stdin))
+ for (i=1; i<argc; ++i)
+ {
+ if (nfiles == INT_MAX)
{
- size_t len = strlen(filename);
+ fprintf(stderr, "%s: skipped, too many files\n", argv[i]);
+ break;
+ }
- if (filename[len-1] == '\n')
- {
- filename[len-1] = 0;
- if (add_one_file(fp, filename))
- ++nfiles;
-
- else
- {
- err = 1;
- break;
- }
- }
+ else if (add_one_file(fp, argv[i]))
+ ++nfiles;
+ }
+ }
- else
+ else if (nfiles == 0) /* Read from stdin withoout --dissemble */
+ {
+ char filename[FILENAME_MAX+1];
+
+ while (fgets(filename, FILENAME_MAX+1, stdin))
+ {
+ size_t len = strlen(filename);
+
+ if (filename[len-1] == '\n')
+ {
+ filename[len-1] = 0;
+ if (nfiles == INT_MAX)
{
- fprintf(stderr, "timepng: truncated file name ...%s\n",
- filename+len-32);
- err = 1;
+ fprintf(stderr, "%s: skipped, too many files\n", filename);
break;
}
+
+ else if (add_one_file(fp, filename))
+ ++nfiles;
}
- if (ferror(stdin))
+ else
{
- fprintf(stderr, "timepng: stdin: read error\n");
+ fprintf(stderr, "timepng: file name too long: ...%s\n",
+ filename+len-32);
err = 1;
+ break;
}
}
- if (!err)
+ if (ferror(stdin))
+ {
+ fprintf(stderr, "timepng: stdin: read error\n");
+ err = 1;
+ }
+ }
+
+ /* Perform the test, or produce the --assemble output: */
+ if (!err)
+ {
+ if (nfiles > 0)
{
- if (nfiles > 0)
- ok = perform_one_test(fp, nfiles);
+ if (assembly != NULL)
+ {
+ if (fflush(fp) && !ferror(fp) && fclose(fp))
+ {
+ perror(assembly);
+ fprintf(stderr, "%s: close failed\n", assembly);
+ }
+
+ else
+ {
+ printf("%s %d\n", assembly, nfiles);
+ fflush(stdout);
+ ok = !ferror(stdout);
+ }
+ }
else
- fprintf(stderr, "usage: timepng {files} or ls files | timepng\n");
+ {
+ ok = perform_one_test(fp, nfiles, transforms);
+ (void)fclose(fp);
+ }
}
- (void)fclose(fp);
+ else
+ usage(fp);
}
else
- fprintf(stderr, "timepng: could not open temporary file\n");
+ (void)fclose(fp);
/* Exit code 0 on success. */
return ok == 0;
}
+#else /* !sufficient support */
+int main(void) { return 77; }
+#endif /* !sufficient support */
diff --git a/libpng/contrib/mips-msa/README b/libpng/contrib/mips-msa/README
new file mode 100644
index 000000000..10acc9364
--- /dev/null
+++ b/libpng/contrib/mips-msa/README
@@ -0,0 +1,83 @@
+OPERATING SYSTEM SPECIFIC MIPS MSA DETECTION
+--------------------------------------------
+
+Detection of the ability to execute MIPS MSA on an MIPS processor requires
+operating system support. (The information is not available in user mode.)
+
+HOW TO USE THIS
+---------------
+
+This directory contains C code fragments that can be included in mips/mips_init.c
+by setting the macro PNG_MIPS_MSA_FILE to the file name in "" or <> at build
+time. This setting is not recorded in pnglibconf.h and can be changed simply by
+rebuilding mips/msa_init.o with the required macro definition.
+
+For any of this code to be used the MIPS MSA code must be enabled and run time
+checks must be supported. I.e.:
+
+#if PNG_MIPS_MSA_OPT > 0
+#ifdef PNG_MIPS_MSA_CHECK_SUPPORTED
+
+This is done in a 'configure' build by passing configure the argument:
+
+ --enable-mips-msa=check
+
+Apart from the basic Linux implementation in contrib/mips-msa/linux.c this code
+is unsupported. That means that it is not even compiled on a regular basis and
+may be broken in any given minor release.
+
+FILE FORMAT
+-----------
+
+Each file documents its testing status as of the last time it was tested (which
+may have been a long time ago):
+
+STATUS: one of:
+ SUPPORTED: This indicates that the file is included in the regularly
+ performed test builds and bugs are fixed when discovered.
+ COMPILED: This indicates that the code did compile at least once. See the
+ more detailed description for the extent to which the result was
+ successful.
+ TESTED: This means the code was fully compiled into the libpng test programs
+ and these were run at least once.
+
+BUG REPORTS: an email address to which to send reports of problems
+
+The file is a fragment of C code. It should not define any 'extern' symbols;
+everything should be static. It must define the function:
+
+static int png_have_msa(png_structp png_ptr);
+
+That function must return 1 if MIPS MSA instructions are supported, 0 if not.
+It must not execute png_error unless it detects a bug. A png_error will prevent
+the reading of the PNG and in the future, writing too.
+
+BUG REPORTS
+-----------
+
+If you mail a bug report for any file that is not SUPPORTED there may only be
+limited response. Consider fixing it and sending a patch to fix the problem -
+this is more likely to result in action.
+
+CONTRIBUTIONS
+-------------
+
+You may send contributions of new implementations to
+png-mng-implement@sourceforge.net. Please write code in strict C90 C where
+possible. Obviously OS dependencies are to be expected. If you submit code you
+must have the authors permission and it must have a license that is acceptable
+to the current maintainer; in particular that license must permit modification
+and redistribution.
+
+Please try to make the contribution a single file and give the file a clear and
+unambiguous name that identifies the target OS. If multiple files really are
+required put them all in a sub-directory.
+
+You must also be prepared to handle bug reports from users of the code, either
+by joining the png-mng-implement mailing list or by providing an email for the
+"BUG REPORTS" entry or both. Please make sure that the header of the file
+contains the STATUS and BUG REPORTS fields as above.
+
+Please list the OS requirements as precisely as possible. Ideally you should
+also list the environment in which the code has been tested and certainly list
+any environments where you suspect it might not work.
diff --git a/libpng/contrib/mips-msa/linux.c b/libpng/contrib/mips-msa/linux.c
new file mode 100644
index 000000000..140215c4e
--- /dev/null
+++ b/libpng/contrib/mips-msa/linux.c
@@ -0,0 +1,64 @@
+/* contrib/mips-msa/linux.c
+ *
+ * Copyright (c) 2016 Glenn Randers-Pehrson
+ * Written by Mandar Sahastrabuddhe, 2016.
+ * Last changed in libpng 1.6.25beta03 [August 29, 2016]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * SEE contrib/mips-msa/README before reporting bugs
+ *
+ * STATUS: SUPPORTED
+ * BUG REPORTS: png-mng-implement@sourceforge.net
+ *
+ * png_have_msa implemented for Linux by reading the widely available
+ * pseudo-file /proc/cpuinfo.
+ *
+ * This code is strict ANSI-C and is probably moderately portable; it does
+ * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int
+png_have_msa(png_structp png_ptr)
+{
+ FILE *f = fopen("/proc/cpuinfo", "rb");
+
+ char *string = "msa";
+ char word[10];
+
+ if (f != NULL)
+ {
+ while(!feof(f))
+ {
+ int ch = fgetc(f);
+ static int i = 0;
+
+ while(!(ch <= 32))
+ {
+ word[i++] = ch;
+ ch = fgetc(f);
+ }
+
+ int val = strcmp(string, word);
+
+ if (val == 0)
+ return 1;
+
+ i = 0;
+ memset(word, 0, 10);
+ }
+
+ fclose(f);
+ }
+#ifdef PNG_WARNINGS_SUPPORTED
+ else
+ png_warning(png_ptr, "/proc/cpuinfo open failed");
+#endif
+ return 0;
+}
diff --git a/libpng/contrib/pngminus/README b/libpng/contrib/pngminus/README
index bbe7407ec..fbcfc9861 100644
--- a/libpng/contrib/pngminus/README
+++ b/libpng/contrib/pngminus/README
@@ -146,7 +146,7 @@ The Turbo bug
The end
-------
Willem van Schaik
-mailto:willem@schaik.com
+mailto:willem at schaik.com
http://www.schaik.com/png/
-------
Oct 1999
diff --git a/libpng/contrib/pngminus/png2pnm.c b/libpng/contrib/pngminus/png2pnm.c
index dff4d0b3d..995fddf37 100644
--- a/libpng/contrib/pngminus/png2pnm.c
+++ b/libpng/contrib/pngminus/png2pnm.c
@@ -1,6 +1,6 @@
/*
* png2pnm.c --- conversion from PNG-file to PGM/PPM-file
- * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
+ * copyright (C) 1999 by Willem van Schaik <willem at schaik.com>
*
* version 1.0 - 1999.10.15 - First version.
*
@@ -266,7 +266,7 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
png_set_expand (png_ptr);
#ifdef NJET
- /* downgrade 16-bit images to 8 bit */
+ /* downgrade 16-bit images to 8-bit */
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
/* transform grayscale images into full-color */
diff --git a/libpng/contrib/pngminus/pnm2png.c b/libpng/contrib/pngminus/pnm2png.c
index 7bf720f68..5de828a74 100644
--- a/libpng/contrib/pngminus/pnm2png.c
+++ b/libpng/contrib/pngminus/pnm2png.c
@@ -1,8 +1,9 @@
/*
* pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
- * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
+ * copyright (C) 1999 by Willem van Schaik <willem at schaik.com>
*
* version 1.0 - 1999.10.15 - First version.
+ * version 1.1 - 2015.07.29 - Fixed leaks (Glenn Randers-Pehrson)
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
@@ -200,17 +201,17 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
char width_token[16];
char height_token[16];
char maxval_token[16];
- volatile int color_type;
+ volatile int color_type=1;
unsigned long ul_width=0, ul_alpha_width=0;
unsigned long ul_height=0, ul_alpha_height=0;
unsigned long ul_maxval=0;
- volatile png_uint_32 width, height;
- volatile png_uint_32 alpha_width, alpha_height;
+ volatile png_uint_32 width=0, height=0;
+ volatile png_uint_32 alpha_width=0, alpha_height=0;
png_uint_32 maxval;
volatile int bit_depth = 0;
- int channels;
+ int channels=0;
int alpha_depth = 0;
- int alpha_present;
+ int alpha_present=0;
int row, col;
BOOL raw, alpha_raw = FALSE;
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
@@ -356,8 +357,10 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
channels = 3;
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
channels = 4;
+#if 0
else
- channels = 0; /* should not happen */
+ channels = 0; /* cannot happen */
+#endif
alpha_present = (channels - 1) % 2;
@@ -429,12 +432,16 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
NULL);
if (!png_ptr)
{
+ free (png_pixels);
+ png_pixels = NULL;
return FALSE;
}
info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
{
png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ free (png_pixels);
+ png_pixels = NULL;
return FALSE;
}
@@ -449,7 +456,9 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
/* setjmp() must be called in every function that calls a PNG-reading libpng function */
if (setjmp (png_jmpbuf(png_ptr)))
{
- png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ png_destroy_write_struct (&png_ptr, &info_ptr);
+ free (png_pixels);
+ png_pixels = NULL;
return FALSE;
}
@@ -470,7 +479,9 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
if ((row_pointers = (png_byte **)
malloc (height * sizeof (png_bytep))) == NULL)
{
- png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ png_destroy_write_struct (&png_ptr, &info_ptr);
+ free (png_pixels);
+ png_pixels = NULL;
return FALSE;
}
}
@@ -486,7 +497,7 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
png_write_end (png_ptr, info_ptr);
/* clean up after the write, and free any memory allocated */
- png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ png_destroy_write_struct (&png_ptr, &info_ptr);
if (row_pointers != (unsigned char**) NULL)
free (row_pointers);
diff --git a/libpng/contrib/pngsuite/README b/libpng/contrib/pngsuite/README
index ec4af9473..53ba5c8f7 100644
--- a/libpng/contrib/pngsuite/README
+++ b/libpng/contrib/pngsuite/README
@@ -1,8 +1,8 @@
pngsuite
--------
-(c) Willem van Schaik, 1999, 2011, 2012
-Two images are by Glenn Randers-Pehrson, 2012
+Copyright (c) Willem van Schaik, 1999, 2011, 2012
+Two images (ftbbn0g01.png and ftbbn0g02.png) are by Glenn Randers-Pehrson, 2012
Permission to use, copy, modify, and distribute these images for any
purpose and without fee is hereby granted.
@@ -101,5 +101,5 @@ Testing basn6a16.png: PASS (1072 zero samples)
libpng passes test
Willem van Schaik
-<willem@schaik.com>
+<willem at schaik.com>
October 1999
diff --git a/libpng/contrib/tools/README.txt b/libpng/contrib/tools/README.txt
index 5ddae02ce..f53be6df9 100644
--- a/libpng/contrib/tools/README.txt
+++ b/libpng/contrib/tools/README.txt
@@ -23,4 +23,5 @@ ORIGINAL AUTHORS
of the people below claim any rights with regard to the contents of this
directory.
- John Bowler <jbowler@acm.org>
+ John Bowler <jbowler at acm.org>
+ Glenn Randers-Pehrson <glennrp at users.sourceforge.net>
diff --git a/libpng/contrib/tools/chkfmt b/libpng/contrib/tools/chkfmt
index 9da6475fd..a1b88ccbf 100755
--- a/libpng/contrib/tools/chkfmt
+++ b/libpng/contrib/tools/chkfmt
@@ -1,4 +1,11 @@
#!/bin/sh
+
+# chkfmt
+#
+# COPYRIGHT: Written by John Cunningham Bowler, 2010.
+# 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.
#
# Check the format of the source files in the current directory - checks for a
# line length of 80 characters max and no tab characters.
diff --git a/libpng/contrib/tools/genpng.c b/libpng/contrib/tools/genpng.c
new file mode 100644
index 000000000..ce43260cb
--- /dev/null
+++ b/libpng/contrib/tools/genpng.c
@@ -0,0 +1,867 @@
+/*- genpng
+ *
+ * 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.
+ *
+ * Generate a PNG with an alpha channel, correctly.
+ *
+ * This is a test case generator; the resultant PNG files are only of interest
+ * to those of us who care about whether the edges of circles are green, red,
+ * or yellow.
+ *
+ * The program generates an RGB+Alpha PNG of a given size containing the given
+ * shapes on a transparent background:
+ *
+ * genpng width height { shape }
+ * shape ::= color width shape x1 y1 x2 y2
+ *
+ * 'color' is:
+ *
+ * black white red green yellow blue brown purple pink orange gray cyan
+ *
+ * The point is to have colors that are linguistically meaningful plus that old
+ * bugbear of the department store dress murders, Cyan, the only color we argue
+ * about.
+ *
+ * 'shape' is:
+ *
+ * circle: an ellipse
+ * square: a rectangle
+ * line: a straight line
+ *
+ * Each shape is followed by four numbers, these are two points in the output
+ * coordinate space (as real numbers) which describe the circle, square, or
+ * line. The shape is filled if it is preceded by 'filled' (not valid for
+ * 'line') or is drawn with a line, in which case the width of the line must
+ * precede the shape.
+ *
+ * The whole set of information can be repeated as many times as desired:
+ *
+ * shape ::= color width shape x1 y1 x2 y2
+ *
+ * color ::= black|white|red|green|yellow|blue
+ * color ::= brown|purple|pink|orange|gray|cyan
+ * width ::= filled
+ * width ::= <number>
+ * shape ::= circle|square|line
+ * x1 ::= <number>
+ * x2 ::= <number>
+ * y1 ::= <number>
+ * y2 ::= <number>
+ *
+ * The output PNG is generated by down-sampling a 4x supersampled image using
+ * a bi-cubic filter. The bi-cubic has a 2 (output) pixel width, so an 8x8
+ * array of super-sampled points contribute to each output pixel. The value of
+ * a super-sampled point is found using an unfiltered, aliased, infinite
+ * precision image: Each shape from the last to the first is checked to see if
+ * the point is in the drawn area and, if it is, the color of the point is the
+ * color of the shape and the alpha is 1, if not the previous shape is checked.
+ *
+ * This is an aliased algorithm because no filtering is done; a point is either
+ * inside or outside each shape and 'close' points do not contribute to the
+ * sample. The down-sampling is relied on to correct the error of not using
+ * a filter.
+ *
+ * The line end-caps are 'flat'; they go through the points. The square line
+ * joins are mitres; the outside of the lines are continued to the point of
+ * intersection.
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.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_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
+
+static const struct color
+{
+ const char *name;
+ double red;
+ double green;
+ double blue;
+} colors[] =
+/* color ::= black|white|red|green|yellow|blue
+ * color ::= brown|purple|pink|orange|gray|cyan
+ */
+{
+ { "black", 0, 0, 0 },
+ { "white", 1, 1, 1 },
+ { "red", 1, 0, 0 },
+ { "green", 0, 1, 0 },
+ { "yellow", 1, 1, 0 },
+ { "blue", 0, 0, 1 },
+ { "brown", .5, .125, 0 },
+ { "purple", 1, 0, 1 },
+ { "pink", 1, .5, .5 },
+ { "orange", 1, .5, 0 },
+ { "gray", 0, .5, .5 },
+ { "cyan", 0, 1, 1 }
+};
+#define color_count ((sizeof colors)/(sizeof colors[0]))
+
+static const struct color *
+color_of(const char *arg)
+{
+ int icolor = color_count;
+
+ while (--icolor >= 0)
+ {
+ if (strcmp(colors[icolor].name, arg) == 0)
+ return colors+icolor;
+ }
+
+ fprintf(stderr, "genpng: invalid color %s\n", arg);
+ exit(1);
+}
+
+static double
+width_of(const char *arg)
+{
+ if (strcmp(arg, "filled") == 0)
+ return 0;
+
+ else
+ {
+ char *ep = NULL;
+ double w = strtod(arg, &ep);
+
+ if (ep != NULL && *ep == 0 && w > 0)
+ return w;
+ }
+
+ fprintf(stderr, "genpng: invalid line width %s\n", arg);
+ exit(1);
+}
+
+static double
+coordinate_of(const char *arg)
+{
+ char *ep = NULL;
+ double w = strtod(arg, &ep);
+
+ if (ep != NULL && *ep == 0)
+ return w;
+
+ fprintf(stderr, "genpng: invalid coordinate value %s\n", arg);
+ exit(1);
+}
+
+struct arg; /* forward declaration */
+
+typedef int (*shape_fn_ptr)(const struct arg *arg, double x, double y);
+ /* A function to determine if (x,y) is inside the shape.
+ *
+ * There are two implementations:
+ *
+ * inside_fn: returns true if the point is inside
+ * check_fn: returns;
+ * -1: the point is outside the shape by more than the filter width (2)
+ * 0: the point may be inside the shape
+ * +1: the point is inside the shape by more than the filter width
+ */
+#define OUTSIDE (-1)
+#define INSIDE (1)
+
+struct arg
+{
+ const struct color *color;
+ shape_fn_ptr inside_fn;
+ shape_fn_ptr check_fn;
+ double width; /* line width, 0 for 'filled' */
+ double x1, y1, x2, y2;
+};
+
+/* IMPLEMENTATION NOTE:
+ *
+ * We want the contribution of each shape to the sample corresponding to each
+ * pixel. This could be obtained by super sampling the image to infinite
+ * dimensions, finding each point within the shape and assigning that a value
+ * '1' while leaving every point outside the shape with value '0' then
+ * downsampling to the image size with sinc; computationally very expensive.
+ *
+ * Approximations are as follows:
+ *
+ * 1) If the pixel coordinate is within the shape assume the sample has the
+ * shape color and is opaque, else assume there is no contribution from
+ * the shape.
+ *
+ * This is the equivalent of aliased rendering or resampling an image with
+ * a block filter. The maximum error in the calculated alpha (which will
+ * always be 0 or 1) is 0.5.
+ *
+ * 2) If the shape is within a square of size 1x1 centered on the pixel assume
+ * that the shape obscures an amount of the pixel equal to its area within
+ * that square.
+ *
+ * This is the equivalent of 'pixel coverage' alpha calculation or resampling
+ * an image with a bi-linear filter. The maximum error is over 0.2, but the
+ * results are often acceptable.
+ *
+ * This can be approximated by applying (1) to a super-sampled image then
+ * downsampling with a bi-linear filter. The error in the super-sampled
+ * image is 0.5 per sample, but the resampling reduces this.
+ *
+ * 3) Use a better filter with a super-sampled image; in the limit this is the
+ * sinc() approach.
+ *
+ * 4) Do the geometric calculation; a bivariate definite integral across the
+ * shape, unfortunately this means evaluating Si(x), the integral of sinc(x),
+ * which is still a lot of math.
+ *
+ * This code uses approach (3) with a bi-cubic filter and 8x super-sampling
+ * and method (1) for the super-samples. This means that the sample is either
+ * 0 or 1, depending on whether the sub-pixel is within or outside the shape.
+ * The bi-cubic weights are also fixed and the 16 required weights are
+ * pre-computed here (note that the 'scale' setting will need to be changed if
+ * 'super' is increased).
+ *
+ * The code also calculates a sum to the edge of the filter. This is not
+ * currently used by could be used to optimize the calculation.
+ */
+#if 0 /* bc code */
+scale=10
+super=8
+define bicubic(x) {
+ if (x <= 1) return (1.5*x - 2.5)*x*x + 1;
+ if (x < 2) return (((2.5 - 0.5*x)*x - 4)*x + 2);
+ return 0;
+}
+define sum(x) {
+ auto s;
+ s = 0;
+ while (x < 2*super) {
+ s = s + bicubic(x/super);
+ x = x + 1;
+ }
+ return s;
+}
+define results(x) {
+ auto b, s;
+ b = bicubic(x/super);
+ s = sum(x);
+
+ print " /*", x, "*/ { ", b, ", ", s, " }";
+ return 1;
+}
+x=0
+while (x<2*super) {
+ x = x + results(x)
+ if (x < 2*super) print ","
+ print "\n"
+}
+quit
+#endif
+
+#define BICUBIC1(x) /* |x| <= 1 */ ((1.5*(x)* - 2.5)*(x)*(x) + 1)
+#define BICUBIC2(x) /* 1 < |x| < 2 */ (((2.5 - 0.5*(x))*(x) - 4)*(x) + 2)
+#define FILTER_WEIGHT 9 /* Twice the first sum below */
+#define FILTER_WIDTH 2 /* Actually half the width; -2..+2 */
+#define FILTER_STEPS 8 /* steps per filter unit */
+static const double
+bicubic[16][2] =
+{
+ /* These numbers are exact; the weight for the filter is 1/9, but this
+ * would make the numbers inexact, so it is not included here.
+ */
+ /* bicubic sum */
+ /* 0*/ { 1.0000000000, 4.5000000000 },
+ /* 1*/ { .9638671875, 3.5000000000 },
+ /* 2*/ { .8671875000, 2.5361328125 },
+ /* 3*/ { .7275390625, 1.6689453125 },
+ /* 4*/ { .5625000000, .9414062500 },
+ /* 5*/ { .3896484375, .3789062500 },
+ /* 6*/ { .2265625000, -.0107421875 },
+ /* 7*/ { .0908203125, -.2373046875 },
+ /* 8*/ { 0, -.3281250000 },
+ /* 9*/ { -.0478515625, -.3281250000 },
+ /*10*/ { -.0703125000, -.2802734375 },
+ /*11*/ { -.0732421875, -.2099609375 },
+ /*12*/ { -.0625000000, -.1367187500 },
+ /*13*/ { -.0439453125, -.0742187500 },
+ /*14*/ { -.0234375000, -.0302734375 },
+ /*15*/ { -.0068359375, -.0068359375 }
+};
+
+static double
+alpha_calc(const struct arg *arg, double x, double y)
+{
+ /* For [x-2..x+2],[y-2,y+2] calculate the weighted bicubic given a function
+ * which tells us whether a point is inside or outside the shape. First
+ * check if we need to do this at all:
+ */
+ switch (arg->check_fn(arg, x, y))
+ {
+ case OUTSIDE:
+ return 0; /* all samples outside the shape */
+
+ case INSIDE:
+ return 1; /* all samples inside the shape */
+
+ default:
+ {
+ int dy;
+ double alpha = 0;
+
+# define FILTER_D (FILTER_WIDTH*FILTER_STEPS-1)
+ for (dy=-FILTER_D; dy<=FILTER_D; ++dy)
+ {
+ double wy = bicubic[abs(dy)][0];
+
+ if (wy != 0)
+ {
+ double alphay = 0;
+ int dx;
+
+ for (dx=-FILTER_D; dx<=FILTER_D; ++dx)
+ {
+ double wx = bicubic[abs(dx)][0];
+
+ if (wx != 0 && arg->inside_fn(arg, x+dx/16, y+dy/16))
+ alphay += wx;
+ }
+
+ alpha += wy * alphay;
+ }
+ }
+
+ /* This needs to be weighted for each dimension: */
+ return alpha / (FILTER_WEIGHT*FILTER_WEIGHT);
+ }
+ }
+}
+
+/* These are the shape functions. */
+/* "square",
+ * { inside_square_filled, check_square_filled },
+ * { inside_square, check_square }
+ */
+static int
+square_check(double x, double y, double x1, double y1, double x2, double y2)
+ /* Is x,y inside the square (x1,y1)..(x2,y2)? */
+{
+ /* Do a modified Cohen-Sutherland on one point, bit patterns that indicate
+ * 'outside' are:
+ *
+ * x<x1 | x<y1 | x<x2 | x<y2
+ * 0 x 0 x To the right
+ * 1 x 1 x To the left
+ * x 0 x 0 Below
+ * x 1 x 1 Above
+ *
+ * So 'inside' is (x<x1) != (x<x2) && (y<y1) != (y<y2);
+ */
+ return ((x<x1) ^ (x<x2)) & ((y<y1) ^ (y<y2));
+}
+
+static int
+inside_square_filled(const struct arg *arg, double x, double y)
+{
+ return square_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2);
+}
+
+static int
+square_check_line(const struct arg *arg, double x, double y, double w)
+ /* Check for a point being inside the boundaries implied by the given arg
+ * and assuming a width 2*w each side of the boundaries. This returns the
+ * 'check' INSIDE/OUTSIDE/0 result but note the semantics:
+ *
+ * +--------------+
+ * | | OUTSIDE
+ * | INSIDE |
+ * | |
+ * +--------------+
+ *
+ * And '0' means within the line boundaries.
+ */
+{
+ double cx = (arg->x1+arg->x2)/2;
+ double wx = fabs(arg->x1-arg->x2)/2;
+ double cy = (arg->y1+arg->y2)/2;
+ double wy = fabs(arg->y1-arg->y2)/2;
+
+ if (square_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w))
+ {
+ /* Inside, but maybe too far; check for the redundant case where
+ * the lines overlap:
+ */
+ wx -= w;
+ wy -= w;
+ if (wx > 0 && wy > 0 && square_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy))
+ return INSIDE; /* between (inside) the boundary lines. */
+
+ return 0; /* inside the lines themselves. */
+ }
+
+ return OUTSIDE; /* outside the boundary lines. */
+}
+
+static int
+check_square_filled(const struct arg *arg, double x, double y)
+{
+ /* The filter extends +/-FILTER_WIDTH each side of each output point, so
+ * the check has to expand and contract the square by that amount; '0'
+ * means close enough to the edge of the square that the bicubic filter has
+ * to be run, OUTSIDE means alpha==0, INSIDE means alpha==1.
+ */
+ return square_check_line(arg, x, y, FILTER_WIDTH);
+}
+
+static int
+inside_square(const struct arg *arg, double x, double y)
+{
+ /* Return true if within the drawn lines, else false, no need to distinguish
+ * INSIDE vs OUTSIDE here:
+ */
+ return square_check_line(arg, x, y, arg->width/2) == 0;
+}
+
+static int
+check_square(const struct arg *arg, double x, double y)
+{
+ /* So for this function a result of 'INSIDE' means inside the actual lines.
+ */
+ double w = arg->width/2;
+
+ if (square_check_line(arg, x, y, w+FILTER_WIDTH) == 0)
+ {
+ /* Somewhere close to the boundary lines. If far enough inside one of
+ * them then we can return INSIDE:
+ */
+ w -= FILTER_WIDTH;
+
+ if (w > 0 && square_check_line(arg, x, y, w) == 0)
+ return INSIDE;
+
+ /* Point is somewhere in the filter region: */
+ return 0;
+ }
+
+ else /* Inside or outside the square by more than w+FILTER_WIDTH. */
+ return OUTSIDE;
+}
+
+/* "circle",
+ * { inside_circle_filled, check_circle_filled },
+ * { inside_circle, check_circle }
+ *
+ * The functions here are analoguous to the square ones; however, they check
+ * the corresponding ellipse as opposed to the rectangle.
+ */
+static int
+circle_check(double x, double y, double x1, double y1, double x2, double y2)
+{
+ if (square_check(x, y, x1, y1, x2, y2))
+ {
+ /* Inside the square, so maybe inside the circle too: */
+ const double cx = (x1 + x2)/2;
+ const double cy = (y1 + y2)/2;
+ const double dx = x1 - x2;
+ const double dy = y1 - y2;
+
+ x = (x - cx)/dx;
+ y = (y - cy)/dy;
+
+ /* It is outside if the distance from the center is more than half the
+ * diameter:
+ */
+ return x*x+y*y < .25;
+ }
+
+ return 0; /* outside */
+}
+
+static int
+inside_circle_filled(const struct arg *arg, double x, double y)
+{
+ return circle_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2);
+}
+
+static int
+circle_check_line(const struct arg *arg, double x, double y, double w)
+ /* Check for a point being inside the boundaries implied by the given arg
+ * and assuming a width 2*w each side of the boundaries. This function has
+ * the same semantic as square_check_line but tests the circle.
+ */
+{
+ double cx = (arg->x1+arg->x2)/2;
+ double wx = fabs(arg->x1-arg->x2)/2;
+ double cy = (arg->y1+arg->y2)/2;
+ double wy = fabs(arg->y1-arg->y2)/2;
+
+ if (circle_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w))
+ {
+ /* Inside, but maybe too far; check for the redundant case where
+ * the lines overlap:
+ */
+ wx -= w;
+ wy -= w;
+ if (wx > 0 && wy > 0 && circle_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy))
+ return INSIDE; /* between (inside) the boundary lines. */
+
+ return 0; /* inside the lines themselves. */
+ }
+
+ return OUTSIDE; /* outside the boundary lines. */
+}
+
+static int
+check_circle_filled(const struct arg *arg, double x, double y)
+{
+ return circle_check_line(arg, x, y, FILTER_WIDTH);
+}
+
+static int
+inside_circle(const struct arg *arg, double x, double y)
+{
+ return circle_check_line(arg, x, y, arg->width/2) == 0;
+}
+
+static int
+check_circle(const struct arg *arg, double x, double y)
+{
+ /* Exactly as the 'square' code. */
+ double w = arg->width/2;
+
+ if (circle_check_line(arg, x, y, w+FILTER_WIDTH) == 0)
+ {
+ w -= FILTER_WIDTH;
+
+ if (w > 0 && circle_check_line(arg, x, y, w) == 0)
+ return INSIDE;
+
+ /* Point is somewhere in the filter region: */
+ return 0;
+ }
+
+ else /* Inside or outside the square by more than w+FILTER_WIDTH. */
+ return OUTSIDE;
+}
+
+/* "line",
+ * { NULL, NULL }, There is no 'filled' line.
+ * { inside_line, check_line }
+ */
+static int
+line_check(double x, double y, double x1, double y1, double x2, double y2,
+ double w, double expand)
+{
+ /* Shift all the points to (arg->x1, arg->y1) */
+ double lx = x2 - x1;
+ double ly = y2 - y1;
+ double len2 = lx*lx + ly*ly;
+ double cross, dot;
+
+ x -= x1;
+ y -= y1;
+
+ /* The dot product is the distance down the line, the cross product is
+ * the distance away from the line:
+ *
+ * distance = |cross| / sqrt(len2)
+ */
+ cross = x * ly - y * lx;
+
+ /* If 'distance' is more than w the point is definitely outside the line:
+ *
+ * distance >= w
+ * |cross| >= w * sqrt(len2)
+ * cross^2 >= w^2 * len2:
+ */
+ if (cross*cross >= (w+expand)*(w+expand)*len2)
+ return 0; /* outside */
+
+ /* Now find the distance *along* the line; this comes from the dot product
+ * lx.x+ly.y. The actual distance (in pixels) is:
+ *
+ * distance = dot / sqrt(len2)
+ */
+ dot = lx * x + ly * y;
+
+ /* The test for 'outside' is:
+ *
+ * distance < 0 || distance > sqrt(len2)
+ * -> dot / sqrt(len2) > sqrt(len2)
+ * -> dot > len2
+ *
+ * But 'expand' is used for the filter width and needs to be handled too:
+ */
+ return dot > -expand && dot < len2+expand;
+}
+
+static int
+inside_line(const struct arg *arg, double x, double y)
+{
+ return line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 0);
+}
+
+static int
+check_line(const struct arg *arg, double x, double y)
+{
+ /* The end caps of the line must be checked too; it's not enough just to
+ * widen the line by FILTER_WIDTH; 'expand' exists for this purpose:
+ */
+ if (line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2,
+ FILTER_WIDTH))
+ {
+ /* Inside the line+filter; far enough inside that the filter isn't
+ * required?
+ */
+ if (arg->width > 2*FILTER_WIDTH &&
+ line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2,
+ -FILTER_WIDTH))
+ return INSIDE;
+
+ return 0;
+ }
+
+ return OUTSIDE;
+}
+
+static const struct
+{
+ const char *name;
+ shape_fn_ptr function[2/*fill,line*/][2];
+# define FN_INSIDE 0
+# define FN_CHECK 1
+} shape_defs[] =
+{
+ { "square",
+ { { inside_square_filled, check_square_filled },
+ { inside_square, check_square } }
+ },
+ { "circle",
+ { { inside_circle_filled, check_circle_filled },
+ { inside_circle, check_circle } }
+ },
+ { "line",
+ { { NULL, NULL },
+ { inside_line, check_line } }
+ }
+};
+
+#define shape_count ((sizeof shape_defs)/(sizeof shape_defs[0]))
+
+static shape_fn_ptr
+shape_of(const char *arg, double width, int f)
+{
+ unsigned int i;
+
+ for (i=0; i<shape_count; ++i) if (strcmp(shape_defs[i].name, arg) == 0)
+ {
+ shape_fn_ptr fn = shape_defs[i].function[width != 0][f];
+
+ if (fn != NULL)
+ return fn;
+
+ fprintf(stderr, "genpng: %s %s not supported\n",
+ width == 0 ? "filled" : "unfilled", arg);
+ exit(1);
+ }
+
+ fprintf(stderr, "genpng: %s: not a valid shape name\n", arg);
+ exit(1);
+}
+
+static void
+parse_arg(struct arg *arg, const char **argv/*7 arguments*/)
+{
+ /* shape ::= color width shape x1 y1 x2 y2 */
+ arg->color = color_of(argv[0]);
+ arg->width = width_of(argv[1]);
+ arg->inside_fn = shape_of(argv[2], arg->width, FN_INSIDE);
+ arg->check_fn = shape_of(argv[2], arg->width, FN_CHECK);
+ arg->x1 = coordinate_of(argv[3]);
+ arg->y1 = coordinate_of(argv[4]);
+ arg->x2 = coordinate_of(argv[5]);
+ arg->y2 = coordinate_of(argv[6]);
+}
+
+static png_uint_32
+read_wh(const char *name, const char *str)
+ /* read a PNG width or height */
+{
+ char *ep = NULL;
+ unsigned long ul = strtoul(str, &ep, 10);
+
+ if (ep != NULL && *ep == 0 && ul > 0 && ul <= 0x7fffffff)
+ return (png_uint_32)/*SAFE*/ul;
+
+ fprintf(stderr, "genpng: %s: invalid number %s\n", name, str);
+ exit(1);
+}
+
+static void
+pixel(png_uint_16p p, struct arg *args, int nargs, double x, double y)
+{
+ /* Fill in the pixel by checking each shape (args[nargs]) for effects on
+ * the corresponding sample:
+ */
+ double r=0, g=0, b=0, a=0;
+
+ while (--nargs >= 0 && a != 1)
+ {
+ /* NOTE: alpha_calc can return a value outside the range 0..1 with the
+ * bicubic filter.
+ */
+ const double alpha = alpha_calc(args+nargs, x, y) * (1-a);
+
+ r += alpha * args[nargs].color->red;
+ g += alpha * args[nargs].color->green;
+ b += alpha * args[nargs].color->blue;
+ a += alpha;
+ }
+
+ /* 'a' may be negative or greater than 1; if it is, negative clamp the
+ * pixel to 0 if >1 clamp r/g/b:
+ */
+ if (a > 0)
+ {
+ if (a > 1)
+ {
+ if (r > 1) r = 1;
+ if (g > 1) g = 1;
+ if (b > 1) b = 1;
+ a = 1;
+ }
+
+ /* And fill in the pixel: */
+ p[0] = (png_uint_16)/*SAFE*/round(r * 65535);
+ p[1] = (png_uint_16)/*SAFE*/round(g * 65535);
+ p[2] = (png_uint_16)/*SAFE*/round(b * 65535);
+ p[3] = (png_uint_16)/*SAFE*/round(a * 65535);
+ }
+
+ else
+ p[3] = p[2] = p[1] = p[0] = 0;
+}
+
+int
+main(int argc, const char **argv)
+{
+ int convert_to_8bit = 0;
+
+ /* There is one option: --8bit: */
+ if (argc > 1 && strcmp(argv[1], "--8bit") == 0)
+ --argc, ++argv, convert_to_8bit = 1;
+
+ if (argc >= 3)
+ {
+ png_uint_16p buffer;
+ int nshapes;
+ png_image image;
+# define max_shapes 256
+ struct arg arg_list[max_shapes];
+
+ /* The libpng Simplified API write code requires a fully initialized
+ * structure.
+ */
+ memset(&image, 0, sizeof image);
+ image.version = PNG_IMAGE_VERSION;
+ image.opaque = NULL;
+ image.width = read_wh("width", argv[1]);
+ image.height = read_wh("height", argv[2]);
+ image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
+ image.flags = 0;
+ image.colormap_entries = 0;
+
+ /* Check the remainder of the arguments */
+ for (nshapes=0; 3+7*(nshapes+1) <= argc && nshapes < max_shapes;
+ ++nshapes)
+ parse_arg(arg_list+nshapes, argv+3+7*nshapes);
+
+ if (3+7*nshapes != argc)
+ {
+ fprintf(stderr, "genpng: %s: too many arguments\n", argv[3+7*nshapes]);
+ return 1;
+ }
+
+ /* Create the buffer: */
+ buffer = malloc(PNG_IMAGE_SIZE(image));
+
+ if (buffer != NULL)
+ {
+ png_uint_32 y;
+
+ /* Write each row... */
+ for (y=0; y<image.height; ++y)
+ {
+ png_uint_32 x;
+
+ /* Each pixel in each row: */
+ for (x=0; x<image.width; ++x)
+ pixel(buffer + 4*(x + y*image.width), arg_list, nshapes, x, y);
+ }
+
+ /* Write the result (to stdout) */
+ if (png_image_write_to_stdio(&image, stdout, convert_to_8bit,
+ buffer, 0/*row_stride*/, NULL/*colormap*/))
+ {
+ free(buffer);
+ return 0; /* success */
+ }
+
+ else
+ fprintf(stderr, "genpng: write stdout: %s\n", image.message);
+
+ free(buffer);
+ }
+
+ else
+ fprintf(stderr, "genpng: out of memory: %lu bytes\n",
+ (unsigned long)PNG_IMAGE_SIZE(image));
+ }
+
+ else
+ {
+ /* Wrong number of arguments */
+ fprintf(stderr, "genpng: usage: genpng [--8bit] width height {shape}\n"
+ " Generate a transparent PNG in RGBA (truecolor+alpha) format\n"
+ " containing the given shape or shapes. Shapes are defined:\n"
+ "\n"
+ " shape ::= color width shape x1 y1 x2 y2\n"
+ " color ::= black|white|red|green|yellow|blue\n"
+ " color ::= brown|purple|pink|orange|gray|cyan\n"
+ " width ::= filled|<number>\n"
+ " shape ::= circle|square|line\n"
+ " x1,x2 ::= <number>\n"
+ " y1,y2 ::= <number>\n"
+ "\n"
+ " Numbers are floating point numbers describing points relative to\n"
+ " the top left of the output PNG as pixel coordinates. The 'width'\n"
+ " parameter is either the width of the line (in output pixels) used\n"
+ " to draw the shape or 'filled' to indicate that the shape should\n"
+ " be filled with the color.\n"
+ "\n"
+ " Colors are interpreted loosely to give access to the eight full\n"
+ " intensity RGB values:\n"
+ "\n"
+ " black, red, green, blue, yellow, cyan, purple, white,\n"
+ "\n"
+ " Cyan is full intensity blue+green; RGB(0,1,1), plus the following\n"
+ " lower intensity values:\n"
+ "\n"
+ " brown: red+orange: RGB(0.5, 0.125, 0) (dark red+orange)\n"
+ " pink: red+white: RGB(1.0, 0.5, 0.5)\n"
+ " orange: red+yellow: RGB(1.0, 0.5, 0)\n"
+ " gray: black+white: RGB(0.5, 0.5, 0.5)\n"
+ "\n"
+ " The RGB values are selected to make detection of aliasing errors\n"
+ " easy. The names are selected to make the description of errors\n"
+ " easy.\n"
+ "\n"
+ " The PNG is written to stdout, if --8bit is given a 32bpp RGBA sRGB\n"
+ " file is produced, otherwise a 64bpp RGBA linear encoded file is\n"
+ " written.\n");
+ }
+
+ return 1;
+}
+#endif /* SIMPLIFIED_WRITE && STDIO */
diff --git a/libpng/contrib/tools/png-fix-itxt.c b/libpng/contrib/tools/png-fix-itxt.c
index 1210bd9c8..c7654c113 100644
--- a/libpng/contrib/tools/png-fix-itxt.c
+++ b/libpng/contrib/tools/png-fix-itxt.c
@@ -1,14 +1,14 @@
/* png-fix-itxt version 1.0.0
*
- * Copyright 2013 Glenn Randers-Pehrson
- * Last changed in libpng 1.6.3 [July 18, 2013]
+ * Copyright 2015 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.18 [July 23, 2015]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
- * Usage:
+ * Usage:
*
* png-fix-itxt.exe < bad.png > good.png
*
@@ -34,8 +34,10 @@
#define MAX_LENGTH 500000
-#define GETBREAK ((unsigned char)(inchar=getchar())); if (inchar == EOF) break
-
+/* Read one character (inchar), also return octet (c), break if EOF */
+#define GETBREAK inchar=getchar(); \
+ c=(inchar & 0xffU);\
+ if (inchar != c) break
int
main(void)
{
@@ -48,25 +50,25 @@ main(void)
/* Skip 8-byte signature */
for (i=8; i; i--)
{
- c=GETBREAK;
+ GETBREAK;
putchar(c);
}
-if (inchar != EOF)
+if (inchar == c) /* !EOF */
for (;;)
{
/* Read the length */
unsigned long length; /* must be 32 bits! */
- c=GETBREAK; buf[0] = c; length = c; length <<= 8;
- c=GETBREAK; buf[1] = c; length += c; length <<= 8;
- c=GETBREAK; buf[2] = c; length += c; length <<= 8;
- c=GETBREAK; buf[3] = c; length += c;
+ GETBREAK; buf[0] = c; length = c; length <<= 8;
+ GETBREAK; buf[1] = c; length += c; length <<= 8;
+ GETBREAK; buf[2] = c; length += c; length <<= 8;
+ GETBREAK; buf[3] = c; length += c;
/* Read the chunkname */
- c=GETBREAK; buf[4] = c;
- c=GETBREAK; buf[5] = c;
- c=GETBREAK; buf[6] = c;
- c=GETBREAK; buf[7] = c;
+ GETBREAK; buf[4] = c;
+ GETBREAK; buf[5] = c;
+ GETBREAK; buf[6] = c;
+ GETBREAK; buf[7] = c;
/* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */
@@ -81,19 +83,22 @@ for (;;)
/* Copy the data bytes */
for (i=8; i < length + 12; i++)
{
- c=GETBREAK; buf[i] = c;
+ GETBREAK; buf[i] = c;
}
+ if (inchar != c) /* EOF */
+ break;
+
/* Calculate the CRC */
crc = crc32(crc, buf+4, (uInt)length+4);
for (;;)
{
/* Check the CRC */
- if (((crc >> 24) & 0xff) == buf[length+8] &&
- ((crc >> 16) & 0xff) == buf[length+9] &&
- ((crc >> 8) & 0xff) == buf[length+10] &&
- ((crc ) & 0xff) == buf[length+11])
+ if (((crc >> 24) & 0xffU) == buf[length+8] &&
+ ((crc >> 16) & 0xffU) == buf[length+9] &&
+ ((crc >> 8) & 0xffU) == buf[length+10] &&
+ ((crc ) & 0xffU) == buf[length+11])
break;
length++;
@@ -101,18 +106,21 @@ for (;;)
if (length >= MAX_LENGTH-12)
break;
- c=GETBREAK;
- buf[length+11]=c;
+ GETBREAK;
+ buf[length+11] = c;
/* Update the CRC */
crc = crc32(crc, buf+7+length, 1);
}
+ if (inchar != c) /* EOF */
+ break;
+
/* Update length bytes */
- buf[0] = (unsigned char)((length << 24) & 0xff);
- buf[1] = (unsigned char)((length << 16) & 0xff);
- buf[2] = (unsigned char)((length << 8) & 0xff);
- buf[3] = (unsigned char)((length ) & 0xff);
+ buf[0] = (unsigned char)((length >> 24) & 0xffU);
+ buf[1] = (unsigned char)((length >> 16) & 0xffU);
+ buf[2] = (unsigned char)((length >> 8) & 0xffU);
+ buf[3] = (unsigned char)((length ) & 0xffU);
/* Write the fixed iTXt chunk (length, name, data, crc) */
for (i=0; i<length+12; i++)
@@ -121,6 +129,9 @@ for (;;)
else
{
+ if (inchar != c) /* EOF */
+ break;
+
/* Copy bytes that were already read (length and chunk name) */
for (i=0; i<8; i++)
putchar(buf[i]);
@@ -128,11 +139,11 @@ for (;;)
/* Copy data bytes and CRC */
for (i=8; i< length+12; i++)
{
- c=GETBREAK;
+ GETBREAK;
putchar(c);
}
- if (inchar == EOF)
+ if (inchar != c) /* EOF */
{
break;
}
@@ -142,7 +153,7 @@ for (;;)
break;
}
- if (inchar == EOF)
+ if (inchar != c) /* EOF */
break;
if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
diff --git a/libpng/contrib/tools/pngcp.c b/libpng/contrib/tools/pngcp.c
new file mode 100644
index 000000000..e82dddccc
--- /dev/null
+++ b/libpng/contrib/tools/pngcp.c
@@ -0,0 +1,2453 @@
+/* pngcp.c
+ *
+ * Copyright (c) 2016 John Cunningham Bowler
+ *
+ * Last changed in libpng 1.6.24 [August 4, 2016]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * This is an example of copying a PNG without changes using the png_read_png
+ * and png_write_png interfaces. A considerable number of options are provided
+ * to manipulate the compression of the PNG data and other compressed chunks.
+ *
+ * For a more extensive example that uses the transforms see
+ * contrib/libtests/pngimage.c in the libpng distribution.
+ */
+#include "pnglibconf.h" /* To find how libpng was configured. */
+
+#ifdef PNG_PNGCP_TIMING_SUPPORTED
+ /* WARNING:
+ *
+ * This test is here to allow POSIX.1b extensions to be used if enabled in
+ * the compile; specifically the code requires_POSIX_C_SOURCE support of
+ * 199309L or later to enable clock_gettime use.
+ *
+ * IF this causes problems THEN compile with a strict ANSI C compiler and let
+ * this code turn on the POSIX features that it minimally requires.
+ *
+ * IF this does not work there is probably a bug in your ANSI C compiler or
+ * your POSIX implementation.
+ */
+# define _POSIX_C_SOURCE 199309L
+#else /* No timing support required */
+# define _POSIX_SOURCE 1
+#endif
+
+#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+/* Define the following to use this test against your installed libpng, rather
+ * than the one being built here:
+ */
+#ifdef PNG_FREESTANDING_TESTS
+# include <png.h>
+#else
+# include "../../png.h"
+#endif
+
+#if PNG_LIBPNG_VER < 10700
+ /* READ_PNG and WRITE_PNG were not defined, so: */
+# ifdef PNG_INFO_IMAGE_SUPPORTED
+# ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+# define PNG_READ_PNG_SUPPORTED
+# endif /* SEQUENTIAL_READ */
+# ifdef PNG_WRITE_SUPPORTED
+# define PNG_WRITE_PNG_SUPPORTED
+# endif /* WRITE */
+# endif /* INFO_IMAGE */
+#endif /* pre 1.7.0 */
+
+#if (defined(PNG_READ_PNG_SUPPORTED)) && (defined(PNG_WRITE_PNG_SUPPORTED))
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <zlib.h>
+
+#ifndef PNG_SETJMP_SUPPORTED
+# include <setjmp.h> /* because png.h did *not* include this */
+#endif
+
+#ifdef __cplusplus
+# define voidcast(type, value) static_cast<type>(value)
+#else
+# define voidcast(type, value) (value)
+#endif /* __cplusplus */
+
+#ifdef __GNUC__
+ /* Many versions of GCC erroneously report that local variables unmodified
+ * within the scope of a setjmp may be clobbered. This hacks round the
+ * problem (sometimes) without harming other compilers.
+ */
+# define gv volatile
+#else
+# define gv
+#endif
+
+/* 'CLOCK_PROCESS_CPUTIME_ID' is one of the clock timers for clock_gettime. It
+ * need not be supported even when clock_gettime is available. It returns the
+ * 'CPU' time the process has consumed. 'CPU' time is assumed to include time
+ * when the CPU is actually blocked by a pending cache fill but not time
+ * waiting for page faults. The attempt is to get a measure of the actual time
+ * the implementation takes to read a PNG ignoring the potentially very large IO
+ * overhead.
+ */
+#ifdef PNG_PNGCP_TIMING_SUPPORTED
+# include <time.h> /* clock_gettime and associated definitions */
+# ifndef CLOCK_PROCESS_CPUTIME_ID
+ /* Prevent inclusion of the spurious code: */
+# undef PNG_PNGCP_TIMING_SUPPORTED
+# endif
+#endif /* PNGCP_TIMING */
+
+/* So if the timing feature has been activated: */
+
+/* This structure is used to control the test of a single file. */
+typedef enum
+{
+ VERBOSE, /* switches on all messages */
+ INFORMATION,
+ WARNINGS, /* switches on warnings */
+ LIBPNG_WARNING,
+ APP_WARNING,
+ ERRORS, /* just errors */
+ APP_FAIL, /* continuable error - no need to longjmp */
+ LIBPNG_ERROR, /* this and higher cause a longjmp */
+ LIBPNG_BUG, /* erroneous behavior in libpng */
+ APP_ERROR, /* such as out-of-memory in a callback */
+ QUIET, /* no normal messages */
+ USER_ERROR, /* such as file-not-found */
+ INTERNAL_ERROR
+} error_level;
+#define LEVEL_MASK 0xf /* where the level is in 'options' */
+
+#define STRICT 0x010 /* Fail on warnings as well as errors */
+#define LOG 0x020 /* Log pass/fail to stdout */
+#define CONTINUE 0x040 /* Continue on APP_FAIL errors */
+#define SIZES 0x080 /* Report input and output sizes */
+#define SEARCH 0x100 /* Search IDAT compression options */
+#define NOWRITE 0x200 /* Do not write an output file */
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+# define IGNORE_INDEX 0x400 /* Ignore out of range palette indices (BAD!) */
+# ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+# define FIX_INDEX 0x800 /* 'Fix' out of range palette indices (OK) */
+# endif /* GET_PALETTE_MAX */
+#endif /* CHECK_FOR_INVALID_INDEX */
+#define OPTION 0x80000000 /* Used for handling options */
+#define LIST 0x80000001 /* Used for handling options */
+
+/* Result masks apply to the result bits in the 'results' field below; these
+ * bits are simple 1U<<error_level. A pass requires either nothing worse than
+ * warnings (--relaxes) or nothing worse than information (--strict)
+ */
+#define RESULT_STRICT(r) (((r) & ~((1U<<WARNINGS)-1)) == 0)
+#define RESULT_RELAXED(r) (((r) & ~((1U<<ERRORS)-1)) == 0)
+
+/* OPTION DEFINITIONS */
+static const char range_lo[] = "low";
+static const char range_hi[] = "high";
+static const char all[] = "all";
+#define RANGE(lo,hi) { range_lo, lo }, { range_hi, hi }
+typedef struct value_list
+{
+ const char *name; /* the command line name of the value */
+ int value; /* the actual value to use */
+} value_list;
+
+static const value_list
+#ifdef PNG_SW_COMPRESS_png_level
+vl_compression[] =
+{
+ /* Overall compression control. The order controls the search order for
+ * 'all'. Since the search is for the smallest the order used is low memory
+ * then high speed.
+ */
+ { "low-memory", PNG_COMPRESSION_LOW_MEMORY },
+ { "high-speed", PNG_COMPRESSION_HIGH_SPEED },
+ { "high-read-speed", PNG_COMPRESSION_HIGH_READ_SPEED },
+ { "low", PNG_COMPRESSION_LOW },
+ { "medium", PNG_COMPRESSION_MEDIUM },
+ { "old", PNG_COMPRESSION_COMPAT },
+ { "high", PNG_COMPRESSION_HIGH },
+ { all, 0 }
+},
+#endif /* SW_COMPRESS_png_level */
+
+#if defined(PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED) ||\
+ defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED)
+vl_strategy[] =
+{
+ /* This controls the order of search. */
+ { "huffman", Z_HUFFMAN_ONLY },
+ { "RLE", Z_RLE },
+ { "fixed", Z_FIXED }, /* the remainder do window searchs */
+ { "filtered", Z_FILTERED },
+ { "default", Z_DEFAULT_STRATEGY },
+ { all, 0 }
+},
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+vl_windowBits_text[] =
+{
+ { "default", MAX_WBITS/*from zlib*/ },
+ { "minimum", 8 },
+ RANGE(8, MAX_WBITS/*from zlib*/),
+ { all, 0 }
+},
+#endif /* text compression */
+vl_level[] =
+{
+ { "default", Z_DEFAULT_COMPRESSION /* this is -1 */ },
+ { "none", Z_NO_COMPRESSION },
+ { "speed", Z_BEST_SPEED },
+ { "best", Z_BEST_COMPRESSION },
+ { "0", Z_NO_COMPRESSION },
+ RANGE(1, 9), /* this deliberately excludes '0' */
+ { all, 0 }
+},
+vl_memLevel[] =
+{
+ { "max", MAX_MEM_LEVEL }, /* zlib maximum */
+ { "1", 1 }, /* zlib minimum */
+ { "default", 8 }, /* zlib default */
+ { "2", 2 },
+ { "3", 3 },
+ { "4", 4 },
+ { "5", 5 }, /* for explicit testing */
+ RANGE(6, MAX_MEM_LEVEL/*zlib*/), /* exclude 5 and below: zlib bugs */
+ { all, 0 }
+},
+#endif /* WRITE_CUSTOMIZE_*COMPRESSION */
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+vl_filter[] =
+{
+ { all, PNG_ALL_FILTERS },
+ { "off", PNG_NO_FILTERS },
+ { "none", PNG_FILTER_NONE },
+ { "sub", PNG_FILTER_SUB },
+ { "up", PNG_FILTER_UP },
+ { "avg", PNG_FILTER_AVG },
+ { "paeth", PNG_FILTER_PAETH }
+},
+#endif /* WRITE_FILTER */
+#ifdef PNG_PNGCP_TIMING_SUPPORTED
+# define PNGCP_TIME_READ 1
+# define PNGCP_TIME_WRITE 2
+vl_time[] =
+{
+ { "both", PNGCP_TIME_READ+PNGCP_TIME_WRITE },
+ { "off", 0 },
+ { "read", PNGCP_TIME_READ },
+ { "write", PNGCP_TIME_WRITE }
+},
+#endif /* PNGCP_TIMING */
+vl_IDAT_size[] = /* for png_set_IDAT_size */
+{
+ { "default", 0x7FFFFFFF },
+ { "minimal", 1 },
+ RANGE(1, 0x7FFFFFFF)
+},
+#ifndef PNG_SW_IDAT_size
+ /* Pre 1.7 API: */
+# define png_set_IDAT_size(p,v) png_set_compression_buffer_size(p, v)
+#endif /* !SW_IDAT_size */
+#define SL 8 /* stack limit in display, below */
+vl_log_depth[] = { { "on", 1 }, { "off", 0 }, RANGE(0, SL) },
+vl_on_off[] = { { "on", 1 }, { "off", 0 } };
+
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+static value_list
+vl_windowBits_IDAT[] =
+{
+ { "default", MAX_WBITS },
+ { "small", 9 },
+ RANGE(8, MAX_WBITS), /* modified by set_windowBits_hi */
+ { all, 0 }
+};
+#endif /* IDAT compression */
+
+typedef struct option
+{
+ const char *name; /* name of the option */
+ png_uint_32 opt; /* an option, or OPTION or LIST */
+ png_byte search; /* Search on --search */
+ png_byte value_count; /* length of the list of values: */
+ const value_list *values; /* values for OPTION or LIST */
+} option;
+
+static const option options[] =
+{
+ /* struct display options, these are set when the command line is read */
+# define S(n,v) { #n, v, 0, 2, vl_on_off },
+ S(verbose, VERBOSE)
+ S(warnings, WARNINGS)
+ S(errors, ERRORS)
+ S(quiet, QUIET)
+ S(strict, STRICT)
+ S(log, LOG)
+ S(continue, CONTINUE)
+ S(sizes, SIZES)
+ S(search, SEARCH)
+ S(nowrite, NOWRITE)
+# ifdef IGNORE_INDEX
+ S(ignore-palette-index, IGNORE_INDEX)
+# endif /* IGNORE_INDEX */
+# ifdef FIX_INDEX
+ S(fix-palette-index, FIX_INDEX)
+# endif /* FIX_INDEX */
+# undef S
+
+ /* OPTION settings, these and LIST settings are read on demand */
+# define VLNAME(name) vl_ ## name
+# define VLSIZE(name) voidcast(png_byte,\
+ (sizeof VLNAME(name))/(sizeof VLNAME(name)[0]))
+# define VL(oname, name, type, search)\
+ { oname, type, search, VLSIZE(name), VLNAME(name) },
+# define VLO(oname, name, search) VL(oname, name, OPTION, search)
+
+# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+# define VLCIDAT(name) VLO(#name, name, 1/*search*/)
+# ifdef PNG_SW_COMPRESS_level
+# define VLCiCCP(name) VLO("ICC-profile-" #name, name, 0/*search*/)
+# else
+# define VLCiCCP(name)
+# endif
+# else
+# define VLCIDAT(name)
+# define VLCiCCP(name)
+# endif /* WRITE_CUSTOMIZE_COMPRESSION */
+
+# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+# define VLCzTXt(name) VLO("text-" #name, name, 0/*search*/)
+# else
+# define VLCzTXt(name)
+# endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
+
+# define VLC(name) VLCIDAT(name) VLCiCCP(name) VLCzTXt(name)
+
+# ifdef PNG_SW_COMPRESS_png_level
+ /* The libpng compression level isn't searched beause it justs sets the
+ * other things that are searched!
+ */
+ VLO("compression", compression, 0)
+ VLO("text-compression", compression, 0)
+ VLO("ICC-profile-compression", compression, 0)
+# endif /* SW_COMPRESS_png_level */
+ VLC(strategy)
+ VLO("windowBits", windowBits_IDAT, 1)
+# ifdef PNG_SW_COMPRESS_windowBits
+ VLO("ICC-profile-windowBits", windowBits_text/*sic*/, 0)
+# endif
+ VLO("text-windowBits", windowBits_text, 0)
+ VLC(level)
+ VLC(memLevel)
+ VLO("IDAT-size", IDAT_size, 0)
+ VLO("log-depth", log_depth, 0)
+
+# undef VLO
+
+ /* LIST settings */
+# define VLL(name, search) VL(#name, name, LIST, search)
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ VLL(filter, 0)
+#endif /* WRITE_FILTER */
+#ifdef PNG_PNGCP_TIMING_SUPPORTED
+ VLL(time, 0)
+#endif /* PNGCP_TIMING */
+# undef VLL
+# undef VL
+};
+
+#ifdef __cplusplus
+ static const size_t option_count((sizeof options)/(sizeof options[0]));
+#else /* !__cplusplus */
+# define option_count ((sizeof options)/(sizeof options[0]))
+#endif /* !__cplusplus */
+
+static const char *
+cts(int ct)
+{
+ switch (ct)
+ {
+ case PNG_COLOR_TYPE_PALETTE: return "P";
+ case PNG_COLOR_TYPE_GRAY: return "G";
+ case PNG_COLOR_TYPE_GRAY_ALPHA: return "GA";
+ case PNG_COLOR_TYPE_RGB: return "RGB";
+ case PNG_COLOR_TYPE_RGB_ALPHA: return "RGBA";
+ default: return "INVALID";
+ }
+}
+
+struct display
+{
+ jmp_buf error_return; /* Where to go to on error */
+ unsigned int errset; /* error_return is set */
+
+ const char *operation; /* What is happening */
+ const char *filename; /* The name of the original file */
+ const char *output_file; /* The name of the output file */
+
+ /* Used on both read and write: */
+ FILE *fp;
+
+ /* Used on a read, both the original read and when validating a written
+ * image.
+ */
+ png_alloc_size_t read_size;
+ png_structp read_pp;
+ png_infop ip;
+# if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
+ png_textp text_ptr; /* stash of text chunks */
+ int num_text;
+ int text_stashed;
+# endif /* pre 1.7 */
+
+# ifdef PNG_PNGCP_TIMING_SUPPORTED
+ struct timespec read_time;
+ struct timespec read_time_total;
+ struct timespec write_time;
+ struct timespec write_time_total;
+# endif /* PNGCP_TIMING */
+
+ /* Used to write a new image (the original info_ptr is used) */
+# define MAX_SIZE ((png_alloc_size_t)(-1))
+ png_alloc_size_t write_size;
+ png_alloc_size_t best_size;
+ png_structp write_pp;
+
+ /* Base file information */
+ png_alloc_size_t size;
+ png_uint_32 w;
+ png_uint_32 h;
+ int bpp;
+ png_byte ct;
+ int no_warnings; /* Do not output libpng warnings */
+ int min_windowBits; /* The windowBits range is 8..8 */
+
+ /* Options handling */
+ png_uint_32 results; /* A mask of errors seen */
+ png_uint_32 options; /* See display_log below */
+ png_byte entry[option_count]; /* The selected entry+1 of an option
+ * that appears on the command line, or
+ * 0 if it was not given. */
+ int value[option_count]; /* Corresponding value */
+
+ /* Compression exhaustive testing */
+ /* Temporary variables used only while testing a single collection of
+ * settings:
+ */
+ unsigned int csp; /* next stack entry to use */
+ unsigned int nsp; /* highest active entry+1 found so far */
+
+ /* Values used while iterating through all the combinations of settings for a
+ * single file:
+ */
+ unsigned int tsp; /* nsp from the last run; this is the
+ * index+1 of the highest active entry on
+ * this run; this entry will be advanced.
+ */
+ int opt_string_start; /* Position in buffer for the first
+ * searched option; non-zero if earlier
+ * options were set on the command line.
+ */
+ struct stack
+ {
+ png_alloc_size_t best_size; /* Best so far for this option */
+ png_alloc_size_t lo_size;
+ png_alloc_size_t hi_size;
+ int lo, hi; /* For binary chop of a range */
+ int best_val; /* Best value found so far */
+ int opt_string_end; /* End of the option string in 'curr' */
+ png_byte opt; /* The option being tested */
+ png_byte entry; /* The next value entry to be tested */
+ png_byte end; /* This is the last entry */
+ } stack[SL]; /* Stack of entries being tested */
+ char curr[32*SL]; /* current options being tested */
+ char best[32*SL]; /* best options */
+
+ char namebuf[FILENAME_MAX]; /* output file name */
+};
+
+static void
+display_init(struct display *dp)
+ /* Call this only once right at the start to initialize the control
+ * structure, the (struct buffer) lists are maintained across calls - the
+ * memory is not freed.
+ */
+{
+ memset(dp, 0, sizeof *dp);
+ dp->operation = "internal error";
+ dp->filename = "command line";
+ dp->output_file = "no output file";
+ dp->options = WARNINGS; /* default to !verbose, !quiet */
+ dp->fp = NULL;
+ dp->read_pp = NULL;
+ dp->ip = NULL;
+ dp->write_pp = NULL;
+ dp->min_windowBits = -1; /* this is an OPTIND, so -1 won't match anything */
+# if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
+ dp->text_ptr = NULL;
+ dp->num_text = 0;
+ dp->text_stashed = 0;
+# endif /* pre 1.7 */
+}
+
+static void
+display_clean_read(struct display *dp)
+{
+ if (dp->read_pp != NULL)
+ png_destroy_read_struct(&dp->read_pp, NULL, NULL);
+
+ if (dp->fp != NULL)
+ {
+ FILE *fp = dp->fp;
+ dp->fp = NULL;
+ (void)fclose(fp);
+ }
+}
+
+static void
+display_clean_write(struct display *dp)
+{
+ if (dp->fp != NULL)
+ {
+ FILE *fp = dp->fp;
+ dp->fp = NULL;
+ (void)fclose(fp);
+ }
+
+ if (dp->write_pp != NULL)
+ png_destroy_write_struct(&dp->write_pp, dp->tsp > 0 ? NULL : &dp->ip);
+}
+
+static void
+display_clean(struct display *dp)
+{
+ display_clean_read(dp);
+ display_clean_write(dp);
+ dp->output_file = NULL;
+
+# if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
+ /* This is actually created and used by the write code, but only
+ * once; it has to be retained for subsequent writes of the same file.
+ */
+ if (dp->text_stashed)
+ {
+ dp->text_stashed = 0;
+ dp->num_text = 0;
+ free(dp->text_ptr);
+ dp->text_ptr = NULL;
+ }
+# endif /* pre 1.7 */
+
+ /* leave the filename for error detection */
+ dp->results = 0; /* reset for next time */
+}
+
+static void
+display_destroy(struct display *dp)
+{
+ /* Release any memory held in the display. */
+ display_clean(dp);
+}
+
+static struct display *
+get_dp(png_structp pp)
+ /* The display pointer is always stored in the png_struct error pointer */
+{
+ struct display *dp = (struct display*)png_get_error_ptr(pp);
+
+ if (dp == NULL)
+ {
+ fprintf(stderr, "pngcp: internal error (no display)\n");
+ exit(99); /* prevents a crash */
+ }
+
+ return dp;
+}
+
+/* error handling */
+#ifdef __GNUC__
+# define VGATTR __attribute__((__format__ (__printf__,3,4)))
+ /* Required to quiet GNUC warnings when the compiler sees a stdarg function
+ * that calls one of the stdio v APIs.
+ */
+#else
+# define VGATTR
+#endif
+static void VGATTR
+display_log(struct display *dp, error_level level, const char *fmt, ...)
+ /* 'level' is as above, fmt is a stdio style format string. This routine
+ * does not return if level is above LIBPNG_WARNING
+ */
+{
+ dp->results |= 1U << level;
+
+ if (level > (error_level)(dp->options & LEVEL_MASK))
+ {
+ const char *lp;
+ va_list ap;
+
+ switch (level)
+ {
+ case INFORMATION: lp = "information"; break;
+ case LIBPNG_WARNING: lp = "warning(libpng)"; break;
+ case APP_WARNING: lp = "warning(pngcp)"; break;
+ case APP_FAIL: lp = "error(continuable)"; break;
+ case LIBPNG_ERROR: lp = "error(libpng)"; break;
+ case LIBPNG_BUG: lp = "bug(libpng)"; break;
+ case APP_ERROR: lp = "error(pngcp)"; break;
+ case USER_ERROR: lp = "error(user)"; break;
+
+ case INTERNAL_ERROR: /* anything unexpected is an internal error: */
+ case VERBOSE: case WARNINGS: case ERRORS: case QUIET:
+ default: lp = "bug(pngcp)"; break;
+ }
+
+ fprintf(stderr, "%s: %s: %s",
+ dp->filename != NULL ? dp->filename : "<stdin>", lp, dp->operation);
+
+ fprintf(stderr, ": ");
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fputc('\n', stderr);
+ }
+ /* else do not output any message */
+
+ /* Errors cause this routine to exit to the fail code */
+ if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
+ {
+ if (dp->errset)
+ longjmp(dp->error_return, level);
+
+ else
+ exit(99);
+ }
+}
+
+#if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
+static void
+text_stash(struct display *dp)
+{
+ /* libpng 1.6 and earlier fixed a bug whereby text chunks were written
+ * multiple times by png_write_png; the issue was that png_write_png passed
+ * the same png_info to both png_write_info and png_write_end. Rather than
+ * fixing it by recording the information in the png_struct, or by recording
+ * where to write the chunks, the fix made was to change the 'compression'
+ * field of the chunk to invalid values, rendering the png_info somewhat
+ * useless.
+ *
+ * The only fix for this given that we use the png_info more than once is to
+ * make a copy of the text chunks and png_set_text it each time. This adds a
+ * text chunks, so they get replicated, but only the new set gets written
+ * each time. This uses memory like crazy but there is no way to delete the
+ * useless chunks from the png_info.
+ *
+ * To make this slightly more efficient only the top level structure is
+ * copied; since the old strings are actually preserved (in 1.6 and earlier)
+ * this happens to work.
+ */
+ png_textp chunks = NULL;
+
+ dp->num_text = png_get_text(dp->write_pp, dp->ip, &chunks, NULL);
+
+ if (dp->num_text > 0)
+ {
+ dp->text_ptr = voidcast(png_textp, malloc(dp->num_text * sizeof *chunks));
+
+ if (dp->text_ptr == NULL)
+ display_log(dp, APP_ERROR, "text chunks: stash malloc failed");
+
+ else
+ memcpy(dp->text_ptr, chunks, dp->num_text * sizeof *chunks);
+ }
+
+ dp->text_stashed = 1; /* regardless of whether there are chunks or not */
+}
+
+#define text_stash(dp) if (!dp->text_stashed) text_stash(dp)
+
+static void
+text_restore(struct display *dp)
+{
+ /* libpng makes a copy, so this is fine: */
+ if (dp->text_ptr != NULL)
+ png_set_text(dp->write_pp, dp->ip, dp->text_ptr, dp->num_text);
+}
+
+#define text_restore(dp) if (dp->text_stashed) text_restore(dp)
+
+#else
+#define text_stash(dp) ((void)0)
+#define text_restore(dp) ((void)0)
+#endif /* pre 1.7 */
+
+/* OPTIONS:
+ *
+ * The command handles options of the forms:
+ *
+ * --option
+ * Turn an option on (Option)
+ * --no-option
+ * Turn an option off (Option)
+ * --option=value
+ * Set an option to a value (Value)
+ * --option=val1,val2,val3
+ * Set an option to a bitmask constructed from the values (List)
+ */
+static png_byte
+option_index(struct display *dp, const char *opt, size_t len)
+ /* Return the index (in options[]) of the given option, outputs an error if
+ * it does not exist. Takes the name of the option and a length (number of
+ * characters in the name).
+ */
+{
+ png_byte j;
+
+ for (j=0; j<option_count; ++j)
+ if (strncmp(options[j].name, opt, len) == 0 && options[j].name[len] == 0)
+ return j;
+
+ /* If the setjmp buffer is set the code is asking for an option index; this
+ * is bad. Otherwise this is the command line option parsing.
+ */
+ display_log(dp, dp->errset ? INTERNAL_ERROR : USER_ERROR,
+ "%.*s: unknown option", (int)/*SAFE*/len, opt);
+ abort(); /* NOT REACHED */
+}
+
+/* This works for an option name (no quotes): */
+#define OPTIND(dp, name) option_index(dp, #name, (sizeof #name)-1)
+
+static int
+get_option(struct display *dp, const char *opt, int *value)
+{
+ const png_byte i = option_index(dp, opt, strlen(opt));
+
+ if (dp->entry[i]) /* option was set on command line */
+ {
+ *value = dp->value[i];
+ return 1;
+ }
+
+ else
+ return 0;
+}
+
+static int
+set_opt_string_(struct display *dp, unsigned int sp, png_byte opt,
+ const char *entry_name)
+ /* Add the appropriate option string to dp->curr. */
+{
+ int offset, add;
+
+ if (sp > 0)
+ offset = dp->stack[sp-1].opt_string_end;
+
+ else
+ offset = dp->opt_string_start;
+
+ if (entry_name == range_lo)
+ add = sprintf(dp->curr+offset, " --%s=%d", options[opt].name,
+ dp->value[opt]);
+
+ else
+ add = sprintf(dp->curr+offset, " --%s=%s", options[opt].name, entry_name);
+
+ if (add < 0)
+ display_log(dp, INTERNAL_ERROR, "sprintf failed");
+
+ assert(offset+add < (int)/*SAFE*/sizeof dp->curr);
+ return offset+add;
+}
+
+static void
+set_opt_string(struct display *dp, unsigned int sp)
+ /* Add the appropriate option string to dp->curr. */
+{
+ dp->stack[sp].opt_string_end = set_opt_string_(dp, sp, dp->stack[sp].opt,
+ options[dp->stack[sp].opt].values[dp->stack[sp].entry].name);
+}
+
+static void
+record_opt(struct display *dp, png_byte opt, const char *entry_name)
+ /* Record this option in dp->curr; called for an option not being searched,
+ * the caller passes in the name of the value, or range_lo to use the
+ * numerical value.
+ */
+{
+ const unsigned int sp = dp->csp; /* stack entry of next searched option */
+
+ if (sp >= dp->tsp)
+ {
+ /* At top of stack; add the opt string for this entry to the previous
+ * searched entry or the start of the dp->curr buffer if there is nothing
+ * on the stack yet (sp == 0).
+ */
+ const int offset = set_opt_string_(dp, sp, opt, entry_name);
+
+ if (sp > 0)
+ dp->stack[sp-1].opt_string_end = offset;
+
+ else
+ dp->opt_string_start = offset;
+ }
+
+ /* else do nothing: option already recorded */
+}
+
+static int
+opt_list_end(struct display *dp, png_byte opt, png_byte entry)
+{
+ if (options[opt].values[entry].name == range_lo)
+ return entry+1U >= options[opt].value_count /* missing range_hi */ ||
+ options[opt].values[entry+1U].name != range_hi /* likewise */ ||
+ options[opt].values[entry+1U].value <= dp->value[opt] /* range end */;
+
+ else
+ return entry+1U >= options[opt].value_count /* missing 'all' */ ||
+ options[opt].values[entry+1U].name == all /* last entry */;
+}
+
+static void
+push_opt(struct display *dp, unsigned int sp, png_byte opt, int search)
+ /* Push a new option onto the stack, initializing the new stack entry
+ * appropriately; this does all the work of next_opt (setting end/nsp) for
+ * the first entry in the list.
+ */
+{
+ png_byte entry;
+ const char *entry_name;
+
+ assert(sp == dp->tsp && sp < SL);
+
+ /* The starting entry is entry 0 unless there is a range in which case it is
+ * the entry corresponding to range_lo:
+ */
+ entry = options[opt].value_count;
+ assert(entry > 0U);
+
+ do
+ {
+ entry_name = options[opt].values[--entry].name;
+ if (entry_name == range_lo)
+ break;
+ }
+ while (entry > 0U);
+
+ dp->tsp = sp+1U;
+ dp->stack[sp].best_size =
+ dp->stack[sp].lo_size =
+ dp->stack[sp].hi_size = MAX_SIZE;
+
+ if (search && entry_name == range_lo) /* search this range */
+ {
+ dp->stack[sp].lo = options[opt].values[entry].value;
+ /* check for a mal-formed RANGE above: */
+ assert(entry+1 < options[opt].value_count &&
+ options[opt].values[entry+1].name == range_hi);
+ dp->stack[sp].hi = options[opt].values[entry+1].value;
+ }
+
+ else
+ {
+ /* next_opt will just iterate over the range. */
+ dp->stack[sp].lo = INT_MAX;
+ dp->stack[sp].hi = INT_MIN; /* Prevent range chop */
+ }
+
+ dp->stack[sp].opt = opt;
+ dp->stack[sp].entry = entry;
+ dp->stack[sp].best_val = dp->value[opt] = options[opt].values[entry].value;
+
+ set_opt_string(dp, sp);
+
+ /* This works for the search case too; if the range has only one entry 'end'
+ * will be marked here.
+ */
+ if (opt_list_end(dp, opt, entry))
+ {
+ dp->stack[sp].end = 1;
+ /* Skip the warning if pngcp did this itself. See the code in
+ * set_windowBits_hi.
+ */
+ if (opt != dp->min_windowBits)
+ display_log(dp, APP_WARNING, "%s: only testing one value",
+ options[opt].name);
+ }
+
+ else
+ {
+ dp->stack[sp].end = 0;
+ dp->nsp = dp->tsp;
+ }
+
+ /* Do a lazy cache of the text chunks for libpng 1.6 and earlier; this is
+ * because they can only be written once(!) so if we are going to re-use the
+ * png_info we need a copy.
+ */
+ text_stash(dp);
+}
+
+static void
+next_opt(struct display *dp, unsigned int sp)
+ /* Return the next value for this option. When called 'sp' is expected to be
+ * the topmost stack entry - only the topmost entry changes each time round -
+ * and there must be a valid entry to return. next_opt will set dp->nsp to
+ * sp+1 if more entries are available, otherwise it will not change it and
+ * set dp->stack[s].end to true.
+ */
+{
+ int search = 0;
+ png_byte entry, opt;
+ const char *entry_name;
+
+ /* dp->stack[sp] must be the top stack entry and it must be active: */
+ assert(sp+1U == dp->tsp && !dp->stack[sp].end);
+
+ opt = dp->stack[sp].opt;
+ entry = dp->stack[sp].entry;
+ assert(entry+1U < options[opt].value_count);
+ entry_name = options[opt].values[entry].name;
+ assert(entry_name != NULL);
+
+ /* For ranges increment the value but don't change the entry, for all other
+ * cases move to the next entry and load its value:
+ */
+ if (entry_name == range_lo) /* a range */
+ {
+ /* A range can be iterated over or searched. The default iteration option
+ * is indicated by hi < lo on the stack, otherwise the range being search
+ * is [lo..hi] (inclusive).
+ */
+ if (dp->stack[sp].lo > dp->stack[sp].hi)
+ dp->value[opt]++;
+
+ else
+ {
+ /* This is the best size found for this option value: */
+ png_alloc_size_t best_size = dp->stack[sp].best_size;
+ int lo = dp->stack[sp].lo;
+ int hi = dp->stack[sp].hi;
+ int val = dp->value[opt];
+
+ search = 1; /* end is determined here */
+ assert(best_size < MAX_SIZE);
+
+ if (val == lo)
+ {
+ /* Finding the best for the low end of the range: */
+ dp->stack[sp].lo_size = best_size;
+ assert(hi > val);
+
+ if (hi == val+1) /* only 2 entries */
+ dp->stack[sp].end = 1;
+
+ val = hi;
+ }
+
+ else if (val == hi)
+ {
+ dp->stack[sp].hi_size = best_size;
+ assert(val > lo+1); /* else 'end' set above */
+
+ if (val == lo+2) /* only three entries to test */
+ dp->stack[sp].end = 1;
+
+ val = (lo + val)/2;
+ }
+
+ else
+ {
+ png_alloc_size_t lo_size = dp->stack[sp].lo_size;
+ png_alloc_size_t hi_size = dp->stack[sp].hi_size;
+
+ /* lo and hi should have been tested. */
+ assert(lo_size < MAX_SIZE && hi_size < MAX_SIZE);
+
+ /* These cases arise with the 'probe' handling below when there is a
+ * dip or peak in the size curve.
+ */
+ if (val < lo) /* probing a new lo */
+ {
+ /* Swap lo and val: */
+ dp->stack[sp].lo = val;
+ dp->stack[sp].lo_size = best_size;
+ val = lo;
+ best_size = lo_size;
+ lo = dp->stack[sp].lo;
+ lo_size = dp->stack[sp].lo_size;
+ }
+
+ else if (val > hi) /* probing a new hi */
+ {
+ /* Swap hi and val: */
+ dp->stack[sp].hi = val;
+ dp->stack[sp].hi_size = best_size;
+ val = hi;
+ best_size = hi_size;
+ hi = dp->stack[sp].hi;
+ hi_size = dp->stack[sp].hi_size;
+ }
+
+ /* The following should be true or something got messed up above. */
+ assert(lo < val && val < hi);
+
+ /* If there are only four entries (lo, val, hi plus one more) just
+ * test the remaining entry.
+ */
+ if (hi == lo+3)
+ {
+ /* Because of the 'probe' code val can either be lo+1 or hi-1; we
+ * need to test the other.
+ */
+ val = lo + ((val == lo+1) ? 2 : 1);
+ assert(lo < val && val < hi);
+ dp->stack[sp].end = 1;
+ }
+
+ else
+ {
+ /* There are at least 2 entries still untested between lo and hi,
+ * i.e. hi >= lo+4. 'val' is the midpoint +/- 0.5
+ *
+ * Separate out the four easy cases when lo..val..hi are
+ * monotonically decreased or (more weird) increasing:
+ */
+ assert(hi > lo+3);
+
+ if (lo_size <= best_size && best_size <= hi_size)
+ {
+ /* Select the low range; testing this first favours the low
+ * range over the high range when everything comes out equal.
+ * Because of the probing 'val' may be lo+1. In that case end
+ * the search and set 'val' to lo+2.
+ */
+ if (val == lo+1)
+ {
+ ++val;
+ dp->stack[sp].end = 1;
+ }
+
+ else
+ {
+ dp->stack[sp].hi = hi = val;
+ dp->stack[sp].hi_size = best_size;
+ val = (lo + val) / 2;
+ }
+ }
+
+ else if (lo_size >= best_size && best_size >= hi_size)
+ {
+ /* Monotonically decreasing size; this is the expected case.
+ * Select the high end of the range. As above, val may be
+ * hi-1.
+ */
+ if (val == hi-1)
+ {
+ --val;
+ dp->stack[sp].end = 1;
+ }
+
+ else
+ {
+ dp->stack[sp].lo = lo = val;
+ dp->stack[sp].lo_size = best_size;
+ val = (val + hi) / 2;
+ }
+ }
+
+ /* If both those tests failed 'best_size' is either greater than
+ * or less than both lo_size and hi_size. There is a peak or dip
+ * in the curve of sizes from lo to hi and val is on the peak or
+ * dip.
+ *
+ * Because the ranges being searched as so small (level is 1..9,
+ * windowBits 8..15, memLevel 1..9) there will only be at most
+ * three untested values between lo..val and val..hi, so solve
+ * the problem by probing down from hi or up from lo, whichever
+ * is the higher.
+ *
+ * This is the place where 'val' is set to outside the range
+ * lo..hi, described as 'probing', though maybe 'narrowing' would
+ * be more accurate.
+ */
+ else if (lo_size <= hi_size) /* down from hi */
+ {
+ dp->stack[sp].hi = val;
+ dp->stack[sp].hi_size = best_size;
+ val = --hi;
+ }
+
+ else /* up from low */
+ {
+ dp->stack[sp].lo = val;
+ dp->stack[sp].lo_size = best_size;
+ val = ++lo;
+ }
+
+ /* lo and hi are still the true range limits, check for the end
+ * condition.
+ */
+ assert(hi > lo+1);
+ if (hi <= lo+2)
+ dp->stack[sp].end = 1;
+ }
+ }
+
+ assert(val != dp->stack[sp].best_val); /* should be a new value */
+ dp->value[opt] = val;
+ dp->stack[sp].best_size = MAX_SIZE;
+ }
+ }
+
+ else
+ {
+ /* Increment 'entry' */
+ dp->value[opt] = options[opt].values[++entry].value;
+ dp->stack[sp].entry = entry;
+ }
+
+ set_opt_string(dp, sp);
+
+ if (!search && opt_list_end(dp, opt, entry)) /* end of list */
+ dp->stack[sp].end = 1;
+
+ else if (!dp->stack[sp].end) /* still active after all these tests */
+ dp->nsp = dp->tsp;
+}
+
+static int
+compare_option(const struct display *dp, unsigned int sp)
+{
+ int opt = dp->stack[sp].opt;
+
+ /* If the best so far is numerically less than the current value the
+ * current set of options is invariably worse.
+ */
+ if (dp->stack[sp].best_val < dp->value[opt])
+ return -1;
+
+ /* Lists of options are searched out of numerical order (currently only
+ * strategy), so only return +1 here when a range is being searched.
+ */
+ else if (dp->stack[sp].best_val > dp->value[opt])
+ {
+ if (dp->stack[sp].lo <= dp->stack[sp].hi /*searching*/)
+ return 1;
+
+ else
+ return -1;
+ }
+
+ else
+ return 0; /* match; current value is the best one */
+}
+
+static int
+advance_opt(struct display *dp, png_byte opt, int search)
+{
+ unsigned int sp = dp->csp++; /* my stack entry */
+
+ assert(sp >= dp->nsp); /* nsp starts off zero */
+
+ /* If the entry was active in the previous run dp->stack[sp] is already
+ * set up and dp->tsp will be greater than sp, otherwise a new entry
+ * needs to be created.
+ *
+ * dp->nsp is handled this way:
+ *
+ * 1) When an option is pushed onto the stack dp->nsp and dp->tsp are
+ * both set (by push_opt) to the next stack entry *unless* there is
+ * only one entry in the new list, in which case dp->stack[sp].end
+ * is set.
+ *
+ * 2) For the top stack entry next_opt is called. The entry must be
+ * active (dp->stack[sp].end is not set) and either 'nsp' or 'end'
+ * will be updated as appropriate.
+ *
+ * 3) For lower stack entries nsp is set unless the stack entry is
+ * already at the end. This means that when all the higher entries
+ * are popped this entry will be too.
+ */
+ if (sp >= dp->tsp)
+ {
+ push_opt(dp, sp, opt, search); /* This sets tsp to sp+1 */
+ return 1; /* initialized */
+ }
+
+ else
+ {
+ int ret = 0; /* unchanged */
+
+ /* An option that is already on the stack; update best_size and best_val
+ * if appropriate. On the first run there are no previous values and
+ * dp->write_size will be MAX_SIZE, however on the first run dp->tsp
+ * starts off as 0.
+ */
+ assert(dp->write_size > 0U && dp->write_size < MAX_SIZE);
+
+ if (dp->stack[sp].best_size > dp->write_size ||
+ (dp->stack[sp].best_size == dp->write_size &&
+ compare_option(dp, sp) > 0))
+ {
+ dp->stack[sp].best_size = dp->write_size;
+ dp->stack[sp].best_val = dp->value[opt];
+ }
+
+ if (sp+1U >= dp->tsp)
+ {
+ next_opt(dp, sp);
+ ret = 1; /* advanced */
+ }
+
+ else if (!dp->stack[sp].end) /* Active, not at top of stack */
+ dp->nsp = sp+1U;
+
+ return ret; /* advanced || unchanged */
+ }
+}
+
+static int
+getallopts_(struct display *dp, const png_byte opt, int *value, int record)
+ /* Like getop but iterate over all the values if the option was set to "all".
+ */
+{
+ if (dp->entry[opt]) /* option was set on command line */
+ {
+ /* Simple, single value, entries don't have a stack frame and have a fixed
+ * value (it doesn't change once set on the command line). Otherwise the
+ * value (entry) selected from the command line is 'all':
+ */
+ const char *entry_name = options[opt].values[dp->entry[opt]-1].name;
+
+ if (entry_name == all)
+ (void)advance_opt(dp, opt, 0/*do not search; iterate*/);
+
+ else if (record)
+ record_opt(dp, opt, entry_name);
+
+ *value = dp->value[opt];
+ return 1; /* set */
+ }
+
+ else
+ return 0; /* not set */
+}
+
+static int
+getallopts(struct display *dp, const char *opt_str, int *value)
+{
+ return getallopts_(dp, option_index(dp, opt_str, strlen(opt_str)), value, 0);
+}
+
+static int
+getsearchopts(struct display *dp, const char *opt_str, int *value)
+ /* As above except that if the option was not set try a search */
+{
+ png_byte istrat;
+ const png_byte opt = option_index(dp, opt_str, strlen(opt_str));
+ int record = options[opt].search;
+ const char *entry_name;
+
+ /* If it was set on the command line honour the setting, including 'all'
+ * which will override the built in search:
+ */
+ if (getallopts_(dp, opt, value, record))
+ return 1;
+
+ else if (!record) /* not a search option */
+ return 0; /* unset and not searched */
+
+ /* Otherwise decide what to do here. */
+ istrat = OPTIND(dp, strategy);
+ entry_name = range_lo; /* record the value, not the name */
+
+ if (opt == istrat) /* search all strategies */
+ (void)advance_opt(dp, opt, 0/*iterate*/), record=0;
+
+ else if (opt == OPTIND(dp, level))
+ {
+ /* Both RLE and HUFFMAN don't benefit from level increases */
+ if (dp->value[istrat] == Z_RLE || dp->value[istrat] == Z_HUFFMAN_ONLY)
+ dp->value[opt] = 1;
+
+ else /* fixed, filtered or default */
+ (void)advance_opt(dp, opt, 1/*search*/), record=0;
+ }
+
+ else if (opt == OPTIND(dp, windowBits))
+ {
+ /* Changing windowBits for strategies that do not search the window is
+ * pointless. Huffman-only does not search, RLE only searches backwards
+ * one byte, so given that the maximum string length is 258, a windowBits
+ * of 9 is always sufficient.
+ */
+ if (dp->value[istrat] == Z_HUFFMAN_ONLY)
+ dp->value[opt] = 8;
+
+ else if (dp->value[istrat] == Z_RLE)
+ dp->value[opt] = 9;
+
+ else /* fixed, filtered or default */
+ (void)advance_opt(dp, opt, 1/*search*/), record=0;
+ }
+
+ else if (opt == OPTIND(dp, memLevel))
+ {
+# if 0
+ (void)advance_opt(dp, opt, 0/*all*/), record=0;
+# else
+ dp->value[opt] = MAX_MEM_LEVEL;
+# endif
+ }
+
+ else /* something else */
+ assert(0=="reached");
+
+ if (record)
+ record_opt(dp, opt, entry_name);
+
+ /* One of the above searched options: */
+ *value = dp->value[opt];
+ return 1;
+}
+
+static int
+find_val(struct display *dp, png_byte opt, const char *str, size_t len)
+ /* Like option_index but sets (index+i) of the entry in options[opt] that
+ * matches str[0..len-1] into dp->entry[opt] as well as returning the actual
+ * value.
+ */
+{
+ int rlo = INT_MAX, rhi = INT_MIN;
+ png_byte j, irange = 0;
+
+ for (j=1U; j<=options[opt].value_count; ++j)
+ {
+ if (strncmp(options[opt].values[j-1U].name, str, len) == 0 &&
+ options[opt].values[j-1U].name[len] == 0)
+ {
+ dp->entry[opt] = j;
+ return options[opt].values[j-1U].value;
+ }
+ else if (options[opt].values[j-1U].name == range_lo)
+ rlo = options[opt].values[j-1U].value, irange = j;
+ else if (options[opt].values[j-1U].name == range_hi)
+ rhi = options[opt].values[j-1U].value;
+ }
+
+ /* No match on the name, but there may be a range. */
+ if (irange > 0)
+ {
+ char *ep = NULL;
+ long l = strtol(str, &ep, 0);
+
+ if (ep == str+len && l >= rlo && l <= rhi)
+ {
+ dp->entry[opt] = irange; /* range_lo */
+ return (int)/*SAFE*/l;
+ }
+ }
+
+ display_log(dp, dp->errset ? INTERNAL_ERROR : USER_ERROR,
+ "%s: unknown value setting '%.*s'", options[opt].name,
+ (int)/*SAFE*/len, str);
+ abort(); /* NOT REACHED */
+}
+
+static int
+opt_check(struct display *dp, const char *arg)
+{
+ assert(dp->errset == 0);
+
+ if (arg != NULL && arg[0] == '-' && arg[1] == '-')
+ {
+ int i = 0, negate = (strncmp(arg+2, "no-", 3) == 0), val;
+ png_byte j;
+
+ if (negate)
+ arg += 5; /* --no- */
+
+ else
+ arg += 2; /* -- */
+
+ /* Find the length (expect arg\0 or arg=) */
+ while (arg[i] != 0 && arg[i] != '=') ++i;
+
+ /* So arg[0..i-1] is the argument name, this does not return if this isn't
+ * a valid option name.
+ */
+ j = option_index(dp, arg, i);
+
+ /* It matcheth an option; check the remainder. */
+ if (arg[i] == 0) /* no specified value, use the default */
+ {
+ val = options[j].values[negate].value;
+ dp->entry[j] = (png_byte)/*SAFE*/(negate + 1U);
+ }
+
+ else
+ {
+ const char *list = arg + (i+1);
+
+ /* Expect a single value here unless this is a list, in which case
+ * multiple values are combined.
+ */
+ if (options[j].opt != LIST)
+ {
+ /* find_val sets 'dp->entry[j]' to a non-zero value: */
+ val = find_val(dp, j, list, strlen(list));
+
+ if (negate)
+ {
+ if (options[j].opt < OPTION)
+ val = !val;
+
+ else
+ {
+ display_log(dp, USER_ERROR,
+ "%.*s: option=arg cannot be negated", i, arg);
+ abort(); /* NOT REACHED */
+ }
+ }
+ }
+
+ else /* multiple options separated by ',' characters */
+ {
+ /* --no-option negates list values from the default, which should
+ * therefore be 'all'. Notice that if the option list is empty in
+ * this case nothing will be removed and therefore --no-option= is
+ * the same as --option.
+ */
+ if (negate)
+ val = options[j].values[0].value;
+
+ else
+ val = 0;
+
+ while (*list != 0) /* allows option= which sets 0 */
+ {
+ /* A value is terminated by the end of the list or a ','
+ * character.
+ */
+ int v, iv;
+
+ iv = 0; /* an index into 'list' */
+ while (list[++iv] != 0 && list[iv] != ',') {}
+
+ v = find_val(dp, j, list, iv);
+
+ if (negate)
+ val &= ~v;
+
+ else
+ val |= v;
+
+ list += iv;
+ if (*list != 0)
+ ++list; /* skip the ',' */
+ }
+ }
+ }
+
+ /* 'val' is the new value, store it for use later and debugging: */
+ dp->value[j] = val;
+
+ if (options[j].opt < LEVEL_MASK)
+ {
+ /* The handling for error levels is to set the level. */
+ if (val) /* Set this level */
+ dp->options = (dp->options & ~LEVEL_MASK) | options[j].opt;
+
+ else
+ display_log(dp, USER_ERROR,
+ "%.*s: messages cannot be turned off individually; set a message level",
+ i, arg);
+ }
+
+ else if (options[j].opt < OPTION)
+ {
+ if (val)
+ dp->options |= options[j].opt;
+
+ else
+ dp->options &= ~options[j].opt;
+ }
+
+ return 1; /* this is an option */
+ }
+
+ else
+ return 0; /* not an option */
+}
+
+#ifdef PNG_PNGCP_TIMING_SUPPORTED
+static void
+set_timer(struct display *dp, struct timespec *timer)
+{
+ /* Do the timing using clock_gettime and the per-process timer. */
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, timer))
+ {
+ display_log(dp, APP_ERROR,
+ "CLOCK_PROCESS_CPUTIME_ID: %s: timing disabled\n", strerror(errno));
+ dp->value[OPTIND(dp,time)] = 0; /* i.e. off */
+ }
+}
+
+static void
+start_timer(struct display *dp, int what)
+{
+ if ((dp->value[OPTIND(dp,time)] & what) != 0)
+ set_timer(dp, what == PNGCP_TIME_READ ? &dp->read_time : &dp->write_time);
+}
+
+static void
+end_timer(struct display *dp, int what)
+{
+ if ((dp->value[OPTIND(dp,time)] & what) != 0)
+ {
+ struct timespec t, tmp;
+
+ set_timer(dp, &t);
+
+ if (what == PNGCP_TIME_READ)
+ tmp = dp->read_time;
+
+ else
+ tmp = dp->write_time;
+
+ t.tv_sec -= tmp.tv_sec;
+ t.tv_nsec -= tmp.tv_nsec;
+
+ if (t.tv_nsec < 0)
+ {
+ --(t.tv_sec);
+ t.tv_nsec += 1000000000L;
+ }
+
+ if (what == PNGCP_TIME_READ)
+ dp->read_time = t, tmp = dp->read_time_total;
+
+ else
+ dp->write_time = t, tmp = dp->write_time_total;
+
+ tmp.tv_sec += t.tv_sec;
+ tmp.tv_nsec += t.tv_nsec;
+
+ if (tmp.tv_nsec >= 1000000000L)
+ {
+ ++(tmp.tv_sec);
+ tmp.tv_nsec -= 1000000000L;
+ }
+
+ if (what == PNGCP_TIME_READ)
+ dp->read_time_total = tmp;
+
+ else
+ dp->write_time_total = tmp;
+ }
+}
+
+static void
+print_time(const char *what, struct timespec t)
+{
+ printf("%s %.2lu.%.9ld", what, (unsigned long)t.tv_sec, t.tv_nsec);
+}
+#else /* !PNGCP_TIMING */
+#define start_timer(dp, what) ((void)0)
+#define end_timer(dp, what) ((void)0)
+#endif /* !PNGCP_TIMING */
+
+/* The following is used in main to verify that the final argument is a
+ * directory:
+ */
+static int
+checkdir(const char *pathname)
+{
+ struct stat buf;
+ return stat(pathname, &buf) == 0 && S_ISDIR(buf.st_mode);
+}
+
+/* Work out whether a path is valid (if not a display_log occurs), a directory
+ * (1 is returned) or a file *or* non-existent (0 is returned).
+ *
+ * Used for a write path.
+ */
+static int
+isdir(struct display *dp, const char *pathname)
+{
+ if (pathname == NULL)
+ return 0; /* stdout */
+
+ else if (pathname[0] == 0)
+ return 1; /* empty string */
+
+ else
+ {
+ struct stat buf;
+ int ret = stat(pathname, &buf);
+
+ if (ret == 0) /* the entry exists */
+ {
+ if (S_ISDIR(buf.st_mode))
+ return 1;
+
+ /* Else expect an object that exists and can be written: */
+ if (access(pathname, W_OK) != 0)
+ display_log(dp, USER_ERROR, "%s: cannot be written (%s)", pathname,
+ strerror(errno));
+
+ return 0; /* file (exists, can be written) */
+ }
+
+ else /* an error */
+ {
+ /* Non-existence is fine, other errors are not: */
+ if (errno != ENOENT)
+ display_log(dp, USER_ERROR, "%s: invalid output name (%s)",
+ pathname, strerror(errno));
+
+ return 0; /* file (does not exist) */
+ }
+ }
+}
+
+static void
+makename(struct display *dp, const char *dir, const char *infile)
+{
+ /* Make a name for an output file (and check it). */
+ dp->namebuf[0] = 0;
+
+ if (dir == NULL || infile == NULL)
+ display_log(dp, INTERNAL_ERROR, "NULL name to makename");
+
+ else
+ {
+ size_t dsize = strlen(dir);
+
+ if (dsize <= (sizeof dp->namebuf)-2) /* Allow for name + '/' + '\0' */
+ {
+ size_t isize = strlen(infile);
+ size_t istart = isize-1;
+
+ /* This should fail before here: */
+ if (infile[istart] == '/')
+ display_log(dp, INTERNAL_ERROR, "infile with trailing /");
+
+ memcpy(dp->namebuf, dir, dsize);
+ if (dsize > 0 && dp->namebuf[dsize-1] != '/')
+ dp->namebuf[dsize++] = '/';
+
+ /* Find the rightmost non-/ character: */
+ while (istart > 0 && infile[istart-1] != '/')
+ --istart;
+
+ isize -= istart;
+ infile += istart;
+
+ if (dsize+isize < (sizeof dp->namebuf)) /* dsize + infile + '\0' */
+ {
+ memcpy(dp->namebuf+dsize, infile, isize+1);
+
+ if (isdir(dp, dp->namebuf))
+ display_log(dp, USER_ERROR, "%s: output file is a directory",
+ dp->namebuf);
+ }
+
+ else
+ {
+ dp->namebuf[dsize] = 0; /* allowed for: -2 at start */
+ display_log(dp, USER_ERROR, "%s%s: output file name too long",
+ dp->namebuf, infile);
+ }
+ }
+
+ else
+ display_log(dp, USER_ERROR, "%s: output directory name too long", dir);
+ }
+}
+
+/* error handler callbacks for libpng */
+static void PNGCBAPI
+display_warning(png_structp pp, png_const_charp warning)
+{
+ struct display *dp = get_dp(pp);
+
+ /* This is used to prevent repeated warnings while searching */
+ if (!dp->no_warnings)
+ display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning);
+}
+
+static void PNGCBAPI
+display_error(png_structp pp, png_const_charp error)
+{
+ struct display *dp = get_dp(pp);
+
+ display_log(dp, LIBPNG_ERROR, "%s", error);
+}
+
+static void
+display_start_read(struct display *dp, const char *filename)
+{
+ if (filename != NULL)
+ {
+ dp->filename = filename;
+ dp->fp = fopen(filename, "rb");
+ }
+
+ else
+ {
+ dp->filename = "<stdin>";
+ dp->fp = stdin;
+ }
+
+ dp->w = dp->h = 0U;
+ dp->bpp = 0U;
+ dp->size = 0U;
+ dp->read_size = 0U;
+
+ if (dp->fp == NULL)
+ display_log(dp, USER_ERROR, "file open failed (%s)", strerror(errno));
+}
+
+static void PNGCBAPI
+read_function(png_structp pp, png_bytep data, png_size_t size)
+{
+ struct display *dp = get_dp(pp);
+
+ if (size == 0U || fread(data, size, 1U, dp->fp) == 1U)
+ dp->read_size += size;
+
+ else
+ {
+ if (feof(dp->fp))
+ display_log(dp, LIBPNG_ERROR, "PNG file truncated");
+ else
+ display_log(dp, LIBPNG_ERROR, "PNG file read failed (%s)",
+ strerror(errno));
+ }
+}
+
+static void
+read_png(struct display *dp, const char *filename)
+{
+ display_clean_read(dp); /* safety */
+ display_start_read(dp, filename);
+
+ dp->read_pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp,
+ display_error, display_warning);
+ if (dp->read_pp == NULL)
+ display_log(dp, LIBPNG_ERROR, "failed to create read struct");
+
+# ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ png_set_benign_errors(dp->read_pp, 1/*allowed*/);
+# endif /* BENIGN_ERRORS */
+
+# ifdef FIX_INDEX
+ if ((dp->options & FIX_INDEX) != 0)
+ png_set_check_for_invalid_index(dp->read_pp, 1/*on, no warning*/);
+# ifdef IGNORE_INDEX
+ else
+# endif /* IGNORE_INDEX */
+# endif /* FIX_INDEX */
+# ifdef IGNORE_INDEX
+ if ((dp->options & IGNORE_INDEX) != 0) /* DANGEROUS */
+ png_set_check_for_invalid_index(dp->read_pp, -1/*off completely*/);
+# endif /* IGNORE_INDEX */
+
+ /* The png_read_png API requires us to make the info struct, but it does the
+ * call to png_read_info.
+ */
+ dp->ip = png_create_info_struct(dp->read_pp);
+ if (dp->ip == NULL)
+ png_error(dp->read_pp, "failed to create info struct");
+
+ /* Set the IO handling */
+ png_set_read_fn(dp->read_pp, dp, read_function);
+
+# ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ png_set_keep_unknown_chunks(dp->read_pp, PNG_HANDLE_CHUNK_ALWAYS, NULL,
+ 0);
+# endif /* HANDLE_AS_UNKNOWN */
+
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ /* Remove the user limits, if any */
+ png_set_user_limits(dp->read_pp, 0x7fffffff, 0x7fffffff);
+# endif /* SET_USER_LIMITS */
+
+ /* Now read the PNG. */
+ start_timer(dp, PNGCP_TIME_READ);
+ png_read_png(dp->read_pp, dp->ip, 0U/*transforms*/, NULL/*params*/);
+ end_timer(dp, PNGCP_TIME_READ);
+ dp->w = png_get_image_width(dp->read_pp, dp->ip);
+ dp->h = png_get_image_height(dp->read_pp, dp->ip);
+ dp->ct = png_get_color_type(dp->read_pp, dp->ip);
+ dp->bpp = png_get_bit_depth(dp->read_pp, dp->ip) *
+ png_get_channels(dp->read_pp, dp->ip);
+ {
+ /* png_get_rowbytes should never return 0 because the value is set by the
+ * first call to png_set_IHDR, which should have happened by now, but just
+ * in case:
+ */
+ png_alloc_size_t rb = png_get_rowbytes(dp->read_pp, dp->ip);
+
+ if (rb == 0)
+ png_error(dp->read_pp, "invalid row byte count from libpng");
+
+ /* The size calc can overflow. */
+ if ((MAX_SIZE-dp->h)/rb < dp->h)
+ png_error(dp->read_pp, "image too large");
+
+ dp->size = rb * dp->h + dp->h/*filter byte*/;
+ }
+
+#ifdef FIX_INDEX
+ if (dp->ct == PNG_COLOR_TYPE_PALETTE && (dp->options & FIX_INDEX) != 0)
+ {
+ int max = png_get_palette_max(dp->read_pp, dp->ip);
+ png_colorp palette = NULL;
+ int num = -1;
+
+ if (png_get_PLTE(dp->read_pp, dp->ip, &palette, &num) != PNG_INFO_PLTE
+ || max < 0 || num <= 0 || palette == NULL)
+ display_log(dp, LIBPNG_ERROR, "invalid png_get_PLTE result");
+
+ if (max >= num)
+ {
+ /* 'Fix' the palette. */
+ int i;
+ png_color newpal[256];
+
+ for (i=0; i<num; ++i)
+ newpal[i] = palette[i];
+
+ /* Fill in any remainder with a warning color: */
+ for (; i<=max; ++i)
+ {
+ newpal[i].red = 0xbe;
+ newpal[i].green = 0xad;
+ newpal[i].blue = 0xed;
+ }
+
+ png_set_PLTE(dp->read_pp, dp->ip, newpal, i);
+ }
+ }
+#endif /* FIX_INDEX */
+
+ display_clean_read(dp);
+ dp->operation = "none";
+}
+
+static void
+display_start_write(struct display *dp, const char *filename)
+{
+ assert(dp->fp == NULL);
+
+ if ((dp->options & NOWRITE) != 0)
+ dp->output_file = "<no write>";
+
+ else
+ {
+ if (filename != NULL)
+ {
+ dp->output_file = filename;
+ dp->fp = fopen(filename, "wb");
+ }
+
+ else
+ {
+ dp->output_file = "<stdout>";
+ dp->fp = stdout;
+ }
+
+ if (dp->fp == NULL)
+ display_log(dp, USER_ERROR, "%s: file open failed (%s)",
+ dp->output_file, strerror(errno));
+ }
+}
+
+static void PNGCBAPI
+write_function(png_structp pp, png_bytep data, png_size_t size)
+{
+ struct display *dp = get_dp(pp);
+
+ /* The write fail is classed as a USER_ERROR, so --quiet does not turn it
+ * off, this seems more likely to be correct.
+ */
+ if (dp->fp == NULL || fwrite(data, size, 1U, dp->fp) == 1U)
+ {
+ dp->write_size += size;
+ if (dp->write_size < size || dp->write_size == MAX_SIZE)
+ png_error(pp, "IDAT size overflow");
+ }
+
+ else
+ display_log(dp, USER_ERROR, "%s: PNG file write failed (%s)",
+ dp->output_file, strerror(errno));
+}
+
+/* Compression option, 'method' is never set: there is no choice.
+ *
+ * IMPORTANT: the order of the entries in this macro determines the preference
+ * order when two different combos of two of these options produce an IDAT of
+ * the same size. The logic here is to put the things that affect the decoding
+ * of the PNG image ahead of those that are relevant only to the encoding.
+ */
+#define SET_COMPRESSION\
+ SET(strategy, strategy);\
+ SET(windowBits, window_bits);\
+ SET(level, level);\
+ SET(memLevel, mem_level);
+
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
+static void
+search_compression(struct display *dp)
+{
+ /* Like set_compression below but use a more restricted search than 'all' */
+ int val;
+
+# define SET(name, func) if (getsearchopts(dp, #name, &val))\
+ png_set_compression_ ## func(dp->write_pp, val);
+ SET_COMPRESSION
+# undef SET
+}
+
+static void
+set_compression(struct display *dp)
+{
+ int val;
+
+# define SET(name, func) if (getallopts(dp, #name, &val))\
+ png_set_compression_ ## func(dp->write_pp, val);
+ SET_COMPRESSION
+# undef SET
+}
+
+#ifdef PNG_SW_COMPRESS_level /* 1.7.0+ */
+static void
+set_ICC_profile_compression(struct display *dp)
+{
+ int val;
+
+# define SET(name, func) if (getallopts(dp, "ICC-profile-" #name, &val))\
+ png_set_ICC_profile_compression_ ## func(dp->write_pp, val);
+ SET_COMPRESSION
+# undef SET
+}
+#else
+# define set_ICC_profile_compression(dp) ((void)0)
+#endif
+#else
+# define search_compression(dp) ((void)0)
+# define set_compression(dp) ((void)0)
+# define set_ICC_profile_compression(dp) ((void)0)
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
+
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+static void
+set_text_compression(struct display *dp)
+{
+ int val;
+
+# define SET(name, func) if (getallopts(dp, "text-" #name, &val))\
+ png_set_text_compression_ ## func(dp->write_pp, val);
+ SET_COMPRESSION
+# undef SET
+}
+#else
+# define set_text_compression(dp) ((void)0)
+#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
+
+static void
+write_png(struct display *dp, const char *destname)
+{
+ display_clean_write(dp); /* safety */
+ display_start_write(dp, destname);
+
+ dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp,
+ display_error, display_warning);
+
+ if (dp->write_pp == NULL)
+ display_log(dp, LIBPNG_ERROR, "failed to create write png_struct");
+
+# ifdef PNG_BENIGN_ERRORS_SUPPORTED
+ png_set_benign_errors(dp->write_pp, 1/*allowed*/);
+# endif /* BENIGN_ERRORS */
+
+ png_set_write_fn(dp->write_pp, dp, write_function, NULL/*flush*/);
+
+#ifdef IGNORE_INDEX
+ if ((dp->options & IGNORE_INDEX) != 0) /* DANGEROUS */
+ png_set_check_for_invalid_index(dp->write_pp, -1/*off completely*/);
+#endif /* IGNORE_INDEX */
+
+ /* Restore the text chunks when using libpng 1.6 or less; this is a macro
+ * which expands to nothing in 1.7+ In earlier versions it tests
+ * dp->text_stashed, which is only set (below) *after* the first write.
+ */
+ text_restore(dp);
+
+# ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ png_set_keep_unknown_chunks(dp->write_pp, PNG_HANDLE_CHUNK_ALWAYS, NULL,
+ 0);
+# endif /* HANDLE_AS_UNKNOWN */
+
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ /* Remove the user limits, if any */
+ png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff);
+# endif
+
+ /* OPTION HANDLING */
+ /* compression outputs, IDAT and zTXt/iTXt: */
+ dp->tsp = dp->nsp;
+ dp->nsp = dp->csp = 0;
+# ifdef PNG_SW_COMPRESS_png_level
+ {
+ int val;
+
+ /* This sets everything, but then the following options just override
+ * the specific settings for ICC profiles and text.
+ */
+ if (getallopts(dp, "compression", &val))
+ png_set_compression(dp->write_pp, val);
+
+ if (getallopts(dp, "ICC-profile-compression", &val))
+ png_set_ICC_profile_compression(dp->write_pp, val);
+
+ if (getallopts(dp, "text-compression", &val))
+ png_set_text_compression(dp->write_pp, val);
+ }
+# endif /* png_level support */
+ if (dp->options & SEARCH)
+ search_compression(dp);
+ else
+ set_compression(dp);
+ set_ICC_profile_compression(dp);
+ set_text_compression(dp);
+
+ {
+ int val;
+
+ /* The permitted range is 1..0x7FFFFFFF, so the cast is safe */
+ if (get_option(dp, "IDAT-size", &val))
+ png_set_IDAT_size(dp->write_pp, val);
+ }
+
+ /* filter handling */
+# ifdef PNG_WRITE_FILTER_SUPPORTED
+ {
+ int val;
+
+ if (get_option(dp, "filter", &val))
+ png_set_filter(dp->write_pp, PNG_FILTER_TYPE_BASE, val);
+ }
+# endif /* WRITE_FILTER */
+
+ /* This just uses the 'read' info_struct directly, it contains the image. */
+ dp->write_size = 0U;
+ start_timer(dp, PNGCP_TIME_WRITE);
+ png_write_png(dp->write_pp, dp->ip, 0U/*transforms*/, NULL/*params*/);
+ end_timer(dp, PNGCP_TIME_WRITE);
+
+ /* Make sure the file was written ok: */
+ if (dp->fp != NULL)
+ {
+ FILE *fp = dp->fp;
+ dp->fp = NULL;
+ if (fclose(fp))
+ display_log(dp, APP_ERROR, "%s: write failed (%s)",
+ destname == NULL ? "stdout" : destname, strerror(errno));
+ }
+
+ /* Clean it on the way out - if control returns to the caller then the
+ * written_file contains the required data.
+ */
+ display_clean_write(dp);
+ dp->operation = "none";
+}
+
+static void
+set_windowBits_hi(struct display *dp)
+{
+ /* windowBits is in the range 8..15 but zlib maps '8' to '9' so it is only
+ * worth using if the data size is 256 byte or less.
+ */
+ int wb = MAX_WBITS; /* for large images */
+ int i = VLSIZE(windowBits_IDAT);
+
+ while (wb > 8 && dp->size <= 1U<<(wb-1)) --wb;
+
+ while (--i >= 0) if (VLNAME(windowBits_IDAT)[i].name == range_hi) break;
+
+ assert(i > 1); /* vl_windowBits_IDAT always has a RANGE() */
+ VLNAME(windowBits_IDAT)[i].value = wb;
+
+ assert(VLNAME(windowBits_IDAT)[--i].name == range_lo);
+ VLNAME(windowBits_IDAT)[i].value = wb > 8 ? 9 : 8;
+
+ /* If wb == 8 then any search has been restricted to just one windowBits
+ * entry. Record that here to avoid producing a spurious app-level warning
+ * above.
+ */
+ if (wb == 8)
+ dp->min_windowBits = OPTIND(dp, windowBits);
+}
+
+static int
+better_options(const struct display *dp)
+{
+ /* Are these options better than the best found so far? Normally the
+ * options are tested in preference order, best first, however when doing a
+ * search operation on a range the range values are tested out of order. In
+ * that case preferable options will get tested later.
+ *
+ * This function looks through the stack from the bottom up looking for an
+ * option that does not match the current best value. When it finds one it
+ * checks to see if it is more or less desireable and returns true or false
+ * as appropriate.
+ *
+ * Notice that this means that the order options are pushed onto the stack
+ * conveys a priority; lower/earlier options are more important than later
+ * ones.
+ */
+ unsigned int sp;
+
+ for (sp=0; sp<dp->csp; ++sp)
+ {
+ int c = compare_option(dp, sp);
+
+ if (c < 0)
+ return 0; /* worse */
+
+ else if (c > 0)
+ return 1; /* better */
+ }
+
+ assert(0 && "unreached");
+}
+
+static void
+print_search_results(struct display *dp)
+{
+ assert(dp->filename != NULL);
+ printf("%s [%ld x %ld %d bpp %s, %lu bytes] %lu -> %lu with '%s'\n",
+ dp->filename, (unsigned long)dp->w, (unsigned long)dp->h, dp->bpp,
+ cts(dp->ct), (unsigned long)dp->size, (unsigned long)dp->read_size,
+ (unsigned long)dp->best_size, dp->best);
+ fflush(stdout);
+}
+
+static void
+log_search(struct display *dp, unsigned int log_depth)
+{
+ /* Log, and reset, the search so far: */
+ if (dp->nsp/*next entry to change*/ <= log_depth)
+ {
+ print_search_results(dp);
+ /* Start again with this entry: */
+ dp->best_size = MAX_SIZE;
+ }
+}
+
+static void
+cp_one_file(struct display *dp, const char *filename, const char *destname)
+{
+ unsigned int log_depth;
+
+ dp->filename = filename;
+ dp->operation = "read";
+ dp->no_warnings = 0;
+
+ /* Read it then write it: */
+ if (filename != NULL && access(filename, R_OK) != 0)
+ display_log(dp, USER_ERROR, "%s: invalid file name (%s)",
+ filename, strerror(errno));
+
+ read_png(dp, filename);
+
+ /* But 'destname' may be a directory. */
+ dp->operation = "write";
+
+ /* Limit the upper end of the windowBits range for this file */
+ set_windowBits_hi(dp);
+
+ /* For logging, depth to log: */
+ {
+ int val;
+
+ if (get_option(dp, "log-depth", &val) && val >= 0)
+ log_depth = (unsigned int)/*SAFE*/val;
+
+ else
+ log_depth = 0U;
+ }
+
+ if (destname != NULL) /* else stdout */
+ {
+ if (isdir(dp, destname))
+ {
+ makename(dp, destname, filename);
+ destname = dp->namebuf;
+ }
+
+ else if (access(destname, W_OK) != 0 && errno != ENOENT)
+ display_log(dp, USER_ERROR, "%s: invalid output name (%s)", destname,
+ strerror(errno));
+ }
+
+ dp->nsp = 0;
+ dp->curr[0] = 0; /* acts as a flag for the caller */
+ dp->opt_string_start = 0;
+ dp->best[0] = 0; /* safety */
+ dp->best_size = MAX_SIZE;
+ write_png(dp, destname);
+
+ /* Initialize the 'best' fields: */
+ strcpy(dp->best, dp->curr);
+ dp->best_size = dp->write_size;
+
+ if (dp->nsp > 0) /* interating over lists */
+ {
+ char *tmpname, tmpbuf[(sizeof dp->namebuf) + 4];
+ assert(dp->curr[0] == ' ' && dp->tsp > 0);
+
+ /* Cancel warnings on subsequent writes */
+ log_search(dp, log_depth);
+ dp->no_warnings = 1;
+
+ /* Make a temporary name for the subsequent tests: */
+ if (destname != NULL)
+ {
+ strcpy(tmpbuf, destname);
+ strcat(tmpbuf, ".tmp"); /* space for .tmp allocated above */
+ tmpname = tmpbuf;
+ }
+
+ else
+ tmpname = NULL; /* stdout */
+
+ /* Loop to find the best option. */
+ do
+ {
+ write_png(dp, tmpname);
+
+ /* And compare the sizes (the write function makes sure write_size
+ * doesn't overflow.)
+ */
+ assert(dp->csp > 0);
+
+ if (dp->write_size < dp->best_size ||
+ (dp->write_size == dp->best_size && better_options(dp)))
+ {
+ if (destname != NULL && rename(tmpname, destname) != 0)
+ display_log(dp, APP_ERROR, "rename %s %s failed (%s)", tmpname,
+ destname, strerror(errno));
+
+ strcpy(dp->best, dp->curr);
+ dp->best_size = dp->write_size;
+ }
+
+ else if (tmpname != NULL && unlink(tmpname) != 0)
+ display_log(dp, APP_WARNING, "unlink %s failed (%s)", tmpname,
+ strerror(errno));
+
+ log_search(dp, log_depth);
+ }
+ while (dp->nsp > 0);
+
+ /* Do this for the 'sizes' option so that it reports the correct size. */
+ dp->write_size = dp->best_size;
+ }
+}
+
+static int
+cppng(struct display *dp, const char *file, const char *gv dest)
+ /* Exists solely to isolate the setjmp clobbers which some versions of GCC
+ * erroneously generate.
+ */
+{
+ int ret = setjmp(dp->error_return);
+
+ if (ret == 0)
+ {
+ dp->errset = 1;
+ cp_one_file(dp, file, dest);
+ dp->errset = 0;
+ return 0;
+ }
+
+ else
+ {
+ dp->errset = 0;
+
+ if (ret < ERRORS) /* shouldn't longjmp on warnings */
+ display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
+
+ return ret;
+ }
+}
+
+int
+main(const int argc, const char * const * const argv)
+{
+ /* For each file on the command line test it with a range of transforms */
+ int option_end;
+ struct display d;
+
+ display_init(&d);
+
+ d.operation = "options";
+ for (option_end = 1;
+ option_end < argc && opt_check(&d, argv[option_end]);
+ ++option_end)
+ {
+ }
+
+ /* Do a quick check on the directory target case; when there are more than
+ * two arguments the last one must be a directory.
+ */
+ if (!(d.options & NOWRITE) && option_end+2 < argc && !checkdir(argv[argc-1]))
+ {
+ fprintf(stderr,
+ "pngcp: %s: directory required with more than two arguments\n",
+ argv[argc-1]);
+ return 99;
+ }
+
+ {
+ int errors = 0;
+ int i = option_end;
+
+ /* Do this at least once; if there are no arguments stdin/stdout are used.
+ */
+ d.operation = "files";
+ do
+ {
+ const char *infile = NULL;
+ const char *outfile = NULL;
+ int ret;
+
+ if (i < argc)
+ {
+ infile = argv[i++];
+ if (!(d.options & NOWRITE) && i < argc)
+ outfile = argv[argc-1];
+ }
+
+ ret = cppng(&d, infile, outfile);
+
+ if (ret)
+ {
+ if (ret > QUIET) /* abort on user or internal error */
+ return 99;
+
+ /* An error: the output is meaningless */
+ }
+
+ else if (d.best[0] != 0)
+ {
+ /* This result may already have been output, in which case best_size
+ * has been reset.
+ */
+ if (d.best_size < MAX_SIZE)
+ print_search_results(&d);
+ }
+
+ else if (d.options & SIZES)
+ {
+ printf("%s [%ld x %ld %d bpp %s, %lu bytes] %lu -> %lu [0x%lx]\n",
+ infile, (unsigned long)d.w, (unsigned long)d.h, d.bpp,
+ cts(d.ct), (unsigned long)d.size, (unsigned long)d.read_size,
+ (unsigned long)d.write_size, (unsigned long)d.results);
+ fflush(stdout);
+ }
+
+ /* Here on any return, including failures, except user/internal issues
+ */
+ {
+ const int pass = (d.options & STRICT) ?
+ RESULT_STRICT(d.results) : RESULT_RELAXED(d.results);
+
+ if (!pass)
+ ++errors;
+
+ if (d.options & LOG)
+ {
+ int j;
+
+ printf("%s: pngcp", pass ? "PASS" : "FAIL");
+
+ for (j=1; j<option_end; ++j)
+ printf(" %s", argv[j]);
+
+ if (infile != NULL)
+ printf(" %s", infile);
+
+# ifdef PNG_PNGCP_TIMING_SUPPORTED
+ /* When logging output the files for each file, if enabled. */
+ if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_READ) != 0)
+ print_time(" read", d.read_time);
+
+ if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_WRITE) != 0)
+ print_time(" write", d.write_time);
+# endif /* PNGCP_TIMING */
+
+ printf("\n");
+ fflush(stdout);
+ }
+ }
+
+ display_clean(&d);
+ }
+ while (i+!(d.options & NOWRITE) < argc);
+ /* I.e. for write cases after the first time through the loop require
+ * there to be at least two arguments left and for the last one to be a
+ * directory (this was checked above).
+ */
+
+ /* Release allocated memory */
+ display_destroy(&d);
+
+# ifdef PNG_PNGCP_TIMING_SUPPORTED
+ {
+ int output = 0;
+
+ if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_READ) != 0)
+ print_time("read", d.read_time_total), output = 1;
+
+ if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_WRITE) != 0)
+ {
+ if (output) putchar(' ');
+ print_time("write", d.write_time_total);
+ output = 1;
+ }
+
+ if (output) putchar('\n');
+ }
+# endif /* PNGCP_TIMING */
+
+ return errors != 0;
+ }
+}
+#else /* !READ_PNG || !WRITE_PNG */
+int
+main(void)
+{
+ fprintf(stderr, "pngcp: no support for png_read/write_image\n");
+ return 77;
+}
+#endif /* !READ_PNG || !WRITE_PNG */
diff --git a/libpng/contrib/tools/pngfix.c b/libpng/contrib/tools/pngfix.c
index 67bab6aec..6da970ccb 100644
--- a/libpng/contrib/tools/pngfix.c
+++ b/libpng/contrib/tools/pngfix.c
@@ -1,8 +1,8 @@
/* pngfix.c
*
- * Copyright (c) 2014-2015 John Cunningham Bowler
+ * Copyright (c) 2014-2016 John Cunningham Bowler
*
- * Last changed in libpng 1.6.17 [March 26, 2015]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -52,7 +52,10 @@
#ifdef PNG_SETJMP_SUPPORTED
#include <setjmp.h>
-#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED)
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED) &&\
+ (defined(PNG_READ_DEINTERLACE_SUPPORTED) ||\
+ defined(PNG_READ_INTERLACING_SUPPORTED))
+
/* zlib.h defines the structure z_stream, an instance of which is included
* in this structure and is required for decompressing the LZ compressed
* data in PNG files.
@@ -71,8 +74,8 @@
* with older builds.
*/
#if ZLIB_VERNUM < 0x1260
-# define PNGZ_MSG_CAST(s) png_constcast(char*,s)
-# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)
+# define PNGZ_MSG_CAST(s) constcast(char*,s)
+# define PNGZ_INPUT_CAST(b) constcast(png_bytep,b)
#else
# define PNGZ_MSG_CAST(s) (s)
# define PNGZ_INPUT_CAST(b) (b)
@@ -86,17 +89,17 @@
/* Copied from pngpriv.h */
#ifdef __cplusplus
-# define png_voidcast(type, value) static_cast<type>(value)
-# define png_constcast(type, value) const_cast<type>(value)
-# define png_aligncast(type, value) \
+# define voidcast(type, value) static_cast<type>(value)
+# define constcast(type, value) const_cast<type>(value)
+# define aligncast(type, value) \
static_cast<type>(static_cast<void*>(value))
-# define png_aligncastconst(type, value) \
+# define aligncastconst(type, value) \
static_cast<type>(static_cast<const void*>(value))
#else
-# define png_voidcast(type, value) (value)
-# define png_constcast(type, value) ((type)(value))
-# define png_aligncast(type, value) ((void*)(value))
-# define png_aligncastconst(type, value) ((const void*)(value))
+# define voidcast(type, value) (value)
+# define constcast(type, value) ((type)(value))
+# define aligncast(type, value) ((void*)(value))
+# define aligncastconst(type, value) ((const void*)(value))
#endif /* __cplusplus */
#if PNG_LIBPNG_VER < 10700
@@ -134,7 +137,7 @@
#define png_zTXt PNG_U32(122, 84, 88, 116)
#endif
-/* The 8 byte signature as a pair of 32 bit quantities */
+/* The 8-byte signature as a pair of 32-bit quantities */
#define sig1 PNG_U32(137, 80, 78, 71)
#define sig2 PNG_U32( 13, 10, 26, 10)
@@ -156,7 +159,7 @@
*/
#define UNREACHED 0
-/* 80-bit number handling - a PNG image can be up to (2^31-1)x(2^31-1) 8 byte
+/* 80-bit number handling - a PNG image can be up to (2^31-1)x(2^31-1) 8-byte
* (16-bit RGBA) pixels in size; that's less than 2^65 bytes or 2^68 bits, so
* arithmetic of 80-bit numbers is sufficient. This representation uses an
* arbitrary length array of png_uint_16 digits (0..65535). The representation
@@ -316,13 +319,13 @@ uarb_mult32(uarb acc, int a_digits, uarb num, int n_digits, png_uint_32 val)
a_digits = uarb_mult_digit(acc, a_digits, num, n_digits,
(png_uint_16)(val & 0xffff));
- /* Because n_digits and val are >0 the following must be true: */
- assert(a_digits > 0);
-
val >>= 16;
if (val > 0)
a_digits = uarb_mult_digit(acc+1, a_digits-1, num, n_digits,
(png_uint_16)val) + 1;
+
+ /* Because n_digits and val are >0 the following must be true: */
+ assert(a_digits > 0);
}
return a_digits;
@@ -446,7 +449,7 @@ static void
make_random_bytes(png_uint_32* seed, void* pv, size_t size)
{
png_uint_32 u0 = seed[0], u1 = seed[1];
- png_bytep bytes = png_voidcast(png_bytep, pv);
+ png_bytep bytes = voidcast(png_bytep, pv);
/* There are thirty-three bits; the next bit in the sequence is bit-33 XOR
* bit-20. The top 1 bit is in u1, the bottom 32 are in u0.
@@ -584,7 +587,7 @@ chunk_type_valid(png_uint_32 c)
c &= ~PNG_U32(32,32,0,32);
t = (c & ~0x1f1f1f1f) ^ 0x40404040;
- /* Subtract 65 for each 8 bit quantity, this must not overflow
+ /* Subtract 65 for each 8-bit quantity, this must not overflow
* and each byte must then be in the range 0-25.
*/
c -= PNG_U32(65,65,65,65);
@@ -667,8 +670,8 @@ IDAT_list_extend(struct IDAT_list *tail)
if (length < tail->length) /* arithmetic overflow */
length = tail->length;
-
- next = png_voidcast(IDAT_list*, malloc(IDAT_list_size(NULL, length)));
+
+ next = voidcast(IDAT_list*, malloc(IDAT_list_size(NULL, length)));
CLEAR(*next);
/* The caller must handle this: */
@@ -921,7 +924,7 @@ emit_string(const char *str, FILE *out)
else if (isspace(UCHAR_MAX & *str))
putc('_', out);
-
+
else
fprintf(out, "\\%.3o", *str);
}
@@ -1821,7 +1824,7 @@ IDAT_init(struct IDAT * const idat, struct file * const file)
}
static png_uint_32
-rechunk_length(struct IDAT *idat)
+rechunk_length(struct IDAT *idat, int start)
/* Return the length for the next IDAT chunk, taking into account
* rechunking.
*/
@@ -1833,7 +1836,7 @@ rechunk_length(struct IDAT *idat)
const struct IDAT_list *cur;
unsigned int count;
- if (idat->idat_index == 0) /* at the new chunk (first time) */
+ if (start)
return idat->idat_length; /* use the cache */
/* Otherwise rechunk_length is called at the end of a chunk for the length
@@ -1945,7 +1948,7 @@ process_IDAT(struct file *file)
list->count = 0;
file->idat->idat_list_tail = list;
}
-
+
/* And fill in the next IDAT information buffer. */
list->lengths[(list->count)++] = file->chunk->chunk_length;
@@ -1992,7 +1995,7 @@ process_IDAT(struct file *file)
idat->idat_index = 0; /* Index into chunk data */
/* Update the chunk length to the correct value for the IDAT chunk: */
- file->chunk->chunk_length = rechunk_length(idat);
+ file->chunk->chunk_length = rechunk_length(idat, 1/*start*/);
/* Change the state to writing IDAT chunks */
file->state = STATE_IDAT;
@@ -2218,7 +2221,7 @@ zlib_init(struct zlib *zlib, struct IDAT *idat, struct chunk *chunk,
/* These values are sticky across reset (in addition to the stuff in the
* first block, which is actually constant.)
*/
- zlib->file_bits = 16;
+ zlib->file_bits = 24;
zlib->ok_bits = 16; /* unset */
zlib->cksum = 0; /* set when a checksum error is detected */
@@ -2301,10 +2304,12 @@ zlib_advance(struct zlib *zlib, png_uint_32 nbytes)
zlib->file_bits = file_bits;
/* Check against the existing value - it may not need to be
- * changed.
+ * changed. Note that a bogus file_bits is allowed through once,
+ * to see if it works, but the window_bits value is set to 15,
+ * the maximum.
*/
if (new_bits == 0) /* no change */
- zlib->window_bits = file_bits;
+ zlib->window_bits = ((file_bits > 15) ? 15 : file_bits);
else if (new_bits != file_bits) /* rewrite required */
bIn = (png_byte)((bIn & 0xf) + ((new_bits-8) << 4));
@@ -2325,8 +2330,7 @@ zlib_advance(struct zlib *zlib, png_uint_32 nbytes)
if (bIn != b2)
{
/* If the first byte wasn't changed this indicates an error in
- * the checksum calculation; signal this by setting file_bits
- * (not window_bits) to 0.
+ * the checksum calculation; signal this by setting 'cksum'.
*/
if (zlib->file_bits == zlib->window_bits)
zlib->cksum = 1;
@@ -2585,7 +2589,7 @@ zlib_run(struct zlib *zlib)
{
struct chunk *chunk = zlib->chunk;
int rc;
-
+
assert(zlib->rewrite_offset < chunk->chunk_length);
rc = zlib_advance(zlib, chunk->chunk_length - zlib->rewrite_offset);
@@ -3469,7 +3473,8 @@ read_callback(png_structp png_ptr, png_bytep buffer, size_t count)
/* Write another IDAT chunk. Call rechunk_length to
* calculate the length required.
*/
- length = chunk->chunk_length = rechunk_length(file->idat);
+ length = chunk->chunk_length =
+ rechunk_length(file->idat, 0/*end*/);
assert(type == png_IDAT);
file->write_count = 0; /* for the new chunk */
--(file->write_count); /* fake out the increment below */
@@ -3535,7 +3540,7 @@ get_control(png_const_structrp png_ptr)
/* This just returns the (file*). The chunk and idat control structures
* don't always exist.
*/
- struct control *control = png_voidcast(struct control*,
+ struct control *control = voidcast(struct control*,
png_get_error_ptr(png_ptr));
return &control->file;
}
@@ -3543,7 +3548,7 @@ get_control(png_const_structrp png_ptr)
static void
allocate(struct file *file, int allocate_idat)
{
- struct control *control = png_voidcast(struct control*, file->alloc_ptr);
+ struct control *control = voidcast(struct control*, file->alloc_ptr);
if (allocate_idat)
{
@@ -3853,6 +3858,7 @@ usage(const char *prog)
int
main(int argc, const char **argv)
{
+ char temp_name[FILENAME_MAX+1];
const char * prog = *argv;
const char * outfile = NULL;
const char * suffix = NULL;
@@ -3955,7 +3961,6 @@ main(int argc, const char **argv)
else
{
size_t outlen = strlen(*argv);
- char temp_name[FILENAME_MAX+1];
if (outfile == NULL) /* else this takes precedence */
{
@@ -4030,7 +4035,7 @@ main(void)
int
main(void)
{
- fprintf(stderr, "pngfix does not work without read support\n");
+ fprintf(stderr, "pngfix does not work without read deinterlace support\n");
return 77;
}
#endif /* PNG_READ_SUPPORTED && PNG_EASY_ACCESS_SUPPORTED */
diff --git a/libpng/contrib/tools/reindent b/libpng/contrib/tools/reindent
new file mode 100755
index 000000000..f4df309b6
--- /dev/null
+++ b/libpng/contrib/tools/reindent
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# reindent a libpng C source
+
+# COPYRIGHT: Written by Glenn Randers-Pehrson, 2016.
+# 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.
+
+# Usage:
+# reindent inputtabsize outputtabsize inputcontinuestring outputcontinuestring
+#
+# Assumes that continued lines begin with indentation plus one space, and
+# that continued comments begin with indentation plus " *".
+#
+# eg, to change libpng coding style from 3-space indentation with 4-space
+# continuations to 4-space indentation with 2-space continuations:
+#
+# reindent 3 4 "\t " " " < example.c > example.c_4_2
+# and to restore the file back to libpng coding style
+# reindent 4 3 " " " " < example.c_4_2 > example.c_3_4
+
+unexpand --first-only --t $1 | \
+ sed -e "/^ *$3[^\*]/{s/$3/$4/}" | \
+ expand -t $2
diff --git a/libpng/contrib/visupng/PngFile.c b/libpng/contrib/visupng/PngFile.c
index e563e9292..dcde18a3a 100644
--- a/libpng/contrib/visupng/PngFile.c
+++ b/libpng/contrib/visupng/PngFile.c
@@ -136,7 +136,7 @@ BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData,
/* create the two png(-info) structures */
- png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL,
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
(png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
if (!png_ptr)
{
@@ -313,7 +313,7 @@ BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData,
/* prepare the standard PNG structures */
- png_ptr = png_create_write_struct(png_get_libpng_ver(NULL), NULL,
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
(png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
if (!png_ptr)
{