[devel] Fixes to rgb_to_gray and cHRM XYZ APIs
This commit is contained in:
parent
0c03fc6f75
commit
736f40f459
17
ANNOUNCE
17
ANNOUNCE
@ -1,5 +1,5 @@
|
||||
|
||||
Libpng 1.5.5beta06 - August 17, 2011
|
||||
Libpng 1.5.5beta06 - August 25, 2011
|
||||
|
||||
This is not intended to be a public release. It will be replaced
|
||||
within a few weeks by a public version or by another test version.
|
||||
@ -62,9 +62,22 @@ Version 1.5.5beta05 [August 17, 2011]
|
||||
Added new types and internal functions for CIE RGB end point handling to
|
||||
pngpriv.h (functions yet to be implemented).
|
||||
|
||||
Version 1.5.5beta06 [August 17, 2011]
|
||||
Version 1.5.5beta06 [August 25, 2011]
|
||||
Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set in CMakeLists.txt
|
||||
(Clifford Yap)
|
||||
Fixes to rgb_to_gray and cHRM XYZ APIs (John Bowler):
|
||||
The rgb_to_gray code had errors when combined with gamma correction.
|
||||
Some pixels were treated as true grey when they weren't and such pixels
|
||||
and true grey ones were not gamma corrected (the original value of the
|
||||
red component was used instead). APIs to get and set cHRM using color
|
||||
space end points have been added and the rgb_to_gray code that defaults
|
||||
based on cHRM (introduced in 1.5.4) has been corrected. A considerable
|
||||
number of tests has been added to pngvalid for the rgb_to_gray transform.
|
||||
Arithmetic errors in rgb_to_gray whereby the calculated gray value was
|
||||
truncated to the bit depth rather than rounded have been fixed except in
|
||||
the 8-bit non-gamma-corrected case (where consistency seems more important
|
||||
than correctness.) The code still has considerable inaccuracies in the
|
||||
8-bit case because 8-bit linear arithmetic is used.
|
||||
|
||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net:
|
||||
(subscription required; visit
|
||||
|
15
CHANGES
15
CHANGES
@ -3546,9 +3546,22 @@ Version 1.5.5beta05 [August 17, 2011]
|
||||
Added new types and internal functions for CIE RGB end point handling to
|
||||
pngpriv.h (functions yet to be implemented).
|
||||
|
||||
Version 1.5.5beta06 [August 17, 2011]
|
||||
Version 1.5.5beta06 [August 25, 2011]
|
||||
Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set in CMakeLists.txt
|
||||
(Clifford Yap)
|
||||
Fixes to rgb_to_gray and cHRM XYZ APIs (John Bowler):
|
||||
The rgb_to_gray code had errors when combined with gamma correction.
|
||||
Some pixels were treated as true grey when they weren't and such pixels
|
||||
and true grey ones were not gamma corrected (the original value of the
|
||||
red component was used instead). APIs to get and set cHRM using color
|
||||
space end points have been added and the rgb_to_gray code that defaults
|
||||
based on cHRM (introduced in 1.5.4) has been corrected. A considerable
|
||||
number of tests has been added to pngvalid for the rgb_to_gray transform.
|
||||
Arithmetic errors in rgb_to_gray whereby the calculated gray value was
|
||||
truncated to the bit depth rather than rounded have been fixed except in
|
||||
the 8-bit non-gamma-corrected case (where consistency seems more important
|
||||
than correctness.) The code still has considerable inaccuracies in the
|
||||
8-bit case because 8-bit linear arithmetic is used.
|
||||
|
||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
||||
(subscription required; visit
|
||||
|
@ -1,6 +1,6 @@
|
||||
libpng-manual.txt - A description on how to use and modify libpng
|
||||
|
||||
libpng version 1.5.5beta06 - August 17, 2011
|
||||
libpng version 1.5.5beta06 - August 25, 2011
|
||||
Updated and distributed by Glenn Randers-Pehrson
|
||||
<glennrp at users.sourceforge.net>
|
||||
Copyright (c) 1998-2011 Glenn Randers-Pehrson
|
||||
@ -11,7 +11,7 @@ libpng-manual.txt - A description on how to use and modify libpng
|
||||
|
||||
Based on:
|
||||
|
||||
libpng versions 0.97, January 1998, through 1.5.5beta06 - August 17, 2011
|
||||
libpng versions 0.97, January 1998, through 1.5.5beta06 - August 25, 2011
|
||||
Updated and distributed by Glenn Randers-Pehrson
|
||||
Copyright (c) 1998-2011 Glenn Randers-Pehrson
|
||||
|
||||
@ -4509,7 +4509,7 @@ Other rules can be inferred by inspecting the libpng source.
|
||||
|
||||
XIV. Y2K Compliance in libpng
|
||||
|
||||
August 17, 2011
|
||||
August 25, 2011
|
||||
|
||||
Since the PNG Development group is an ad-hoc body, we can't make
|
||||
an official declaration.
|
||||
|
38
libpng.3
38
libpng.3
@ -1,4 +1,4 @@
|
||||
.TH LIBPNG 3 "August 17, 2011"
|
||||
.TH LIBPNG 3 "August 25, 2011"
|
||||
.SH NAME
|
||||
libpng \- Portable Network Graphics (PNG) Reference Library 1.5.5beta06
|
||||
.SH SYNOPSIS
|
||||
@ -128,10 +128,22 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.5beta06
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBpng_uint_32 png_get_chunk_cache_max (png_const_structp \fIpng_ptr\fP\fB);\fP
|
||||
\fBpng_uint_32 png_get_cHRM_XYZ (png_structp \fIpng_ptr,
|
||||
|
||||
\fBpng_const_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*red_X\fP\fB, double \fP\fI*red_Y\fP\fB, double \fI*red_Z,
|
||||
|
||||
\fBdouble \fP\fI*green_X\fP\fB, double \fP\fI*green_Y\fP\fB, double \fP\fI*green_Z\fP\fB, double \fI*blue_X,
|
||||
|
||||
\fBdouble \fP\fI*blue_Y\fP\fB, double \fI*blue_Z\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBpng_uint_32 png_get_cHRM_XYZ_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_fixed_point \fP\fI*int_red_X\fP\fB, png_fixed_point \fP\fI*int_red_Y\fP\fB, png_fixed_point \fP\fI*int_red_Z\fP\fB, png_fixed_point \fP\fI*int_green_X\fP\fB, png_fixed_point \fP\fI*int_green_Y\fP\fB, png_fixed_point \fP\fI*int_green_Z\fP\fB, png_fixed_point \fP\fI*int_blue_X\fP\fB, png_fixed_point \fP\fI*int_blue_Y\fP\fB, png_fixed_point \fI*int_blue_Z\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBpng_uint_32 png_get_chunk_cache_max (png_const_structp \fIpng_ptr\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBpng_alloc_size_t png_get_chunk_malloc_max (png_const_structp \fIpng_ptr\fP\fB);\fP
|
||||
@ -548,6 +560,16 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.5beta06
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBvoid png_set_cHRM_XYZ (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIred_X\fP\fB, double \fP\fIred_Y\fP\fB, double \fP\fIred_Z\fP\fB, double \fP\fIgreen_X\fP\fB, double \fIgreen_Y,
|
||||
|
||||
\fBdouble \fP\fIgreen_Z\fP\fB, double \fP\fIblue_X\fP\fB, double \fP\fIblue_Y\fP\fB, double \fIblue_Z\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBvoid png_set_cHRM_XYZ_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_fixed_point \fP\fIint_red_X\fP\fB, png_fixed_point \fP\fIint_red_Y\fP\fB, png_fixed_point \fP\fIint_red_Z\fP\fB, png_fixed_point \fP\fIint_green_X\fP\fB, png_fixed_point \fP\fIint_green_Y\fP\fB, png_fixed_point \fP\fIint_green_Z\fP\fB, png_fixed_point \fP\fIint_blue_X\fP\fB, png_fixed_point \fP\fIint_blue_Y\fP\fB, png_fixed_point \fIint_blue_Z\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
|
||||
\fBvoid png_set_chunk_cache_max (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIuser_chunk_cache_max\fP\fB);\fP
|
||||
|
||||
\fI\fB
|
||||
@ -955,7 +977,7 @@ Following is a copy of the libpng-manual.txt file that accompanies libpng.
|
||||
.SH LIBPNG.TXT
|
||||
libpng-manual.txt - A description on how to use and modify libpng
|
||||
|
||||
libpng version 1.5.5beta06 - August 17, 2011
|
||||
libpng version 1.5.5beta06 - August 25, 2011
|
||||
Updated and distributed by Glenn Randers-Pehrson
|
||||
<glennrp at users.sourceforge.net>
|
||||
Copyright (c) 1998-2011 Glenn Randers-Pehrson
|
||||
@ -966,7 +988,7 @@ libpng-manual.txt - A description on how to use and modify libpng
|
||||
|
||||
Based on:
|
||||
|
||||
libpng versions 0.97, January 1998, through 1.5.5beta06 - August 17, 2011
|
||||
libpng versions 0.97, January 1998, through 1.5.5beta06 - August 25, 2011
|
||||
Updated and distributed by Glenn Randers-Pehrson
|
||||
Copyright (c) 1998-2011 Glenn Randers-Pehrson
|
||||
|
||||
@ -5465,7 +5487,7 @@ Other rules can be inferred by inspecting the libpng source.
|
||||
|
||||
.SH XIV. Y2K Compliance in libpng
|
||||
|
||||
August 17, 2011
|
||||
August 25, 2011
|
||||
|
||||
Since the PNG Development group is an ad-hoc body, we can't make
|
||||
an official declaration.
|
||||
@ -5724,7 +5746,7 @@ possible without all of you.
|
||||
|
||||
Thanks to Frank J. T. Wojcik for helping with the documentation.
|
||||
|
||||
Libpng version 1.5.5beta06 - August 17, 2011:
|
||||
Libpng version 1.5.5beta06 - August 25, 2011:
|
||||
Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
|
||||
Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net).
|
||||
|
||||
@ -5747,7 +5769,7 @@ this sentence.
|
||||
|
||||
This code is released under the libpng license.
|
||||
|
||||
libpng versions 1.2.6, August 15, 2004, through 1.5.5beta06, August 17, 2011, are
|
||||
libpng versions 1.2.6, August 15, 2004, through 1.5.5beta06, August 25, 2011, are
|
||||
Copyright (c) 2004,2006-2007 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
|
||||
@ -5846,7 +5868,7 @@ certification mark of the Open Source Initiative.
|
||||
|
||||
Glenn Randers-Pehrson
|
||||
glennrp at users.sourceforge.net
|
||||
August 17, 2011
|
||||
August 25, 2011
|
||||
|
||||
.\" end of man page
|
||||
|
||||
|
339
png.c
339
png.c
@ -617,13 +617,13 @@ png_get_copyright(png_const_structp png_ptr)
|
||||
#else
|
||||
# ifdef __STDC__
|
||||
return PNG_STRING_NEWLINE \
|
||||
"libpng version 1.5.5beta06 - August 17, 2011" PNG_STRING_NEWLINE \
|
||||
"libpng version 1.5.5beta06 - August 25, 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.5beta06 - August 17, 2011\
|
||||
return "libpng version 1.5.5beta06 - August 25, 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 +713,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 +789,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_chunk_benign_error(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,
|
||||
|
33
png.h
33
png.h
@ -1,7 +1,7 @@
|
||||
|
||||
/* png.h - header file for PNG reference library
|
||||
*
|
||||
* libpng version 1.5.5beta06 - August 17, 2011
|
||||
* libpng version 1.5.5beta06 - August 25, 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.5beta06 - August 17, 2011: Glenn
|
||||
* libpng versions 0.97, January 1998, through 1.5.5beta06 - August 25, 2011: Glenn
|
||||
* See also "Contributing Authors", below.
|
||||
*
|
||||
* Note about libpng version numbers:
|
||||
@ -189,7 +189,7 @@
|
||||
*
|
||||
* This code is released under the libpng license.
|
||||
*
|
||||
* libpng versions 1.2.6, August 15, 2004, through 1.5.5beta06, August 17, 2011, are
|
||||
* libpng versions 1.2.6, August 15, 2004, through 1.5.5beta06, August 25, 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:
|
||||
@ -301,7 +301,7 @@
|
||||
* Y2K compliance in libpng:
|
||||
* =========================
|
||||
*
|
||||
* August 17, 2011
|
||||
* August 25, 2011
|
||||
*
|
||||
* Since the PNG Development group is an ad-hoc body, we can't make
|
||||
* an official declaration.
|
||||
@ -364,7 +364,7 @@
|
||||
/* Version information for png.h - this should match the version in png.c */
|
||||
#define PNG_LIBPNG_VER_STRING "1.5.5beta06"
|
||||
#define PNG_HEADER_VERSION_STRING \
|
||||
" libpng version 1.5.5beta06 - August 17, 2011\n"
|
||||
" libpng version 1.5.5beta06 - August 25, 2011\n"
|
||||
|
||||
#define PNG_LIBPNG_VER_SONUM 15
|
||||
#define PNG_LIBPNG_VER_DLLNUM 15
|
||||
@ -2048,6 +2048,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,
|
||||
@ -2057,6 +2061,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
|
||||
@ -2064,12 +2075,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
|
||||
@ -2577,7 +2598,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
|
||||
|
95
pngget.c
95
pngget.c
@ -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
|
||||
|
@ -1166,7 +1166,12 @@ typedef struct png_XYZ
|
||||
png_fixed_point blueX, blueY, blueZ;
|
||||
} png_XYZ;
|
||||
|
||||
/* The conversion APIs return 0 on success, non-zero on a parameter error. */
|
||||
/* 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,
|
||||
|
388
pngrtran.c
388
pngrtran.c
@ -968,13 +968,17 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
|
||||
{
|
||||
png_uint_16 red_int, green_int;
|
||||
|
||||
/* 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*32768L)/100000L);
|
||||
green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
|
||||
|
||||
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;
|
||||
@ -3089,26 +3094,38 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
|
||||
*
|
||||
* Y = (6966 * R + 23436 * G + 2366 * B)/32768
|
||||
*
|
||||
* We use the approximation
|
||||
* 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:
|
||||
*
|
||||
* 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.4, if the image being converted has the
|
||||
* sRGB chunk, then the sRGB numbers are used by default:
|
||||
* 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.
|
||||
*
|
||||
* Y = 0.33000*R + 0.60000*G + 0.06000*B
|
||||
* 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.
|
||||
*
|
||||
* The calculation is to be done in a linear colorspace.
|
||||
*
|
||||
* Other integer coefficents can be used via png_set_rgb_to_gray().
|
||||
* 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");
|
||||
@ -3116,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++)];
|
||||
red = png_ptr->gamma_to_1[red];
|
||||
green = png_ptr->gamma_to_1[green];
|
||||
blue = png_ptr->gamma_to_1[blue];
|
||||
|
||||
if (red != green || red != blue)
|
||||
{
|
||||
rgb_error |= 1;
|
||||
*(dp++) = png_ptr->gamma_from_1[
|
||||
(rc*red + gc*green + bc*blue)>>15];
|
||||
}
|
||||
|
||||
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++)
|
||||
|
||||
else
|
||||
{
|
||||
png_byte red = *(sp++);
|
||||
png_byte green = *(sp++);
|
||||
png_byte blue = *(sp++);
|
||||
/* If there is no overall correction the table will not be
|
||||
* set.
|
||||
*/
|
||||
if (png_ptr->gamma_table != NULL)
|
||||
red = png_ptr->gamma_table[red];
|
||||
|
||||
if (red != green || red != blue)
|
||||
{
|
||||
rgb_error |= 1;
|
||||
*(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
|
||||
}
|
||||
|
||||
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;
|
||||
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 = *(sp++);
|
||||
png_byte green = *(sp++);
|
||||
png_byte blue = *(sp++);
|
||||
|
||||
if (red != green || red != blue)
|
||||
{
|
||||
png_uint_16 red, green, blue, w;
|
||||
rgb_error |= 1;
|
||||
/*NOTE: this is the historical approach which simply
|
||||
* truncates the results.
|
||||
*/
|
||||
*(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>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;
|
||||
else
|
||||
*(dp++) = red;
|
||||
|
||||
if (red == green && red == blue)
|
||||
w = red;
|
||||
if (have_alpha)
|
||||
*(dp++) = *(sp++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff)
|
||||
else /* RGB bit_depth == 16 */
|
||||
{
|
||||
#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;
|
||||
png_uint_32 i;
|
||||
|
||||
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)
|
||||
{
|
||||
if (png_ptr->gamma_16_table != NULL)
|
||||
w = png_ptr->gamma_16_table[(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;
|
||||
}
|
||||
|
||||
*(dp++) = (png_byte)((w>>8) & 0xff);
|
||||
*(dp++) = (png_byte)(w & 0xff);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
png_bytep sp = row;
|
||||
png_bytep dp = row;
|
||||
for (i = 0; i < row_width; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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++)];
|
||||
|
||||
if (red != green || red != blue)
|
||||
rgb_error |= 1;
|
||||
|
||||
*(dp++) = png_ptr->gamma_from_1
|
||||
[(rc*red + gc*green + bc*blue)>>15];
|
||||
|
||||
*(dp++) = *(sp++); /* alpha */
|
||||
}
|
||||
}
|
||||
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);
|
||||
*(dp++) = *(sp++); /* alpha */
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* RGBA bit_depth == 16 */
|
||||
{
|
||||
#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];
|
||||
w = red;
|
||||
}
|
||||
|
||||
png_uint_16 green_1 =
|
||||
png_ptr->gamma_16_to_1[(green&0xff) >>
|
||||
png_ptr->gamma_shift][green>>8];
|
||||
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 + 16384)>>15);
|
||||
w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
|
||||
png_ptr->gamma_shift][gray16 >> 8];
|
||||
rgb_error |= 1;
|
||||
}
|
||||
|
||||
png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
|
||||
png_ptr->gamma_shift][blue>>8];
|
||||
*(dp++) = (png_byte)((w>>8) & 0xff);
|
||||
*(dp++) = (png_byte)(w & 0xff);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*(dp++) = (png_byte)((w>>8) & 0xff);
|
||||
*(dp++) = (png_byte)(w & 0xff);
|
||||
*(dp++) = *(sp++); /* alpha */
|
||||
if (have_alpha)
|
||||
{
|
||||
*(dp++) = *(sp++);
|
||||
*(dp++) = *(sp++);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
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_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;
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
128
pngrutil.c
128
pngrutil.c
@ -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))
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
png_uint_32 w = y_red + y_green + y_blue;
|
||||
png_XYZ XYZ;
|
||||
png_xy xy;
|
||||
|
||||
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);
|
||||
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 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_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
|
||||
@ -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 */
|
||||
|
50
pngset.c
50
pngset.c
@ -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 */
|
||||
|
@ -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) */
|
||||
|
1444
pngvalid.c
1444
pngvalid.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user