From 59ae38984f35cfcf2e89ada35460d28027a29669 Mon Sep 17 00:00:00 2001 From: John Bowler Date: Wed, 6 Mar 2013 22:15:25 -0600 Subject: [PATCH] [libpng16] Corrected simplified API default gamma for color-mapped output, added a flag to change default. In 1.6.0 when the simplified API was used to produce color-mapped output from an input image with no gamma information the gamma assumed for the input could be different from that assumed for non-color-mapped output. In particular 16-bit depth input files were assumed to be sRGB encoded, whereas in the 'direct' case they were assumed to have linear data. This was an error. The fix makes the simplified API treat all input files the same way and adds a new flag to the png_image::flags member to allow the application/user to specify that 16-bit files contain sRGB data rather than the default linear. Fixed bugs in the pngpixel and makepng test programs. --- ANNOUNCE | 16 ++++++++++++++-- CHANGES | 14 +++++++++++++- contrib/examples/pngpixel.c | 2 +- contrib/libtests/makepng.c | 6 +++--- contrib/libtests/pngstest.c | 11 +++++++++++ png.h | 30 ++++++++++++++++++++++++------ pngread.c | 25 ++++++++++++++++++++++++- 7 files changed, 90 insertions(+), 14 deletions(-) diff --git a/ANNOUNCE b/ANNOUNCE index 23d23ecc6..485520478 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.6.1beta07 - March 4, 2013 +Libpng 1.6.1beta07 - March 7, 2013 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. @@ -79,7 +79,19 @@ Version 1.6.1beta06 [March 4, 2013] settings to depend on options and options can now set (or override) the defaults for settings. -Version 1.6.1beta07 [March 4, 2013] +Version 1.6.1beta07 [March 7, 2013] + Corrected simplified API default gamma for color-mapped output, added + a flag to change default. In 1.6.0 when the simplified API was used + to produce color-mapped output from an input image with no gamma + information the gamma assumed for the input could be different from + that assumed for non-color-mapped output. In particular 16-bit depth + input files were assumed to be sRGB encoded, whereas in the 'direct' + case they were assumed to have linear data. This was an error. The + fix makes the simplified API treat all input files the same way and + adds a new flag to the png_image::flags member to allow the + application/user to specify that 16-bit files contain sRGB data + rather than the default linear. + Fixed bugs in the pngpixel and makepng test programs. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index a00683af6..f8f952473 100644 --- a/CHANGES +++ b/CHANGES @@ -4435,7 +4435,19 @@ Version 1.6.1beta06 [March 4, 2013] settings to depend on options and options can now set (or override) the defaults for settings. -Version 1.6.1beta07 [March 4, 2013] +Version 1.6.1beta07 [March 7, 2013] + Corrected simplified API default gamma for color-mapped output, added + a flag to change default. In 1.6.0 when the simplified API was used + to produce color-mapped output from an input image with no gamma + information the gamma assumed for the input could be different from + that assumed for non-color-mapped output. In particular 16-bit depth + input files were assumed to be sRGB encoded, whereas in the 'direct' + case they were assumed to have linear data. This was an error. The + fix makes the simplified API treat all input files the same way and + adds a new flag to the png_image::flags member to allow the + application/user to specify that 16-bit files contain sRGB data + rather than the default linear. + Fixed bugs in the pngpixel and makepng test programs. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/contrib/examples/pngpixel.c b/contrib/examples/pngpixel.c index d82ef83d0..410476031 100644 --- a/contrib/examples/pngpixel.c +++ b/contrib/examples/pngpixel.c @@ -37,7 +37,7 @@ component(png_const_bytep row, png_uint_32 x, unsigned int c, * bytes wide. Since the row fitted into memory, however, the following must * work: */ - png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels + c); + png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels); png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c); row = (png_const_bytep)(((PNG_CONST png_byte (*)[8])row) + bit_offset_hi); diff --git a/contrib/libtests/makepng.c b/contrib/libtests/makepng.c index 3b2e92f4f..6df320453 100644 --- a/contrib/libtests/makepng.c +++ b/contrib/libtests/makepng.c @@ -440,7 +440,7 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, /* Palette with fixed color: the image rows are all 0 and the image width * is 16. */ - memset(row, rowbytes, 0); + memset(row, 0, rowbytes); } else if (colors[0] == channels_of_type(color_type)) @@ -624,8 +624,8 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth, gamma_table[0] = 0; - for (i=0; i<255; ++i) - gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + 127.5); + for (i=1; i<255; ++i) + gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + .5); gamma_table[255] = 255; } diff --git a/contrib/libtests/pngstest.c b/contrib/libtests/pngstest.c index 543e50bd0..8b55b2ab9 100644 --- a/contrib/libtests/pngstest.c +++ b/contrib/libtests/pngstest.c @@ -315,6 +315,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) #define KEEP_GOING 32 #define ACCUMULATE 64 #define FAST_WRITE 128 +#define sRGB_16BIT 256 static void print_opts(png_uint_32 opts) @@ -335,6 +336,8 @@ print_opts(png_uint_32 opts) printf(" --accumulate"); if (!(opts & FAST_WRITE)) /* --fast is currently the default */ printf(" --slow"); + if (opts & sRGB_16BIT) + printf(" --sRGB-16bit"); } #define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ @@ -3026,6 +3029,10 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background) return logerror(image, "file init: ", image->file_name, ""); } + /* This must be set after the begin_read call: */ + if (image->opts & sRGB_16BIT) + image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; + /* Have an initialized image with all the data we need plus, maybe, an * allocated file (myfile) or buffer (mybuffer) that need to be freed. */ @@ -3488,6 +3495,10 @@ main(int argc, char **argv) opts &= ~KEEP_GOING; else if (strcmp(arg, "--strict") == 0) opts |= STRICT; + else if (strcmp(arg, "--sRGB-16bit") == 0) + opts |= sRGB_16BIT; + else if (strcmp(arg, "--linear-16bit") == 0) + opts &= ~sRGB_16BIT; else if (strcmp(arg, "--tmpfile") == 0) { if (c+1 < argc) diff --git a/png.h b/png.h index abd252870..1322984e3 100644 --- a/png.h +++ b/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.1beta07 - March 4, 2013 + * libpng version 1.6.1beta07 - March 7, 2013 * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -11,7 +11,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.6.1beta07 - March 4, 2013: Glenn + * libpng versions 0.97, January 1998, through 1.6.1beta07 - March 7, 2013: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -201,7 +201,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.6.1beta07, March 4, 2013, are + * libpng versions 1.2.6, August 15, 2004, through 1.6.1beta07, March 7, 2013, are * Copyright (c) 2004, 2006-2013 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: @@ -313,7 +313,7 @@ * Y2K compliance in libpng: * ========================= * - * March 4, 2013 + * March 7, 2013 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. @@ -381,7 +381,7 @@ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.6.1beta07" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.6.1beta07 - March 4, 2013\n" + " libpng version 1.6.1beta07 - March 7, 2013\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 @@ -3098,6 +3098,24 @@ typedef struct * slight speed gain. */ +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* READ APIs * --------- @@ -3148,7 +3166,7 @@ PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, * PNG_FORMAT_FLAG_LINEAR *not* set. * * For linear output removing the alpha channel is always done by compositing - * on black and background is ignored.: + * on black and background is ignored. * * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. diff --git a/pngread.c b/pngread.c index e4fa21551..b1751ace8 100644 --- a/pngread.c +++ b/pngread.c @@ -2004,6 +2004,28 @@ png_image_read_colormap(png_voidp argument) else back_b = back_r = back_g = 255; + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + /* Decide what to do based on the PNG color type of the input data. The * utility function png_create_colormap_entry deals with most aspects of the * output transformations; this code works out how to produce bytes of @@ -3547,7 +3569,8 @@ png_image_read_direct(png_voidp argument) { png_fixed_point input_gamma_default; - if (base_format & PNG_FORMAT_FLAG_LINEAR) + if ((base_format & PNG_FORMAT_FLAG_LINEAR) && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) input_gamma_default = PNG_GAMMA_LINEAR; else input_gamma_default = PNG_DEFAULT_sRGB;