[libpng16] Merged with pngvalid.c from libpng-1.7 changes to create a single

pngvalid.c
This commit is contained in:
John Bowler
2013-12-27 08:43:55 -06:00
committed by Glenn Randers-Pehrson
parent 1d3c990425
commit a80e864faa
3 changed files with 366 additions and 124 deletions

View File

@@ -45,6 +45,8 @@ Version 1.6.9beta01 [December 26, 2013]
Version 1.6.9beta02 [December 27, 2013] Version 1.6.9beta02 [December 27, 2013]
Added checks for libpng 1.5 to pngvalid.c. This supports the use of Added checks for libpng 1.5 to pngvalid.c. This supports the use of
this version of pngvalid in libpng 1.5 this version of pngvalid in libpng 1.5
Merged with pngvalid.c from libpng-1.7 changes to create a single
pngvalid.c
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@@ -4770,6 +4770,8 @@ Version 1.6.9beta01 [December 26, 2013]
Version 1.6.9beta02 [December 27, 2013] Version 1.6.9beta02 [December 27, 2013]
Added checks for libpng 1.5 to pngvalid.c. This supports the use of Added checks for libpng 1.5 to pngvalid.c. This supports the use of
this version of pngvalid in libpng 1.5 this version of pngvalid in libpng 1.5
Merged with pngvalid.c from libpng-1.7 changes to create a single
pngvalid.c
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@@ -43,6 +43,12 @@
# include "../../png.h" # include "../../png.h"
#endif #endif
#ifdef PNG_ZLIB_HEADER
# include PNG_ZLIB_HEADER
#else
# include <zlib.h> /* For crc32 */
#endif
/* pngvalid requires write support and one of the fixed or floating point APIs. /* pngvalid requires write support and one of the fixed or floating point APIs.
*/ */
#if defined(PNG_WRITE_SUPPORTED) &&\ #if defined(PNG_WRITE_SUPPORTED) &&\
@@ -91,8 +97,6 @@ typedef png_byte *png_const_bytep;
# define png_const_structp png_structp # define png_const_structp png_structp
#endif #endif
#include <zlib.h> /* For crc32 */
#include <float.h> /* For floating point constants */ #include <float.h> /* For floating point constants */
#include <stdlib.h> /* For malloc */ #include <stdlib.h> /* For malloc */
#include <string.h> /* For memcpy, memset */ #include <string.h> /* For memcpy, memset */
@@ -352,11 +356,16 @@ standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
static int static int
next_format(png_bytep colour_type, png_bytep bit_depth, next_format(png_bytep colour_type, png_bytep bit_depth,
unsigned int* palette_number) unsigned int* palette_number, int no_low_depth_gray)
{ {
if (*bit_depth == 0) if (*bit_depth == 0)
{ {
*colour_type = 0, *bit_depth = 1, *palette_number = 0; *colour_type = 0;
if (no_low_depth_gray)
*bit_depth = 8;
else
*bit_depth = 1;
*palette_number = 0;
return 1; return 1;
} }
@@ -1874,6 +1883,7 @@ typedef struct png_modifier
double maxout16; /* Maximum output value error */ double maxout16; /* Maximum output value error */
double maxabs16; /* Absolute sample error 0..1 */ double maxabs16; /* Absolute sample error 0..1 */
double maxcalc16;/* Absolute sample error 0..1 */ double maxcalc16;/* Absolute sample error 0..1 */
double maxcalcG; /* Absolute sample error 0..1 */
double maxpc16; /* Percentage sample error 0..100% */ double maxpc16; /* Percentage sample error 0..100% */
/* This is set by transforms that need to allow a higher limit, it is an /* This is set by transforms that need to allow a higher limit, it is an
@@ -1913,10 +1923,15 @@ typedef struct png_modifier
/* Run the odd-sized image and interlace read/write tests? */ /* Run the odd-sized image and interlace read/write tests? */
unsigned int test_size :1; unsigned int test_size :1;
/* Run tests on reading with a combiniation of transforms, */ /* Run tests on reading with a combination of transforms, */
unsigned int test_transform :1; unsigned int test_transform :1;
/* When to use the use_input_precision option: */ /* When to use the use_input_precision option, this controls the gamma
* validation code checks. If set any value that is within the transformed
* range input-.5 to input+.5 will be accepted, otherwise the value must be
* within the normal limits. It should not be necessary to set this; the
* result should always be exact within the permitted error limits.
*/
unsigned int use_input_precision :1; unsigned int use_input_precision :1;
unsigned int use_input_precision_sbit :1; unsigned int use_input_precision_sbit :1;
unsigned int use_input_precision_16to8 :1; unsigned int use_input_precision_16to8 :1;
@@ -1926,8 +1941,8 @@ typedef struct png_modifier
*/ */
unsigned int calculations_use_input_precision :1; unsigned int calculations_use_input_precision :1;
/* If set assume that the calculations are done in 16 bits even if both input /* If set assume that the calculations are done in 16 bits even if the sample
* and output are 8 bit or less. * depth is 8 bits.
*/ */
unsigned int assume_16_bit_calculations :1; unsigned int assume_16_bit_calculations :1;
@@ -1982,6 +1997,7 @@ modifier_init(png_modifier *pm)
pm->test_uses_encoding = 0; pm->test_uses_encoding = 0;
pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0; pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0;
pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0; pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0;
pm->maxcalcG = 0;
pm->limit = 4E-3; pm->limit = 4E-3;
pm->log8 = pm->log16 = 0; /* Means 'off' */ pm->log8 = pm->log16 = 0; /* Means 'off' */
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
@@ -1996,6 +2012,7 @@ modifier_init(png_modifier *pm)
pm->use_input_precision_sbit = 0; pm->use_input_precision_sbit = 0;
pm->use_input_precision_16to8 = 0; pm->use_input_precision_16to8 = 0;
pm->calculations_use_input_precision = 0; pm->calculations_use_input_precision = 0;
pm->assume_16_bit_calculations = 0;
pm->test_gamma_threshold = 0; pm->test_gamma_threshold = 0;
pm->test_gamma_transform = 0; pm->test_gamma_transform = 0;
pm->test_gamma_sbit = 0; pm->test_gamma_sbit = 0;
@@ -2010,8 +2027,16 @@ modifier_init(png_modifier *pm)
} }
#ifdef PNG_READ_TRANSFORMS_SUPPORTED #ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* This controls use of checks that explicitly know how libpng digitizes the
* samples in calculations; setting this circumvents simple error limit checking
* in the rgb_to_gray check, replacing it with an exact copy of the libpng 1.5
* algorithm.
*/
#define DIGITIZE PNG_LIBPNG_VER < 10700
/* If pm->calculations_use_input_precision is set then operations will happen /* If pm->calculations_use_input_precision is set then operations will happen
* with only 8 bit precision unless both the input and output bit depth are 16. * with the precision of the input, not the precision of the output depth.
* *
* If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16 * If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16
* bit precision. This only affects those of the following limits that pertain * bit precision. This only affects those of the following limits that pertain
@@ -2019,8 +2044,8 @@ modifier_init(png_modifier *pm)
* called directly. * called directly.
*/ */
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
static double digitize(PNG_CONST png_modifier *pm, double value, #if DIGITIZE
int sample_depth, int do_round) static double digitize(double value, int depth, int do_round)
{ {
/* 'value' is in the range 0 to 1, the result is the same value rounded to a /* 'value' is in the range 0 to 1, the result is the same value rounded to a
* multiple of the digitization factor - 8 or 16 bits depending on both the * multiple of the digitization factor - 8 or 16 bits depending on both the
@@ -2028,14 +2053,14 @@ static double digitize(PNG_CONST png_modifier *pm, double value,
* rounding and 'do_round' should be 1, if it is 0 the digitized value will * rounding and 'do_round' should be 1, if it is 0 the digitized value will
* be truncated. * be truncated.
*/ */
PNG_CONST unsigned int digitization_factor = PNG_CONST unsigned int digitization_factor = (1U << depth) -1;
(pm->assume_16_bit_calculations || sample_depth == 16) ? 65535 : 255;
/* Limiting the range is done as a convenience to the caller - it's easier to /* Limiting the range is done as a convenience to the caller - it's easier to
* do it once here than every time at the call site. * do it once here than every time at the call site.
*/ */
if (value <= 0) if (value <= 0)
value = 0; value = 0;
else if (value >= 1) else if (value >= 1)
value = 1; value = 1;
@@ -2044,31 +2069,30 @@ static double digitize(PNG_CONST png_modifier *pm, double value,
return floor(value)/digitization_factor; return floor(value)/digitization_factor;
} }
#endif #endif
#endif /* RGB_TO_GRAY */
#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ #ifdef PNG_READ_GAMMA_SUPPORTED
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
{ {
/* Absolute error permitted in linear values - affected by the bit depth of /* Absolute error permitted in linear values - affected by the bit depth of
* the calculations. * the calculations.
*/ */
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || if (pm->assume_16_bit_calculations ||
!pm->calculations_use_input_precision))) (pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
return pm->maxabs16; return pm->maxabs16;
else else
return pm->maxabs8; return pm->maxabs8;
} }
#endif
#ifdef PNG_READ_GAMMA_SUPPORTED
static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
{ {
/* Error in the linear composition arithmetic - only relevant when /* Error in the linear composition arithmetic - only relevant when
* composition actually happens (0 < alpha < 1). * composition actually happens (0 < alpha < 1).
*/ */
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
!pm->calculations_use_input_precision)))
return pm->maxcalc16; return pm->maxcalc16;
else if (pm->assume_16_bit_calculations)
return pm->maxcalcG;
else else
return pm->maxcalc8; return pm->maxcalc8;
} }
@@ -2078,8 +2102,8 @@ static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
/* Percentage error permitted in the linear values. Note that the specified /* Percentage error permitted in the linear values. Note that the specified
* value is a percentage but this routine returns a simple number. * value is a percentage but this routine returns a simple number.
*/ */
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || if (pm->assume_16_bit_calculations ||
!pm->calculations_use_input_precision))) (pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
return pm->maxpc16 * .01; return pm->maxpc16 * .01;
else else
return pm->maxpc8 * .01; return pm->maxpc8 * .01;
@@ -2111,8 +2135,7 @@ static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
if (out_depth == 4) if (out_depth == 4)
return .90644-.5; return .90644-.5;
if (out_depth == 16 && (in_depth == 16 || if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
!pm->calculations_use_input_precision))
return pm->maxout16; return pm->maxout16;
/* This is the case where the value was calculated at 8-bit precision then /* This is the case where the value was calculated at 8-bit precision then
@@ -2145,8 +2168,7 @@ static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
return pm->log8; return pm->log8;
} }
if (out_depth == 16 && (in_depth == 16 || if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
!pm->calculations_use_input_precision))
{ {
if (pm->log16 == 0) if (pm->log16 == 0)
return 65536; return 65536;
@@ -2171,8 +2193,8 @@ static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth, static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth,
int out_depth) int out_depth)
{ {
if (out_depth == 16 && in_depth != 16 if (out_depth == 16 && in_depth != 16 &&
&& pm->calculations_use_input_precision) pm->calculations_use_input_precision)
return 257; return 257;
else else
return 1; return 1;
@@ -3534,7 +3556,7 @@ make_transform_images(png_store *ps)
/* Use next_format to enumerate all the combinations we test, including /* Use next_format to enumerate all the combinations we test, including
* generating multiple low bit depth palette images. * generating multiple low bit depth palette images.
*/ */
while (next_format(&colour_type, &bit_depth, &palette_number)) while (next_format(&colour_type, &bit_depth, &palette_number, 0))
{ {
int interlace_type; int interlace_type;
@@ -3843,8 +3865,15 @@ make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
width, height, 0); width, height, 0);
# endif # endif
# if defined(PNG_WRITE_INTERLACING_SUPPORTED) || PNG_LIBPNG_VER > 10518
/* This fails in 1.5.8 with a zlib stream error writing the rows of
* the internally generated interlaced images, but only when the
* read code is disabled: to be investigated. Probably an erroneous
* #define out of the zlib deflate reset.
*/
make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7,
width, height, 1); width, height, 1);
# endif
} }
} }
} }
@@ -5886,12 +5915,9 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
memset(out_palette, 0x5e, sizeof out_palette); memset(out_palette, 0x5e, sizeof out_palette);
/* assume-8-bit-calculations means assume that if the input has 8 bit /* use-input-precision means assume that if the input has 8 bit (or less)
* (or less) samples and the output has 16 bit samples the calculations * samples and the output has 16 bit samples the calculations will be done
* will be done with 8 bit precision, not 16. * with 8 bit precision, not 16.
*
* TODO: fix this in libpng; png_set_expand_16 should cause 16 bit
* calculations to be used throughout.
*/ */
if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16) if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16)
in_sample_depth = 8; in_sample_depth = 8;
@@ -5902,7 +5928,8 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
!dp->pm->calculations_use_input_precision) !dp->pm->calculations_use_input_precision)
digitization_error = .5; digitization_error = .5;
/* Else errors are at 8 bit precision, scale .5 in 8 bits to the 16 bits: /* Else calculations are at 8 bit precision, and the output actually
* consists of scaled 8-bit values, so scale .5 in 8 bits to the 16 bits:
*/ */
else else
digitization_error = .5 * 257; digitization_error = .5 * 257;
@@ -6718,10 +6745,23 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
{ {
if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations) if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations)
{ {
/* The 16 bit case ends up producing a maximum error of about /* The computations have the form:
* +/-5 in 65535, allow for +/-8 with the given gamma. *
* r * rc + g * gc + b * bc
*
* Each component of which is +/-1/65535 from the gamma_to_1 table
* lookup, resulting in a base error of +/-6. The gamma_from_1
* conversion adds another +/-2 in the 16-bit case and
* +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case.
*/ */
that->pm->limit += pow(8./65535, data.gamma); that->pm->limit += pow(
# if PNG_MAX_GAMMA_8 < 14
(that->this.bit_depth == 16 ? 8. :
6. + (1<<(15-PNG_MAX_GAMMA_8)))
# else
8.
# endif
/65535, data.gamma);
} }
else else
@@ -6729,8 +6769,23 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
/* Rounding to 8 bits in the linear space causes massive errors which /* Rounding to 8 bits in the linear space causes massive errors which
* will trigger the error check in transform_range_check. Fix that * will trigger the error check in transform_range_check. Fix that
* here by taking the gamma encoding into account. * here by taking the gamma encoding into account.
*
* When DIGITIZE is set because a pre-1.7 version of libpng is being
* tested allow a bigger slack.
*
* NOTE: this magic number was determined by experiment to be 1.1 (when
* using fixed point arithmetic). There's no great merit to the value
* below, however it only affects the limit used for checking for
* internal calculation errors, not the actual limit imposed by
* pngvalid on the output errors.
*/ */
that->pm->limit += pow(1./255, data.gamma); that->pm->limit += pow(
# if DIGITIZE
1.1
# else
1.
# endif
/255, data.gamma);
} }
} }
@@ -6739,7 +6794,7 @@ image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this,
/* With no gamma correction a large error comes from the truncation of the /* With no gamma correction a large error comes from the truncation of the
* calculation in the 8 bit case, allow for that here. * calculation in the 8 bit case, allow for that here.
*/ */
if (that->this.bit_depth != 16) if (that->this.bit_depth != 16 && !pm->assume_16_bit_calculations)
that->pm->limit += 4E-3; that->pm->limit += 4E-3;
} }
} }
@@ -6884,9 +6939,14 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
image_pixel_convert_PLTE(that); image_pixel_convert_PLTE(that);
/* Image now has RGB channels... */ /* Image now has RGB channels... */
# if DIGITIZE
{ {
PNG_CONST png_modifier *pm = display->pm; PNG_CONST png_modifier *pm = display->pm;
PNG_CONST unsigned int sample_depth = that->sample_depth; const unsigned int sample_depth = that->sample_depth;
const unsigned int calc_depth = (pm->assume_16_bit_calculations ? 16 :
sample_depth);
const unsigned int gamma_depth = (sample_depth == 16 ? 16 :
(pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth));
int isgray; int isgray;
double r, g, b; double r, g, b;
double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi; double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi;
@@ -6902,28 +6962,28 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
*/ */
r = rlo = rhi = that->redf; r = rlo = rhi = that->redf;
rlo -= that->rede; rlo -= that->rede;
rlo = digitize(pm, rlo, sample_depth, 1/*round*/); rlo = digitize(rlo, calc_depth, 1/*round*/);
rhi += that->rede; rhi += that->rede;
rhi = digitize(pm, rhi, sample_depth, 1/*round*/); rhi = digitize(rhi, calc_depth, 1/*round*/);
g = glo = ghi = that->greenf; g = glo = ghi = that->greenf;
glo -= that->greene; glo -= that->greene;
glo = digitize(pm, glo, sample_depth, 1/*round*/); glo = digitize(glo, calc_depth, 1/*round*/);
ghi += that->greene; ghi += that->greene;
ghi = digitize(pm, ghi, sample_depth, 1/*round*/); ghi = digitize(ghi, calc_depth, 1/*round*/);
b = blo = bhi = that->bluef; b = blo = bhi = that->bluef;
blo -= that->bluee; blo -= that->bluee;
blo = digitize(pm, blo, sample_depth, 1/*round*/); blo = digitize(blo, calc_depth, 1/*round*/);
bhi += that->greene; bhi += that->greene;
bhi = digitize(pm, bhi, sample_depth, 1/*round*/); bhi = digitize(bhi, calc_depth, 1/*round*/);
isgray = r==g && g==b; isgray = r==g && g==b;
if (data.gamma != 1) if (data.gamma != 1)
{ {
PNG_CONST double power = 1/data.gamma; PNG_CONST double power = 1/data.gamma;
PNG_CONST double abse = abserr(pm, sample_depth, sample_depth); PNG_CONST double abse = calc_depth == 16 ? .5/65535 : .5/255;
/* 'abse' is the absolute error permitted in linear calculations. It /* 'abse' is the absolute error permitted in linear calculations. It
* is used here to capture the error permitted in the handling * is used here to capture the error permitted in the handling
@@ -6932,16 +6992,16 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
* where the real errors are introduced. * where the real errors are introduced.
*/ */
r = pow(r, power); r = pow(r, power);
rlo = digitize(pm, pow(rlo, power)-abse, sample_depth, 1); rlo = digitize(pow(rlo, power)-abse, calc_depth, 1);
rhi = digitize(pm, pow(rhi, power)+abse, sample_depth, 1); rhi = digitize(pow(rhi, power)+abse, calc_depth, 1);
g = pow(g, power); g = pow(g, power);
glo = digitize(pm, pow(glo, power)-abse, sample_depth, 1); glo = digitize(pow(glo, power)-abse, calc_depth, 1);
ghi = digitize(pm, pow(ghi, power)+abse, sample_depth, 1); ghi = digitize(pow(ghi, power)+abse, calc_depth, 1);
b = pow(b, power); b = pow(b, power);
blo = digitize(pm, pow(blo, power)-abse, sample_depth, 1); blo = digitize(pow(blo, power)-abse, calc_depth, 1);
bhi = digitize(pm, pow(bhi, power)+abse, sample_depth, 1); bhi = digitize(pow(bhi, power)+abse, calc_depth, 1);
} }
/* Now calculate the actual gray values. Although the error in the /* Now calculate the actual gray values. Although the error in the
@@ -6958,18 +7018,18 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
b * data.blue_coefficient; b * data.blue_coefficient;
{ {
PNG_CONST int do_round = data.gamma != 1 || sample_depth == 16; PNG_CONST int do_round = data.gamma != 1 || calc_depth == 16;
PNG_CONST double ce = 1. / 32768; PNG_CONST double ce = 1. / 32768;
graylo = digitize(pm, rlo * (data.red_coefficient-ce) + graylo = digitize(rlo * (data.red_coefficient-ce) +
glo * (data.green_coefficient-ce) + glo * (data.green_coefficient-ce) +
blo * (data.blue_coefficient-ce), sample_depth, do_round); blo * (data.blue_coefficient-ce), gamma_depth, do_round);
if (graylo <= 0) if (graylo <= 0)
graylo = 0; graylo = 0;
grayhi = digitize(pm, rhi * (data.red_coefficient+ce) + grayhi = digitize(rhi * (data.red_coefficient+ce) +
ghi * (data.green_coefficient+ce) + ghi * (data.green_coefficient+ce) +
bhi * (data.blue_coefficient+ce), sample_depth, do_round); bhi * (data.blue_coefficient+ce), gamma_depth, do_round);
if (grayhi >= 1) if (grayhi >= 1)
grayhi = 1; grayhi = 1;
} }
@@ -6980,8 +7040,8 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
PNG_CONST double power = data.gamma; PNG_CONST double power = data.gamma;
gray = pow(gray, power); gray = pow(gray, power);
graylo = digitize(pm, pow(graylo, power), sample_depth, 1); graylo = digitize(pow(graylo, power), sample_depth, 1);
grayhi = digitize(pm, pow(grayhi, power), sample_depth, 1); grayhi = digitize(pow(grayhi, power), sample_depth, 1);
} }
/* Now the error can be calculated. /* Now the error can be calculated.
@@ -6999,7 +7059,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
err = fabs(graylo-gray); err = fabs(graylo-gray);
/* Check that this worked: */ /* Check that this worked: */
if (err > display->pm->limit) if (err > pm->limit)
{ {
size_t pos = 0; size_t pos = 0;
char buffer[128]; char buffer[128];
@@ -7007,12 +7067,120 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error ");
pos = safecatd(buffer, sizeof buffer, pos, err, 6); pos = safecatd(buffer, sizeof buffer, pos, err, 6);
pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
pos = safecatd(buffer, sizeof buffer, pos, pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6);
display->pm->limit, 6);
png_error(pp, buffer); png_error(pp, buffer);
} }
} }
} }
# else /* DIGITIZE */
{
double r = that->redf;
double re = that->rede;
double g = that->greenf;
double ge = that->greene;
double b = that->bluef;
double be = that->bluee;
/* The true gray case involves no math. */
if (r == g && r == b)
{
gray = r;
err = re;
if (err < ge) err = ge;
if (err < be) err = be;
}
else if (data.gamma == 1)
{
/* There is no need to do the conversions to and from linear space,
* so the calculation should be a lot more accurate. There is a
* built in 1/32768 error in the coefficients because they only have
* 15 bits and are adjusted to make sure they add up to 32768, so
* the result may have an additional error up to 1/32768. (Note
* that adding the 1/32768 here avoids needing to increase the
* global error limits to take this into account.)
*/
gray = r * data.red_coefficient + g * data.green_coefficient +
b * data.blue_coefficient;
err = re * data.red_coefficient + ge * data.green_coefficient +
be * data.blue_coefficient + 1./32768 + gray * 5 * DBL_EPSILON;
}
else
{
/* The calculation happens in linear space, and this produces much
* wider errors in the encoded space. These are handled here by
* factoring the errors in to the calculation. There are two table
* lookups in the calculation and each introduces a quantization
* error defined by the table size.
*/
PNG_CONST png_modifier *pm = display->pm;
double in_qe = (that->sample_depth > 8 ? .5/65535 : .5/255);
double out_qe = (that->sample_depth > 8 ? .5/65535 :
(pm->assume_16_bit_calculations ? .5/(1<<PNG_MAX_GAMMA_8) :
.5/255));
double rhi, ghi, bhi, grayhi;
double g1 = 1/data.gamma;
rhi = r + re + in_qe; if (rhi > 1) rhi = 1;
r -= re + in_qe; if (r < 0) r = 0;
ghi = g + ge + in_qe; if (ghi > 1) ghi = 1;
g -= ge + in_qe; if (g < 0) g = 0;
bhi = b + be + in_qe; if (bhi > 1) bhi = 1;
b -= be + in_qe; if (b < 0) b = 0;
r = pow(r, g1)*(1-DBL_EPSILON); rhi = pow(rhi, g1)*(1+DBL_EPSILON);
g = pow(g, g1)*(1-DBL_EPSILON); ghi = pow(ghi, g1)*(1+DBL_EPSILON);
b = pow(b, g1)*(1-DBL_EPSILON); bhi = pow(bhi, g1)*(1+DBL_EPSILON);
/* Work out the lower and upper bounds for the gray value in the
* encoded space, then work out an average and error. Remove the
* previously added input quantization error at this point.
*/
gray = r * data.red_coefficient + g * data.green_coefficient +
b * data.blue_coefficient - 1./32768 - out_qe;
if (gray <= 0)
gray = 0;
else
{
gray *= (1 - 6 * DBL_EPSILON);
gray = pow(gray, data.gamma) * (1-DBL_EPSILON);
}
grayhi = rhi * data.red_coefficient + ghi * data.green_coefficient +
bhi * data.blue_coefficient + 1./32768 + out_qe;
grayhi *= (1 + 6 * DBL_EPSILON);
if (grayhi >= 1)
grayhi = 1;
else
grayhi = pow(grayhi, data.gamma) * (1+DBL_EPSILON);
err = (grayhi - gray) / 2;
gray = (grayhi + gray) / 2;
if (err <= in_qe)
err = gray * DBL_EPSILON;
else
err -= in_qe;
/* Validate that the error is within limits (this has caused
* problems before, it's much easier to detect them here.)
*/
if (err > pm->limit)
{
size_t pos = 0;
char buffer[128];
pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error ");
pos = safecatd(buffer, sizeof buffer, pos, err, 6);
pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6);
png_error(pp, buffer);
}
}
}
# endif /* !DIGITIZE */
that->bluef = that->greenf = that->redf = gray; that->bluef = that->greenf = that->redf = gray;
that->bluee = that->greene = that->rede = err; that->bluee = that->greene = that->rede = err;
@@ -7061,7 +7229,7 @@ IT(rgb_to_gray);
* int background_gamma_code, int need_expand, * int background_gamma_code, int need_expand,
* png_fixed_point background_gamma) * png_fixed_point background_gamma)
* *
* As with rgb_to_gray this ignores the gamma (at present.) * This ignores the gamma (at present.)
*/ */
#define data ITDATA(background) #define data ITDATA(background)
static image_pixel data; static image_pixel data;
@@ -7072,6 +7240,7 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
{ {
png_byte colour_type, bit_depth; png_byte colour_type, bit_depth;
png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */ png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */
int expand;
png_color_16 back; png_color_16 back;
/* We need a background colour, because we don't know exactly what transforms /* We need a background colour, because we don't know exactly what transforms
@@ -7089,10 +7258,14 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
{ {
colour_type = PNG_COLOR_TYPE_RGB; colour_type = PNG_COLOR_TYPE_RGB;
bit_depth = 8; bit_depth = 8;
expand = 0; /* passing in an RGB not a pixel index */
} }
else else
{
bit_depth = that->this.bit_depth; bit_depth = that->this.bit_depth;
expand = 1;
}
image_pixel_init(&data, random_bytes, colour_type, image_pixel_init(&data, random_bytes, colour_type,
bit_depth, 0/*x*/, 0/*unused: palette*/); bit_depth, 0/*x*/, 0/*unused: palette*/);
@@ -7113,11 +7286,9 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
back.gray = (png_uint_16)data.red; back.gray = (png_uint_16)data.red;
# ifdef PNG_FLOATING_POINT_SUPPORTED # ifdef PNG_FLOATING_POINT_SUPPORTED
png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1/*need expand*/, png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
0);
# else # else
png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
1/*need expand*/, 0);
# endif # endif
this->next->set(this->next, that, pp, pi); this->next->set(this->next, that, pp, pi);
@@ -7449,7 +7620,7 @@ perform_transform_test(png_modifier *pm)
png_byte bit_depth = 0; png_byte bit_depth = 0;
unsigned int palette_number = 0; unsigned int palette_number = 0;
while (next_format(&colour_type, &bit_depth, &palette_number)) while (next_format(&colour_type, &bit_depth, &palette_number, 0))
{ {
png_uint_32 counter = 0; png_uint_32 counter = 0;
size_t base_pos; size_t base_pos;
@@ -8134,14 +8305,25 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
* passed. Don't do these additional tests here - just log the * passed. Don't do these additional tests here - just log the
* original [es_lo..es_hi] values. * original [es_lo..es_hi] values.
*/ */
if (pass == 0 && vi->use_input_precision) if (pass == 0 && vi->use_input_precision && vi->dp->sbit)
{ {
/* Ok, something is wrong - this actually happens in current libpng /* Ok, something is wrong - this actually happens in current libpng
* 16-to-8 processing. Assume that the input value (id, adjusted * 16-to-8 processing. Assume that the input value (id, adjusted
* for sbit) can be anywhere between value-.5 and value+.5 - quite a * for sbit) can be anywhere between value-.5 and value+.5 - quite a
* large range if sbit is low. * large range if sbit is low.
*
* NOTE: at present because the libpng gamma table stuff has been
* changed to use a rounding algorithm to correct errors in 8-bit
* calculations the precise sbit calculation (a shift) has been
* lost. This can result in up to a +/-1 error in the presence of
* an sbit less than the bit depth.
*/ */
double tmp = (isbit - .5)/sbit_max; # if PNG_LIBPNG_VER < 10700
# define SBIT_ERROR .5
# else
# define SBIT_ERROR 1.
# endif
double tmp = (isbit - SBIT_ERROR)/sbit_max;
if (tmp <= 0) if (tmp <= 0)
tmp = 0; tmp = 0;
@@ -8160,10 +8342,10 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
if (is_lo < 0) if (is_lo < 0)
is_lo = 0; is_lo = 0;
tmp = (isbit + .5)/sbit_max; tmp = (isbit + SBIT_ERROR)/sbit_max;
if (tmp <= 0) if (tmp >= 1)
tmp = 0; tmp = 1;
else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1)
tmp = pow(tmp, vi->file_inverse); tmp = pow(tmp, vi->file_inverse);
@@ -8480,7 +8662,7 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
* Because there is limited precision in the input it is arguable that * Because there is limited precision in the input it is arguable that
* an acceptable result is any valid result from input-.5 to input+.5. * an acceptable result is any valid result from input-.5 to input+.5.
* The basic tests below do not do this, however if 'use_input_precision' * The basic tests below do not do this, however if 'use_input_precision'
* is set a subsequent test is performed below. * is set a subsequent test is performed above.
*/ */
PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U; PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U;
int processing; int processing;
@@ -8822,7 +9004,7 @@ perform_gamma_threshold_tests(png_modifier *pm)
* fact this test is somewhat excessive since libpng doesn't make this * fact this test is somewhat excessive since libpng doesn't make this
* decision based on colour type or bit depth! * decision based on colour type or bit depth!
*/ */
while (next_format(&colour_type, &bit_depth, &palette_number)) while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
if (palette_number == 0) if (palette_number == 0)
{ {
double test_gamma = 1.0; double test_gamma = 1.0;
@@ -8883,7 +9065,7 @@ static void perform_gamma_transform_tests(png_modifier *pm)
png_byte bit_depth = 0; png_byte bit_depth = 0;
unsigned int palette_number = 0; unsigned int palette_number = 0;
while (next_format(&colour_type, &bit_depth, &palette_number)) while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
{ {
unsigned int i, j; unsigned int i, j;
@@ -8913,7 +9095,7 @@ static void perform_gamma_sbit_tests(png_modifier *pm)
png_byte colour_type = 0, bit_depth = 0; png_byte colour_type = 0, bit_depth = 0;
unsigned int npalette = 0; unsigned int npalette = 0;
while (next_format(&colour_type, &bit_depth, &npalette)) while (next_format(&colour_type, &bit_depth, &npalette, 1/*gamma*/))
if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 && if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 &&
((colour_type == 3 && sbit < 8) || ((colour_type == 3 && sbit < 8) ||
(colour_type != 3 && sbit < bit_depth))) (colour_type != 3 && sbit < bit_depth)))
@@ -8948,6 +9130,7 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
# ifndef PNG_MAX_GAMMA_8 # ifndef PNG_MAX_GAMMA_8
# define PNG_MAX_GAMMA_8 11 # define PNG_MAX_GAMMA_8 11
# endif # endif
# define SBIT_16_TO_8 PNG_MAX_GAMMA_8
/* Include the alpha cases here. Note that sbit matches the internal value /* Include the alpha cases here. Note that sbit matches the internal value
* used by the library - otherwise we will get spurious errors from the * used by the library - otherwise we will get spurious errors from the
* internal sbit style approximation. * internal sbit style approximation.
@@ -8965,28 +9148,28 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD) fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD)
{ {
gamma_transform_test(pm, 0, 16, 0, pm->interlace_type, gamma_transform_test(pm, 0, 16, 0, pm->interlace_type,
1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8,
pm->use_input_precision_16to8, 1 /*scale16*/); pm->use_input_precision_16to8, 1 /*scale16*/);
if (fail(pm)) if (fail(pm))
return; return;
gamma_transform_test(pm, 2, 16, 0, pm->interlace_type, gamma_transform_test(pm, 2, 16, 0, pm->interlace_type,
1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8,
pm->use_input_precision_16to8, 1 /*scale16*/); pm->use_input_precision_16to8, 1 /*scale16*/);
if (fail(pm)) if (fail(pm))
return; return;
gamma_transform_test(pm, 4, 16, 0, pm->interlace_type, gamma_transform_test(pm, 4, 16, 0, pm->interlace_type,
1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8,
pm->use_input_precision_16to8, 1 /*scale16*/); pm->use_input_precision_16to8, 1 /*scale16*/);
if (fail(pm)) if (fail(pm))
return; return;
gamma_transform_test(pm, 6, 16, 0, pm->interlace_type, gamma_transform_test(pm, 6, 16, 0, pm->interlace_type,
1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8,
pm->use_input_precision_16to8, 1 /*scale16*/); pm->use_input_precision_16to8, 1 /*scale16*/);
if (fail(pm)) if (fail(pm))
@@ -9132,7 +9315,7 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
/* Skip the non-alpha cases - there is no setting of a transparency colour at /* Skip the non-alpha cases - there is no setting of a transparency colour at
* present. * present.
*/ */
while (next_format(&colour_type, &bit_depth, &palette_number)) while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0) if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0)
{ {
unsigned int i, j; unsigned int i, j;
@@ -9154,31 +9337,46 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
static void static void
init_gamma_errors(png_modifier *pm) init_gamma_errors(png_modifier *pm)
{ {
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; /* Use -1 to catch tests that were not actually run */
pm->error_color_8 = 0; pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = -1.;
pm->error_indexed = 0; pm->error_color_8 = -1.;
pm->error_gray_16 = pm->error_color_16 = 0; pm->error_indexed = -1.;
pm->error_gray_16 = pm->error_color_16 = -1.;
} }
static void static void
summarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth) print_one(const char *leader, double err)
{ {
if (err != -1.)
printf(" %s %.5f\n", leader, err);
}
static void
summarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth,
int indexed)
{
fflush(stderr);
if (who) if (who)
printf("Gamma correction with %s:\n", who); printf("\nGamma correction with %s:\n", who);
else
printf("\nBasic gamma correction:\n");
if (low_bit_depth) if (low_bit_depth)
{ {
printf(" 2 bit gray: %.5f\n", pm->error_gray_2); print_one(" 2 bit gray: ", pm->error_gray_2);
printf(" 4 bit gray: %.5f\n", pm->error_gray_4); print_one(" 4 bit gray: ", pm->error_gray_4);
printf(" 8 bit gray: %.5f\n", pm->error_gray_8); print_one(" 8 bit gray: ", pm->error_gray_8);
printf(" 8 bit color: %.5f\n", pm->error_color_8); print_one(" 8 bit color:", pm->error_color_8);
printf(" indexed: %.5f\n", pm->error_indexed); if (indexed)
print_one(" indexed: ", pm->error_indexed);
} }
#ifdef DO_16BIT print_one("16 bit gray: ", pm->error_gray_16);
printf(" 16 bit gray: %.5f\n", pm->error_gray_16); print_one("16 bit color:", pm->error_color_16);
printf(" 16 bit color: %.5f\n", pm->error_color_16);
#endif fflush(stdout);
} }
static void static void
@@ -9204,18 +9402,9 @@ perform_gamma_test(png_modifier *pm, int summary)
/* Now some real transforms. */ /* Now some real transforms. */
if (pm->test_gamma_transform) if (pm->test_gamma_transform)
{ {
init_gamma_errors(pm);
/*TODO: remove this. Necessary because the current libpng
* implementation works in 8 bits:
*/
if (pm->test_gamma_expand16)
pm->calculations_use_input_precision = 1;
perform_gamma_transform_tests(pm);
if (!calculations_use_input_precision)
pm->calculations_use_input_precision = 0;
if (summary) if (summary)
{ {
fflush(stderr);
printf("Gamma correction error summary\n\n"); printf("Gamma correction error summary\n\n");
printf("The printed value is the maximum error in the pixel values\n"); printf("The printed value is the maximum error in the pixel values\n");
printf("calculated by the libpng gamma correction code. The error\n"); printf("calculated by the libpng gamma correction code. The error\n");
@@ -9227,10 +9416,25 @@ perform_gamma_test(png_modifier *pm, int summary)
printf("less than 1 for formats with fewer than 8 bits and a small\n"); printf("less than 1 for formats with fewer than 8 bits and a small\n");
printf("number (typically less than 5) for the 16 bit formats.\n"); printf("number (typically less than 5) for the 16 bit formats.\n");
printf("For performance reasons the value for 16 bit formats\n"); printf("For performance reasons the value for 16 bit formats\n");
printf("increases when the image file includes an sBIT chunk.\n\n"); printf("increases when the image file includes an sBIT chunk.\n");
fflush(stdout);
summarize_gamma_errors(pm, 0/*who*/, 1);
} }
init_gamma_errors(pm);
/*TODO: remove this. Necessary because the current libpng
* implementation works in 8 bits:
*/
if (pm->test_gamma_expand16)
pm->calculations_use_input_precision = 1;
perform_gamma_transform_tests(pm);
if (!calculations_use_input_precision)
pm->calculations_use_input_precision = 0;
if (summary)
summarize_gamma_errors(pm, 0/*who*/, 1/*low bit depth*/, 1/*indexed*/);
if (fail(pm))
return;
} }
/* The sbit tests produce much larger errors: */ /* The sbit tests produce much larger errors: */
@@ -9240,7 +9444,10 @@ perform_gamma_test(png_modifier *pm, int summary)
perform_gamma_sbit_tests(pm); perform_gamma_sbit_tests(pm);
if (summary) if (summary)
summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U); summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U, 1/*indexed*/);
if (fail(pm))
return;
} }
#ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */ #ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */
@@ -9252,10 +9459,15 @@ perform_gamma_test(png_modifier *pm, int summary)
if (summary) if (summary)
{ {
printf("Gamma correction with 16 to 8 bit reduction:\n"); fflush(stderr);
printf("\nGamma correction with 16 to 8 bit reduction:\n");
printf(" 16 bit gray: %.5f\n", pm->error_gray_16); printf(" 16 bit gray: %.5f\n", pm->error_gray_16);
printf(" 16 bit color: %.5f\n", pm->error_color_16); printf(" 16 bit color: %.5f\n", pm->error_color_16);
fflush(stdout);
} }
if (fail(pm))
return;
} }
#endif #endif
@@ -9279,7 +9491,10 @@ perform_gamma_test(png_modifier *pm, int summary)
pm->maxout8 = maxout8; pm->maxout8 = maxout8;
if (summary) if (summary)
summarize_gamma_errors(pm, "background", 1); summarize_gamma_errors(pm, "background", 1, 0/*indexed*/);
if (fail(pm))
return;
} }
#endif #endif
@@ -9304,7 +9519,10 @@ perform_gamma_test(png_modifier *pm, int summary)
pm->calculations_use_input_precision = 0; pm->calculations_use_input_precision = 0;
if (summary) if (summary)
summarize_gamma_errors(pm, "alpha mode", 1); summarize_gamma_errors(pm, "alpha mode", 1, 0/*indexed*/);
if (fail(pm))
return;
} }
#endif #endif
} }
@@ -9812,6 +10030,19 @@ int main(int argc, char **argv)
/* Default to error on warning: */ /* Default to error on warning: */
pm.this.treat_warnings_as_errors = 1; pm.this.treat_warnings_as_errors = 1;
/* Default assume_16_bit_calculations appropriately; this tells the checking
* code that 16-bit arithmetic is used for 8-bit samples when it would make a
* difference.
*/
pm.assume_16_bit_calculations = PNG_LIBPNG_VER >= 10700;
/* Currently 16 bit expansion happens at the end of the pipeline, so the
* calculations are done in the input bit depth not the output.
*
* TODO: fix this
*/
pm.calculations_use_input_precision = 1U;
/* Store the test gammas */ /* Store the test gammas */
pm.gammas = gammas; pm.gammas = gammas;
pm.ngammas = (sizeof gammas) / (sizeof gammas[0]); pm.ngammas = (sizeof gammas) / (sizeof gammas[0]);
@@ -9822,13 +10053,16 @@ int main(int argc, char **argv)
pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]); pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]);
pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */ pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
/* The following allows results to pass if they correspond to anything in the /* The following allows results to pass if they correspond to anything in the
* transformed range [input-.5,input+.5]; this is is required because of the * transformed range [input-.5,input+.5]; this is is required because of the
* way libpng treates the 16_TO_8 flag when building the gamma tables. * way libpng treates the 16_TO_8 flag when building the gamma tables in
* releases up to 1.6.0.
* *
* TODO: review this * TODO: review this
*/ */
pm.use_input_precision_16to8 = 1U; pm.use_input_precision_16to8 = 1U;
pm.use_input_precision_sbit = 1U; /* because libpng now rounds sBIT */
/* Some default values (set the behavior for 'make check' here). /* Some default values (set the behavior for 'make check' here).
* These values simply control the maximum error permitted in the gamma * These values simply control the maximum error permitted in the gamma
@@ -9839,11 +10073,12 @@ int main(int argc, char **argv)
*/ */
pm.maxout8 = .1; /* Arithmetic error in *encoded* value */ pm.maxout8 = .1; /* Arithmetic error in *encoded* value */
pm.maxabs8 = .00005; /* 1/20000 */ pm.maxabs8 = .00005; /* 1/20000 */
pm.maxcalc8 = .004; /* +/-1 in 8 bits for compose errors */ pm.maxcalc8 = 1./255; /* +/-1 in 8 bits for compose errors */
pm.maxpc8 = .499; /* I.e., .499% fractional error */ pm.maxpc8 = .499; /* I.e., .499% fractional error */
pm.maxout16 = .499; /* Error in *encoded* value */ pm.maxout16 = .499; /* Error in *encoded* value */
pm.maxabs16 = .00005;/* 1/20000 */ pm.maxabs16 = .00005;/* 1/20000 */
pm.maxcalc16 =.000015;/* +/-1 in 16 bits for compose errors */ pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */
pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
/* NOTE: this is a reasonable perceptual limit. We assume that humans can /* NOTE: this is a reasonable perceptual limit. We assume that humans can
* perceive light level differences of 1% over a 100:1 range, so we need to * perceive light level differences of 1% over a 100:1 range, so we need to
@@ -9990,13 +10225,16 @@ int main(int argc, char **argv)
pm.interlace_type = PNG_INTERLACE_ADAM7; pm.interlace_type = PNG_INTERLACE_ADAM7;
else if (strcmp(*argv, "--use-input-precision") == 0) else if (strcmp(*argv, "--use-input-precision") == 0)
pm.use_input_precision = 1; pm.use_input_precision = 1U;
else if (strcmp(*argv, "--use-calculation-precision") == 0)
pm.use_input_precision = 0;
else if (strcmp(*argv, "--calculations-use-input-precision") == 0) else if (strcmp(*argv, "--calculations-use-input-precision") == 0)
pm.calculations_use_input_precision = 1; pm.calculations_use_input_precision = 1U;
else if (strcmp(*argv, "--assume-16-bit-calculations") == 0) else if (strcmp(*argv, "--assume-16-bit-calculations") == 0)
pm.assume_16_bit_calculations = 1; pm.assume_16_bit_calculations = 1U;
else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0) else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0)
pm.calculations_use_input_precision = pm.calculations_use_input_precision =