diff --git a/ANNOUNCE b/ANNOUNCE index 62d76fccd..f2e652fba 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -336,6 +336,8 @@ Version 1.6.0beta19 [March 19, 2012] Added application error reporting and added chunk names to read benign errors; also added --strict to pngstest - not enabled yet because a warning is produced. + Avoid the double gamma correction warning in the simplified API. + This allows the --strict option to pass in the pngstest checks Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index e378d3cbe..6191cdaed 100644 --- a/CHANGES +++ b/CHANGES @@ -4087,6 +4087,8 @@ Version 1.6.0beta19 [March 19, 2012] Added application error reporting and added chunk names to read benign errors; also added --strict to pngstest - not enabled yet because a warning is produced. + Avoid the double gamma correction warning in the simplified API. + This allows the --strict option to pass in the pngstest checks Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/contrib/libtests/pngstest.c b/contrib/libtests/pngstest.c index d82671319..c16de9642 100644 --- a/contrib/libtests/pngstest.c +++ b/contrib/libtests/pngstest.c @@ -299,7 +299,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) #define READ_FILE 1 /* else memory */ #define USE_STDIO 2 /* else use file name */ -/* 4: unused */ +#define STRICT 4 /* fail on warnings too */ #define VERBOSE 8 #define KEEP_TMPFILES 16 /* else delete temporary files */ #define KEEP_GOING 32 @@ -313,6 +313,8 @@ print_opts(png_uint_32 opts) printf(" --file"); if (opts & USE_STDIO) printf(" --stdio"); + if (opts & STRICT) + printf(" --strict"); if (opts & VERBOSE) printf(" --verbose"); if (opts & KEEP_TMPFILES) @@ -321,6 +323,8 @@ print_opts(png_uint_32 opts) printf(" --keep-going"); if (opts & ACCUMULATE) printf(" --accumulate"); + if (!(opts & FAST_WRITE)) /* --fast is currently the default */ + printf(" --slow"); } #define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ @@ -715,6 +719,9 @@ checkopaque(Image *image) return logerror(image, image->file_name, ": opaque not NULL", ""); } + else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) + return logerror(image, image->file_name, " --strict", ""); + else return 1; } @@ -3454,6 +3461,8 @@ main(int argc, char **argv) redundant = 1; else if (strcmp(arg, "--stop") == 0) opts &= ~KEEP_GOING; + else if (strcmp(arg, "--strict") == 0) + opts |= STRICT; else if (strcmp(arg, "--touch") == 0) { if (c+1 < argc) diff --git a/pngread.c b/pngread.c index e9cd59c7d..78285b5d2 100644 --- a/pngread.c +++ b/pngread.c @@ -1838,6 +1838,17 @@ png_create_colormap_entry(png_image_read_control *display, } } +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, E_FILE); + + return i; +} + static int make_gray_colormap(png_image_read_control *display) { @@ -2368,7 +2379,23 @@ png_image_read_colormap(png_voidp argument) if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb[gray] color-map: too few entries"); - cmap_entries = make_gray_colormap(display); + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && png_gamma_not_sRGB(png_ptr->gamma)) + { + cmap_entries = make_gray_file_colormap(display); + data_encoding = E_FILE; + } + + else + cmap_entries = make_gray_colormap(display); /* But if the input has alpha or transparency it must be removed */ @@ -2383,18 +2410,38 @@ png_image_read_colormap(png_voidp argument) * it. Achieve this simply by ensuring that the entry * selected for the background really is the background color. */ - if (output_encoding == E_LINEAR) + if (data_encoding == E_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (E_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == E_sRGB) + gray = png_sRGB_table[gray]; /* now E_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->gamma)); /* now E_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == E_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry matches. */ png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 65535, E_LINEAR); + back_g, 0/*unused*/, E_LINEAR); } - /* The background passed to libpng, however, must be the sRGB - * value. + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. */ c.index = 0; /*unused*/ c.gray = c.red = c.green = c.blue = (png_uint_16)gray; @@ -2657,13 +2704,12 @@ png_image_read_colormap(png_voidp argument) png_error(png_ptr, "bad data option (internal error)"); break; - case E_FILE: - /* Make no changes */ - break; - case E_sRGB: /* Change to 8-bit sRGB */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALL THROUGH */ + + case E_FILE: if (png_ptr->bit_depth > 8) png_set_scale_16(png_ptr); break; diff --git a/test-pngstest.sh b/test-pngstest.sh index c9da5324b..e977a5b50 100755 --- a/test-pngstest.sh +++ b/test-pngstest.sh @@ -11,7 +11,7 @@ for image in ${srcdir}/contrib/pngsuite/*.png do for opts in "" do - if ./pngstest --log "$@" $opts $image >>pngtest-log.txt 2>&1 + if ./pngstest --strict --log "$@" $opts $image >>pngtest-log.txt 2>&1 then echo " PASS: pngstest $opts $image" else