summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ANNOUNCE10
-rw-r--r--CHANGES10
-rw-r--r--png.c1392
-rw-r--r--png.h96
-rw-r--r--pngerror.c35
-rw-r--r--pngpriv.h40
-rw-r--r--pngrutil.c56
-rw-r--r--pngset.c60
-rw-r--r--pngstruct.h17
-rw-r--r--pngwutil.c17
-rw-r--r--scripts/pnglibconf.dfa21
-rw-r--r--scripts/pnglibconf.h.prebuilt3
-rw-r--r--scripts/symbols.def3
-rw-r--r--scripts/symbols.dfn1
14 files changed, 819 insertions, 942 deletions
diff --git a/ANNOUNCE b/ANNOUNCE
index c9cd11934..b8e9ce8bb 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -528,6 +528,16 @@ Version 1.6.0beta30 [October 24, 2012]
Version 1.6.0beta31 [October 26, 2012]
Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30.
Made pngvalid so that it will build outside the libpng source tree.
+ Changed ICC profile support to allow use of an external color management
+ system (CMS). In practice it is not possible to obtain cHRM information
+ reliably using just the end-point tags because they do not exist in the
+ vast majority of profiles. Instead it is necessary to run the endpoints
+ through the ICC colorimetric intent transform (as described in the v4
+ spec). Since this is likely to be too much code inside libpng for too
+ little gain (it implies a fairly complete CMS implementation) the code
+ has been changed to allow an external CMS to be used. This code is
+ temporarily disabled until a suitable set of test cases using one or more
+ external CMS implementations have been implemented.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
diff --git a/CHANGES b/CHANGES
index 0a25103d3..58cbd10ef 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4280,6 +4280,16 @@ Version 1.6.0beta30 [October 24, 2012]
Version 1.6.0beta31 [October 26, 2012]
Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30.
Made pngvalid so that it will build outside the libpng source tree.
+ Changed ICC profile support to allow use of an external color management
+ system (CMS). In practice it is not possible to obtain cHRM information
+ reliably using just the end-point tags because they do not exist in the
+ vast majority of profiles. Instead it is necessary to run the endpoints
+ through the ICC colorimetric intent transform (as described in the v4
+ spec). Since this is likely to be too much code inside libpng for too
+ little gain (it implies a fairly complete CMS implementation) the code
+ has been changed to allow an external CMS to be used. This code is
+ temporarily disabled until a suitable set of test cases using one or more
+ external CMS implementations have been implemented.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
diff --git a/png.c b/png.c
index d838dbd97..27d31d357 100644
--- a/png.c
+++ b/png.c
@@ -663,6 +663,23 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp)
}
# endif
+#ifdef PNG_SAVE_INT_32_SUPPORTED
+/* The png_save_int_32 function assumes integers are stored in two's
+ * complement format. If this isn't the case, then this routine needs to
+ * be modified to write data in two's complement format. Note that,
+ * the following works correctly even if png_int_32 has more than 32 bits
+ * (compare the more complex code required on read for sign extention.)
+ */
+void PNGAPI
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+#endif
+
# ifdef PNG_TIME_RFC1123_SUPPORTED
/* Convert the supplied time into an RFC 1123 string suitable for use in
* a "Creation Time" or other text-based time string.
@@ -749,13 +766,13 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.6.0beta31 - October 24, 2012" PNG_STRING_NEWLINE \
+ "libpng version 1.6.0beta31 - October 26, 2012" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2012 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.6.0beta31 - October 24, 2012\
+ return "libpng version 1.6.0beta31 - October 26, 2012\
Copyright (c) 1998-2012 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -950,73 +967,100 @@ png_zstream_error(png_structrp png_ptr, int ret)
#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
static int
png_colorspace_check_gamma(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_fixed_point gAMA, int preferred)
- /* preferred:
- *
- * 0: do not override an existing setting, but *do* check for
- * compatibility with an existing setting.
- * 1: preferred over an existing setting, but only if the existing
- * setting is compatible with this one (i.e. approximately the same.)
- * 2: overrides existing setting and does not check for compatibility.
+ png_colorspacerp colorspace, png_fixed_point gAMA, int from)
+ /* This is called to check a new gamma value against an existing one. The
+ * routine returns false if the new gamma value should not be written.
*
- * result:
- * 0: incompatible existing setting, failure case
- * 1: compatible existing setting, existing value retained
- * 2: value written, either an existing value was compatible and preferred
- * was set or preferred was 2 and an existing value was ignored
+ * 'from' says where the new gamma value comes from:
*
- * Use thus:
- * If you don't want to override an existing setting and *don't* want to
- * check for compatibility don't call this if the PNG_COLORSPACE_HAVE_
- * flag is set.
- *
- * If you want to override an existing setting unconditionally - with no
- * check on compatibility - call with preferred == 2.
- *
- * Otherwise you want to check for compatibility with an existing setting,
- * call with preferred == 0 to favor the existing setting, == 1 to
- * override the existing setting.
+ * 0: the new gamma value is the libpng estimate for an ICC profile
+ * 1: the new gamma value comes from a gAMA chunk
+ * 2: the new gamma value comes from an sRGB chunk
*/
{
- /* The 'invalid' flag needs to be sticky, doing things this way avoids having
- * many messages caused by just one invalid colorspace chunk.
- */
- if (colorspace->flags & PNG_COLORSPACE_INVALID)
- return 0;
+ png_fixed_point gtest;
- if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA))
+ if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
+ (!png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) ||
+ png_gamma_significant(gtest)))
{
- png_fixed_point gtest;
-
- if (!png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) ||
- png_gamma_significant(gtest))
+ /* Either this is an sRGB image, in which case the calculated gamma
+ * approximation should match, or this is an image with a profile and the
+ * value libpng calculates for the gamma of the profile does not match the
+ * value recorded in the file. The former, sRGB, case is an error, the
+ * latter is just a warning.
+ */
+ if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)
{
- colorspace->flags |= PNG_COLORSPACE_INVALID;
- png_benign_error(png_ptr, "inconsistent gamma values");
- return 0; /* failed */
+ png_chunk_report(png_ptr, "gamma value does not match sRGB",
+ PNG_CHUNK_ERROR);
+ /* Do not overwrite an sRGB value */
+ return from == 2;
}
- else if (!preferred)
- return 1; /* ok, use existing gamma */
+ else /* sRGB tag not involved */
+ {
+ png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
+ PNG_CHUNK_WARNING);
+ return from == 1;
+ }
}
- return 2; /* ok, write gamma */
+ return 1;
}
-int /* PRIVATE */
+void /* PRIVATE */
png_colorspace_set_gamma(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_fixed_point gAMA, int preferred)
+ png_colorspacerp colorspace, png_fixed_point gAMA)
{
- int result = png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
- preferred);
+ /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
+ * occur. Since the fixed point representation is assymetrical it is
+ * 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 truly ridiculous gamma values (and will produce
+ * displays that are all black or all white.)
+ *
+ * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
+ * handling code, which only required the value to be >0.
+ */
+ png_const_charp errmsg;
+
+ if (gAMA < 16 || gAMA > 625000000)
+ errmsg = "gamma value out of range";
+
+# ifdef PNG_READ_gAMA_SUPPORTED
+ /* Allow the application to set the gamma value more than once */
+ else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
+ (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
+ errmsg = "duplicate";
+# endif
- if (result == 2)
+ /* Do nothing if the colorspace is already invalid */
+ else if (colorspace->flags & PNG_COLORSPACE_INVALID)
+ return;
+
+ else
{
- colorspace->gamma = gAMA;
- colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
+ if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/))
+ {
+ /* Store this gamma value. */
+ colorspace->gamma = gAMA;
+ colorspace->flags |=
+ (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
+ }
+
+ /* At present if the check_gamma test fails the gamma of the colorspace is
+ * not updated however the colorspace is not invalidated. This
+ * corresponds to the case where the existing gamma comes from an sRGB
+ * chunk or profile. An error message has already been output.
+ */
+ return;
}
- return result;
+ /* Error exit - errmsg has been set. */
+ colorspace->flags |= PNG_COLORSPACE_INVALID;
+ png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
}
void /* PRIVATE */
@@ -1078,117 +1122,6 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
#endif
#ifdef PNG_COLORSPACE_SUPPORTED
-#if 0
-/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
- * 2010: moved from pngset.c) */
-/*
- * Multiply two 32-bit numbers, V1 and V2, using 32-bit
- * arithmetic, to produce a 64-bit result in the HI/LO words.
- *
- * A B
- * x C D
- * ------
- * AD || BD
- * AC || CB || 0
- *
- * where A and B are the high and low 16-bit words of V1,
- * C and D are the 16-bit words of V2, AD is the product of
- * A and D, and X || Y is (X << 16) + Y.
-*/
-static void
-png_64bit_product (long v1, long v2, unsigned long *hi_product,
- unsigned long *lo_product)
-{
- int a, b, c, d;
- long lo, hi, x, y;
-
- a = (v1 >> 16) & 0xffff;
- b = v1 & 0xffff;
- c = (v2 >> 16) & 0xffff;
- d = v2 & 0xffff;
-
- lo = b * d; /* BD */
- x = a * d + c * b; /* AD + CB */
- y = ((lo >> 16) & 0xffff) + x;
-
- lo = (lo & 0xffff) | ((y & 0xffff) << 16);
- hi = (y >> 16) & 0xffff;
-
- hi += a * c; /* AC */
-
- *hi_product = (unsigned long)hi;
- *lo_product = (unsigned long)lo;
-}
-
-static int
-png_check_cHRM_fixed(png_const_structrp png_ptr,
- png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
- png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
- png_fixed_point blue_x, png_fixed_point blue_y)
-{
- int ret = 1;
- unsigned long xy_hi,xy_lo,yx_hi,yx_lo;
-
- png_debug(1, "in function png_check_cHRM_fixed");
-
- if (png_ptr == NULL)
- return 0;
-
- /* (x,y,z) values are first limited to 0..100000 (PNG_FP_1), the white
- * y must also be greater than 0. To test for the upper limit calculate
- * (PNG_FP_1-y) - x must be <= to this for z to be >= 0 (and the expression
- * cannot overflow.) At this point we know x and y are >= 0 and (x+y) is
- * <= PNG_FP_1. The previous test on PNG_MAX_UINT_31 is removed because it
- * pointless (and it produces compiler warnings!)
- */
- if (white_x < 0 || white_y <= 0 ||
- red_x < 0 || red_y < 0 ||
- green_x < 0 || green_y < 0 ||
- blue_x < 0 || blue_y < 0)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set negative chromaticity value");
- ret = 0;
- }
- /* And (x+y) must be <= PNG_FP_1 (so z is >= 0) */
- if (white_x > PNG_FP_1 - white_y)
- {
- png_warning(png_ptr, "Invalid cHRM white point");
- ret = 0;
- }
-
- if (red_x > PNG_FP_1 - red_y)
- {
- png_warning(png_ptr, "Invalid cHRM red point");
- ret = 0;
- }
-
- if (green_x > PNG_FP_1 - green_y)
- {
- png_warning(png_ptr, "Invalid cHRM green point");
- ret = 0;
- }
-
- if (blue_x > PNG_FP_1 - blue_y)
- {
- png_warning(png_ptr, "Invalid cHRM blue point");
- ret = 0;
- }
-
- png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo);
- png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo);
-
- if (xy_hi == yx_hi && xy_lo == yx_lo)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set cHRM RGB triangle with zero area");
- ret = 0;
- }
-
- return ret;
-}
-#endif /*0*/
-
/* 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
@@ -1713,6 +1646,28 @@ png_colorspace_set_endpoints(png_const_structrp png_ptr,
}
#if defined PNG_sRGB_SUPPORTED || defined PNG_iCCP_SUPPORTED
+/* Error message generation */
+static char
+png_icc_tag_char(png_uint_32 byte)
+{
+ byte &= 0xff;
+ if (byte >= 32 && byte <= 126)
+ return (char)byte;
+ else
+ return '?';
+}
+
+static void
+png_icc_tag_name(char *name, png_uint_32 tag)
+{
+ name[0] = '\'';
+ name[1] = png_icc_tag_char(tag >> 24);
+ name[2] = png_icc_tag_char(tag >> 16);
+ name[3] = png_icc_tag_char(tag >> 8);
+ name[4] = png_icc_tag_char(tag );
+ name[5] = '\'';
+}
+
static int
is_ICC_signature_char(png_alloc_size_t it)
{
@@ -1729,7 +1684,7 @@ static int is_ICC_signature(png_alloc_size_t it)
}
static int
-profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
+png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_alloc_size_t value, png_const_charp reason)
{
size_t pos;
@@ -1743,12 +1698,9 @@ profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
if (is_ICC_signature(value))
{
- message[pos++] = '\''; /* total +8; less than the else clause */
- message[pos++] = (char)(value >> 24);
- message[pos++] = (char)(value >> 16);
- message[pos++] = (char)(value >> 8);
- message[pos++] = (char)(value);
- message[pos++] = '\'';
+ /* So 'value' is at most 4 bytes and the following cast is safe */
+ png_icc_tag_name(message+pos, (png_uint_32)value);
+ pos += 6; /* total +8; less than the else clause */
message[pos++] = ':';
message[pos++] = ' ';
}
@@ -1766,123 +1718,34 @@ profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
/* The 'reason' is an arbitrary message, allow +79 maximum 195 */
pos = png_safecat(message, (sizeof message), pos, reason);
- if (colorspace != NULL)
- {
-# ifdef PNG_READ_SUPPORTED
- if (png_ptr->mode & PNG_IS_READ_STRUCT)
- png_chunk_benign_error(png_ptr, message);
-
- else
-# endif
- png_app_error(png_ptr, message);
- }
-
-# ifdef PNG_WARNINGS_SUPPORTED
- else
- {
- /* This is recoverable, but make it unconditionally an app_error on
- * write to avoid writing invalid ICC profiles into PNG files. (I.e.
- * we handle them on read, with a warning, but on write unless the app
- * turns off application errors the PNG won't be written.)
- */
-# ifdef PNG_READ_SUPPORTED
- if (png_ptr->mode & PNG_IS_READ_STRUCT)
- png_chunk_warning(png_ptr, message);
-
- else
-# endif
- png_app_error(png_ptr, message);
- }
-# endif
-
- return 0;
-}
-
-static int /* PRIVATE */
-png_colorspace_set_profile(png_const_structrp png_ptr, png_const_charp name,
- png_colorspacerp colorspace, png_fixed_point gAMA, const png_xy *xy,
- const png_XYZ *XYZ, int intent, int preferred)
-{
- int write_intent, write_gamma, result;
-
- if (colorspace->flags & PNG_COLORSPACE_INVALID)
- return 0;
-
- /* Similar to the above routines, but ensure that both the gamma and the
- * end-points are checked before doing any assignment.
- */
- if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_INTENT))
- {
- if (colorspace->rendering_intent != intent)
- return profile_error(png_ptr, colorspace, name, (unsigned)intent,
- "inconsistent rendering intents");
-
- write_intent = 0; /* Ok, don't change */
- }
-
- else
- write_intent = 1; /* Needs to be written */
-
- switch (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, preferred))
- {
- case 2:
- write_gamma = 1;
- break;
-
- case 1:
- write_gamma = 0; /* current value ok and preferred */
- break;
-
- default: /* error */
- return 0;
- }
-
- /* Everything seems ok up to this point, update the endpoints and, if this
- * works, do the gamma and intent too.
+ /* This is recoverable, but make it unconditionally an app_error on write to
+ * avoid writing invalid ICC profiles into PNG files. (I.e. we handle them
+ * on read, with a warning, but on write unless the app turns off
+ * application errors the PNG won't be written.)
*/
- result = png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, XYZ,
- preferred);
-
- switch (result)
- {
- case 2: /* ok, changed */
- case 1: /* ok, no end-point change */
- if (write_intent)
- {
- /* The value of intent must be checked in the caller; bugs in GCC
- * force 'int' to be used as the parameter type.
- */
- colorspace->rendering_intent = (png_uint_16)intent;
- colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
- result = 2;
- }
-
- if (write_gamma)
- {
- colorspace->gamma = gAMA;
- colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
- result = 2;
- }
-
- return result;
+ png_chunk_report(png_ptr, message,
+ (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
- default: /* failure */
- return 0;
- }
+ return 0;
}
#endif /* sRGB || iCCP */
#ifdef PNG_sRGB_SUPPORTED
int /* PRIVATE */
png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
- int intent, int preferred)
+ int intent)
{
/* sRGB sets known gamma, end points and (from the chunk) intent. */
/* IMPORTANT: these are not necessarily the values found in an ICC profile
- * because ICC profiles assume a D50 environment and therefore use XYZ values
- * appropriate to a D50 environment. Perhaps we should too; it's just
- * slightly weird because the chromaticities of the adapted colorants don't
- * match the above values.
+ * because ICC profiles store values adapted to a D50 environment; it is
+ * expected that the ICC profile mediaWhitePointTag will be D50, see the
+ * checks and code elsewhere to understand this better.
+ *
+ * These XYZ values, which are accurate to 5dp, produce rgb to gray
+ * coefficients of (6968,23435,2366), which are reduced (because they add up
+ * to 32769 not 32768) to (6968,23434,2366). These are the values that
+ * libpng has traditionally used (and are the best values given the 15bit
+ * algorithm used by the rgb to gray code.)
*/
static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */
{
@@ -1892,26 +1755,68 @@ png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
/* blue */ 18048, 7219, 95053
};
- int result;
+ /* Do nothing if the colorspace is already invalidated. */
+ if (colorspace->flags & PNG_COLORSPACE_INVALID)
+ return 0;
- /* The above XYZ values, which are accurate to 5dp, produce rgb to gray
- * coefficients of (6968,23435,2366), which are reduced (because they add up
- * to 32769 not 32768) to (6968,23434,2366). These are the values that
- * libpng has traditionally used (and are the best values given the 15bit
- * algorithm used by the rgb to gray code.)
+ /* Check the intent, then check for existing settings. It is valid for the
+ * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
+ * be consistent with the correct values. If, however, this function is
+ * called below because an iCCP chunk matches sRGB then it is quite
+ * conceivable that an older app recorded incorrect gAMA and cHRM because of
+ * an incorrect calculation based on the values in the profile - this does
+ * *not* invalidate the profile (though it still produces an error, which can
+ * be ignored.)
*/
if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
- return profile_error(png_ptr, colorspace, "sRGB", (unsigned)intent,
- "invalid sRGB rendering intent");
+ return png_icc_profile_error(png_ptr, colorspace, "sRGB",
+ (unsigned)intent, "invalid sRGB rendering intent");
+
+ if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
+ colorspace->rendering_intent != intent)
+ return png_icc_profile_error(png_ptr, colorspace, "sRGB",
+ (unsigned)intent, "inconsistent rendering intents");
+
+ if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
+ {
+ png_benign_error(png_ptr, "duplicate sRGB information ignored");
+ return 0; /* not set */
+ }
+
+ /* If the standard sRGB cHRM chunk does not match the one from the PNG file
+ * warn but overwrite the value with the correct one.
+ */
+ if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&
+ !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
+ 100))
+ png_chunk_report(png_ptr, "cHRM chunk does not match sRGB",
+ PNG_CHUNK_ERROR);
+
+ /* This check is just done for the error reporting - the routine always
+ * returns true when the 'from' argument corresponds to sRGB (2).
+ */
+ (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,
+ 2/*from sRGB*/);
- result = png_colorspace_set_profile(png_ptr, "sRGB", colorspace,
- PNG_GAMMA_sRGB_INVERSE, &sRGB_xy, &sRGB_XYZ, intent, preferred);
+ /* intent: bugs in GCC force 'int' to be used as the parameter type. */
+ colorspace->rendering_intent = (png_uint_16)intent;
+ colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
- /* The implicit profile is the sRGB one, so: */
- if (result)
- colorspace->flags |= PNG_COLORSPACE_MATCHES_sRGB;
+ /* endpoints */
+ colorspace->end_points_xy = sRGB_xy;
+ colorspace->end_points_XYZ = sRGB_XYZ;
+ colorspace->flags |=
+ (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
- return result;
+ /* gamma */
+ colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;
+ colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
+
+ /* Finally record that we have an sRGB profile */
+ colorspace->flags |=
+ (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);
+
+ return 1/*set*/;
}
#endif /* sRGB */
@@ -1929,11 +1834,11 @@ png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_uint_32 profile_length)
{
if (profile_length < 132)
- return profile_error(png_ptr, colorspace, name, profile_length,
+ return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"too short");
if (profile_length & 3)
- return profile_error(png_ptr, colorspace, name, profile_length,
+ return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"invalid length");
return 1;
@@ -1954,13 +1859,13 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
temp = png_get_uint_32(profile);
if (temp != profile_length)
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"length does not match profile");
temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */
if (temp > 357913930 || /* (2^32-4-132)/12: maxium possible tag count */
profile_length < 132+12*temp) /* truncated tag table */
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"tag count too large");
/* The 'intent' must be valid or we can't store it, ICC limits the intent to
@@ -1968,14 +1873,14 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
temp = png_get_uint_32(profile+64);
if (temp >= 0xffff) /* The ICC limit */
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"invalid rendering intent");
/* This is just a warning because the profile may be valid in future
* versions.
*/
if (temp >= PNG_sRGB_INTENT_LAST)
- (void)profile_error(png_ptr, NULL, name, temp,
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"intent outside defined range");
/* At this point the tag table can't be checked because it hasn't necessarily
@@ -1992,7 +1897,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
temp = png_get_uint_32(profile+36); /* signature 'ascp' */
if (temp != 0x61637370)
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"invalid signature");
/* Currently the PCS illuminant/adopted white point (the computational
@@ -2003,7 +1908,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* following is just a warning.
*/
if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)
- (void)profile_error(png_ptr, NULL, name, 0/*no tag value*/,
+ (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
"PCS illuminant is not D50");
/* The PNG spec requires this:
@@ -2031,19 +1936,19 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
{
case 0x52474220: /* 'RGB ' */
if (!(color_type & PNG_COLOR_MASK_COLOR))
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"RGB color space not permitted on grayscale PNG");
info |= PNG_ICC_RGB;
break;
case 0x47524159: /* 'GRAY' */
if (color_type & PNG_COLOR_MASK_COLOR)
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"Gray color space not permitted on RGB PNG");
break;
default:
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"invalid ICC profile color space");
}
@@ -2068,7 +1973,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
case 0x61627374: /* 'abst' */
/* May not be embedded in an image */
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"invalid embedded Abstract ICC profile");
case 0x6C696E6B: /* 'link' */
@@ -2078,7 +1983,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* therefore a DeviceLink profile should not be found embedded in a
* PNG.
*/
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"unexpected DeviceLink ICC profile class");
case 0x6E6D636C: /* 'nmcl' */
@@ -2086,7 +1991,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* contain an AToB0 tag that is open to misintrepretation. Almost
* certainly it will fail the tests below.
*/
- (void)profile_error(png_ptr, NULL, name, temp,
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"unexpected NamedColor ICC profile class");
break;
@@ -2096,7 +2001,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
* tag content to ensure they are backward compatible with one of the
* understood profiles.
*/
- (void)profile_error(png_ptr, NULL, name, temp,
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"unrecognized ICC profile class");
break;
}
@@ -2115,7 +2020,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
break;
default:
- return profile_error(png_ptr, colorspace, name, temp,
+ return png_icc_profile_error(png_ptr, colorspace, name, temp,
"unexpected ICC PCS encoding");
}
@@ -2124,8 +2029,9 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
return 1;
}
+#ifdef PNG_ICC_SUPPORTED
static png_uint_32
-png_find_icc_tag(png_const_bytep profile, png_uint_32 tag, png_uint_32p length)
+png_icc_find_tag(png_const_bytep profile, png_uint_32 tag, png_uint_32p length)
/* Find a single tag in the tag table, returns 0 if the tag is not found,
* else returns the offset in the profile of the tag and, via *length, the
* length from the tag table.
@@ -2348,7 +2254,40 @@ png_invert_matrix(png_const_icc_matrixrp m, png_icc_matrixrp o)
}
static int
-png_icc_find_wtpt(png_const_structrp png_ptr, png_const_charp name,
+png_icc_XYZ_compare(png_const_bytep xyz1, png_const_bytep xyz2)
+ /* The arguments are 12 byte big-endian XYZ values as s15Fixed16 values, they
+ * are compared and the routine returns 0 if they are within about +/-1/1024
+ * else 1. The input values are always big-endian.
+ */
+{
+ int i;
+
+ for (i=0; i<3; ++i)
+ {
+ int diff = 0;
+ int j;
+
+ /* This won't overflow. */
+ for (j=0; j<3; ++j)
+ diff = (diff << 8) + (*xyz1++ - *xyz2++);
+
+ if (diff < -1 || diff > 1)
+ return 1; /* Too big a difference */
+
+ diff = (diff << 8) + (*xyz1++ - *xyz2++);
+
+ /* This is the limit on the difference, 64/65536 or +/- 1/1024 (determined
+ * by experiment) at present.
+ */
+ if (diff <= -64 || diff >= 64)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+png_icc_check_wtpt(png_const_structrp png_ptr, png_const_charp name,
png_const_bytep profile, png_icc_vectorrp adapted_white_point)
/* The mediaWhitePointTag contains an adapted white point (the observer
* white point) expressed as XYZ tristimulus values. It is always adapted
@@ -2356,7 +2295,7 @@ png_icc_find_wtpt(png_const_structrp png_ptr, png_const_charp name,
*/
{
png_uint_32 tag_length;
- png_uint_32 tag_start = png_find_icc_tag(profile, 0x77747074/*'wtpt'*/,
+ png_uint_32 tag_start = png_icc_find_tag(profile, 0x77747074/*'wtpt'*/,
&tag_length);
if (tag_start > 0 && tag_length == 20)
@@ -2378,59 +2317,68 @@ png_icc_find_wtpt(png_const_structrp png_ptr, png_const_charp name,
* profile "sRGB Profile.icc".) In that profile the mediaWhitePointTag
* is incorrectly recorded with the D65 (not D50) values.
*/
+ if (adapted_white_point != NULL)
+ {
+ (*adapted_white_point)[0] = png_get_int_32(tag+ 8);
+ (*adapted_white_point)[1] = png_get_int_32(tag+12);
+ (*adapted_white_point)[2] = png_get_int_32(tag+16);
+ }
+
+ if (png_icc_XYZ_compare(profile+68, tag+8) == 0)
+ return 1;
+
+ /* The media white point differs from the PCS illuminant.
+ *
+ * This deserves a warning; the PNG data stream is technically invalid
+ * because either the ICC profile is wrong or the color data in the
+ * image is not encoded in the way the PNG specification expects, such
+ * that colors with r==g==b are achromatic.
+ *
+ * Notice that on write the application can write a cHRM chunk to
+ * attempt to minimize the problems this might cause, however the data
+ * has the property that the maximum of all the colorants (r,g,b ==
+ * 1,1,1) does not correspond to an achromatic color and this is
+ * impossible to represent in PNG with just cHRM.
+ *
+ * If this is a monitor of color-space class profile then the profile
+ * is wrong (the white point should always be the same as the image
+ * adopted white), otherwise a simple warning is produced.
+ */
temp = png_get_uint_32(profile+12);
- if ((temp == 0x6D6E7472 /* 'mntr' */ ||
- temp == 0x73706163 /* 'spac' */) &&
- memcmp(profile+68, tag+8, 12) != 0)
- (void)profile_error(png_ptr, NULL, name, temp,
+
+ if (temp == 0x6D6E7472 /* 'mntr' */ ||
+ temp == 0x73706163 /* 'spac' */)
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"media white point differs from image adopted white");
- (*adapted_white_point)[0] = png_get_int_32(tag+ 8);
- (*adapted_white_point)[1] = png_get_int_32(tag+12);
- (*adapted_white_point)[2] = png_get_int_32(tag+16);
- return 1;
+ else
+ png_warning(png_ptr, "ICC profile indicates that image data does "
+ "not conform to the PNG specification");
+
+ return 0;
}
else
- (void)profile_error(png_ptr, NULL, name, temp,
+ {
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"invalid type for mediaWhitePointTag");
+ /* Assume it matches the PCS illuminant */
+ }
}
- else /* This should have been caught before */
- png_error(png_ptr, "lost 'wtpt'");
-
- return 0;
-}
+ /* else: no mediaWhitePointTag, already reported */
-static int
-png_icc_find_XYZ(png_const_structrp png_ptr, png_const_charp name,
- png_const_bytep profile, png_uint_32 tag_id, png_icc_vectorrp column)
-{
- png_uint_32 tag_length;
- png_uint_32 tag_start = png_find_icc_tag(profile, tag_id, &tag_length);
-
- if (tag_start > 0 && tag_length == 20)
+ /* Here if the mediaWhitePointTag is absent or invalid, assume the PCS
+ * illuminant; this is an error in the profile, but is mostly harmless.
+ */
+ if (adapted_white_point != NULL)
{
- png_const_bytep tag = profile+tag_start;
- png_uint_32 temp = png_get_uint_32(tag);
-
- if (temp == 0x58595A20 /* 'XYZ ' */)
- {
- (*column)[0] = png_get_int_32(tag+ 8);
- (*column)[1] = png_get_int_32(tag+12);
- (*column)[2] = png_get_int_32(tag+16);
- return 1;
- }
-
- else
- (void)profile_error(png_ptr, NULL, name, temp,
- "invalid type for <rgb>MatrixColumnTag");
+ (*adapted_white_point)[0] = png_get_int_32(profile+68);
+ (*adapted_white_point)[1] = png_get_int_32(profile+72);
+ (*adapted_white_point)[2] = png_get_int_32(profile+76);
}
- else /* This should have been caught before */
- png_error(png_ptr, "lost '[c]XYZ'");
-
- return 0;
+ return 1;
}
static int /* 0: fail, 1: identity, 2: not identity */
@@ -2459,7 +2407,7 @@ png_icc_find_chad(png_const_structrp png_ptr, png_const_charp name,
{
png_uint_32 tag_start, tag_length;
- tag_start = png_find_icc_tag(profile, 0x63686164/*'chad'*/, &tag_length);
+ tag_start = png_icc_find_tag(profile, 0x63686164/*'chad'*/, &tag_length);
if (tag_start > 0)
{
@@ -2487,17 +2435,17 @@ png_icc_find_chad(png_const_structrp png_ptr, png_const_charp name,
inverted_adaptation_matrix))
return 2;
- (void)profile_error(png_ptr, NULL, name, temp,
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"singular or overflowed ICC profile chromaticAdaptationTag");
}
else
- (void)profile_error(png_ptr, NULL, name, temp,
+ (void)png_icc_profile_error(png_ptr, NULL, name, temp,
"invalid type for ICC profile chromaticAdaptationTag");
}
else /* Internal libpng error */
- (void)profile_error(png_ptr, NULL, name, tag_length,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_length,
"invalid length for ICC profile chromaticAdaptationTag");
}
@@ -2519,171 +2467,14 @@ png_icc_find_chad(png_const_structrp png_ptr, png_const_charp name,
return 0;
}
-static int
-png_icc_set_cHRM_from_chrm(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile)
- /* Find the PNG cHRM chunk values from the chromaticityTag entry from the ICC
- * profile. This tag stores the chromaticities of the colorants unadapted to
- * the PCS white, however the white point, which tells us the relative
- * intensity of the colorants, is not given. We can get the white point from
- * the mediaWhitePointTag value, which should be present in all profiles,
- * however this is adapted to the PCS illuminated/adopted white, so must be
- * unadapted.
- */
-{
- png_uint_32 tag_length;
- png_uint_32 tag_start = png_find_icc_tag(profile, 0x6368726D/* 'chrm' */,
- &tag_length);
-
- if (tag_start > 0 && tag_length == 36)
- {
- png_const_bytep tag = profile+tag_start;
- png_uint_32 temp = png_get_uint_32(tag);
-
- if (temp == 0x6368726D && /* type must be 'chrm' */
- png_get_uint_16(tag+8) == 3) /* three channels */
- {
- png_xy cHRM_xy;
-
- tag += 12;
-
- /* The ICC chromaticities are stored as 16.16 unsigned numbers,
- * convert to png_fixed_point, because the ICC values are
- * unsigned the >>1 below is used to avoid unsigned/signed
- * overflow.
- */
- if (png_muldiv(&cHRM_xy.redx,
- (png_int_32)(png_get_uint_32(tag+ 0)>>1), PNG_FP_1, 65536>>1) &&
- png_muldiv(&cHRM_xy.redy,
- (png_int_32)(png_get_uint_32(tag+ 4)>>1), PNG_FP_1, 65536>>1) &&
- png_muldiv(&cHRM_xy.greenx,
- (png_int_32)(png_get_uint_32(tag+ 8)>>1), PNG_FP_1, 65536>>1) &&
- png_muldiv(&cHRM_xy.greeny,
- (png_int_32)(png_get_uint_32(tag+12)>>1), PNG_FP_1, 65536>>1) &&
- png_muldiv(&cHRM_xy.bluex,
- (png_int_32)(png_get_uint_32(tag+16)>>1), PNG_FP_1, 65536>>1) &&
- png_muldiv(&cHRM_xy.bluey,
- (png_int_32)(png_get_uint_32(tag+20)>>1), PNG_FP_1, 65536>>1))
- {
- /* We need a white point chromaticity too, this comes from the
- * media white point, but the value in the profile is adapted
- * to the PCS illuminant (D50) so must be unadapted first.
- */
- png_icc_vector adapted_profile_white;
-
- if (png_icc_find_wtpt(png_ptr, name, profile,
- &adapted_profile_white))
- {
- png_icc_vector profile_white;
- png_icc_matrix adaptation, inverted_adaptation;
-
- /* The media white point tag is chromatically adapted using the
- * chromatic adaptation matrix and so the adaptation must be
- * inverted to find the original white point.
- */
- switch (png_icc_find_chad(png_ptr, name, profile, &adaptation,
- &inverted_adaptation))
- {
- default: /* error */
- return 0;
-
- case 1: /* identity */
- break;
-
- case 2: /* apply the matrix */
- if (!png_matrix_x_vector(png_cpm(inverted_adaptation),
- png_cpv(adapted_profile_white), &profile_white))
- {
- (void)profile_error(png_ptr, NULL, name, 0,
- "overflow unadapting mediaWhitePointTag");
- return 0;
- }
-
- break;
- }
-
- {
- /* For the perfect reflector 'Y' shall be normalized
- * to 1,0 (see ICC 2010 4.14, XYZNumber), but this is
- * the media white point (not the adopted white)
- * adapted to the PCS illuminant, so Y might be some
- * other value, this sanity check is mainly to avoid
- * integer overflow.
- */
- png_int_32 white = profile_white[0] + profile_white[1] +
- profile_white[2];
-
- /* This is a hard error because it makes the profile
- * meaningless.
- */
- if (profile_white[0] < 0 || profile_white[0] > 655360 ||
- profile_white[1] < 0 || profile_white[1] > 655360 ||
- profile_white[2] < 0 || profile_white[2] > 655360 ||
- white < 1000 || white > 655360)
- (void)profile_error(png_ptr, NULL, name, 0,
- "bad XYZ in media white point");
-
- else
- {
- /* We want X/(X+Y+Z)*PNG_FP_1 to scale back to a
- * png_fixed_point value, this may produce ridiculous
- * numbers, but the checking on a png_xy value
- * detects them.
- */
- if (png_muldiv(&cHRM_xy.whitex, profile_white[0], PNG_FP_1,
- white) &&
- png_muldiv(&cHRM_xy.whitey, profile_white[0], PNG_FP_1,
- white))
- {
- png_XYZ cHRM_XYZ;
-
- /* This function returns 0 on success: */
- if (!png_colorspace_check_xy(&cHRM_XYZ, &cHRM_xy))
- return png_colorspace_set_xy_and_XYZ(png_ptr,
- colorspace, &cHRM_xy, &cHRM_XYZ,
- 0/*not preferred*/);
-
- /* Else the XYZ value was invalid */
- (void)profile_error(png_ptr, NULL, name, temp,
- "invalid colorantTableTag end points");
- }
-
- else
- return profile_error(png_ptr, colorspace, name, 0,
- "overflow in media white point chromaticities");
- }
- }
- } /* 'wtpt' exists and is valid */
-
- else
- (void)profile_error(png_ptr, NULL, name, 0,
- "missing or invalid mediaWhitePointTag");
- } /* 'chrm' tag convertion to png_xy ok */
-
- else
- (void)profile_error(png_ptr, NULL, name, 0,
- "overflow in ICC 'chrm' tag chromaticities");
- }
-
- else
- (void)profile_error(png_ptr, NULL, name, temp,
- "invalid type or colorant count for ICC profile chromaticityTag");
- }
-
- else /* checked before, so should not fail */
- png_error(png_ptr, "lost 'chrm'");
-
- return 0;
-}
-
-static int
+static void
png_icc_set_cHRM_from_endpoints(png_const_structrp png_ptr,
png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile,
- png_const_icc_matrixrp XYZ)
+ png_const_uint_16p pcsxyz)
/* The input XYZ values are the three red, green, blue endpoints still
* adapted to the PCS illuminant. The adaptation is inverted and the result
* applied to the profile. The result is also checked against the
- * mediaWhitePointTag, which should match the sum of the end points.
+ * PCS illuminant, which should match the sum of the end points.
*/
{
png_icc_matrix adaptation, inverted_adaptation;
@@ -2692,98 +2483,69 @@ png_icc_set_cHRM_from_endpoints(png_const_structrp png_ptr,
if (chad) /* else error finding 'chad' */
{
- png_icc_matrix end_points;
+ png_byte end_point_white[3*4];
+ png_icc_matrix XYZ, end_points;
- if ((colorspace->icc_info & PNG_ICC_mediaWhitePointTag) != 0)
+ /* Sanity check the adapted colorants against the PCS white point -
+ * because of the checks performed before calling this routine the adapted
+ * colorant white point should always match the PCS illuminant.
+ */
{
- png_icc_vector profile_white;
+ int i;
- if (png_icc_find_wtpt(png_ptr, name, profile, &profile_white))
+ for (i=0; i<3; ++i)
{
- png_icc_vector end_point_white;
- int i;
+ png_int_32 c = pcsxyz[i];
- /* Sanity check the adapted colorants against the adapted
- * media white point.
- */
- for (i=0; i<3; ++i)
- end_point_white[i] = (*XYZ)[0][i] + (*XYZ)[1][i] + (*XYZ)[2][i];
+ c += pcsxyz[i+3];
+ c += pcsxyz[i+6];
+ /* Convert u1Fixed15Number to s15Fixed16Number */
+ png_save_int_32(end_point_white+4*i, 2*c);
+ }
- /* The values are s15Fixed16Number values. The delta value allows
- * the two versions of the end point to differ by about 0.001 (1 in
- * 1024) and this is consistent with the test in
- * png_colorspace_set_xy_and_XYZ above.
+ if (png_icc_XYZ_compare(profile+68, end_point_white) != 0)
+ {
+ /* The colorant (media) white point differs from the PCS illuminant.
*/
- if (PNG_OUT_OF_RANGE(profile_white[0], end_point_white[0], 64) ||
- PNG_OUT_OF_RANGE(profile_white[1], end_point_white[1], 64) ||
- PNG_OUT_OF_RANGE(profile_white[2], end_point_white[2], 64))
- {
- /* It is possible that the white point stored was not adapted to
- * the PCS illuminant, check for that case here and do not abort
- * setting cHRM if it seems to be true.
- */
- png_icc_vector adapted_white;
-
- if (chad != 2 /* Else no chad */ ||
- !png_matrix_x_vector(png_cpm(adaptation),
- png_cpv(profile_white), &adapted_white) ||
- PNG_OUT_OF_RANGE(adapted_white[0], end_point_white[0], 64) ||
- PNG_OUT_OF_RANGE(adapted_white[1], end_point_white[1], 64) ||
- PNG_OUT_OF_RANGE(adapted_white[2], end_point_white[2], 64))
- {
- (void)profile_error(png_ptr, NULL, name, 0,
- "colorant end-points do not match mediaWhitePointTag");
- return 0;
- }
-
- else
- {
- /* This happens because some writers of profiles (and,
- * perhaps, some CMS software) no not notice that the
- * mediaWhitePointTag requires the XYZ of the white point
- * adapted to the PCS illuminant (using the chad); this is why
- * the mediaWhitePointTag is always D50 for display profiles!
- */
- (void)profile_error(png_ptr, NULL, name, 0,
- "ICC.1:2010 9.2.34 mediaWhitePointTag not adapted to PCS"
- " Illuminant (ignored)");
- }
- }
+ (void)png_icc_profile_error(png_ptr, NULL, name,
+ colorspace->icc_info,
+ "colorant white point differs from image adopted white");
+ return;
}
-
- else
- png_error(png_ptr, "lost 'wtpt'"); /* internal error */
}
- switch (chad)
{
- default: /* error */
- return 0;
+ int row, col;
- case 1: /* identity */
- memcpy(&end_points, XYZ, sizeof end_points);
- break;
+ /* The png_icc_matrix is a matrix of s15Fixed16Number, the pcsxyz
+ * returned by the CMS is u1Fixed15, so multiply by 65536/32768
+ */
+ for (row=0; row<3; ++row) for (col=0; col<3; ++col)
+ XYZ[row][col] = 2 * pcsxyz[3*row + col];
+ }
- case 2: /* apply the matrix */
- /* The input XYZ rows are unadapted using the 'chad' matrix and
- * assigned to the end_points rows.
- */
- if (!png_matrix_x_TmatrixT(png_cpm(inverted_adaptation), XYZ,
- &end_points))
- {
- (void)profile_error(png_ptr, NULL, name, 0,
- "overflow unadapting colorant end-points");
- return 0;
- }
+ if (chad == 1) /* identity */
+ memcpy(&end_points, XYZ, sizeof end_points);
- break;
+ else /* apply the matrix */
+ {
+ /* The input XYZ rows are unadapted using the 'chad' matrix and
+ * assigned to the end_points rows.
+ */
+ if (!png_matrix_x_TmatrixT(png_cpm(inverted_adaptation), png_cpm(XYZ),
+ &end_points))
+ {
+ (void)png_icc_profile_error(png_ptr, NULL, name, 0,
+ "overflow unadapting colorant end-points");
+ return;
+ }
}
{
png_XYZ cHRM_XYZ;
/* Now we have colorant XYZ values in their unadapted form
- * (i.e. implicitly with an adopted white of the media).
+ * (i.e. implicitly with an adopted white of the original scene).
* This is what PNG uses for cHRM, but they need to be
* converted to the libpng structure.
*
@@ -2808,154 +2570,129 @@ png_icc_set_cHRM_from_endpoints(png_const_structrp png_ptr,
/* This function returns 0 on success: */
if (!png_colorspace_check_XYZ(&xy, &cHRM_XYZ))
- return png_colorspace_set_xy_and_XYZ(png_ptr,
- colorspace, &xy, &cHRM_XYZ, 0/*not preferred*/);
+ {
+ /* TODO: review this, it currently overwrites an explicit cHRM
+ * chunk, this seems safer as the cHRM chunk is often calculated
+ * incorrectly. In release builds this overwrites silently,
+ * in pre-release it will cause an error.
+ */
+ (void)png_colorspace_set_xy_and_XYZ(png_ptr,
+ colorspace, &xy, &cHRM_XYZ,
+ (PNG_LIBPNG_BUILD_BASE_TYPE < PNG_LIBPNG_BUILD_RC) ? 1 : 2);
+ return;
+ }
/* Else the XYZ value was invalid */
- (void)profile_error(png_ptr, NULL, name, 0,
+ (void)png_icc_profile_error(png_ptr, NULL, name, 0,
"invalid colorant end-points");
}
else
- (void)profile_error(png_ptr, NULL, name, 0,
+ (void)png_icc_profile_error(png_ptr, NULL, name, 0,
"overflow converting colorant end-points to cHRM");
}
}
-
- return 0;
}
-static int
-png_icc_set_cHRM_from_clrt(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile)
- /* Find the cHRM values from the colorantTableTag, if present. The
- * colorantTableTag ('clrt') lists the PCS values as three 16-bit integer
- * (0..65535) for each colorant. Beause these are PCS values they have been
- * adapted to the profile color space, so the corresponding L*a*b* or XYZ
- * values may need to be converted back to the unadapted values by applying
- * the inverse of chromaticAdaptationTag. Note that the values in the
- * colorantTableTag can also be derived directly by passing the maximum value
- * for each colorant through the AToB1Tag transformation, but this is a lot
- * more work.
- */
+#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
+/* This is defined below, so a forward declaration is needed here. */
+static png_int_32 png_log16bit(png_uint_32 x);
+#endif
+
+static void
+png_icc_set_gAMA_from_Y(png_const_structrp png_ptr, png_colorspacerp colorspace,
+ png_uint_32 y, int is_u1Fixed15/*scale of y*/)
{
- png_uint_32 tag_length, tag_start;
+ /* PNG gAMA approximates the actual transfer function used to encode
+ * the image data with a single number in a power law equation:
+ *
+ * image = sample ^ gAMA
+ *
+ * So given a test image value (GRAY_TEST) and the value of Y, 'y',
+ * which the transform produces we can simply deduce the value of gAMA:
+ *
+ * gAMA = log(GRAY_TEST)/log(y)
+ *
+ * However this will produce different answers for each point on the
+ * profile, unless the profile really is a simple power law transform
+ * (this is hardly ever found in practice.)
+ *
+ * In fact most image encoding uses some variant of a linear segment
+ * followed by a power law - sRGB, ITU REC709 and L*a*b* all do this.
+ * We know (from the PNG spec) that sRGB should be encoded with a gAMA
+ * of .45455 (1/2.2) and it is easy to find that the sRGB transfer
+ * function crosses this power law transfer at about 0.389222. This is
+ * 25508 as a 16-bit value or 99.25 in 8-bits.
+ */
+# define GRAY_TEST 99 /* /255 */
+ /*
+ * Feeding this number through the above equations (see
+ * contrib/tools/icc-gamma.bc) gives the following results:
+ *
+ * sRGB: 45455
+ * L*a*b*: 42069
+ * 2.2 power law: 45455
+ * ITU REC-709: 52333 (because of the linear segment)
+ * Apple Mac: 65087 (by applying a 1.45 power law to sRGB)
+ */
+# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
+ double dl;
- tag_start = png_find_icc_tag(profile, 0x636C7274/*'clrt'*/, &tag_length);
+ if (is_u1Fixed15) y *= 2;
- if (tag_start > 0 && tag_length == 126)
- {
- /* The type is also 'clrt' (note that the tag table has already been
- * checked to ensure all tags are at least 8 bytes long!) The checks
- * below ensure that the tag is exactly the expected size.
- */
- png_const_bytep tag = profile+tag_start;
- png_uint_32 temp = png_get_uint_32(tag+0);
+ /* The constant is 100000*log(99/255) */
+ dl = floor(.5 - 94614.36950238362194 / log(y / 65535.));
- if (temp == 0x636C7274/*'clrt'*/)
+ /* We expect a reasonable gAMA value from this calculation; check for a
+ * number in the range 20,000 (.2) to 200,000 (2).
+ */
+ if (dl > 20000. && dl < 200000.)
{
- temp = png_get_uint_32(tag+8);
-
- if (temp == 3) /* count */
- {
- int i, j;
- png_icc_matrix XYZ; /* end points, r,g,b in each row */
-
- /* Colorants are 38 byte structures consisting of a 32 byte
- * name followed by three two byte PCS values. Read the three
- * values and convert PCSLAB to PCSXYZ if necessary.
- *
- *
- * NOTE: these values are (0..65535) and must be scaled to the
- * actual output range before use. The PCSXYZ 16-bit format is
- * u1Fixed15Number in which 1,0 is 0x8000. The PCSLAB 16-bit format
- * is somewhat more complex - see ICC 2010 (v4) 6.3.4.2
- */
- tag += 12 + 32;
- for (i=0; i<3; ++i, tag += 32) for (j=0; j<3; ++j, tag += 2)
- XYZ[i][j] = png_get_uint_16(tag);
-
- if ((colorspace->icc_info & PNG_ICC_PCSXYZ) != 0)
- {
- /* Convert from u1Fixed15Number to s15Fixed16Number */
- for (i=0; i<3; ++i) for (j=0; j<3; ++j)
- XYZ[i][j] = (XYZ[i][j] << 1) + (XYZ[i][j] >> 15);
- }
+ png_int_32 l = (png_int_32)dl;
+# else
+ /* The fixed point calculation is somewhat more complex.
+ *
+ * Because PCSXYZ is scaled by 32768, whereas the input to png_log16bit
+ * is scaled by 65535 the value of 'l' corresponds to y*32768/65535,
+ * thus the required calculation is:
+ *
+ * 100000 * 89456.43138
+ * gAMA = --------------------
+ * l + 65535
+ *
+ * l = 65536*-log2(y)
+ * 89456 = -65536*log2(99/255)
+ * 65535 = -65536*log2(32768/65535) (but only for PCSXYZ)
+ *
+ * 8945643138 = 1581061 * 5658
+ */
+ png_int_32 l = png_log16bit(y);
- else
- {
- /* Convert from the 16 bit Lab format to 32 bit XYZ */
- /* TODO: implement this */
- png_warning(png_ptr,
- "TODO: skipping ICC 'clrt' tag because PCS is Lab");
- return 0;
- }
+ if (is_u1Fixed15 && l >= 0)
+ l += 65535; /* Overflow will just make this negative */
- return png_icc_set_cHRM_from_endpoints(png_ptr, colorspace, name,
- profile, png_cpm(XYZ));
+ if (png_muldiv(&l, 1581061, 5658, l) && l >= 20000 && l <= 200000)
+ {
+# endif
+ if (png_colorspace_check_gamma(png_ptr, colorspace, l,
+ 0/*from profile*/))
+ {
+ /* Store this gamma value. */
+ colorspace->gamma = l;
+ colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
}
-
- else
- (void)profile_error(png_ptr, NULL, name, temp,
- "invalid colorant count for ICC profile colorantTableTag");
}
else
- (void)profile_error(png_ptr, NULL, name, temp,
- "invalid type for ICC profile colorantTableTag");
- }
-
- else
- png_error(png_ptr, "lost 'clrt'");
-
- return 0; /* error or 'clrt' not found */
-}
-
-static int
-png_icc_set_cHRM_from_MatrixTRC(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile)
-{
- /* The profile contains a set of RGB Matrix and TRC tags, these can be used
- * to find the colorant XYZ in the PCS encoding (which must be PCSXYZ.)
- * This is a simplistic implementation which does not run the curve (TRC)
- * part and assumes that 1,0 maps to 1,0 in the matrix (or at least to the
- * same scaled value in each case.)
- *
- * This applies to true 3-component Matrix TRC profiles and the profiles
- * produced by lcms where the MatrixColumnTag values are used in place of the
- * ColorantTableTag on non-TRC profiles, however these profiles still fail to
- * set a cHRM because the mediaWhitePointTag value is wrong (an example is
- * SA216x.icc, a scanner profile copyright Samsung for the Samnsung CLX-216x
- * scanner and with CMS type lcms).
- */
- png_icc_matrix XYZ; /* end points, r,g,b in each row */
-
- if (png_icc_find_XYZ(png_ptr, name, profile, 0x7258595A/*rXYZ*/, XYZ+0) &&
- png_icc_find_XYZ(png_ptr, name, profile, 0x6758595A/*gXYZ*/, XYZ+1) &&
- png_icc_find_XYZ(png_ptr, name, profile, 0x6258595A/*bXYZ*/, XYZ+2))
- {
- /* TODO: run r/g/b through the TRCs to check that the TRC transformed
- * values for 0 and 1 really are 0 and 1!
- */
- return png_icc_set_cHRM_from_endpoints(png_ptr, colorspace, name, profile,
- png_cpm(XYZ));
- }
-
- return 0;
-}
-
-static int
-png_icc_set_cHRM_from_LUT(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile)
-{
- /* TODO: implement this */
- PNG_UNUSED(png_ptr)
- PNG_UNUSED(colorspace)
- PNG_UNUSED(name)
- PNG_UNUSED(profile)
-
- return 0;
+ {
+ /* This is just a warning that the algorithm has failed in an
+ * apparently extreme way. (This is here mainly to discover
+ * profiles on which the algorithm doesn't work.)
+ */
+ png_warning(png_ptr, "ICC profile gamma value out of range");
+ }
}
+#endif /* PNG_ICC_SUPPORTED */
int /* PRIVATE */
png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
@@ -2989,7 +2726,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* only a warning here because libpng does not care about the
* alignment.
*/
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"ICC profile tag start not a multiple of 4");
}
@@ -2998,7 +2735,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
if (tag_length < 8)
{
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"short ICC profile tag skipped");
continue;
}
@@ -3007,7 +2744,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* profile.
*/
if (tag_start > profile_length || tag_length > profile_length - tag_start)
- return profile_error(png_ptr, colorspace, name, tag_id,
+ return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
"ICC profile tag outside profile");
/* Check the tag_id for the specific tags which must be present for the
@@ -3031,7 +2768,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* bytes).
*/
if (tag_length != 20)
- (void)profile_error(png_ptr, NULL, name, tag_length,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_length,
"invalid media white point length");
else
@@ -3044,7 +2781,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* white was the same as the PCS adopted white - D50.
*/
if (tag_length != 44)
- (void)profile_error(png_ptr, NULL, name, tag_start,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_start,
"invalid chromatic adaptation matrix length");
else
@@ -3071,11 +2808,11 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* clearly outlawed by the specification.
*/
if (tag_length != 20)
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid <rgb>MatrixColumnTag length");
else if (!(tags & PNG_ICC_RGB))
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid <rgb>MatrixColumnTag on monochrome profile");
else
@@ -3101,11 +2838,11 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* requires special handling below.
*/
if (!(tags & PNG_ICC_RGB))
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid <rgb>TRCTag on monochrome profile");
else if (!(tags & PNG_ICC_PCSXYZ))
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid <rgb>TRCTag (requires PCSXYZ encoding)");
else
@@ -3115,7 +2852,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
case 0x6B545243: /* 'kTRC' - grayTRCTag */
if ((tags & PNG_ICC_RGB) != 0)
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid grayTRCTag on RGB profile");
else
@@ -3131,7 +2868,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* is shortest, only 12 bytes for an identity response.
*/
if (tag_length < 12)
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid <rgbk>TRCTag length");
else
@@ -3169,7 +2906,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* longer. In fact all need more data than this in practice.
*/
if (tag_length < 32)
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid LUT Tag length");
else
@@ -3185,7 +2922,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* number of channels, the permitted type is chromaticityType.
*/
if (tag_length != 12 + 8*PNG_ICC_CHANNELS(tags))
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid chromaticityTag length");
else
@@ -3197,7 +2934,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* colorants are determined by the number of channels, as above.
*/
if (tag_length != 12 + 38*PNG_ICC_CHANNELS(tags))
- (void)profile_error(png_ptr, NULL, name, tag_id,
+ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"invalid colorantTableTag length");
else
@@ -3326,12 +3063,12 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* information and will probably result in a second warning here.
*/
if ((required_tags & ~tags) != 0)
- (void)profile_error(png_ptr, NULL, name, (required_tags & ~tags),
- "required tags missing");
+ (void)png_icc_profile_error(png_ptr, NULL, name,
+ (required_tags & ~tags), "required tags missing");
if ((tags & ~permitted_tags) != 0)
- (void)profile_error(png_ptr, NULL, name, (tags & ~permitted_tags),
- "unpermitted tags present");
+ (void)png_icc_profile_error(png_ptr, NULL, name,
+ (tags & ~permitted_tags), "unpermitted tags present");
}
return 1; /* success, maybe with warnings */
@@ -3421,8 +3158,8 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)
{
if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
- png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
- png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
+ png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
+ png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
{
/* This may be one of the old HP profiles without an MD5, in that
@@ -3477,14 +3214,8 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
* discourage their use, skip the 'have_md5' warning below,
* which is made irrelevant by this error.
*/
-# ifdef PNG_READ_SUPPORTED
- if (png_ptr->mode & PNG_IS_READ_STRUCT)
- png_chunk_benign_error(png_ptr,
- "known incorrect sRGB profile");
- else
-# endif
- png_app_error(png_ptr,
- "known incorrect sRGB profile");
+ png_chunk_report(png_ptr, "known incorrect sRGB profile",
+ PNG_CHUNK_ERROR);
}
/* Warn that this being done; this isn't even an error since
@@ -3493,14 +3224,9 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
*/
else if (!png_sRGB_checks[i].have_md5)
{
-# ifdef PNG_READ_SUPPORTED
- if (png_ptr->mode & PNG_IS_READ_STRUCT)
- png_chunk_warning(png_ptr,
- "out-of-date sRGB profile with no signature");
- else
-# endif
- png_app_warning(png_ptr,
- "out-of-date sRGB profile with no signature");
+ png_chunk_report(png_ptr,
+ "out-of-date sRGB profile with no signature",
+ PNG_CHUNK_WARNING);
}
return 1+png_sRGB_checks[i].is_broken;
@@ -3524,31 +3250,22 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
}
#endif
-int /* PRIVATE */
+void /* PRIVATE */
png_icc_set_gAMA_and_cHRM(png_const_structrp png_ptr,
png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile,
uLong adler)
{
- int set;
- png_uint_32 info;
-
# ifdef PNG_sRGB_SUPPORTED
+ {
/* 1) Is this profile one of the known ICC sRGB profiles? If it is, just
* set the sRGB information.
*/
- set = png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler);
+ int set = png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler);
- if (set)
+ /* It is, simply set the profile intent. */
+ if (set && png_colorspace_set_sRGB(png_ptr, colorspace,
+ (int)/*already checked*/png_get_uint_32(profile+64)))
{
- /* It is, simply set the profile intent. */
- int done = png_colorspace_set_sRGB(png_ptr, colorspace,
- (int)/*already checked*/png_get_uint_32(profile+64),
- 0/* check gAMA and cHRM against sRGB but do not override */);
-
- /* Stop here on error */
- if (!done)
- return done;
-
# if PNG_LIBPNG_BUILD_BASE_TYPE < PNG_LIBPNG_BUILD_RC
/* In pre-RC builds run sRGB profiles through the profile checking
* code; this is because it is a useful validation of that code and
@@ -3560,93 +3277,112 @@ png_icc_set_gAMA_and_cHRM(png_const_structrp png_ptr,
*/
if (set >= 2)
# endif
- return set;
+ return;
}
+ }
+# else
+ PNG_UNUSED(adler)
+# ifndef PNG_ICC_SUPPORTED
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(colorspace)
+ PNG_UNUSED(profile)
+# endif
# endif
+#ifdef PNG_ICC_SUPPORTED
/* 2) Attempt to extract the gAMA and cHRM information from non-sRGB
* profiles. Always set the rendering intent from the profile.
+ *
+ * Doing this requires a large body of code to parse an ICC profile and
+ * implement ICC color correction. This is because the profile tags that
+ * store colorant information are rarely, if ever, present in practice.
+ * It is therefore necessary to follow the algorithm described in section
+ * 10.4 (colorantTableType) and transform the RGB colorants through the
+ * full profile.
+ *
+ * Similarly to calculate a value for the PNG gAMA chunk it is necessary
+ * to process at least one gray level through the transform.
+ *
+ * The code to do this relies on a CMS implementation provided by the
+ * application.
*/
- info = colorspace->icc_info;
-
- /* The cHRM chunk is only useful for an RGB image/profile, note that the
- * check on 'set' causes pre-RC builds to do a spurious check on sRGB
- * profiles, this validates the libpng algorithms because the known sRGB
- * profiles are known to be correct.
- */
- if ((info & PNG_ICC_RGB) != 0 &&
- (set || (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) == 0))
+ if (png_ptr->cms_transform_fn != NULL) /* Else no support */
{
- /* There are three ways to determine the correct value for cHRM, in order
- * of preference they are:
- *
- * 1) Use 'chrm' - the chromaticityTag - if present for the colorant
- * chromaticities and combine this with the chromaticity of the media
- * white point (unadapted).
- * 2) Use 'clrt' - the colorantTableTag - if present; reverse the
- * adaptation of the colorant end points the PCS illuminant and
- * use the XYZ values so obtained to set the cHRM values.
- * 3) Use the XYZ values of the colorant obtained following section 10.4
- * of the ICC 2010 (v4) specification in the 'EXAMPLE' paragraph. The
- * specification states that the AToB1Tag should be used, but the
- * Matrix TRC method is also colorimetric (see Table 25) and works in
- * older profiles too.
- *
- * For methods (2) and (3) the mediaWhitePointTag provides a check - it
- * should match the sum of the adapted colorant end points.
+ png_uint_32 info = colorspace->icc_info;
+ png_alloc_size_t sample_bytes = 0/*error*/;
+ png_uint_16 pcsxyz[4/*samples*/ * 3/*components*/];
+
+ /* The input array; we want one sample to work out the gAMA chunk value
+ * and, for color images, three samples with the colorant endpoints. The
+ * sample used for gAMA calculation is discussed below. This gives the
+ * following byte array which works for either case (RGB or grayscale):
*/
- if ((info & (PNG_ICC_chromaticityTag|PNG_ICC_mediaWhitePointTag)) ==
- (PNG_ICC_chromaticityTag|PNG_ICC_mediaWhitePointTag) &&
- png_icc_set_cHRM_from_chrm(png_ptr, colorspace, name, profile))
+ static const png_byte samples[] =
{
- /* finished */
- }
-
- else if ((info & PNG_ICC_colorantTableTag) != 0 &&
- png_icc_set_cHRM_from_clrt(png_ptr, colorspace, name, profile))
- {
- /* finished */
- }
-
- /* (3): divided into two caes, where we have the MatrixColumnTags for all
- * columns of the Matrix (and may have TRC tags too) as opposed to the
- * case where the AToB LUT has to be used.
- *
- * At present only do this if the full set of TRC *and* MatrixColumn tags
- * are present. The code will handle the case where there is just the
- * MatrixColumn set, and some lcms profiles have MatrixColumn but no TRC,
- * but this seems to be erroneous (the result does not match the
- * mediaWhitePointTag.)
+ GRAY_TEST, GRAY_TEST, GRAY_TEST, /* see png_icc_set_gAMA_from_Y */
+ 255, 0, 0, /* red */
+ 0, 255, 0, /* green */
+ 0, 0, 255 /* blue */
+ };
+
+ /* The cHRM chunk is only useful for an RGB image/profile, note that the
+ * check on 'set' causes pre-RC builds to do a spurious check on sRGB
+ * profiles, this validates the libpng algorithms because the known sRGB
+ * profiles are known to be correct (except for the 'broken' ones which
+ * are excluded by the 'set >= 2' test above.)
*/
- else if ((info & PNG_ICC_REQUIRED_RGB_MATRIXTRC) ==
- PNG_ICC_REQUIRED_RGB_MATRIXTRC &&
- png_icc_set_cHRM_from_MatrixTRC(png_ptr, colorspace, name, profile))
+ if ((info & PNG_ICC_RGB) != 0)
{
- /* finished */
+ if ((info & PNG_ICC_mediaWhitePointTag) == 0 /* Assume D50 */ ||
+ png_icc_check_wtpt(png_ptr, name, profile, NULL))
+ {
+ /* The mediaWhitePointTag is absent (an error, but we assume
+ * it was meant to be D50) or is sufficiently close to the PCS
+ * illuminant. This is the normal case.
+ *
+ * The code does not actually need the media white point,
+ * because it is the same as the PCS illuminant if we get to
+ * this point.
+ */
+ sample_bytes = sizeof samples; /* i.e. all of them */
+ }
+
+ else
+ {
+ /* The mediaWhitePointTag has a major problem or doesn't match
+ * the PCS illuminant. A cHRM chunk cannot be generated for
+ * this profile, so just do gAMA:
+ */
+ sample_bytes = 3; /* Just the gray value */
+ }
}
- else if ((info & PNG_ICC_AToB_TAGS) != 0 &&
- png_icc_set_cHRM_from_LUT(png_ptr, colorspace, name, profile))
+ else
{
- /* finished */
+ /* This is a grayscale image/profile, so just do gAMA */
+ sample_bytes = 1;
}
- } /* 'RGB ' profile */
- /* TODO: implement discovery of gAMA. */
+ /* Now apply the transform. */
+ if (png_ptr->cms_transform_fn(png_ptr, png_ptr->cms_data_ptr, samples,
+ sample_bytes, pcsxyz, sizeof pcsxyz, 0/*format*/,
+ PNG_sRGB_INTENT_RELATIVE))
+ {
+ /* First handle the gAMA based on the 'Y' value in pcsxyz, it is either
+ * a grayscale 16-bit achromatic value with 1.0 represented as 65535 or
+ * a the Y part of a PCSXYZ value with 1.0 represented as 32768.
+ */
+ png_uint_32 y = (sample_bytes != 1 ? pcsxyz[1] : pcsxyz[0]);
+ png_icc_set_gAMA_from_Y(png_ptr, colorspace, y, sample_bytes != 1);
- /* Only write the intent if there is no other setting; the intent recorded in
- * the profile is somewhat curious since the profile can have support for
- * several intents.
- */
- if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) == 0)
- {
- colorspace->rendering_intent = (png_uint_16)/*already checked*/
- png_get_uint_32(profile+64);
- colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
- set = 2;
+ if (sample_bytes == sizeof samples) /* RGB samples too */
+ png_icc_set_cHRM_from_endpoints(png_ptr, colorspace, name,
+ profile, pcsxyz+3/*skip the gamma sample*/);
+ } /* sample_bytes > 0 */
}
-
- return set;
+#else
+ PNG_UNUSED(name)
+#endif /* PNG_ICC_SUPPORTED */
}
int /* PRIVATE */
diff --git a/png.h b/png.h
index 6273ddaf3..897416b8f 100644
--- a/png.h
+++ b/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.0beta31 - October 24, 2012
+ * libpng version 1.6.0beta31 - October 26, 2012
* Copyright (c) 1998-2012 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.6.0beta31 - October 24, 2012: Glenn
+ * libpng versions 0.97, January 1998, through 1.6.0beta31 - October 26, 2012: Glenn
* See also "Contributing Authors", below.
*
* Note about libpng version numbers:
@@ -198,7 +198,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.2.6, August 15, 2004, through 1.6.0beta31, October 24, 2012, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.6.0beta31, October 26, 2012, are
* Copyright (c) 2004, 2006-2012 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:
@@ -310,7 +310,7 @@
* Y2K compliance in libpng:
* =========================
*
- * October 24, 2012
+ * October 26, 2012
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
@@ -378,7 +378,7 @@
/* Version information for png.h - this should match the version in png.c */
#define PNG_LIBPNG_VER_STRING "1.6.0beta31"
#define PNG_HEADER_VERSION_STRING \
- " libpng version 1.6.0beta31 - October 24, 2012\n"
+ " libpng version 1.6.0beta31 - October 26, 2012\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -3204,6 +3204,90 @@ PNG_EXPORT(242, void, png_set_check_for_invalid_index,
(png_structrp png_ptr, int allowed));
#endif
+/*******************************************************************************
+ * CMS (Color Management System) SUPPORT
+ *******************************************************************************
+ *
+ * The PNG file format supports embedding of ICC profiles, however libpng
+ * provides only limited support for handling these profiles. In particular
+ * libpng includes no support for using the profile to transform data into a
+ * different color space. If PNG_ICC_SUPPORTED is set, however, libpng allows
+ * an external CMS to be registered into the png_struct after it is created.
+ * This simply records a single callback function to transform samples between
+ * two color spaces.
+ */
+typedef struct png_cms_data *png_cms_datap, * PNG_RESTRICT png_cms_datarp;
+ /* An opaque type defined by a specific implementation to hold whatever data
+ * is required. The implementation is responsible for all storage management
+ * of this data.
+ */
+
+typedef PNG_CALLBACK(png_uint_32, *png_cms_transform_ptr,
+ (png_const_structrp png_ptr, png_cms_datarp data_ptr, png_const_voidp input,
+ png_alloc_size_t input_bytes, png_voidp output,
+ png_alloc_size_t output_bytes, int format, int intent));
+ /* Transform input[input_bytes] of samples to output[output_bytes]. The
+ * format of the input and output is given by 'format'. The function shall
+ * transform only so much input as there is space for in the output buffer.
+ * 'intent' is the ICC intent required for the transformation.
+ *
+ * The connection space data (which may be either the input or output) is
+ * always either 16-bit achromatic data (as described in Annex F.2 of the v4
+ * ICC specification) for grayscale PNG files or 16-bit PCSXYZ data for RGB
+ * PNG files. Any alpha channel may be present in the connection space, in
+ * which case it is a 16-bit channel and the alpha value follows each sample.
+ * Samples are not pre-multiplied by the alpha. The connection space data
+ * is stored as an array of png_uint_16 values in the native representation
+ * of the machine.
+ *
+ * For transforms to the connection space the input is in the PNG format
+ * using either 8-bit or big-endian 16-bit components. 16-bit quantities use
+ * the PNG layout - big-endian in two bytes.
+ *
+ * By default a transform from the connection space will be to 8-bit sRGB
+ * (with an optional alpha value) or 8-bit gray encoded with the inverse of
+ * the sRGB transfer function. If png_set_cms_output is called, however, the
+ * transform may produce arbitrary output in a format potentially not handled
+ * by libpng.
+ *
+ * It is valid to register a CMS when writing a PNG image, however the CMS
+ * will only be used to generate appropriate values for cHRM and gAMA of the
+ * profile.
+ *
+ * The format parameter is made up of the following flags:
+ */
+#define PNG_CMS_FORMAT_FLAG_ALPHA 0x01 /* data has alpha channel */
+#define PNG_CMS_FORMAT_FLAG_16BIT 0x02 /* 16-bit image components else 8-bit */
+#define PNG_CMS_FORMAT_FLAG_PCS 0x04 /* input is PCS data, else image data */
+
+#ifdef PNG_ICC_SUPPORTED
+PNG_EXPORT(243, void, png_set_cms, (png_structrp png_ptr,
+ png_cms_datap cms_data_ptr, png_cms_transform_ptr cms_transform_function));
+ /* Register the CMS transform function. The given pointer will be passed to
+ * every call to the function.
+ */
+
+#ifdef PNG_READ_SUPPORTED
+PNG_EXPORT(244, void, png_set_cms_output, (png_structrp png_ptr,
+ int bytes_per_pixel, int rendering_intent));
+ /* Inform libpng that the transform function will write output requiring
+ * bytes_per_pixel bytes for each sample. The output need not be in any
+ * particular format, for example the transform could produce a print
+ * separation. libpng will provide a buffer equal in size to the row width
+ * of the image times the bytes_per_pixel value (and the application must
+ * provide this size buffer.)
+ *
+ * This also forces the CMS transform to be used even when it is apparently
+ * not necessary (e.g. for sRGB input data, or for PNG files with no ICC
+ * profile information and no sRGB data.) The intent overrides the default,
+ * which is perceptual.
+ */
+#endif
+#endif
+/*******************************************************************************
+ * END OF CMS (Color Management System) SUPPORT
+ ******************************************************************************/
+
/* Maintainer: Put new public prototypes here ^, in libpng.3, and project
* defs
*/
@@ -3213,7 +3297,7 @@ PNG_EXPORT(242, void, png_set_check_for_invalid_index,
* scripts/symbols.def as well.
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(242);
+ PNG_EXPORT_LAST_ORDINAL(244);
#endif
#ifdef __cplusplus
diff --git a/pngerror.c b/pngerror.c
index dbc6534ba..a97778b3c 100644
--- a/pngerror.c
+++ b/pngerror.c
@@ -510,6 +510,41 @@ png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
#endif
#endif /* PNG_READ_SUPPORTED */
+void /* PRIVATE */
+png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
+{
+ /* This is always supported, but for just read or just write it
+ * unconditionally does the right thing.
+ */
+# if (defined PNG_READ_SUPPORTED) && (defined PNG_WRITE_SUPPORTED)
+ if (png_ptr->mode & PNG_IS_READ_STRUCT)
+# endif
+
+# ifdef PNG_READ_SUPPORTED
+ {
+ if (error < PNG_CHUNK_ERROR)
+ png_chunk_warning(png_ptr, message);
+
+ else
+ png_chunk_benign_error(png_ptr, message);
+ }
+# endif
+
+# if (defined PNG_READ_SUPPORTED) && (defined PNG_WRITE_SUPPORTED)
+ else if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
+# endif
+
+# ifdef PNG_WRITE_SUPPORTED
+ {
+ if (error < PNG_CHUNK_WRITE_ERROR)
+ png_app_warning(png_ptr, message);
+
+ else
+ png_app_error(png_ptr, message);
+ }
+# endif
+}
+
#ifdef PNG_ERROR_TEXT_SUPPORTED
#ifdef PNG_FLOATING_POINT_SUPPORTED
PNG_FUNCTION(void,
diff --git a/pngpriv.h b/pngpriv.h
index b01c00d10..6c46e47e0 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -1406,9 +1406,12 @@ PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info,
/* Added at libpng version 1.6.0 */
#ifdef PNG_GAMMA_SUPPORTED
-PNG_INTERNAL_FUNCTION(int,png_colorspace_set_gamma,(png_const_structrp png_ptr,
- png_colorspacerp colorspace, png_fixed_point gAMA, int preferred),
- PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,
+ png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY);
+ /* Set the colorspace gamma with a value provided by the application or by
+ * the gAMA chunk on read. The value will override anything set by an ICC
+ * profile.
+ */
PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr,
png_inforp info_ptr), PNG_EMPTY);
@@ -1436,7 +1439,12 @@ PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints,
#ifdef PNG_sRGB_SUPPORTED
PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr,
- png_colorspacerp colorspace, int intent, int preferred), PNG_EMPTY);
+ png_colorspacerp colorspace, int intent), PNG_EMPTY);
+ /* This does set the colorspace gAMA and cHRM values too, but doesn't set the
+ * flags to write them, if it returns false there was a problem and an error
+ * message has already been output (but the colorspace may still need to be
+ * synced to record the invalid flag).
+ */
#endif /* sRGB */
#ifdef PNG_iCCP_SUPPORTED
@@ -1459,14 +1467,15 @@ PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,
png_colorspacerp colorspace, png_const_charp name,
png_uint_32 profile_length,
png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(int,png_icc_set_gAMA_and_cHRM,(
+PNG_INTERNAL_FUNCTION(void,png_icc_set_gAMA_and_cHRM,(
png_const_structrp png_ptr, png_colorspacerp colorspace,
png_const_charp name, png_const_bytep profile, uLong adler), PNG_EMPTY);
/* 'adler' is the Adler32 checksum of the uncompressed profile data. It may
* be zero to indicate that it is not available. It is used, if provided,
- * as a fast check on the profile when checking to see if it is sRGB. The
- * result is false only if an error is detected in the profile; the routine
- * may return true without actually setting cHRM and gAMA values.
+ * as a fast check on the profile when checking to see if it is sRGB.
+ * The routine may not set gAMA or cHRM if there are problems in the profile,
+ * however none of these problems are fatal (the profile has already been
+ * checked.)
*/
#endif /* iCCP */
@@ -1598,6 +1607,21 @@ PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,
# define png_app_error(pp,s) png_error(pp,s)
#endif
+PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,
+ png_const_charp message, int error),PNG_EMPTY);
+ /* Report a recoverable issue in chunk data. On read this is used to report
+ * a problem found while reading a particular chunk and the
+ * png_chunk_benign_error or png_chunk_warning function is used as
+ * appropriate. On write this is used to report an error that comes from
+ * data set via an application call to a png_set_ API and png_app_error or
+ * png_app_warning is used as appropriate.
+ *
+ * The 'error' parameter must have one of the following values:
+ */
+#define PNG_CHUNK_WARNING 0 /* never an error */
+#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */
+#define PNG_CHUNK_ERROR 2 /* always an error */
+
/* ASCII to FP interfaces, currently only implemented if sCAL
* support is required.
*/
diff --git a/pngrutil.c b/pngrutil.c
index 83a580497..b76b8dd8a 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -1087,31 +1087,7 @@ png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
igamma = png_get_fixed_point(NULL, buf);
- /* The gAMA value is unsigned (and is a power law correction, so 0 is
- * meaningless.)
- */
- if (igamma <= 0)
- {
- png_chunk_benign_error(png_ptr, "out of range");
- return;
- }
-
- /* If a colorspace error has already been output skip this chunk */
- if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
- return;
-
- if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA)
- {
- png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
- png_colorspace_sync(png_ptr, info_ptr);
-
- png_chunk_benign_error(png_ptr, "duplicate");
- return;
- }
-
- png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA;
- (void)png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma,
- 1/*prefer gAMA values*/);
+ png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);
png_colorspace_sync(png_ptr, info_ptr);
}
#endif
@@ -1285,13 +1261,6 @@ png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
if (png_crc_finish(png_ptr, 0))
return;
- /* Check for bad intent */
- if (intent >= PNG_sRGB_INTENT_LAST)
- {
- png_chunk_benign_error(png_ptr, "Unknown sRGB intent");
- return;
- }
-
/* If a colorspace error has already been output skip this chunk */
if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
return;
@@ -1307,16 +1276,7 @@ png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
return;
}
- /* Do not override gAMA or cHRM from the PNG file; just check they match.
- * This is because we write a cHRM which corresponds to D65, however there is
- * an issue with CMMs that assume a D50 environment that requires adaptation
- * of the white point. This way at least it is possible to supply an
- * adapated value (so long as it is within the tolerance limits for a match
- * against the D65 chromaticities.)
- *
- * TODO: get expert opinions on this issue
- */
- (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent, 0);
+ png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
png_colorspace_sync(png_ptr, info_ptr);
}
#endif /* PNG_READ_sRGB_SUPPORTED */
@@ -1475,8 +1435,6 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
/* But otherwise allow extra data: */
else if (size == 0)
{
- int ok;
-
if (length > 0)
{
/* This can be handled completely, so
@@ -1493,12 +1451,12 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
* checks for a known sRGB profile. The
* result is 0 on error.
*/
- ok = png_icc_set_gAMA_and_cHRM(png_ptr,
+ png_icc_set_gAMA_and_cHRM(png_ptr,
&png_ptr->colorspace, keyword, profile,
png_ptr->zstream.adler);
/* Steal the profile for info_ptr. */
- if (ok && info_ptr != NULL)
+ if (info_ptr != NULL)
{
png_free_data(png_ptr, info_ptr,
PNG_FREE_ICCP, 0);
@@ -1534,15 +1492,11 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
if (info_ptr != NULL)
png_colorspace_sync(png_ptr, info_ptr);
- if (errmsg == NULL && ok)
+ if (errmsg == NULL)
{
png_ptr->zowner = 0;
return;
}
-
- /* else png_icc_set_gAMA_and_cHRM has
- * already output an error.
- */
}
else if (size > 0)
diff --git a/pngset.c b/pngset.c
index b905ae38d..30a348e6a 100644
--- a/pngset.c
+++ b/pngset.c
@@ -143,25 +143,8 @@ png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
if (png_ptr == NULL || info_ptr == NULL)
return;
- /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
- * occur. Since the fixed point representation is assymetrical it is
- * 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 truly ridiculous gamma values (and will produce
- * displays that are all black or all white.)
- */
- if (file_gamma < 16 || file_gamma > 625000000)
- png_app_error(png_ptr, "Out of range gamma value ignored");
-
- else
- {
- if (png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma,
- 2/* overrided with app value */))
- info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA;
-
- png_colorspace_sync_info(png_ptr, info_ptr);
- }
+ png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
+ png_colorspace_sync_info(png_ptr, info_ptr);
}
# ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -595,9 +578,7 @@ png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
if (png_ptr == NULL || info_ptr == NULL)
return;
- (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent,
- 2/* app value overrides*/);
-
+ png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
png_colorspace_sync_info(png_ptr, info_ptr);
}
@@ -610,10 +591,9 @@ png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent,
- 2/* app value overrides*/))
+ if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent))
{
- /* And cause the gAMA and cHRM to be written too */
+ /* This causes the gAMA and cHRM to be written too */
info_ptr->colorspace.flags |=
PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
}
@@ -1570,4 +1550,34 @@ png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
}
#endif
+#ifdef PNG_ICC_SUPPORTED
+void PNGAPI
+png_set_cms(png_structrp png_ptr, png_cms_datap cms_data_ptr,
+ png_cms_transform_ptr cms_transform_function)
+{
+ png_ptr->cms_transform_fn = cms_transform_function;
+ png_ptr->cms_data_ptr = cms_data_ptr;
+}
+
+#ifdef PNG_READ_SUPPORTED
+void PNGAPI
+png_set_cms_output(png_structrp png_ptr, int bytes_per_pixel,
+ int rendering_intent)
+{
+ if (png_ptr->mode & PNG_IS_READ_STRUCT)
+ {
+ png_ptr->cms_bytes_per_pixel = bytes_per_pixel;
+ png_ptr->cms_intent = rendering_intent;
+
+ /* A CMS must be registered before calling this */
+ if (png_ptr->cms_transform_fn == NULL)
+ png_app_error(png_ptr, "no CMS registered to transform output");
+ }
+
+ else
+ png_app_error(png_ptr, "attempt to do CMS tranform on write");
+}
+#endif /* PNG_READ_SUPPORTED */
+#endif /* PNG_ICC_SUPPORTED */
+
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/pngstruct.h b/pngstruct.h
index a0a913b5a..ab1d789ad 100644
--- a/pngstruct.h
+++ b/pngstruct.h
@@ -203,8 +203,9 @@ typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
#define PNG_COLORSPACE_HAVE_INTENT 0x0004
#define PNG_COLORSPACE_FROM_gAMA 0x0008
#define PNG_COLORSPACE_FROM_cHRM 0x0010
-#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0020
-#define PNG_COLORSPACE_MATCHES_sRGB 0x0040 /* exact match on profile */
+#define PNG_COLORSPACE_FROM_sRGB 0x0020
+#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040
+#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */
#define PNG_COLORSPACE_INVALID 0x8000
#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags))
#endif /* COLORSPACE || GAMMA */
@@ -547,5 +548,17 @@ struct png_struct_def
png_colorspace colorspace;
#endif
#endif
+
+#ifdef PNG_ICC_SUPPORTED
+ /* Full ICC support requires an external CMS be registered in the png_struct
+ * after it is created. The registration stores this information.
+ */
+ png_cms_transform_ptr cms_transform_fn;
+ png_cms_datap cms_data_ptr;
+#ifdef PNG_READ_SUPPORTED
+ int cms_bytes_per_pixel; /* non-standard output size */
+ int cms_intent; /* for non-standard output */
+#endif
+#endif /* PNG_ICC_SUPPORTED */
};
#endif /* PNGSTRUCT_H */
diff --git a/pngwutil.c b/pngwutil.c
index 51b2c4569..73b1de7a0 100644
--- a/pngwutil.c
+++ b/pngwutil.c
@@ -29,23 +29,6 @@ png_save_uint_32(png_bytep buf, png_uint_32 i)
buf[3] = (png_byte)(i & 0xff);
}
-#ifdef PNG_SAVE_INT_32_SUPPORTED
-/* The png_save_int_32 function assumes integers are stored in two's
- * complement format. If this isn't the case, then this routine needs to
- * be modified to write data in two's complement format. Note that,
- * the following works correctly even if png_int_32 has more than 32 bits
- * (compare the more complex code required on read for sign extention.)
- */
-void PNGAPI
-png_save_int_32(png_bytep buf, png_int_32 i)
-{
- buf[0] = (png_byte)((i >> 24) & 0xff);
- buf[1] = (png_byte)((i >> 16) & 0xff);
- buf[2] = (png_byte)((i >> 8) & 0xff);
- buf[3] = (png_byte)(i & 0xff);
-}
-#endif
-
/* Place a 16-bit number into a buffer in PNG byte order.
* The parameter is declared unsigned int, not png_uint_16,
* just to avoid potential problems on pre-ANSI C compilers.
diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa
index b5b1fca67..0a3c659c7 100644
--- a/scripts/pnglibconf.dfa
+++ b/scripts/pnglibconf.dfa
@@ -478,6 +478,20 @@ option WRITE_TEXT requires WRITE_ANCILLARY_CHUNKS enables TEXT
option GAMMA disabled
option COLORSPACE enables GAMMA disabled
+# ICC profile support; basic ICC profile support is enabled if iCCP chunk read
+# or write is enabled. The application must perform all iCCP profile handling
+# itself. If full support is enabled with the option below libpng will attempt
+# to do more processing using the profile data itself, this includes setting
+# appropriate values for cHRM and gAMA chunks if not present in the stream.
+#
+# ICC profile support is not build in to core libpng because of the size of the
+# code required; an external ICC implementation must be passed to libpng to
+# enable it.
+#
+# WARNING: this option is CURRENTLY UNTESTED because a test CMS implementation
+# has not yet been written, as a result it is disabled in current beta builds.
+option ICC requires iCCP enables SAVE_INT_32 disabled
+
# When an ICC profile is read, or png_set, it will be checked for a match
# against known sRGB profiles if the sRGB handling is enabled. This
# setting controls how much work is done during the check:
@@ -694,9 +708,10 @@ option CONVERT_tIME requires WRITE_ANCILLARY_CHUNKS
option WRITE_FILTER requires WRITE
-option SAVE_INT_32 requires WRITE
-
-# png_save_int_32 is required by the ancillary chunks oFFs and pCAL
+option SAVE_INT_32 disabled
+# png_save_int_32 is required internally for writing the ancillary chunks oFFs
+# and pCAL and for both reading and writing iCCP (for the generation/checking of
+# the corresponding cHRM/gAMA chunks) if full ICC is supported.
# added at libpng-1.5.4
diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt
index eb45a9fdd..59cc1ce95 100644
--- a/scripts/pnglibconf.h.prebuilt
+++ b/scripts/pnglibconf.h.prebuilt
@@ -3,7 +3,7 @@
/* pnglibconf.h - library build configuration */
-/* Libpng 1.6.0beta31 - October 24, 2012 */
+/* Libpng 1.6.0beta31 - October 26, 2012 */
/* Copyright (c) 1998-2012 Glenn Randers-Pehrson */
@@ -63,6 +63,7 @@
#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
#define PNG_hIST_SUPPORTED
#define PNG_iCCP_SUPPORTED
+/*#undef PNG_ICC_SUPPORTED*/
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
diff --git a/scripts/symbols.def b/scripts/symbols.def
index 10074f2fc..92c0a703c 100644
--- a/scripts/symbols.def
+++ b/scripts/symbols.def
@@ -205,7 +205,6 @@ EXPORTS
png_get_y_offset_inches @197
png_get_pHYs_dpi @198
png_get_io_state @199
-;png_get_io_chunk_name @200
png_get_uint_32 @201
png_get_uint_16 @202
png_get_int_32 @203
@@ -248,3 +247,5 @@ EXPORTS
png_image_write_to_stdio @240
png_convert_to_rfc1123_buffer @241
png_set_check_for_invalid_index @242
+ png_set_cms @243
+ png_set_cms_output @244
diff --git a/scripts/symbols.dfn b/scripts/symbols.dfn
index d790929e7..7d0d3d050 100644
--- a/scripts/symbols.dfn
+++ b/scripts/symbols.dfn
@@ -42,6 +42,7 @@
#define PNG_READ_BIG_ENDIAN_SUPPORTED /* should do nothing! */
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+#define PNG_ICC_SUPPORTED /* currently disabled */
#undef PNG_H
#include "../png.h"