summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.html7
-rw-r--r--blacken.c57
-rw-r--r--png.c415
-rw-r--r--png.h63
-rw-r--r--pngconf.h80
-rw-r--r--pngcrush.c16
-rw-r--r--pngcrush.h7
-rw-r--r--pngget.c99
-rw-r--r--pnglibconf.h4
-rw-r--r--pngpriv.h155
-rw-r--r--pngrtran.c404
-rw-r--r--pngrutil.c148
-rw-r--r--pngset.c70
-rw-r--r--pngstruct.h11
-rw-r--r--pngtest.c2
-rw-r--r--pngvalid.c1546
-rw-r--r--pngwutil.c14
17 files changed, 2401 insertions, 697 deletions
diff --git a/ChangeLog.html b/ChangeLog.html
index 0a4038551..246e3ea22 100644
--- a/ChangeLog.html
+++ b/ChangeLog.html
@@ -3,6 +3,12 @@
Change log:
+Version 1.7.17 (built with libpng-1.5.5beta08 and zlib-1.2.5)
+ Changed "#if !defined(PNG_NO_STDIO)" to "#ifdef PNG_STDIO_SUPPORTED"
+ as recommended in the libpng documentation.
+ Added PNG_UINT_32_NAME macro and used it to simplify chunk_type integer
+ definitions.
+
Version 1.7.16 (built with libpng-1.5.4 and zlib-1.2.5)
Only report best method==0 if pngcrush cannot match the input filesize.
Otherwise, if there is no improvement, report the first matching method.
@@ -18,6 +24,7 @@ Version 1.7.14 (built with libpng-1.5.1beta08 and zlib-1.2.5)
png_get_iCCP() and png_set_iCCP() calls to be able to build
with bundled libpng-1.5.x. Pngcrush cannot be built yet with
a system libpng-1.5.x.
+ Dropped most of pngcrush.h, that eliminates various parts of libpng.
Version 1.7.13 (built with libpng-1.4.5 and zlib-1.2.5)
diff --git a/blacken.c b/blacken.c
new file mode 100644
index 000000000..5f8396099
--- /dev/null
+++ b/blacken.c
@@ -0,0 +1,57 @@
+void PNGCBAPI
+pngcrush_blacken_transparent(png_structp png_ptr, png_row_infop row_info,
+ png_bytep data);
+void PNGCBAPI
+pngcrush_blacken_transparent(png_structp png_ptr, png_row_infop row_info,
+ png_bytep data)
+{
+ /* Changes underlying color of GA or RGBA fully transparent pixels to black */
+
+ png_bytep dp = data;
+ if (png_ptr == NULL)
+ return;
+
+ if (row_info->color_type < 4)
+ return;
+
+ /* Contents of row_info:
+ * png_uint_32 width width of row
+ * png_uint_32 rowbytes number of bytes in row
+ * png_byte color_type color type of pixels
+ * png_byte bit_depth bit depth of samples
+ * png_byte channels number of channels (1-4)
+ * png_byte pixel_depth bits per pixel (depth*channels)
+ */
+
+ {
+ png_uint_32 n, nstop;
+ int channel;
+ int color_channels = row_info->channels;
+ if (row_info->color_type > 3)color_channels--;
+
+ for (n = 0, nstop=row_info->width; n<nstop; n++)
+ {
+ for (channel = 0; channel < color_channels; channel++)
+ {
+ if (row_info->bit_depth == 8)
+ if (*dp++ == 0)
+ zero_samples++;
+
+ if (row_info->bit_depth == 16)
+ {
+ if ((*dp | *(dp+1)) == 0)
+ zero_samples++;
+
+ dp+=2;
+ }
+ }
+ if (row_info->color_type > 3)
+ {
+ dp++;
+ if (row_info->bit_depth == 16)
+ dp++;
+ }
+ }
+ }
+}
+#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
diff --git a/png.c b/png.c
index eed313619..e871ed910 100644
--- a/png.c
+++ b/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4;
+typedef png_libpng_version_1_5_5beta08 Your_png_h_is_not_version_1_5_5beta08;
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
@@ -43,7 +43,7 @@ png_set_sig_bytes(png_structp png_ptr, int num_bytes)
* can simply check the remaining bytes for extra assurance. Returns
* an integer less than, equal to, or greater than zero if sig is found,
* respectively, to be less than, to match, or be greater than the correct
- * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ * PNG signature (this is the same behavior as strcmp, memcmp, etc).
*/
int PNGAPI
png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
@@ -107,7 +107,8 @@ png_zfree(voidpf png_ptr, voidpf ptr)
void /* PRIVATE */
png_reset_crc(png_structp png_ptr)
{
- png_ptr->crc = crc32(0, Z_NULL, 0);
+ /* The cast is safe because the crc is a 32 bit value. */
+ png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0);
}
/* Calculate the CRC over a section of data. We can only pass as
@@ -133,8 +134,35 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
need_crc = 0;
}
- if (need_crc)
- png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+ /* 'uLong' is defined as unsigned long, this means that on some systems it is
+ * a 64 bit value. crc32, however, returns 32 bits so the following cast is
+ * safe. 'uInt' may be no more than 16 bits, so it is necessary to perform a
+ * loop here.
+ */
+ if (need_crc && length > 0)
+ {
+ uLong crc = png_ptr->crc; /* Should never issue a warning */
+
+ do
+ {
+ uInt safeLength = (uInt)length;
+ if (safeLength == 0)
+ safeLength = (uInt)-1; /* evil, but safe */
+
+ crc = crc32(crc, ptr, safeLength);
+
+ /* The following should never issue compiler warnings, if they do the
+ * target system has characteristics that will probably violate other
+ * assumptions within the libpng code.
+ */
+ ptr += safeLength;
+ length -= safeLength;
+ }
+ while (length > 0);
+
+ /* And the following is always safe because the crc is only 32 bits. */
+ png_ptr->crc = (png_uint_32)crc;
+ }
}
/* Check a user supplied version number, called from both read and write
@@ -542,8 +570,8 @@ png_get_io_ptr(png_structp png_ptr)
/* Initialize the default input/output functions for the PNG file. If you
* use your own read or write routines, you can call either png_set_read_fn()
* or png_set_write_fn() instead of png_init_io(). If you have defined
- * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
- * necessarily available.
+ * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
+ * function of your own because "FILE *" isn't necessarily available.
*/
void PNGAPI
png_init_io(png_structp png_ptr, png_FILE_p fp)
@@ -617,13 +645,13 @@ png_get_copyright(png_const_structp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.5.4 - July 7, 2011" PNG_STRING_NEWLINE \
+ "libpng version 1.5.5beta08 - September 10, 2011" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
- return "libpng version 1.5.4 - July 7, 2011\
+ return "libpng version 1.5.5beta08 - September 10, 2011\
Copyright (c) 1998-2011 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -713,18 +741,9 @@ png_access_version_number(void)
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
-# ifdef PNG_SIZE_T
-/* Added at libpng version 1.2.6 */
- PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
-png_size_t PNGAPI
-png_convert_size(size_t size)
-{
- if (size > (png_size_t)-1)
- PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
-
- return ((png_size_t)size);
-}
-# endif /* PNG_SIZE_T */
+/* png_convert_size: a PNGAPI but no longer in png.h, so deleted
+ * at libpng 1.5.5!
+ */
/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
# ifdef PNG_CHECK_cHRM_SUPPORTED
@@ -798,6 +817,326 @@ png_check_cHRM_fixed(png_structp png_ptr,
}
# endif /* PNG_CHECK_cHRM_SUPPORTED */
+#ifdef PNG_cHRM_SUPPORTED
+/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
+ * cHRM, as opposed to using chromaticities. These internal APIs return
+ * non-zero on a parameter error. The X, Y and Z values are required to be
+ * positive and less than 1.0.
+ */
+int png_xy_from_XYZ(png_xy *xy, png_XYZ XYZ)
+{
+ png_int_32 d, dwhite, whiteX, whiteY;
+
+ d = XYZ.redX + XYZ.redY + XYZ.redZ;
+ if (!png_muldiv(&xy->redx, XYZ.redX, PNG_FP_1, d)) return 1;
+ if (!png_muldiv(&xy->redy, XYZ.redY, PNG_FP_1, d)) return 1;
+ dwhite = d;
+ whiteX = XYZ.redX;
+ whiteY = XYZ.redY;
+
+ d = XYZ.greenX + XYZ.greenY + XYZ.greenZ;
+ if (!png_muldiv(&xy->greenx, XYZ.greenX, PNG_FP_1, d)) return 1;
+ if (!png_muldiv(&xy->greeny, XYZ.greenY, PNG_FP_1, d)) return 1;
+ dwhite += d;
+ whiteX += XYZ.greenX;
+ whiteY += XYZ.greenY;
+
+ d = XYZ.blueX + XYZ.blueY + XYZ.blueZ;
+ if (!png_muldiv(&xy->bluex, XYZ.blueX, PNG_FP_1, d)) return 1;
+ if (!png_muldiv(&xy->bluey, XYZ.blueY, PNG_FP_1, d)) return 1;
+ dwhite += d;
+ whiteX += XYZ.blueX;
+ whiteY += XYZ.blueY;
+
+ /* The reference white is simply the same of the end-point (X,Y,Z) vectors,
+ * thus:
+ */
+ if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1;
+ if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1;
+
+ return 0;
+}
+
+int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
+{
+ png_fixed_point red_inverse, green_inverse, blue_scale;
+ png_fixed_point left, right, denominator;
+
+ /* Check xy and, implicitly, z. Note that wide gamut color spaces typically
+ * have end points with 0 tristimulus values (these are impossible end
+ * points, but they are used to cover the possible colors.)
+ */
+ if (xy.redx < 0 || xy.redx > PNG_FP_1) return 1;
+ if (xy.redy < 0 || xy.redy > PNG_FP_1-xy.redx) return 1;
+ if (xy.greenx < 0 || xy.greenx > PNG_FP_1) return 1;
+ if (xy.greeny < 0 || xy.greeny > PNG_FP_1-xy.greenx) return 1;
+ if (xy.bluex < 0 || xy.bluex > PNG_FP_1) return 1;
+ if (xy.bluey < 0 || xy.bluey > PNG_FP_1-xy.bluex) return 1;
+ if (xy.whitex < 0 || xy.whitex > PNG_FP_1) return 1;
+ if (xy.whitey < 0 || xy.whitey > PNG_FP_1-xy.whitex) return 1;
+
+ /* The reverse calculation is more difficult because the original tristimulus
+ * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
+ * derived values were recorded in the cHRM chunk;
+ * (red,green,blue,white)x(x,y). This loses one degree of freedom and
+ * therefore an arbitrary ninth value has to be introduced to undo the
+ * original transformations.
+ *
+ * Think of the original end-points as points in (X,Y,Z) space. The
+ * chromaticity values (c) have the property:
+ *
+ * C
+ * c = ---------
+ * X + Y + Z
+ *
+ * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the
+ * three chromaticity values (x,y,z) for each end-point obey the
+ * relationship:
+ *
+ * x + y + z = 1
+ *
+ * This describes the plane in (X,Y,Z) space that intersects each axis at the
+ * value 1.0; call this the chromaticity plane. Thus the chromaticity
+ * calculation has scaled each end-point so that it is on the x+y+z=1 plane
+ * and chromaticity is the intersection of the vector from the origin to the
+ * (X,Y,Z) value with the chromaticity plane.
+ *
+ * To fully invert the chromaticity calculation we would need the three
+ * end-point scale factors, (red-scale, green-scale, blue-scale), but these
+ * were not recorded. Instead we calculated the reference white (X,Y,Z) and
+ * recorded the chromaticity of this. The reference white (X,Y,Z) would have
+ * given all three of the scale factors since:
+ *
+ * color-C = color-c * color-scale
+ * white-C = red-C + green-C + blue-C
+ * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
+ *
+ * But cHRM records only white-x and white-y, so we have lost the white scale
+ * factor:
+ *
+ * white-C = white-c*white-scale
+ *
+ * To handle this the inverse transformation makes an arbitrary assumption
+ * about white-scale:
+ *
+ * Assume: white-Y = 1.0
+ * Hence: white-scale = 1/white-y
+ * Or: red-Y + green-Y + blue-Y = 1.0
+ *
+ * Notice the last statement of the assumption gives an equation in three of
+ * the nine values we want to calculate. 8 more equations come from the
+ * above routine as summarised at the top above (the chromaticity
+ * calculation):
+ *
+ * Given: color-x = color-X / (color-X + color-Y + color-Z)
+ * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0
+ *
+ * This is 9 simultaneous equations in the 9 variables "color-C" and can be
+ * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix
+ * determinants, however this is not as bad as it seems because only 28 of
+ * the total of 90 terms in the various matrices are non-zero. Nevertheless
+ * Cramer's rule is notoriously numerically unstable because the determinant
+ * calculation involves the difference of large, but similar, numbers. It is
+ * difficult to be sure that the calculation is stable for real world values
+ * and it is certain that it becomes unstable where the end points are close
+ * together.
+ *
+ * So this code uses the perhaps slighly less optimal but more understandable
+ * and totally obvious approach of calculating color-scale.
+ *
+ * This algorithm depends on the precision in white-scale and that is
+ * (1/white-y), so we can immediately see that as white-y approaches 0 the
+ * accuracy inherent in the cHRM chunk drops off substantially.
+ *
+ * libpng arithmetic: a simple invertion of the above equations
+ * ------------------------------------------------------------
+ *
+ * white_scale = 1/white-y
+ * white-X = white-x * white-scale
+ * white-Y = 1.0
+ * white-Z = (1 - white-x - white-y) * white_scale
+ *
+ * white-C = red-C + green-C + blue-C
+ * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
+ *
+ * This gives us three equations in (red-scale,green-scale,blue-scale) where
+ * all the coefficients are now known:
+ *
+ * red-x*red-scale + green-x*green-scale + blue-x*blue-scale
+ * = white-x/white-y
+ * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1
+ * red-z*red-scale + green-z*green-scale + blue-z*blue-scale
+ * = (1 - white-x - white-y)/white-y
+ *
+ * In the last equation color-z is (1 - color-x - color-y) so we can add all
+ * three equations together to get an alternative third:
+ *
+ * red-scale + green-scale + blue-scale = 1/white-y = white-scale
+ *
+ * So now we have a Cramer's rule solution where the determinants are just
+ * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve
+ * multiplication of three coefficients so we can't guarantee to avoid
+ * overflow in the libpng fixed point representation. Using Cramer's rule in
+ * floating point is probably a good choice here, but it's not an option for
+ * fixed point. Instead proceed to simplify the first two equations by
+ * eliminating what is likely to be the largest value, blue-scale:
+ *
+ * blue-scale = white-scale - red-scale - green-scale
+ *
+ * Hence:
+ *
+ * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale =
+ * (white-x - blue-x)*white-scale
+ *
+ * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale =
+ * 1 - blue-y*white-scale
+ *
+ * And now we can trivially solve for (red-scale,green-scale):
+ *
+ * green-scale =
+ * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale
+ * -----------------------------------------------------------
+ * green-x - blue-x
+ *
+ * red-scale =
+ * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale
+ * ---------------------------------------------------------
+ * red-y - blue-y
+ *
+ * Hence:
+ *
+ * red-scale =
+ * ( (green-x - blue-x) * (white-y - blue-y) -
+ * (green-y - blue-y) * (white-x - blue-x) ) / white-y
+ * -------------------------------------------------------------------------
+ * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
+ *
+ * green-scale =
+ * ( (red-y - blue-y) * (white-x - blue-x) -
+ * (red-x - blue-x) * (white-y - blue-y) ) / white-y
+ * -------------------------------------------------------------------------
+ * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
+ *
+ * Accuracy:
+ * The input values have 5 decimal digits of accuracy. The values are all in
+ * the range 0 < value < 1, so simple products are in the same range but may
+ * need up to 10 decimal digits to preserve the original precision and avoid
+ * underflow. Because we are using a 32-bit signed representation we cannot
+ * match this; the best is a little over 9 decimal digits, less than 10.
+ *
+ * The approach used here is to preserve the maximum precision within the
+ * signed representation. Because the red-scale calculation above uses the
+ * difference between two products of values that must be in the range -1..+1
+ * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The
+ * factor is irrelevant in the calculation because it is applied to both
+ * numerator and denominator.
+ *
+ * Note that the values of the differences of the products of the
+ * chromaticities in the above equations tend to be small, for example for
+ * the sRGB chromaticities they are:
+ *
+ * red numerator: -0.04751
+ * green numerator: -0.08788
+ * denominator: -0.2241 (without white-y multiplication)
+ *
+ * The resultant Y coefficients from the chromaticities of some widely used
+ * color space definitions are (to 15 decimal places):
+ *
+ * sRGB
+ * 0.212639005871510 0.715168678767756 0.072192315360734
+ * Kodak ProPhoto
+ * 0.288071128229293 0.711843217810102 0.000085653960605
+ * Adobe RGB
+ * 0.297344975250536 0.627363566255466 0.075291458493998
+ * Adobe Wide Gamut RGB
+ * 0.258728243040113 0.724682314948566 0.016589442011321
+ */
+ /* By the argument, above overflow should be impossible here. The return
+ * value of 2 indicates an internal error to the caller.
+ */
+ if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.redy - xy.bluey, 7)) return 2;
+ if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.redx - xy.bluex, 7)) return 2;
+ denominator = left - right;
+
+ /* Now find the red numerator. */
+ if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2;
+ if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.whitex-xy.bluex, 7)) return 2;
+
+ /* Overflow is possible here and it indicates an extreme set of PNG cHRM
+ * chunk values. This calculation actually returns the reciprocal of the
+ * scale value because this allows us to delay the multiplication of white-y
+ * into the denominator, which tends to produce a small number.
+ */
+ if (!png_muldiv(&red_inverse, xy.whitey, denominator, left-right) ||
+ red_inverse <= xy.whitey /* r+g+b scales = white scale */)
+ return 1;
+
+ /* Similarly for green_inverse: */
+ if (!png_muldiv(&left, xy.redy-xy.bluey, xy.whitex-xy.bluex, 7)) return 2;
+ if (!png_muldiv(&right, xy.redx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2;
+ if (!png_muldiv(&green_inverse, xy.whitey, denominator, left-right) ||
+ green_inverse <= xy.whitey)
+ return 1;
+
+ /* And the blue scale, the checks above guarantee this can't overflow but it
+ * can still produce 0 for extreme cHRM values.
+ */
+ blue_scale = png_reciprocal(xy.whitey) - png_reciprocal(red_inverse) -
+ png_reciprocal(green_inverse);
+ if (blue_scale <= 0) return 1;
+
+
+ /* And fill in the png_XYZ: */
+ if (!png_muldiv(&XYZ->redX, xy.redx, PNG_FP_1, red_inverse)) return 1;
+ if (!png_muldiv(&XYZ->redY, xy.redy, PNG_FP_1, red_inverse)) return 1;
+ if (!png_muldiv(&XYZ->redZ, PNG_FP_1 - xy.redx - xy.redy, PNG_FP_1,
+ red_inverse))
+ return 1;
+
+ if (!png_muldiv(&XYZ->greenX, xy.greenx, PNG_FP_1, green_inverse)) return 1;
+ if (!png_muldiv(&XYZ->greenY, xy.greeny, PNG_FP_1, green_inverse)) return 1;
+ if (!png_muldiv(&XYZ->greenZ, PNG_FP_1 - xy.greenx - xy.greeny, PNG_FP_1,
+ green_inverse))
+ return 1;
+
+ if (!png_muldiv(&XYZ->blueX, xy.bluex, blue_scale, PNG_FP_1)) return 1;
+ if (!png_muldiv(&XYZ->blueY, xy.bluey, blue_scale, PNG_FP_1)) return 1;
+ if (!png_muldiv(&XYZ->blueZ, PNG_FP_1 - xy.bluex - xy.bluey, blue_scale,
+ PNG_FP_1))
+ return 1;
+
+ return 0; /*success*/
+}
+
+int png_XYZ_from_xy_checked(png_structp png_ptr, png_XYZ *XYZ, png_xy xy)
+{
+ switch (png_XYZ_from_xy(XYZ, xy))
+ {
+ case 0: /* success */
+ return 1;
+
+ case 1:
+ /* The chunk may be technically valid, but we got png_fixed_point
+ * overflow while trying to get XYZ values out of it. This is
+ * entirely benign - the cHRM chunk is pretty extreme.
+ */
+ png_warning(png_ptr,
+ "extreme cHRM chunk cannot be converted to tristimulus values");
+ break;
+
+ default:
+ /* libpng is broken; this should be a warning but if it happens we
+ * want error reports so for the moment it is an error.
+ */
+ png_error(png_ptr, "internal error in png_XYZ_from_xy");
+ break;
+ }
+
+ /* ERROR RETURN */
+ return 0;
+}
+#endif
+
void /* PRIVATE */
png_check_IHDR(png_structp png_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -1383,18 +1722,30 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
size -= cdigits;
*ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */
- if (exp_b10 < 0)
+
+ /* The following use of an unsigned temporary avoids ambiguities in
+ * the signed arithmetic on exp_b10 and permits GCC at least to do
+ * better optimization.
+ */
{
- *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
- exp_b10 = -exp_b10;
- }
+ unsigned int uexp_b10;
+
+ if (exp_b10 < 0)
+ {
+ *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
+ uexp_b10 = -exp_b10;
+ }
- cdigits = 0;
+ else
+ uexp_b10 = exp_b10;
- while (exp_b10 > 0)
- {
- exponent[cdigits++] = (char)(48 + exp_b10 % 10);
- exp_b10 /= 10;
+ cdigits = 0;
+
+ while (uexp_b10 > 0)
+ {
+ exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
+ uexp_b10 /= 10;
+ }
}
/* Need another size check here for the exponent digits, so
@@ -1452,7 +1803,7 @@ png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
else
num = fp;
- if (num <= 0x80000000U) /* else overflowed */
+ if (num <= 0x80000000) /* else overflowed */
{
unsigned int ndigits = 0, first = 16 /* flag value */;
char digits[10];
diff --git a/png.h b/png.h
index c655a51af..6a7c27aa2 100644
--- a/png.h
+++ b/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.5.4 - July 7, 2011
+ * libpng version 1.5.5beta08 - September 10, 2011
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -11,7 +11,7 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.5.4 - July 7, 2011: Glenn
+ * libpng versions 0.97, January 1998, through 1.5.5beta08 - September 10, 2011: Glenn
* See also "Contributing Authors", below.
*
* Note about libpng version numbers:
@@ -157,6 +157,8 @@
* 1.5.4beta01-08 15 10504 15.so.15.4[.0]
* 1.5.4rc01 15 10504 15.so.15.4[.0]
* 1.5.4 15 10504 15.so.15.4[.0]
+ * 1.5.5beta01-08 15 10505 15.so.15.5[.0]
+ * 1.5.5rc01 15 10505 15.so.15.5[.0]
*
* Henceforth the source version will match the shared-library major
* and minor numbers; the shared-library major version number will be
@@ -188,7 +190,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.5.5beta08, September 10, 2011, are
* Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
* distributed according to the same disclaimer and license as libpng-1.2.5
* with the following individual added to the list of Contributing Authors:
@@ -300,13 +302,13 @@
* Y2K compliance in libpng:
* =========================
*
- * July 7, 2011
+ * September 10, 2011
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
*
* This is your unofficial assurance that libpng from version 0.71 and
- * upward through 1.5.4 are Y2K compliant. It is my belief that
+ * upward through 1.5.5beta08 are Y2K compliant. It is my belief that
* earlier versions were also Y2K compliant.
*
* Libpng only has two year fields. One is a 2-byte unsigned integer
@@ -361,9 +363,9 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.5.4"
+#define PNG_LIBPNG_VER_STRING "1.5.5beta08"
#define PNG_HEADER_VERSION_STRING \
- " libpng version 1.5.4 - July 7, 2011\n"
+ " libpng version 1.5.5beta08 - September 10, 2011\n"
#define PNG_LIBPNG_VER_SONUM 15
#define PNG_LIBPNG_VER_DLLNUM 15
@@ -371,12 +373,12 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 5
-#define PNG_LIBPNG_VER_RELEASE 4
+#define PNG_LIBPNG_VER_RELEASE 5
/* This should match the numeric part of the final component of
* PNG_LIBPNG_VER_STRING, omitting any leading zero:
*/
-#define PNG_LIBPNG_VER_BUILD 0
+#define PNG_LIBPNG_VER_BUILD 08
/* Release Status */
#define PNG_LIBPNG_BUILD_ALPHA 1
@@ -401,7 +403,7 @@
* version 1.0.0 was mis-numbered 100 instead of 10000). From
* version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release
*/
-#define PNG_LIBPNG_VER 10504 /* 1.5.4 */
+#define PNG_LIBPNG_VER 10505 /* 1.5.5 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -523,7 +525,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_5_4;
+typedef char* png_libpng_version_1_5_5beta08;
/* Three color definitions. The order of the red, green, and blue, (and the
* exact size) is not important, although the size of the fields need to
@@ -793,7 +795,7 @@ typedef png_info FAR * FAR * png_infopp;
#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */
#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
-#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
+#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -2047,6 +2049,10 @@ PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr,
png_const_infop info_ptr, double *white_x, double *white_y, double *red_x,
double *red_y, double *green_x, double *green_y, double *blue_x,
double *blue_y));
+PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr,
+ png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z,
+ double *green_X, double *green_Y, double *green_Z, double *blue_X,
+ double *blue_Y, double *blue_Z));
#ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */
PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
(png_const_structp png_ptr,
@@ -2056,6 +2062,13 @@ PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
png_fixed_point *int_green_y, png_fixed_point *int_blue_x,
png_fixed_point *int_blue_y));
#endif
+PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
+ (png_structp png_ptr, png_const_infop info_ptr,
+ png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+ png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+ png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+ png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+ png_fixed_point *int_blue_Z));
#endif
#ifdef PNG_cHRM_SUPPORTED
@@ -2063,12 +2076,22 @@ PNG_FP_EXPORT(135, void, png_set_cHRM,
(png_structp png_ptr, png_infop info_ptr,
double white_x, double white_y, double red_x, double red_y, double green_x,
double green_y, double blue_x, double blue_y));
+PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr,
+ png_infop info_ptr, double red_X, double red_Y, double red_Z,
+ double green_X, double green_Y, double green_Z, double blue_X,
+ double blue_Y, double blue_Z));
PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr,
png_infop info_ptr, png_fixed_point int_white_x,
png_fixed_point int_white_y, png_fixed_point int_red_x,
png_fixed_point int_red_y, png_fixed_point int_green_x,
png_fixed_point int_green_y, png_fixed_point int_blue_x,
png_fixed_point int_blue_y));
+PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
+ png_fixed_point int_red_Z, png_fixed_point int_green_X,
+ png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+ png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+ png_fixed_point int_blue_Z));
#endif
#ifdef PNG_gAMA_SUPPORTED
@@ -2282,7 +2305,7 @@ PNG_EXPORT(171, void, png_set_sCAL_s,
handling or default unknown chunk handling is not desired. Any chunks not
listed will be handled in the default manner. The IHDR and IEND chunks
must not be listed.
- keep = 0: follow default behaviour
+ keep = 0: follow default behavior
= 1: do not keep
= 2: keep only if safe-to-copy
= 3: keep even if unsafe-to-copy
@@ -2492,14 +2515,14 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
{ png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \
* (png_uint_16)(alpha) \
+ (png_uint_16)(bg)*(png_uint_16)(255 \
- - (png_uint_16)(alpha)) + (png_uint_16)128); \
+ - (png_uint_16)(alpha)) + 128); \
(composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
# define png_composite_16(composite, fg, alpha, bg) \
{ png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \
* (png_uint_32)(alpha) \
- + (png_uint_32)(bg)*(png_uint_32)(65535L \
- - (png_uint_32)(alpha)) + (png_uint_32)32768L); \
+ + (png_uint_32)(bg)*(65535 \
+ - (png_uint_32)(alpha)) + 32768); \
(composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
#else /* Standard method using integer division */
@@ -2507,12 +2530,12 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
# define png_composite(composite, fg, alpha, bg) \
(composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \
(png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
- (png_uint_16)127) / 255)
+ 127) / 255)
# define png_composite_16(composite, fg, alpha, bg) \
(composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
- (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \
- (png_uint_32)32767) / (png_uint_32)65535L)
+ (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \
+ 32767) / 65535)
#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
@@ -2576,7 +2599,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
* scripts/symbols.def as well.
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(229);
+ PNG_EXPORT_LAST_ORDINAL(233);
#endif
#ifdef __cplusplus
diff --git a/pngconf.h b/pngconf.h
index f0e0da035..db3569416 100644
--- a/pngconf.h
+++ b/pngconf.h
@@ -1,7 +1,7 @@
/* pngconf.h - machine configurable file for libpng
*
- * libpng version 1.5.4 - July 7, 2011
+ * libpng version 1.5.5beta08 - September 10, 2011
*
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
@@ -14,7 +14,6 @@
* This file has been modified, by Glenn Randers-Pehrson, from the original
* libpng distribution by adding a line reading
* #include "pngcrush.h"
- *
*/
/* Any machine specific code is near the front of this file, so if you
@@ -170,7 +169,9 @@
* 'type', compiler specific.
*
* PNG_DLL_EXPORT Set to the magic to use during a libpng build to
- * make a symbol exported from the DLL.
+ * make a symbol exported from the DLL. Not used in the
+ * public header files; see pngpriv.h for how it is used
+ * in the libpng build.
*
* PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come
* from a DLL - used to define PNG_IMPEXP when
@@ -264,25 +265,14 @@
# define PNGAPI PNGCAPI
#endif
-/* The default for PNG_IMPEXP depends on whether the library is
- * being built or used.
+/* PNG_IMPEXP may be set on the compilation system command line or (if not set)
+ * then in an internal header file when building the library, otherwise (when
+ * using the library) it is set here.
*/
#ifndef PNG_IMPEXP
-# ifdef PNGLIB_BUILD
- /* Building the library */
-# if (defined(DLL_EXPORT)/*from libtool*/ ||\
- defined(_WINDLL) || defined(_DLL) || defined(__DLL__) ||\
- defined(_USRDLL) ||\
- defined(PNG_BUILD_DLL)) && defined(PNG_DLL_EXPORT)
- /* Building a DLL. */
-# define PNG_IMPEXP PNG_DLL_EXPORT
-# endif /* DLL */
-# else
- /* Using the library */
-# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)
- /* This forces use of a DLL, disallowing static linking */
-# define PNG_IMPEXP PNG_DLL_IMPORT
-# endif
+# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)
+ /* This forces use of a DLL, disallowing static linking */
+# define PNG_IMPEXP PNG_DLL_IMPORT
# endif
# ifndef PNG_IMPEXP
@@ -362,25 +352,18 @@
# ifndef PNG_ALLOCATED
# define PNG_ALLOCATED __attribute__((__malloc__))
# endif
-
- /* This specifically protects structure members that should only be
- * accessed from within the library, therefore should be empty during
- * a library build.
- */
-# ifndef PNGLIB_BUILD
-# ifndef PNG_DEPRECATED
-# define PNG_DEPRECATED __attribute__((__deprecated__))
-# endif
-# ifndef PNG_PRIVATE
-# if 0 /* Doesn't work so we use deprecated instead*/
-# define PNG_PRIVATE \
- __attribute__((warning("This function is not exported by libpng.")))
-# else
-# define PNG_PRIVATE \
- __attribute__((__deprecated__))
-# endif
+# ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED __attribute__((__deprecated__))
+# endif
+# ifndef PNG_PRIVATE
+# if 0 /* Doesn't work so we use deprecated instead*/
+# define PNG_PRIVATE \
+ __attribute__((warning("This function is not exported by libpng.")))
+# else
+# define PNG_PRIVATE \
+ __attribute__((__deprecated__))
# endif
-# endif /* PNGLIB_BUILD */
+# endif
# endif /* __GNUC__ */
# if defined(_MSC_VER) && (_MSC_VER >= 1300)
@@ -391,23 +374,16 @@
# define PNG_NORETURN __declspec(noreturn)
# endif
# ifndef PNG_ALLOCATED
-# if (_MSC_VER >= 1400)
+# if defined(_MSC_VER) && (_MSC_VER >= 1300)
# define PNG_ALLOCATED __declspec(restrict)
# endif
# endif
-
- /* This specifically protects structure members that should only be
- * accessed from within the library, therefore should be empty during
- * a library build.
- */
-# ifndef PNGLIB_BUILD
-# ifndef PNG_DEPRECATED
-# define PNG_DEPRECATED __declspec(deprecated)
-# endif
-# ifndef PNG_PRIVATE
-# define PNG_PRIVATE __declspec(deprecated)
-# endif
-# endif /* PNGLIB_BUILD */
+# ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED __declspec(deprecated)
+# endif
+# ifndef PNG_PRIVATE
+# define PNG_PRIVATE __declspec(deprecated)
+# endif
# endif /* _MSC_VER */
#endif /* PNG_PEDANTIC_WARNINGS */
diff --git a/pngcrush.c b/pngcrush.c
index 1ed4865ca..04bf20658 100644
--- a/pngcrush.c
+++ b/pngcrush.c
@@ -185,7 +185,7 @@
Change log:
-Version 1.7.17 (built with libpng-1.5.4 and zlib-1.2.5)
+Version 1.7.17 (built with libpng-1.5.5beta08 and zlib-1.2.5)
Changed "#if !defined(PNG_NO_STDIO)" to "#ifdef PNG_STDIO_SUPPORTED"
as recommended in the libpng documentation.
Added PNG_UINT_32_NAME macro and used it to simplify chunk_type integer
@@ -3970,9 +3970,11 @@ int main(int argc, char *argv[])
need_expand = 1;
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
- if ((color_type == 2 || color_type == 6
- || color_type == 3) &&
- (output_color_type == 0 || output_color_type == 4))
+ if ((color_type == 2 ||
+ color_type == 6 ||
+ color_type == 3) &&
+ (output_color_type == 0 ||
+ output_color_type == 4))
{
if (verbose > 0 && first_trial)
{
@@ -3986,9 +3988,11 @@ int main(int argc, char *argv[])
"image to grayscale.\n");
}
#ifdef PNG_FIXED_POINT_SUPPORTED
- png_set_rgb_to_gray_fixed(read_ptr, 1, -1, -1);
+ png_set_rgb_to_gray_fixed(read_ptr, 1,
+ 21260, 71520);
#else
- png_set_rgb_to_gray(read_ptr, 1, 0., 0.);
+ png_set_rgb_to_gray(read_ptr, 1,
+ 0.21260, 0.71520);
#endif
if (output_bit_depth < 8)
output_bit_depth = 8;
diff --git a/pngcrush.h b/pngcrush.h
index 62890f977..f00311d7a 100644
--- a/pngcrush.h
+++ b/pngcrush.h
@@ -5,16 +5,11 @@
* license (see LICENSE, in pngcrush.c).
*/
-/* Special defines for pngcrush, mostly just to reduce the size of the
- static executable. */
+/* Special defines for pngcrush. */
#ifndef PNGCRUSH_H
#define PNGCRUSH_H
-/*
-#include <malloc.h>
-*/
-
#define TOO_FAR 32767
/* This allows png_default_error() to return, when it is called after our
diff --git a/pngget.c b/pngget.c
index b5e5798c0..770c123e7 100644
--- a/pngget.c
+++ b/pngget.c
@@ -1,7 +1,7 @@
/* pngget.c - retrieval of values from info struct
*
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -459,6 +459,65 @@ png_get_bKGD(png_const_structp png_ptr, png_infop info_ptr,
#endif
#ifdef PNG_cHRM_SUPPORTED
+/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the
+ * same time to correct the rgb grayscale coefficient defaults obtained from the
+ * cHRM chunk in 1.5.4
+ */
+png_uint_32 PNGFAPI
+png_get_cHRM_XYZ_fixed(png_structp png_ptr, png_const_infop info_ptr,
+ png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+ png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+ png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+ png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+ png_fixed_point *int_blue_Z)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_xy xy;
+ png_XYZ XYZ;
+
+ png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
+
+ xy.whitex = info_ptr->x_white;
+ xy.whitey = info_ptr->y_white;
+ xy.redx = info_ptr->x_red;
+ xy.redy = info_ptr->y_red;
+ xy.greenx = info_ptr->x_green;
+ xy.greeny = info_ptr->y_green;
+ xy.bluex = info_ptr->x_blue;
+ xy.bluey = info_ptr->y_blue;
+
+ /* The *_checked function handles error reporting, so just return 0 if
+ * there is a failure here.
+ */
+ if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy))
+ {
+ if (int_red_X != NULL)
+ *int_red_X = XYZ.redX;
+ if (int_red_Y != NULL)
+ *int_red_Y = XYZ.redY;
+ if (int_red_Z != NULL)
+ *int_red_Z = XYZ.redZ;
+ if (int_green_X != NULL)
+ *int_green_X = XYZ.greenX;
+ if (int_green_Y != NULL)
+ *int_green_Y = XYZ.greenY;
+ if (int_green_Z != NULL)
+ *int_green_Z = XYZ.greenZ;
+ if (int_blue_X != NULL)
+ *int_blue_X = XYZ.blueX;
+ if (int_blue_Y != NULL)
+ *int_blue_Y = XYZ.blueY;
+ if (int_blue_Z != NULL)
+ *int_blue_Z = XYZ.blueZ;
+
+ return (PNG_INFO_cHRM);
+ }
+ }
+
+ return (0);
+}
+
# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_cHRM(png_const_structp png_ptr, png_const_infop info_ptr,
@@ -490,6 +549,42 @@ png_get_cHRM(png_const_structp png_ptr, png_const_infop info_ptr,
return (0);
}
+
+png_uint_32 PNGAPI
+png_get_cHRM_XYZ(png_structp png_ptr, png_const_infop info_ptr,
+ double *red_X, double *red_Y, double *red_Z, double *green_X,
+ double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
+ double *blue_Z)
+{
+ png_XYZ XYZ;
+
+ if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr,
+ &XYZ.redX, &XYZ.redY, &XYZ.redZ, &XYZ.greenX, &XYZ.greenY, &XYZ.greenZ,
+ &XYZ.blueX, &XYZ.blueY, &XYZ.blueZ) & PNG_INFO_cHRM)
+ {
+ if (red_X != NULL)
+ *red_X = png_float(png_ptr, XYZ.redX, "cHRM red X");
+ if (red_Y != NULL)
+ *red_Y = png_float(png_ptr, XYZ.redY, "cHRM red Y");
+ if (red_Z != NULL)
+ *red_Z = png_float(png_ptr, XYZ.redZ, "cHRM red Z");
+ if (green_X != NULL)
+ *green_X = png_float(png_ptr, XYZ.greenX, "cHRM green X");
+ if (green_Y != NULL)
+ *green_Y = png_float(png_ptr, XYZ.greenY, "cHRM green Y");
+ if (green_Z != NULL)
+ *green_Z = png_float(png_ptr, XYZ.greenZ, "cHRM green Z");
+ if (blue_X != NULL)
+ *blue_X = png_float(png_ptr, XYZ.blueX, "cHRM blue X");
+ if (blue_Y != NULL)
+ *blue_Y = png_float(png_ptr, XYZ.blueY, "cHRM blue Y");
+ if (blue_Z != NULL)
+ *blue_Z = png_float(png_ptr, XYZ.blueZ, "cHRM blue Z");
+ return (PNG_INFO_cHRM);
+ }
+
+ return (0);
+}
# endif
# ifdef PNG_FIXED_POINT_SUPPORTED
@@ -971,7 +1066,7 @@ png_get_user_chunk_ptr(png_const_structp png_ptr)
png_size_t PNGAPI
png_get_compression_buffer_size(png_const_structp png_ptr)
{
- return (png_ptr ? png_ptr->zbuf_size : 0L);
+ return (png_ptr ? png_ptr->zbuf_size : 0);
}
diff --git a/pnglibconf.h b/pnglibconf.h
index 827d17e54..8022a5a88 100644
--- a/pnglibconf.h
+++ b/pnglibconf.h
@@ -33,8 +33,8 @@
#define PNG_sCAL_PRECISION 5
#define PNG_USER_CHUNK_CACHE_MAX 0
#define PNG_USER_CHUNK_MALLOC_MAX 0
-#define PNG_USER_HEIGHT_MAX 1000000L
-#define PNG_USER_WIDTH_MAX 1000000L
+#define PNG_USER_HEIGHT_MAX 1000000
+#define PNG_USER_WIDTH_MAX 1000000
#define PNG_WEIGHT_SHIFT 8
#define PNG_ZBUF_SIZE 8192
/* end of settings */
diff --git a/pngpriv.h b/pngpriv.h
index 5b4d2127c..92e39ab49 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -6,7 +6,7 @@
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -44,7 +44,8 @@
*/
#include <stdlib.h>
-#define PNGLIB_BUILD
+#define PNGLIB_BUILD /*libpng is being built, not used*/
+
#ifdef PNG_USER_CONFIG
# include "pngusr.h"
/* These should have been defined in pngusr.h */
@@ -55,10 +56,80 @@
# define PNG_USER_DLLFNAME_POSTFIX "Cb"
# endif
#endif
+
+/* Is this a build of a DLL where compilation of the object modules requires
+ * different preprocessor settings to those required for a simple library? If
+ * so PNG_BUILD_DLL must be set.
+ *
+ * If libpng is used inside a DLL but that DLL does not export the libpng APIs
+ * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a
+ * static library of libpng then link the DLL against that.
+ */
+#ifndef PNG_BUILD_DLL
+# ifdef DLL_EXPORT
+ /* This is set by libtool when files are compiled for a DLL; libtool
+ * always compiles twice, even on systems where it isn't necessary. Set
+ * PNG_BUILD_DLL in case it is necessary:
+ */
+# define PNG_BUILD_DLL
+# else
+# ifdef _WINDLL
+ /* This is set by the Microsoft Visual Studio IDE in projects that
+ * build a DLL. It can't easily be removed from those projects (it
+ * isn't visible in the Visual Studio UI) so it is a fairly reliable
+ * indication that PNG_IMPEXP needs to be set to the DLL export
+ * attributes.
+ */
+# define PNG_BUILD_DLL
+# else
+# ifdef __DLL__
+ /* This is set by the Borland C system when compiling for a DLL
+ * (as above.)
+ */
+# define PNG_BUILD_DLL
+# else
+ /* Add additional compiler cases here. */
+# endif
+# endif
+# endif
+#endif /* Setting PNG_BUILD_DLL if required */
+
+/* See pngconf.h for more details: the builder of the library may set this on
+ * the command line to the right thing for the specific compilation system or it
+ * may be automagically set above (at present we know of no system where it does
+ * need to be set on the command line.)
+ *
+ * PNG_IMPEXP must be set here when building the library to prevent pngconf.h
+ * setting it to the "import" setting for a DLL build.
+ */
+#ifndef PNG_IMPEXP
+# ifdef PNG_BUILD_DLL
+# define PNG_IMPEXP PNG_DLL_EXPORT
+# else
+ /* Not building a DLL, or the DLL doesn't require specific export
+ * definitions.
+ */
+# define PNG_IMPEXP
+# endif
+#endif
+
+/* No warnings for private or deprecated functions in the build: */
+#ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED
+#endif
+#ifndef PNG_PRIVATE
+# define PNG_PRIVATE
+#endif
+
#include "png.h"
#include "pnginfo.h"
#include "pngstruct.h"
+/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */
+#ifndef PNG_DLL_EXPORT
+# define PNG_DLL_EXPORT
+#endif
+
/* This is used for 16 bit gamma tables - only the top level pointers are const,
* this could be changed:
*/
@@ -301,16 +372,15 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define PNG_USER_TRANSFORM 0x100000L
#define PNG_RGB_TO_GRAY_ERR 0x200000L
#define PNG_RGB_TO_GRAY_WARN 0x400000L
-#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
-#define PNG_ENCODE_ALPHA 0x800000L /* Added to libpng-1.5.4 */
-#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */
-#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */
-#define PNG_SCALE_16_TO_8 0x4000000L /* Added to libpng-1.5.4 */
- /* 0x8000000L unused */
- /* 0x10000000L unused */
- /* 0x20000000L unused */
- /* 0x40000000L unused */
-
+#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
+#define PNG_ENCODE_ALPHA 0x800000L /* Added to libpng-1.5.4 */
+#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */
+#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */
+#define PNG_SCALE_16_TO_8 0x4000000L /* Added to libpng-1.5.4 */
+ /* 0x8000000L unused */
+ /* 0x10000000L unused */
+ /* 0x20000000L unused */
+ /* 0x40000000L unused */
/* Flags for png_create_struct */
#define PNG_STRUCT_PNG 0x0001
#define PNG_STRUCT_INFO 0x0002
@@ -335,22 +405,22 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */
-#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L
-#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L
-#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L
-#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L
-#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L
-#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L
- /* 0x200000L unused */
- /* 0x400000L unused */
-#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000L /* Added to libpng-1.4.0 */
-#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000L /* 5 lines added */
-#define PNG_FLAG_ZTXT_CUSTOM_LEVEL 0x2000000L /* to libpng-1.5.4 */
-#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL 0x4000000L
-#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000L
-#define PNG_FLAG_ZTXT_CUSTOM_METHOD 0x10000000L
- /* 0x20000000L unused */
- /* 0x40000000L unused */
+#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000
+#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000
+#define PNG_FLAG_LIBRARY_MISMATCH 0x20000
+#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000
+#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000
+#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000
+ /* 0x200000 unused */
+ /* 0x400000 unused */
+#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000 /* Added to libpng-1.4.0 */
+#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000 /* 5 lines added */
+#define PNG_FLAG_ZTXT_CUSTOM_LEVEL 0x2000000 /* to libpng-1.5.4 */
+#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL 0x4000000
+#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000
+#define PNG_FLAG_ZTXT_CUSTOM_METHOD 0x10000000
+ /* 0x20000000 unused */
+ /* 0x40000000 unused */
#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
PNG_FLAG_CRC_ANCILLARY_NOWARN)
@@ -1078,6 +1148,35 @@ PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2,
unsigned long *hi_product, unsigned long *lo_product));
#endif
+#ifdef PNG_cHRM_SUPPORTED
+/* Added at libpng version 1.5.5 */
+typedef struct png_xy
+{
+ png_fixed_point redx, redy;
+ png_fixed_point greenx, greeny;
+ png_fixed_point bluex, bluey;
+ png_fixed_point whitex, whitey;
+} png_xy;
+
+typedef struct png_XYZ
+{
+ png_fixed_point redX, redY, redZ;
+ png_fixed_point greenX, greenY, greenZ;
+ png_fixed_point blueX, blueY, blueZ;
+} png_XYZ;
+
+/* The conversion APIs return 0 on success, non-zero on a parameter error. They
+ * allow conversion between the above representations of a color encoding. When
+ * converting from XYZ end points to chromaticities the absolute magnitude of
+ * the end points is lost, when converting back the sum of the Y values of the
+ * three end points will be 1.0
+ */
+PNG_EXTERN int png_xy_from_XYZ PNGARG((png_xy *xy, png_XYZ XYZ));
+PNG_EXTERN int png_XYZ_from_xy PNGARG((png_XYZ *XYZ, png_xy xy));
+PNG_EXTERN int png_XYZ_from_xy_checked PNGARG((png_structp png_ptr,
+ png_XYZ *XYZ, png_xy xy));
+#endif
+
/* Added at libpng version 1.4.0 */
PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth,
diff --git a/pngrtran.c b/pngrtran.c
index 4e0401aa9..c6dd28808 100644
--- a/pngrtran.c
+++ b/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -968,13 +968,17 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
{
png_uint_16 red_int, green_int;
- red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
- green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
+ /* NOTE: this calculation does not round, but this behavior is retained
+ * for consistency, the inaccuracy is very small. The code here always
+ * overwrites the coefficients, regardless of whether they have been
+ * defaulted or set already.
+ */
+ red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);
+ green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);
png_ptr->rgb_to_gray_red_coeff = red_int;
png_ptr->rgb_to_gray_green_coeff = green_int;
- png_ptr->rgb_to_gray_blue_coeff =
- (png_uint_16)(32768 - red_int - green_int);
+ png_ptr->rgb_to_gray_coefficients_set = 1;
}
else
@@ -983,17 +987,18 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
png_warning(png_ptr,
"ignoring out of range rgb_to_gray coefficients");
- /* Use the defaults, from the cHRM chunk if set, else the built in Rec
- * 709 values (which correspond to sRGB, so we don't have to worry
- * about the sRGB chunk!)
+ /* Use the defaults, from the cHRM chunk if set, else the historical
+ * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See
+ * png_do_rgb_to_gray for more discussion of the values. In this case
+ * the coefficients are not marked as 'set' and are not overwritten if
+ * something has already provided a default.
*/
if (png_ptr->rgb_to_gray_red_coeff == 0 &&
- png_ptr->rgb_to_gray_green_coeff == 0 &&
- png_ptr->rgb_to_gray_blue_coeff == 0)
+ png_ptr->rgb_to_gray_green_coeff == 0)
{
- png_ptr->rgb_to_gray_red_coeff = 6968; /* .212671 * 32768 + .5 */
- png_ptr->rgb_to_gray_green_coeff = 23434; /* .715160 * 32768 + .5 */
- png_ptr->rgb_to_gray_blue_coeff = 2366;
+ png_ptr->rgb_to_gray_red_coeff = 6968;
+ png_ptr->rgb_to_gray_green_coeff = 23434;
+ /* png_ptr->rgb_to_gray_blue_coeff = 2366; */
}
}
}
@@ -1401,7 +1406,7 @@ png_init_read_transformations(png_structp png_ptr)
if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
{
/* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
- * the file was greyscale the background value is gray.
+ * the file was grayscale the background value is gray.
*/
if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
@@ -1635,7 +1640,7 @@ png_init_read_transformations(png_structp png_ptr)
/* Prevent the transformations being done again.
*
- * NOTE: this is highly dubious; it zaps the transformations in
+ * NOTE: this is highly dubious; it removes the transformations in
* place. This seems inconsistent with the general treatment of the
* transformations elsewhere.
*/
@@ -3066,33 +3071,61 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
/* Reduce RGB files to grayscale, with or without alpha
- * using the equation given in Poynton's ColorFAQ at
- * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
- * New link:
- * <http://www.poynton.com/notes/colour_and_gamma/>
+ * using the equation given in Poynton's ColorFAQ of 1998-01-04 at
+ * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008 but
+ * versions dated 1998 through November 2002 have been archived at
+ * http://web.archive.org/web/20000816232553/http://www.inforamp.net/
+ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )
* Charles Poynton poynton at poynton.com
*
* Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
*
- * We approximate this with
+ * which can be expressed with integers as
+ *
+ * Y = (6969 * R + 23434 * G + 2365 * B)/32768
+ *
+ * Poynton's current link (as of January 2003 through July 2011):
+ * <http://www.poynton.com/notes/colour_and_gamma/>
+ * has changed the numbers slightly:
*
- * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+ * Y = 0.2126*R + 0.7152*G + 0.0722*B
*
* which can be expressed with integers as
*
- * Y = (6969 * R + 23434 * G + 2365 * B)/32768
+ * Y = (6966 * R + 23436 * G + 2366 * B)/32768
*
- * The calculation is to be done in a linear colorspace.
+ * Historically, however, libpng uses numbers derived from the ITU-R Rec 709
+ * end point chromaticities and the D65 white point. Depending on the
+ * precision used for the D65 white point this produces a variety of different
+ * numbers, however if the four decimal place value used in ITU-R Rec 709 is
+ * used (0.3127,0.3290) the Y calculation would be:
*
- * Other integer coefficents can be used via png_set_rgb_to_gray().
+ * Y = (6968 * R + 23435 * G + 2366 * B)/32768
+ *
+ * While this is correct the rounding results in an overflow for white, because
+ * the sum of the rounded coefficients is 32769, not 32768. Consequently
+ * libpng uses, instead, the closest non-overflowing approximation:
+ *
+ * Y = (6968 * R + 23434 * G + 2366 * B)/32768
+ *
+ * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk
+ * (including an sRGB chunk) then the chromaticities are used to calculate the
+ * coefficients. See the chunk handling in pngrutil.c for more information.
+ *
+ * In all cases the calculation is to be done in a linear colorspace. If no
+ * gamma information is available to correct the encoding of the original RGB
+ * values this results in an implicit assumption that the original PNG RGB
+ * values were linear.
+ *
+ * Other integer coefficents can be used via png_set_rgb_to_gray(). Because
+ * the API takes just red and green coefficients the blue coefficient is
+ * calculated to make the sum 32768. This will result in different rounding
+ * to that used above.
*/
int /* PRIVATE */
png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
{
- png_uint_32 i;
-
- png_uint_32 row_width = row_info->width;
int rgb_error = 0;
png_debug(1, "in png_do_rgb_to_gray");
@@ -3100,234 +3133,179 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) &&
(row_info->color_type & PNG_COLOR_MASK_COLOR))
{
- png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
- png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
- png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
+ PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
+ PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
+ PNG_CONST png_uint_32 bc = 32768 - rc - gc;
+ PNG_CONST png_uint_32 row_width = row_info->width;
+ PNG_CONST int have_alpha =
+ (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;
- if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ if (row_info->bit_depth == 8)
{
- if (row_info->bit_depth == 8)
- {
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ /* Notice that gamma to/from 1 are not necessarily inverses (if
+ * there is an overall gamma correction). Prior to 1.5.5 this code
+ * checked the linearized values for equality; this doesn't match
+ * the documentation, the original values must be checked.
+ */
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
- for (i = 0; i < row_width; i++)
+ if (red != green || red != blue)
{
- png_byte red = png_ptr->gamma_to_1[*(sp++)];
- png_byte green = png_ptr->gamma_to_1[*(sp++)];
- png_byte blue = png_ptr->gamma_to_1[*(sp++)];
-
- if (red != green || red != blue)
- {
- rgb_error |= 1;
- *(dp++) = png_ptr->gamma_from_1[
- (rc*red + gc*green + bc*blue)>>15];
- }
+ red = png_ptr->gamma_to_1[red];
+ green = png_ptr->gamma_to_1[green];
+ blue = png_ptr->gamma_to_1[blue];
- else
- *(dp++) = *(sp - 1);
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1[
+ (rc*red + gc*green + bc*blue + 16384)>>15];
}
- }
- else
-#endif
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_byte red = *(sp++);
- png_byte green = *(sp++);
- png_byte blue = *(sp++);
- if (red != green || red != blue)
- {
- rgb_error |= 1;
- *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
- }
+ else
+ {
+ /* If there is no overall correction the table will not be
+ * set.
+ */
+ if (png_ptr->gamma_table != NULL)
+ red = png_ptr->gamma_table[red];
- else
- *(dp++) = *(sp - 1);
+ *(dp++) = red;
}
+
+ if (have_alpha)
+ *(dp++) = *(sp++);
}
}
-
- else /* RGB bit_depth == 16 */
+ else
+#endif
{
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_16_to_1 != NULL &&
- png_ptr->gamma_16_from_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_uint_16 red, green, blue, w;
-
- red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
-
- if (red == green && red == blue)
- w = red;
-
- else
- {
- png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff)
- >> png_ptr->gamma_shift][red>>8];
- png_uint_16 green_1 =
- png_ptr->gamma_16_to_1[(green&0xff) >>
- png_ptr->gamma_shift][green>>8];
- png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff)
- >> png_ptr->gamma_shift][blue>>8];
- png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
- + bc*blue_1)>>15);
- w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
- png_ptr->gamma_shift][gray16 >> 8];
- rgb_error |= 1;
- }
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
- *(dp++) = (png_byte)((w>>8) & 0xff);
- *(dp++) = (png_byte)(w & 0xff);
- }
- }
- else
-#endif
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_uint_16 red, green, blue, gray16;
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
- red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+ if (red != green || red != blue)
+ {
+ rgb_error |= 1;
+ /*NOTE: this is the historical approach which simply
+ * truncates the results.
+ */
+ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
+ }
- if (red != green || red != blue)
- rgb_error |= 1;
+ else
+ *(dp++) = red;
- gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = (png_byte)((gray16>>8) & 0xff);
- *(dp++) = (png_byte)(gray16 & 0xff);
- }
+ if (have_alpha)
+ *(dp++) = *(sp++);
}
}
}
- if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+
+ else /* RGB bit_depth == 16 */
{
- if (row_info->bit_depth == 8)
- {
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
{
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_byte red = png_ptr->gamma_to_1[*(sp++)];
- png_byte green = png_ptr->gamma_to_1[*(sp++)];
- png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ png_uint_16 red, green, blue, w;
- if (red != green || red != blue)
- rgb_error |= 1;
+ red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- *(dp++) = png_ptr->gamma_from_1
- [(rc*red + gc*green + bc*blue)>>15];
+ if (red == green && red == blue)
+ {
+ if (png_ptr->gamma_16_table != NULL)
+ w = png_ptr->gamma_16_table[(red&0xff)
+ >> png_ptr->gamma_shift][red>>8];
- *(dp++) = *(sp++); /* alpha */
+ else
+ w = red;
}
- }
- else
-#endif
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
+
+ else
{
- png_byte red = *(sp++);
- png_byte green = *(sp++);
- png_byte blue = *(sp++);
- if (red != green || red != blue)
- rgb_error |= 1;
-
- *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = *(sp++); /* alpha */
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff)
+ >> png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 =
+ png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff)
+ >> png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
+ + bc*blue_1 + 16384)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+
+ if (have_alpha)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
}
}
}
- else /* RGBA bit_depth == 16 */
+ else
+#endif
{
-#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
- if (png_ptr->gamma_16_to_1 != NULL &&
- png_ptr->gamma_16_from_1 != NULL)
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
- {
- png_uint_16 red, green, blue, w;
-
- red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
-
- if (red == green && red == blue)
- w = red;
-
- else
- {
- png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
- png_ptr->gamma_shift][red>>8];
-
- png_uint_16 green_1 =
- png_ptr->gamma_16_to_1[(green&0xff) >>
- png_ptr->gamma_shift][green>>8];
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
- png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
- png_ptr->gamma_shift][blue>>8];
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
- png_uint_16 gray16 = (png_uint_16)((rc * red_1
- + gc * green_1 + bc * blue_1)>>15);
+ red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
- w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
- png_ptr->gamma_shift][gray16 >> 8];
+ if (red != green || red != blue)
+ rgb_error |= 1;
- rgb_error |= 1;
- }
+ /* From 1.5.5 in the 16 bit case do the accurate convertion even
+ * in the 'fast' case - this is because this is where the code
+ * ends up when handling linear 16 bit data.
+ */
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>
+ 15);
+ *(dp++) = (png_byte)((gray16>>8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
- *(dp++) = (png_byte)((w>>8) & 0xff);
- *(dp++) = (png_byte)(w & 0xff);
- *(dp++) = *(sp++); /* alpha */
- *(dp++) = *(sp++);
- }
- }
- else
-#endif
- {
- png_bytep sp = row;
- png_bytep dp = row;
- for (i = 0; i < row_width; i++)
+ if (have_alpha)
{
- png_uint_16 red, green, blue, gray16;
- red = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2;
- green = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2;
- blue = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2;
-
- if (red != green || red != blue)
- rgb_error |= 1;
-
- gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
- *(dp++) = (png_byte)((gray16>>8) & 0xff);
- *(dp++) = (png_byte)(gray16 & 0xff);
- *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
*(dp++) = *(sp++);
}
}
}
}
+
row_info->channels -= 2;
row_info->color_type = (png_byte)(row_info->color_type &
~PNG_COLOR_MASK_COLOR);
@@ -4762,7 +4740,7 @@ png_do_expand(png_row_infop row_info, png_bytep row,
#endif
#ifdef PNG_READ_EXPAND_16_SUPPORTED
-/* If the bit depth is 8 and the colour type is not a palette type expand the
+/* If the bit depth is 8 and the color type is not a palette type expand the
* whole row to 16 bits. Has no effect otherwise.
*/
void /* PRIVATE */
@@ -4939,8 +4917,8 @@ png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
- png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
- png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
+ png_uint_32 red = (s0 + s1 + 65536) & 0xffff;
+ png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;
*(rp ) = (png_byte)((red >> 8) & 0xff);
*(rp + 1) = (png_byte)(red & 0xff);
*(rp + 4) = (png_byte)((blue >> 8) & 0xff);
diff --git a/pngrutil.c b/pngrutil.c
index 07e46e2fe..a74353de1 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -87,10 +87,10 @@ png_int_32 (PNGAPI
png_get_int_32)(png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
- if ((uval & 0x80000000L) == 0) /* non-negative */
+ if ((uval & 0x80000000) == 0) /* non-negative */
return uval;
- uval = (uval ^ 0xffffffffL) + 1; /* 2's complement: -x = ~x+1 */
+ uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
return -(png_int_32)uval;
}
@@ -458,7 +458,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
{
/* Success (maybe) - really uncompress the chunk. */
png_size_t new_size = 0;
- png_charp text = png_malloc_warn(png_ptr,
+ png_charp text = (png_charp)png_malloc_warn(png_ptr,
prefix_size + expanded_size + 1);
if (text != NULL)
@@ -501,7 +501,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
* amount of compressed data.
*/
{
- png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
+ png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + 1);
if (text != NULL)
{
@@ -827,7 +827,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
# ifdef PNG_READ_sRGB_SUPPORTED
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
{
- if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
+ if (PNG_OUT_OF_RANGE(igamma, 45500, 500))
{
PNG_WARNING_PARAMETERS(p)
png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma);
@@ -994,10 +994,10 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) ||
PNG_OUT_OF_RANGE(y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(x_red, 64000L, 1000) ||
+ PNG_OUT_OF_RANGE(x_red, 64000, 1000) ||
PNG_OUT_OF_RANGE(y_red, 33000, 1000) ||
PNG_OUT_OF_RANGE(x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(y_green, 60000L, 1000) ||
+ PNG_OUT_OF_RANGE(y_green, 60000, 1000) ||
PNG_OUT_OF_RANGE(x_blue, 15000, 1000) ||
PNG_OUT_OF_RANGE(y_blue, 6000, 1000))
{
@@ -1022,27 +1022,80 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
/* Store the _white values as default coefficients for the rgb to gray
- * operation if it is supported.
+ * operation if it is supported. Check if the transform is already set to
+ * avoid destroying the transform values.
*/
- if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
+ if (!png_ptr->rgb_to_gray_coefficients_set)
{
- /* png_set_background has not been called, the coefficients must be in
- * range for the following to work without overflow.
+ /* png_set_background has not been called and we haven't seen an sRGB
+ * chunk yet. Find the XYZ of the three end points.
*/
- if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17))
+ png_XYZ XYZ;
+ png_xy xy;
+
+ xy.redx = x_red;
+ xy.redy = y_red;
+ xy.greenx = x_green;
+ xy.greeny = y_green;
+ xy.bluex = x_blue;
+ xy.bluey = y_blue;
+ xy.whitex = x_white;
+ xy.whitey = y_white;
+
+ if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy))
{
- /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray
- * transformation are simply the normalized Y values for red, green and
- * blue scaled by 32768.
+ /* The success case, because XYZ_from_xy normalises to a reference
+ * white Y of 1.0 we just need to scale the numbers. This should
+ * always work just fine. It is an internal error if this overflows.
*/
- png_uint_32 w = y_red + y_green + y_blue;
-
- png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red *
- 32768)/w);
- png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green
- * 32768)/w);
- png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue *
- 32768)/w);
+ {
+ png_fixed_point r, g, b;
+ if (png_muldiv(&r, XYZ.redY, 32768, PNG_FP_1) &&
+ r >= 0 && r <= 32768 &&
+ png_muldiv(&g, XYZ.greenY, 32768, PNG_FP_1) &&
+ g >= 0 && g <= 32768 &&
+ png_muldiv(&b, XYZ.blueY, 32768, PNG_FP_1) &&
+ b >= 0 && b <= 32768 &&
+ r+g+b <= 32769)
+ {
+ /* We allow 0 coefficients here. r+g+b may be 32769 if two or
+ * all of the coefficients were rounded up. Handle this by
+ * reducing the *largest* coefficient by 1; this matches the
+ * approach used for the default coefficients in pngrtran.c
+ */
+ int add = 0;
+
+ if (r+g+b > 32768)
+ add = -1;
+ else if (r+g+b < 32768)
+ add = 1;
+
+ if (add != 0)
+ {
+ if (g >= r && g >= b)
+ g += add;
+ else if (r >= g && r >= b)
+ r += add;
+ else
+ b += add;
+ }
+
+ /* Check for an internal error. */
+ if (r+g+b != 32768)
+ png_error(png_ptr,
+ "internal error handling cHRM coefficients");
+
+ png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
+ png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
+ }
+
+ /* This is a png_error at present even though it could be ignored -
+ * it should never happen, but it is important that if it does, the
+ * bug is fixed.
+ */
+ else
+ png_error(png_ptr, "internal error handling cHRM->XYZ");
+ }
}
}
#endif
@@ -1106,7 +1159,7 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
{
- if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
+ if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500, 500))
{
PNG_WARNING_PARAMETERS(p)
@@ -1123,10 +1176,10 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) ||
PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->x_red, 64000L, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->x_red, 64000, 1000) ||
PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) ||
PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->y_green, 60000, 1000) ||
PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) ||
PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000))
{
@@ -1135,6 +1188,47 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif /* PNG_READ_cHRM_SUPPORTED */
+ /* This is recorded for use when handling the cHRM chunk above. An sRGB
+ * chunk unconditionally overwrites the coefficients for grayscale conversion
+ * too.
+ */
+ png_ptr->is_sRGB = 1;
+
+# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+ /* Don't overwrite user supplied values: */
+ if (!png_ptr->rgb_to_gray_coefficients_set)
+ {
+ /* These numbers come from the sRGB specification (or, since one has to
+ * pay much money to get a copy, the wikipedia sRGB page) the
+ * chromaticity values quoted have been inverted to get the reverse
+ * transformation from RGB to XYZ and the 'Y' coefficients scaled by
+ * 32768 (then rounded).
+ *
+ * sRGB and ITU Rec-709 both truncate the values for the D65 white
+ * point to four digits and, even though it actually stores five
+ * digits, the PNG spec gives the truncated value.
+ *
+ * This means that when the chromaticities are converted back to XYZ
+ * end points we end up with (6968,23435,2366), which, as described in
+ * pngrtran.c, would overflow. If the five digit precision and up is
+ * used we get, instead:
+ *
+ * 6968*R + 23435*G + 2365*B
+ *
+ * (Notice that this rounds the blue coefficient down, rather than the
+ * choice used in pngrtran.c which is to round the green one down.)
+ */
+ png_ptr->rgb_to_gray_red_coeff = 6968; /* 0.212639005871510 */
+ png_ptr->rgb_to_gray_green_coeff = 23434; /* 0.715168678767756 */
+ /* png_ptr->rgb_to_gray_blue_coeff = 2366; 0.072192315360734 */
+
+ /* The following keeps the cHRM chunk from destroying the
+ * coefficients again in the event that it follows the sRGB chunk.
+ */
+ png_ptr->rgb_to_gray_coefficients_set = 1;
+ }
+# endif
+
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
}
#endif /* PNG_READ_sRGB_SUPPORTED */
diff --git a/pngset.c b/pngset.c
index 7eaad7dd4..373d21b28 100644
--- a/pngset.c
+++ b/pngset.c
@@ -1,7 +1,7 @@
/* pngset.c - storage of image information into info struct
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -64,6 +64,39 @@ png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
}
}
+void PNGFAPI
+png_set_cHRM_XYZ_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point int_red_X, png_fixed_point int_red_Y,
+ png_fixed_point int_red_Z, png_fixed_point int_green_X,
+ png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+ png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+ png_fixed_point int_blue_Z)
+{
+ png_XYZ XYZ;
+ png_xy xy;
+
+ png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ XYZ.redX = int_red_X;
+ XYZ.redY = int_red_Y;
+ XYZ.redZ = int_red_Z;
+ XYZ.greenX = int_green_X;
+ XYZ.greenY = int_green_Y;
+ XYZ.greenZ = int_green_Z;
+ XYZ.blueX = int_blue_X;
+ XYZ.blueY = int_blue_Y;
+ XYZ.blueZ = int_blue_Z;
+
+ if (png_xy_from_XYZ(&xy, XYZ))
+ png_error(png_ptr, "XYZ values out of representable range");
+
+ png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
+ xy.greenx, xy.greeny, xy.bluex, xy.bluey);
+}
+
# ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
@@ -80,6 +113,23 @@ png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
png_fixed(png_ptr, blue_x, "cHRM Blue X"),
png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
}
+
+void PNGAPI
+png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X,
+ double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
+ double blue_X, double blue_Y, double blue_Z)
+{
+ png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
+ png_fixed(png_ptr, red_X, "cHRM Red X"),
+ png_fixed(png_ptr, red_Y, "cHRM Red Y"),
+ png_fixed(png_ptr, red_Z, "cHRM Red Z"),
+ png_fixed(png_ptr, green_X, "cHRM Red X"),
+ png_fixed(png_ptr, green_Y, "cHRM Red Y"),
+ png_fixed(png_ptr, green_Z, "cHRM Red Z"),
+ png_fixed(png_ptr, blue_X, "cHRM Red X"),
+ png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
+ png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
+}
# endif /* PNG_FLOATING_POINT_SUPPORTED */
#endif /* PNG_cHRM_SUPPORTED */
@@ -99,7 +149,7 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
* possible for 1/gamma to overflow the limit of 21474 and this means the
* gamma value must be at least 5/100000 and hence at most 20000.0. For
* safety the limits here are a little narrower. The values are 0.00016 to
- * 6250.0, which are truely ridiculous gammma values (and will produce
+ * 6250.0, which are truly ridiculous gammma values (and will produce
* displays that are all black or all white.)
*/
if (file_gamma < 16 || file_gamma > 625000000)
@@ -552,10 +602,10 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
# ifdef PNG_cHRM_SUPPORTED
png_set_cHRM_fixed(png_ptr, info_ptr,
/* color x y */
- /* white */ 31270L, 32900L,
- /* red */ 64000L, 33000L,
- /* green */ 30000L, 60000L,
- /* blue */ 15000L, 6000L
+ /* white */ 31270, 32900,
+ /* red */ 64000, 33000,
+ /* green */ 30000, 60000,
+ /* blue */ 15000, 6000
);
# endif /* cHRM */
}
@@ -570,7 +620,7 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
{
png_charp new_iccp_name;
png_bytep new_iccp_profile;
- png_uint_32 length;
+ png_size_t length;
png_debug1(1, "in %s storage function", "iCCP");
@@ -916,10 +966,10 @@ png_set_sPLT(png_structp png_ptr,
{
png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
png_const_sPLT_tp from = entries + i;
- png_uint_32 length;
+ png_size_t length;
length = png_strlen(from->name) + 1;
- to->name = (png_charp)png_malloc_warn(png_ptr, (png_size_t)length);
+ to->name = (png_charp)png_malloc_warn(png_ptr, length);
if (to->name == NULL)
{
@@ -930,7 +980,7 @@ png_set_sPLT(png_structp png_ptr,
png_memcpy(to->name, from->name, length);
to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
- (png_size_t)(from->nentries * png_sizeof(png_sPLT_entry)));
+ from->nentries * png_sizeof(png_sPLT_entry));
if (to->entries == NULL)
{
diff --git a/pngstruct.h b/pngstruct.h
index 93b2b3eb0..b4e5f3b60 100644
--- a/pngstruct.h
+++ b/pngstruct.h
@@ -5,7 +5,7 @@
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@@ -255,13 +255,20 @@ struct png_struct_def
png_bytep chunk_list;
#endif
+#ifdef PNG_READ_sRGB_SUPPORTED
+ /* Added in 1.5.5 to record an sRGB chunk in the png. */
+ png_byte is_sRGB;
+#endif
+
/* New members added in libpng-1.0.3 */
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
png_byte rgb_to_gray_status;
+ /* Added in libpng 1.5.5 to record setting of coefficients: */
+ png_byte rgb_to_gray_coefficients_set;
/* These were changed from png_byte in libpng-1.0.6 */
png_uint_16 rgb_to_gray_red_coeff;
png_uint_16 rgb_to_gray_green_coeff;
- png_uint_16 rgb_to_gray_blue_coeff;
+ /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */
#endif
/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
diff --git a/pngtest.c b/pngtest.c
index 9084ada62..25531ce33 100644
--- a/pngtest.c
+++ b/pngtest.c
@@ -1794,4 +1794,4 @@ main(int argc, char *argv[])
}
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4;
+typedef png_libpng_version_1_5_5beta08 Your_png_h_is_not_version_1_5_5beta08;
diff --git a/pngvalid.c b/pngvalid.c
index 6d1736c15..9d1ce798c 100644
--- a/pngvalid.c
+++ b/pngvalid.c
@@ -1,7 +1,7 @@
/* pngvalid.c - validate libpng by constructing then reading png files.
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
+ * Last changed in libpng 1.5.5 [(PENDING RELEASE)]
* Copyright (c) 2011 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
@@ -53,8 +53,9 @@ typedef png_byte *png_const_bytep;
#define PNG_READ_16BIT_SUPPORTED
/* This comes from pnglibconf.h afer 1.5: */
+#define PNG_FP_1 100000
#define PNG_GAMMA_THRESHOLD_FIXED\
- ((png_fixed_point)(PNG_GAMMA_THRESHOLD * 100000))
+ ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1))
#endif
#include "zlib.h" /* For crc32 */
@@ -77,6 +78,15 @@ typedef png_byte *png_const_bytep;
/***************************** EXCEPTION HANDLING *****************************/
#include "contrib/visupng/cexcept.h"
+
+#ifdef __cplusplus
+# define this not_the_cpp_this
+# define new not_the_cpp_new
+# define voidcast(type, value) static_cast<type>(value)
+#else
+# define voidcast(type, value) (value)
+#endif /* __cplusplus */
+
struct png_store;
define_exception_type(struct png_store*);
@@ -129,10 +139,18 @@ static PNG_CONST char sep[] = ": ";
static PNG_CONST char *colour_types[8] =
{
- "greyscale", invalid, "truecolour", "indexed-colour",
- "greyscale with alpha", invalid, "truecolour with alpha", invalid
+ "grayscale", invalid, "truecolour", "indexed-colour",
+ "grayscale with alpha", invalid, "truecolour with alpha", invalid
};
+/* Convert a double precision value to fixed point. */
+static png_fixed_point
+fix(double d)
+{
+ d = floor(d * PNG_FP_1 + .5);
+ return (png_fixed_point)d;
+}
+
/* Generate random bytes. This uses a boring repeatable algorithm and it
* is implemented here so that it gives the same set of numbers on every
* architecture. It's a linear congruential generator (Knuth or Sedgewick
@@ -143,7 +161,7 @@ static void
make_random_bytes(png_uint_32* seed, void* pv, size_t size)
{
png_uint_32 u0 = seed[0], u1 = seed[1];
- png_bytep bytes = /*no cast required*/pv;
+ png_bytep bytes = voidcast(png_bytep, pv);
/* There are thirty three bits, the next bit in the sequence is bit-33 XOR
* bit-20. The top 1 bit is in u1, the bottom 32 are in u0.
@@ -179,6 +197,26 @@ randomize(void *pv, size_t size)
#define RANDOMIZE(this) randomize(&(this), sizeof (this))
+static unsigned int
+random_mod(unsigned int max)
+{
+ unsigned int x;
+
+ RANDOMIZE(x);
+
+ return x % max; /* 0 .. max-1 */
+}
+
+static int
+random_choice(void)
+{
+ unsigned char x;
+
+ RANDOMIZE(x);
+
+ return x & 1;
+}
+
/* 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
@@ -631,7 +669,7 @@ store_storenew(png_store *ps)
if (ps->writepos != STORE_BUFFER_SIZE)
png_error(ps->pwrite, "invalid store call");
- pb = malloc(sizeof *pb);
+ pb = voidcast(png_store_buffer*, malloc(sizeof *pb));
if (pb == NULL)
png_error(ps->pwrite, "store new: OOM");
@@ -667,7 +705,7 @@ store_freefile(png_store_file **ppf)
static void
store_storefile(png_store *ps, png_uint_32 id)
{
- png_store_file *pf = malloc(sizeof *pf);
+ png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf));
if (pf == NULL)
png_error(ps->pwrite, "storefile: OOM");
safecat(pf->name, sizeof pf->name, 0, ps->wname);
@@ -761,7 +799,7 @@ store_log(png_store* ps, png_structp pp, png_const_charp message, int is_error)
static void
store_error(png_structp pp, png_const_charp message) /* PNG_NORETURN */
{
- png_store *ps = png_get_error_ptr(pp);
+ png_store *ps = voidcast(png_store*, png_get_error_ptr(pp));
if (!ps->expect_error)
store_log(ps, pp, message, 1 /* error */);
@@ -776,7 +814,7 @@ store_error(png_structp pp, png_const_charp message) /* PNG_NORETURN */
static void
store_warning(png_structp pp, png_const_charp message)
{
- png_store *ps = png_get_error_ptr(pp);
+ png_store *ps = voidcast(png_store*, png_get_error_ptr(pp));
if (!ps->expect_warning)
store_log(ps, pp, message, 0 /* warning */);
@@ -838,7 +876,7 @@ store_ensure_image(png_store *ps, png_structp pp, int nImages, png_size_t cbRow,
store_image_free(ps, pp);
/* The buffer is deliberately mis-aligned. */
- image = malloc(cb+2);
+ image = voidcast(png_bytep, malloc(cb+2));
if (image == NULL)
{
/* Called from the startup - ignore the error for the moment. */
@@ -922,7 +960,7 @@ store_image_check(PNG_CONST png_store* ps, png_structp pp, int iImage)
static void
store_write(png_structp pp, png_bytep pb, png_size_t st)
{
- png_store *ps = png_get_io_ptr(pp);
+ png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
if (ps->pwrite != pp)
png_error(pp, "store state damaged");
@@ -1042,7 +1080,7 @@ store_read_imp(png_store *ps, png_bytep pb, png_size_t st)
static void
store_read(png_structp pp, png_bytep pb, png_size_t st)
{
- png_store *ps = png_get_io_ptr(pp);
+ png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
if (ps == NULL || ps->pread != pp)
png_error(pp, "bad store read call");
@@ -1082,7 +1120,8 @@ store_write_palette(png_store *ps, int npalette)
/* This function can only return NULL if called with '0'! */
if (npalette > 0)
{
- ps->palette = malloc(npalette * sizeof *ps->palette);
+ ps->palette = voidcast(store_palette_entry*, malloc(npalette *
+ sizeof *ps->palette));
if (ps->palette == NULL)
png_error(ps->pwrite, "store new palette: OOM");
@@ -1229,8 +1268,9 @@ store_pool_delete(png_store *ps, store_pool *pool)
static png_voidp
store_malloc(png_structp pp, png_alloc_size_t cb)
{
- store_pool *pool = png_get_mem_ptr(pp);
- store_memory *new = malloc(cb + (sizeof *new) + (sizeof pool->mark));
+ store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp));
+ store_memory *new = voidcast(store_memory*, malloc(cb + (sizeof *new) +
+ (sizeof pool->mark)));
if (new != NULL)
{
@@ -1262,8 +1302,8 @@ store_malloc(png_structp pp, png_alloc_size_t cb)
static void
store_free(png_structp pp, png_voidp memory)
{
- store_pool *pool = png_get_mem_ptr(pp);
- store_memory *this = memory, **test;
+ store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp));
+ store_memory *this = voidcast(store_memory*, memory), **test;
/* First check that this 'memory' really is valid memory - it must be in the
* pool list. If it is, use the shared memory_free function to free it.
@@ -1483,17 +1523,125 @@ store_delete(png_store *ps)
* png_store. There is a special read function, set_modifier_for_read, which
* replaces set_store_for_read.
*/
+typedef enum modifier_state
+{
+ modifier_start, /* Initial value */
+ modifier_signature, /* Have a signature */
+ modifier_IHDR /* Have an IHDR */
+} modifier_state;
+
+typedef struct CIE_color
+{
+ /* A single CIE tristimulus value, representing the unique response of a
+ * standard observer to a variety of light spectra. The observer recognizes
+ * all spectra that produce this response as the same color, therefore this
+ * is effectively a description of a color.
+ */
+ double X, Y, Z;
+} CIE_color;
+
+static double
+chromaticity_x(CIE_color c)
+{
+ return c.X / (c.X + c.Y + c.Z);
+}
+
+static double
+chromaticity_y(CIE_color c)
+{
+ return c.Y / (c.X + c.Y + c.Z);
+}
+
+typedef struct color_encoding
+{
+ /* A description of an (R,G,B) encoding of color (as defined above); this
+ * includes the actual colors of the (R,G,B) triples (1,0,0), (0,1,0) and
+ * (0,0,1) plus an encoding value that is used to encode the linear
+ * components R, G and B to give the actual values R^gamma, G^gamma and
+ * B^gamma that are stored.
+ */
+ double gamma; /* Encoding (file) gamma of space */
+ CIE_color red, green, blue; /* End points */
+} color_encoding;
+
+static CIE_color
+white_point(PNG_CONST color_encoding *encoding)
+{
+ CIE_color white;
+
+ white.X = encoding->red.X + encoding->green.X + encoding->blue.X;
+ white.Y = encoding->red.Y + encoding->green.Y + encoding->blue.Y;
+ white.Z = encoding->red.Z + encoding->green.Z + encoding->blue.Z;
+
+ return white;
+}
+
+static void
+normalize_color_encoding(color_encoding *encoding)
+{
+ PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y +
+ encoding->blue.Y;
+
+ if (whiteY != 1)
+ {
+ encoding->red.X /= whiteY;
+ encoding->red.Y /= whiteY;
+ encoding->red.Z /= whiteY;
+ encoding->green.X /= whiteY;
+ encoding->green.Y /= whiteY;
+ encoding->green.Z /= whiteY;
+ encoding->blue.X /= whiteY;
+ encoding->blue.Y /= whiteY;
+ encoding->blue.Z /= whiteY;
+ }
+}
+
+static size_t
+safecat_color_encoding(char *buffer, size_t bufsize, size_t pos,
+ PNG_CONST color_encoding *e, double encoding_gamma)
+{
+ if (e != 0)
+ {
+ if (encoding_gamma != 0)
+ pos = safecat(buffer, bufsize, pos, "(");
+ pos = safecat(buffer, bufsize, pos, "R(");
+ pos = safecatd(buffer, bufsize, pos, e->red.X, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->red.Y, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->red.Z, 4);
+ pos = safecat(buffer, bufsize, pos, "),G(");
+ pos = safecatd(buffer, bufsize, pos, e->green.X, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->green.Y, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->green.Z, 4);
+ pos = safecat(buffer, bufsize, pos, "),B(");
+ pos = safecatd(buffer, bufsize, pos, e->blue.X, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->blue.Y, 4);
+ pos = safecat(buffer, bufsize, pos, ",");
+ pos = safecatd(buffer, bufsize, pos, e->blue.Z, 4);
+ pos = safecat(buffer, bufsize, pos, ")");
+ if (encoding_gamma != 0)
+ pos = safecat(buffer, bufsize, pos, ")");
+ }
+
+ if (encoding_gamma != 0)
+ {
+ pos = safecat(buffer, bufsize, pos, "^");
+ pos = safecatd(buffer, bufsize, pos, encoding_gamma, 5);
+ }
+
+ return pos;
+}
+
typedef struct png_modifier
{
png_store this; /* I am a png_store */
struct png_modification *modifications; /* Changes to make */
- enum modifier_state
- {
- modifier_start, /* Initial value */
- modifier_signature, /* Have a signature */
- modifier_IHDR /* Have an IHDR */
- } state; /* My state */
+ modifier_state state; /* My state */
/* Information from IHDR: */
png_byte bit_depth; /* From IHDR */
@@ -1506,8 +1654,22 @@ typedef struct png_modifier
png_uint_32 pending_chunk;
/* Test values */
- double *gammas;
- unsigned int ngammas;
+ double *gammas;
+ 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;
+ unsigned int nencodings;
+ PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */
+ unsigned int encoding_counter; /* For iteration */
+ int encoding_ignored; /* Something overwrote it */
+
+ /* Control variables used to iterate through possible encodings, the
+ * following must be set to 0 and tested by the function that uses the
+ * png_modifier because the modifier only sets it to 1 (true.)
+ */
+ unsigned int repeat :1; /* Repeat this transform test. */
+ unsigned int test_uses_encoding :1;
/* Lowest sbit to test (libpng fails for sbit < 8) */
png_byte sbitlow;
@@ -1524,6 +1686,13 @@ typedef struct png_modifier
double maxcalc16;/* Absolute sample error 0..1 */
double maxpc16; /* Percentage sample error 0..100% */
+ /* This is set by transforms that need to allow a higher limit, it is an
+ * internal check on pngvalid to ensure that the calculated error limits are
+ * not ridiculous; without this it is too easy to make a mistake in pngvalid
+ * that allows any value through.
+ */
+ double limit; /* limit on error values, normally 4E-3 */
+
/* Log limits - values above this are logged, but not necessarily
* warned.
*/
@@ -1575,6 +1744,7 @@ typedef struct png_modifier
unsigned int test_gamma_background :1;
unsigned int test_gamma_alpha_mode :1;
unsigned int test_gamma_expand16 :1;
+ unsigned int test_exhaustive :1;
unsigned int log :1; /* Log max error */
@@ -1605,9 +1775,19 @@ modifier_init(png_modifier *pm)
pm->state = modifier_start;
pm->sbitlow = 1U;
pm->ngammas = 0;
+ pm->ngamma_tests = 0;
pm->gammas = 0;
+ pm->current_gamma = 0;
+ pm->encodings = 0;
+ pm->nencodings = 0;
+ pm->current_encoding = 0;
+ pm->encoding_counter = 0;
+ pm->encoding_ignored = 0;
+ pm->repeat = 0;
+ pm->test_uses_encoding = 0;
pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0;
pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0;
+ pm->limit = 4E-3;
pm->log8 = pm->log16 = 0; /* Means 'off' */
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0;
@@ -1627,6 +1807,7 @@ modifier_init(png_modifier *pm)
pm->test_gamma_background = 0;
pm->test_gamma_alpha_mode = 0;
pm->test_gamma_expand16 = 0;
+ pm->test_exhaustive = 0;
pm->log = 0;
/* Rely on the memset for all the other fields - there are no pointers */
@@ -1638,9 +1819,35 @@ modifier_init(png_modifier *pm)
*
* If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16
* bit precision. This only affects those of the following limits that pertain
- * to a calculation - not a digitization operation!
+ * to a calculation - not a digitization operation - unless the following API is
+ * called directly.
*/
-static double abserr(png_modifier *pm, int in_depth, int out_depth)
+static double digitize(PNG_CONST png_modifier *pm, double value,
+ int sample_depth, int do_round)
+{
+ /* 'value' is in the range 0 to 1, the result is the same value rounded to a
+ * multiple of the digitization factor - 8 or 16 bits depending on both the
+ * sample depth and the 'assume' setting. Digitization is normally by
+ * rounding and 'do_round' should be 1, if it is 0 the digitized value will
+ * be truncated.
+ */
+ PNG_CONST unsigned int digitization_factor =
+ (pm->assume_16_bit_calculations || sample_depth == 16) ? 65535 : 255;
+
+ /* 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.
+ */
+ if (value <= 0)
+ value = 0;
+ else if (value >= 1)
+ value = 1;
+
+ value *= digitization_factor;
+ if (do_round) value += .5;
+ return floor(value)/digitization_factor;
+}
+
+static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
{
/* Absolute error permitted in linear values - affected by the bit depth of
* the calculations.
@@ -1652,7 +1859,7 @@ static double abserr(png_modifier *pm, int in_depth, int out_depth)
return pm->maxabs8;
}
-static double calcerr(png_modifier *pm, int in_depth, int out_depth)
+static double calcerr(PNG_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).
@@ -1664,7 +1871,7 @@ static double calcerr(png_modifier *pm, int in_depth, int out_depth)
return pm->maxcalc8;
}
-static double pcerr(png_modifier *pm, int in_depth, int out_depth)
+static double pcerr(PNG_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.
@@ -1687,11 +1894,11 @@ static double pcerr(png_modifier *pm, int in_depth, int out_depth)
* The specified parameter does *not* include the base .5 digitization error but
* it is added here.
*/
-static double outerr(png_modifier *pm, int in_depth, int out_depth)
+static double outerr(PNG_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
- * error in 4 bit greyscale gamma is up to the value below. This is a hack
+ * error in 4 bit grayscale gamma is up to the value below. This is a hack
* to allow pngvalid to succeed:
*
* TODO: fix this in libpng
@@ -1720,7 +1927,7 @@ static double outerr(png_modifier *pm, int in_depth, int out_depth)
* rather than raising a warning. This is useful for debugging to track down
* exactly what set of parameters cause high error values.
*/
-static double outlog(png_modifier *pm, int in_depth, int out_depth)
+static double outlog(PNG_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:
@@ -1759,7 +1966,7 @@ static double outlog(png_modifier *pm, int in_depth, int out_depth)
* but in the 8 bit calculation case it's actually quantization to a multiple of
* 257!
*/
-static int output_quantization_factor(png_modifier *pm, int in_depth,
+static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth,
int out_depth)
{
if (out_depth == 16 && in_depth != 16
@@ -1797,7 +2004,8 @@ typedef struct png_modification
unsigned int removed :1; /* Chunk was removed */
} png_modification;
-static void modification_reset(png_modification *pmm)
+static void
+modification_reset(png_modification *pmm)
{
if (pmm != NULL)
{
@@ -1820,14 +2028,174 @@ modification_init(png_modification *pmm)
}
static void
+modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce)
+{
+ if (pm->current_encoding != 0)
+ *ce = *pm->current_encoding;
+
+ else
+ memset(ce, 0, sizeof *ce);
+
+ ce->gamma = pm->current_gamma;
+}
+
+static size_t
+safecat_current_encoding(char *buffer, size_t bufsize, size_t pos,
+ PNG_CONST png_modifier *pm)
+{
+ pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding,
+ pm->current_gamma);
+
+ if (pm->encoding_ignored)
+ pos = safecat(buffer, bufsize, pos, "[overridden]");
+
+ return pos;
+}
+
+/* Iterate through the usefully testable color encodings. An encoding is one
+ * of:
+ *
+ * 1) Nothing (no color space, no gamma).
+ * 2) Just a gamma value from the gamma array (including 1.0)
+ * 3) A color space from the encodings array with the corresponding gamma.
+ * 4) The same, but with gamma 1.0 (only really useful with 16 bit calculations)
+ *
+ * The iterator selects these in turn, the randomizer selects one at random,
+ * which is used depends on the setting of the 'test_exhaustive' flag. Notice
+ * that this function changes the colour space encoding so it must only be
+ * called on completion of the previous test. This is what 'modifier_reset'
+ * does, below.
+ *
+ * After the function has been called the 'repeat' flag will still be set; the
+ * 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)
+{
+ return 1 + /* (1) nothing */
+ pm->ngammas + /* (2) gamma values to test */
+ pm->nencodings + /* (3) total number of encodings */
+ /* The following test only works after the first time through the
+ * png_modifier code because 'bit_depth' is set when the IHDR is read.
+ * modifier_reset, below, preserves the setting until after it has called
+ * the iterate function (also below.)
+ *
+ * For this reason do not rely on this function outside a call to
+ * modifier_reset.
+ */
+ ((pm->bit_depth == 16 || pm->assume_16_bit_calculations) ?
+ pm->nencodings : 0); /* (4) encodings with gamma == 1.0 */
+}
+
+static void
+modifier_encoding_iterate(png_modifier *pm)
+{
+ if (!pm->repeat && /* Else something needs the current encoding again. */
+ pm->test_uses_encoding) /* Some transform is encoding dependent */
+ {
+ if (pm->test_exhaustive)
+ {
+ if (++pm->encoding_counter >= modifier_total_encodings(pm))
+ pm->encoding_counter = 0; /* This will stop the repeat */
+ }
+
+ else
+ {
+ /* Not exhaustive - choose an encoding at random; generate a number in
+ * the range 1..(max-1), so the result is always non-zero:
+ */
+ if (pm->encoding_counter == 0)
+ pm->encoding_counter = random_mod(modifier_total_encodings(pm)-1)+1;
+ else
+ pm->encoding_counter = 0;
+ }
+
+ if (pm->encoding_counter > 0)
+ pm->repeat = 1;
+ }
+
+ else if (!pm->repeat)
+ pm->encoding_counter = 0;
+}
+
+static void
modifier_reset(png_modifier *pm)
{
store_read_reset(&pm->this);
+ pm->limit = 4E-3;
+ pm->pending_len = pm->pending_chunk = 0;
+ pm->flush = pm->buffer_count = pm->buffer_position = 0;
pm->modifications = NULL;
pm->state = modifier_start;
+ modifier_encoding_iterate(pm);
+ /* The following must be set in the next run. In particular
+ * test_uses_encodings must be set in the _ini function of each transform
+ * that looks at the encodings. (Not the 'add' function!)
+ */
+ pm->test_uses_encoding = 0;
+ pm->current_gamma = 0;
+ pm->current_encoding = 0;
+ pm->encoding_ignored = 0;
+ /* These only become value after IHDR is read: */
pm->bit_depth = pm->colour_type = 0;
- pm->pending_len = pm->pending_chunk = 0;
- pm->flush = pm->buffer_count = pm->buffer_position = 0;
+}
+
+/* The following must be called before anything else to get the encoding set up
+ * on the modifier. In particular it must be called before the transform init
+ * functions are called.
+ */
+static void
+modifier_set_encoding(png_modifier *pm)
+{
+ /* Set the encoding to the one specified by the current encoding counter,
+ * first clear out all the settings - this corresponds to an encoding_counter
+ * of 0.
+ */
+ pm->current_gamma = 0;
+ pm->current_encoding = 0;
+ pm->encoding_ignored = 0; /* not ignored yet - happens in _ini functions. */
+
+ /* Now, if required, set the gamma and encoding fields. */
+ if (pm->encoding_counter > 0)
+ {
+ /* The gammas[] array is an array of screen gammas, not encoding gammas,
+ * so we need the inverse:
+ */
+ if (pm->encoding_counter <= pm->ngammas)
+ pm->current_gamma = 1/pm->gammas[pm->encoding_counter-1];
+
+ else
+ {
+ unsigned int i = pm->encoding_counter - pm->ngammas;
+
+ if (i >= pm->nencodings)
+ {
+ i %= pm->nencodings;
+ pm->current_gamma = 1; /* Linear, only in the 16 bit case */
+ }
+
+ else
+ pm->current_gamma = pm->encodings[i].gamma;
+
+ pm->current_encoding = pm->encodings + i;
+ }
+ }
+}
+
+/* Enquiry functions to find out what is set. Notice that there is an implicit
+ * 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)
+{
+ 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)
+{
+ return pm->current_gamma != 0;
}
/* Convenience macros. */
@@ -1849,7 +2217,10 @@ modifier_crc(png_bytep buffer)
* the buffer, at the start.
*/
uInt datalen = png_get_uint_32(buffer);
- png_save_uint_32(buffer+datalen+8, crc32(0L, buffer+4, datalen+4));
+ uLong crc = crc32(0, buffer+4, datalen+4);
+ /* The cast to png_uint_32 is safe because a crc32 is always a 32 bit value.
+ */
+ png_save_uint_32(buffer+datalen+8, (png_uint_32)crc);
}
static void
@@ -2072,7 +2443,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
static void
modifier_read(png_structp pp, png_bytep pb, png_size_t st)
{
- png_modifier *pm = png_get_io_ptr(pp);
+ png_modifier *pm = voidcast(png_modifier*, png_get_io_ptr(pp));
if (pm == NULL || pm->this.pread != pp)
png_error(pp, "bad modifier_read call");
@@ -2091,7 +2462,7 @@ modifier_progressive_read(png_modifier *pm, png_structp pp, png_infop pi)
png_error(pp, "store state damaged (progressive)");
/* This is another Horowitz and Hill random noise generator. In this case
- * the aim is to stress the progressive reader with truely horrible variable
+ * the aim is to stress the progressive reader with truly horrible variable
* buffer sizes in the range 1..500, so a sequence of 9 bit random numbers
* is generated. We could probably just count from 1 to 32767 and get as
* good a result.
@@ -2158,6 +2529,205 @@ set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id,
return set_store_for_read(&pm->this, ppi, id, name);
}
+
+
+/******************************** MODIFICATIONS *******************************/
+/* Standard modifications to add chunks. These do not require the _SUPPORTED
+ * macros because the chunks can be there regardless of whether this specific
+ * libpng supports them.
+ */
+typedef struct gama_modification
+{
+ png_modification this;
+ png_fixed_point gamma;
+} gama_modification;
+
+static int
+gama_modify(png_modifier *pm, png_modification *me, int add)
+{
+ UNUSED(add)
+ /* This simply dumps the given gamma value into the buffer. */
+ png_save_uint_32(pm->buffer, 4);
+ png_save_uint_32(pm->buffer+4, CHUNK_gAMA);
+ png_save_uint_32(pm->buffer+8, ((gama_modification*)me)->gamma);
+ return 1;
+}
+
+static void
+gama_modification_init(gama_modification *me, png_modifier *pm, double gammad)
+{
+ double g;
+
+ modification_init(&me->this);
+ me->this.chunk = CHUNK_gAMA;
+ me->this.modify_fn = gama_modify;
+ me->this.add = CHUNK_PLTE;
+ g = fix(gammad);
+ me->gamma = (png_fixed_point)g;
+ me->this.next = pm->modifications;
+ pm->modifications = &me->this;
+}
+
+typedef struct chrm_modification
+{
+ png_modification this;
+ PNG_CONST color_encoding *encoding;
+ png_fixed_point wx, wy, rx, ry, gx, gy, bx, by;
+} chrm_modification;
+
+static int
+chrm_modify(png_modifier *pm, png_modification *me, int add)
+{
+ UNUSED(add)
+ /* As with gAMA this just adds the required cHRM chunk to the buffer. */
+ png_save_uint_32(pm->buffer , 32);
+ png_save_uint_32(pm->buffer+ 4, CHUNK_cHRM);
+ png_save_uint_32(pm->buffer+ 8, ((chrm_modification*)me)->wx);
+ png_save_uint_32(pm->buffer+12, ((chrm_modification*)me)->wy);
+ png_save_uint_32(pm->buffer+16, ((chrm_modification*)me)->rx);
+ png_save_uint_32(pm->buffer+20, ((chrm_modification*)me)->ry);
+ png_save_uint_32(pm->buffer+24, ((chrm_modification*)me)->gx);
+ png_save_uint_32(pm->buffer+28, ((chrm_modification*)me)->gy);
+ png_save_uint_32(pm->buffer+32, ((chrm_modification*)me)->bx);
+ png_save_uint_32(pm->buffer+36, ((chrm_modification*)me)->by);
+ return 1;
+}
+
+static void
+chrm_modification_init(chrm_modification *me, png_modifier *pm,
+ PNG_CONST color_encoding *encoding)
+{
+ CIE_color white = white_point(encoding);
+
+ /* Original end points: */
+ me->encoding = encoding;
+
+ /* Chromaticities (in fixed point): */
+ me->wx = fix(chromaticity_x(white));
+ me->wy = fix(chromaticity_y(white));
+
+ me->rx = fix(chromaticity_x(encoding->red));
+ me->ry = fix(chromaticity_y(encoding->red));
+ me->gx = fix(chromaticity_x(encoding->green));
+ me->gy = fix(chromaticity_y(encoding->green));
+ me->bx = fix(chromaticity_x(encoding->blue));
+ me->by = fix(chromaticity_y(encoding->blue));
+
+ modification_init(&me->this);
+ me->this.chunk = CHUNK_cHRM;
+ me->this.modify_fn = chrm_modify;
+ me->this.add = CHUNK_PLTE;
+ me->this.next = pm->modifications;
+ pm->modifications = &me->this;
+}
+
+typedef struct srgb_modification
+{
+ png_modification this;
+ png_byte intent;
+} srgb_modification;
+
+static int
+srgb_modify(png_modifier *pm, png_modification *me, int add)
+{
+ UNUSED(add)
+ /* As above, ignore add and just make a new chunk */
+ png_save_uint_32(pm->buffer, 1);
+ png_save_uint_32(pm->buffer+4, CHUNK_sRGB);
+ pm->buffer[8] = ((srgb_modification*)me)->intent;
+ return 1;
+}
+
+static void
+srgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent)
+{
+ modification_init(&me->this);
+ me->this.chunk = CHUNK_sBIT;
+
+ if (intent <= 3) /* if valid, else *delete* sRGB chunks */
+ {
+ me->this.modify_fn = srgb_modify;
+ me->this.add = CHUNK_PLTE;
+ me->intent = intent;
+ }
+
+ else
+ {
+ me->this.modify_fn = 0;
+ me->this.add = 0;
+ me->intent = 0;
+ }
+
+ me->this.next = pm->modifications;
+ pm->modifications = &me->this;
+}
+
+typedef struct sbit_modification
+{
+ png_modification this;
+ png_byte sbit;
+} sbit_modification;
+
+static int
+sbit_modify(png_modifier *pm, png_modification *me, int add)
+{
+ png_byte sbit = ((sbit_modification*)me)->sbit;
+ if (pm->bit_depth > sbit)
+ {
+ int cb = 0;
+ switch (pm->colour_type)
+ {
+ case 0:
+ cb = 1;
+ break;
+
+ case 2:
+ case 3:
+ cb = 3;
+ break;
+
+ case 4:
+ cb = 2;
+ break;
+
+ case 6:
+ cb = 4;
+ break;
+
+ default:
+ png_error(pm->this.pread,
+ "unexpected colour type in sBIT modification");
+ }
+
+ png_save_uint_32(pm->buffer, cb);
+ png_save_uint_32(pm->buffer+4, CHUNK_sBIT);
+
+ while (cb > 0)
+ (pm->buffer+8)[--cb] = sbit;
+
+ return 1;
+ }
+ else if (!add)
+ {
+ /* Remove the sBIT chunk */
+ pm->buffer_count = pm->buffer_position = 0;
+ return 1;
+ }
+ else
+ return 0; /* do nothing */
+}
+
+static void
+sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit)
+{
+ modification_init(&me->this);
+ me->this.chunk = CHUNK_sBIT;
+ me->this.modify_fn = sbit_modify;
+ me->this.add = CHUNK_PLTE;
+ me->sbit = sbit;
+ me->this.next = pm->modifications;
+ pm->modifications = &me->this;
+}
#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
/***************************** STANDARD PNG FILES *****************************/
@@ -2224,7 +2794,7 @@ make_standard_palette(png_store* ps, int npalette, int do_tRNS)
values[i][3] = (i&4) ? 255 : 0;
}
- /* Then add 62 greys (one quarter of the remaining 256 slots). */
+ /* Then add 62 grays (one quarter of the remaining 256 slots). */
{
int j = 0;
png_byte random_bytes[4];
@@ -2255,7 +2825,7 @@ make_standard_palette(png_store* ps, int npalette, int do_tRNS)
}
/* Finally add 192 colors at random - don't worry about matches to things we
- * already have, chance is less than 1/65536. Don't worry about greys,
+ * already have, chance is less than 1/65536. Don't worry about grays,
* chance is the same, so we get a duplicate or extra gray less than 1 time
* in 170.
*/
@@ -3323,6 +3893,8 @@ static void
standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id,
int do_interlace)
{
+ memset(dp, 0, sizeof *dp);
+
dp->ps = ps;
dp->colour_type = COL_FROM_ID(id);
dp->bit_depth = DEPTH_FROM_ID(id);
@@ -3429,8 +4001,8 @@ read_palette(store_palette palette, int *npalette, png_structp pp, png_infop pi)
if ((png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS) != 0 &&
(trans_alpha != NULL || num != 1/*returns 1 for a transparent color*/) &&
/* Oops, if a palette tRNS gets expanded png_read_update_info (at least so
- * far as 1.5.4) does not zap the trans_alpha pointer, only num_trans, so
- * in the above call we get a success, we get a pointer (who knows what
+ * far as 1.5.4) does not remove the trans_alpha pointer, only num_trans,
+ * so in the above call we get a success, we get a pointer (who knows what
* to) and we get num_trans == 0:
*/
!(trans_alpha != NULL && num == 0)) /* TODO: fix this in libpng. */
@@ -3711,7 +4283,8 @@ standard_info_imp(standard_display *dp, png_structp pp, png_infop pi,
static void
standard_info(png_structp pp, png_infop pi)
{
- standard_display *dp = png_get_progressive_ptr(pp);
+ standard_display *dp = voidcast(standard_display*,
+ png_get_progressive_ptr(pp));
/* Call with nImages==1 because the progressive reader can only produce one
* image.
@@ -3722,7 +4295,8 @@ standard_info(png_structp pp, png_infop pi)
static void
progressive_row(png_structp pp, png_bytep new_row, png_uint_32 y, int pass)
{
- PNG_CONST standard_display *dp = png_get_progressive_ptr(pp);
+ PNG_CONST standard_display *dp = voidcast(standard_display*,
+ png_get_progressive_ptr(pp));
/* When handling interlacing some rows will be absent in each pass, the
* callback still gets called, but with a NULL pointer. This is checked
@@ -3897,7 +4471,8 @@ standard_image_validate(standard_display *dp, png_structp pp, int iImage,
static void
standard_end(png_structp pp, png_infop pi)
{
- standard_display *dp = png_get_progressive_ptr(pp);
+ standard_display *dp = voidcast(standard_display*,
+ png_get_progressive_ptr(pp));
UNUSED(pi)
@@ -4119,7 +4694,7 @@ perform_size_test(png_modifier *pm)
return;
/* For the moment don't do the palette test - it's a waste of time when
- * compared to the greyscale test.
+ * compared to the grayscale test.
*/
#if 0
if (!test_size(pm, 3, 0, 3))
@@ -4290,7 +4865,7 @@ image_pixel_convert_PLTE(image_pixel *this)
* least 8. Palette images will be converted to alpha (using the above API).
*/
static void
-image_pixel_add_alpha(image_pixel *this, const standard_display *display)
+image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display)
{
if (this->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(this);
@@ -4376,7 +4951,13 @@ typedef struct image_transform
/* A single transform for the image, expressed as a series of function
* callbacks and some space for values.
*
- * First a callback to set the transform on the current png_read_struct:
+ * 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,
+ 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,
struct transform_display *that, png_structp pp, png_infop pi);
@@ -4412,12 +4993,48 @@ typedef struct transform_display
png_byte output_colour_type;
png_byte output_bit_depth;
- /* Variables for the individual transforms. */
- /* png_set_background */
- image_pixel background_colour;
+ /* Modifications (not necessarily used.) */
+ gama_modification gama_mod;
+ chrm_modification chrm_mod;
+ srgb_modification srgb_mod;
} transform_display;
-/* Two functions to end the list: */
+/* Set sRGB, cHRM and gAMA transforms as required by the current encoding. */
+static void
+transform_set_encoding(transform_display *this)
+{
+ /* Set up the png_modifier '_current' fields then use these to determine how
+ * to add appropriate chunks.
+ */
+ png_modifier *pm = this->pm;
+
+ modifier_set_encoding(pm);
+
+ if (modifier_color_encoding_is_set(pm))
+ {
+ if (modifier_color_encoding_is_sRGB(pm))
+ srgb_modification_init(&this->srgb_mod, pm, PNG_sRGB_INTENT_ABSOLUTE);
+
+ else
+ {
+ /* Set gAMA and cHRM separately. */
+ gama_modification_init(&this->gama_mod, pm, pm->current_gamma);
+
+ if (pm->current_encoding != 0)
+ chrm_modification_init(&this->chrm_mod, pm, pm->current_encoding);
+ }
+ }
+}
+
+/* Three functions to end the list: */
+static void
+image_transform_ini_end(PNG_CONST image_transform *this,
+ transform_display *that)
+{
+ UNUSED(this)
+ UNUSED(that)
+}
+
static void
image_transform_set_end(PNG_CONST image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
@@ -4513,6 +5130,7 @@ static image_transform image_transform_end =
0, /* global_use */
0, /* local_use */
0, /* next */
+ image_transform_ini_end,
image_transform_set_end,
image_transform_mod_end,
0 /* never called, I want it to crash if it is! */
@@ -4525,6 +5143,8 @@ static void
transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id,
PNG_CONST image_transform *transform_list)
{
+ memset(dp, 0, sizeof dp);
+
/* Standard fields */
standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/);
@@ -4657,25 +5277,26 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi)
static void
transform_info(png_structp pp, png_infop pi)
{
- transform_info_imp(png_get_progressive_ptr(pp), pp, pi);
+ transform_info_imp(voidcast(transform_display*, png_get_progressive_ptr(pp)),
+ pp, pi);
}
static void
transform_range_check(png_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, PNG_CONST char *name,
- double digitization_error)
+ unsigned int out, png_byte sample_depth, double err, double limit,
+ PNG_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
* digitization depth of the libpng output colors (the bit depth except for
* palette images where it is always 8.) The check on 'err' is to detect
- * internal errors in pngvalid itself (the threshold is about 1/255.)
+ * internal errors in pngvalid itself.
*/
unsigned int max = (1U<<sample_depth)-1;
double in_min = ceil((in-err)*max - digitization_error);
double in_max = floor((in+err)*max + digitization_error);
- if (err > 4E-3 || !(out >= in_min && out <= in_max))
+ if (err > limit || !(out >= in_min && out <= in_max))
{
char message[256];
size_t pos;
@@ -4830,26 +5451,30 @@ transform_image_validate(transform_display *dp, png_structp pp, png_infop pi)
*/
if (in_pixel.red != out_pixel.red)
transform_range_check(pp, r, g, b, a, in_pixel.red, in_pixel.redf,
- out_pixel.red, sample_depth, in_pixel.rede, "red/gray",
+ out_pixel.red, sample_depth, in_pixel.rede,
+ dp->pm->limit + 1./(2*((1U<<in_pixel.red_sBIT)-1)), "red/gray",
digitization_error);
if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 &&
in_pixel.green != out_pixel.green)
transform_range_check(pp, r, g, b, a, in_pixel.green,
in_pixel.greenf, out_pixel.green, sample_depth, in_pixel.greene,
- "green", digitization_error);
+ dp->pm->limit + 1./(2*((1U<<in_pixel.green_sBIT)-1)), "green",
+ digitization_error);
if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 &&
in_pixel.blue != out_pixel.blue)
transform_range_check(pp, r, g, b, a, in_pixel.blue, in_pixel.bluef,
- out_pixel.blue, sample_depth, in_pixel.bluee, "blue",
+ out_pixel.blue, sample_depth, in_pixel.bluee,
+ dp->pm->limit + 1./(2*((1U<<in_pixel.blue_sBIT)-1)), "blue",
digitization_error);
if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0 &&
in_pixel.alpha != out_pixel.alpha)
transform_range_check(pp, r, g, b, a, in_pixel.alpha,
in_pixel.alphaf, out_pixel.alpha, sample_depth, in_pixel.alphae,
- "alpha", digitization_error);
+ dp->pm->limit + 1./(2*((1U<<in_pixel.alpha_sBIT)-1)), "alpha",
+ digitization_error);
} /* pixel (x) loop */
} /* row (y) loop */
@@ -4860,7 +5485,8 @@ transform_image_validate(transform_display *dp, png_structp pp, png_infop pi)
static void
transform_end(png_structp pp, png_infop pi)
{
- transform_display *dp = png_get_progressive_ptr(pp);
+ transform_display *dp = voidcast(transform_display*,
+ png_get_progressive_ptr(pp));
transform_image_validate(dp, pp, pi);
}
@@ -4868,7 +5494,7 @@ transform_end(png_structp pp, png_infop pi)
/* A single test run. */
static void
transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
- PNG_CONST image_transform* transform_listIn, PNG_CONST char *name)
+ PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name)
{
transform_display d;
context(&pmIn->this, fault);
@@ -4877,11 +5503,25 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
Try
{
+ size_t pos = 0;
png_structp pp;
png_infop pi;
+ char full_name[256];
+
+ /* Make sure the encoding fields are correct and enter the required
+ * modifications.
+ */
+ transform_set_encoding(&d);
+
+ /* Add any modifications required by the transform list. */
+ d.transform_list->ini(d.transform_list, &d);
+
+ /* Add the color space information, if any, to the name. */
+ pos = safecat(full_name, sizeof full_name, pos, name);
+ pos = safecat_current_encoding(full_name, sizeof full_name, pos, d.pm);
/* Get a png_struct for reading the image. */
- pp = set_modifier_for_read(d.pm, &pi, d.this.id, name);
+ pp = set_modifier_for_read(d.pm, &pi, d.this.id, full_name);
standard_palette_init(&d.this);
# if 0
@@ -4927,11 +5567,15 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
}
Catch(fault)
+ {
modifier_reset((png_modifier*)fault);
+ }
}
/* The transforms: */
#define ITSTRUCT(name) image_transform_##name
+#define ITDATA(name) image_transform_data_##name
+#define image_transform_ini image_transform_default_ini
#define IT(name)\
static image_transform ITSTRUCT(name) =\
{\
@@ -4941,6 +5585,7 @@ static image_transform ITSTRUCT(name) =\
0, /*global_use*/\
0, /*local_use*/\
0, /*next*/\
+ image_transform_ini,\
image_transform_png_set_##name##_set,\
image_transform_png_set_##name##_mod,\
image_transform_png_set_##name##_add\
@@ -4948,6 +5593,13 @@ static image_transform ITSTRUCT(name) =\
#define PT ITSTRUCT(end) /* stores the previous transform */
/* To save code: */
+static void
+image_transform_default_ini(PNG_CONST image_transform *this,
+ transform_display *that)
+{
+ this->next->ini(this->next, that);
+}
+
static int
image_transform_default_add(image_transform *this,
PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
@@ -5397,16 +6049,173 @@ IT(strip_alpha);
* png_fixed_point green)
* png_get_rgb_to_gray_status
*
- * At present the APIs are simply tested using the 16.16 fixed point conversion
- * values known to be used inside libpng:
+ * The 'default' test here uses values known to be used inside libpng:
*
* red: 6968
* green: 23434
* blue: 2366
*
- * NOTE: this currently ignores the gamma because no gamma is being set, the
- * tests on gamma need to happen in the gamma test set.
+ * These values are being retained for compatibility, along with the somewhat
+ * broken truncation calculation in the fast-and-inaccurate code path. Older
+ * versions of libpng will fail the accuracy tests below because they use the
+ * truncation algorithm everywhere.
*/
+#define data ITDATA(rgb_to_gray)
+static struct
+{
+ double gamma; /* File gamma to use in processing */
+
+ /* The following are the parameters for png_set_rgb_to_gray: */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ double red_to_set;
+ double green_to_set;
+# else
+ png_fixed_point red_to_set;
+ png_fixed_point green_to_set;
+# endif
+
+ /* The actual coefficients: */
+ double red_coefficient;
+ double green_coefficient;
+ double blue_coefficient;
+
+ /* Set if the coeefficients have been overridden. */
+ int coefficients_overridden;
+} data;
+
+#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,
+ transform_display *that)
+{
+ png_modifier *pm = that->pm;
+ PNG_CONST color_encoding *e = pm->current_encoding;
+
+ UNUSED(this)
+
+ /* Since we check the encoding this flag must be set: */
+ pm->test_uses_encoding = 1;
+
+ /* If 'e' is not NULL chromaticity information is present and either a cHRM
+ * or an sRGB chunk will be inserted.
+ */
+ if (e != 0)
+ {
+ /* 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;
+
+ data.red_coefficient = e->red.Y;
+ data.green_coefficient = e->green.Y;
+ data.blue_coefficient = e->blue.Y;
+
+ if (whiteY != 1)
+ {
+ data.red_coefficient /= whiteY;
+ data.green_coefficient /= whiteY;
+ data.blue_coefficient /= whiteY;
+ }
+ }
+
+ else
+ {
+ /* The default (built in) coeffcients, as above: */
+ data.red_coefficient = 6968 / 32768.;
+ data.green_coefficient = 23434 / 32768.;
+ data.blue_coefficient = 2366 / 32768.;
+ }
+
+ data.gamma = pm->current_gamma;
+
+ /* If not set then the calculations assume linear encoding (implicitly): */
+ if (data.gamma == 0)
+ data.gamma = 1;
+
+ /* The arguments to png_set_rgb_to_gray can override the coefficients implied
+ * by the color space encoding. If doing exhaustive checks do the override
+ * in each case, otherwise do it randomly.
+ */
+ if (pm->test_exhaustive)
+ {
+ /* First time in coefficients_overridden is 0, the following sets it to 1,
+ * so repeat if it is set. If a test fails this may mean we subsequently
+ * skip a non-override test, ignore that.
+ */
+ data.coefficients_overridden = !data.coefficients_overridden;
+ pm->repeat = data.coefficients_overridden != 0;
+ }
+
+ else
+ data.coefficients_overridden = random_choice();
+
+ if (data.coefficients_overridden)
+ {
+ /* These values override the color encoding defaults, simply use random
+ * numbers.
+ */
+ png_uint_32 ru;
+ double total;
+
+ RANDOMIZE(ru);
+ data.green_coefficient = total = (ru & 0xffff) / 65535.;
+ ru >>= 16;
+ data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.;
+ total += data.red_coefficient;
+ data.blue_coefficient = 1 - total;
+
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ data.red_to_set = data.red_coefficient;
+ data.green_to_set = data.green_coefficient;
+# else
+ data.red_to_set = fix(data.red_coefficient);
+ data.green_to_set = fix(data.green_coefficient);
+# endif
+
+ /* The following just changes the error messages: */
+ pm->encoding_ignored = 1;
+ }
+
+ else
+ {
+ data.red_to_set = -1;
+ data.green_to_set = -1;
+ }
+
+ /* Adjust the error limit in the png_modifier because of the larger errors
+ * produced in the digitization during the gamma handling.
+ */
+ if (data.gamma != 1) /* Use gamma tables */
+ {
+ if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations)
+ {
+ /* The 16 bit case ends up producing a maximum error of about
+ * +/-5 in 65535, allow for +/-8 with the given gamma.
+ */
+ that->pm->limit += pow(8./65535, data.gamma);
+ }
+
+ else
+ {
+ /* Rounding to 8 bits in the linear space causes massive errors which
+ * will trigger the error check in transform_range_check. Fix that
+ * here by taking the gamma encoding into account.
+ */
+ that->pm->limit += pow(1./255, data.gamma);
+ }
+ }
+
+ else
+ {
+ /* With no gamma correction a large error comes from the truncation of the
+ * calculation in the 8 bit case, allow for that here.
+ */
+ if (that->this.bit_depth != 16)
+ that->pm->limit += 4E-3;
+ }
+}
+
static void
image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
@@ -5414,11 +6223,123 @@ image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this,
PNG_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, -1, -1);
+ png_set_rgb_to_gray(pp, error_action, data.red_to_set, data.green_to_set);
# else
- png_set_rgb_to_gray_fixed(pp, error_action, -1, -1);
+ png_set_rgb_to_gray_fixed(pp, error_action, data.red_to_set,
+ data.green_to_set);
# endif
+# ifdef PNG_READ_cHRM_SUPPORTED
+ if (that->pm->current_encoding != 0)
+ {
+ /* We have an encoding so a cHRM chunk may have been set; if so then
+ * check that the libpng APIs give the correct (X,Y,Z) values within
+ * some margin of error for the round trip through the chromaticity
+ * form.
+ */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+# define API_function png_get_cHRM_XYZ
+# define API_form "FP"
+# define API_type double
+# define API_cvt(x) (x)
+# else
+# define API_function png_get_cHRM_XYZ_fixed
+# define API_form "fixed"
+# define API_type png_fixed_point
+# define API_cvt(x) ((double)(x)/PNG_FP_1)
+# endif
+
+ API_type rX, gX, bX;
+ API_type rY, gY, bY;
+ API_type rZ, gZ, bZ;
+
+ if ((API_function(pp, pi, &rX, &rY, &rZ, &gX, &gY, &gZ, &bX, &bY, &bZ)
+ & PNG_INFO_cHRM) != 0)
+ {
+ double maxe;
+ PNG_CONST char *el;
+ color_encoding e, o;
+
+ /* Expect libpng to return a normalized result, but the original
+ * color space encoding may not be normalized.
+ */
+ modifier_current_encoding(that->pm, &o);
+ normalize_color_encoding(&o);
+
+ /* Sanity check the pngvalid code - the coefficients should match
+ * the normalized Y values of the encoding unless they were
+ * overridden.
+ */
+ if (data.red_to_set == -1 && data.green_to_set == -1 &&
+ (fabs(o.red.Y - data.red_coefficient) > DBL_EPSILON ||
+ fabs(o.green.Y - data.green_coefficient) > DBL_EPSILON ||
+ fabs(o.blue.Y - data.blue_coefficient) > DBL_EPSILON))
+ png_error(pp, "internal pngvalid cHRM coefficient error");
+
+ /* Generate a colour space encoding. */
+ e.gamma = o.gamma; /* not used */
+ e.red.X = API_cvt(rX);
+ e.red.Y = API_cvt(rY);
+ e.red.Z = API_cvt(rZ);
+ e.green.X = API_cvt(gX);
+ e.green.Y = API_cvt(gY);
+ e.green.Z = API_cvt(gZ);
+ e.blue.X = API_cvt(bX);
+ e.blue.Y = API_cvt(bY);
+ e.blue.Z = API_cvt(bZ);
+
+ /* This should match the original one from the png_modifier, within
+ * the range permitted by the libpng fixed point representation.
+ */
+ maxe = 0;
+ el = "-"; /* Set to element name with error */
+
+# define CHECK(col,x)\
+ {\
+ double err = fabs(o.col.x - e.col.x);\
+ if (err > maxe)\
+ {\
+ maxe = err;\
+ el = #col "(" #x ")";\
+ }\
+ }
+
+ CHECK(red,X)
+ CHECK(red,Y)
+ CHECK(red,Z)
+ CHECK(green,X)
+ CHECK(green,Y)
+ CHECK(green,Z)
+ CHECK(blue,X)
+ CHECK(blue,Y)
+ CHECK(blue,Z)
+
+ /* Here in both fixed and floating cases to check the values read
+ * from the cHRm chunk. PNG uses fixed point in the cHRM chunk, so
+ * we can't expect better than +/-.5E-5 on the result, allow 1E-5.
+ */
+ if (maxe >= 1E-5)
+ {
+ size_t pos = 0;
+ char buffer[256];
+
+ pos = safecat(buffer, sizeof buffer, pos, API_form);
+ pos = safecat(buffer, sizeof buffer, pos, " cHRM ");
+ pos = safecat(buffer, sizeof buffer, pos, el);
+ pos = safecat(buffer, sizeof buffer, pos, " error: ");
+ pos = safecatd(buffer, sizeof buffer, pos, maxe, 7);
+ pos = safecat(buffer, sizeof buffer, pos, " ");
+ /* Print the color space without the gamma value: */
+ pos = safecat_color_encoding(buffer, sizeof buffer, pos, &o, 0);
+ pos = safecat(buffer, sizeof buffer, pos, " -> ");
+ pos = safecat_color_encoding(buffer, sizeof buffer, pos, &e, 0);
+
+ png_error(pp, buffer);
+ }
+ }
+ }
+# endif /* READ_cHRM */
+
this->next->set(this->next, that, pp, pi);
}
@@ -5428,15 +6349,144 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
{
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);
/* Image now has RGB channels... */
- that->bluef = that->greenf = that->redf = (that->redf * 6968 +
- that->greenf * 23434 + that->bluef * 2366) / 32768;
- that->bluee = that->greene = that->rede = (that->rede * 6968 +
- that->greene * 23434 + that->bluee * 2366) / 32768 *
- (1 + DBL_EPSILON * 6);
+ {
+ PNG_CONST png_modifier *pm = display->pm;
+ PNG_CONST unsigned int sample_depth = that->sample_depth;
+ int isgray;
+ double r, g, b;
+ double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi;
+
+ /* Do this using interval arithmetic, otherwise it is too difficult to
+ * handle the errors correctly.
+ *
+ * To handle the gamma correction work out the upper and lower bounds
+ * of the digitized value. Assume rounding here - normally the values
+ * 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!)
+ */
+ r = rlo = rhi = that->redf;
+ rlo -= that->rede;
+ rlo = digitize(pm, rlo, sample_depth, 1/*round*/);
+ rhi += that->rede;
+ rhi = digitize(pm, rhi, sample_depth, 1/*round*/);
+
+ g = glo = ghi = that->greenf;
+ glo -= that->greene;
+ glo = digitize(pm, glo, sample_depth, 1/*round*/);
+ ghi += that->greene;
+ ghi = digitize(pm, ghi, sample_depth, 1/*round*/);
+
+ b = blo = bhi = that->bluef;
+ blo -= that->bluee;
+ blo = digitize(pm, blo, sample_depth, 1/*round*/);
+ bhi += that->greene;
+ bhi = digitize(pm, bhi, sample_depth, 1/*round*/);
+
+ isgray = r==g && g==b;
+
+ if (data.gamma != 1)
+ {
+ PNG_CONST double power = 1/data.gamma;
+ PNG_CONST double abse = abserr(pm, sample_depth, sample_depth);
+
+ /* '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.
+ */
+ r = pow(r, power);
+ rlo = digitize(pm, pow(rlo, power)-abse, sample_depth, 1);
+ rhi = digitize(pm, pow(rhi, power)+abse, sample_depth, 1);
+
+ g = pow(g, power);
+ glo = digitize(pm, pow(glo, power)-abse, sample_depth, 1);
+ ghi = digitize(pm, pow(ghi, power)+abse, sample_depth, 1);
+
+ b = pow(b, power);
+ blo = digitize(pm, pow(blo, power)-abse, sample_depth, 1);
+ bhi = digitize(pm, pow(bhi, power)+abse, sample_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
+ * 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
+ * the non-gamma code path is used for less than 16 bit data.
+ */
+ gray = r * data.red_coefficient + g * data.green_coefficient +
+ b * data.blue_coefficient;
+
+ {
+ PNG_CONST int do_round = data.gamma != 1 || sample_depth == 16;
+ PNG_CONST double ce = 1. / 32768;
+
+ graylo = digitize(pm, rlo * (data.red_coefficient-ce) +
+ glo * (data.green_coefficient-ce) +
+ blo * (data.blue_coefficient-ce), sample_depth, do_round);
+ if (graylo <= 0)
+ graylo = 0;
+
+ grayhi = digitize(pm, rhi * (data.red_coefficient+ce) +
+ ghi * (data.green_coefficient+ce) +
+ bhi * (data.blue_coefficient+ce), sample_depth, do_round);
+ if (grayhi >= 1)
+ grayhi = 1;
+ }
+
+ /* And invert the gamma. */
+ if (data.gamma != 1)
+ {
+ PNG_CONST double power = data.gamma;
+
+ gray = pow(gray, power);
+ graylo = digitize(pm, pow(graylo, power), sample_depth, 1);
+ grayhi = digitize(pm, pow(grayhi, power), sample_depth, 1);
+ }
+
+ /* Now the error can be calculated.
+ *
+ * If r==g==b because there is no overall gamma correction libpng
+ * currently preserves the original value.
+ */
+ if (isgray)
+ err = (that->rede + that->greene + that->bluee)/3;
+
+ else
+ {
+ err = fabs(grayhi-gray);
+ if (fabs(gray - graylo) > err)
+ err = fabs(graylo-gray);
+
+ /* Check that this worked: */
+ if (err > display->pm->limit)
+ {
+ size_t pos = 0;
+ char buffer[128];
+
+ pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error ");
+ pos = safecatd(buffer, sizeof buffer, pos, err, 6);
+ pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
+ pos = safecatd(buffer, sizeof buffer, pos,
+ display->pm->limit, 6);
+ png_error(pp, buffer);
+ }
+ }
+ }
+
+ that->bluef = that->greenf = that->redf = gray;
+ that->bluee = that->greene = that->rede = err;
/* The sBIT is the minium of the three colour channel sBITs. */
if (that->red_sBIT > that->green_sBIT)
@@ -5445,7 +6495,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
that->red_sBIT = that->blue_sBIT;
that->blue_sBIT = that->green_sBIT = that->red_sBIT;
- /* And zap the colour bit in the type: */
+ /* And remove the colour bit in the type: */
if (that->colour_type == PNG_COLOR_TYPE_RGB)
that->colour_type = PNG_COLOR_TYPE_GRAY;
else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA)
@@ -5467,9 +6517,12 @@ image_transform_png_set_rgb_to_gray_add(image_transform *this,
return (colour_type & PNG_COLOR_MASK_COLOR) != 0;
}
+#undef data
IT(rgb_to_gray);
#undef PT
#define PT ITSTRUCT(rgb_to_gray)
+#undef image_transform_ini
+#define image_transform_ini image_transform_default_ini
#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */
#ifdef PNG_READ_BACKGROUND_SUPPORTED
@@ -5479,8 +6532,11 @@ IT(rgb_to_gray);
* int background_gamma_code, int need_expand,
* png_fixed_point background_gamma)
*
- * As with rgb_to_gray this ignores the gamma.
+ * As with rgb_to_gray this ignores the gamma (at present.)
*/
+#define data ITDATA(background)
+static image_pixel data;
+
static void
image_transform_png_set_background_set(PNG_CONST image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
@@ -5509,7 +6565,7 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
else
bit_depth = that->this.bit_depth;
- image_pixel_init(&that->background_colour, random_bytes, colour_type,
+ image_pixel_init(&data, random_bytes, colour_type,
bit_depth, 0/*x*/, 0/*unused: palette*/);
/* Extract the background colour from this image_pixel, but make sure the
@@ -5519,13 +6575,13 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
if (colour_type & PNG_COLOR_MASK_COLOR)
{
- back.red = (png_uint_16)that->background_colour.red;
- back.green = (png_uint_16)that->background_colour.green;
- back.blue = (png_uint_16)that->background_colour.blue;
+ back.red = (png_uint_16)data.red;
+ back.green = (png_uint_16)data.green;
+ back.blue = (png_uint_16)data.blue;
}
else
- back.gray = (png_uint_16)that->background_colour.red;
+ back.gray = (png_uint_16)data.red;
# ifdef PNG_FLOATING_POINT_SUPPORTED
png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1/*need expand*/,
@@ -5549,36 +6605,34 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
/* This is only necessary if the alpha value is less than 1. */
if (that->alphaf < 1)
{
- PNG_CONST image_pixel *back = &display->background_colour;
-
/* Now we do the background calculation without any gamma correction. */
if (that->alphaf <= 0)
{
- that->redf = back->redf;
- that->greenf = back->greenf;
- that->bluef = back->bluef;
+ that->redf = data.redf;
+ that->greenf = data.greenf;
+ that->bluef = data.bluef;
- that->rede = back->rede;
- that->greene = back->greene;
- that->bluee = back->bluee;
+ that->rede = data.rede;
+ that->greene = data.greene;
+ that->bluee = data.bluee;
- that->red_sBIT= back->red_sBIT;
- that->green_sBIT= back->green_sBIT;
- that->blue_sBIT= back->blue_sBIT;
+ that->red_sBIT= data.red_sBIT;
+ that->green_sBIT= data.green_sBIT;
+ that->blue_sBIT= data.blue_sBIT;
}
else /* 0 < alpha < 1 */
{
double alf = 1 - that->alphaf;
- that->redf = that->redf * that->alphaf + back->redf * alf;
- that->rede = that->rede * that->alphaf + back->rede * alf +
+ that->redf = that->redf * that->alphaf + data.redf * alf;
+ that->rede = that->rede * that->alphaf + data.rede * alf +
DBL_EPSILON;
- that->greenf = that->greenf * that->alphaf + back->greenf * alf;
- that->greene = that->greene * that->alphaf + back->greene * alf +
+ that->greenf = that->greenf * that->alphaf + data.greenf * alf;
+ that->greene = that->greene * that->alphaf + data.greene * alf +
DBL_EPSILON;
- that->bluef = that->bluef * that->alphaf + back->bluef * alf;
- that->bluee = that->bluee * that->alphaf + back->bluee * alf +
+ that->bluef = that->bluef * that->alphaf + data.bluef * alf;
+ that->bluee = that->bluee * that->alphaf + data.bluee * alf +
DBL_EPSILON;
}
@@ -5598,6 +6652,7 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
#define image_transform_png_set_background_add image_transform_default_add
+#undef data
IT(background);
#undef PT
#define PT ITSTRUCT(background)
@@ -5755,7 +6810,7 @@ image_transform_add(PNG_CONST image_transform **this, unsigned int max,
else
{
- /* Not useful and max>0, so remvoe it from *this: */
+ /* Not useful and max>0, so remove it from *this: */
*this = list->next;
list->next = 0;
@@ -5886,11 +6941,16 @@ perform_transform_test(png_modifier *pm)
break;
/* The command line can change this to checking interlaced images. */
- transform_test(pm, FILEID(colour_type, bit_depth, palette_number,
- pm->interlace_type, 0, 0, 0), list, name);
+ do
+ {
+ pm->repeat = 0;
+ transform_test(pm, FILEID(colour_type, bit_depth, palette_number,
+ pm->interlace_type, 0, 0, 0), list, name);
- if (fail(pm))
- return;
+ if (fail(pm))
+ return;
+ }
+ while (pm->repeat);
}
}
}
@@ -5898,147 +6958,6 @@ perform_transform_test(png_modifier *pm)
/********************************* GAMMA TESTS ********************************/
#ifdef PNG_READ_GAMMA_SUPPORTED
-/* Gamma test images. */
-typedef struct gamma_modification
-{
- png_modification this;
- png_fixed_point gamma;
-} gamma_modification;
-
-static int
-gamma_modify(png_modifier *pm, png_modification *me, int add)
-{
- UNUSED(add)
- /* This simply dumps the given gamma value into the buffer. */
- png_save_uint_32(pm->buffer, 4);
- png_save_uint_32(pm->buffer+4, CHUNK_gAMA);
- png_save_uint_32(pm->buffer+8, ((gamma_modification*)me)->gamma);
- return 1;
-}
-
-static void
-gamma_modification_init(gamma_modification *me, png_modifier *pm, double gammad)
-{
- double g;
-
- modification_init(&me->this);
- me->this.chunk = CHUNK_gAMA;
- me->this.modify_fn = gamma_modify;
- me->this.add = CHUNK_PLTE;
- g = floor(gammad * 100000 + .5);
- me->gamma = (png_fixed_point)g;
- me->this.next = pm->modifications;
- pm->modifications = &me->this;
-}
-
-typedef struct srgb_modification
-{
- png_modification this;
- png_byte intent;
-} srgb_modification;
-
-static int
-srgb_modify(png_modifier *pm, png_modification *me, int add)
-{
- UNUSED(add)
- /* As above, ignore add and just make a new chunk */
- png_save_uint_32(pm->buffer, 1);
- png_save_uint_32(pm->buffer+4, CHUNK_sRGB);
- pm->buffer[8] = ((srgb_modification*)me)->intent;
- return 1;
-}
-
-static void
-srgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent)
-{
- modification_init(&me->this);
- me->this.chunk = CHUNK_sBIT;
-
- if (intent <= 3) /* if valid, else *delete* sRGB chunks */
- {
- me->this.modify_fn = srgb_modify;
- me->this.add = CHUNK_PLTE;
- me->intent = intent;
- }
-
- else
- {
- me->this.modify_fn = 0;
- me->this.add = 0;
- me->intent = 0;
- }
-
- me->this.next = pm->modifications;
- pm->modifications = &me->this;
-}
-
-typedef struct sbit_modification
-{
- png_modification this;
- png_byte sbit;
-} sbit_modification;
-
-static int
-sbit_modify(png_modifier *pm, png_modification *me, int add)
-{
- png_byte sbit = ((sbit_modification*)me)->sbit;
- if (pm->bit_depth > sbit)
- {
- int cb = 0;
- switch (pm->colour_type)
- {
- case 0:
- cb = 1;
- break;
-
- case 2:
- case 3:
- cb = 3;
- break;
-
- case 4:
- cb = 2;
- break;
-
- case 6:
- cb = 4;
- break;
-
- default:
- png_error(pm->this.pread,
- "unexpected colour type in sBIT modification");
- }
-
- png_save_uint_32(pm->buffer, cb);
- png_save_uint_32(pm->buffer+4, CHUNK_sBIT);
-
- while (cb > 0)
- (pm->buffer+8)[--cb] = sbit;
-
- return 1;
- }
- else if (!add)
- {
- /* Remove the sBIT chunk */
- pm->buffer_count = pm->buffer_position = 0;
- return 1;
- }
- else
- return 0; /* do nothing */
-}
-
-static void
-sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit)
-{
- modification_init(&me->this);
- me->this.chunk = CHUNK_sBIT;
- me->this.modify_fn = sbit_modify;
- me->this.add = CHUNK_PLTE;
- me->sbit = sbit;
- me->this.next = pm->modifications;
- pm->modifications = &me->this;
-}
-
/* Reader callbacks and implementations, where they differ from the standard
* ones.
*/
@@ -6140,7 +7059,7 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
*/
PNG_CONST double sg = dp->screen_gamma;
# ifndef PNG_FLOATING_POINT_SUPPORTED
- PNG_CONST png_fixed_point g = (png_fixed_point)(sg*100000+.5);
+ PNG_CONST png_fixed_point g = fix(sg);
# endif
# ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -6158,7 +7077,7 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
# ifdef PNG_FLOATING_POINT_SUPPORTED
png_set_gamma(pp, sg, dp->file_gamma);
# else
- png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5);
+ png_fixed_point f = fix(dp->file_gamma);
png_set_gamma_fixed(pp, g, f);
# endif
}
@@ -6175,8 +7094,8 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
png_set_gamma(pp, dp->screen_gamma, dp->file_gamma);
# else
{
- png_fixed_point s = (png_fixed_point)(dp->screen_gamma*100000+.5);
- png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5);
+ png_fixed_point s = fix(dp->screen_gamma);
+ png_fixed_point f = fix(dp->file_gamma);
png_set_gamma_fixed(pp, s, f);
}
# endif
@@ -6188,7 +7107,7 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
*/
PNG_CONST double bg = dp->background_gamma;
# ifndef PNG_FLOATING_POINT_SUPPORTED
- PNG_CONST png_fixed_point g = (png_fixed_point)(bg*100000+.5);
+ PNG_CONST png_fixed_point g = fix(bg);
# endif
# ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -6213,7 +7132,8 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
static void
gamma_info(png_structp pp, png_infop pi)
{
- gamma_info_imp(png_get_progressive_ptr(pp), pp, pi);
+ gamma_info_imp(voidcast(gamma_display*, png_get_progressive_ptr(pp)), pp,
+ pi);
}
/* Validate a single component value - the routine gets the input and output
@@ -7107,8 +8027,8 @@ gamma_image_validate(gamma_display *dp, png_structp pp, png_infop pi)
}
}
- /* Handle greyscale or RGB components. */
- if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* greyscale */
+ /* 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*/,
@@ -7156,7 +8076,7 @@ gamma_image_validate(gamma_display *dp, png_structp pp, png_infop pi)
static void
gamma_end(png_structp pp, png_infop pi)
{
- gamma_display *dp = png_get_progressive_ptr(pp);
+ gamma_display *dp = voidcast(gamma_display*, png_get_progressive_ptr(pp));
if (!dp->this.speed)
gamma_image_validate(dp, pp, pi);
@@ -7192,15 +8112,20 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
{
png_structp pp;
png_infop pi;
- gamma_modification gamma_mod;
+ gama_modification gama_mod;
srgb_modification srgb_mod;
sbit_modification sbit_mod;
+ /* For the moment don't use the png_modifier support here. */
+ d.pm->encoding_counter = 0;
+ modifier_set_encoding(d.pm); /* Just resets everything */
+ d.pm->current_gamma = d.file_gamma;
+
/* Make an appropriate modifier to set the PNG file gamma to the
* given gamma value and the sBIT chunk to the given precision.
*/
d.pm->modifications = NULL;
- gamma_modification_init(&gamma_mod, d.pm, d.file_gamma);
+ gama_modification_init(&gama_mod, d.pm, d.file_gamma);
srgb_modification_init(&srgb_mod, d.pm, 127 /*delete*/);
if (d.sbit > 0)
sbit_modification_init(&sbit_mod, d.pm, d.sbit);
@@ -7410,15 +8335,16 @@ static void perform_gamma_transform_tests(png_modifier *pm)
{
unsigned int i, j;
- for (i=0; i<pm->ngammas; ++i) for (j=0; j<pm->ngammas; ++j) if (i != j)
- {
- gamma_transform_test(pm, colour_type, bit_depth, palette_number,
- pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/,
- pm->use_input_precision, 0 /*do not scale16*/);
+ for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j)
+ if (i != j)
+ {
+ gamma_transform_test(pm, colour_type, bit_depth, palette_number,
+ pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/,
+ pm->use_input_precision, 0 /*do not scale16*/);
- if (fail(pm))
- return;
- }
+ if (fail(pm))
+ return;
+ }
}
}
@@ -7445,11 +8371,11 @@ static void perform_gamma_sbit_tests(png_modifier *pm)
{
unsigned int i;
- for (i=0; i<pm->ngammas; ++i)
+ for (i=0; i<pm->ngamma_tests; ++i)
{
unsigned int j;
- for (j=0; j<pm->ngammas; ++j) if (i != j)
+ for (j=0; j<pm->ngamma_tests; ++j) if (i != j)
{
gamma_transform_test(pm, colour_type, bit_depth, npalette,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
@@ -7482,9 +8408,9 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
* by much) - this could be fixed, it only appears with the -g option.
*/
unsigned int i, j;
- for (i=0; i<pm->ngammas; ++i)
+ for (i=0; i<pm->ngamma_tests; ++i)
{
- for (j=0; j<pm->ngammas; ++j)
+ for (j=0; j<pm->ngamma_tests; ++j)
{
if (i != j &&
fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD)
@@ -7663,7 +8589,7 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
unsigned int i, j;
/* Don't skip the i==j case here - it's relevant. */
- for (i=0; i<pm->ngammas; ++i) for (j=0; j<pm->ngammas; ++j)
+ for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j)
{
gamma_composition_test(pm, colour_type, bit_depth, palette_number,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
@@ -8179,6 +9105,41 @@ perform_interlace_macro_validation(void)
}
}
+/* Test color encodings. These values are back-calculated from the published
+ * chromaticities. The values are accurate to about 14 decimal places; 15 are
+ * given. These values are much more accurate than the ones given in the spec,
+ * which typically don't exceed 4 decimal places. This allows testing of the
+ * libpng code to its theoretical accuracy of 4 decimal places. (If pngvalid
+ * used the published errors the 'slack' permitted would have to be +/-.5E-4 or
+ * more.)
+ *
+ * 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[] =
+{
+/* sRGB: must be first in this list! */
+/*gamma:*/ { 1/2.2,
+/*red: */ { 0.412390799265959, 0.212639005871510, 0.019330818715592 },
+/*green:*/ { 0.357584339383878, 0.715168678767756, 0.119194779794626 },
+/*blue: */ { 0.180480788401834, 0.072192315360734, 0.950532152249660} },
+/* Kodak ProPhoto (wide gamut) */
+/*gamma:*/ { 1/1.6 /*approximate: uses 1.8 power law compared to sRGB 2.4*/,
+/*red: */ { 0.797760489672303, 0.288071128229293, 0.000000000000000 },
+/*green:*/ { 0.135185837175740, 0.711843217810102, 0.000000000000000 },
+/*blue: */ { 0.031349349581525, 0.000085653960605, 0.825104602510460} },
+/* Adobe RGB (1998) */
+/*gamma:*/ { 1/(2+51./256),
+/*red: */ { 0.576669042910131, 0.297344975250536, 0.027031361386412 },
+/*green:*/ { 0.185558237906546, 0.627363566255466, 0.070688852535827 },
+/*blue: */ { 0.188228646234995, 0.075291458493998, 0.991337536837639} },
+/* Adobe Wide Gamut RGB */
+/*gamma:*/ { 1/(2+51./256),
+/*red: */ { 0.716500716779386, 0.258728243040113, 0.000000000000000 },
+/*green:*/ { 0.101020574397477, 0.724682314948566, 0.051211818965388 },
+/*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} },
+};
+
/* main program */
int main(int argc, PNG_CONST char **argv)
{
@@ -8220,7 +9181,13 @@ int main(int argc, PNG_CONST char **argv)
/* Store the test gammas */
pm.gammas = gammas;
- pm.ngammas = 0; /* default to off */
+ pm.ngammas = (sizeof gammas) / (sizeof gammas[0]);
+ pm.ngamma_tests = 0; /* default to off */
+
+ /* And the test encodings */
+ pm.encodings = test_encodings;
+ pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]);
+
pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
/* 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
@@ -8277,8 +9244,8 @@ int main(int argc, PNG_CONST char **argv)
pm.this.treat_warnings_as_errors = 0;
else if (strcmp(*argv, "--speed") == 0)
- pm.this.speed = 1, pm.ngammas = (sizeof gammas)/(sizeof gammas[0]),
- pm.test_standard = 0, summary = 0;
+ pm.this.speed = 1, pm.ngamma_tests = pm.ngammas, pm.test_standard = 0,
+ summary = 0;
else if (strcmp(*argv, "--memory") == 0)
memstats = 1;
@@ -8320,7 +9287,7 @@ int main(int argc, PNG_CONST char **argv)
else if (strcmp(*argv, "--gamma") == 0)
{
/* Just do two gamma tests here (2.2 and linear) for speed: */
- pm.ngammas = 2U;
+ pm.ngamma_tests = 2U;
pm.test_gamma_threshold = 1;
pm.test_gamma_transform = 1;
pm.test_gamma_sbit = 1;
@@ -8330,40 +9297,40 @@ int main(int argc, PNG_CONST char **argv)
}
else if (strcmp(*argv, "--nogamma") == 0)
- pm.ngammas = 0;
+ pm.ngamma_tests = 0;
else if (strcmp(*argv, "--gamma-threshold") == 0)
- pm.ngammas = 2U, pm.test_gamma_threshold = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_threshold = 1;
else if (strcmp(*argv, "--nogamma-threshold") == 0)
pm.test_gamma_threshold = 0;
else if (strcmp(*argv, "--gamma-transform") == 0)
- pm.ngammas = 2U, pm.test_gamma_transform = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_transform = 1;
else if (strcmp(*argv, "--nogamma-transform") == 0)
pm.test_gamma_transform = 0;
else if (strcmp(*argv, "--gamma-sbit") == 0)
- pm.ngammas = 2U, pm.test_gamma_sbit = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_sbit = 1;
else if (strcmp(*argv, "--nogamma-sbit") == 0)
pm.test_gamma_sbit = 0;
else if (strcmp(*argv, "--gamma-16-to-8") == 0)
- pm.ngammas = 2U, pm.test_gamma_scale16 = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_scale16 = 1;
else if (strcmp(*argv, "--nogamma-16-to-8") == 0)
pm.test_gamma_scale16 = 0;
else if (strcmp(*argv, "--gamma-background") == 0)
- pm.ngammas = 2U, pm.test_gamma_background = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_background = 1;
else if (strcmp(*argv, "--nogamma-background") == 0)
pm.test_gamma_background = 0;
else if (strcmp(*argv, "--gamma-alpha-mode") == 0)
- pm.ngammas = 2U, pm.test_gamma_alpha_mode = 1;
+ pm.ngamma_tests = 2U, pm.test_gamma_alpha_mode = 1;
else if (strcmp(*argv, "--nogamma-alpha-mode") == 0)
pm.test_gamma_alpha_mode = 0;
@@ -8375,10 +9342,10 @@ int main(int argc, PNG_CONST char **argv)
pm.test_gamma_expand16 = 0;
else if (strcmp(*argv, "--more-gammas") == 0)
- pm.ngammas = 3U;
+ pm.ngamma_tests = 3U;
else if (strcmp(*argv, "--all-gammas") == 0)
- pm.ngammas = (sizeof gammas)/(sizeof gammas[0]);
+ pm.ngamma_tests = pm.ngammas;
else if (strcmp(*argv, "--progressive-read") == 0)
pm.this.progressive = 1;
@@ -8399,6 +9366,9 @@ int main(int argc, PNG_CONST char **argv)
pm.calculations_use_input_precision =
pm.assume_16_bit_calculations = 0;
+ else if (strcmp(*argv, "--exhaustive") == 0)
+ pm.test_exhaustive = 1;
+
else if (argc > 1 && strcmp(*argv, "--sbitlow") == 0)
--argc, pm.sbitlow = (png_byte)atoi(*++argv), catmore = 1;
@@ -8465,7 +9435,7 @@ int main(int argc, PNG_CONST char **argv)
* tests.
*/
if (pm.test_standard == 0 && pm.test_size == 0 && pm.test_transform == 0 &&
- pm.ngammas == 0)
+ pm.ngamma_tests == 0)
{
/* Make this do all the tests done in the test shell scripts with the same
* parameters, where possible. The limitation is that all the progressive
@@ -8475,10 +9445,10 @@ int main(int argc, PNG_CONST char **argv)
pm.test_standard = 1;
pm.test_size = 1;
pm.test_transform = 1;
- pm.ngammas = 2U;
+ pm.ngamma_tests = 2U;
}
- if (pm.ngammas > 0 &&
+ if (pm.ngamma_tests > 0 &&
pm.test_gamma_threshold == 0 && pm.test_gamma_transform == 0 &&
pm.test_gamma_sbit == 0 && pm.test_gamma_scale16 == 0 &&
pm.test_gamma_background == 0 && pm.test_gamma_alpha_mode == 0)
@@ -8491,7 +9461,7 @@ int main(int argc, PNG_CONST char **argv)
pm.test_gamma_alpha_mode = 1;
}
- else if (pm.ngammas == 0)
+ else if (pm.ngamma_tests == 0)
{
/* Nothing to test so turn everything off: */
pm.test_gamma_threshold = 0;
@@ -8530,7 +9500,7 @@ int main(int argc, PNG_CONST char **argv)
#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
#ifdef PNG_READ_GAMMA_SUPPORTED
- if (pm.ngammas > 0)
+ if (pm.ngamma_tests > 0)
perform_gamma_test(&pm, summary);
#endif
}
diff --git a/pngwutil.c b/pngwutil.c
index 3ae5ed4e2..4e422ce68 100644
--- a/pngwutil.c
+++ b/pngwutil.c
@@ -1860,7 +1860,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
{
PNG_pCAL;
png_size_t purpose_len, units_len, total_len;
- png_uint_32p params_len;
+ png_size_tp params_len;
png_byte buf[10];
png_charp new_purpose;
int i;
@@ -1876,8 +1876,8 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
png_debug1(3, "pCAL units length = %d", (int)units_len);
total_len = purpose_len + units_len + 10;
- params_len = (png_uint_32p)png_malloc(png_ptr,
- (png_alloc_size_t)(nparams * png_sizeof(png_uint_32)));
+ params_len = (png_size_tp)png_malloc(png_ptr,
+ (png_alloc_size_t)(nparams * png_sizeof(png_size_t)));
/* Find the length of each parameter, making sure we don't count the
* null terminator for the last parameter.
@@ -1887,13 +1887,12 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
png_debug2(3, "pCAL parameter %d length = %lu", i,
(unsigned long)params_len[i]);
- total_len += (png_size_t)params_len[i];
+ total_len += params_len[i];
}
png_debug1(3, "pCAL total length = %d", (int)total_len);
png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len);
- png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose,
- (png_size_t)purpose_len);
+ png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose, purpose_len);
png_save_int_32(buf, X0);
png_save_int_32(buf + 4, X1);
buf[8] = (png_byte)type;
@@ -1905,8 +1904,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
for (i = 0; i < nparams; i++)
{
- png_write_chunk_data(png_ptr, (png_const_bytep)params[i],
- (png_size_t)params_len[i]);
+ png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
}
png_free(png_ptr, params_len);