http://sourceforge.net/p/libpng/code/ci/a21a5b22c10b900d44d40fe30a203302b2a67f8b/ --- contrib/libtests/pngvalid.c +++ contrib/libtests/pngvalid.c @@ -258,7 +258,7 @@ make_random_bytes(seed, bytes, 4); } -#ifdef PNG_READ_SUPPORTED +#if defined PNG_READ_SUPPORTED || defined PNG_WRITE_tRNS_SUPPORTED static void randomize(void *pv, size_t size) { @@ -267,7 +267,9 @@ } #define RANDOMIZE(this) randomize(&(this), sizeof (this)) - +#endif /* READ || WRITE_tRNS */ + +#ifdef PNG_READ_SUPPORTED static unsigned int random_mod(unsigned int max) { @@ -295,7 +297,8 @@ /* A numeric ID based on PNG file characteristics. The 'do_interlace' field * simply records whether pngvalid did the interlace itself or whether it * was done by libpng. Width and height must be less than 256. 'palette' is an - * index of the palette to use for formats with a palette (0 otherwise.) + * index of the palette to use for formats with a palette otherwise a boolean + * indicating if a tRNS chunk was generated. */ #define FILEID(col, depth, palette, interlace, width, height, do_interlace) \ ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \ @@ -316,12 +319,16 @@ png_uint_32 w, png_uint_32 h, int do_interlace) { pos = safecat(buffer, bufsize, pos, colour_types[colour_type]); - if (npalette > 0) + if (colour_type == 3) /* must have a palette */ { pos = safecat(buffer, bufsize, pos, "["); pos = safecatn(buffer, bufsize, pos, npalette); pos = safecat(buffer, bufsize, pos, "]"); } + + else if (npalette != 0) + pos = safecat(buffer, bufsize, pos, "+tRNS"); + pos = safecat(buffer, bufsize, pos, " "); pos = safecatn(buffer, bufsize, pos, bit_depth); pos = safecat(buffer, bufsize, pos, " bit"); @@ -378,25 +385,32 @@ static int next_format(png_bytep colour_type, png_bytep bit_depth, - unsigned int* palette_number, int no_low_depth_gray) + unsigned int* palette_number, int low_depth_gray, int tRNS) { if (*bit_depth == 0) { *colour_type = 0; - if (no_low_depth_gray) + if (low_depth_gray) + *bit_depth = 1; + else *bit_depth = 8; - else - *bit_depth = 1; *palette_number = 0; return 1; } - if (*colour_type == 3) - { - /* Add multiple palettes for colour type 3. */ - if (++*palette_number < PALETTE_COUNT(*bit_depth)) + if (*colour_type < 4/*no alpha channel*/) + { + /* Add multiple palettes for colour type 3, one image with tRNS + * and one without for other non-alpha formats: + */ + unsigned int pn = ++*palette_number; + png_byte ct = *colour_type; + + if (((ct == 0/*GRAY*/ || ct/*RGB*/ == 2) && tRNS && pn < 2) || + (ct == 3/*PALETTE*/ && pn < PALETTE_COUNT(*bit_depth))) return 1; + /* No: next bit depth */ *palette_number = 0; } @@ -1959,6 +1973,7 @@ /* Run tests on reading with a combination of transforms, */ unsigned int test_transform :1; + unsigned int test_tRNS :1; /* Includes tRNS images */ /* When to use the use_input_precision option, this controls the gamma * validation code checks. If set any value that is within the transformed @@ -1989,6 +2004,16 @@ unsigned int test_gamma_alpha_mode :1; unsigned int test_gamma_expand16 :1; unsigned int test_exhaustive :1; + + /* Whether or not to run the low-bit-depth grayscale tests. This fail on + * gamma images in some cases because of gross inaccuracies in the grayscale + * gamma handling for low bit depth. + */ + unsigned int test_lbg :1; + unsigned int test_lbg_gamma_threshold :1; + unsigned int test_lbg_gamma_transform :1; + unsigned int test_lbg_gamma_sbit :1; + unsigned int test_lbg_gamma_composition :1; unsigned int log :1; /* Log max error */ @@ -2042,6 +2067,11 @@ pm->test_standard = 0; pm->test_size = 0; pm->test_transform = 0; +# ifdef PNG_WRITE_tRNS_SUPPORTED + pm->test_tRNS = 1; +# else + pm->test_tRNS = 0; +# endif pm->use_input_precision = 0; pm->use_input_precision_sbit = 0; pm->use_input_precision_16to8 = 0; @@ -2054,6 +2084,11 @@ pm->test_gamma_background = 0; pm->test_gamma_alpha_mode = 0; pm->test_gamma_expand16 = 0; + pm->test_lbg = 1; + pm->test_lbg_gamma_threshold = 1; + pm->test_lbg_gamma_transform = 1; + pm->test_lbg_gamma_sbit = 1; + pm->test_lbg_gamma_composition = 1; pm->test_exhaustive = 0; pm->log = 0; @@ -3192,6 +3227,45 @@ } } +#ifdef PNG_WRITE_tRNS_SUPPORTED +static void +set_random_tRNS(png_structp pp, png_infop pi, PNG_CONST png_byte colour_type, + PNG_CONST int bit_depth) +{ + /* To make this useful the tRNS color needs to match at least one pixel. + * Random values are fine for gray, including the 16-bit case where we know + * that the test image contains all the gray values. For RGB we need more + * method as only 65536 different RGB values are generated. + */ + png_color_16 tRNS; + const png_uint_16 mask = (png_uint_16)((1U << bit_depth)-1); + + RANDOMIZE(tRNS); + + if (colour_type & 2/*RGB*/) + { + if (bit_depth == 8) + { + tRNS.blue = tRNS.red ^ tRNS.green; + tRNS.red &= mask; + tRNS.green &= mask; + tRNS.blue &= mask; + } + + else /* bit_depth == 16 */ + { + tRNS.green = (png_uint_16)(tRNS.red * 257); + tRNS.blue = (png_uint_16)(tRNS.green * 17); + } + } + + else + tRNS.gray &= mask; + + png_set_tRNS(pp, pi, NULL, 0, &tRNS); +} +#endif + /* The number of passes is related to the interlace type. There was no libpng * API to determine this prior to 1.5, so we need an inquiry function: */ @@ -3525,6 +3599,11 @@ if (colour_type == 3) /* palette */ init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/); +# ifdef PNG_WRITE_tRNS_SUPPORTED + else if (palette_number) + set_random_tRNS(pp, pi, colour_type, bit_depth); +# endif + png_write_info(pp, pi); if (png_get_rowbytes(pp, pi) != @@ -3598,19 +3677,20 @@ } static void -make_transform_images(png_store *ps) +make_transform_images(png_modifier *pm) { png_byte colour_type = 0; png_byte bit_depth = 0; unsigned int palette_number = 0; /* This is in case of errors. */ - safecat(ps->test, sizeof ps->test, 0, "make standard images"); + safecat(pm->this.test, sizeof pm->this.test, 0, "make standard images"); /* Use next_format to enumerate all the combinations we test, including - * generating multiple low bit depth palette images. - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 0)) + * generating multiple low bit depth palette images. Non-A images (palette + * and direct) are created with and without tRNS chunks. + */ + while (next_format(&colour_type, &bit_depth, &palette_number, 1, 1)) { int interlace_type; @@ -3621,7 +3701,7 @@ standard_name(name, sizeof name, 0, colour_type, bit_depth, palette_number, interlace_type, 0, 0, 0); - make_transform_image(ps, colour_type, bit_depth, palette_number, + make_transform_image(&pm->this, colour_type, bit_depth, palette_number, interlace_type, name); } } @@ -4287,6 +4367,7 @@ size_t cbRow; /* Bytes in a row of the output image */ int do_interlace; /* Do interlacing internally */ int is_transparent; /* Transparency information was present. */ + int has_tRNS; /* color type GRAY or RGB with a tRNS chunk. */ int speed; /* Doing a speed test */ int use_update_info;/* Call update_info, not start_image */ struct @@ -4619,14 +4700,14 @@ case 0: dp->transparent.red = dp->transparent.green = dp->transparent.blue = trans_color->gray; - dp->is_transparent = 1; + dp->has_tRNS = 1; break; case 2: dp->transparent.red = trans_color->red; dp->transparent.green = trans_color->green; dp->transparent.blue = trans_color->blue; - dp->is_transparent = 1; + dp->has_tRNS = 1; break; case 3: @@ -5518,7 +5599,7 @@ if (this->colour_type == PNG_COLOR_TYPE_GRAY) { if (this->bit_depth < 8) - this->bit_depth = 8; + this->bit_depth = this->sample_depth = 8; if (this->have_tRNS) { @@ -5553,9 +5634,11 @@ this->alphaf = 0; else this->alphaf = 1; - - this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; } + else + this->alphaf = 1; + + this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; } /* The error in the alpha is zero and the sBIT value comes from the @@ -5848,8 +5931,9 @@ /* If png_set_filler is in action then fake the output color type to include * an alpha channel where appropriate. */ - if (dp->output_bit_depth >= 8 && (dp->output_colour_type == PNG_COLOR_TYPE_RGB || - dp->output_colour_type == PNG_COLOR_TYPE_GRAY) && dp->this.filler) + if (dp->output_bit_depth >= 8 && + (dp->output_colour_type == PNG_COLOR_TYPE_RGB || + dp->output_colour_type == PNG_COLOR_TYPE_GRAY) && dp->this.filler) dp->output_colour_type |= 4; /* Validate the combination of colour type and bit depth that we are getting @@ -6372,6 +6456,13 @@ transform_display *that, png_structp pp, png_infop pi) { png_set_tRNS_to_alpha(pp); + + /* If there was a tRNS chunk that would get expanded and add an alpha + * channel is_transparent must be updated: + */ + if (that->this.has_tRNS) + that->this.is_transparent = 1; + this->next->set(this->next, that, pp, pi); } @@ -6430,6 +6521,7 @@ transform_display *that, png_structp pp, png_infop pi) { png_set_gray_to_rgb(pp); + /* NOTE: this doesn't result in tRNS expansion. */ this->next->set(this->next, that, pp, pi); } @@ -6489,6 +6581,10 @@ transform_display *that, png_structp pp, png_infop pi) { png_set_expand(pp); + + if (that->this.has_tRNS) + that->this.is_transparent = 1; + this->next->set(this->next, that, pp, pi); } @@ -6539,6 +6635,7 @@ png_infop pi) { png_set_expand_gray_1_2_4_to_8(pp); + /* NOTE: don't expect this to expand tRNS */ this->next->set(this->next, that, pp, pi); } @@ -6570,6 +6667,11 @@ transform_display *that, png_structp pp, png_infop pi) { png_set_expand_16(pp); + + /* NOTE: at present libpng does SET_EXPAND as well, so tRNS is expanded. */ + if (that->this.has_tRNS) + that->this.is_transparent = 1; + this->next->set(this->next, that, pp, pi); } @@ -6940,14 +7042,14 @@ * 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.25. - * 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. + * NOTE: this magic number was determined by experiment to be about + * 1.263. 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( # if DIGITIZE - 1.25 + 1.3 # else 1.0 # endif @@ -7111,7 +7213,8 @@ 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 : + const unsigned int gamma_depth = (sample_depth == 16 ? + PNG_MAX_GAMMA_8 : (pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth)); int isgray; double r, g, b; @@ -7125,56 +7228,73 @@ * will be identical after this operation if there is only one * transform, feel free to delete the png_error checks on this below in * the future (this is just me trying to ensure it works!) + * + * Interval arithmetic is exact, but to implement it it must be + * possible to control the floating point implementation rounding mode. + * This cannot be done in ANSI-C, so instead I reduce the 'lo' values + * by DBL_EPSILON and increase the 'hi' values by the same. */ +# define DD(v,d,r) (digitize(v*(1-DBL_EPSILON), d, r) * (1-DBL_EPSILON)) +# define DU(v,d,r) (digitize(v*(1+DBL_EPSILON), d, r) * (1+DBL_EPSILON)) + r = rlo = rhi = that->redf; rlo -= that->rede; - rlo = digitize(rlo, calc_depth, 1/*round*/); + rlo = DD(rlo, calc_depth, 1/*round*/); rhi += that->rede; - rhi = digitize(rhi, calc_depth, 1/*round*/); + rhi = DU(rhi, calc_depth, 1/*round*/); g = glo = ghi = that->greenf; glo -= that->greene; - glo = digitize(glo, calc_depth, 1/*round*/); + glo = DD(glo, calc_depth, 1/*round*/); ghi += that->greene; - ghi = digitize(ghi, calc_depth, 1/*round*/); + ghi = DU(ghi, calc_depth, 1/*round*/); b = blo = bhi = that->bluef; blo -= that->bluee; - blo = digitize(blo, calc_depth, 1/*round*/); + blo = DD(blo, calc_depth, 1/*round*/); bhi += that->greene; - bhi = digitize(bhi, calc_depth, 1/*round*/); + bhi = DU(bhi, calc_depth, 1/*round*/); isgray = r==g && g==b; if (data.gamma != 1) { PNG_CONST double power = 1/data.gamma; - PNG_CONST double abse = calc_depth == 16 ? .5/65535 : .5/255; - - /* 'abse' is the absolute error permitted in linear calculations. It - * is used here to capture the error permitted in the handling - * (undoing) of the gamma encoding. Once again digitization occurs - * to handle the upper and lower bounds of the values. This is - * where the real errors are introduced. + PNG_CONST double abse = .5/(sample_depth == 16 ? 65535 : 255); + + /* If a gamma calculation is done it is done using lookup tables of + * precision gamma_depth, so the already digitized value above may + * need to be further digitized here. */ + if (gamma_depth != calc_depth) + { + rlo = DD(rlo, gamma_depth, 0/*truncate*/); + rhi = DU(rhi, gamma_depth, 0/*truncate*/); + glo = DD(glo, gamma_depth, 0/*truncate*/); + ghi = DU(ghi, gamma_depth, 0/*truncate*/); + blo = DD(blo, gamma_depth, 0/*truncate*/); + bhi = DU(bhi, gamma_depth, 0/*truncate*/); + } + + /* 'abse' is the error in the gamma table calculation itself. */ r = pow(r, power); - rlo = digitize(pow(rlo, power)-abse, calc_depth, 1); - rhi = digitize(pow(rhi, power)+abse, calc_depth, 1); + rlo = DD(pow(rlo, power)-abse, calc_depth, 1); + rhi = DU(pow(rhi, power)+abse, calc_depth, 1); g = pow(g, power); - glo = digitize(pow(glo, power)-abse, calc_depth, 1); - ghi = digitize(pow(ghi, power)+abse, calc_depth, 1); + glo = DD(pow(glo, power)-abse, calc_depth, 1); + ghi = DU(pow(ghi, power)+abse, calc_depth, 1); b = pow(b, power); - blo = digitize(pow(blo, power)-abse, calc_depth, 1); - bhi = digitize(pow(bhi, power)+abse, calc_depth, 1); + blo = DD(pow(blo, power)-abse, calc_depth, 1); + bhi = DU(pow(bhi, power)+abse, calc_depth, 1); } /* Now calculate the actual gray values. Although the error in the * coefficients depends on whether they were specified on the command * line (in which case truncation to 15 bits happened) or not (rounding * was used) the maxium error in an individual coefficient is always - * 1/32768, because even in the rounding case the requirement that + * 2/32768, because even in the rounding case the requirement that * coefficients add up to 32768 can cause a larger rounding error. * * The only time when rounding doesn't occur in 1.5.5 and later is when @@ -7185,19 +7305,19 @@ { PNG_CONST int do_round = data.gamma != 1 || calc_depth == 16; - PNG_CONST double ce = 1. / 32768; - - graylo = digitize(rlo * (data.red_coefficient-ce) + + PNG_CONST double ce = 2. / 32768; + + graylo = DD(rlo * (data.red_coefficient-ce) + glo * (data.green_coefficient-ce) + - blo * (data.blue_coefficient-ce), gamma_depth, do_round); - if (graylo <= 0) - graylo = 0; - - grayhi = digitize(rhi * (data.red_coefficient+ce) + + blo * (data.blue_coefficient-ce), calc_depth, do_round); + if (graylo > gray) /* always accept the right answer */ + graylo = gray; + + grayhi = DU(rhi * (data.red_coefficient+ce) + ghi * (data.green_coefficient+ce) + - bhi * (data.blue_coefficient+ce), gamma_depth, do_round); - if (grayhi >= 1) - grayhi = 1; + bhi * (data.blue_coefficient+ce), calc_depth, do_round); + if (grayhi < gray) + grayhi = gray; } /* And invert the gamma. */ @@ -7205,10 +7325,24 @@ { PNG_CONST double power = data.gamma; + /* And this happens yet again, shifting the values once more. */ + if (gamma_depth != sample_depth) + { + rlo = DD(rlo, gamma_depth, 0/*truncate*/); + rhi = DU(rhi, gamma_depth, 0/*truncate*/); + glo = DD(glo, gamma_depth, 0/*truncate*/); + ghi = DU(ghi, gamma_depth, 0/*truncate*/); + blo = DD(blo, gamma_depth, 0/*truncate*/); + bhi = DU(bhi, gamma_depth, 0/*truncate*/); + } + gray = pow(gray, power); - graylo = digitize(pow(graylo, power), sample_depth, 1); - grayhi = digitize(pow(grayhi, power), sample_depth, 1); + graylo = DD(pow(graylo, power), sample_depth, 1); + grayhi = DU(pow(grayhi, power), sample_depth, 1); } + +# undef DD +# undef DU /* Now the error can be calculated. * @@ -7260,16 +7394,28 @@ { /* 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.) + * built in error in the coefficients because they only have 15 bits + * and are adjusted to make sure they add up to 32768. This + * involves a integer calculation with truncation of the form: + * + * ((int)(coefficient * 100000) * 32768)/100000 + * + * This is done to the red and green coefficients (the ones + * provided to the API) then blue is calculated from them so the + * result adds up to 32768. In the worst case this can result in + * a -1 error in red and green and a +2 error in blue. Consequently + * the worst case in the calculation below is 2/32768 error. + * + * TODO: consider fixing this in libpng by rounding the calculation + * limiting the error to 1/32768. + * + * Handling this by adding 2/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; + be * data.blue_coefficient + 2./32768 + gray * 5 * DBL_EPSILON; } else @@ -7304,7 +7450,7 @@ * 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; + b * data.blue_coefficient - 2./32768 - out_qe; if (gray <= 0) gray = 0; else @@ -7314,7 +7460,7 @@ } grayhi = rhi * data.red_coefficient + ghi * data.green_coefficient + - bhi * data.blue_coefficient + 1./32768 + out_qe; + bhi * data.blue_coefficient + 2./32768 + out_qe; grayhi *= (1 + 6 * DBL_EPSILON); if (grayhi >= 1) grayhi = 1; @@ -7429,6 +7575,9 @@ else { + if (that->this.has_tRNS) + that->this.is_transparent = 1; + bit_depth = that->this.bit_depth; expand = 1; } @@ -7506,13 +7655,13 @@ /* Remove the alpha type and set the alpha (not in that order.) */ that->alphaf = 1; that->alphae = 0; - - if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) - that->colour_type = PNG_COLOR_TYPE_RGB; - else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) - that->colour_type = PNG_COLOR_TYPE_GRAY; - /* PNG_COLOR_TYPE_PALETTE is not changed */ - } + } + + if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) + that->colour_type = PNG_COLOR_TYPE_RGB; + else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) + that->colour_type = PNG_COLOR_TYPE_GRAY; + /* PNG_COLOR_TYPE_PALETTE is not changed */ this->next->mod(this->next, that, pp, display); } @@ -8301,7 +8450,8 @@ png_byte bit_depth = 0; unsigned int palette_number = 0; - while (next_format(&colour_type, &bit_depth, &palette_number, 0)) + while (next_format(&colour_type, &bit_depth, &palette_number, pm->test_lbg, + pm->test_tRNS)) { png_uint_32 counter = 0; size_t base_pos; @@ -8604,7 +8754,9 @@ vi->outlog = outlog(dp->pm, in_depth, out_depth); if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 || - (dp->this.colour_type == 3 && dp->this.is_transparent)) + (dp->this.colour_type == 3 && dp->this.is_transparent) || + ((dp->this.colour_type == 0 || dp->this.colour_type == 2) && + dp->this.has_tRNS)) { vi->do_background = dp->do_background; @@ -8634,7 +8786,7 @@ vi->background_blue = b; } } - else + else /* Do not expect any background processing */ vi->do_background = 0; if (vi->do_background == 0) @@ -9350,6 +9502,7 @@ png_uint_32 y; PNG_CONST store_palette_entry *in_palette = dp->this.palette; PNG_CONST int in_is_transparent = dp->this.is_transparent; + int process_tRNS; int out_npalette = -1; int out_is_transparent = 0; /* Just refers to the palette case */ store_palette out_palette; @@ -9365,6 +9518,7 @@ processing = (vi.gamma_correction > 0 && !dp->threshold_test) || in_bd != out_bd || in_ct != out_ct || vi.do_background; + process_tRNS = dp->this.has_tRNS && vi.do_background; /* TODO: FIX THIS: MAJOR BUG! If the transformations all happen inside * the palette there is no way of finding out, because libpng fails to @@ -9403,8 +9557,8 @@ /* Handle input alpha - png_set_background will cause the output * alpha to disappear so there is nothing to check. */ - if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || (in_ct == 3 && - in_is_transparent)) + if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || + (in_ct == 3 && in_is_transparent)) { PNG_CONST unsigned int input_alpha = in_ct == 3 ? dp->this.palette[in_index].alpha : @@ -9433,6 +9587,35 @@ */ alpha = input_alpha >> vi.isbit_shift; alpha /= vi.sbit_max; + } + } + + else if (process_tRNS) + { + /* alpha needs to be set appropriately for this pixel, it is + * currently 1 and needs to be 0 for an input pixel which matches + * the values in tRNS. + */ + switch (in_ct) + { + case 0: /* gray */ + if (sample(std, in_ct, in_bd, x, 0, 0, 0) == + dp->this.transparent.red) + alpha = 0; + break; + + case 2: /* RGB */ + if (sample(std, in_ct, in_bd, x, 0, 0, 0) == + dp->this.transparent.red && + sample(std, in_ct, in_bd, x, 1, 0, 0) == + dp->this.transparent.green && + sample(std, in_ct, in_bd, x, 2, 0, 0) == + dp->this.transparent.blue) + alpha = 0; + break; + + default: + break; } } @@ -9545,7 +9728,7 @@ modification_reset(d.pm->modifications); - /* Get a png_struct for writing the image. */ + /* Get a png_struct for reading the image. */ pp = set_modifier_for_read(d.pm, &pi, d.this.id, name); standard_palette_init(&d.this); @@ -9684,9 +9867,13 @@ /* Don't test more than one instance of each palette - it's pointless, in * fact this test is somewhat excessive since libpng doesn't make this * decision based on colour type or bit depth! - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) - if (palette_number == 0) + * + * CHANGED: now test two palettes and, as a side effect, images with and + * without tRNS. + */ + while (next_format(&colour_type, &bit_depth, &palette_number, + pm->test_lbg_gamma_threshold, pm->test_tRNS)) + if (palette_number < 2) { double test_gamma = 1.0; while (test_gamma >= .4) @@ -9746,7 +9933,8 @@ png_byte bit_depth = 0; unsigned int palette_number = 0; - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) + while (next_format(&colour_type, &bit_depth, &palette_number, + pm->test_lbg_gamma_transform, pm->test_tRNS)) { unsigned int i, j; @@ -9776,7 +9964,8 @@ png_byte colour_type = 0, bit_depth = 0; unsigned int npalette = 0; - while (next_format(&colour_type, &bit_depth, &npalette, 1/*gamma*/)) + while (next_format(&colour_type, &bit_depth, &npalette, + pm->test_lbg_gamma_sbit, pm->test_tRNS)) if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 && ((colour_type == 3 && sbit < 8) || (colour_type != 3 && sbit < bit_depth))) @@ -9967,8 +10156,17 @@ } background.index = 193; /* rgb(193,193,193) to detect errors */ + if (!(colour_type & PNG_COLOR_MASK_COLOR)) { + /* Because, currently, png_set_background is always called with + * 'need_expand' false in this case and because the gamma test itself + * doesn't cause an expand to 8-bit for lower bit depths the colour must + * be reduced to the correct range. + */ + if (bit_depth < 8) + background.gray &= (png_uint_16)((1U << bit_depth)-1); + /* Grayscale input, we do not convert to RGB (TBD), so we must set the * background to gray - else libpng seems to fail. */ @@ -10017,9 +10215,18 @@ /* Skip the non-alpha cases - there is no setting of a transparency colour at * present. - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) - if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0) + * + * TODO: incorrect; the palette case sets tRNS and, now RGB and gray do, + * however the palette case fails miserably so is commented out below. + */ + while (next_format(&colour_type, &bit_depth, &palette_number, + pm->test_lbg_gamma_composition, pm->test_tRNS)) + if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0 +#if 0 /* TODO: FIXME */ + /*TODO: FIXME: this should work */ + || colour_type == 3 +#endif + || (colour_type != 3 && palette_number != 0)) { unsigned int i, j; @@ -10751,6 +10958,18 @@ pm.ngammas = ARRAY_SIZE(gammas); pm.ngamma_tests = 0; /* default to off */ + /* Low bit depth gray images don't do well in the gamma tests, until + * this is fixed turn them off for some gamma cases: + */ +# ifdef PNG_WRITE_tRNS_SUPPORTED + pm.test_tRNS = 1; +# endif + pm.test_lbg = 0; + pm.test_lbg_gamma_threshold = 1; + pm.test_lbg_gamma_transform = 0/*PNG_LIBPNG_VER >= 10700*/; + pm.test_lbg_gamma_sbit = 1; + pm.test_lbg_gamma_composition = 0; + /* And the test encodings */ pm.encodings = test_encodings; pm.nencodings = ARRAY_SIZE(test_encodings); @@ -10863,7 +11082,7 @@ pm.test_gamma_transform = 1; pm.test_gamma_sbit = 1; pm.test_gamma_scale16 = 1; - pm.test_gamma_background = 1; + pm.test_gamma_background = 1; /* composition */ pm.test_gamma_alpha_mode = 1; } @@ -10911,6 +11130,24 @@ else if (strcmp(*argv, "--noexpand16") == 0) pm.test_gamma_expand16 = 0; + + else if (strcmp(*argv, "--low-depth-gray") == 0) + pm.test_lbg = pm.test_lbg_gamma_threshold = + pm.test_lbg_gamma_transform = pm.test_lbg_gamma_sbit = + pm.test_lbg_gamma_composition = 1; + + else if (strcmp(*argv, "--nolow-depth-gray") == 0) + pm.test_lbg = pm.test_lbg_gamma_threshold = + pm.test_lbg_gamma_transform = pm.test_lbg_gamma_sbit = + pm.test_lbg_gamma_composition = 0; + +# ifdef PNG_WRITE_tRNS_SUPPORTED + else if (strcmp(*argv, "--tRNS") == 0) + pm.test_tRNS = 1; +# endif + + else if (strcmp(*argv, "--notRNS") == 0) + pm.test_tRNS = 0; else if (strcmp(*argv, "--more-gammas") == 0) pm.ngamma_tests = 3U; @@ -11102,7 +11339,7 @@ Try { /* Make useful base images */ - make_transform_images(&pm.this); + make_transform_images(&pm); /* Perform the standard and gamma tests. */ if (pm.test_standard)