From cb0b29631f36c667eb353421fdf7b81e96637d2d Mon Sep 17 00:00:00 2001 From: John Bowler Date: Thu, 12 May 2011 21:48:29 -0500 Subject: [PATCH] [devel] Documented png_set_alpha_mode(), other changes in libpng.3 and libpng-manual.txt. The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative parameters are supplied by the caller), while in the absence of cHRM sRGB/Rec 709 values are still used. The bKGD chunk no longer overwrites the background value set by png_set_background(), allowing the latter to be used before the file header is read. It never performed any useful function to override the default anyway. Send comments/corrections/commendations to png-mng-implement at lists.sf.net: (subscription required; visit --- ANNOUNCE | 14 +- CHANGES | 12 +- libpng-manual.txt | 417 +++++++++++++++++++++++++++++++++------------ libpng.3 | 425 +++++++++++++++++++++++++++++++++------------- png.h | 16 +- pngrtran.c | 38 +++-- pngrutil.c | 65 +++++-- 7 files changed, 718 insertions(+), 269 deletions(-) diff --git a/ANNOUNCE b/ANNOUNCE index 083ea2472..8dc1536b0 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.5.3beta08 - May 12, 2011 +Libpng 1.5.3beta08 - May 13, 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. @@ -112,8 +112,16 @@ Version 1.5.3beta07 [May 11, 2011] Check for up->location !PNG_AFTER_IDAT when writing unknown chunks before IDAT. -Version 1.5.3beta08 [May 12, 2011] - Improve "pngvalid --speed" to exclude more of pngvalid from the time. +Version 1.5.3beta08 [May 13, 2011] + Improved "pngvalid --speed" to exclude more of pngvalid from the time. + Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt + The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative + parameters are supplied by the caller), while in the absence of cHRM + sRGB/Rec 709 values are still used. + The bKGD chunk no longer overwrites the background value set by + png_set_background(), allowing the latter to be used before the file + header is read. It never performed any useful function to override + the default anyway. Send comments/corrections/commendations to png-mng-implement at lists.sf.net: (subscription required; visit diff --git a/CHANGES b/CHANGES index 57a2c8c69..5f3b1e988 100644 --- a/CHANGES +++ b/CHANGES @@ -3371,8 +3371,16 @@ Version 1.5.3beta07 [May 11, 2011] Check for up->location !PNG_AFTER_IDAT when writing unknown chunks before IDAT. -Version 1.5.3beta08 [May 12, 2011] - Improve "pngvalid --speed" to exclude more of pngvalid from the time. +Version 1.5.3beta08 [May 13, 2011] + Improved "pngvalid --speed" to exclude more of pngvalid from the time. + Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt + The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative + parameters are supplied by the caller), while in the absence of cHRM + sRGB/Rec 709 values are still used. + The bKGD chunk no longer overwrites the background value set by + png_set_background(), allowing the latter to be used before the file + header is read. It never performed any useful function to override + the default anyway. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/libpng-manual.txt b/libpng-manual.txt index d8c69dd5f..d1f534d13 100644 --- a/libpng-manual.txt +++ b/libpng-manual.txt @@ -1,6 +1,6 @@ libpng-manual.txt - A description on how to use and modify libpng - libpng version 1.5.3beta08 - May 11, 2011 + libpng version 1.5.3beta08 - May 13, 2011 Updated and distributed by Glenn Randers-Pehrson 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.3beta08 - May 11, 2011 + libpng versions 0.97, January 1998, through 1.5.3beta08 - May 13, 2011 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2011 Glenn Randers-Pehrson @@ -637,6 +637,223 @@ and you can retrieve the limit with Any chunks that would cause either of these limits to be exceeded will be ignored. +Information about your system + +If you intend to display the PNG or to incorporate it in other image data you +need to tell libpng information about your display or drawing surface so that +libpng can convert the values in the image to match the display. + +From libpng-1.5.3 this information can be set before reading the PNG file +header. In earlier versions png_set_gamma() existed but behaved incorrectly if +called before the PNG file header had been read and png_set_alpha_mode() did not +exist. + +If you need to support versions prior to libpng-1.5.3 test the version number +and follow the procedures described in the appropriate manual page. + +You give libpng the encoding expected by your system expressed as a 'gamma' +value. You can also specify a default encoding for the PNG file in +case the required information is missing from the file. By default libpng +assumes that the PNG data matches your system, to keep this default call: + + png_set_gamma(png_ptr, screen_gamma, 1/screen_gamma/*file gamma*/); + +or you can use the fixed point equivalent: + + png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, PNG_FP_1/screen_gamma); + +If you don't know the gamma for you system it is probably 2.2 - a good +approximation to the IEC standard for display systems (sRGB). If images are +too contrasty or washed out you got the value wrong - check your system +documentation! + +Many systems permit the system gamma to be changed via a lookup table in the +display driver, a few systems, including older Macs, change the response by +default. As of 1.5.3 three special values are available to handle common +situations: + + PNG_DEFAULT_sRGB: Indicates that the system conforms to the IEC 61966-2-1 + standard. This matches almost all systems. + PNG_GAMMA_MAC_18: Indicates that the system is an older (pre Mac OS 10.6) + Apple Macintosh system with the default settings. + PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates that the + system expects data with no gamma encoding. + +You would use the linear (unencoded) value if you need to process the pixel +values further because this avoids the need to decode and reencode each +component value whenever arithmetic is performed. A lot of graphics software +uses linear values for this reason, often with higher precision component values +to preserve overall accuracy. + +The second thing you may need to tell libpng about is how your system handles +alpha channel information. Some, but not all, PNG files contain an alpha +channel. To display these files correctly you need to compose the data onto a +suitable background, as described in the PNG specification. + +Libpng only supports composing onto a single color (using png_set_background; +see below.) Otherwise you must do the composition yourself and, in this case, +you may need to call png_set_alpha_mode: + + png_set_alpha_mode(png_ptr, mode, screen_gamma); + +The screen_gamma value is the same as the argument to png_set_gamma, however how +it effects the output depends on the mode. png_set_alpha_mode sets the file +gamma default to 1/screen_gamma, so normally you don't need to call +png_set_gamma. If you need different defaults call png_set_gamma before +png_set_alpha_mode - if you call it after it will override the settings made by +png_set_alpha_mode. + +The mode is as follows: + + PNG_ALPHA_PNG: The data is encoded according to the PNG specification. Red, + green and blue, or gray, components are gamma encoded color + values and are not premultiplied by the alpha value. The + alpha value is a linear measure of the contribution of the + pixel to the corresponding final output pixel. + + You should normally use this format if you intend to perform + color correction on the color values; most, maybe all, color + correction software has no handling for the alpha channel and, + anyway, the math to handle pre-multiplied component values is + unnecessarily complex. + + Before you do any arithmetic on the component values you need + to remove the gamma encoding and multiply out the alpha + channel. See the PNG specification for more detail. It is + important to note that when an image with an alpha channel is + scaled linear encoded, pre-multiplied, component values must + be used! + +The remaining modes assume you don't need to do any further color correction or +that if you do your color correction software knows all about alpha (it +probably doesn't!) + + PNG_ALPHA_STANDARD: The data libpng produces is encoded in the standard way + assumed by most correctly written graphics software. + The gamma encodiing will be removed by libpng and the + linear component values will be pre-multiplied by the + alpha channel. + + With this format the final image must be re-encoded to + match the display gamma before the image is displayed. + If your system doesn't do that, yet still seems to + perform arithmetic on the pixels without decoding them, + it is broken - check out the modes below. + + With PNG_ALPHA_STANDARD libpng always produces linear + component values, whatever screen_gamma you supply. The + screen_gamma value is, however, used as a default for + the file gamma if the PNG file has no gamma information. + + If you call png_set_gamma after png_set_alpha_mode you + will override the linear encoding. Instead the + pre-multiplied pixel values will be gamma encoded but + the alpha channel will still be linear. This may + actually match the requirements of some broken software, + but it is unlikely. + + While linear 8 bit data is often used it has + insufficient precision for any image with a reasonable + dynamic range. To avoid problems, and if your software + supports it, use png_set_expand_16() to force all + components to 16 bits. + + PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD except that + completely opaque pixels are gamma encoded according to + the screen_gamma value. Pixels with alpha less than 1.0 + will still have linear components. + + Use this format if you have control over your + compositing software and do don't do other arithmetic + (such as scaling) on the data you get from libpng. Your + compositing software can simply copy opaque pixels to + the output but still has linear values for the + non-opaque pixels. + + In normal compositing, where the alpha channel encodes + partial pixel coverage (as opposed to broad area + translucency), the inaccuracies of the 8 bit + representation of non-opaque pixels are irrelevant. + + You can also try this format if your software is broken; + it might look better. + + PNG_ALPHA_BROKEN This is PNG_ALPHA_STANDARD however all component values, + including the alpha channel are gamma encoded. This is + an appropriate format to try if your software, or more + likely hardware, is totally broken: if it performs + linear arithmetic directly on gamma encoded values. + +In most cases of broken software or hardware the bug in the final display +manifests as a subtle halo around composited parts of the image. You may not +even perceive this as a halo; the composited part of the image may simply appear +separate from the background, as though it had been cut out of paper and pasted +on afterward. + +If you don't have to deal with bugs in software or hardware, or if you can fix +them, there are three recommended ways of using png_set_alpha_mode: + + png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, screen_gamma); + You can do color correction on the result (libpng does not currently + support color correction internally.) When you handle the alpha channel + you need to undo the gamma encoding and multipy out the alpha. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, screen_gamma); + png_set_expand_16(png_ptr); + If you are using the high level interface don't call png_set_expand_16, + instead pass PNG_TRANSFORM_EXPAND_16 to the interface. + + With this mode you can't do color corrrection, but you can do arithmetic, + including composition and scaling, on the data without further processing. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMZED, screen_gamma); + You can avoid the expansion to 16 bit components with this mode, but you + lose the ability to scale the image or perform other linear arithmetic. + All you can do is compose the result onto a matching output. Since this + mode is libpng specific you also need to write your own composition + software. + +If you don't need, or can't handle, the alpha channel you can call +png_set_background to remove it by compositing against a fixed color. Don't +call png_set_strip_alpha to do this - it will leave spurious pixel values in +transparent parts of this image. + + png_set_background(png_ptr, &background_color, PNG_BACKGROUND_GAMMA_SCREEN, + 0, 1); + +The background_color is an RGB or grayscale value according to the data format +libpng will produce for you. Because you don't yet know the format of the PNG +file if you call png_set_background at this point you must arrange for the +format produced by libpng to always have 8-bit or 16-bit components and then +store the color as an 8-bit or 16-bit color as appropriate. The color contains +separate gray and RGB component values, so you can let libpng produce gray or +RGB output according to the input format, but low bit depth grayscale images +must always be converted to at least 8-bit format. (Even low low bit depth +grayscale images can't have an alpha channel they can have a transparent +color!) + +You set the transforms you need later, either as flags to the high level +interface or libpng API calls for the low level interface. For reference the +settings required are: + +8-bit values: + PNG_TRANSFORM_STRIP_16 | PNG_EXPAND + png_set_expand(png_ptr); png_set_strip_16(png_ptr); + +16-bit values: + PNG_TRANSFORM_EXPAND_16 + png_set_expand_16(png_ptr); + +In either case palette image data will be expanded to RGB. If you just want +color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr) +to the list. + +Calling png_set_background before the PNG file header is read will not work +prior to libpng-1.5.3. Because the failure may result in unexpected warnings or +errors it is therefore much safer to call png_set_background after the head has +been read. Unfortunately this means that prior to libpng-1.5.3 it cannot be +used with the high level interface. + The high-level read interface At this point there are two ways to proceed; through the high-level @@ -735,6 +952,22 @@ call to png_read_info(). This will process all chunks up to but not including the image data. +This also copies some of the data from the PNG file into the decode structure +for use in later transformations. Important information copied in is: + +1) The PNG file gamma from the gAMA chunk. This overwrites the default value +provided by an earlier call to png_set_gamma or png_set_alpha_mode. + +2) Prior to libpng-1.5.3 the background color from a bKGd chunk. This +damages the information provided by an earlier call to png_set_background +resulting in expected behavior. Libpng-1.5.3 no longer does this. + +3) The number of significant bits in each component value. Libpng uses this to +optimize gamma handling by reducing the internal lookup table sizes. + +4) The transparent color information from a tRNS chunk. This can be modified by +a later call to png_set_tRNS. + Querying the info structure Functions are used to get the information from the info_ptr once it @@ -1098,7 +1331,7 @@ forms: converted to microns and back without some loss of precision. -For more information, see the png_info definition in png.h and the +For more information, see the PNG specification for chunk contents. Be careful with trusting rowbytes, as some of the transformations could increase the space needed to hold a row (expand, filler, gray_to_rgb, etc.). @@ -1133,17 +1366,20 @@ to handle any special transformations of the image data. The various ways to transform the data will be described in the order that they should occur. This is important, as some of these change the color type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. +certain color types and bit depths. -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). +Transformations you request are ignored if they don't have any meaning for a +particular input data format. However some transformations can have an effect +as a result of a previous transformation. If you specify a contradictory set of +transformations, for example both adding and removing the alpha channel, you +cannot predict the final result. + +The color used for the transparency values should be supplied in the same +format/depth as the current image data. It is stored in the same format/depth +as the image data in a tRNS chunk, so this is what libpng expects for this data. + +The color used for the background value depends on the need_expand argument as +described below. Data will be decoded into the supplied row buffers packed into bytes unless the library has been told to transform it into another format. @@ -1197,18 +1433,16 @@ PNG can have files with 16 bits per channel. If you only can handle if (bit_depth == 16) png_set_strip_16(png_ptr); -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): +If you need to process the alpha channel on the image separately from the image +data (for example if you convert it to a bitmap mask) it is possible to have +libpng strip the channel leaving just RGB or gray data: if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); -See below for png_set_background(), which does the correct composition on a -single opaque color. This is probably what you should do in all cases rather -than use png_set_strip_alpha() - unless you know for sure that it is the wrong -thing to do. +If you strip the alpha channel you need to find some other way of dealing with +the information. If, instead, you want to convert the image to an opaque +version with no alpha channel use png_set_background; see below. As of libpng version 1.5.2, almost all useful expansions are supported, the major ommissions are convertion of grayscale to indexed images (which can be @@ -1342,8 +1576,8 @@ with alpha. if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); + png_set_rgb_to_gray(png_ptr, error_action, double red_weight, + double green_weight); error_action = 1: silently do the conversion @@ -1356,122 +1590,83 @@ with alpha. image has any pixel where red != green or red != blue - red_weight: weight of red component times 100000 + red_weight: weight of red component - green_weight: weight of green component times 100000 + green_weight: weight of green component If either weight is negative, default - weights (21268, 71514) are used. + weights are used. + +In the corresponding fixed point API the red_weight and green_weight values are +simply scaled by 100,000: + + png_set_rgb_to_gray(png_ptr, error_action, png_fixed_point red_weight, + png_fixed_point green_weight); If you have set error_action = 1 or 2, you can later check whether the image really was gray, after processing the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data +1 if there were any non-gray pixels. Background and sBIT data will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. +data for sBIT, regardless of the error_action setting. -With red_weight+green_weight<=100000, -the normalized graylevel is computed: +The default values come from the PNG file cHRM chunk if present, otherwise the +defaults correspond to the ITU-R recommendation 709, and also the sRGB color +space, as recommended in the Charles Poynton's Colour FAQ, +, in section 9: - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B -Libpng approximates this with integers scaled by 32768: - - Y = (6968 * R + 23434 * G + 2366 * B)/32768 - The calculation is done in a linear colorspace, if the image gamma can be determined. -If you have a grayscale and you are using png_set_expand_gray_1_2_4_to_8(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). +The png_set_background() function has been described already, it tells libpng to +composite images with alpha or simple transparency against the supplied +background color. For compatibility with versions of libpng earlier than +libpng-1.5.3 it is recommended that you call the function after reading the file +header, even if you don't want to use the color in a bKGD chunk, if one exists. + +If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng how the color is represented, both the format of the +component values in the color (the number of bits) and the gamme encoding of the +color. The function takes two arguments, background_gamma_mode and need_expand +to convey this information, however only two combinations are like to be useful: png_color_16 my_background; png_color_16p image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1); else png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1); -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. +The second call was described above - my_background is in the format of the +final, display, output produced by libpng. Because you now know the format of +the PNG it is possible to avoid the need to choose either 8 or 16 bit output and +to retain palette images (the palette colors will be modified appropriately and +the tRNS chunk removed.) However, if you are doing this, take great care not to +ask for transformations without checking first that they apply! -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. +In the first call the background color has the original bit depth and color type +of the PNG file. So, for palette images the color is supplied as a palette +index and for low bit greyscale images the color is a reduced bit value in +image_background->gray. - double gamma, screen_gamma; +If you didn't call png_set_gamma() before reading the file header, for example +if you need your code to remain compatible with older versions of libpng prior +to libpng-1.5.3, this is the place to call it. - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The functions png_set_gamma() and its fixed point equivalent -png_set_gamma_fixed() handle gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. +Do not call it if you called png_set_alpha_mode(); doing so will damage the +settings put in place by png_set_alpha_mode(). (If png_set_alpha_mode() is +supported then you can certainly do png_set_gamma() before reading the PNG +header.) This API unconditionally sets the screen and file gamma values, so it will override the value in the PNG file unless it is called before the PNG file @@ -4199,7 +4394,7 @@ Other rules can be inferred by inspecting the libpng source. XIV. Y2K Compliance in libpng -May 11, 2011 +May 13, 2011 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. diff --git a/libpng.3 b/libpng.3 index 1f6f459b0..ccc38701b 100644 --- a/libpng.3 +++ b/libpng.3 @@ -1,4 +1,4 @@ -.TH LIBPNG 3 "May 11, 2011" +.TH LIBPNG 3 "May 13, 2011" .SH NAME libpng \- Portable Network Graphics (PNG) Reference Library 1.5.3beta08 .SH SYNOPSIS @@ -951,7 +951,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.3beta08 - May 11, 2011 + libpng version 1.5.3beta08 - May 13, 2011 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2011 Glenn Randers-Pehrson @@ -962,7 +962,7 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng versions 0.97, January 1998, through 1.5.3beta08 - May 11, 2011 + libpng versions 0.97, January 1998, through 1.5.3beta08 - May 13, 2011 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2011 Glenn Randers-Pehrson @@ -1588,6 +1588,223 @@ and you can retrieve the limit with Any chunks that would cause either of these limits to be exceeded will be ignored. +.SS Information about your system + +If you intend to display the PNG or to incorporate it in other image data you +need to tell libpng information about your display or drawing surface so that +libpng can convert the values in the image to match the display. + +From libpng-1.5.3 this information can be set before reading the PNG file +header. In earlier versions png_set_gamma() existed but behaved incorrectly if +called before the PNG file header had been read and png_set_alpha_mode() did not +exist. + +If you need to support versions prior to libpng-1.5.3 test the version number +and follow the procedures described in the appropriate manual page. + +You give libpng the encoding expected by your system expressed as a 'gamma' +value. You can also specify a default encoding for the PNG file in +case the required information is missing from the file. By default libpng +assumes that the PNG data matches your system, to keep this default call: + + png_set_gamma(png_ptr, screen_gamma, 1/screen_gamma/*file gamma*/); + +or you can use the fixed point equivalent: + + png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, PNG_FP_1/screen_gamma); + +If you don't know the gamma for you system it is probably 2.2 - a good +approximation to the IEC standard for display systems (sRGB). If images are +too contrasty or washed out you got the value wrong - check your system +documentation! + +Many systems permit the system gamma to be changed via a lookup table in the +display driver, a few systems, including older Macs, change the response by +default. As of 1.5.3 three special values are available to handle common +situations: + + PNG_DEFAULT_sRGB: Indicates that the system conforms to the IEC 61966-2-1 + standard. This matches almost all systems. + PNG_GAMMA_MAC_18: Indicates that the system is an older (pre Mac OS 10.6) + Apple Macintosh system with the default settings. + PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates that the + system expects data with no gamma encoding. + +You would use the linear (unencoded) value if you need to process the pixel +values further because this avoids the need to decode and reencode each +component value whenever arithmetic is performed. A lot of graphics software +uses linear values for this reason, often with higher precision component values +to preserve overall accuracy. + +The second thing you may need to tell libpng about is how your system handles +alpha channel information. Some, but not all, PNG files contain an alpha +channel. To display these files correctly you need to compose the data onto a +suitable background, as described in the PNG specification. + +Libpng only supports composing onto a single color (using png_set_background; +see below.) Otherwise you must do the composition yourself and, in this case, +you may need to call png_set_alpha_mode: + + png_set_alpha_mode(png_ptr, mode, screen_gamma); + +The screen_gamma value is the same as the argument to png_set_gamma, however how +it effects the output depends on the mode. png_set_alpha_mode sets the file +gamma default to 1/screen_gamma, so normally you don't need to call +png_set_gamma. If you need different defaults call png_set_gamma before +png_set_alpha_mode - if you call it after it will override the settings made by +png_set_alpha_mode. + +The mode is as follows: + + PNG_ALPHA_PNG: The data is encoded according to the PNG specification. Red, + green and blue, or gray, components are gamma encoded color + values and are not premultiplied by the alpha value. The + alpha value is a linear measure of the contribution of the + pixel to the corresponding final output pixel. + + You should normally use this format if you intend to perform + color correction on the color values; most, maybe all, color + correction software has no handling for the alpha channel and, + anyway, the math to handle pre-multiplied component values is + unnecessarily complex. + + Before you do any arithmetic on the component values you need + to remove the gamma encoding and multiply out the alpha + channel. See the PNG specification for more detail. It is + important to note that when an image with an alpha channel is + scaled linear encoded, pre-multiplied, component values must + be used! + +The remaining modes assume you don't need to do any further color correction or +that if you do your color correction software knows all about alpha (it +probably doesn't!) + + PNG_ALPHA_STANDARD: The data libpng produces is encoded in the standard way + assumed by most correctly written graphics software. + The gamma encodiing will be removed by libpng and the + linear component values will be pre-multiplied by the + alpha channel. + + With this format the final image must be re-encoded to + match the display gamma before the image is displayed. + If your system doesn't do that, yet still seems to + perform arithmetic on the pixels without decoding them, + it is broken - check out the modes below. + + With PNG_ALPHA_STANDARD libpng always produces linear + component values, whatever screen_gamma you supply. The + screen_gamma value is, however, used as a default for + the file gamma if the PNG file has no gamma information. + + If you call png_set_gamma after png_set_alpha_mode you + will override the linear encoding. Instead the + pre-multiplied pixel values will be gamma encoded but + the alpha channel will still be linear. This may + actually match the requirements of some broken software, + but it is unlikely. + + While linear 8 bit data is often used it has + insufficient precision for any image with a reasonable + dynamic range. To avoid problems, and if your software + supports it, use png_set_expand_16() to force all + components to 16 bits. + + PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD except that + completely opaque pixels are gamma encoded according to + the screen_gamma value. Pixels with alpha less than 1.0 + will still have linear components. + + Use this format if you have control over your + compositing software and do don't do other arithmetic + (such as scaling) on the data you get from libpng. Your + compositing software can simply copy opaque pixels to + the output but still has linear values for the + non-opaque pixels. + + In normal compositing, where the alpha channel encodes + partial pixel coverage (as opposed to broad area + translucency), the inaccuracies of the 8 bit + representation of non-opaque pixels are irrelevant. + + You can also try this format if your software is broken; + it might look better. + + PNG_ALPHA_BROKEN This is PNG_ALPHA_STANDARD however all component values, + including the alpha channel are gamma encoded. This is + an appropriate format to try if your software, or more + likely hardware, is totally broken: if it performs + linear arithmetic directly on gamma encoded values. + +In most cases of broken software or hardware the bug in the final display +manifests as a subtle halo around composited parts of the image. You may not +even perceive this as a halo; the composited part of the image may simply appear +separate from the background, as though it had been cut out of paper and pasted +on afterward. + +If you don't have to deal with bugs in software or hardware, or if you can fix +them, there are three recommended ways of using png_set_alpha_mode: + + png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, screen_gamma); + You can do color correction on the result (libpng does not currently + support color correction internally.) When you handle the alpha channel + you need to undo the gamma encoding and multipy out the alpha. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, screen_gamma); + png_set_expand_16(png_ptr); + If you are using the high level interface don't call png_set_expand_16, + instead pass PNG_TRANSFORM_EXPAND_16 to the interface. + + With this mode you can't do color corrrection, but you can do arithmetic, + including composition and scaling, on the data without further processing. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMZED, screen_gamma); + You can avoid the expansion to 16 bit components with this mode, but you + lose the ability to scale the image or perform other linear arithmetic. + All you can do is compose the result onto a matching output. Since this + mode is libpng specific you also need to write your own composition + software. + +If you don't need, or can't handle, the alpha channel you can call +png_set_background to remove it by compositing against a fixed color. Don't +call png_set_strip_alpha to do this - it will leave spurious pixel values in +transparent parts of this image. + + png_set_background(png_ptr, &background_color, PNG_BACKGROUND_GAMMA_SCREEN, + 0, 1); + +The background_color is an RGB or grayscale value according to the data format +libpng will produce for you. Because you don't yet know the format of the PNG +file if you call png_set_background at this point you must arrange for the +format produced by libpng to always have 8-bit or 16-bit components and then +store the color as an 8-bit or 16-bit color as appropriate. The color contains +separate gray and RGB component values, so you can let libpng produce gray or +RGB output according to the input format, but low bit depth grayscale images +must always be converted to at least 8-bit format. (Even low low bit depth +grayscale images can't have an alpha channel they can have a transparent +color!) + +You set the transforms you need later, either as flags to the high level +interface or libpng API calls for the low level interface. For reference the +settings required are: + +8-bit values: + PNG_TRANSFORM_STRIP_16 | PNG_EXPAND + png_set_expand(png_ptr); png_set_strip_16(png_ptr); + +16-bit values: + PNG_TRANSFORM_EXPAND_16 + png_set_expand_16(png_ptr); + +In either case palette image data will be expanded to RGB. If you just want +color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr) +to the list. + +Calling png_set_background before the PNG file header is read will not work +prior to libpng-1.5.3. Because the failure may result in unexpected warnings or +errors it is therefore much safer to call png_set_background after the head has +been read. Unfortunately this means that prior to libpng-1.5.3 it cannot be +used with the high level interface. + .SS The high-level read interface At this point there are two ways to proceed; through the high-level @@ -1686,6 +1903,22 @@ call to png_read_info(). This will process all chunks up to but not including the image data. +This also copies some of the data from the PNG file into the decode structure +for use in later transformations. Important information copied in is: + +1) The PNG file gamma from the gAMA chunk. This overwrites the default value +provided by an earlier call to png_set_gamma or png_set_alpha_mode. + +2) Prior to libpng-1.5.3 the background color from a bKGd chunk. This +damages the information provided by an earlier call to png_set_background +resulting in expected behavior. Libpng-1.5.3 no longer does this. + +3) The number of significant bits in each component value. Libpng uses this to +optimize gamma handling by reducing the internal lookup table sizes. + +4) The transparent color information from a tRNS chunk. This can be modified by +a later call to png_set_tRNS. + .SS Querying the info structure Functions are used to get the information from the info_ptr once it @@ -2049,7 +2282,7 @@ forms: converted to microns and back without some loss of precision. -For more information, see the png_info definition in png.h and the +For more information, see the PNG specification for chunk contents. Be careful with trusting rowbytes, as some of the transformations could increase the space needed to hold a row (expand, filler, gray_to_rgb, etc.). @@ -2084,17 +2317,20 @@ to handle any special transformations of the image data. The various ways to transform the data will be described in the order that they should occur. This is important, as some of these change the color type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. +certain color types and bit depths. -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). +Transformations you request are ignored if they don't have any meaning for a +particular input data format. However some transformations can have an effect +as a result of a previous transformation. If you specify a contradictory set of +transformations, for example both adding and removing the alpha channel, you +cannot predict the final result. + +The color used for the transparency values should be supplied in the same +format/depth as the current image data. It is stored in the same format/depth +as the image data in a tRNS chunk, so this is what libpng expects for this data. + +The color used for the background value depends on the need_expand argument as +described below. Data will be decoded into the supplied row buffers packed into bytes unless the library has been told to transform it into another format. @@ -2148,18 +2384,16 @@ PNG can have files with 16 bits per channel. If you only can handle if (bit_depth == 16) png_set_strip_16(png_ptr); -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): +If you need to process the alpha channel on the image separately from the image +data (for example if you convert it to a bitmap mask) it is possible to have +libpng strip the channel leaving just RGB or gray data: if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); -See below for png_set_background(), which does the correct composition on a -single opaque color. This is probably what you should do in all cases rather -than use png_set_strip_alpha() - unless you know for sure that it is the wrong -thing to do. +If you strip the alpha channel you need to find some other way of dealing with +the information. If, instead, you want to convert the image to an opaque +version with no alpha channel use png_set_background; see below. As of libpng version 1.5.2, almost all useful expansions are supported, the major ommissions are convertion of grayscale to indexed images (which can be @@ -2293,8 +2527,8 @@ with alpha. if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); + png_set_rgb_to_gray(png_ptr, error_action, double red_weight, + double green_weight); error_action = 1: silently do the conversion @@ -2307,122 +2541,83 @@ with alpha. image has any pixel where red != green or red != blue - red_weight: weight of red component times 100000 + red_weight: weight of red component - green_weight: weight of green component times 100000 + green_weight: weight of green component If either weight is negative, default - weights (21268, 71514) are used. + weights are used. + +In the corresponding fixed point API the red_weight and green_weight values are +simply scaled by 100,000: + + png_set_rgb_to_gray(png_ptr, error_action, png_fixed_point red_weight, + png_fixed_point green_weight); If you have set error_action = 1 or 2, you can later check whether the image really was gray, after processing the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data +1 if there were any non-gray pixels. Background and sBIT data will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. +data for sBIT, regardless of the error_action setting. -With red_weight+green_weight<=100000, -the normalized graylevel is computed: +The default values come from the PNG file cHRM chunk if present, otherwise the +defaults correspond to the ITU-R recommendation 709, and also the sRGB color +space, as recommended in the Charles Poynton's Colour FAQ, +, in section 9: - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B -Libpng approximates this with integers scaled by 32768: - - Y = (6968 * R + 23434 * G + 2366 * B)/32768 - The calculation is done in a linear colorspace, if the image gamma can be determined. -If you have a grayscale and you are using png_set_expand_gray_1_2_4_to_8(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). +The png_set_background() function has been described already, it tells libpng to +composite images with alpha or simple transparency against the supplied +background color. For compatibility with versions of libpng earlier than +libpng-1.5.3 it is recommended that you call the function after reading the file +header, even if you don't want to use the color in a bKGD chunk, if one exists. + +If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng how the color is represented, both the format of the +component values in the color (the number of bits) and the gamme encoding of the +color. The function takes two arguments, background_gamma_mode and need_expand +to convey this information, however only two combinations are like to be useful: png_color_16 my_background; png_color_16p image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1); else png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1); -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. +The second call was described above - my_background is in the format of the +final, display, output produced by libpng. Because you now know the format of +the PNG it is possible to avoid the need to choose either 8 or 16 bit output and +to retain palette images (the palette colors will be modified appropriately and +the tRNS chunk removed.) However, if you are doing this, take great care not to +ask for transformations without checking first that they apply! -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. +In the first call the background color has the original bit depth and color type +of the PNG file. So, for palette images the color is supplied as a palette +index and for low bit greyscale images the color is a reduced bit value in +image_background->gray. - double gamma, screen_gamma; +If you didn't call png_set_gamma() before reading the file header, for example +if you need your code to remain compatible with older versions of libpng prior +to libpng-1.5.3, this is the place to call it. - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The functions png_set_gamma() and its fixed point equivalent -png_set_gamma_fixed() handle gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. +Do not call it if you called png_set_alpha_mode(); doing so will damage the +settings put in place by png_set_alpha_mode(). (If png_set_alpha_mode() is +supported then you can certainly do png_set_gamma() before reading the PNG +header.) This API unconditionally sets the screen and file gamma values, so it will override the value in the PNG file unless it is called before the PNG file @@ -5150,7 +5345,7 @@ Other rules can be inferred by inspecting the libpng source. .SH XIV. Y2K Compliance in libpng -May 11, 2011 +May 13, 2011 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. @@ -5402,7 +5597,7 @@ possible without all of you. Thanks to Frank J. T. Wojcik for helping with the documentation. -Libpng version 1.5.3beta08 - May 11, 2011: +Libpng version 1.5.3beta08 - May 13, 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). @@ -5425,7 +5620,7 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.5.3beta08, May 11, 2011, are +libpng versions 1.2.6, August 15, 2004, through 1.5.3beta08, May 13, 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 @@ -5524,7 +5719,7 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -May 11, 2011 +May 13, 2011 .\" end of man page diff --git a/png.h b/png.h index d10fd29d5..9bb53f8b8 100644 --- a/png.h +++ b/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.5.3beta08 - May 11, 2011 + * libpng version 1.5.3beta08 - May 13, 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.3beta08 - May 11, 2011: Glenn + * libpng versions 0.97, January 1998, through 1.5.3beta08 - May 13, 2011: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -182,7 +182,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.5.3beta08, May 11, 2011, are + * libpng versions 1.2.6, August 15, 2004, through 1.5.3beta08, May 13, 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: @@ -294,7 +294,7 @@ * Y2K compliance in libpng: * ========================= * - * May 11, 2011 + * May 13, 2011 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. @@ -357,7 +357,7 @@ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.5.3beta08" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.5.3beta08 - May 11, 2011\n" + " libpng version 1.5.3beta08 - May 13, 2011\n" #define PNG_LIBPNG_VER_SONUM 15 #define PNG_LIBPNG_VER_DLLNUM 15 @@ -1400,7 +1400,11 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS by replacing with a background color. */ +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.3 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors int the PNG file contains a bKGD chunk. + */ PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)); diff --git a/pngrtran.c b/pngrtran.c index dda48c0a2..66c75b569 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -947,30 +947,38 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, } #endif { - png_uint_16 red_int, green_int; - if (red < 0 || green < 0) + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) { - red_int = 6968; /* .212671 * 32768 + .5 */ - green_int = 23434; /* .715160 * 32768 + .5 */ - } + png_uint_16 red_int, green_int; - else if (red + green < 100000L) - { 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); } else { - png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - red_int = 6968; - green_int = 23434; - } + if (red >= 0 && green >= 0) + png_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); - 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); + /* 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!) + */ + 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_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; + } + } } } diff --git a/pngrutil.c b/pngrutil.c index d52f1007b..feab4103b 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1020,6 +1020,33 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Store the _white values as default coefficients for the rgb to gray + * operation if it is supported. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + { + /* png_set_background has not been called, the coefficients must be in + * range for the following to work without overflow. + */ + 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_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); + } + } +#endif + png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red, x_green, y_green, x_blue, y_blue); } @@ -1544,6 +1571,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_size_t truelen; png_byte buf[6]; + png_color_16 background; png_debug(1, "in png_handle_bKGD"); @@ -1600,7 +1628,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - png_ptr->background.index = buf[0]; + background.index = buf[0]; if (info_ptr && info_ptr->num_palette) { @@ -1610,33 +1638,36 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - png_ptr->background.red = - (png_uint_16)png_ptr->palette[buf[0]].red; - - png_ptr->background.green = - (png_uint_16)png_ptr->palette[buf[0]].green; - - png_ptr->background.blue = - (png_uint_16)png_ptr->palette[buf[0]].blue; + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; } + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; } else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ { - png_ptr->background.red = - png_ptr->background.green = - png_ptr->background.blue = - png_ptr->background.gray = png_get_uint_16(buf); + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); } else { - png_ptr->background.red = png_get_uint_16(buf); - png_ptr->background.green = png_get_uint_16(buf + 2); - png_ptr->background.blue = png_get_uint_16(buf + 4); + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; } - png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); + png_set_bKGD(png_ptr, info_ptr, &background); } #endif