FPII-2034: DO NOT MERGE Update libpng to 1.6.20
DO NOT MERGE Update libpng to 1.6.20
BUG:23265085
Change-Id: I2fc2106965c789a54f04412e9c63a0901b0c1e71
(cherry picked from commit 0b39f202aaedd3029e4270d2af7d58ba6634f9cd)
diff --git a/contrib/libtests/pngvalid.c b/contrib/libtests/pngvalid.c
index 788b693..bdd3c91 100644
--- a/contrib/libtests/pngvalid.c
+++ b/contrib/libtests/pngvalid.c
@@ -1,8 +1,8 @@
/* pngvalid.c - validate libpng by constructing then reading png files.
*
- * Last changed in libpng 1.6.10 [March 6, 2014]
- * Copyright (c) 2014 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.25 [December 3, 2015]
+ * Copyright (c) 2014-2015 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
* This code is released under the libpng license.
@@ -34,6 +34,16 @@
# include <fenv.h>
#endif
+#ifndef FE_DIVBYZERO
+# define FE_DIVBYZERO 0
+#endif
+#ifndef FE_INVALID
+# define FE_INVALID 0
+#endif
+#ifndef FE_OVERFLOW
+# define FE_OVERFLOW 0
+#endif
+
/* Define the following to use this test against your installed libpng, rather
* than the one being built here:
*/
@@ -64,7 +74,7 @@
(defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED))
#if PNG_LIBPNG_VER < 10500
-/* This deliberately lacks the PNG_CONST. */
+/* This deliberately lacks the const. */
typedef png_byte *png_const_bytep;
/* This is copied from 1.5.1 png.h: */
@@ -147,6 +157,31 @@
&(ps)->exception_context
#define context(ps,fault) anon_context(ps); png_store *fault
+/* This macro returns the number of elements in an array as an (unsigned int),
+ * it is necessary to avoid the inability of certain versions of GCC to use
+ * the value of a compile-time constant when performing range checks. It must
+ * be passed an array name.
+ */
+#define ARRAY_SIZE(a) ((unsigned int)((sizeof (a))/(sizeof (a)[0])))
+
+/* GCC BUG 66447 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66447) requires
+ * some broken GCC versions to be fixed up to avoid invalid whining about auto
+ * variables that are *not* changed within the scope of a setjmp being changed.
+ *
+ * Feel free to extend the list of broken versions.
+ */
+#define is_gnu(major,minor)\
+ (defined __GNUC__) && __GNUC__ == (major) && __GNUC_MINOR__ == (minor)
+#define is_gnu_patch(major,minor,patch)\
+ is_gnu(major,minor) && __GNUC_PATCHLEVEL__ == 0
+/* For the moment just do it always; all versions of GCC seem to be broken: */
+#ifdef __GNUC__
+ const void * volatile make_volatile_for_gnu;
+# define gnu_volatile(x) make_volatile_for_gnu = &x;
+#else /* !GNUC broken versions */
+# define gnu_volatile(x)
+#endif /* !GNUC broken versions */
+
/******************************* UTILITIES ************************************/
/* Error handling is particularly problematic in production code - error
* handlers often themselves have bugs which lead to programs that detect
@@ -155,7 +190,7 @@
* warning messages into buffers that are too small.
*/
static size_t safecat(char *buffer, size_t bufsize, size_t pos,
- PNG_CONST char *cat)
+ const char *cat)
{
while (pos < bufsize && cat != NULL && *cat != 0)
buffer[pos++] = *cat++;
@@ -184,16 +219,16 @@
}
#endif
-static PNG_CONST char invalid[] = "invalid";
-static PNG_CONST char sep[] = ": ";
+static const char invalid[] = "invalid";
+static const char sep[] = ": ";
-static PNG_CONST char *colour_types[8] =
+static const char *colour_types[8] =
{
"grayscale", invalid, "truecolour", "indexed-colour",
"grayscale with alpha", invalid, "truecolour with alpha", invalid
};
-#ifdef PNG_READ_SUPPORTED
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Convert a double precision value to fixed point. */
static png_fixed_point
fix(double d)
@@ -241,7 +276,7 @@
make_random_bytes(seed, bytes, 4);
}
-#ifdef PNG_READ_SUPPORTED
+#if defined PNG_READ_SUPPORTED || defined PNG_WRITE_tRNS_SUPPORTED
static void
randomize(void *pv, size_t size)
{
@@ -250,7 +285,9 @@
}
#define RANDOMIZE(this) randomize(&(this), sizeof (this))
+#endif /* READ || WRITE_tRNS */
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
static unsigned int
random_mod(unsigned int max)
{
@@ -261,7 +298,8 @@
return x % max; /* 0 .. max-1 */
}
-#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+#if (defined PNG_READ_RGB_TO_GRAY_SUPPORTED) ||\
+ (defined PNG_READ_FILLER_SUPPORTED)
static int
random_choice(void)
{
@@ -277,7 +315,8 @@
/* A numeric ID based on PNG file characteristics. The 'do_interlace' field
* simply records whether pngvalid did the interlace itself or whether it
* was done by libpng. Width and height must be less than 256. 'palette' is an
- * index of the palette to use for formats with a palette (0 otherwise.)
+ * index of the palette to use for formats with a palette otherwise a boolean
+ * indicating if a tRNS chunk was generated.
*/
#define FILEID(col, depth, palette, interlace, width, height, do_interlace) \
((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \
@@ -286,7 +325,7 @@
#define COL_FROM_ID(id) ((png_byte)((id)& 0x7U))
#define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU))
#define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f)
-#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3))
+#define INTERLACE_FROM_ID(id) ((png_byte)(((id) >> 13) & 0x3))
#define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1))
#define WIDTH_FROM_ID(id) (((id)>>16) & 0xff)
#define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff)
@@ -298,12 +337,16 @@
png_uint_32 w, png_uint_32 h, int do_interlace)
{
pos = safecat(buffer, bufsize, pos, colour_types[colour_type]);
- if (npalette > 0)
+ if (colour_type == 3) /* must have a palette */
{
pos = safecat(buffer, bufsize, pos, "[");
pos = safecatn(buffer, bufsize, pos, npalette);
pos = safecat(buffer, bufsize, pos, "]");
}
+
+ else if (npalette != 0)
+ pos = safecat(buffer, bufsize, pos, "+tRNS");
+
pos = safecat(buffer, bufsize, pos, " ");
pos = safecatn(buffer, bufsize, pos, bit_depth);
pos = safecat(buffer, bufsize, pos, " bit");
@@ -360,25 +403,32 @@
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;
}
@@ -386,9 +436,9 @@
/* Palette images are restricted to 8 bit depth */
if (*bit_depth <= 8
-# ifdef DO_16BIT
+#ifdef DO_16BIT
|| (*colour_type != 3 && *bit_depth <= 16)
-# endif
+#endif
)
return 1;
@@ -423,7 +473,7 @@
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
static unsigned int
sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
- png_uint_32 x, unsigned int sample_index)
+ png_uint_32 x, unsigned int sample_index, int swap16, int littleendian)
{
png_uint_32 bit_index, result;
@@ -452,11 +502,23 @@
return result;
else if (bit_depth > 8)
- return (result << 8) + *++row;
+ {
+ if (swap16)
+ return (*++row << 8) + result;
+ else
+ return (result << 8) + *++row;
+ }
- /* Less than 8 bits per sample. */
+ /* Less than 8 bits per sample. By default PNG has the big end of
+ * the egg on the left of the screen, but if littleendian is set
+ * then the big end is on the right.
+ */
bit_index &= 7;
- return (result >> (8-bit_index-bit_depth)) & ((1U<<bit_depth)-1);
+
+ if (!littleendian)
+ bit_index = 8-bit_index-bit_depth;
+
+ return (result >> bit_index) & ((1U<<bit_depth)-1);
}
#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
@@ -470,7 +532,8 @@
*/
static void
pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
- png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize)
+ png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize,
+ int littleendian)
{
/* Assume we can multiply by 'size' without overflow because we are
* just working in a single buffer.
@@ -480,15 +543,25 @@
if (pixelSize < 8) /* Sub-byte */
{
/* Mask to select the location of the copied pixel: */
- unsigned int destMask = ((1U<<pixelSize)-1) << (8-pixelSize-(toIndex&7));
+ unsigned int destMask = ((1U<<pixelSize)-1) <<
+ (littleendian ? toIndex&7 : 8-pixelSize-(toIndex&7));
/* The following read the entire pixels and clears the extra: */
unsigned int destByte = toBuffer[toIndex >> 3] & ~destMask;
unsigned int sourceByte = fromBuffer[fromIndex >> 3];
/* Don't rely on << or >> supporting '0' here, just in case: */
fromIndex &= 7;
- if (fromIndex > 0) sourceByte <<= fromIndex;
- if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
+ if (littleendian)
+ {
+ if (fromIndex > 0) sourceByte >>= fromIndex;
+ if ((toIndex & 7) > 0) sourceByte <<= toIndex & 7;
+ }
+
+ else
+ {
+ if (fromIndex > 0) sourceByte <<= fromIndex;
+ if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
+ }
toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask));
}
@@ -501,7 +574,8 @@
* bytes at the end.
*/
static void
-row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
+row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth,
+ int littleendian)
{
memcpy(toBuffer, fromBuffer, bitWidth >> 3);
@@ -511,10 +585,10 @@
toBuffer += bitWidth >> 3;
fromBuffer += bitWidth >> 3;
- /* The remaining bits are in the top of the byte, the mask is the bits to
- * retain.
- */
- mask = 0xff >> (bitWidth & 7);
+ if (littleendian)
+ mask = 0xff << (bitWidth & 7);
+ else
+ mask = 0xff >> (bitWidth & 7);
*toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask));
}
}
@@ -678,7 +752,7 @@
make_four_random_bytes(store_seed, mark);
}
-#ifdef PNG_READ_SUPPORTED
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Use this for random 32 bit values; this function makes sure the result is
* non-zero.
*/
@@ -686,7 +760,7 @@
random_32(void)
{
- for(;;)
+ for (;;)
{
png_byte mark[4];
png_uint_32 result;
@@ -836,7 +910,7 @@
/* Generate an error message (in the given buffer) */
static size_t
store_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize,
- size_t pos, PNG_CONST char *msg)
+ size_t pos, const char *msg)
{
if (pp != NULL && pp == ps->pread)
{
@@ -954,7 +1028,7 @@
*/
/* Return a single row from the correct image. */
static png_bytep
-store_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage,
+store_image_row(const png_store* ps, png_const_structp pp, int nImage,
png_uint_32 y)
{
png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2;
@@ -1058,7 +1132,7 @@
#ifdef PNG_READ_SUPPORTED
static void
-store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage)
+store_image_check(const png_store* ps, png_const_structp pp, int iImage)
{
png_const_bytep image = ps->image;
@@ -1275,7 +1349,10 @@
* operation.)
*/
if (ps->current == NULL)
+ {
store_log(ps, ps->pread, "no current stream for palette", 1);
+ return NULL;
+ }
/* The result may be null if there is no palette. */
*npalette = ps->current->npalette;
@@ -1305,7 +1382,7 @@
* all the memory.
*/
static void
-store_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg)
+store_pool_error(png_store *ps, png_const_structp pp, const char *msg)
{
if (pp != NULL)
png_error(pp, msg);
@@ -1369,7 +1446,7 @@
next->next = NULL;
fprintf(stderr, "\t%lu bytes @ %p\n",
- (unsigned long)next->size, (PNG_CONST void*)(next+1));
+ (unsigned long)next->size, (const void*)(next+1));
/* The NULL means this will always return, even if the memory is
* corrupted.
*/
@@ -1524,8 +1601,7 @@
* returned libpng structures as destroyed by store_write_reset above.
*/
static png_structp
-set_store_for_write(png_store *ps, png_infopp ppi,
- PNG_CONST char * volatile name)
+set_store_for_write(png_store *ps, png_infopp ppi, const char *name)
{
anon_context(ps);
@@ -1645,7 +1721,7 @@
*/
static png_structp
set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id,
- PNG_CONST char *name)
+ const char *name)
{
/* Set the name for png_error */
safecat(ps->test, sizeof ps->test, 0, name);
@@ -1752,6 +1828,7 @@
} color_encoding;
#ifdef PNG_READ_SUPPORTED
+#if defined PNG_READ_TRANSFORMS_SUPPORTED && defined PNG_READ_cHRM_SUPPORTED
static double
chromaticity_x(CIE_color c)
{
@@ -1765,7 +1842,7 @@
}
static CIE_color
-white_point(PNG_CONST color_encoding *encoding)
+white_point(const color_encoding *encoding)
{
CIE_color white;
@@ -1775,12 +1852,13 @@
return white;
}
+#endif /* READ_TRANSFORMS && READ_cHRM */
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
static void
normalize_color_encoding(color_encoding *encoding)
{
- PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y +
+ const double whiteY = encoding->red.Y + encoding->green.Y +
encoding->blue.Y;
if (whiteY != 1)
@@ -1798,9 +1876,10 @@
}
#endif
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
static size_t
safecat_color_encoding(char *buffer, size_t bufsize, size_t pos,
- PNG_CONST color_encoding *e, double encoding_gamma)
+ const color_encoding *e, double encoding_gamma)
{
if (e != 0)
{
@@ -1837,6 +1916,7 @@
return pos;
}
+#endif /* READ_TRANSFORMS */
#endif /* PNG_READ_SUPPORTED */
typedef struct png_modifier
@@ -1861,9 +1941,9 @@
unsigned int ngammas;
unsigned int ngamma_tests; /* Number of gamma tests to run*/
double current_gamma; /* 0 if not set */
- PNG_CONST color_encoding *encodings;
+ const color_encoding *encodings;
unsigned int nencodings;
- PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */
+ const color_encoding *current_encoding; /* If an encoding has been set */
unsigned int encoding_counter; /* For iteration */
int encoding_ignored; /* Something overwrote it */
@@ -1874,7 +1954,7 @@
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
@@ -1929,6 +2009,7 @@
/* Run tests on reading with a combination of transforms, */
unsigned int test_transform :1;
+ unsigned int test_tRNS :1; /* Includes tRNS images */
/* When to use the use_input_precision option, this controls the gamma
* validation code checks. If set any value that is within the transformed
@@ -1960,6 +2041,16 @@
unsigned int test_gamma_expand16 :1;
unsigned int test_exhaustive :1;
+ /* Whether or not to run the low-bit-depth grayscale tests. This fails on
+ * gamma images in some cases because of gross inaccuracies in the grayscale
+ * gamma handling for low bit depth.
+ */
+ unsigned int test_lbg :1;
+ unsigned int test_lbg_gamma_threshold :1;
+ unsigned int test_lbg_gamma_transform :1;
+ unsigned int test_lbg_gamma_sbit :1;
+ unsigned int test_lbg_gamma_composition :1;
+
unsigned int log :1; /* Log max error */
/* Buffer information, the buffer size limits the size of the chunks that can
@@ -2012,6 +2103,11 @@
pm->test_standard = 0;
pm->test_size = 0;
pm->test_transform = 0;
+# ifdef PNG_WRITE_tRNS_SUPPORTED
+ pm->test_tRNS = 1;
+# else
+ pm->test_tRNS = 0;
+# endif
pm->use_input_precision = 0;
pm->use_input_precision_sbit = 0;
pm->use_input_precision_16to8 = 0;
@@ -2024,6 +2120,11 @@
pm->test_gamma_background = 0;
pm->test_gamma_alpha_mode = 0;
pm->test_gamma_expand16 = 0;
+ pm->test_lbg = 1;
+ pm->test_lbg_gamma_threshold = 1;
+ pm->test_lbg_gamma_transform = 1;
+ pm->test_lbg_gamma_sbit = 1;
+ pm->test_lbg_gamma_composition = 1;
pm->test_exhaustive = 0;
pm->log = 0;
@@ -2057,7 +2158,7 @@
* rounding and 'do_round' should be 1, if it is 0 the digitized value will
* be truncated.
*/
- PNG_CONST unsigned int digitization_factor = (1U << depth) -1;
+ const unsigned int digitization_factor = (1U << depth) -1;
/* Limiting the range is done as a convenience to the caller - it's easier to
* do it once here than every time at the call site.
@@ -2076,7 +2177,7 @@
#endif /* RGB_TO_GRAY */
#ifdef PNG_READ_GAMMA_SUPPORTED
-static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double abserr(const png_modifier *pm, int in_depth, int out_depth)
{
/* Absolute error permitted in linear values - affected by the bit depth of
* the calculations.
@@ -2088,7 +2189,7 @@
return pm->maxabs8;
}
-static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double calcerr(const png_modifier *pm, int in_depth, int out_depth)
{
/* Error in the linear composition arithmetic - only relevant when
* composition actually happens (0 < alpha < 1).
@@ -2101,7 +2202,7 @@
return pm->maxcalc8;
}
-static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double pcerr(const png_modifier *pm, int in_depth, int out_depth)
{
/* Percentage error permitted in the linear values. Note that the specified
* value is a percentage but this routine returns a simple number.
@@ -2124,7 +2225,7 @@
* The specified parameter does *not* include the base .5 digitization error but
* it is added here.
*/
-static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double outerr(const png_modifier *pm, int in_depth, int out_depth)
{
/* There is a serious error in the 2 and 4 bit grayscale transform because
* the gamma table value (8 bits) is simply shifted, not rounded, so the
@@ -2156,7 +2257,7 @@
* rather than raising a warning. This is useful for debugging to track down
* exactly what set of parameters cause high error values.
*/
-static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
+static double outlog(const png_modifier *pm, int in_depth, int out_depth)
{
/* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535)
* and so must be adjusted for low bit depth grayscale:
@@ -2194,7 +2295,7 @@
* but in the 8 bit calculation case it's actually quantization to a multiple of
* 257!
*/
-static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth,
+static int output_quantization_factor(const png_modifier *pm, int in_depth,
int out_depth)
{
if (out_depth == 16 && in_depth != 16 &&
@@ -2258,7 +2359,7 @@
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
static void
-modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce)
+modifier_current_encoding(const png_modifier *pm, color_encoding *ce)
{
if (pm->current_encoding != 0)
*ce = *pm->current_encoding;
@@ -2270,9 +2371,10 @@
}
#endif
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
static size_t
safecat_current_encoding(char *buffer, size_t bufsize, size_t pos,
- PNG_CONST png_modifier *pm)
+ const png_modifier *pm)
{
pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding,
pm->current_gamma);
@@ -2282,6 +2384,7 @@
return pos;
}
+#endif
/* Iterate through the usefully testable color encodings. An encoding is one
* of:
@@ -2301,7 +2404,7 @@
* caller of modifier_reset must reset it at the start of each run of the test!
*/
static unsigned int
-modifier_total_encodings(PNG_CONST png_modifier *pm)
+modifier_total_encodings(const png_modifier *pm)
{
return 1 + /* (1) nothing */
pm->ngammas + /* (2) gamma values to test */
@@ -2417,14 +2520,14 @@
* assumption below that the first encoding in the list is the one for sRGB.
*/
static int
-modifier_color_encoding_is_sRGB(PNG_CONST png_modifier *pm)
+modifier_color_encoding_is_sRGB(const png_modifier *pm)
{
return pm->current_encoding != 0 && pm->current_encoding == pm->encodings &&
pm->current_encoding->gamma == pm->current_gamma;
}
static int
-modifier_color_encoding_is_set(PNG_CONST png_modifier *pm)
+modifier_color_encoding_is_set(const png_modifier *pm)
{
return pm->current_gamma != 0;
}
@@ -2743,7 +2846,7 @@
/* Set up a modifier. */
static png_structp
set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id,
- PNG_CONST char *name)
+ const char *name)
{
/* Do this first so that the modifier fields are cleared even if an error
* happens allocating the png_struct. No allocation is done here so no
@@ -2803,7 +2906,7 @@
typedef struct chrm_modification
{
png_modification this;
- PNG_CONST color_encoding *encoding;
+ const color_encoding *encoding;
png_fixed_point wx, wy, rx, ry, gx, gy, bx, by;
} chrm_modification;
@@ -2827,7 +2930,7 @@
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);
@@ -3162,6 +3265,45 @@
}
}
+#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);
+
+ RANDOMIZE(tRNS);
+
+ if (colour_type & 2/*RGB*/)
+ {
+ if (bit_depth == 8)
+ {
+ tRNS.blue = tRNS.red ^ tRNS.green;
+ tRNS.red &= mask;
+ tRNS.green &= mask;
+ tRNS.blue &= mask;
+ }
+
+ else /* bit_depth == 16 */
+ {
+ tRNS.green = (png_uint_16)(tRNS.red * 257);
+ tRNS.blue = (png_uint_16)(tRNS.green * 17);
+ }
+ }
+
+ else
+ tRNS.gray &= mask;
+
+ png_set_tRNS(pp, pi, NULL, 0, &tRNS);
+}
+#endif
+
/* The number of passes is related to the interlace type. There was no libpng
* API to determine this prior to 1.5, so we need an inquiry function:
*/
@@ -3411,13 +3553,17 @@
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
# define INTERLACE_LAST PNG_INTERLACE_LAST
# define check_interlace_type(type) ((void)(type))
-#else
-# define INTERLACE_LAST (PNG_INTERLACE_NONE+1)
-# define png_set_interlace_handling(a) (1)
-
+# define set_write_interlace_handling(pp,type) png_set_interlace_handling(pp)
+# define do_own_interlace 0
+#elif PNG_LIBPNG_VER < 10700
+# define set_write_interlace_handling(pp,type) (1)
static void
-check_interlace_type(int PNG_CONST interlace_type)
+check_interlace_type(int const interlace_type)
{
+ /* Prior to 1.7.0 libpng does not support the write of an interlaced image
+ * unless PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the
+ * code here does the pixel interlace itself, so:
+ */
if (interlace_type != PNG_INTERLACE_NONE)
{
/* This is an internal error - --interlace tests should be skipped, not
@@ -3427,17 +3573,85 @@
exit(99);
}
}
-#endif
+# 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 */
-/* Make a standardized image given a an image colour type, bit depth and
+#define CAN_WRITE_INTERLACE\
+ PNG_LIBPNG_VER >= 10700 || defined PNG_WRITE_INTERLACING_SUPPORTED
+
+/* Do the same thing for read interlacing; this controls whether read tests do
+ * their own de-interlace or use libpng.
+ */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+# define do_read_interlace 0
+#else /* no libpng read interlace support */
+# define do_read_interlace 1
+#endif
+/* The following two routines use the PNG interlace support macros from
+ * png.h to interlace or deinterlace rows.
+ */
+static void
+interlace_row(png_bytep buffer, png_const_bytep imageRow,
+ unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
+{
+ png_uint_32 xin, xout, xstep;
+
+ /* Note that this can, trivially, be optimized to a memcpy on pass 7, the
+ * code is presented this way to make it easier to understand. In practice
+ * consult the code in the libpng source to see other ways of doing this.
+ *
+ * It is OK for buffer and imageRow to be identical, because 'xin' moves
+ * faster than 'xout' and we copy up.
+ */
+ xin = PNG_PASS_START_COL(pass);
+ xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
+
+ for (xout=0; xin<w; xin+=xstep)
+ {
+ pixel_copy(buffer, xout, imageRow, xin, pixel_size, littleendian);
+ ++xout;
+ }
+}
+
+#ifdef PNG_READ_SUPPORTED
+static void
+deinterlace_row(png_bytep buffer, png_const_bytep row,
+ unsigned int pixel_size, png_uint_32 w, int pass, int littleendian)
+{
+ /* The inverse of the above, 'row' is part of row 'y' of the output image,
+ * in 'buffer'. The image is 'w' wide and this is pass 'pass', distribute
+ * the pixels of row into buffer and return the number written (to allow
+ * this to be checked).
+ */
+ png_uint_32 xin, xout, xstep;
+
+ xout = PNG_PASS_START_COL(pass);
+ xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
+
+ for (xin=0; xout<w; xout+=xstep)
+ {
+ pixel_copy(buffer, xout, row, xin, pixel_size, littleendian);
+ ++xin;
+ }
+}
+#endif /* PNG_READ_SUPPORTED */
+
+/* Make a standardized image given 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.
*/
static void
-make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
- png_byte PNG_CONST bit_depth, unsigned int palette_number,
+make_transform_image(png_store* const ps, png_byte const colour_type,
+ png_byte const bit_depth, unsigned int palette_number,
int interlace_type, png_const_charp name)
{
context(ps, fault);
@@ -3448,7 +3662,7 @@
{
png_infop pi;
png_structp pp = set_store_for_write(ps, &pi, name);
- png_uint_32 h;
+ png_uint_32 h, w;
/* In the event of a problem return control to the Catch statement below
* to do the clean up - it is not possible to 'return' directly from a Try
@@ -3457,10 +3671,10 @@
if (pp == NULL)
Throw ps;
+ w = transform_width(pp, colour_type, bit_depth);
h = transform_height(pp, colour_type, bit_depth);
- png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), h,
- bit_depth, colour_type, interlace_type,
+ png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
#ifdef PNG_TEXT_SUPPORTED
@@ -3495,11 +3709,16 @@
if (colour_type == 3) /* palette */
init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/);
+# ifdef PNG_WRITE_tRNS_SUPPORTED
+ else if (palette_number)
+ set_random_tRNS(pp, pi, colour_type, bit_depth);
+# endif
+
png_write_info(pp, pi);
if (png_get_rowbytes(pp, pi) !=
transform_rowsize(pp, colour_type, bit_depth))
- png_error(pp, "row size incorrect");
+ png_error(pp, "transform row size incorrect");
else
{
@@ -3507,7 +3726,7 @@
* because if it is called before, the information in *pp has not been
* updated to reflect the interlaced image.
*/
- int npasses = png_set_interlace_handling(pp);
+ int npasses = set_write_interlace_handling(pp, interlace_type);
int pass;
if (npasses != npasses_from_interlace_type(pp, interlace_type))
@@ -3517,11 +3736,37 @@
{
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 */
+
png_write_row(pp, buffer);
}
}
@@ -3568,19 +3813,20 @@
}
static void
-make_transform_images(png_store *ps)
+make_transform_images(png_modifier *pm)
{
png_byte colour_type = 0;
png_byte bit_depth = 0;
unsigned int palette_number = 0;
/* This is in case of errors. */
- safecat(ps->test, sizeof ps->test, 0, "make standard images");
+ safecat(pm->this.test, sizeof pm->this.test, 0, "make standard images");
/* Use next_format to enumerate all the combinations we test, including
- * generating multiple low bit depth palette images.
+ * generating multiple low bit depth palette images. Non-A images (palette
+ * and direct) are created with and without tRNS chunks.
*/
- while (next_format(&colour_type, &bit_depth, &palette_number, 0))
+ while (next_format(&colour_type, &bit_depth, &palette_number, 1, 1))
{
int interlace_type;
@@ -3590,59 +3836,13 @@
char name[FILE_NAME_SIZE];
standard_name(name, sizeof name, 0, colour_type, bit_depth,
- palette_number, interlace_type, 0, 0, 0);
- make_transform_image(ps, colour_type, bit_depth, palette_number,
+ palette_number, interlace_type, 0, 0, do_own_interlace);
+ make_transform_image(&pm->this, colour_type, bit_depth, palette_number,
interlace_type, name);
}
}
}
-/* The following two routines use the PNG interlace support macros from
- * png.h to interlace or deinterlace rows.
- */
-static void
-interlace_row(png_bytep buffer, png_const_bytep imageRow,
- unsigned int pixel_size, png_uint_32 w, int pass)
-{
- png_uint_32 xin, xout, xstep;
-
- /* Note that this can, trivially, be optimized to a memcpy on pass 7, the
- * code is presented this way to make it easier to understand. In practice
- * consult the code in the libpng source to see other ways of doing this.
- */
- xin = PNG_PASS_START_COL(pass);
- xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
-
- for (xout=0; xin<w; xin+=xstep)
- {
- pixel_copy(buffer, xout, imageRow, xin, pixel_size);
- ++xout;
- }
-}
-
-#ifdef PNG_READ_SUPPORTED
-static void
-deinterlace_row(png_bytep buffer, png_const_bytep row,
- unsigned int pixel_size, png_uint_32 w, int pass)
-{
- /* The inverse of the above, 'row' is part of row 'y' of the output image,
- * in 'buffer'. The image is 'w' wide and this is pass 'pass', distribute
- * the pixels of row into buffer and return the number written (to allow
- * this to be checked).
- */
- png_uint_32 xin, xout, xstep;
-
- xout = PNG_PASS_START_COL(pass);
- xstep = 1U<<PNG_PASS_COL_SHIFT(pass);
-
- for (xin=0; xout<w; xout+=xstep)
- {
- pixel_copy(buffer, xout, row, xin, pixel_size);
- ++xin;
- }
-}
-#endif /* PNG_READ_SUPPORTED */
-
/* Build a single row for the 'size' test images; this fills in only the
* first bit_width bits of the sample row.
*/
@@ -3668,17 +3868,13 @@
}
static void
-make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
- png_byte PNG_CONST bit_depth, int PNG_CONST interlace_type,
- png_uint_32 PNG_CONST w, png_uint_32 PNG_CONST h,
- int PNG_CONST do_interlace)
+make_size_image(png_store* const ps, png_byte const colour_type,
+ png_byte const bit_depth, int const interlace_type,
+ png_uint_32 const w, png_uint_32 const h,
+ int const do_interlace)
{
context(ps, fault);
- /* At present libpng does not support the write of an interlaced image unless
- * PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the code here
- * does the pixel interlace itself, so:
- */
check_interlace_type(interlace_type);
Try
@@ -3689,7 +3885,7 @@
/* Make a name and get an appropriate id for the store: */
char name[FILE_NAME_SIZE];
- PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/,
+ const png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/,
interlace_type, w, h, do_interlace);
standard_name_from_id(name, sizeof name, 0, id);
@@ -3740,7 +3936,7 @@
*/
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
{
@@ -3757,7 +3953,8 @@
*/
memset(image, 0xff, sizeof image);
- if (!do_interlace && npasses != png_set_interlace_handling(pp))
+ if (!do_interlace &&
+ npasses != set_write_interlace_handling(pp, interlace_type))
png_error(pp, "write: png_set_interlace_handling failed");
/* Prepare the whole image first to avoid making it 7 times: */
@@ -3767,7 +3964,7 @@
for (pass=0; pass<npasses; ++pass)
{
/* The following two are for checking the macros: */
- PNG_CONST png_uint_32 wPass = PNG_PASS_COLS(w, pass);
+ const png_uint_32 wPass = PNG_PASS_COLS(w, pass);
/* If do_interlace is set we don't call png_write_row for every
* row because some of them are empty. In fact, for a 1x1 image,
@@ -3796,7 +3993,8 @@
* 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
@@ -3866,8 +4064,8 @@
}
static void
-make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
- int PNG_CONST bdhi)
+make_size(png_store* const ps, png_byte const colour_type, int bdlo,
+ int const bdhi)
{
for (; bdlo <= bdhi; ++bdlo)
{
@@ -3890,6 +4088,11 @@
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
width, height, 0);
+# endif
+# if CAN_WRITE_INTERLACE
+ /* 1.7.0 removes the hack that prevented app write of an interlaced
+ * image if WRITE_INTERLACE was not supported
+ */
make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
width, height, 1);
# endif
@@ -3963,41 +4166,45 @@
png_set_sBIT(pp, pi, &bad);
}
-static PNG_CONST struct
+static const struct
{
void (*fn)(png_structp, png_infop);
- PNG_CONST char *msg;
+ const char *msg;
unsigned int warning :1; /* the error is a warning... */
} error_test[] =
{
- /* no warnings makes these errors undetectable. */
- { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 },
- { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 },
+ /* no warnings makes these errors undetectable prior to 1.7.0 */
+ { sBIT0_error_fn, "sBIT(0): failed to detect error",
+ PNG_LIBPNG_VER < 10700 },
+
+ { sBIT_error_fn, "sBIT(too big): failed to detect error",
+ PNG_LIBPNG_VER < 10700 },
};
static void
-make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type,
+make_error(png_store* const ps, png_byte const colour_type,
png_byte bit_depth, int interlace_type, int test, png_const_charp name)
{
- png_store * volatile ps = psIn;
-
context(ps, fault);
check_interlace_type(interlace_type);
Try
{
- png_structp pp;
png_infop pi;
-
- pp = set_store_for_write(ps, &pi, name);
+ const png_structp pp = set_store_for_write(ps, &pi, name);
+ png_uint_32 w, h;
+ gnu_volatile(pp)
if (pp == NULL)
Throw ps;
- png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth),
- transform_height(pp, colour_type, bit_depth), bit_depth, colour_type,
- interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+ w = transform_width(pp, colour_type, bit_depth);
+ gnu_volatile(w)
+ h = transform_height(pp, colour_type, bit_depth);
+ gnu_volatile(h)
+ png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (colour_type == 3) /* palette */
init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/);
@@ -4009,6 +4216,8 @@
# define exception__env exception_env_1
Try
{
+ gnu_volatile(exception__prev)
+
/* Expect this to throw: */
ps->expect_error = !error_test[test].warning;
ps->expect_warning = error_test[test].warning;
@@ -4029,7 +4238,8 @@
}
Catch (fault)
- ps = fault; /* expected exit, make sure ps is not clobbered */
+ { /* expected exit */
+ }
#undef exception__prev
#undef exception__env
@@ -4046,8 +4256,7 @@
else
{
- png_uint_32 h = transform_height(pp, colour_type, bit_depth);
- 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))
@@ -4062,6 +4271,29 @@
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);
}
}
@@ -4080,8 +4312,8 @@
}
static int
-make_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
- int bdlo, int PNG_CONST bdhi)
+make_errors(png_modifier* const pm, png_byte const colour_type,
+ int bdlo, int const bdhi)
{
for (; bdlo <= bdhi; ++bdlo)
{
@@ -4094,9 +4326,9 @@
char name[FILE_NAME_SIZE];
standard_name(name, sizeof name, 0, colour_type, 1<<bdlo, 0,
- interlace_type, 0, 0, 0);
+ interlace_type, 0, 0, do_own_interlace);
- for (test=0; test<(sizeof error_test)/(sizeof error_test[0]); ++test)
+ for (test=0; test<ARRAY_SIZE(error_test); ++test)
{
make_error(&pm->this, colour_type, DEPTH(bdlo), interlace_type,
test, name);
@@ -4141,7 +4373,7 @@
* then the warning messages the library outputs will probably be garbage.
*/
static void
-perform_formatting_test(png_store *volatile ps)
+perform_formatting_test(png_store *ps)
{
#ifdef PNG_TIME_RFC1123_SUPPORTED
/* The handle into the formatting code is the RFC1123 support; this test does
@@ -4246,7 +4478,8 @@
png_byte green_sBIT;
png_byte blue_sBIT;
png_byte alpha_sBIT;
- int interlace_type;
+ png_byte interlace_type;
+ png_byte filler; /* Output has a filler */
png_uint_32 id; /* Calculated file ID */
png_uint_32 w; /* Width of image */
png_uint_32 h; /* Height of image */
@@ -4255,7 +4488,9 @@
png_uint_32 bit_width; /* Width of output row in bits */
size_t cbRow; /* Bytes in a row of the output image */
int do_interlace; /* Do interlacing internally */
+ int littleendian; /* App (row) data is little endian */
int is_transparent; /* Transparency information was present. */
+ int has_tRNS; /* color type GRAY or RGB with a tRNS chunk. */
int speed; /* Doing a speed test */
int use_update_info;/* Call update_info, not start_image */
struct
@@ -4296,6 +4531,7 @@
dp->bit_width = 0;
dp->cbRow = 0;
dp->do_interlace = do_interlace;
+ dp->littleendian = 0;
dp->is_transparent = 0;
dp->speed = ps->speed;
dp->use_update_info = use_update_info;
@@ -4588,14 +4824,14 @@
case 0:
dp->transparent.red = dp->transparent.green = dp->transparent.blue =
trans_color->gray;
- dp->is_transparent = 1;
+ dp->has_tRNS = 1;
break;
case 2:
dp->transparent.red = trans_color->red;
dp->transparent.green = trans_color->green;
dp->transparent.blue = trans_color->blue;
- dp->is_transparent = 1;
+ dp->has_tRNS = 1;
break;
case 3:
@@ -4616,8 +4852,19 @@
* turning on interlace handling (if do_interlace is not set.)
*/
dp->npasses = npasses_from_interlace_type(pp, dp->interlace_type);
- if (!dp->do_interlace && dp->npasses != png_set_interlace_handling(pp))
- png_error(pp, "validate: file changed interlace type");
+ if (!dp->do_interlace)
+ {
+# ifdef PNG_READ_INTERLACING_SUPPORTED
+ if (dp->npasses != png_set_interlace_handling(pp))
+ png_error(pp, "validate: file changed interlace type");
+# else /* !READ_INTERLACING */
+ /* This should never happen: the relevant tests (!do_interlace) should
+ * not be run.
+ */
+ if (dp->npasses > 1)
+ png_error(pp, "validate: no libpng interlace support");
+# endif /* !READ_INTERLACING */
+ }
/* Caller calls png_read_update_info or png_start_read_image now, then calls
* part2.
@@ -4633,8 +4880,16 @@
png_const_infop pi, int nImages)
{
/* Record cbRow now that it can be found. */
- dp->pixel_size = bit_size(pp, png_get_color_type(pp, pi),
- png_get_bit_depth(pp, pi));
+ {
+ png_byte ct = png_get_color_type(pp, pi);
+ png_byte bd = png_get_bit_depth(pp, pi);
+
+ if (bd >= 8 && (ct == PNG_COLOR_TYPE_RGB || ct == PNG_COLOR_TYPE_GRAY) &&
+ dp->filler)
+ ct |= 4; /* handle filler as faked alpha channel */
+
+ dp->pixel_size = bit_size(pp, ct, bd);
+ }
dp->bit_width = png_get_image_width(pp, pi) * dp->pixel_size;
dp->cbRow = png_get_rowbytes(pp, pi);
@@ -4691,7 +4946,7 @@
progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass)
{
png_const_structp pp = ppIn;
- PNG_CONST standard_display *dp = voidcast(standard_display*,
+ const standard_display *dp = voidcast(standard_display*,
png_get_progressive_ptr(pp));
/* When handling interlacing some rows will be absent in each pass, the
@@ -4715,7 +4970,7 @@
if (pass != png_get_current_pass_number(pp))
png_error(pp, "png_get_current_pass_number is broken");
-#endif
+#endif /* USER_TRANSFORM_INFO */
y = PNG_ROW_FROM_PASS_ROW(y, pass);
}
@@ -4726,38 +4981,39 @@
row = store_image_row(dp->ps, pp, 0, y);
-#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Combine the new row into the old: */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
if (dp->do_interlace)
+#endif /* READ_INTERLACING */
{
if (dp->interlace_type == PNG_INTERLACE_ADAM7)
- deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass);
+ deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass,
+ dp->littleendian);
else
- row_copy(row, new_row, dp->pixel_size * dp->w);
+ row_copy(row, new_row, dp->pixel_size * dp->w, dp->littleendian);
}
+#ifdef PNG_READ_INTERLACING_SUPPORTED
else
png_progressive_combine_row(pp, row, new_row);
#endif /* PNG_READ_INTERLACING_SUPPORTED */
}
-#ifdef PNG_READ_INTERLACING_SUPPORTED
else if (dp->interlace_type == PNG_INTERLACE_ADAM7 &&
PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
PNG_PASS_COLS(dp->w, pass) > 0)
png_error(pp, "missing row in progressive de-interlacing");
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
}
static void
sequential_row(standard_display *dp, png_structp pp, png_infop pi,
- PNG_CONST int iImage, PNG_CONST int iDisplay)
+ const int iImage, const int iDisplay)
{
- PNG_CONST int npasses = dp->npasses;
- PNG_CONST int do_interlace = dp->do_interlace &&
+ const int npasses = dp->npasses;
+ const int do_interlace = dp->do_interlace &&
dp->interlace_type == PNG_INTERLACE_ADAM7;
- PNG_CONST png_uint_32 height = standard_height(pp, dp->id);
- PNG_CONST png_uint_32 width = standard_width(pp, dp->id);
- PNG_CONST png_store* ps = dp->ps;
+ const png_uint_32 height = standard_height(pp, dp->id);
+ const png_uint_32 width = standard_width(pp, dp->id);
+ const png_store* ps = dp->ps;
int pass;
for (pass=0; pass<npasses; ++pass)
@@ -4792,11 +5048,11 @@
if (iImage >= 0)
deinterlace_row(store_image_row(ps, pp, iImage, y), row,
- dp->pixel_size, dp->w, pass);
+ dp->pixel_size, dp->w, pass, dp->littleendian);
if (iDisplay >= 0)
deinterlace_row(store_image_row(ps, pp, iDisplay, y), display,
- dp->pixel_size, dp->w, pass);
+ dp->pixel_size, dp->w, pass, dp->littleendian);
}
}
else
@@ -4943,14 +5199,6 @@
* In earlier passes 'row' will be partially filled in, with only the pixels
* that have been read so far, but 'display' will have those pixels
* replicated to fill the unread pixels while reading an interlaced image.
-#if PNG_LIBPNG_VER < 10506
- * The side effect inside the libpng sequential reader is that the 'row'
- * array retains the correct values for unwritten pixels within the row
- * bytes, while the 'display' array gets bits off the end of the image (in
- * the last byte) trashed. Unfortunately in the progressive reader the
- * row bytes are always trashed, so we always do a pixel_cmp here even though
- * a memcmp of all cbRow bytes will succeed for the sequential reader.
-#endif
*/
if (iImage >= 0 &&
(where = pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y),
@@ -4963,19 +5211,12 @@
png_error(pp, msg);
}
-#if PNG_LIBPNG_VER < 10506
- /* In this case use pixel_cmp because we need to compare a partial
- * byte at the end of the row if the row is not an exact multiple
- * of 8 bits wide. (This is fixed in libpng-1.5.6 and pixel_cmp is
- * changed to match!)
- */
-#endif
if (iDisplay >= 0 &&
(where = pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y),
dp->bit_width)) != 0)
{
char msg[64];
- sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x",
+ sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x",
(unsigned long)y, where-1, std[where-1],
store_image_row(dp->ps, pp, iDisplay, y)[where-1]);
png_error(pp, msg);
@@ -5020,7 +5261,7 @@
/* A single test run checking the standard image to ensure it is not damaged. */
static void
-standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id,
+standard_test(png_store* const psIn, png_uint_32 const id,
int do_interlace, int use_update_info)
{
standard_display d;
@@ -5108,8 +5349,8 @@
}
static int
-test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
- int bdlo, int PNG_CONST bdhi)
+test_standard(png_modifier* const pm, png_byte const colour_type,
+ int bdlo, int const bdhi)
{
for (; bdlo <= bdhi; ++bdlo)
{
@@ -5119,7 +5360,7 @@
interlace_type < INTERLACE_LAST; ++interlace_type)
{
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
- interlace_type, 0, 0, 0), 0/*do_interlace*/, pm->use_update_info);
+ interlace_type, 0, 0, 0), do_read_interlace, pm->use_update_info);
if (fail(pm))
return 0;
@@ -5154,8 +5395,8 @@
/********************************** SIZE TESTS ********************************/
static int
-test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
- int bdlo, int PNG_CONST bdhi)
+test_size(png_modifier* const pm, png_byte const colour_type,
+ int bdlo, int const bdhi)
{
/* Run the tests on each combination.
*
@@ -5164,8 +5405,10 @@
* width and height. This is a waste of time in practice, hence the
* hinc and winc stuff:
*/
- static PNG_CONST png_byte hinc[] = {1, 3, 11, 1, 5};
- static PNG_CONST png_byte winc[] = {1, 9, 5, 7, 1};
+ static const png_byte hinc[] = {1, 3, 11, 1, 5};
+ static const png_byte winc[] = {1, 9, 5, 7, 1};
+ const int save_bdlo = bdlo;
+
for (; bdlo <= bdhi; ++bdlo)
{
png_uint_32 h, w;
@@ -5191,22 +5434,6 @@
if (fail(pm))
return 0;
-# ifdef PNG_WRITE_INTERLACING_SUPPORTED
- 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;
-
- standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
- PNG_INTERLACE_ADAM7, w, h, 1), 0/*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.
@@ -5218,7 +5445,45 @@
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), 1/*do_interlace*/,
+ pm->use_update_info);
+
+ if (fail(pm))
+ return 0;
+# endif
+ }
+ }
+
+ /* 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_ADAM7, w, h, 1), 0/*do_interlace*/,
+ pm->use_update_info);
+
+ if (fail(pm))
+ return 0;
+# endif
+# endif /* READ_INTERLACING */
+
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* Test the libpng write side against the pngvalid read side: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/,
pm->use_update_info);
@@ -5226,6 +5491,18 @@
if (fail(pm))
return 0;
# endif
+
+# ifdef PNG_READ_INTERLACING_SUPPORTED
+# ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* Test both together: */
+ standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
+ PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/,
+ pm->use_update_info);
+
+ if (fail(pm))
+ return 0;
+# endif
+# endif /* READ_INTERLACING */
}
}
@@ -5274,10 +5551,17 @@
*/
unsigned int red, green, blue, alpha; /* For non-palette images. */
unsigned int palette_index; /* For a palette image. */
- png_byte colour_type; /* As in the spec. */
- png_byte bit_depth; /* Defines bit size in row */
- png_byte sample_depth; /* Scale of samples */
- int have_tRNS; /* tRNS chunk may need processing */
+ png_byte colour_type; /* As in the spec. */
+ png_byte bit_depth; /* Defines bit size in row */
+ png_byte sample_depth; /* Scale of samples */
+ unsigned int have_tRNS :1; /* tRNS chunk may need processing */
+ unsigned int swap_rgb :1; /* RGB swapped to BGR */
+ unsigned int alpha_first :1; /* Alpha at start, not end */
+ unsigned int alpha_inverted :1; /* Alpha channel inverted */
+ unsigned int mono_inverted :1; /* Gray channel inverted */
+ unsigned int swap16 :1; /* Byte swap 16-bit components */
+ unsigned int littleendian :1; /* High bits on right */
+ unsigned int sig_bits :1; /* Pixel shifted (sig bits only) */
/* For checking the code calculates double precision floating point values
* along with an error value, accumulated from the transforms. Because an
@@ -5285,6 +5569,9 @@
* up to just less than +/-1 in the scaled value) the *lowest* sBIT for each
* channel is stored. This sBIT value is folded in to the stored error value
* at the end of the application of the transforms to the pixel.
+ *
+ * If sig_bits is set above the red, green, blue and alpha values have been
+ * scaled so they only contain the significant bits of the component values.
*/
double redf, greenf, bluef, alphaf;
double rede, greene, bluee, alphae;
@@ -5293,26 +5580,27 @@
/* Shared utility function, see below. */
static void
-image_pixel_setf(image_pixel *this, unsigned int max)
+image_pixel_setf(image_pixel *this, unsigned int rMax, unsigned int gMax,
+ unsigned int bMax, unsigned int aMax)
{
- this->redf = this->red / (double)max;
- this->greenf = this->green / (double)max;
- this->bluef = this->blue / (double)max;
- this->alphaf = this->alpha / (double)max;
+ this->redf = this->red / (double)rMax;
+ this->greenf = this->green / (double)gMax;
+ this->bluef = this->blue / (double)bMax;
+ this->alphaf = this->alpha / (double)aMax;
- if (this->red < max)
+ if (this->red < rMax)
this->rede = this->redf * DBL_EPSILON;
else
this->rede = 0;
- if (this->green < max)
+ if (this->green < gMax)
this->greene = this->greenf * DBL_EPSILON;
else
this->greene = 0;
- if (this->blue < max)
+ if (this->blue < bMax)
this->bluee = this->bluef * DBL_EPSILON;
else
this->bluee = 0;
- if (this->alpha < max)
+ if (this->alpha < aMax)
this->alphae = this->alphaf * DBL_EPSILON;
else
this->alphae = 0;
@@ -5324,18 +5612,22 @@
*/
static void
image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
- png_byte bit_depth, png_uint_32 x, store_palette palette)
+ png_byte bit_depth, png_uint_32 x, store_palette palette,
+ const image_pixel *format /*from pngvalid transform of input*/)
{
- PNG_CONST png_byte sample_depth = (png_byte)(colour_type ==
+ const png_byte sample_depth = (png_byte)(colour_type ==
PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth);
- PNG_CONST unsigned int max = (1U<<sample_depth)-1;
+ const unsigned int max = (1U<<sample_depth)-1;
+ const int swap16 = (format != 0 && format->swap16);
+ const int littleendian = (format != 0 && format->littleendian);
+ const int sig_bits = (format != 0 && format->sig_bits);
/* Initially just set everything to the same number and the alpha to opaque.
* Note that this currently assumes a simple palette where entry x has colour
* rgb(x,x,x)!
*/
this->palette_index = this->red = this->green = this->blue =
- sample(row, colour_type, bit_depth, x, 0);
+ sample(row, colour_type, bit_depth, x, 0, swap16, littleendian);
this->alpha = max;
this->red_sBIT = this->green_sBIT = this->blue_sBIT = this->alpha_sBIT =
sample_depth;
@@ -5346,7 +5638,7 @@
/* This permits the caller to default to the sample value. */
if (palette != 0)
{
- PNG_CONST unsigned int i = this->palette_index;
+ const unsigned int i = this->palette_index;
this->red = palette[i].red;
this->green = palette[i].green;
@@ -5359,21 +5651,52 @@
{
unsigned int i = 0;
+ if ((colour_type & 4) != 0 && format != 0 && format->alpha_first)
+ {
+ this->alpha = this->red;
+ /* This handles the gray case for 'AG' pixels */
+ this->palette_index = this->red = this->green = this->blue =
+ sample(row, colour_type, bit_depth, x, 1, swap16, littleendian);
+ i = 1;
+ }
+
if (colour_type & 2)
{
- this->green = sample(row, colour_type, bit_depth, x, 1);
- this->blue = sample(row, colour_type, bit_depth, x, 2);
- i = 2;
+ /* Green is second for both BGR and RGB: */
+ this->green = sample(row, colour_type, bit_depth, x, ++i, swap16,
+ littleendian);
+
+ if (format != 0 && format->swap_rgb) /* BGR */
+ this->red = sample(row, colour_type, bit_depth, x, ++i, swap16,
+ littleendian);
+ else
+ this->blue = sample(row, colour_type, bit_depth, x, ++i, swap16,
+ littleendian);
}
- if (colour_type & 4)
- this->alpha = sample(row, colour_type, bit_depth, x, ++i);
+
+ else /* grayscale */ if (format != 0 && format->mono_inverted)
+ this->red = this->green = this->blue = this->red ^ max;
+
+ if ((colour_type & 4) != 0) /* alpha */
+ {
+ if (format == 0 || !format->alpha_first)
+ this->alpha = sample(row, colour_type, bit_depth, x, ++i, swap16,
+ littleendian);
+
+ if (format != 0 && format->alpha_inverted)
+ this->alpha ^= max;
+ }
}
/* Calculate the scaled values, these are simply the values divided by
* 'max' and the error is initialized to the double precision epsilon value
* from the header file.
*/
- image_pixel_setf(this, max);
+ image_pixel_setf(this,
+ sig_bits ? (1U << format->red_sBIT)-1 : max,
+ sig_bits ? (1U << format->green_sBIT)-1 : max,
+ sig_bits ? (1U << format->blue_sBIT)-1 : max,
+ sig_bits ? (1U << format->alpha_sBIT)-1 : max);
/* Store the input information for use in the transforms - these will
* modify the information.
@@ -5382,8 +5705,18 @@
this->bit_depth = bit_depth;
this->sample_depth = sample_depth;
this->have_tRNS = 0;
+ this->swap_rgb = 0;
+ this->alpha_first = 0;
+ this->alpha_inverted = 0;
+ this->mono_inverted = 0;
+ this->swap16 = 0;
+ this->littleendian = 0;
+ this->sig_bits = 0;
}
+#if defined PNG_READ_EXPAND_SUPPORTED || defined PNG_READ_GRAY_TO_RGB_SUPPORTED\
+ || defined PNG_READ_EXPAND_SUPPORTED || defined PNG_READ_EXPAND_16_SUPPORTED\
+ || defined PNG_READ_BACKGROUND_SUPPORTED
/* Convert a palette image to an rgb image. This necessarily converts the tRNS
* chunk at the same time, because the tRNS will be in palette form. The way
* palette validation works means that the original palette is never updated,
@@ -5413,10 +5746,14 @@
/* Add an alpha channel; this will import the tRNS information because tRNS is
* not valid in an alpha image. The bit depth will invariably be set to at
- * least 8. Palette images will be converted to alpha (using the above API).
+ * least 8 prior to 1.7.0. Palette images will be converted to alpha (using
+ * the above API). With png_set_background the alpha channel is never expanded
+ * but this routine is used by pngvalid to simplify code; 'for_background'
+ * records this.
*/
static void
-image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
+image_pixel_add_alpha(image_pixel *this, const standard_display *display,
+ int for_background)
{
if (this->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(this);
@@ -5425,11 +5762,21 @@
{
if (this->colour_type == PNG_COLOR_TYPE_GRAY)
{
- if (this->bit_depth < 8)
- this->bit_depth = 8;
+# if PNG_LIBPNG_VER < 10700
+ if (!for_background && this->bit_depth < 8)
+ this->bit_depth = this->sample_depth = 8;
+# endif
if (this->have_tRNS)
{
+ /* After 1.7 the expansion of bit depth only happens if there is a
+ * tRNS chunk to expand at this point.
+ */
+# if PNG_LIBPNG_VER >= 10700
+ if (!for_background && this->bit_depth < 8)
+ this->bit_depth = this->sample_depth = 8;
+# endif
+
this->have_tRNS = 0;
/* Check the input, original, channel value here against the
@@ -5461,9 +5808,11 @@
this->alphaf = 0;
else
this->alphaf = 1;
-
- this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
+ else
+ this->alphaf = 1;
+
+ this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
/* The error in the alpha is zero and the sBIT value comes from the
@@ -5473,18 +5822,19 @@
this->alpha_sBIT = display->alpha_sBIT;
}
}
+#endif /* transforms that need image_pixel_add_alpha */
struct transform_display;
typedef struct image_transform
{
/* The name of this transform: a string. */
- PNG_CONST char *name;
+ const char *name;
/* Each transform can be disabled from the command line: */
int enable;
/* The global list of transforms; read only. */
- struct image_transform *PNG_CONST list;
+ struct image_transform *const list;
/* The global count of the number of times this transform has been set on an
* image.
@@ -5497,7 +5847,7 @@
/* The next transform in the list, each transform must call its own next
* transform after it has processed the pixel successfully.
*/
- PNG_CONST struct image_transform *next;
+ const struct image_transform *next;
/* A single transform for the image, expressed as a series of function
* callbacks and some space for values.
@@ -5505,12 +5855,12 @@
* First a callback to add any required modifications to the png_modifier;
* this gets called just before the modifier is set up for read.
*/
- void (*ini)(PNG_CONST struct image_transform *this,
+ void (*ini)(const struct image_transform *this,
struct transform_display *that);
/* And a callback to set the transform on the current png_read_struct:
*/
- void (*set)(PNG_CONST struct image_transform *this,
+ void (*set)(const struct image_transform *this,
struct transform_display *that, png_structp pp, png_infop pi);
/* Then a transform that takes an input pixel in one PNG format or another
@@ -5519,8 +5869,8 @@
* in the libpng implementation!) The png_structp is solely to allow error
* reporting via png_error and png_warning.
*/
- void (*mod)(PNG_CONST struct image_transform *this, image_pixel *that,
- png_const_structp pp, PNG_CONST struct transform_display *display);
+ void (*mod)(const struct image_transform *this, image_pixel *that,
+ png_const_structp pp, const struct transform_display *display);
/* Add this transform to the list and return true if the transform is
* meaningful for this colour type and bit depth - if false then the
@@ -5528,7 +5878,7 @@
* point running it.
*/
int (*add)(struct image_transform *this,
- PNG_CONST struct image_transform **that, png_byte colour_type,
+ const struct image_transform **that, png_byte colour_type,
png_byte bit_depth);
} image_transform;
@@ -5538,11 +5888,13 @@
/* Parameters */
png_modifier* pm;
- PNG_CONST image_transform* transform_list;
+ const image_transform* transform_list;
+ unsigned int max_gamma_8;
/* Local variables */
png_byte output_colour_type;
png_byte output_bit_depth;
+ png_byte unpacked;
/* Modifications (not necessarily used.) */
gama_modification gama_mod;
@@ -5579,7 +5931,7 @@
/* Three functions to end the list: */
static void
-image_transform_ini_end(PNG_CONST image_transform *this,
+image_transform_ini_end(const image_transform *this,
transform_display *that)
{
UNUSED(this)
@@ -5587,7 +5939,7 @@
}
static void
-image_transform_set_end(PNG_CONST image_transform *this,
+image_transform_set_end(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
UNUSED(this)
@@ -5614,10 +5966,11 @@
}
static void
-image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that,
- png_const_structp pp, PNG_CONST transform_display *display)
+image_transform_mod_end(const image_transform *this, image_pixel *that,
+ png_const_structp pp, const transform_display *display)
{
- PNG_CONST unsigned int scale = (1U<<that->sample_depth)-1;
+ const unsigned int scale = (1U<<that->sample_depth)-1;
+ const int sig_bits = that->sig_bits;
UNUSED(this)
UNUSED(pp)
@@ -5632,6 +5985,13 @@
*/
that->red = sample_scale(that->redf, scale);
+ /* This is a bit bogus; really the above calculation should use the red_sBIT
+ * value, not sample_depth, but because libpng does png_set_shift by just
+ * shifting the bits we get errors if we don't do it the same way.
+ */
+ if (sig_bits && that->red_sBIT < that->sample_depth)
+ that->red >>= that->sample_depth - that->red_sBIT;
+
/* The error value is increased, at the end, according to the lowest sBIT
* value seen. Common sense tells us that the intermediate integer
* representations are no more accurate than +/- 0.5 in the integral values,
@@ -5647,7 +6007,13 @@
if (that->colour_type & PNG_COLOR_MASK_COLOR)
{
that->green = sample_scale(that->greenf, scale);
+ if (sig_bits && that->green_sBIT < that->sample_depth)
+ that->green >>= that->sample_depth - that->green_sBIT;
+
that->blue = sample_scale(that->bluef, scale);
+ if (sig_bits && that->blue_sBIT < that->sample_depth)
+ that->blue >>= that->sample_depth - that->blue_sBIT;
+
that->greene += 1./(2*((1U<<that->green_sBIT)-1));
that->bluee += 1./(2*((1U<<that->blue_sBIT)-1));
}
@@ -5667,9 +6033,12 @@
else
{
that->alpha = scale; /* opaque */
- that->alpha = 1; /* Override this. */
+ that->alphaf = 1; /* Override this. */
that->alphae = 0; /* It's exact ;-) */
}
+
+ if (sig_bits && that->alpha_sBIT < that->sample_depth)
+ that->alpha >>= that->sample_depth - that->alpha_sBIT;
}
/* Static 'end' structure: */
@@ -5692,21 +6061,23 @@
*/
static void
transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id,
- PNG_CONST image_transform *transform_list)
+ const image_transform *transform_list)
{
memset(dp, 0, sizeof *dp);
/* Standard fields */
- standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/,
+ standard_display_init(&dp->this, &pm->this, id, do_read_interlace,
pm->use_update_info);
/* Parameter fields */
dp->pm = pm;
dp->transform_list = transform_list;
+ dp->max_gamma_8 = 16;
/* Local variable fields */
dp->output_colour_type = 255; /* invalid */
dp->output_bit_depth = 255; /* invalid */
+ dp->unpacked = 0; /* not unpacked */
}
static void
@@ -5734,6 +6105,14 @@
dp->output_colour_type = png_get_color_type(pp, pi);
dp->output_bit_depth = png_get_bit_depth(pp, pi);
+ /* If png_set_filler is in action then fake the output color type to include
+ * an alpha channel where appropriate.
+ */
+ if (dp->output_bit_depth >= 8 &&
+ (dp->output_colour_type == PNG_COLOR_TYPE_RGB ||
+ dp->output_colour_type == PNG_COLOR_TYPE_GRAY) && dp->this.filler)
+ dp->output_colour_type |= 4;
+
/* Validate the combination of colour type and bit depth that we are getting
* out of libpng; the semantics of something not in the PNG spec are, at
* best, unclear.
@@ -5768,7 +6147,8 @@
}
/* Use a test pixel to check that the output agrees with what we expect -
- * this avoids running the whole test if the output is unexpected.
+ * this avoids running the whole test if the output is unexpected. This also
+ * checks for internal errors.
*/
{
image_pixel test_pixel;
@@ -5783,7 +6163,7 @@
/* Don't need sBIT here, but it must be set to non-zero to avoid
* arithmetic overflows.
*/
- test_pixel.have_tRNS = dp->this.is_transparent;
+ test_pixel.have_tRNS = dp->this.is_transparent != 0;
test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT =
test_pixel.alpha_sBIT = test_pixel.sample_depth;
@@ -5814,22 +6194,41 @@
}
/* If both bit depth and colour type are correct check the sample depth.
- * I believe these are both internal errors.
*/
- if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE)
- {
- if (test_pixel.sample_depth != 8) /* oops - internal error! */
- png_error(pp, "pngvalid: internal: palette sample depth not 8");
- }
- else if (test_pixel.sample_depth != dp->output_bit_depth)
+ if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE &&
+ test_pixel.sample_depth != 8) /* oops - internal error! */
+ png_error(pp, "pngvalid: internal: palette sample depth not 8");
+ else if (dp->unpacked && test_pixel.bit_depth != 8)
+ png_error(pp, "pngvalid: internal: bad unpacked pixel depth");
+ else if (!dp->unpacked && test_pixel.colour_type != PNG_COLOR_TYPE_PALETTE
+ && test_pixel.bit_depth != test_pixel.sample_depth)
{
char message[128];
size_t pos = safecat(message, sizeof message, 0,
"internal: sample depth ");
+ /* Because unless something has set 'unpacked' or the image is palette
+ * mapped we expect the transform to keep sample depth and bit depth
+ * the same.
+ */
+ pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth);
+ pos = safecat(message, sizeof message, pos, " expected ");
+ pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth);
+
+ png_error(pp, message);
+ }
+ else if (test_pixel.bit_depth != dp->output_bit_depth)
+ {
+ /* This could be a libpng error too; libpng has not produced what we
+ * expect for the output bit depth.
+ */
+ char message[128];
+ size_t pos = safecat(message, sizeof message, 0,
+ "internal: bit depth ");
+
pos = safecatn(message, sizeof message, pos, dp->output_bit_depth);
pos = safecat(message, sizeof message, pos, " expected ");
- pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth);
+ pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth);
png_error(pp, message);
}
@@ -5847,7 +6246,7 @@
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
@@ -5891,20 +6290,20 @@
png_infop pi)
{
/* Constants for the loop below: */
- PNG_CONST png_store* PNG_CONST ps = dp->this.ps;
- PNG_CONST png_byte in_ct = dp->this.colour_type;
- PNG_CONST png_byte in_bd = dp->this.bit_depth;
- PNG_CONST png_uint_32 w = dp->this.w;
- PNG_CONST png_uint_32 h = dp->this.h;
- PNG_CONST png_byte out_ct = dp->output_colour_type;
- PNG_CONST png_byte out_bd = dp->output_bit_depth;
- PNG_CONST png_byte sample_depth = (png_byte)(out_ct ==
+ const png_store* const ps = dp->this.ps;
+ const png_byte in_ct = dp->this.colour_type;
+ const png_byte in_bd = dp->this.bit_depth;
+ const png_uint_32 w = dp->this.w;
+ const png_uint_32 h = dp->this.h;
+ const png_byte out_ct = dp->output_colour_type;
+ const png_byte out_bd = dp->output_bit_depth;
+ const png_byte sample_depth = (png_byte)(out_ct ==
PNG_COLOR_TYPE_PALETTE ? 8 : out_bd);
- PNG_CONST png_byte red_sBIT = dp->this.red_sBIT;
- PNG_CONST png_byte green_sBIT = dp->this.green_sBIT;
- PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT;
- PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT;
- PNG_CONST int have_tRNS = dp->this.is_transparent;
+ const png_byte red_sBIT = dp->this.red_sBIT;
+ const png_byte green_sBIT = dp->this.green_sBIT;
+ const png_byte blue_sBIT = dp->this.blue_sBIT;
+ const png_byte alpha_sBIT = dp->this.alpha_sBIT;
+ const int have_tRNS = dp->this.is_transparent;
double digitization_error;
store_palette out_palette;
@@ -5959,7 +6358,7 @@
for (y=0; y<h; ++y)
{
- png_const_bytep PNG_CONST pRow = store_image_row(ps, pp, 0, y);
+ png_const_bytep const pRow = store_image_row(ps, pp, 0, y);
png_uint_32 x;
/* The original, standard, row pre-transforms. */
@@ -5976,13 +6375,14 @@
unsigned int r, g, b, a;
/* Find out what we think the pixel should be: */
- image_pixel_init(&in_pixel, std, in_ct, in_bd, x, dp->this.palette);
+ image_pixel_init(&in_pixel, std, in_ct, in_bd, x, dp->this.palette,
+ NULL);
in_pixel.red_sBIT = red_sBIT;
in_pixel.green_sBIT = green_sBIT;
in_pixel.blue_sBIT = blue_sBIT;
in_pixel.alpha_sBIT = alpha_sBIT;
- in_pixel.have_tRNS = have_tRNS;
+ in_pixel.have_tRNS = have_tRNS != 0;
/* For error detection, below. */
r = in_pixel.red;
@@ -5990,12 +6390,18 @@
b = in_pixel.blue;
a = in_pixel.alpha;
+ /* This applies the transforms to the input data, including output
+ * format operations which must be used when reading the output
+ * pixel that libpng produces.
+ */
dp->transform_list->mod(dp->transform_list, &in_pixel, pp, dp);
/* Read the output pixel and compare it to what we got, we don't
- * use the error field here, so no need to update sBIT.
+ * use the error field here, so no need to update sBIT. in_pixel
+ * says whether we expect libpng to change the output format.
*/
- image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette);
+ image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette,
+ &in_pixel);
/* We don't expect changes to the index here even if the bit depth is
* changed.
@@ -6058,8 +6464,8 @@
/* A single test run. */
static void
-transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
- PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name)
+transform_test(png_modifier *pmIn, const png_uint_32 idIn,
+ const image_transform* transform_listIn, const char * const name)
{
transform_display d;
context(&pmIn->this, fault);
@@ -6160,8 +6566,11 @@
#define PT ITSTRUCT(end) /* stores the previous transform */
/* To save code: */
-static void
-image_transform_default_ini(PNG_CONST image_transform *this,
+extern void image_transform_default_ini(const image_transform *this,
+ transform_display *that); /* silence GCC warnings */
+
+void /* private, but almost always needed */
+image_transform_default_ini(const image_transform *this,
transform_display *that)
{
this->next->ini(this->next, that);
@@ -6170,7 +6579,7 @@
#ifdef PNG_READ_BACKGROUND_SUPPORTED
static int
image_transform_default_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(colour_type)
UNUSED(bit_depth)
@@ -6185,7 +6594,7 @@
#ifdef PNG_READ_EXPAND_SUPPORTED
/* png_set_palette_to_rgb */
static void
-image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this,
+image_transform_png_set_palette_to_rgb_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_palette_to_rgb(pp);
@@ -6193,9 +6602,9 @@
}
static void
-image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this,
+image_transform_png_set_palette_to_rgb_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(that);
@@ -6205,7 +6614,7 @@
static int
image_transform_png_set_palette_to_rgb_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(bit_depth)
@@ -6223,28 +6632,42 @@
#ifdef PNG_READ_EXPAND_SUPPORTED
/* png_set_tRNS_to_alpha */
static void
-image_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this,
+image_transform_png_set_tRNS_to_alpha_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_tRNS_to_alpha(pp);
+
+ /* If there was a tRNS chunk that would get expanded and add an alpha
+ * channel is_transparent must be updated:
+ */
+ if (that->this.has_tRNS)
+ that->this.is_transparent = 1;
+
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_tRNS_to_alpha_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
+#if PNG_LIBPNG_VER < 10700
/* LIBPNG BUG: this always forces palette images to RGB. */
if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(that);
+#endif
/* This effectively does an 'expand' only if there is some transparency to
* convert to an alpha channel.
*/
if (that->have_tRNS)
- image_pixel_add_alpha(that, &display->this);
+# if PNG_LIBPNG_VER >= 10700
+ if (that->colour_type != PNG_COLOR_TYPE_PALETTE &&
+ (that->colour_type & PNG_COLOR_MASK_ALPHA) == 0)
+# endif
+ image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
+#if PNG_LIBPNG_VER < 10700
/* LIBPNG BUG: otherwise libpng still expands to 8 bits! */
else
{
@@ -6253,13 +6676,14 @@
if (that->sample_depth < 8)
that->sample_depth = 8;
}
+#endif
this->next->mod(this->next, that, pp, display);
}
static int
image_transform_png_set_tRNS_to_alpha_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(bit_depth)
@@ -6268,9 +6692,14 @@
/* We don't know yet whether there will be a tRNS chunk, but we know that
* this transformation should do nothing if there already is an alpha
- * channel.
+ * channel. In addition, after the bug fix in 1.7.0, there is no longer
+ * any action on a palette image.
*/
- return (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
+ return
+# if PNG_LIBPNG_VER >= 10700
+ colour_type != PNG_COLOR_TYPE_PALETTE &&
+# endif
+ (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
}
IT(tRNS_to_alpha);
@@ -6281,17 +6710,18 @@
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
/* png_set_gray_to_rgb */
static void
-image_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this,
+image_transform_png_set_gray_to_rgb_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_gray_to_rgb(pp);
+ /* NOTE: this doesn't result in tRNS expansion. */
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this,
+image_transform_png_set_gray_to_rgb_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
/* NOTE: we can actually pend the tRNS processing at this point because we
* can correctly recognize the original pixel value even though we have
@@ -6299,7 +6729,7 @@
* doesn't do this, so we don't either.
*/
if ((that->colour_type & PNG_COLOR_MASK_COLOR) == 0 && that->have_tRNS)
- image_pixel_add_alpha(that, &display->this);
+ image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
/* Simply expand the bit depth and alter the colour type as required. */
if (that->colour_type == PNG_COLOR_TYPE_GRAY)
@@ -6322,7 +6752,7 @@
static int
image_transform_png_set_gray_to_rgb_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(bit_depth)
@@ -6340,17 +6770,21 @@
#ifdef PNG_READ_EXPAND_SUPPORTED
/* png_set_expand */
static void
-image_transform_png_set_expand_set(PNG_CONST image_transform *this,
+image_transform_png_set_expand_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_expand(pp);
+
+ if (that->this.has_tRNS)
+ that->this.is_transparent = 1;
+
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_expand_mod(PNG_CONST image_transform *this,
+image_transform_png_set_expand_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
/* The general expand case depends on what the colour type is: */
if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
@@ -6359,14 +6793,14 @@
that->sample_depth = that->bit_depth = 8;
if (that->have_tRNS)
- image_pixel_add_alpha(that, &display->this);
+ image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
this->next->mod(this->next, that, pp, display);
}
static int
image_transform_png_set_expand_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(bit_depth)
@@ -6386,31 +6820,53 @@
#ifdef PNG_READ_EXPAND_SUPPORTED
/* png_set_expand_gray_1_2_4_to_8
- * LIBPNG BUG: this just does an 'expand'
+ * Pre 1.7.0 LIBPNG BUG: this just does an 'expand'
*/
static void
image_transform_png_set_expand_gray_1_2_4_to_8_set(
- PNG_CONST image_transform *this, transform_display *that, png_structp pp,
+ const image_transform *this, transform_display *that, png_structp pp,
png_infop pi)
{
png_set_expand_gray_1_2_4_to_8(pp);
+ /* NOTE: don't expect this to expand tRNS */
this->next->set(this->next, that, pp, pi);
}
static void
image_transform_png_set_expand_gray_1_2_4_to_8_mod(
- PNG_CONST image_transform *this, image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const image_transform *this, image_pixel *that, png_const_structp pp,
+ const transform_display *display)
{
+#if PNG_LIBPNG_VER < 10700
image_transform_png_set_expand_mod(this, that, pp, display);
+#else
+ /* Only expand grayscale of bit depth less than 8: */
+ if (that->colour_type == PNG_COLOR_TYPE_GRAY &&
+ that->bit_depth < 8)
+ that->sample_depth = that->bit_depth = 8;
+
+ this->next->mod(this->next, that, pp, display);
+#endif /* 1.7 or later */
}
static int
image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
+#if PNG_LIBPNG_VER < 10700
return image_transform_png_set_expand_add(this, that, colour_type,
bit_depth);
+#else
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ /* This should do nothing unless the color type is gray and the bit depth is
+ * less than 8:
+ */
+ return colour_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8;
+#endif /* 1.7 or later */
}
IT(expand_gray_1_2_4_to_8);
@@ -6421,17 +6877,24 @@
#ifdef PNG_READ_EXPAND_16_SUPPORTED
/* png_set_expand_16 */
static void
-image_transform_png_set_expand_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_expand_16_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_expand_16(pp);
+
+ /* NOTE: prior to 1.7 libpng does SET_EXPAND as well, so tRNS is expanded. */
+# if PNG_LIBPNG_VER < 10700
+ if (that->this.has_tRNS)
+ that->this.is_transparent = 1;
+# endif
+
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_expand_16_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
/* Expect expand_16 to expand everything to 16 bits as a result of also
* causing 'expand' to happen.
@@ -6440,7 +6903,7 @@
image_pixel_convert_PLTE(that);
if (that->have_tRNS)
- image_pixel_add_alpha(that, &display->this);
+ image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
if (that->bit_depth < 16)
that->sample_depth = that->bit_depth = 16;
@@ -6450,7 +6913,7 @@
static int
image_transform_png_set_expand_16_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(colour_type)
@@ -6469,17 +6932,21 @@
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* API added in 1.5.4 */
/* png_set_scale_16 */
static void
-image_transform_png_set_scale_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_scale_16_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_scale_16(pp);
+# if PNG_LIBPNG_VER < 10700
+ /* libpng will limit the gamma table size: */
+ that->max_gamma_8 = PNG_MAX_GAMMA_8;
+# endif
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_scale_16_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
if (that->bit_depth == 16)
{
@@ -6495,7 +6962,7 @@
static int
image_transform_png_set_scale_16_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(colour_type)
@@ -6513,17 +6980,21 @@
#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */
/* png_set_strip_16 */
static void
-image_transform_png_set_strip_16_set(PNG_CONST image_transform *this,
+image_transform_png_set_strip_16_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_strip_16(pp);
+# if PNG_LIBPNG_VER < 10700
+ /* libpng will limit the gamma table size: */
+ that->max_gamma_8 = PNG_MAX_GAMMA_8;
+# endif
this->next->set(this->next, that, pp, pi);
}
static void
-image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this,
+image_transform_png_set_strip_16_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
if (that->bit_depth == 16)
{
@@ -6548,7 +7019,7 @@
* png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!)
*/
{
- PNG_CONST double d = (255-128.5)/65535;
+ const double d = (255-128.5)/65535;
that->rede += d;
that->greene += d;
that->bluee += d;
@@ -6562,7 +7033,7 @@
static int
image_transform_png_set_strip_16_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(colour_type)
@@ -6580,7 +7051,7 @@
#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
/* png_set_strip_alpha */
static void
-image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this,
+image_transform_png_set_strip_alpha_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_strip_alpha(pp);
@@ -6588,9 +7059,9 @@
}
static void
-image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this,
+image_transform_png_set_strip_alpha_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
+ const transform_display *display)
{
if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
that->colour_type = PNG_COLOR_TYPE_GRAY;
@@ -6605,7 +7076,7 @@
static int
image_transform_png_set_strip_alpha_add(image_transform *this,
- PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
UNUSED(bit_depth)
@@ -6626,7 +7097,8 @@
* png_fixed_point green)
* png_get_rgb_to_gray_status
*
- * The 'default' test here uses values known to be used inside libpng:
+ * The 'default' test here uses values known to be used inside libpng prior to
+ * 1.7.0:
*
* red: 6968
* green: 23434
@@ -6663,11 +7135,11 @@
#undef image_transform_ini
#define image_transform_ini image_transform_png_set_rgb_to_gray_ini
static void
-image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
+image_transform_png_set_rgb_to_gray_ini(const image_transform *this,
transform_display *that)
{
png_modifier *pm = that->pm;
- PNG_CONST color_encoding *e = pm->current_encoding;
+ const color_encoding *e = pm->current_encoding;
UNUSED(this)
@@ -6682,7 +7154,7 @@
/* Coefficients come from the encoding, but may need to be normalized to a
* white point Y of 1.0
*/
- PNG_CONST double whiteY = e->red.Y + e->green.Y + e->blue.Y;
+ const double whiteY = e->red.Y + e->green.Y + e->blue.Y;
data.red_coefficient = e->red.Y;
data.green_coefficient = e->green.Y;
@@ -6699,9 +7171,15 @@
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;
@@ -6776,14 +7254,15 @@
* 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
@@ -6795,19 +7274,18 @@
* When DIGITIZE is set because a pre-1.7 version of libpng is being
* tested allow a bigger slack.
*
- * NOTE: this magic number was determined by experiment to be 1.1 (when
- * using fixed point arithmetic). There's no great merit to the value
- * below, however it only affects the limit used for checking for
- * internal calculation errors, not the actual limit imposed by
- * pngvalid on the output errors.
+ * NOTE: this magic number was determined by experiment to be about
+ * 1.263. 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.
*/
that->pm->limit += pow(
-# if DIGITIZE
- 1.1
-# else
- 1.
-# endif
- /255, data.gamma);
+# if DIGITIZE
+ 1.3
+# else
+ 1.0
+# endif
+ /255, data.gamma);
}
}
@@ -6822,10 +7300,10 @@
}
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);
@@ -6862,7 +7340,7 @@
& 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
@@ -6949,26 +7427,32 @@
}
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;
+ const 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;
@@ -6981,56 +7465,73 @@
* 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;
+ const double power = 1/data.gamma;
+ const double abse = .5/(sample_depth == 16 ? 65535 : 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.
+ /* 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
@@ -7040,32 +7541,46 @@
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
@@ -7103,29 +7618,46 @@
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
@@ -7136,10 +7668,10 @@
* lookups in the calculation and each introduces a quantization
* error defined by the table size.
*/
- PNG_CONST png_modifier *pm = display->pm;
+ const 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;
@@ -7160,7 +7692,7 @@
* 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
@@ -7170,7 +7702,7 @@
}
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;
@@ -7226,7 +7758,7 @@
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)
@@ -7257,7 +7789,7 @@
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;
@@ -7285,12 +7817,15 @@
else
{
+ if (that->this.has_tRNS)
+ that->this.is_transparent = 1;
+
bit_depth = that->this.bit_depth;
expand = 1;
}
image_pixel_init(&data, random_bytes, colour_type,
- bit_depth, 0/*x*/, 0/*unused: palette*/);
+ bit_depth, 0/*x*/, 0/*unused: palette*/, NULL/*format*/);
/* Extract the background colour from this image_pixel, but make sure the
* unused fields of 'back' are garbage.
@@ -7317,13 +7852,13 @@
}
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)
@@ -7362,14 +7897,14 @@
/* 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);
}
@@ -7381,11 +7916,604 @@
#define PT ITSTRUCT(background)
#endif /* PNG_READ_BACKGROUND_SUPPORTED */
-/* This may just be 'end' if all the transforms are disabled! */
-static image_transform *PNG_CONST image_transform_first = &PT;
+/* png_set_quantize(png_structp, png_colorp palette, int num_palette,
+ * int maximum_colors, png_const_uint_16p histogram, int full_quantize)
+ *
+ * Very difficult to validate this!
+ */
+/*NOTE: TBD NYI */
+
+/* The data layout transforms are handled by swapping our own channel data,
+ * necessarily these need to happen at the end of the transform list because the
+ * semantic of the channels changes after these are executed. Some of these,
+ * like set_shift and set_packing, can't be done at present because they change
+ * the layout of the data at the sub-sample level so sample() won't get the
+ * right answer.
+ */
+/* png_set_invert_alpha */
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+/* Invert the alpha channel
+ *
+ * png_set_invert_alpha(png_structrp png_ptr)
+ */
+static void
+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);
+ this->next->set(this->next, that, pp, pi);
+}
static void
-transform_enable(PNG_CONST char *name)
+image_transform_png_set_invert_alpha_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->colour_type & 4)
+ that->alpha_inverted = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_invert_alpha_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ /* Only has an effect on pixels with alpha: */
+ return (colour_type & 4) != 0;
+}
+
+IT(invert_alpha);
+#undef PT
+#define PT ITSTRUCT(invert_alpha)
+
+#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */
+
+/* png_set_bgr */
+#ifdef PNG_READ_BGR_SUPPORTED
+/* Swap R,G,B channels to order B,G,R.
+ *
+ * png_set_bgr(png_structrp png_ptr)
+ *
+ * This only has an effect on RGB and RGBA pixels.
+ */
+static void
+image_transform_png_set_bgr_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_bgr(pp);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_bgr_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->colour_type == PNG_COLOR_TYPE_RGB ||
+ that->colour_type == PNG_COLOR_TYPE_RGBA)
+ that->swap_rgb = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_bgr_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ return colour_type == PNG_COLOR_TYPE_RGB ||
+ colour_type == PNG_COLOR_TYPE_RGBA;
+}
+
+IT(bgr);
+#undef PT
+#define PT ITSTRUCT(bgr)
+
+#endif /* PNG_READ_BGR_SUPPORTED */
+
+/* png_set_swap_alpha */
+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
+/* Put the alpha channel first.
+ *
+ * png_set_swap_alpha(png_structrp png_ptr)
+ *
+ * This only has an effect on GA and RGBA pixels.
+ */
+static void
+image_transform_png_set_swap_alpha_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_swap_alpha(pp);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_swap_alpha_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->colour_type == PNG_COLOR_TYPE_GA ||
+ that->colour_type == PNG_COLOR_TYPE_RGBA)
+ that->alpha_first = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_swap_alpha_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ return colour_type == PNG_COLOR_TYPE_GA ||
+ colour_type == PNG_COLOR_TYPE_RGBA;
+}
+
+IT(swap_alpha);
+#undef PT
+#define PT ITSTRUCT(swap_alpha)
+
+#endif /* PNG_READ_SWAP_ALPHA_SUPPORTED */
+
+/* png_set_swap */
+#ifdef PNG_READ_SWAP_SUPPORTED
+/* Byte swap 16-bit components.
+ *
+ * png_set_swap(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_swap_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_swap(pp);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_swap_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->bit_depth == 16)
+ that->swap16 = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_swap_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(colour_type)
+
+ this->next = *that;
+ *that = this;
+
+ return bit_depth == 16;
+}
+
+IT(swap);
+#undef PT
+#define PT ITSTRUCT(swap)
+
+#endif /* PNG_READ_SWAP_SUPPORTED */
+
+#ifdef PNG_READ_FILLER_SUPPORTED
+/* Add a filler byte to 8-bit Gray or 24-bit RGB images.
+ *
+ * png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags));
+ *
+ * Flags:
+ *
+ * PNG_FILLER_BEFORE
+ * PNG_FILLER_AFTER
+ */
+#define data ITDATA(filler)
+static struct
+{
+ png_uint_32 filler;
+ int flags;
+} data;
+
+static void
+image_transform_png_set_filler_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ /* Need a random choice for 'before' and 'after' as well as for the
+ * filler. The 'filler' value has all 32 bits set, but only bit_depth
+ * will be used. At this point we don't know bit_depth.
+ */
+ RANDOMIZE(data.filler);
+ data.flags = random_choice();
+
+ png_set_filler(pp, data.filler, data.flags);
+
+ /* The standard display handling stuff also needs to know that
+ * there is a filler, so set that here.
+ */
+ that->this.filler = 1;
+
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_filler_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->bit_depth >= 8 &&
+ (that->colour_type == PNG_COLOR_TYPE_RGB ||
+ that->colour_type == PNG_COLOR_TYPE_GRAY))
+ {
+ const unsigned int max = (1U << that->bit_depth)-1;
+ that->alpha = data.filler & max;
+ that->alphaf = ((double)that->alpha) / max;
+ that->alphae = 0;
+
+ /* The filler has been stored in the alpha channel, we must record
+ * that this has been done for the checking later on, the color
+ * type is faked to have an alpha channel, but libpng won't report
+ * this; the app has to know the extra channel is there and this
+ * was recording in standard_display::filler above.
+ */
+ that->colour_type |= 4; /* alpha added */
+ that->alpha_first = data.flags == PNG_FILLER_BEFORE;
+ }
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_filler_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ this->next = *that;
+ *that = this;
+
+ return bit_depth >= 8 && (colour_type == PNG_COLOR_TYPE_RGB ||
+ colour_type == PNG_COLOR_TYPE_GRAY);
+}
+
+#undef data
+IT(filler);
+#undef PT
+#define PT ITSTRUCT(filler)
+
+/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */
+/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */
+#define data ITDATA(add_alpha)
+static struct
+{
+ png_uint_32 filler;
+ int flags;
+} data;
+
+static void
+image_transform_png_set_add_alpha_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ /* Need a random choice for 'before' and 'after' as well as for the
+ * filler. The 'filler' value has all 32 bits set, but only bit_depth
+ * will be used. At this point we don't know bit_depth.
+ */
+ RANDOMIZE(data.filler);
+ data.flags = random_choice();
+
+ png_set_add_alpha(pp, data.filler, data.flags);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_add_alpha_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->bit_depth >= 8 &&
+ (that->colour_type == PNG_COLOR_TYPE_RGB ||
+ that->colour_type == PNG_COLOR_TYPE_GRAY))
+ {
+ const unsigned int max = (1U << that->bit_depth)-1;
+ that->alpha = data.filler & max;
+ that->alphaf = ((double)that->alpha) / max;
+ that->alphae = 0;
+
+ that->colour_type |= 4; /* alpha added */
+ that->alpha_first = data.flags == PNG_FILLER_BEFORE;
+ }
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_add_alpha_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ this->next = *that;
+ *that = this;
+
+ return bit_depth >= 8 && (colour_type == PNG_COLOR_TYPE_RGB ||
+ colour_type == PNG_COLOR_TYPE_GRAY);
+}
+
+#undef data
+IT(add_alpha);
+#undef PT
+#define PT ITSTRUCT(add_alpha)
+
+#endif /* PNG_READ_FILLER_SUPPORTED */
+
+/* png_set_packing */
+#ifdef PNG_READ_PACK_SUPPORTED
+/* Use 1 byte per pixel in 1, 2, or 4-bit depth files.
+ *
+ * png_set_packing(png_structrp png_ptr)
+ *
+ * This should only affect grayscale and palette images with less than 8 bits
+ * per pixel.
+ */
+static void
+image_transform_png_set_packing_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_packing(pp);
+ that->unpacked = 1;
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_packing_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ /* The general expand case depends on what the colour type is,
+ * low bit-depth pixel values are unpacked into bytes without
+ * scaling, so sample_depth is not changed.
+ */
+ if (that->bit_depth < 8) /* grayscale or palette */
+ that->bit_depth = 8;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_packing_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(colour_type)
+
+ this->next = *that;
+ *that = this;
+
+ /* Nothing should happen unless the bit depth is less than 8: */
+ return bit_depth < 8;
+}
+
+IT(packing);
+#undef PT
+#define PT ITSTRUCT(packing)
+
+#endif /* PNG_READ_PACK_SUPPORTED */
+
+/* png_set_packswap */
+#ifdef PNG_READ_PACKSWAP_SUPPORTED
+/* Swap pixels packed into bytes; reverses the order on screen so that
+ * the high order bits correspond to the rightmost pixels.
+ *
+ * png_set_packswap(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_packswap_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_packswap(pp);
+ that->this.littleendian = 1;
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_packswap_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->bit_depth < 8)
+ that->littleendian = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_packswap_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(colour_type)
+
+ this->next = *that;
+ *that = this;
+
+ return bit_depth < 8;
+}
+
+IT(packswap);
+#undef PT
+#define PT ITSTRUCT(packswap)
+
+#endif /* PNG_READ_PACKSWAP_SUPPORTED */
+
+
+/* png_set_invert_mono */
+#ifdef PNG_READ_INVERT_MONO_SUPPORTED
+/* Invert the gray channel
+ *
+ * png_set_invert_mono(png_structrp png_ptr)
+ */
+static void
+image_transform_png_set_invert_mono_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_invert_mono(pp);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_invert_mono_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ if (that->colour_type & 4)
+ that->mono_inverted = 1;
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_invert_mono_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ /* Only has an effect on pixels with no colour: */
+ return (colour_type & 2) == 0;
+}
+
+IT(invert_mono);
+#undef PT
+#define PT ITSTRUCT(invert_mono)
+
+#endif /* PNG_READ_INVERT_MONO_SUPPORTED */
+
+#ifdef PNG_READ_SHIFT_SUPPORTED
+/* png_set_shift(png_structp, png_const_color_8p true_bits)
+ *
+ * The output pixels will be shifted by the given true_bits
+ * values.
+ */
+#define data ITDATA(shift)
+static png_color_8 data;
+
+static void
+image_transform_png_set_shift_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ /* Get a random set of shifts. The shifts need to do something
+ * to test the transform, so they are limited to the bit depth
+ * of the input image. Notice that in the following the 'gray'
+ * field is randomized independently. This acts as a check that
+ * libpng does use the correct field.
+ */
+ const unsigned int depth = that->this.bit_depth;
+
+ data.red = (png_byte)/*SAFE*/(random_mod(depth)+1);
+ data.green = (png_byte)/*SAFE*/(random_mod(depth)+1);
+ data.blue = (png_byte)/*SAFE*/(random_mod(depth)+1);
+ data.gray = (png_byte)/*SAFE*/(random_mod(depth)+1);
+ data.alpha = (png_byte)/*SAFE*/(random_mod(depth)+1);
+
+ png_set_shift(pp, &data);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_shift_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ /* Copy the correct values into the sBIT fields, libpng does not do
+ * anything to palette data:
+ */
+ if (that->colour_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ that->sig_bits = 1;
+
+ /* The sBIT fields are reset to the values previously sent to
+ * png_set_shift according to the colour type.
+ * does.
+ */
+ if (that->colour_type & 2) /* RGB channels */
+ {
+ that->red_sBIT = data.red;
+ that->green_sBIT = data.green;
+ that->blue_sBIT = data.blue;
+ }
+
+ else /* One grey channel */
+ that->red_sBIT = that->green_sBIT = that->blue_sBIT = data.gray;
+
+ that->alpha_sBIT = data.alpha;
+ }
+
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_shift_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ UNUSED(bit_depth)
+
+ this->next = *that;
+ *that = this;
+
+ return colour_type != PNG_COLOR_TYPE_PALETTE;
+}
+
+IT(shift);
+#undef PT
+#define PT ITSTRUCT(shift)
+
+#endif /* PNG_READ_SHIFT_SUPPORTED */
+
+#ifdef THIS_IS_THE_PROFORMA
+static void
+image_transform_png_set_@_set(const image_transform *this,
+ transform_display *that, png_structp pp, png_infop pi)
+{
+ png_set_@(pp);
+ this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_@_mod(const image_transform *this,
+ image_pixel *that, png_const_structp pp,
+ const transform_display *display)
+{
+ this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_@_add(image_transform *this,
+ const image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+ this->next = *that;
+ *that = this;
+
+ return 1;
+}
+
+IT(@);
+#endif
+
+
+/* This may just be 'end' if all the transforms are disabled! */
+static image_transform *const image_transform_first = &PT;
+
+static void
+transform_enable(const char *name)
{
/* Everything starts out enabled, so if we see an 'enable' disabled
* everything else the first time round.
@@ -7418,7 +8546,7 @@
}
static void
-transform_disable(PNG_CONST char *name)
+transform_disable(const char *name)
{
image_transform *list = image_transform_first;
@@ -7481,7 +8609,7 @@
}
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)
{
@@ -7558,83 +8686,6 @@
}
}
-#ifdef THIS_IS_THE_PROFORMA
-static void
-image_transform_png_set_@_set(PNG_CONST image_transform *this,
- transform_display *that, png_structp pp, png_infop pi)
-{
- png_set_@(pp);
- this->next->set(this->next, that, pp, pi);
-}
-
-static void
-image_transform_png_set_@_mod(PNG_CONST image_transform *this,
- image_pixel *that, png_const_structp pp,
- PNG_CONST transform_display *display)
-{
- this->next->mod(this->next, that, pp, display);
-}
-
-static int
-image_transform_png_set_@_add(image_transform *this,
- PNG_CONST image_transform **that, char *name, size_t sizeof_name,
- size_t *pos, png_byte colour_type, png_byte bit_depth)
-{
- this->next = *that;
- *that = this;
-
- *pos = safecat(name, sizeof_name, *pos, " +@");
-
- return 1;
-}
-
-IT(@);
-#endif
-
-/* png_set_quantize(png_structp, png_colorp palette, int num_palette,
- * int maximum_colors, png_const_uint_16p histogram, int full_quantize)
- *
- * Very difficult to validate this!
- */
-/*NOTE: TBD NYI */
-
-/* The data layout transforms are handled by swapping our own channel data,
- * necessarily these need to happen at the end of the transform list because the
- * semantic of the channels changes after these are executed. Some of these,
- * like set_shift and set_packing, can't be done at present because they change
- * the layout of the data at the sub-sample level so sample() won't get the
- * right answer.
- */
-/* png_set_invert_alpha */
-/*NOTE: TBD NYI */
-
-/* png_set_bgr */
-/*NOTE: TBD NYI */
-
-/* png_set_swap_alpha */
-/*NOTE: TBD NYI */
-
-/* png_set_swap */
-/*NOTE: TBD NYI */
-
-/* png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags)); */
-/*NOTE: TBD NYI */
-
-/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */
-/*NOTE: TBD NYI */
-
-/* png_set_packing */
-/*NOTE: TBD NYI */
-
-/* png_set_packswap */
-/*NOTE: TBD NYI */
-
-/* png_set_invert_mono */
-/*NOTE: TBD NYI */
-
-/* png_set_shift(png_structp, png_const_color_8p true_bits) */
-/*NOTE: TBD NYI */
-
static void
perform_transform_test(png_modifier *pm)
{
@@ -7642,7 +8693,8 @@
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;
@@ -7653,7 +8705,7 @@
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.
@@ -7714,11 +8766,11 @@
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 */
@@ -7750,7 +8802,7 @@
/* 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
@@ -7782,9 +8834,9 @@
* 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
@@ -7830,9 +8882,9 @@
# 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
@@ -7906,7 +8958,7 @@
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;
@@ -7945,13 +8997,15 @@
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 */
@@ -7975,7 +9029,7 @@
vi->background_blue = b;
}
}
- else
+ else /* Do not expect any background processing */
vi->do_background = 0;
if (vi->do_background == 0)
@@ -8065,15 +9119,15 @@
/* 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;
@@ -8638,14 +9692,14 @@
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
@@ -8686,11 +9740,12 @@
* 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;
@@ -8706,6 +9761,7 @@
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
@@ -8736,20 +9792,20 @@
double alpha = 1; /* serves as a flag value */
/* Record the palette index for index images. */
- PNG_CONST unsigned int in_index =
- in_ct == 3 ? sample(std, 3, in_bd, x, 0) : 256;
- PNG_CONST unsigned int out_index =
- out_ct == 3 ? sample(std, 3, out_bd, x, 0) : 256;
+ const unsigned int in_index =
+ in_ct == 3 ? sample(std, 3, in_bd, x, 0, 0, 0) : 256;
+ const unsigned int out_index =
+ out_ct == 3 ? sample(std, 3, out_bd, x, 0, 0, 0) : 256;
/* Handle input alpha - png_set_background will cause the output
* alpha to disappear so there is nothing to check.
*/
- if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || (in_ct == 3 &&
- in_is_transparent))
+ if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 ||
+ (in_ct == 3 && in_is_transparent))
{
- PNG_CONST unsigned int input_alpha = in_ct == 3 ?
+ const unsigned int input_alpha = in_ct == 3 ?
dp->this.palette[in_index].alpha :
- sample(std, in_ct, in_bd, x, samples_per_pixel);
+ sample(std, in_ct, in_bd, x, samples_per_pixel, 0, 0);
unsigned int output_alpha = 65536 /* as a flag value */;
@@ -8761,7 +9817,7 @@
else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0)
output_alpha = sample(pRow, out_ct, out_bd, x,
- samples_per_pixel);
+ samples_per_pixel, 0, 0);
if (output_alpha != 65536)
alpha = gamma_component_validate("alpha", &vi, input_alpha,
@@ -8777,33 +9833,62 @@
}
}
+ else if (process_tRNS)
+ {
+ /* alpha needs to be set appropriately for this pixel, it is
+ * currently 1 and needs to be 0 for an input pixel which matches
+ * the values in tRNS.
+ */
+ switch (in_ct)
+ {
+ case 0: /* gray */
+ if (sample(std, in_ct, in_bd, x, 0, 0, 0) ==
+ dp->this.transparent.red)
+ alpha = 0;
+ break;
+
+ case 2: /* RGB */
+ if (sample(std, in_ct, in_bd, x, 0, 0, 0) ==
+ dp->this.transparent.red &&
+ sample(std, in_ct, in_bd, x, 1, 0, 0) ==
+ dp->this.transparent.green &&
+ sample(std, in_ct, in_bd, x, 2, 0, 0) ==
+ dp->this.transparent.blue)
+ alpha = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
/* Handle grayscale or RGB components. */
if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* grayscale */
(void)gamma_component_validate("gray", &vi,
- sample(std, in_ct, in_bd, x, 0),
- sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/,
- vi.background_red);
+ sample(std, in_ct, in_bd, x, 0, 0, 0),
+ sample(pRow, out_ct, out_bd, x, 0, 0, 0),
+ alpha/*component*/, vi.background_red);
else /* RGB or palette */
{
(void)gamma_component_validate("red", &vi,
in_ct == 3 ? in_palette[in_index].red :
- sample(std, in_ct, in_bd, x, 0),
+ sample(std, in_ct, in_bd, x, 0, 0, 0),
out_ct == 3 ? out_palette[out_index].red :
- sample(pRow, out_ct, out_bd, x, 0),
+ sample(pRow, out_ct, out_bd, x, 0, 0, 0),
alpha/*component*/, vi.background_red);
(void)gamma_component_validate("green", &vi,
in_ct == 3 ? in_palette[in_index].green :
- sample(std, in_ct, in_bd, x, 1),
+ sample(std, in_ct, in_bd, x, 1, 0, 0),
out_ct == 3 ? out_palette[out_index].green :
- sample(pRow, out_ct, out_bd, x, 1),
+ sample(pRow, out_ct, out_bd, x, 1, 0, 0),
alpha/*component*/, vi.background_green);
(void)gamma_component_validate("blue", &vi,
in_ct == 3 ? in_palette[in_index].blue :
- sample(std, in_ct, in_bd, x, 2),
+ sample(std, in_ct, in_bd, x, 2, 0, 0),
out_ct == 3 ? out_palette[out_index].blue :
- sample(pRow, out_ct, out_bd, x, 2),
+ sample(pRow, out_ct, out_bd, x, 2, 0, 0),
alpha/*component*/, vi.background_blue);
}
}
@@ -8843,15 +9928,15 @@
* 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);
@@ -8886,7 +9971,7 @@
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);
@@ -9025,9 +10110,13 @@
/* 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)
@@ -9050,11 +10139,11 @@
}
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];
@@ -9087,7 +10176,8 @@
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;
@@ -9117,7 +10207,8 @@
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)))
@@ -9152,7 +10243,11 @@
# 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.
@@ -9205,12 +10300,12 @@
#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;
@@ -9308,8 +10403,17 @@
}
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.
*/
@@ -9358,9 +10462,18 @@
/* Skip the non-alpha cases - there is no setting of a transparency colour at
* present.
+ *
+ * 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, 1/*gamma*/))
- if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0)
+ 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;
@@ -9579,7 +10692,7 @@
* 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 },
@@ -9930,7 +11043,7 @@
* 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,
@@ -9952,6 +11065,11 @@
/*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
@@ -10023,11 +11141,11 @@
/* 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.)
@@ -10043,6 +11161,10 @@
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);
@@ -10089,14 +11211,30 @@
/* Store the test gammas */
pm.gammas = gammas;
- pm.ngammas = (sizeof gammas) / (sizeof gammas[0]);
+ pm.ngammas = ARRAY_SIZE(gammas);
pm.ngamma_tests = 0; /* default to off */
+ /* Low bit depth gray images don't do well in the gamma tests, until
+ * this is fixed turn them off for some gamma cases:
+ */
+# ifdef PNG_WRITE_tRNS_SUPPORTED
+ pm.test_tRNS = 1;
+# endif
+ pm.test_lbg = PNG_LIBPNG_VER >= 10600;
+ pm.test_lbg_gamma_threshold = 1;
+ pm.test_lbg_gamma_transform = PNG_LIBPNG_VER >= 10600;
+ pm.test_lbg_gamma_sbit = 1;
+ pm.test_lbg_gamma_composition = PNG_LIBPNG_VER >= 10700;
+
/* And the test encodings */
pm.encodings = test_encodings;
- pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]);
+ pm.nencodings = ARRAY_SIZE(test_encodings);
- pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
+# if PNG_LIBPNG_VER < 10700
+ pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
+# else
+ pm.sbitlow = 1U;
+# endif
/* The following allows results to pass if they correspond to anything in the
* transformed range [input-.5,input+.5]; this is is required because of the
@@ -10122,7 +11260,11 @@
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
@@ -10152,7 +11294,8 @@
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 = 0;
else if (strcmp(*argv, "--speed") == 0)
@@ -10204,7 +11347,7 @@
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;
}
@@ -10253,6 +11396,24 @@
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;
@@ -10267,12 +11428,12 @@
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)
@@ -10350,12 +11511,18 @@
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;
@@ -10443,7 +11610,7 @@
Try
{
/* Make useful base images */
- make_transform_images(&pm.this);
+ make_transform_images(&pm);
/* Perform the standard and gamma tests. */
if (pm.test_standard)