mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
[libpng17] Made 8-bit compose and rgb_to_grayscale accuracy improvements.
These changes cause 16-bit arithmetic to be used for 8-bit data in the gamma corrected compose and grayscale operations. The arithmetic errors have three sources all of which are fixed in this commit: 1) 8-bit linear calculations produce massive errors for lower intensity values. 2) The old 16-bit "16 to 8" gamma table code erroneously wrote the lowest output value into a table entry which corresponded to multiple output values (so where the value written should have been the closest to the transformed input value.) 3) In a number of cases the code to access the 16-bit table did not round; it did a simple shift, which was wrong and made the side effects of (2) even worse. The new gamma code does not have the 16-to-8 problem at the cost of slighly more calculations and the algorithm used to minimize the number of calculations has been extended to all the 16-bit tables; it has advantages for any significant gamma correction.
This commit is contained in:
parent
ac3b4d9b69
commit
3e42c81193
17
ANNOUNCE
17
ANNOUNCE
@ -28,6 +28,23 @@ Changes since the last public release (1.6.0):
|
||||
|
||||
Version 1.7.0alpha01 [December 10, 2012]
|
||||
Started 1.7.0 branch from libpng-1.6.0beta33.
|
||||
Made 8-bit compose and rgb_to_grayscale accuracy improvements. These
|
||||
changes cause 16-bit arithmetic to be used for 8-bit data in the gamma
|
||||
corrected compose and grayscale operations. The arithmetic errors have
|
||||
three sources all of which are fixed in this commit:
|
||||
1) 8-bit linear calculations produce massive errors for lower intensity
|
||||
values.
|
||||
2) The old 16-bit "16 to 8" gamma table code erroneously wrote the lowest
|
||||
output value into a table entry which corresponded to multiple output
|
||||
values (so where the value written should have been the closest to the
|
||||
transformed input value.)
|
||||
3) In a number of cases the code to access the 16-bit table did not round;
|
||||
it did a simple shift, which was wrong and made the side effects of (2)
|
||||
even worse.
|
||||
The new gamma code does not have the 16-to-8 problem at the cost of slighly
|
||||
more calculations and the algorithm used to minimize the number of
|
||||
calculations has been extended to all the 16-bit tables; it has advantages
|
||||
for any significant gamma correction.
|
||||
|
||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
||||
(subscription required; visit
|
||||
|
17
CHANGES
17
CHANGES
@ -4313,6 +4313,23 @@ Version 1.6.0beta33 [December 10, 2012]
|
||||
|
||||
Version 1.7.0alpha01 [December 10, 2012]
|
||||
Started 1.7.0 branch from libpng-1.6.0beta33.
|
||||
Made 8-bit compose and rgb_to_grayscale accuracy improvements. These
|
||||
changes cause 16-bit arithmetic to be used for 8-bit data in the gamma
|
||||
corrected compose and grayscale operations. The arithmetic errors have
|
||||
three sources all of which are fixed in this commit:
|
||||
1) 8-bit linear calculations produce massive errors for lower intensity
|
||||
values.
|
||||
2) The old 16-bit "16 to 8" gamma table code erroneously wrote the lowest
|
||||
output value into a table entry which corresponded to multiple output
|
||||
values (so where the value written should have been the closest to the
|
||||
transformed input value.)
|
||||
3) In a number of cases the code to access the 16-bit table did not round;
|
||||
it did a simple shift, which was wrong and made the side effects of (2)
|
||||
even worse.
|
||||
The new gamma code does not have the 16-to-8 problem at the cost of slighly
|
||||
more calculations and the algorithm used to minimize the number of
|
||||
calculations has been extended to all the 16-bit tables; it has advantages
|
||||
for any significant gamma correction.
|
||||
|
||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
||||
(subscription required; visit
|
||||
|
@ -344,11 +344,16 @@ standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
|
||||
|
||||
static int
|
||||
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)
|
||||
{
|
||||
*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;
|
||||
}
|
||||
|
||||
@ -1828,6 +1833,7 @@ typedef struct png_modifier
|
||||
double maxout16; /* Maximum output value error */
|
||||
double maxabs16; /* 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% */
|
||||
|
||||
/* This is set by transforms that need to allow a higher limit, it is an
|
||||
@ -1870,7 +1876,12 @@ typedef struct png_modifier
|
||||
/* Run tests on reading with a combiniation of transforms, */
|
||||
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_sbit :1;
|
||||
unsigned int use_input_precision_16to8 :1;
|
||||
@ -1880,8 +1891,8 @@ typedef struct png_modifier
|
||||
*/
|
||||
unsigned int calculations_use_input_precision :1;
|
||||
|
||||
/* If set assume that the calculations are done in 16 bits even if both input
|
||||
* and output are 8 bit or less.
|
||||
/* If set assume that the calculations are done in 16 bits even if the sample
|
||||
* depth is 8 bits.
|
||||
*/
|
||||
unsigned int assume_16_bit_calculations :1;
|
||||
|
||||
@ -1936,6 +1947,7 @@ modifier_init(png_modifier *pm)
|
||||
pm->test_uses_encoding = 0;
|
||||
pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0;
|
||||
pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0;
|
||||
pm->maxcalcG = 0;
|
||||
pm->limit = 4E-3;
|
||||
pm->log8 = pm->log16 = 0; /* Means 'off' */
|
||||
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
|
||||
@ -1950,6 +1962,7 @@ modifier_init(png_modifier *pm)
|
||||
pm->use_input_precision_sbit = 0;
|
||||
pm->use_input_precision_16to8 = 0;
|
||||
pm->calculations_use_input_precision = 0;
|
||||
pm->assume_16_bit_calculations = 0;
|
||||
pm->test_gamma_threshold = 0;
|
||||
pm->test_gamma_transform = 0;
|
||||
pm->test_gamma_sbit = 0;
|
||||
@ -1964,8 +1977,16 @@ modifier_init(png_modifier *pm)
|
||||
}
|
||||
|
||||
#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 < 10600
|
||||
|
||||
/* 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
|
||||
* bit precision. This only affects those of the following limits that pertain
|
||||
@ -1973,8 +1994,8 @@ modifier_init(png_modifier *pm)
|
||||
* called directly.
|
||||
*/
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
static double digitize(PNG_CONST png_modifier *pm, double value,
|
||||
int sample_depth, int do_round)
|
||||
#if DIGITIZE
|
||||
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
|
||||
* multiple of the digitization factor - 8 or 16 bits depending on both the
|
||||
@ -1982,14 +2003,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
|
||||
* be truncated.
|
||||
*/
|
||||
PNG_CONST unsigned int digitization_factor =
|
||||
(pm->assume_16_bit_calculations || sample_depth == 16) ? 65535 : 255;
|
||||
PNG_CONST unsigned int digitization_factor = (1U << depth) -1;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
if (value <= 0)
|
||||
value = 0;
|
||||
|
||||
else if (value >= 1)
|
||||
value = 1;
|
||||
|
||||
@ -1998,31 +2019,30 @@ static double digitize(PNG_CONST png_modifier *pm, double value,
|
||||
return floor(value)/digitization_factor;
|
||||
}
|
||||
#endif
|
||||
#endif /* RGB_TO_GRAY */
|
||||
|
||||
#if (defined PNG_READ_GAMMA_SUPPORTED) ||\
|
||||
(defined PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
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
|
||||
* the calculations.
|
||||
*/
|
||||
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
|
||||
!pm->calculations_use_input_precision)))
|
||||
if (pm->assume_16_bit_calculations ||
|
||||
(pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
|
||||
return pm->maxabs16;
|
||||
else
|
||||
return pm->maxabs8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
|
||||
{
|
||||
/* Error in the linear composition arithmetic - only relevant when
|
||||
* composition actually happens (0 < alpha < 1).
|
||||
*/
|
||||
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
|
||||
!pm->calculations_use_input_precision)))
|
||||
if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
|
||||
return pm->maxcalc16;
|
||||
else if (pm->assume_16_bit_calculations)
|
||||
return pm->maxcalcG;
|
||||
else
|
||||
return pm->maxcalc8;
|
||||
}
|
||||
@ -2032,8 +2052,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
|
||||
* value is a percentage but this routine returns a simple number.
|
||||
*/
|
||||
if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
|
||||
!pm->calculations_use_input_precision)))
|
||||
if (pm->assume_16_bit_calculations ||
|
||||
(pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
|
||||
return pm->maxpc16 * .01;
|
||||
else
|
||||
return pm->maxpc8 * .01;
|
||||
@ -2065,8 +2085,7 @@ static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
|
||||
if (out_depth == 4)
|
||||
return .90644-.5;
|
||||
|
||||
if (out_depth == 16 && (in_depth == 16 ||
|
||||
!pm->calculations_use_input_precision))
|
||||
if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
|
||||
return pm->maxout16;
|
||||
|
||||
/* This is the case where the value was calculated at 8-bit precision then
|
||||
@ -2099,8 +2118,7 @@ static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth)
|
||||
return pm->log8;
|
||||
}
|
||||
|
||||
if (out_depth == 16 && (in_depth == 16 ||
|
||||
!pm->calculations_use_input_precision))
|
||||
if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16)
|
||||
{
|
||||
if (pm->log16 == 0)
|
||||
return 65536;
|
||||
@ -2125,8 +2143,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,
|
||||
int out_depth)
|
||||
{
|
||||
if (out_depth == 16 && in_depth != 16
|
||||
&& pm->calculations_use_input_precision)
|
||||
if (out_depth == 16 && in_depth != 16 &&
|
||||
pm->calculations_use_input_precision)
|
||||
return 257;
|
||||
else
|
||||
return 1;
|
||||
@ -3473,7 +3491,7 @@ make_transform_images(png_store *ps)
|
||||
/* 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))
|
||||
while (next_format(&colour_type, &bit_depth, &palette_number, 0))
|
||||
{
|
||||
int interlace_type;
|
||||
|
||||
@ -5784,12 +5802,9 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
|
||||
|
||||
memset(out_palette, 0x5e, sizeof out_palette);
|
||||
|
||||
/* assume-8-bit-calculations means assume that if the input has 8 bit
|
||||
* (or less) samples and the output has 16 bit samples the calculations
|
||||
* will be done with 8 bit precision, not 16.
|
||||
*
|
||||
* TODO: fix this in libpng; png_set_expand_16 should cause 16 bit
|
||||
* calculations to be used throughout.
|
||||
/* use-input-precision means assume that if the input has 8 bit (or less)
|
||||
* samples and the output has 16 bit samples the calculations will be done
|
||||
* with 8 bit precision, not 16.
|
||||
*/
|
||||
if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16)
|
||||
in_sample_depth = 8;
|
||||
@ -5800,7 +5815,8 @@ transform_image_validate(transform_display *dp, png_const_structp pp,
|
||||
!dp->pm->calculations_use_input_precision)
|
||||
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
|
||||
digitization_error = .5 * 257;
|
||||
@ -6616,10 +6632,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)
|
||||
{
|
||||
/* The 16 bit case ends up producing a maximum error of about
|
||||
* +/-5 in 65535, allow for +/-8 with the given gamma.
|
||||
/* The computations have the form:
|
||||
*
|
||||
* 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
|
||||
* convertion 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
|
||||
@ -6637,7 +6666,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
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@ -6782,9 +6811,14 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
image_pixel_convert_PLTE(that);
|
||||
|
||||
/* Image now has RGB channels... */
|
||||
# if DIGITIZE
|
||||
{
|
||||
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;
|
||||
double r, g, b;
|
||||
double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi;
|
||||
@ -6800,28 +6834,28 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
*/
|
||||
r = rlo = rhi = that->redf;
|
||||
rlo -= that->rede;
|
||||
rlo = digitize(pm, rlo, sample_depth, 1/*round*/);
|
||||
rlo = digitize(rlo, calc_depth, 1/*round*/);
|
||||
rhi += that->rede;
|
||||
rhi = digitize(pm, rhi, sample_depth, 1/*round*/);
|
||||
rhi = digitize(rhi, calc_depth, 1/*round*/);
|
||||
|
||||
g = glo = ghi = that->greenf;
|
||||
glo -= that->greene;
|
||||
glo = digitize(pm, glo, sample_depth, 1/*round*/);
|
||||
glo = digitize(glo, calc_depth, 1/*round*/);
|
||||
ghi += that->greene;
|
||||
ghi = digitize(pm, ghi, sample_depth, 1/*round*/);
|
||||
ghi = digitize(ghi, calc_depth, 1/*round*/);
|
||||
|
||||
b = blo = bhi = that->bluef;
|
||||
blo -= that->bluee;
|
||||
blo = digitize(pm, blo, sample_depth, 1/*round*/);
|
||||
blo = digitize(blo, calc_depth, 1/*round*/);
|
||||
bhi += that->greene;
|
||||
bhi = digitize(pm, bhi, sample_depth, 1/*round*/);
|
||||
bhi = digitize(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 = 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
|
||||
* is used here to capture the error permitted in the handling
|
||||
@ -6830,16 +6864,16 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
* where the real errors are introduced.
|
||||
*/
|
||||
r = pow(r, power);
|
||||
rlo = digitize(pm, pow(rlo, power)-abse, sample_depth, 1);
|
||||
rhi = digitize(pm, pow(rhi, power)+abse, sample_depth, 1);
|
||||
rlo = digitize(pow(rlo, power)-abse, calc_depth, 1);
|
||||
rhi = digitize(pow(rhi, power)+abse, calc_depth, 1);
|
||||
|
||||
g = pow(g, power);
|
||||
glo = digitize(pm, pow(glo, power)-abse, sample_depth, 1);
|
||||
ghi = digitize(pm, pow(ghi, power)+abse, sample_depth, 1);
|
||||
glo = digitize(pow(glo, power)-abse, calc_depth, 1);
|
||||
ghi = digitize(pow(ghi, power)+abse, calc_depth, 1);
|
||||
|
||||
b = pow(b, power);
|
||||
blo = digitize(pm, pow(blo, power)-abse, sample_depth, 1);
|
||||
bhi = digitize(pm, pow(bhi, power)+abse, sample_depth, 1);
|
||||
blo = digitize(pow(blo, power)-abse, calc_depth, 1);
|
||||
bhi = digitize(pow(bhi, power)+abse, calc_depth, 1);
|
||||
}
|
||||
|
||||
/* Now calculate the actual gray values. Although the error in the
|
||||
@ -6856,18 +6890,18 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
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;
|
||||
|
||||
graylo = digitize(pm, rlo * (data.red_coefficient-ce) +
|
||||
graylo = digitize(rlo * (data.red_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)
|
||||
graylo = 0;
|
||||
|
||||
grayhi = digitize(pm, rhi * (data.red_coefficient+ce) +
|
||||
grayhi = digitize(rhi * (data.red_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)
|
||||
grayhi = 1;
|
||||
}
|
||||
@ -6878,8 +6912,8 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
PNG_CONST double power = data.gamma;
|
||||
|
||||
gray = pow(gray, power);
|
||||
graylo = digitize(pm, pow(graylo, power), sample_depth, 1);
|
||||
grayhi = digitize(pm, pow(grayhi, power), sample_depth, 1);
|
||||
graylo = digitize(pow(graylo, power), sample_depth, 1);
|
||||
grayhi = digitize(pow(grayhi, power), sample_depth, 1);
|
||||
}
|
||||
|
||||
/* Now the error can be calculated.
|
||||
@ -6897,7 +6931,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
|
||||
err = fabs(graylo-gray);
|
||||
|
||||
/* Check that this worked: */
|
||||
if (err > display->pm->limit)
|
||||
if (err > pm->limit)
|
||||
{
|
||||
size_t pos = 0;
|
||||
char buffer[128];
|
||||
@ -6905,12 +6939,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 = safecatd(buffer, sizeof buffer, pos, err, 6);
|
||||
pos = safecat(buffer, sizeof buffer, pos, " exceeds limit ");
|
||||
pos = safecatd(buffer, sizeof buffer, pos,
|
||||
display->pm->limit, 6);
|
||||
pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6);
|
||||
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 convertions 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->bluee = that->greene = that->rede = err;
|
||||
@ -6959,7 +7101,7 @@ IT(rgb_to_gray);
|
||||
* int background_gamma_code, int need_expand,
|
||||
* 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)
|
||||
static image_pixel data;
|
||||
@ -6970,6 +7112,7 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
|
||||
{
|
||||
png_byte colour_type, bit_depth;
|
||||
png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */
|
||||
int expand;
|
||||
png_color_16 back;
|
||||
|
||||
/* We need a background colour, because we don't know exactly what transforms
|
||||
@ -6987,10 +7130,14 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
|
||||
{
|
||||
colour_type = PNG_COLOR_TYPE_RGB;
|
||||
bit_depth = 8;
|
||||
expand = 0; /* passing in an RGB not a pixel index */
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bit_depth = that->this.bit_depth;
|
||||
expand = 1;
|
||||
}
|
||||
|
||||
image_pixel_init(&data, random_bytes, colour_type,
|
||||
bit_depth, 0/*x*/, 0/*unused: palette*/);
|
||||
@ -7011,11 +7158,9 @@ image_transform_png_set_background_set(PNG_CONST image_transform *this,
|
||||
back.gray = (png_uint_16)data.red;
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1/*need expand*/,
|
||||
0);
|
||||
png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
|
||||
# else
|
||||
png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE,
|
||||
1/*need expand*/, 0);
|
||||
png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0);
|
||||
# endif
|
||||
|
||||
this->next->set(this->next, that, pp, pi);
|
||||
@ -7347,7 +7492,7 @@ perform_transform_test(png_modifier *pm)
|
||||
png_byte bit_depth = 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;
|
||||
size_t base_pos;
|
||||
@ -8032,14 +8177,25 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
|
||||
* passed. Don't do these additional tests here - just log the
|
||||
* 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
|
||||
* 16-to-8 processing. Assume that the input value (id, adjusted
|
||||
* for sbit) can be anywhere between value-.5 and value+.5 - quite a
|
||||
* 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 < 10600
|
||||
# define SBIT_ERROR .5
|
||||
# else
|
||||
# define SBIT_ERROR 1.
|
||||
# endif
|
||||
double tmp = (isbit - SBIT_ERROR)/sbit_max;
|
||||
|
||||
if (tmp <= 0)
|
||||
tmp = 0;
|
||||
@ -8058,10 +8214,10 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
|
||||
if (is_lo < 0)
|
||||
is_lo = 0;
|
||||
|
||||
tmp = (isbit + .5)/sbit_max;
|
||||
tmp = (isbit + SBIT_ERROR)/sbit_max;
|
||||
|
||||
if (tmp <= 0)
|
||||
tmp = 0;
|
||||
if (tmp >= 1)
|
||||
tmp = 1;
|
||||
|
||||
else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1)
|
||||
tmp = pow(tmp, vi->file_inverse);
|
||||
@ -8378,7 +8534,7 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp,
|
||||
* 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.
|
||||
* 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;
|
||||
int processing;
|
||||
@ -8720,7 +8876,7 @@ perform_gamma_threshold_tests(png_modifier *pm)
|
||||
* 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))
|
||||
while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/))
|
||||
if (palette_number == 0)
|
||||
{
|
||||
double test_gamma = 1.0;
|
||||
@ -8781,7 +8937,7 @@ static void perform_gamma_transform_tests(png_modifier *pm)
|
||||
png_byte bit_depth = 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;
|
||||
|
||||
@ -8811,7 +8967,7 @@ static void perform_gamma_sbit_tests(png_modifier *pm)
|
||||
png_byte colour_type = 0, bit_depth = 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 &&
|
||||
((colour_type == 3 && sbit < 8) ||
|
||||
(colour_type != 3 && sbit < bit_depth)))
|
||||
@ -8846,6 +9002,7 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
|
||||
# ifndef PNG_MAX_GAMMA_8
|
||||
# define PNG_MAX_GAMMA_8 11
|
||||
# endif
|
||||
# define SBIT_16_TO_8 PNG_MAX_GAMMA_8
|
||||
/* Include the alpha cases here. Note that sbit matches the internal value
|
||||
* used by the library - otherwise we will get spurious errors from the
|
||||
* internal sbit style approximation.
|
||||
@ -8863,28 +9020,28 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
|
||||
fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD)
|
||||
{
|
||||
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*/);
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
|
||||
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*/);
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
|
||||
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*/);
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
|
||||
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*/);
|
||||
|
||||
if (fail(pm))
|
||||
@ -9030,7 +9187,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
|
||||
* 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)
|
||||
{
|
||||
unsigned int i, j;
|
||||
@ -9052,31 +9209,46 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
|
||||
static void
|
||||
init_gamma_errors(png_modifier *pm)
|
||||
{
|
||||
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
|
||||
pm->error_color_8 = 0;
|
||||
pm->error_indexed = 0;
|
||||
pm->error_gray_16 = pm->error_color_16 = 0;
|
||||
/* Use -1 to catch tests that were not actually run */
|
||||
pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = -1.;
|
||||
pm->error_color_8 = -1.;
|
||||
pm->error_indexed = -1.;
|
||||
pm->error_gray_16 = pm->error_color_16 = -1.;
|
||||
}
|
||||
|
||||
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)
|
||||
printf("Gamma correction with %s:\n", who);
|
||||
printf("\nGamma correction with %s:\n", who);
|
||||
|
||||
else
|
||||
printf("\nBasic gamma correction:\n");
|
||||
|
||||
if (low_bit_depth)
|
||||
{
|
||||
printf(" 2 bit gray: %.5f\n", pm->error_gray_2);
|
||||
printf(" 4 bit gray: %.5f\n", pm->error_gray_4);
|
||||
printf(" 8 bit gray: %.5f\n", pm->error_gray_8);
|
||||
printf(" 8 bit color: %.5f\n", pm->error_color_8);
|
||||
printf(" indexed: %.5f\n", pm->error_indexed);
|
||||
print_one(" 2 bit gray: ", pm->error_gray_2);
|
||||
print_one(" 4 bit gray: ", pm->error_gray_4);
|
||||
print_one(" 8 bit gray: ", pm->error_gray_8);
|
||||
print_one(" 8 bit color:", pm->error_color_8);
|
||||
if (indexed)
|
||||
print_one(" indexed: ", pm->error_indexed);
|
||||
}
|
||||
|
||||
#ifdef DO_16BIT
|
||||
printf(" 16 bit gray: %.5f\n", pm->error_gray_16);
|
||||
printf(" 16 bit color: %.5f\n", pm->error_color_16);
|
||||
#endif
|
||||
print_one("16 bit gray: ", pm->error_gray_16);
|
||||
print_one("16 bit color:", pm->error_color_16);
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -9102,18 +9274,9 @@ perform_gamma_test(png_modifier *pm, int summary)
|
||||
/* Now some real transforms. */
|
||||
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)
|
||||
{
|
||||
fflush(stderr);
|
||||
printf("Gamma correction error summary\n\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");
|
||||
@ -9125,10 +9288,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("number (typically less than 5) for the 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");
|
||||
|
||||
summarize_gamma_errors(pm, 0/*who*/, 1);
|
||||
printf("increases when the image file includes an sBIT chunk.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
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: */
|
||||
@ -9138,7 +9316,10 @@ perform_gamma_test(png_modifier *pm, int summary)
|
||||
perform_gamma_sbit_tests(pm);
|
||||
|
||||
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 */
|
||||
@ -9150,10 +9331,15 @@ perform_gamma_test(png_modifier *pm, int 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 color: %.5f\n", pm->error_color_16);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -9177,7 +9363,10 @@ perform_gamma_test(png_modifier *pm, int summary)
|
||||
pm->maxout8 = maxout8;
|
||||
|
||||
if (summary)
|
||||
summarize_gamma_errors(pm, "background", 1);
|
||||
summarize_gamma_errors(pm, "background", 1, 0/*indexed*/);
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -9202,7 +9391,10 @@ perform_gamma_test(png_modifier *pm, int summary)
|
||||
pm->calculations_use_input_precision = 0;
|
||||
|
||||
if (summary)
|
||||
summarize_gamma_errors(pm, "alpha mode", 1);
|
||||
summarize_gamma_errors(pm, "alpha mode", 1, 0/*indexed*/);
|
||||
|
||||
if (fail(pm))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -9710,6 +9902,22 @@ int main(int argc, char **argv)
|
||||
/* Default to error on warning: */
|
||||
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.
|
||||
*
|
||||
* TODO: IMPORTANT; set to '>= 10600' below to enable development, change
|
||||
* this to the correct value before release!
|
||||
*/
|
||||
pm.assume_16_bit_calculations = PNG_LIBPNG_VER >= 10600;
|
||||
|
||||
/* 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 */
|
||||
pm.gammas = gammas;
|
||||
pm.ngammas = (sizeof gammas) / (sizeof gammas[0]);
|
||||
@ -9720,13 +9928,16 @@ int main(int argc, char **argv)
|
||||
pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]);
|
||||
|
||||
pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
*/
|
||||
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).
|
||||
* These values simply control the maximum error permitted in the gamma
|
||||
@ -9737,11 +9948,12 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
pm.maxout8 = .1; /* Arithmetic error in *encoded* value */
|
||||
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.maxout16 = .499; /* Error in *encoded* value */
|
||||
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
|
||||
* perceive light level differences of 1% over a 100:1 range, so we need to
|
||||
@ -9888,13 +10100,16 @@ int main(int argc, char **argv)
|
||||
pm.interlace_type = PNG_INTERLACE_ADAM7;
|
||||
|
||||
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)
|
||||
pm.calculations_use_input_precision = 1;
|
||||
pm.calculations_use_input_precision = 1U;
|
||||
|
||||
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)
|
||||
pm.calculations_use_input_precision =
|
||||
|
238
contrib/tools/scale.c
Normal file
238
contrib/tools/scale.c
Normal file
@ -0,0 +1,238 @@
|
||||
/* Given a target range and a source range work out an expression to scale from
|
||||
* the source to the target of the form:
|
||||
*
|
||||
* (number * mult + add)>>16
|
||||
*
|
||||
* The command arguments are:
|
||||
*
|
||||
* scale target source
|
||||
*
|
||||
* and the program works out a pair of numbers, mult and add, that evaluate:
|
||||
*
|
||||
* number * target
|
||||
* round( --------------- )
|
||||
* source
|
||||
*
|
||||
* exactly for number in the range 0..source
|
||||
*/
|
||||
#define _ISOC99_SOURCE 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
static double minerr;
|
||||
static unsigned long minmult, minadd, minshift;
|
||||
static long mindelta;
|
||||
|
||||
static int
|
||||
test(unsigned long target, unsigned long source, unsigned long mult,
|
||||
long add, unsigned long shift, long delta)
|
||||
{
|
||||
unsigned long i;
|
||||
double maxerr = 0;
|
||||
double rs = (double)target/source;
|
||||
|
||||
for (i=0; i<=source; ++i)
|
||||
{
|
||||
unsigned long t = i*mult+add;
|
||||
double err = fabs((t >> shift) - i*rs);
|
||||
|
||||
if (err > minerr)
|
||||
return 0;
|
||||
|
||||
if (err > maxerr)
|
||||
maxerr = err;
|
||||
}
|
||||
|
||||
if (maxerr < minerr)
|
||||
{
|
||||
minerr = maxerr;
|
||||
minmult = mult;
|
||||
minadd = add;
|
||||
minshift = shift;
|
||||
mindelta = delta;
|
||||
}
|
||||
|
||||
return maxerr < .5;
|
||||
}
|
||||
|
||||
static int
|
||||
dotest(unsigned long target, unsigned long source, unsigned long mult,
|
||||
long add, unsigned long shift, long delta, int print)
|
||||
{
|
||||
if (test(target, source, mult, add, shift, delta))
|
||||
{
|
||||
if (print & 4)
|
||||
printf(" {%11lu,%6ld /* >>%lu */ }, /* %lu/%lu */\n",
|
||||
mult, add, shift, target, source);
|
||||
|
||||
else if (print & 2)
|
||||
printf(" {%11lu,%6ld,%3lu }, /* %lu/%lu */\n",
|
||||
mult, add, shift, target, source);
|
||||
|
||||
else if (print)
|
||||
printf("number * %lu/%lu = (number * %lu + %ld) >> %lu [delta %ld]\n",
|
||||
target, source, mult, add, shift, delta);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
find(unsigned long target, unsigned long source, int print, int fixshift)
|
||||
{
|
||||
unsigned long shift = 0;
|
||||
unsigned long shiftlim = 0;
|
||||
|
||||
/* In the final math the sum is at most (source*mult+add) >> shift, so:
|
||||
*
|
||||
* source*mult+add < 1<<32
|
||||
* mult < (1<<32)/source
|
||||
*
|
||||
* but:
|
||||
*
|
||||
* mult = (target<<shift)/source
|
||||
*
|
||||
* so:
|
||||
*
|
||||
* (target<<shift) < (1<<32)
|
||||
*/
|
||||
if (fixshift < 0)
|
||||
while ((target<<shiftlim) < 0x80000000U) ++shiftlim;
|
||||
|
||||
else
|
||||
shift = shiftlim = (unsigned long)fixshift;
|
||||
|
||||
minerr = 1E8;
|
||||
|
||||
for (; shift<=shiftlim; ++shift)
|
||||
{
|
||||
unsigned long mult = ((target<<shift) + (source>>1)) / source;
|
||||
long delta;
|
||||
long limit = 1; /* seems to be sufficient */
|
||||
long add, start, end;
|
||||
|
||||
end = 1<<shift;
|
||||
start = -end;
|
||||
|
||||
for (add=start; add<=end; ++add)
|
||||
if (dotest(target,source,mult,add,shift,0,print))
|
||||
return 1;
|
||||
|
||||
for (delta=1; delta<=limit; ++delta)
|
||||
{
|
||||
# if 0
|
||||
fprintf(stderr, "%lu/%lu: shift %lu, delta %lu\n", target, source,
|
||||
shift, delta);
|
||||
# endif
|
||||
|
||||
for (add=start; add<=end; ++add)
|
||||
{
|
||||
if (dotest(target, source, mult-delta, add, shift, -delta, print))
|
||||
return 1;
|
||||
|
||||
if (dotest(target, source, mult+delta, add, shift, delta, print))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print & 4)
|
||||
printf(" {%11lu,%6ld /* >>%lu */ }, /* %lu/%lu ERROR: .5+%g*/\n",
|
||||
minmult, minadd, minshift, target, source, minerr-.5);
|
||||
|
||||
else if (print & 2)
|
||||
printf(" {%11lu,%6ld,%3lu }, /* %lu/%lu ERROR: .5+%g*/\n",
|
||||
minmult, minadd, minshift, target, source, minerr-.5);
|
||||
|
||||
else if (print)
|
||||
printf(
|
||||
"number * %lu/%lu ~= (number * %lu + %ld) >> %lu +/-.5+%g [delta %ld]\n",
|
||||
target, source, minmult, minadd, minshift, minerr-.5, mindelta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s {--denominator|--maxshift|--code} target {source}\n"
|
||||
" For each 'source' prints 'mult' and 'add' such that:\n\n"
|
||||
" (number * mult + add) >> 16 = round(number*target/source)\n\n"
|
||||
" for all integer values of number in the range 0..source.\n\n"
|
||||
" --denominator: swap target and source (specify a single source first\n"
|
||||
" and follow with multiple targets.)\n"
|
||||
" --maxshift: find the lowest shift value that works for all the\n"
|
||||
" repeated 'source' values\n"
|
||||
" --code: output C code for array/structure initialization\n",
|
||||
prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
int i, err = 0, maxshift = 0, firstsrc = 1, code = 0, denominator = 0;
|
||||
unsigned long target, shift = 0;
|
||||
|
||||
while (argc > 1)
|
||||
{
|
||||
if (strcmp(argv[firstsrc], "--maxshift") == 0)
|
||||
{
|
||||
maxshift = 1;
|
||||
++firstsrc;
|
||||
}
|
||||
|
||||
else if (strcmp(argv[firstsrc], "--code") == 0)
|
||||
{
|
||||
code = 1;
|
||||
++firstsrc;
|
||||
}
|
||||
|
||||
else if (strcmp(argv[firstsrc], "--denominator") == 0)
|
||||
{
|
||||
denominator = 1;
|
||||
++firstsrc;
|
||||
}
|
||||
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (argc < 2+firstsrc)
|
||||
usage(argv[0]);
|
||||
|
||||
target = strtoul(argv[firstsrc++], 0, 0);
|
||||
if (target == 0) usage(argv[0]);
|
||||
|
||||
for (i=firstsrc; i<argc; ++i)
|
||||
{
|
||||
unsigned long source = strtoul(argv[i], 0, 0);
|
||||
|
||||
if (source == 0) usage(argv[0]);
|
||||
|
||||
if (!find(denominator ? source : target, denominator ? target : source,
|
||||
maxshift ? 0 : 1+code, -1))
|
||||
err = 1;
|
||||
|
||||
if (minshift > shift) shift = minshift;
|
||||
}
|
||||
|
||||
if (maxshift) for (i=firstsrc; i<argc; ++i)
|
||||
{
|
||||
unsigned long source = strtoul(argv[i], 0, 0);
|
||||
|
||||
if (!find(denominator ? source : target, denominator ? target : source,
|
||||
code ? 4 : 1, shift))
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* Just an exit code - the printout above lists the problem */
|
||||
return err;
|
||||
}
|
660
png.c
660
png.c
@ -247,9 +247,7 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
|
||||
# endif
|
||||
|
||||
# ifdef PNG_USER_CHUNK_MALLOC_MAX
|
||||
/* Added at libpng-1.2.43 and 1.4.1, required only for read but exists
|
||||
* in png_struct regardless.
|
||||
*/
|
||||
/* Added at libpng-1.2.43 and 1.4.1 */
|
||||
create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
|
||||
# endif
|
||||
# endif
|
||||
@ -473,9 +471,10 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
|
||||
/* Free any tRNS entry */
|
||||
if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
|
||||
{
|
||||
info_ptr->valid &= ~PNG_INFO_tRNS;
|
||||
png_free(png_ptr, info_ptr->trans_alpha);
|
||||
info_ptr->trans_alpha = NULL;
|
||||
info_ptr->valid &= ~PNG_INFO_tRNS;
|
||||
info_ptr->num_trans = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -732,29 +731,6 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# if PNG_LIBPNG_VER < 10700
|
||||
/* To do: remove the following from libpng-1.7 */
|
||||
/* Original API that uses a private buffer in png_struct.
|
||||
* Deprecated because it causes png_struct to carry a spurious temporary
|
||||
* buffer (png_struct::time_buffer), better to have the caller pass this in.
|
||||
*/
|
||||
png_const_charp PNGAPI
|
||||
png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime)
|
||||
{
|
||||
if (png_ptr != NULL)
|
||||
{
|
||||
/* The only failure above if png_ptr != NULL is from an invalid ptime */
|
||||
if (!png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime))
|
||||
png_warning(png_ptr, "Ignoring invalid time value");
|
||||
|
||||
else
|
||||
return png_ptr->time_buffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
# endif
|
||||
# endif /* PNG_TIME_RFC1123_SUPPORTED */
|
||||
|
||||
#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
|
||||
@ -2287,7 +2263,7 @@ void /* PRIVATE */
|
||||
png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
|
||||
{
|
||||
/* Set the rgb_to_gray coefficients from the colorspace. */
|
||||
if (!png_ptr->rgb_to_gray_coefficients_set &&
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_RGB_TO_GRAY_SET) == 0 &&
|
||||
(png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
{
|
||||
/* png_set_background has not been called, get the coefficients from the Y
|
||||
@ -3263,6 +3239,7 @@ png_gamma_significant(png_fixed_point gamma_val)
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* A local convenience routine. */
|
||||
#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
|
||||
static png_fixed_point
|
||||
png_product2(png_fixed_point a, png_fixed_point b)
|
||||
{
|
||||
@ -3283,6 +3260,7 @@ png_product2(png_fixed_point a, png_fixed_point b)
|
||||
|
||||
return 0; /* overflow */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The inverse of the above. */
|
||||
png_fixed_point
|
||||
@ -3661,6 +3639,7 @@ png_gamma_correct(png_structrp png_ptr, unsigned int value,
|
||||
return png_gamma_16bit_correct(value, gamma_val);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Internal function to build a single 16-bit table - the table consists of
|
||||
* 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
|
||||
* to shift the input values right (or 16-number_of_signifiant_bits).
|
||||
@ -3670,7 +3649,7 @@ png_gamma_correct(png_structrp png_ptr, unsigned int value,
|
||||
* should be somewhere that will be cleaned.
|
||||
*/
|
||||
static void
|
||||
png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,
|
||||
png_build_16bit_table(png_structrp png_ptr, png_uint_16p *ptable,
|
||||
PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
|
||||
{
|
||||
/* Various values derived from 'shift': */
|
||||
@ -3751,7 +3730,7 @@ png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable,
|
||||
|
||||
/* 'num' is the number of tables and also the number of low bits of low
|
||||
* bits of the input 16-bit value used to select a table. Each table is
|
||||
* itself index by the high 8 bits of the value.
|
||||
* itself indexed by the high 8 bits of the value.
|
||||
*/
|
||||
for (i = 0; i < num; i++)
|
||||
table[i] = (png_uint_16p)png_malloc(png_ptr,
|
||||
@ -3818,6 +3797,504 @@ png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable,
|
||||
table[i] = (png_byte)i;
|
||||
}
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
static void
|
||||
png_build_8to16_table(png_structrp png_ptr, png_uint_16pp ptable,
|
||||
PNG_CONST png_fixed_point gamma_val)
|
||||
{
|
||||
unsigned int i;
|
||||
png_uint_16p table = *ptable = (png_uint_16p)png_malloc(png_ptr,
|
||||
sizeof (png_uint_16[256]));
|
||||
|
||||
if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++)
|
||||
table[i] = png_gamma_16bit_correct(i*257, gamma_val);
|
||||
|
||||
else for (i=0; i<256; ++i)
|
||||
table[i] = (png_uint_16)(i*257);
|
||||
}
|
||||
|
||||
static void
|
||||
png_build_16to8_table(png_structrp png_ptr, png_bytepp ptable8,
|
||||
png_uint_16pp ptable16, png_fixed_point gamma_val, int gamma_shift)
|
||||
/* Build a table of (1<<(16-gamma_shift))+1 entries to find 8-bit values
|
||||
* encoded by gamma_val. The table is to be indexed with a 16-bit value
|
||||
* scaled down by gamma_shift:
|
||||
*
|
||||
* table[(value + (1<<(gamma_shift-1)) >> gamma_shift]
|
||||
*
|
||||
* Because of the rounding the table is 2^(16-gamma_shift)+1 entries.
|
||||
* Each table entry must contain value^gamma_val, rounded to 8 bits.
|
||||
*/
|
||||
{
|
||||
unsigned int size = 1U << (16-gamma_shift);
|
||||
unsigned int add = (gamma_shift > 0 ? 1U<<(gamma_shift-1) : 0U);
|
||||
png_bytep table8;
|
||||
png_uint_16p table16;
|
||||
unsigned int i;
|
||||
|
||||
/* If 'table8' it gets the output values as 8-bit bytes, if 'table16' is set
|
||||
* the same values are scaled by 257 to give 16-bit values.
|
||||
*/
|
||||
if (ptable8)
|
||||
{
|
||||
table8 = png_voidcast(png_bytep, png_malloc(png_ptr, size+1));
|
||||
*ptable8 = table8;
|
||||
table8[0] = 0;
|
||||
}
|
||||
|
||||
else
|
||||
table8 = NULL;
|
||||
|
||||
if (ptable16)
|
||||
{
|
||||
table16 = png_voidcast(png_uint_16p, png_malloc(png_ptr,
|
||||
sizeof (png_uint_16) * (size+1)));
|
||||
*ptable16 = table16;
|
||||
table16[0] = 0;
|
||||
}
|
||||
|
||||
else
|
||||
table16 = NULL;
|
||||
|
||||
i = 1;
|
||||
|
||||
# define FILL(val) do {\
|
||||
if (table8) table8[i] = (val);\
|
||||
if (table16) table16[i] = (png_uint_16)((val)*257U);\
|
||||
++i;
|
||||
} while (0)
|
||||
|
||||
if (gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED)
|
||||
{
|
||||
/* gamma < 1; the output values will jump by more than one for each table
|
||||
* entry initially.
|
||||
*/
|
||||
png_byte last_out = 0;
|
||||
|
||||
while (i < size)
|
||||
{
|
||||
png_byte out = (png_byte)PNG_DIV257(png_gamma_16bit_correct(
|
||||
i << gamma_shift, gamma_val));
|
||||
|
||||
FILL(out);
|
||||
|
||||
if (out <= last_out)
|
||||
{
|
||||
/* The table values are no longer advancing at each step, swap to
|
||||
* finding the *last* table index corresponding to this value
|
||||
* of 'out' - this is the one that corresponds to out+.5, below this
|
||||
* is calculated as out*257+128; the exact value would be
|
||||
* out*257+128.5, so we get a lower value, rounding ensures that we
|
||||
* fill all the table entries corresponding to 'out' (with some very
|
||||
* small chance of error at the boundaries.)
|
||||
*/
|
||||
png_fixed_point gamma_inv = png_reciprocal(gamma_val);
|
||||
|
||||
while (out < 255 && i < size)
|
||||
{
|
||||
unsigned int next_index = (png_gamma_16bit_correct(out*257+128,
|
||||
gamma_inv) + add) >> gamma_shift;
|
||||
|
||||
while (i <= next_index && i < size)
|
||||
FILL(out);
|
||||
|
||||
++out;
|
||||
}
|
||||
|
||||
break; /* fill remaining entries with 255 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED)
|
||||
{
|
||||
/* gamma > 1; initially multiple table entries will correspond to the same
|
||||
* value, invert the above loops.
|
||||
*/
|
||||
png_fixed_point gamma_inv = png_reciprocal(gamma_val);
|
||||
png_byte out = 0;
|
||||
|
||||
while (out < 255)
|
||||
{
|
||||
unsigned int next_index = (png_gamma_16bit_correct(out*257+128,
|
||||
gamma_inv) + add) >> gamma_shift;
|
||||
|
||||
/* If this 'out' value falls in the same slot as the last one
|
||||
* recalculate the value for this slot.
|
||||
*/
|
||||
if (next_index <= i)
|
||||
{
|
||||
i = next_index;
|
||||
break;
|
||||
}
|
||||
|
||||
while (i <= next_index && i < size)
|
||||
FILL(out);
|
||||
|
||||
++out;
|
||||
}
|
||||
|
||||
while (i < size && out < 255)
|
||||
{
|
||||
out = (png_byte)PNG_DIV257(png_gamma_16bit_correct(i << gamma_shift,
|
||||
gamma_val));
|
||||
FILL(out);
|
||||
}
|
||||
}
|
||||
|
||||
else /* gamma_val not significant */
|
||||
{
|
||||
png_byte out = 0; /* current output value */
|
||||
|
||||
add += 128;
|
||||
|
||||
while (out < 255 && i < size) {
|
||||
unsigned int next_index = (out*257+add) >> gamma_shift;
|
||||
|
||||
while (i <= next_index && i < size)
|
||||
FILL(out);
|
||||
|
||||
++out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the remainder of the table */
|
||||
while (i <= size)
|
||||
FILL(255);
|
||||
}
|
||||
#endif /* BACKGROUND || ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif /* UNUSED */
|
||||
|
||||
#define PNG_GAMMA_TABLE_8 0 /* 8-bit entries in png_byte */
|
||||
#define PNG_GAMMA_TABLE_8_IN_16 1 /* 8-bit entries * 257 in png_uint_16 */
|
||||
#define PNG_GAMMA_TABLE_16 2 /* 16-bit entries in png_uint_16 */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
png_fixed_point gamma;
|
||||
png_uint_32 mult;
|
||||
unsigned int add;
|
||||
unsigned int shift; /* input value is (i * mult + add) >> shift */
|
||||
unsigned int output; /* One of the above values */
|
||||
int adjust; /* Divide or multiple output by 257 */
|
||||
png_voidp table; /* Lookup table */
|
||||
} gamma_table_data;
|
||||
|
||||
static unsigned int
|
||||
write_gamma_table_entry(const gamma_table_data *data, png_uint_32 i)
|
||||
/* Calculate and write a single entry into table[i], the value of the entry
|
||||
* written is returned.
|
||||
*/
|
||||
{
|
||||
png_uint_32 in = (i * data->mult + data->add) >> data->shift;
|
||||
unsigned int out;
|
||||
|
||||
/* If the output is TABLE_8 with no adjust, or the output is not with an
|
||||
* adjust, use 8-bit correction.
|
||||
*/
|
||||
if ((data->output == PNG_GAMMA_TABLE_8) != (data->adjust != 0))
|
||||
{
|
||||
out = png_gamma_8bit_correct((unsigned int)in, data->gamma);
|
||||
|
||||
if (data->adjust != 0)
|
||||
out *= 257U;
|
||||
}
|
||||
|
||||
else /* 16-bit correction */
|
||||
{
|
||||
out = png_gamma_16bit_correct((unsigned int)in, data->gamma);
|
||||
|
||||
if (data->adjust != 0)
|
||||
out = PNG_DIV257(out);
|
||||
}
|
||||
|
||||
if (data->output == PNG_GAMMA_TABLE_8)
|
||||
((png_bytep)data->table)[i] = (png_byte)out;
|
||||
|
||||
else
|
||||
((png_uint_16p)data->table)[i] = (png_uint_16)out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void
|
||||
write_gamma_table(const gamma_table_data *data, png_uint_32 lo,
|
||||
unsigned int loval, png_uint_32 hi, unsigned int hival)
|
||||
/* Fill in gamma table entries between lo and hi, exclusive. The entries at
|
||||
* table[lo] and table[hi] have already been written, the intervening entries
|
||||
* are written.
|
||||
*/
|
||||
{
|
||||
if (hi > lo+1) /* Else nothing to fill in */
|
||||
{
|
||||
if (hival == loval)
|
||||
{
|
||||
/* All intervening entries must be the same. */
|
||||
if (data->output == PNG_GAMMA_TABLE_8)
|
||||
{
|
||||
png_bytep table8 = ((png_bytep)data->table);
|
||||
|
||||
while (++lo < hi)
|
||||
table8[lo] = (png_byte)loval;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_uint_16p table16 = ((png_uint_16p)data->table);
|
||||
|
||||
while (++lo < hi)
|
||||
table16[lo] = (png_uint_16)loval;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_uint_32 mid = (lo+hi) >> 1;
|
||||
unsigned int midval = write_gamma_table_entry(data, mid);
|
||||
|
||||
/* The algorithm used is to divide the entries to be written in half
|
||||
* and fill in the middle. For all practical tables with significant
|
||||
* gamma this will result in a performance gain because the expensive
|
||||
* gamma correction arithmetic is avoided for some entries.
|
||||
*/
|
||||
write_gamma_table(data, lo, loval, mid, midval);
|
||||
write_gamma_table(data, mid, midval, hi, hival);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
png_build_gamma_table(png_structrp png_ptr, png_fixed_point gamma_val,
|
||||
unsigned int output/*as above*/, unsigned int input_depth, int use_shift)
|
||||
/* Build a gamma lookup table to encode input_depth bit input values.
|
||||
* The table will have 2^input_depth entries plus an extra one if use_shift
|
||||
* is specified. With shift the table is accessed:
|
||||
*
|
||||
* table[(original-value + rounding) >> shift]
|
||||
*
|
||||
* And an extra entry exists to accomodate overflow of original-value on
|
||||
* rounding. If use_shift is not specified the table is accessed with an
|
||||
* input_depth bit value and the original values must have been correctly
|
||||
* scaled to this range (not using a shift!)
|
||||
*
|
||||
* Each table entry contains input-value^gamma_val rounded to the output
|
||||
* precision. This is 8 bit precision unless output is specified as
|
||||
* PNG_GAMMA_TABLE_16, in which case it is 16-bit precision. For
|
||||
* PNG_GAMMA_TABLE_8_IN_16 the 8-bit value is scaled to 16-bits by
|
||||
* multiplying by 257.
|
||||
*/
|
||||
{
|
||||
png_uint_32 size;
|
||||
unsigned int hival;
|
||||
gamma_table_data data;
|
||||
|
||||
/* If use_shift is true or if the input or output is not 8-bit the gamma
|
||||
* correction will use the 16-bit correction code. This requires a value in
|
||||
* the range 0..65535. For use_shift the value is simply:
|
||||
*
|
||||
* input << shift
|
||||
*
|
||||
* For the scaling case the value is:
|
||||
*
|
||||
* round(input * 65535 / ((1<<input_depth)-1)
|
||||
*
|
||||
* Both these expressions can be rewritten as:
|
||||
*
|
||||
* (input * mult + add) >> shift;
|
||||
*
|
||||
* With 'mult' and 'add' chosen to minimize the error for all input values
|
||||
* in the range 0..((1<<input_depth)-1). The following table does this for
|
||||
* the scaling case. In fact all the answers are except except for the
|
||||
* 13-bit case, where the maximum error (from the exact value) is 0.500183.
|
||||
*
|
||||
* This table can be produced using the code in contrib/tools/scale.c
|
||||
*/
|
||||
static const struct
|
||||
{
|
||||
png_uint_32 mult;
|
||||
png_uint_16 add;
|
||||
png_byte shift;
|
||||
} multadd65535[16] =
|
||||
{
|
||||
{ 65535, 0, 0 }, /* 65535/1 */
|
||||
{ 21845, 0, 0 }, /* 65535/3 */
|
||||
{ 37449, 0, 2 }, /* 65535/7 */
|
||||
{ 4369, 0, 0 }, /* 65535/15 */
|
||||
{ 33825, 0, 4 }, /* 65535/31 */
|
||||
{ 266301, 121, 8 }, /* 65535/63 */
|
||||
{ 1056817, 970, 11 }, /* 65535/127 */
|
||||
{ 257, 0, 0 }, /* 65535/255 */
|
||||
{ 262653, 1020, 11 }, /* 65535/511 */
|
||||
{ 1049585, 8165, 14 }, /* 65535/1023 */
|
||||
{ 2098145, 31774, 16 }, /* 65535/2047 */
|
||||
{ 65551, 2055, 12 }, /* 65535/4095 */
|
||||
{ 65543, 4100, 13 }, /* 65535/8191 ERROR: .5+0.000183128*/
|
||||
{ 65539, 8193, 14 }, /* 65535/16383 */
|
||||
{ 32769, 0, 14 }, /* 65535/32767 */
|
||||
{ 1, 0, 0 } /* 65535/65535 */
|
||||
# if 0 /* inverse */
|
||||
{ 1, 0, 15 }, /* 1/65535 */
|
||||
{ 3, 32769, 16 }, /* 3/65535 */
|
||||
{ 28673, 134188470, 28 }, /* 7/65535 */
|
||||
{ 15, 32775, 16 }, /* 15/65535 */
|
||||
{ 31745, 33522654, 26 }, /* 31/65535 */
|
||||
{ 64513, 33552693, 26 }, /* 63/65535 */
|
||||
{ 65025, 16776620, 25 }, /* 127/65535 */
|
||||
{ 255, 32895, 16 }, /* 255/65535 */
|
||||
{ 65409, 4194134, 23 }, /* 511/65535 */
|
||||
{ 65473, 2097037, 22 }, /* 1023/65535 */
|
||||
{ 65505, 1048544, 21 }, /* 2047/65535 */
|
||||
{ 65521, 524167, 20 }, /* 4095/65535 */
|
||||
{ 65529, 262136, 19 }, /* 8191/65535 */
|
||||
{ 65533, 131065, 18 }, /* 16383/65535 */
|
||||
{ 1, 0, 1 }, /* 32767/65535 */
|
||||
{ 1, 0, 0 } /* 65535/65535 */
|
||||
# endif
|
||||
};
|
||||
|
||||
/* When both the input and output are 8-bit (i.e. the output is not
|
||||
* PNG_GAMMA_TABLE_16 and the input_depth is <9) the 8-bit gamma correction
|
||||
* code can be used, it is slightly faster. This requires values scaled to
|
||||
* 255, not 65535:
|
||||
*/
|
||||
static const struct
|
||||
{
|
||||
png_uint_16 mult;
|
||||
png_byte add;
|
||||
png_byte shift;
|
||||
} multadd255[8] =
|
||||
{
|
||||
{ 255, 0, 0 }, /* 255/1 */
|
||||
{ 85, 0, 0 }, /* 255/3 */
|
||||
{ 73, 0, 1 }, /* 255/7 */
|
||||
{ 17, 0, 0 }, /* 255/15 */
|
||||
{ 527, 23, 6 }, /* 255/31 */
|
||||
{ 259, 33, 6 }, /* 255/63 */
|
||||
{ 129, 0, 6 }, /* 255/127 */
|
||||
{ 1, 0, 0 } /* 255/255 */
|
||||
# if 0 /* inverse */
|
||||
{ 1, 0, 7 }, /* 1/255 */
|
||||
{ 3, 129, 8 }, /* 3/255 */
|
||||
{ 225, 4060, 13 }, /* 7/255 */
|
||||
{ 15, 135, 8 }, /* 15/255 */
|
||||
{ 249, 1014, 11 }, /* 31/255 */
|
||||
{ 253, 505, 10 }, /* 63/255 */
|
||||
{ 1, 0, 1 }, /* 127/255 */
|
||||
{ 1, 0, 0 } /* 255/255 */
|
||||
# endif
|
||||
};
|
||||
|
||||
/* Basic table size, increased by one below in the use_shift case where the
|
||||
* input is rounded.
|
||||
*/
|
||||
size = 1U << input_depth;
|
||||
data.gamma = gamma_val;
|
||||
data.output = output;
|
||||
|
||||
if (output < PNG_GAMMA_TABLE_16 && input_depth <= 8)
|
||||
{
|
||||
/* The 8-bit correction can only be used if both input and output have no
|
||||
* more than 8 bits of precision.
|
||||
*/
|
||||
data.adjust = output > PNG_GAMMA_TABLE_8;
|
||||
|
||||
if (use_shift)
|
||||
{
|
||||
/* The multiplier does the shift: */
|
||||
data.mult = 1U << (8-input_depth);
|
||||
data.add = 0;
|
||||
data.shift = 0;
|
||||
if (input_depth < 8) ++size;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
data.mult = multadd255[input_depth-1].mult;
|
||||
data.add = multadd255[input_depth-1].add;
|
||||
data.shift = multadd255[input_depth-1].shift;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* 16-bit correction is used for cases where input or output require more
|
||||
* than 8 bits.
|
||||
*/
|
||||
data.adjust = output == PNG_GAMMA_TABLE_8;
|
||||
|
||||
if (use_shift)
|
||||
{
|
||||
data.mult = 1U << (16-input_depth);
|
||||
data.add = 0;
|
||||
data.shift = 0;
|
||||
if (input_depth < 16) ++size;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
data.mult = multadd65535[input_depth-1].mult;
|
||||
data.add = multadd65535[input_depth-1].add;
|
||||
data.shift = multadd65535[input_depth-1].shift;
|
||||
}
|
||||
}
|
||||
|
||||
if (output == PNG_GAMMA_TABLE_8)
|
||||
{
|
||||
data.table = png_malloc(png_ptr, size * sizeof (png_byte));
|
||||
((png_bytep)data.table)[0] = 0;
|
||||
hival = ((png_bytep)data.table)[size-1] = 255;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Output is 16 bits, although it may only have 8 bits of precision */
|
||||
data.table = png_malloc(png_ptr, size * sizeof (png_uint_16));
|
||||
((png_uint_16p)data.table)[0] = 0;
|
||||
hival = ((png_uint_16p)data.table)[size-1] = 65535;
|
||||
}
|
||||
|
||||
if (png_gamma_significant(gamma_val))
|
||||
write_gamma_table(&data, 0, 0, size-1, hival);
|
||||
|
||||
else /* gamma_val not significant */
|
||||
{
|
||||
if (output == PNG_GAMMA_TABLE_8)
|
||||
{
|
||||
png_uint_32 i;
|
||||
png_bytep table8 = ((png_bytep)data.table);
|
||||
|
||||
if (data.adjust)
|
||||
for (i=1; i<size-1; ++i)
|
||||
table8[i] = (png_byte)PNG_DIV257((i * data.mult + data.add) >>
|
||||
data.shift);
|
||||
|
||||
else
|
||||
for (i=1; i<size-1; ++i)
|
||||
table8[i] = (png_byte)((i * data.mult + data.add) >> data.shift);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_uint_32 i;
|
||||
png_uint_16p table16 = ((png_uint_16p)data.table);
|
||||
|
||||
if (data.adjust)
|
||||
for (i=1; i<size-1; ++i)
|
||||
table16[i] = (png_uint_16)(((i * data.mult + data.add) >>
|
||||
data.shift) * 257U);
|
||||
|
||||
else
|
||||
for (i=1; i<size-1; ++i)
|
||||
table16[i] = (png_uint_16)((i * data.mult + data.add) >>
|
||||
data.shift);
|
||||
}
|
||||
}
|
||||
|
||||
return data.table;
|
||||
}
|
||||
|
||||
/* Used from png_read_destroy and below to release the memory used by the gamma
|
||||
* tables.
|
||||
*/
|
||||
@ -3827,17 +4304,8 @@ png_destroy_gamma_table(png_structrp png_ptr)
|
||||
png_free(png_ptr, png_ptr->gamma_table);
|
||||
png_ptr->gamma_table = NULL;
|
||||
|
||||
if (png_ptr->gamma_16_table != NULL)
|
||||
{
|
||||
int i;
|
||||
int istop = (1 << (8 - png_ptr->gamma_shift));
|
||||
for (i = 0; i < istop; i++)
|
||||
{
|
||||
png_free(png_ptr, png_ptr->gamma_16_table[i]);
|
||||
}
|
||||
png_free(png_ptr, png_ptr->gamma_16_table);
|
||||
png_ptr->gamma_16_table = NULL;
|
||||
}
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
@ -3847,28 +4315,10 @@ png_destroy_gamma_table(png_structrp png_ptr)
|
||||
png_free(png_ptr, png_ptr->gamma_to_1);
|
||||
png_ptr->gamma_to_1 = NULL;
|
||||
|
||||
if (png_ptr->gamma_16_from_1 != NULL)
|
||||
{
|
||||
int i;
|
||||
int istop = (1 << (8 - png_ptr->gamma_shift));
|
||||
for (i = 0; i < istop; i++)
|
||||
{
|
||||
png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
|
||||
}
|
||||
png_free(png_ptr, png_ptr->gamma_16_from_1);
|
||||
png_ptr->gamma_16_from_1 = NULL;
|
||||
}
|
||||
if (png_ptr->gamma_16_to_1 != NULL)
|
||||
{
|
||||
int i;
|
||||
int istop = (1 << (8 - png_ptr->gamma_shift));
|
||||
for (i = 0; i < istop; i++)
|
||||
{
|
||||
png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
|
||||
}
|
||||
png_free(png_ptr, png_ptr->gamma_16_to_1);
|
||||
png_ptr->gamma_16_to_1 = NULL;
|
||||
}
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
}
|
||||
|
||||
@ -3878,7 +4328,7 @@ png_destroy_gamma_table(png_structrp png_ptr)
|
||||
* we don't need to allocate > 64K chunks for a full 16-bit table.
|
||||
*/
|
||||
void /* PRIVATE */
|
||||
png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
png_build_gamma_tables(png_structrp png_ptr, int bit_depth)
|
||||
{
|
||||
png_debug(1, "in png_build_gamma_table");
|
||||
|
||||
@ -3896,27 +4346,44 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
|
||||
if (bit_depth <= 8)
|
||||
{
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
png_ptr->gamma_table = png_voidcast(png_bytep, png_build_gamma_table(
|
||||
png_ptr, png_ptr->screen_gamma > 0 ?
|
||||
png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) :
|
||||
PNG_FP_1, PNG_GAMMA_TABLE_8, 8/*input depth*/, 0/*scale*/));
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
|
||||
{
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
|
||||
png_reciprocal(png_ptr->colorspace.gamma));
|
||||
/* This sets the accuracy of 8-bit composition and the 8-bit RGB to gray
|
||||
* conversion - PNG_MAX_GAMMA_8 (the number of bits in the sixteen bit
|
||||
* value that are considered significant.)
|
||||
*/
|
||||
png_ptr->gamma_to_1 = png_voidcast(png_uint_16p, png_build_gamma_table(
|
||||
png_ptr, png_reciprocal(png_ptr->colorspace.gamma),
|
||||
PNG_GAMMA_TABLE_16, 8/*input depth*/, 0/*scale*/));
|
||||
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
|
||||
png_ptr->gamma_from_1 = png_voidcast(png_bytep, png_build_gamma_table(
|
||||
png_ptr, png_ptr->screen_gamma > 0 ?
|
||||
png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */,
|
||||
PNG_GAMMA_TABLE_8, PNG_MAX_GAMMA_8/*input depth*/, 1/*shift*/));
|
||||
|
||||
png_ptr->gamma_shift = 16-PNG_MAX_GAMMA_8;
|
||||
}
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
}
|
||||
else
|
||||
{
|
||||
png_byte shift, sig_bit;
|
||||
int table_type;
|
||||
|
||||
# ifdef PNG_16BIT_SUPPORTED
|
||||
table_type = PNG_GAMMA_TABLE_16;
|
||||
# else
|
||||
table_type = PNG_GAMMA_TABLE_8_IN_16;
|
||||
# endif
|
||||
|
||||
if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
|
||||
{
|
||||
@ -3931,24 +4398,6 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
else
|
||||
sig_bit = png_ptr->sig_bit.gray;
|
||||
|
||||
/* 16-bit gamma code uses this equation:
|
||||
*
|
||||
* ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
|
||||
*
|
||||
* Where 'iv' is the input color value and 'ov' is the output value -
|
||||
* pow(iv, gamma).
|
||||
*
|
||||
* Thus the gamma table consists of up to 256 256 entry tables. The table
|
||||
* is selected by the (8-gamma_shift) most significant of the low 8 bits of
|
||||
* the color value then indexed by the upper 8 bits:
|
||||
*
|
||||
* table[low bits][high 8 bits]
|
||||
*
|
||||
* So the table 'n' corresponds to all those 'iv' of:
|
||||
*
|
||||
* <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
|
||||
*
|
||||
*/
|
||||
if (sig_bit > 0 && sig_bit < 16U)
|
||||
shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */
|
||||
|
||||
@ -3959,51 +4408,40 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
{
|
||||
/* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
|
||||
* the significant bits in the *input* when the output will
|
||||
* eventually be 8 bits. By default it is 11.
|
||||
* eventually be 8 bits.
|
||||
*/
|
||||
if (shift < (16U - PNG_MAX_GAMMA_8))
|
||||
shift = (16U - PNG_MAX_GAMMA_8);
|
||||
}
|
||||
|
||||
if (shift > 8U)
|
||||
shift = 8U; /* Guarantees at least one table! */
|
||||
table_type = PNG_GAMMA_TABLE_8_IN_16;
|
||||
}
|
||||
|
||||
png_ptr->gamma_shift = shift;
|
||||
|
||||
#ifdef PNG_16BIT_SUPPORTED
|
||||
/* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now
|
||||
* PNG_COMPOSE). This effectively smashed the background calculation for
|
||||
* 16-bit output because the 8-bit table assumes the result will be reduced
|
||||
* to 8 bits.
|
||||
*/
|
||||
if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))
|
||||
#endif
|
||||
png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
|
||||
#ifdef PNG_16BIT_SUPPORTED
|
||||
else
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
#endif
|
||||
png_ptr->gamma_16_table = png_voidcast(png_uint_16p, png_build_gamma_table(
|
||||
png_ptr, png_ptr->screen_gamma > 0 ? png_reciprocal2(
|
||||
png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1,
|
||||
table_type, (16-shift)/*input depth*/, 1/*shift*/));
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
|
||||
{
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
|
||||
png_reciprocal(png_ptr->colorspace.gamma));
|
||||
png_ptr->gamma_16_to_1 = png_voidcast(png_uint_16p,
|
||||
png_build_gamma_table(png_ptr,
|
||||
png_reciprocal(png_ptr->colorspace.gamma), PNG_GAMMA_TABLE_16,
|
||||
(16-shift)/*input depth*/, 1/*shift*/));
|
||||
|
||||
/* Notice that the '16 from 1' table should be full precision, however
|
||||
* the lookup on this table still uses gamma_shift, so it can't be.
|
||||
* TODO: fix this.
|
||||
*/
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
|
||||
png_ptr->gamma_16_from_1 = png_voidcast(png_uint_16p,
|
||||
png_build_gamma_table(png_ptr, png_ptr->screen_gamma > 0 ?
|
||||
png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */,
|
||||
PNG_GAMMA_TABLE_16, (16-shift)/*input depth*/, 1/*shift*/));
|
||||
}
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
}
|
||||
|
45
png.h
45
png.h
@ -1116,13 +1116,10 @@ PNG_EXPORT(22, void, png_read_info,
|
||||
#ifdef PNG_TIME_RFC1123_SUPPORTED
|
||||
/* Convert to a US string format: there is no localization support in this
|
||||
* routine. The original implementation used a 29 character buffer in
|
||||
* png_struct, this will be removed in future versions.
|
||||
* png_struct, this has been removed.
|
||||
*/
|
||||
#if PNG_LIBPNG_VER < 10700
|
||||
/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */
|
||||
PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,
|
||||
png_const_timep ptime),PNG_DEPRECATED);
|
||||
#endif
|
||||
PNG_REMOVED(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,
|
||||
png_const_timep ptime),PNG_DEPRECATED)
|
||||
PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29],
|
||||
png_const_timep ptime));
|
||||
#endif
|
||||
@ -1619,22 +1616,8 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
|
||||
PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
|
||||
int filters));
|
||||
|
||||
/* Flags for png_set_filter() to say which filters to use. The flags
|
||||
* are chosen so that they don't conflict with real filter types
|
||||
* below, in case they are supplied instead of the #defined constants.
|
||||
* These values should NOT be changed.
|
||||
*/
|
||||
#define PNG_NO_FILTERS 0x00
|
||||
#define PNG_FILTER_NONE 0x08
|
||||
#define PNG_FILTER_SUB 0x10
|
||||
#define PNG_FILTER_UP 0x20
|
||||
#define PNG_FILTER_AVG 0x40
|
||||
#define PNG_FILTER_PAETH 0x80
|
||||
#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
|
||||
PNG_FILTER_AVG | PNG_FILTER_PAETH)
|
||||
|
||||
/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
|
||||
* These defines should NOT be changed.
|
||||
* These defines match the values in the PNG specification.
|
||||
*/
|
||||
#define PNG_FILTER_VALUE_NONE 0
|
||||
#define PNG_FILTER_VALUE_SUB 1
|
||||
@ -1643,6 +1626,26 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
|
||||
#define PNG_FILTER_VALUE_PAETH 4
|
||||
#define PNG_FILTER_VALUE_LAST 5
|
||||
|
||||
/* The above values are valid arguments to png_set_filter() if only a single
|
||||
* filter is to be used. If multiple filters are to be allowed (the default is
|
||||
* to allow any of them) then a combination of the following masks must be used
|
||||
* and the low three bits of the argument to png_set_filter must be 0.
|
||||
*
|
||||
* The resultant argument fits in a single byte.
|
||||
*/
|
||||
#define PNG_FILTER_NONE (0x08 << PNG_FILTER_VALUE_NONE)
|
||||
#define PNG_FILTER_SUB (0x08 << PNG_FILTER_VALUE_SUB)
|
||||
#define PNG_FILTER_UP (0x08 << PNG_FILTER_VALUE_UP)
|
||||
#define PNG_FILTER_AVG (0x08 << PNG_FILTER_VALUE_AVG)
|
||||
#define PNG_FILTER_PAETH (0x08 << PNG_FILTER_VALUE_PAETH)
|
||||
|
||||
/* Then two convenience values. PNG_NO_FILTERS is the same as
|
||||
* PNG_FILTER_VALUE_NONE, but this is harmless because they mean the same thing.
|
||||
*/
|
||||
#define PNG_NO_FILTERS 0x00
|
||||
#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
|
||||
PNG_FILTER_AVG | PNG_FILTER_PAETH)
|
||||
|
||||
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */
|
||||
/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
|
||||
* defines, either the default (minimum-sum-of-absolute-differences), or
|
||||
|
40
pngpriv.h
40
pngpriv.h
@ -458,7 +458,7 @@ typedef const png_uint_16p * png_const_uint_16pp;
|
||||
#define PNG_HAVE_CHUNK_HEADER 0x100
|
||||
#define PNG_WROTE_tIME 0x200
|
||||
#define PNG_WROTE_INFO_BEFORE_PLTE 0x400
|
||||
#define PNG_BACKGROUND_IS_GRAY 0x800
|
||||
/* 0x800 (unused) */
|
||||
#define PNG_HAVE_PNG_SIGNATURE 0x1000
|
||||
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
|
||||
/* 0x4000 (unused) */
|
||||
@ -472,10 +472,10 @@ typedef const png_uint_16p * png_const_uint_16pp;
|
||||
#define PNG_SWAP_BYTES 0x0010
|
||||
#define PNG_INVERT_MONO 0x0020
|
||||
#define PNG_QUANTIZE 0x0040
|
||||
#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */
|
||||
#define PNG_BACKGROUND_EXPAND 0x0100
|
||||
#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */
|
||||
#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */
|
||||
#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */
|
||||
/* 0x0100 unused */
|
||||
#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */
|
||||
#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */
|
||||
#define PNG_RGBA 0x0800
|
||||
#define PNG_EXPAND 0x1000
|
||||
#define PNG_GAMMA 0x2000
|
||||
@ -490,13 +490,13 @@ typedef const png_uint_16p * png_const_uint_16pp;
|
||||
#define PNG_RGB_TO_GRAY_WARN 0x400000
|
||||
#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */
|
||||
#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */
|
||||
#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */
|
||||
#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */
|
||||
#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */
|
||||
/* 0x8000000 unused */
|
||||
/* 0x10000000 unused */
|
||||
/* 0x20000000 unused */
|
||||
/* 0x40000000 unused */
|
||||
#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */
|
||||
#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */
|
||||
#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */
|
||||
/* 0x8000000 unused */
|
||||
/* 0x10000000 unused */
|
||||
/* 0x20000000 unused */
|
||||
/* 0x40000000 unused */
|
||||
/* Flags for png_create_struct */
|
||||
#define PNG_STRUCT_PNG 0x0001
|
||||
#define PNG_STRUCT_INFO 0x0002
|
||||
@ -529,8 +529,8 @@ typedef const png_uint_16p * png_const_uint_16pp;
|
||||
#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */
|
||||
#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */
|
||||
#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */
|
||||
/* 0x800000 unused */
|
||||
/* 0x1000000 unused */
|
||||
#define PNG_FLAG_BACKGROUND_IS_GRAY 0x800000
|
||||
#define PNG_FLAG_BACKGROUND_EXPAND 0x1000000
|
||||
/* 0x2000000 unused */
|
||||
/* 0x4000000 unused */
|
||||
/* 0x8000000 unused */
|
||||
@ -733,6 +733,16 @@ PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
|
||||
/* Free the buffer list used by the compressed write code. */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_alloc_filter_row_buffers,
|
||||
(png_structrp png_ptr, int filters),PNG_EMPTY);
|
||||
/* Allocate pixel row buffers to cache filtered rows while testing candidate
|
||||
* filters.
|
||||
* TODO: avoid this, only one spare row buffer (at most) is required, this
|
||||
* wastes a lot of memory for large images.
|
||||
*/
|
||||
#endif
|
||||
|
||||
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
|
||||
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
||||
(defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
|
||||
@ -1802,7 +1812,7 @@ PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value,
|
||||
png_fixed_point gamma_value),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,
|
||||
PNG_INTERNAL_FUNCTION(void,png_build_gamma_tables,(png_structrp png_ptr,
|
||||
int bit_depth),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
|
2
pngrio.c
2
pngrio.c
@ -102,6 +102,7 @@ png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
|
||||
png_ptr->read_data_fn = read_data_fn;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
/* It is an error to write to a read device */
|
||||
if (png_ptr->write_data_fn != NULL)
|
||||
{
|
||||
@ -110,6 +111,7 @@ png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
|
||||
"Can't set both read_data_fn and write_data_fn in the"
|
||||
" same structure");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||
png_ptr->output_flush_fn = NULL;
|
||||
|
1108
pngrtran.c
1108
pngrtran.c
File diff suppressed because it is too large
Load Diff
@ -1832,6 +1832,8 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
*/
|
||||
png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
|
||||
&(png_ptr->trans_color));
|
||||
|
||||
png_ptr->trans_alpha = info_ptr->trans_alpha;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -4410,7 +4412,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
|
||||
png_error(png_ptr, "This image requires a row greater than 64KB");
|
||||
#endif
|
||||
|
||||
if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
|
||||
if (row_bytes + 48 > png_ptr->big_row_buf_size)
|
||||
{
|
||||
png_free(png_ptr, png_ptr->big_row_buf);
|
||||
png_free(png_ptr, png_ptr->big_prev_row);
|
||||
@ -4447,7 +4449,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
|
||||
png_ptr->row_buf = png_ptr->big_row_buf + 31;
|
||||
png_ptr->prev_row = png_ptr->big_prev_row + 31;
|
||||
#endif
|
||||
png_ptr->old_big_row_buf_size = row_bytes + 48;
|
||||
png_ptr->big_row_buf_size = row_bytes + 48;
|
||||
}
|
||||
|
||||
#ifdef PNG_MAX_MALLOC_64K
|
||||
|
127
pngset.c
127
pngset.c
@ -910,52 +910,89 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
if (trans_alpha != NULL)
|
||||
if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
|
||||
png_chunk_report(png_ptr,
|
||||
"png_set_tRNS: invalid on PNG with alpha channel", PNG_CHUNK_ERROR);
|
||||
|
||||
else if (info_ptr->color_type & PNG_COLOR_MASK_PALETTE)
|
||||
{
|
||||
/* It may not actually be necessary to set png_ptr->trans_alpha here;
|
||||
* we do it for backward compatibility with the way the png_handle_tRNS
|
||||
* function used to do the allocation.
|
||||
*
|
||||
* 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
|
||||
* relies on png_set_tRNS storing the information in png_struct
|
||||
* (otherwise it won't be there for the code in pngrtran.c).
|
||||
*/
|
||||
int max_num;
|
||||
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
|
||||
/* Free the old data; num_trans 0 can be used to kill the tRNS */
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
|
||||
|
||||
/* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
|
||||
png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
|
||||
png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
|
||||
/* Do this just in case the old data was not owned by libpng: */
|
||||
info_ptr->valid &= ~PNG_INFO_tRNS;
|
||||
info_ptr->trans_alpha = NULL;
|
||||
info_ptr->num_trans = 0;
|
||||
|
||||
if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
|
||||
memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
|
||||
/* Expect png_set_PLTE to happen before png_set_tRNS, so num_palette will
|
||||
* be set, but this is not a requirement of the API.
|
||||
*/
|
||||
if (png_ptr->num_palette)
|
||||
max_num = png_ptr->num_palette;
|
||||
|
||||
else
|
||||
max_num = 1 << png_ptr->bit_depth;
|
||||
|
||||
if (num_trans > max_num)
|
||||
{
|
||||
png_chunk_report(png_ptr, "png_set_tRNS: num_trans too large",
|
||||
PNG_CHUNK_ERROR);
|
||||
/* If control returns simply limit it; the behavior prior to 1.7 was to
|
||||
* issue a warning and skip the palette in png_write_tRNS.
|
||||
*/
|
||||
num_trans = max_num;
|
||||
}
|
||||
|
||||
/* But only attempt a malloc if there is something to do; so the app can
|
||||
* set a tRNS array then later delete it.
|
||||
*/
|
||||
if (num_trans > 0 && trans_alpha != NULL)
|
||||
{
|
||||
/* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1,
|
||||
* this avoids issues where a palette image contains out of range
|
||||
* indices.
|
||||
*/
|
||||
info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr,
|
||||
PNG_MAX_PALETTE_LENGTH));
|
||||
info_ptr->free_me |= PNG_FREE_TRNS;
|
||||
|
||||
memcpy(info_ptr->trans_alpha, trans_alpha, num_trans);
|
||||
info_ptr->valid |= PNG_INFO_tRNS;
|
||||
info_ptr->num_trans = (png_uint_16)num_trans; /* SAFE */
|
||||
}
|
||||
}
|
||||
|
||||
if (trans_color != NULL)
|
||||
else /* not a PALETTE image */
|
||||
{
|
||||
int sample_max = (1 << info_ptr->bit_depth);
|
||||
/* Invalidate any prior transparent color, set num_trans too, it is not
|
||||
* used internally in this case but png_get_tRNS still returns it.
|
||||
*/
|
||||
info_ptr->valid &= ~PNG_INFO_tRNS;
|
||||
info_ptr->num_trans = 0; /* for png_get_tRNS */
|
||||
|
||||
if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
|
||||
trans_color->gray > sample_max) ||
|
||||
(info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
|
||||
(trans_color->red > sample_max ||
|
||||
trans_color->green > sample_max ||
|
||||
trans_color->blue > sample_max)))
|
||||
png_warning(png_ptr,
|
||||
"tRNS chunk has out-of-range samples for bit_depth");
|
||||
if (trans_color != NULL)
|
||||
{
|
||||
int sample_max = (1 << info_ptr->bit_depth);
|
||||
|
||||
info_ptr->trans_color = *trans_color;
|
||||
if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
|
||||
trans_color->gray <= sample_max) ||
|
||||
(info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
|
||||
trans_color->red <= sample_max &&
|
||||
trans_color->green <= sample_max &&
|
||||
trans_color->blue <= sample_max))
|
||||
{
|
||||
info_ptr->trans_color = *trans_color;
|
||||
info_ptr->valid |= PNG_INFO_tRNS;
|
||||
info_ptr->num_trans = 1; /* for png_get_tRNS */
|
||||
}
|
||||
|
||||
if (num_trans == 0)
|
||||
num_trans = 1;
|
||||
}
|
||||
|
||||
info_ptr->num_trans = (png_uint_16)num_trans;
|
||||
|
||||
if (num_trans != 0)
|
||||
{
|
||||
info_ptr->valid |= PNG_INFO_tRNS;
|
||||
info_ptr->free_me |= PNG_FREE_TRNS;
|
||||
else
|
||||
png_chunk_report(png_ptr,
|
||||
"tRNS chunk has out-of-range samples for bit_depth",
|
||||
PNG_CHUNK_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1498,8 +1535,13 @@ png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
|
||||
void PNGAPI
|
||||
png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
|
||||
{
|
||||
if (png_ptr)
|
||||
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
|
||||
# ifdef PNG_READ_SUPPORTED
|
||||
if (png_ptr)
|
||||
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
|
||||
# else
|
||||
PNG_UNUSED(png_ptr)
|
||||
PNG_UNUSED(user_chunk_cache_max)
|
||||
# endif
|
||||
}
|
||||
|
||||
/* This function was added to libpng 1.4.1 */
|
||||
@ -1507,8 +1549,13 @@ void PNGAPI
|
||||
png_set_chunk_malloc_max (png_structrp png_ptr,
|
||||
png_alloc_size_t user_chunk_malloc_max)
|
||||
{
|
||||
if (png_ptr)
|
||||
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
|
||||
# ifdef PNG_READ_SUPPORTED
|
||||
if (png_ptr)
|
||||
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
|
||||
# else
|
||||
PNG_UNUSED(png_ptr)
|
||||
PNG_UNUSED(user_chunk_malloc_max)
|
||||
# endif
|
||||
}
|
||||
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
|
||||
|
||||
|
651
pngstruct.h
651
pngstruct.h
@ -48,10 +48,10 @@
|
||||
/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib
|
||||
* can handle at once. This type need be no larger than 16 bits (so maximum of
|
||||
* 65535), this define allows us to discover how big it is, but limited by the
|
||||
* maximuum for png_size_t. The value can be overriden in a library build
|
||||
* (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably
|
||||
* lower value (e.g. 255 works). A lower value may help memory usage (slightly)
|
||||
* and may even improve performance on some systems (and degrade it on others.)
|
||||
* maximum for size_t. The value can be overriden in a library build (pngusr.h,
|
||||
* or set it in CPPFLAGS) and it works to set it to a considerably lower value
|
||||
* (e.g. 255 works). A lower value may help memory usage (slightly) and may
|
||||
* even improve performance on some systems (and degrade it on others.)
|
||||
*/
|
||||
#ifndef ZLIB_IO_MAX
|
||||
# define ZLIB_IO_MAX ((uInt)-1)
|
||||
@ -137,313 +137,232 @@ typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
|
||||
#define PNG_COLORSPACE_FROM_sRGB 0x0020
|
||||
#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040
|
||||
#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */
|
||||
#define PNG_COLORSPACE_RGB_TO_GRAY_SET 0x0100 /* user specified coeffs */
|
||||
#define PNG_COLORSPACE_INVALID 0x8000
|
||||
#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags))
|
||||
#endif /* COLORSPACE || GAMMA */
|
||||
|
||||
struct png_struct_def
|
||||
{
|
||||
#ifdef PNG_SETJMP_SUPPORTED
|
||||
jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */
|
||||
png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */
|
||||
jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */
|
||||
size_t jmp_buf_size; /* size of the above, if allocated */
|
||||
#endif
|
||||
png_error_ptr error_fn; /* function for printing errors and aborting */
|
||||
#ifdef PNG_WARNINGS_SUPPORTED
|
||||
png_error_ptr warning_fn; /* function for printing warnings */
|
||||
#endif
|
||||
png_voidp error_ptr; /* user supplied struct for error functions */
|
||||
png_rw_ptr write_data_fn; /* function for writing output data */
|
||||
png_rw_ptr read_data_fn; /* function for reading input data */
|
||||
png_voidp io_ptr; /* ptr to application struct for I/O functions */
|
||||
/* Rearranged in libpng 1.7 to attempt to lessen padding; in general
|
||||
* (char), (short), (int) and pointer types are kept separate, however
|
||||
* associated members under the control of the same #define are still
|
||||
* together.
|
||||
*
|
||||
* First the frequently accessed fields. Many processors perform arithmetic
|
||||
* in the address pipeline, but frequently the amount of addition or
|
||||
* subtraction is limited. By putting these fields at the head of png_struct
|
||||
* the hope is that such processors will generate code that is both smaller
|
||||
* and faster.
|
||||
*/
|
||||
png_colorp palette; /* palette from the input file */
|
||||
size_t rowbytes; /* size of row in bytes */
|
||||
size_t info_rowbytes; /* cache of updated row bytes */
|
||||
png_uint_32 width; /* width of image in pixels */
|
||||
png_uint_32 height; /* height of image in pixels */
|
||||
png_uint_32 num_rows; /* number of rows in current pass */
|
||||
png_uint_32 usr_width; /* width of row at start of write */
|
||||
png_uint_32 iwidth; /* width of current interlaced row in pixels */
|
||||
png_uint_32 row_number; /* current row in interlace pass */
|
||||
png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */
|
||||
png_uint_32 crc; /* current chunk CRC value */
|
||||
png_uint_32 mode; /* tells us where we are in the PNG file */
|
||||
png_uint_32 flags; /* flags indicating various things to libpng */
|
||||
png_uint_32 transformations;/* which transformations to perform */
|
||||
png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
|
||||
png_uint_32 free_me; /* items libpng is responsible for freeing */
|
||||
|
||||
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
|
||||
png_user_transform_ptr read_user_transform_fn; /* user read transform */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
|
||||
png_user_transform_ptr write_user_transform_fn; /* user write transform */
|
||||
#endif
|
||||
|
||||
/* These were added in libpng-1.0.2 */
|
||||
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
|
||||
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
|
||||
defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
|
||||
png_voidp user_transform_ptr; /* user supplied struct for user transform */
|
||||
png_byte user_transform_depth; /* bit depth of user transformed pixels */
|
||||
png_byte user_transform_channels; /* channels in user transformed pixels */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
png_uint_32 mode; /* tells us where we are in the PNG file */
|
||||
png_uint_32 flags; /* flags indicating various things to libpng */
|
||||
png_uint_32 transformations; /* which transformations to perform */
|
||||
|
||||
png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
|
||||
z_stream zstream; /* decompression structure */
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
png_compression_bufferp zbuffer_list; /* Created on demand during write */
|
||||
uInt zbuffer_size; /* size of the actual buffer */
|
||||
|
||||
int zlib_level; /* holds zlib compression level */
|
||||
int zlib_method; /* holds zlib compression method */
|
||||
int zlib_window_bits; /* holds zlib compression window bits */
|
||||
int zlib_mem_level; /* holds zlib compression memory level */
|
||||
int zlib_strategy; /* holds zlib compression strategy */
|
||||
#endif
|
||||
/* Added at libpng 1.5.4 */
|
||||
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
|
||||
int zlib_text_level; /* holds zlib compression level */
|
||||
int zlib_text_method; /* holds zlib compression method */
|
||||
int zlib_text_window_bits; /* holds zlib compression window bits */
|
||||
int zlib_text_mem_level; /* holds zlib compression memory level */
|
||||
int zlib_text_strategy; /* holds zlib compression strategy */
|
||||
#endif
|
||||
/* End of material added at libpng 1.5.4 */
|
||||
/* Added at libpng 1.6.0 */
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
int zlib_set_level; /* Actual values set into the zstream on write */
|
||||
int zlib_set_method;
|
||||
int zlib_set_window_bits;
|
||||
int zlib_set_mem_level;
|
||||
int zlib_set_strategy;
|
||||
#endif
|
||||
|
||||
png_uint_32 width; /* width of image in pixels */
|
||||
png_uint_32 height; /* height of image in pixels */
|
||||
png_uint_32 num_rows; /* number of rows in current pass */
|
||||
png_uint_32 usr_width; /* width of row at start of write */
|
||||
png_size_t rowbytes; /* size of row in bytes */
|
||||
png_uint_32 iwidth; /* width of current interlaced row in pixels */
|
||||
png_uint_32 row_number; /* current row in interlace pass */
|
||||
png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */
|
||||
png_bytep prev_row; /* buffer to save previous (unfiltered) row.
|
||||
* This is a pointer into big_prev_row
|
||||
*/
|
||||
png_bytep row_buf; /* buffer to save current (unfiltered) row.
|
||||
* This is a pointer into big_row_buf
|
||||
*/
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
png_bytep sub_row; /* buffer to save "sub" row when filtering */
|
||||
png_bytep up_row; /* buffer to save "up" row when filtering */
|
||||
png_bytep avg_row; /* buffer to save "avg" row when filtering */
|
||||
png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
|
||||
#endif
|
||||
png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */
|
||||
|
||||
png_uint_32 idat_size; /* current IDAT size for read */
|
||||
png_uint_32 crc; /* current chunk CRC value */
|
||||
png_colorp palette; /* palette from the input file */
|
||||
png_uint_16 num_palette; /* number of color entries in palette */
|
||||
|
||||
/* Added at libpng-1.5.10 */
|
||||
int maximum_pixel_depth; /* pixel depth used for the row buffers */
|
||||
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
|
||||
int num_palette_max; /* maximum palette index found in IDAT */
|
||||
int num_palette_max; /* maximum palette index found in IDAT */
|
||||
#endif
|
||||
|
||||
png_uint_16 num_palette; /* number of color entries in palette */
|
||||
png_uint_16 num_trans; /* number of transparency values */
|
||||
png_byte compression; /* file compression type (always 0) */
|
||||
|
||||
/* Single byte values, typically used either to save space or to hold 1-byte
|
||||
* values from the PNG chunk specifications.
|
||||
*/
|
||||
png_byte compression_type; /* file compression type (always 0) */
|
||||
png_byte filter; /* file filter type (always 0) */
|
||||
png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
|
||||
png_byte pass; /* current interlace pass (0 - 6) */
|
||||
png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
|
||||
png_byte color_type; /* color type of file */
|
||||
png_byte bit_depth; /* bit depth of file */
|
||||
png_byte usr_bit_depth; /* bit depth of users row: write only */
|
||||
png_byte pixel_depth; /* number of bits per pixel */
|
||||
png_byte channels; /* number of channels in file */
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
png_byte usr_channels; /* channels at start of write: write only */
|
||||
#endif
|
||||
png_byte sig_bytes; /* magic bytes read/written from start of file */
|
||||
png_byte maximum_pixel_depth;
|
||||
/* pixel depth used for the row buffers */
|
||||
png_byte transformed_pixel_depth;
|
||||
/* pixel depth after read/write transforms */
|
||||
#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
|
||||
png_uint_16 filler; /* filler bytes for pixel expansion */
|
||||
|
||||
/* ERROR HANDLING */
|
||||
#ifdef PNG_SETJMP_SUPPORTED
|
||||
/* jmp_buf can have very high alignment requirements on some systems, so put
|
||||
* it first.
|
||||
*/
|
||||
jmp_buf jmp_buf_local;
|
||||
jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */
|
||||
png_longjmp_ptr longjmp_fn; /* setjmp non-local goto function. */
|
||||
size_t jmp_buf_size; /* size of *jmp_buf_ptr, if allocated */
|
||||
#endif
|
||||
|
||||
#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED)
|
||||
png_byte background_gamma_type;
|
||||
png_fixed_point background_gamma;
|
||||
png_color_16 background; /* background color in screen gamma space */
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
png_color_16 background_1; /* background normalized to gamma 1.0 */
|
||||
/* Error/warning callbacks */
|
||||
png_error_ptr error_fn; /* print an error message and abort */
|
||||
#ifdef PNG_WARNINGS_SUPPORTED
|
||||
png_error_ptr warning_fn; /* print a warning and continue */
|
||||
#endif
|
||||
#endif /* PNG_bKGD_SUPPORTED */
|
||||
png_voidp error_ptr; /* user supplied data for the above */
|
||||
|
||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||
png_flush_ptr output_flush_fn; /* Function for flushing output */
|
||||
png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
|
||||
png_uint_32 flush_rows; /* number of rows written since last flush */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */
|
||||
png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */
|
||||
|
||||
png_bytep gamma_table; /* gamma table for 8-bit depth files */
|
||||
png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
png_bytep gamma_from_1; /* converts from 1.0 to screen */
|
||||
png_bytep gamma_to_1; /* converts from file to 1.0 */
|
||||
png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
|
||||
png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
|
||||
png_color_8 sig_bit; /* significant bits in each available channel */
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
|
||||
png_color_8 shift; /* shift for significant bit tranformation */
|
||||
#endif
|
||||
|
||||
#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
|
||||
|| defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
|
||||
png_bytep trans_alpha; /* alpha values for paletted files */
|
||||
png_color_16 trans_color; /* transparent color for non-paletted files */
|
||||
#endif
|
||||
|
||||
png_read_status_ptr read_row_fn; /* called after each row is decoded */
|
||||
png_write_status_ptr write_row_fn; /* called after each row is encoded */
|
||||
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
|
||||
png_progressive_info_ptr info_fn; /* called after header data fully read */
|
||||
png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */
|
||||
png_progressive_end_ptr end_fn; /* called after image is complete */
|
||||
png_bytep save_buffer_ptr; /* current location in save_buffer */
|
||||
png_bytep save_buffer; /* buffer for previously read data */
|
||||
png_bytep current_buffer_ptr; /* current location in current_buffer */
|
||||
png_bytep current_buffer; /* buffer for recently used data */
|
||||
png_uint_32 push_length; /* size of current input chunk */
|
||||
png_uint_32 skip_length; /* bytes to skip in input data */
|
||||
png_size_t save_buffer_size; /* amount of data now in save_buffer */
|
||||
png_size_t save_buffer_max; /* total size of save_buffer */
|
||||
png_size_t buffer_size; /* total amount of available input data */
|
||||
png_size_t current_buffer_size; /* amount of data now in current_buffer */
|
||||
int process_mode; /* what push library is currently doing */
|
||||
int cur_palette; /* current push library palette index */
|
||||
|
||||
#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
|
||||
|
||||
#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
|
||||
/* For the Borland special 64K segment handler */
|
||||
png_bytepp offset_table_ptr;
|
||||
png_bytep offset_table;
|
||||
png_uint_16 offset_table_number;
|
||||
png_uint_16 offset_table_count;
|
||||
png_uint_16 offset_table_count_free;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_QUANTIZE_SUPPORTED
|
||||
png_bytep palette_lookup; /* lookup table for quantizing */
|
||||
png_bytep quantize_index; /* index translation for palette files */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
|
||||
png_byte heuristic_method; /* heuristic for row filter selection */
|
||||
png_byte num_prev_filters; /* number of weights for previous rows */
|
||||
png_bytep prev_filters; /* filter type(s) of previous row(s) */
|
||||
png_uint_16p filter_weights; /* weight(s) for previous line(s) */
|
||||
png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
|
||||
png_uint_16p filter_costs; /* relative filter calculation cost */
|
||||
png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
|
||||
#endif
|
||||
|
||||
#if PNG_LIBPNG_VER < 10700
|
||||
/* To do: remove this from libpng-1.7 */
|
||||
#ifdef PNG_TIME_RFC1123_SUPPORTED
|
||||
char time_buffer[29]; /* String to hold RFC 1123 time text */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* New members added in libpng-1.0.6 */
|
||||
|
||||
png_uint_32 free_me; /* flags items libpng is responsible for freeing */
|
||||
|
||||
#ifdef PNG_USER_CHUNKS_SUPPORTED
|
||||
png_voidp user_chunk_ptr;
|
||||
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
|
||||
png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
|
||||
int unknown_default; /* As PNG_HANDLE_* */
|
||||
unsigned int num_chunk_list; /* Number of entries in the list */
|
||||
png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name
|
||||
* followed by a PNG_HANDLE_* byte */
|
||||
#endif
|
||||
|
||||
/* New members added in libpng-1.0.3 */
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_byte rgb_to_gray_status;
|
||||
/* Added in libpng 1.5.5 to record setting of coefficients: */
|
||||
png_byte rgb_to_gray_coefficients_set;
|
||||
/* These were changed from png_byte in libpng-1.0.6 */
|
||||
png_uint_16 rgb_to_gray_red_coeff;
|
||||
png_uint_16 rgb_to_gray_green_coeff;
|
||||
/* deleted in 1.5.5: rgb_to_gray_blue_coeff; */
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
|
||||
#if defined(PNG_MNG_FEATURES_SUPPORTED)
|
||||
/* Changed from png_byte to png_uint_32 at version 1.2.0 */
|
||||
png_uint_32 mng_features_permitted;
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */
|
||||
#ifdef PNG_MNG_FEATURES_SUPPORTED
|
||||
png_byte filter_type;
|
||||
#endif
|
||||
|
||||
/* New members added in libpng-1.2.0 */
|
||||
|
||||
/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
|
||||
/* MEMORY ALLOCATION */
|
||||
#ifdef PNG_USER_MEM_SUPPORTED
|
||||
png_voidp mem_ptr; /* user supplied struct for mem functions */
|
||||
png_malloc_ptr malloc_fn; /* function for allocating memory */
|
||||
png_free_ptr free_fn; /* function for freeing memory */
|
||||
png_malloc_ptr malloc_fn; /* allocate memory */
|
||||
png_free_ptr free_fn; /* free memory */
|
||||
png_voidp mem_ptr; /* user supplied data for the above */
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.0.13 and 1.2.0 */
|
||||
png_bytep big_row_buf; /* buffer to save current (unfiltered) row */
|
||||
/* IO and BASIC READ/WRITE SUPPORT */
|
||||
png_voidp io_ptr; /* user supplied data for IO callbacks */
|
||||
|
||||
#ifdef PNG_READ_QUANTIZE_SUPPORTED
|
||||
/* The following three members were added at version 1.0.14 and 1.2.4 */
|
||||
png_bytep quantize_sort; /* working sort array */
|
||||
png_bytep index_to_palette; /* where the original index currently is
|
||||
in the palette */
|
||||
png_bytep palette_to_index; /* which original index points to this
|
||||
palette color */
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
png_rw_ptr read_data_fn; /* read some bytes (must succeed) */
|
||||
png_read_status_ptr read_row_fn; /* called after each row is decoded */
|
||||
png_bytep read_buffer; /* buffer for reading chunk data */
|
||||
|
||||
/* During read the following array is set up to point to the appropriate
|
||||
* un-filter function, this allows per-image and per-processor optimization.
|
||||
*/
|
||||
void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
|
||||
png_bytep row, png_const_bytep prev_row);
|
||||
|
||||
#if (defined PNG_COLORSPACE_SUPPORTED || defined PNG_GAMMA_SUPPORTED)
|
||||
/* The png_struct colorspace structure is only required on read - on write it
|
||||
* is in (just) the info_struct.
|
||||
*/
|
||||
png_colorspace colorspace;
|
||||
#endif
|
||||
|
||||
/* New members added in libpng-1.0.16 and 1.2.6 */
|
||||
png_byte compression_type;
|
||||
#endif /* PNG_READ_SUPPORTED */
|
||||
|
||||
#ifdef PNG_USER_LIMITS_SUPPORTED
|
||||
png_uint_32 user_width_max;
|
||||
png_uint_32 user_height_max;
|
||||
|
||||
/* Added in libpng-1.4.0: Total number of sPLT, text, and unknown
|
||||
* chunks that can be stored (0 means unlimited).
|
||||
*/
|
||||
png_uint_32 user_chunk_cache_max;
|
||||
|
||||
/* The limits only affect read from libpng 1.7 */
|
||||
/* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk
|
||||
* can occupy when decompressed. 0 means unlimited.
|
||||
*/
|
||||
png_alloc_size_t user_chunk_malloc_max;
|
||||
/* limit on total *number* of sPLT, text and unknown chunks that can be
|
||||
* stored. 0 means unlimited.
|
||||
*/
|
||||
png_uint_32 user_chunk_cache_max;
|
||||
png_uint_32 user_width_max;
|
||||
png_uint_32 user_height_max;
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.0.25 and 1.2.17 */
|
||||
/* The progressive reader gets passed data and calls application handling
|
||||
* functions when appropriate.
|
||||
*/
|
||||
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
|
||||
png_progressive_info_ptr info_fn; /* called after header data fully read */
|
||||
png_progressive_row_ptr row_fn; /* called after a row is decoded */
|
||||
png_progressive_end_ptr end_fn; /* called after image is complete */
|
||||
|
||||
/* Progressive read control data */
|
||||
png_bytep save_buffer_ptr; /* current location in save_buffer */
|
||||
png_bytep save_buffer; /* buffer for previously read data */
|
||||
png_bytep current_buffer_ptr; /* current location in current_buffer */
|
||||
png_bytep current_buffer; /* buffer for recently used data */
|
||||
|
||||
size_t save_buffer_size; /* amount of data now in save_buffer */
|
||||
size_t save_buffer_max; /* total size of save_buffer */
|
||||
size_t buffer_size; /* total amount of available input data */
|
||||
size_t current_buffer_size; /* amount of data now in current_buffer */
|
||||
|
||||
png_uint_32 push_length; /* size of current input chunk */
|
||||
png_uint_32 skip_length; /* bytes to skip in input data */
|
||||
|
||||
int process_mode; /* what push library is currently doing */
|
||||
int cur_palette; /* current push library palette index */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
png_rw_ptr write_data_fn;/* write some bytes (must succeed) */
|
||||
png_write_status_ptr write_row_fn; /* called after each row is encoded */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||
png_flush_ptr output_flush_fn; /* Function for flushing output */
|
||||
png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
|
||||
png_uint_32 flush_rows; /* number of rows written since last flush */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
|
||||
png_bytep prev_filters; /* filter type(s) of previous row(s) */
|
||||
png_uint_16p filter_weights; /* weight(s) for previous line(s) */
|
||||
png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
|
||||
png_uint_16p filter_costs; /* relative filter calculation cost */
|
||||
png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
|
||||
png_byte heuristic_method; /* heuristic for row filter selection */
|
||||
png_byte num_prev_filters; /* number of weights for previous rows */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
png_byte usr_bit_depth; /* bit depth of users row */
|
||||
png_byte usr_channels; /* channels at start of write */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_IO_STATE_SUPPORTED
|
||||
png_uint_32 io_state; /* tells the app read/write progress */
|
||||
#endif
|
||||
|
||||
/* ROW BUFFERS
|
||||
*
|
||||
* Members that hold pointers to the decompressed image rows.
|
||||
*/
|
||||
png_bytep row_buf; /* buffer for the current (unfiltered) row */
|
||||
#if (defined PNG_WRITE_FILTER_SUPPORTED) || (defined PNG_READ_SUPPORTED)
|
||||
png_bytep prev_row; /* buffer to save the previous (unfiltered) row */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
/* The row_buf and prev_row pointers are misaligned so that the start of the
|
||||
* row - after the filter byte - is aligned, the 'big_' pointers record the
|
||||
* original allocated pointer.
|
||||
*/
|
||||
png_bytep big_row_buf;
|
||||
png_bytep big_prev_row;
|
||||
size_t big_row_buf_size; /* Actual size of both */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
/* This is somewhat excessive, there is no obvious reason on write to
|
||||
* allocate a buffer for each possible filtered row, only for the one being
|
||||
* tested and the current best.
|
||||
*
|
||||
* TODO: fix this
|
||||
*/
|
||||
png_bytep sub_row; /* buffer to save "sub" row when filtering */
|
||||
png_bytep up_row; /* buffer to save "up" row when filtering */
|
||||
png_bytep avg_row; /* buffer to save "avg" row when filtering */
|
||||
png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
|
||||
#endif
|
||||
|
||||
/* UNKNOWN CHUNK HANDLING */
|
||||
/* TODO: this is excessively complicated, there are multiple ways of doing
|
||||
* the same thing. It should be cleaned up, possibly by finding out which
|
||||
* APIs applications really use.
|
||||
*/
|
||||
#ifdef PNG_USER_CHUNKS_SUPPORTED
|
||||
/* General purpose pointer for all user/unknown chunk handling; points to
|
||||
* application supplied data for use in the read_user_chunk_fn callback
|
||||
* (currently there is no write side support - the write side must use the
|
||||
* set_unknown_chunks interface.)
|
||||
*/
|
||||
png_voidp user_chunk_ptr;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
|
||||
/* This is called back from the unknown chunk handling */
|
||||
png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
|
||||
#endif
|
||||
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||
/* Temporary storage for unknown chunk that the library doesn't recognize,
|
||||
* used while reading the chunk.
|
||||
@ -451,33 +370,175 @@ struct png_struct_def
|
||||
png_unknown_chunk unknown_chunk;
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.2.26 */
|
||||
png_size_t old_big_row_buf_size;
|
||||
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
|
||||
png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name
|
||||
* followed by a PNG_HANDLE_* byte */
|
||||
int unknown_default; /* As PNG_HANDLE_* */
|
||||
unsigned int num_chunk_list; /* Number of entries in the list */
|
||||
#endif
|
||||
|
||||
/* USER TRANSFORM SUPPORT */
|
||||
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
|
||||
png_user_transform_ptr read_user_transform_fn; /* user read transform */
|
||||
#endif
|
||||
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
|
||||
png_user_transform_ptr write_user_transform_fn; /* user write transform */
|
||||
#endif
|
||||
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
|
||||
png_voidp user_transform_ptr; /* user supplied data for the above */
|
||||
png_byte user_transform_depth; /* bit depth of user transformed pixels */
|
||||
png_byte user_transform_channels; /* channels in user transformed pixels */
|
||||
#endif
|
||||
|
||||
/* READ TRANSFORM SUPPORT
|
||||
*
|
||||
* Quite a lot of things can be done to the original image data on read, and
|
||||
* most of these are configurable. The data required by the configurable
|
||||
* read transforms should be stored here. The png_color_16 and png_color_8
|
||||
* structures have low alignment requirements and odd sizes, so may cause
|
||||
* misalignment when present. Member alignment is as follows:
|
||||
*
|
||||
* png_color_16 png_uint_16
|
||||
* png_color_8 png_byte
|
||||
*/
|
||||
/* GAMMA/BACKGROUND/ALPHA-MODE/RGB-TO-GRAY/tRNS/sBIT
|
||||
*
|
||||
* These things are all interrelated because they need some or all of the
|
||||
* gamma tables. Some attempt has been made below to order these members by
|
||||
* size, so that as little padding as possible is required.
|
||||
*/
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
png_bytep gamma_table; /* gamma table for 8-bit depth files */
|
||||
png_uint_16p gamma_16_table; /* gamma table for 16-bit depth files */
|
||||
|
||||
#if defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_ALPHA_MODE_SUPPORTED ||\
|
||||
defined PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_bytep gamma_from_1; /* converts from 1.0 to screen */
|
||||
png_uint_16p gamma_to_1; /* converts from file to 1.0 */
|
||||
png_uint_16p gamma_16_from_1; /* converts from 1.0 to screen */
|
||||
png_uint_16p gamma_16_to_1; /* converts from file to 1.0 */
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif /* PNG_READ_GAMMA_SUPPORTED */
|
||||
|
||||
#if defined PNG_READ_tRNS_SUPPORTED || defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_EXPAND_SUPPORTED
|
||||
png_bytep trans_alpha; /* alpha values for paletted files */
|
||||
#endif
|
||||
|
||||
/* Integer values */
|
||||
#if defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_ALPHA_MODE_SUPPORTED
|
||||
png_fixed_point background_gamma;
|
||||
#endif
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */
|
||||
int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */
|
||||
#endif
|
||||
|
||||
/* png_color_16 */
|
||||
#if defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_ALPHA_MODE_SUPPORTED
|
||||
png_color_16 background; /* background color in screen gamma space */
|
||||
png_color_16 background_1; /* background normalized to gamma 1.0 */
|
||||
#endif
|
||||
#if defined PNG_READ_tRNS_SUPPORTED || defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_EXPAND_SUPPORTED
|
||||
png_color_16 trans_color; /* transparent color for non-paletted files */
|
||||
#endif
|
||||
|
||||
/* png_uint_16 */
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_uint_16 rgb_to_gray_red_coeff;
|
||||
png_uint_16 rgb_to_gray_green_coeff;
|
||||
/* The blue coefficient is calculated from the above */
|
||||
#endif
|
||||
|
||||
/* png_color_8 */
|
||||
#if defined PNG_READ_GAMMA_SUPPORTED || defined PNG_READ_sBIT_SUPPORTED
|
||||
png_color_8 sig_bit; /* significant bits in each available channel */
|
||||
#endif
|
||||
|
||||
/* png_byte */
|
||||
#if defined PNG_READ_BACKGROUND_SUPPORTED ||\
|
||||
defined PNG_READ_ALPHA_MODE_SUPPORTED
|
||||
png_byte background_gamma_type;
|
||||
#endif
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_byte rgb_to_gray_status;
|
||||
#endif
|
||||
|
||||
/* SHIFT - both READ_SHIFT and WRITE_SHIFT */
|
||||
#if defined PNG_READ_SHIFT_SUPPORTED || defined PNG_WRITE_SHIFT_SUPPORTED
|
||||
png_color_8 shift; /* shift for significant bit tranformation */
|
||||
#endif
|
||||
|
||||
/* FILLER SUPPORT (pixel expansion or read, contraction on write) */
|
||||
#if defined PNG_READ_FILLER_SUPPORTED || defined PNG_WRITE_FILLER_SUPPORTED
|
||||
png_uint_16 filler; /* filler bytes for pixel expansion */
|
||||
#endif
|
||||
|
||||
/* QUANTIZE (convert to color-mapped) */
|
||||
#ifdef PNG_READ_QUANTIZE_SUPPORTED
|
||||
png_bytep palette_lookup; /* lookup table for quantizing */
|
||||
png_bytep quantize_index; /* index translation for palette files */
|
||||
png_bytep quantize_sort; /* working sort array */
|
||||
png_bytep index_to_palette; /* where the original index currently is in the
|
||||
* palette
|
||||
*/
|
||||
png_bytep palette_to_index; /* which original index points to this palette
|
||||
* color
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* MNG SUPPORT */
|
||||
#ifdef PNG_MNG_FEATURES_SUPPORTED
|
||||
png_uint_32 mng_features_permitted;
|
||||
png_byte filter_type;
|
||||
#endif
|
||||
|
||||
/* COMPRESSION AND DECOMPRESSION SUPPORT.
|
||||
*
|
||||
* zlib expects a 'zstream' as the fundamental control structure, it allows
|
||||
* all the parameters to be passed as one pointer.
|
||||
*/
|
||||
z_stream zstream; /* decompression structure */
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
/* New member added in libpng-1.2.30 */
|
||||
png_bytep read_buffer; /* buffer for reading chunk data */
|
||||
png_alloc_size_t read_buffer_size; /* current size of the buffer */
|
||||
/* These, and IDAT_read_size below, control how much input and output (at
|
||||
* most) is available to zlib.
|
||||
*/
|
||||
png_uint_32 idat_size; /* current IDAT size for read */
|
||||
png_alloc_size_t read_buffer_size; /* current size of the buffer */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
|
||||
int zlib_text_level; /* holds zlib compression level */
|
||||
int zlib_text_method; /* holds zlib compression method */
|
||||
int zlib_text_window_bits; /* holds zlib compression window bits */
|
||||
int zlib_text_mem_level; /* holds zlib compression memory level */
|
||||
int zlib_text_strategy; /* holds zlib compression strategy */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_SUPPORTED
|
||||
int zlib_level; /* holds zlib compression level */
|
||||
int zlib_method; /* holds zlib compression method */
|
||||
int zlib_window_bits; /* holds zlib compression window bits */
|
||||
int zlib_mem_level; /* holds zlib compression memory level */
|
||||
int zlib_strategy; /* holds zlib compression strategy */
|
||||
|
||||
int zlib_set_level; /* Actual values set into the zstream on write */
|
||||
int zlib_set_method;
|
||||
int zlib_set_window_bits;
|
||||
int zlib_set_mem_level;
|
||||
int zlib_set_strategy;
|
||||
|
||||
png_compression_bufferp zbuffer_list; /* Created on demand during write */
|
||||
uInt zbuffer_size; /* size of the actual zlib buffer */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
|
||||
uInt IDAT_read_size; /* limit on read buffer size for IDAT */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_IO_STATE_SUPPORTED
|
||||
/* New member added in libpng-1.4.0 */
|
||||
png_uint_32 io_state;
|
||||
#endif
|
||||
|
||||
/* New member added in libpng-1.5.6 */
|
||||
png_bytep big_prev_row;
|
||||
|
||||
void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
|
||||
png_bytep row, png_const_bytep prev_row);
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
#if defined PNG_COLORSPACE_SUPPORTED || defined PNG_GAMMA_SUPPORTED
|
||||
png_colorspace colorspace;
|
||||
#endif
|
||||
uInt IDAT_read_size; /* limit on read buffer size for IDAT */
|
||||
#endif
|
||||
};
|
||||
#endif /* PNGSTRUCT_H */
|
||||
|
@ -57,7 +57,9 @@ png_set_packing(png_structrp png_ptr)
|
||||
if (png_ptr->bit_depth < 8)
|
||||
{
|
||||
png_ptr->transformations |= PNG_PACK;
|
||||
png_ptr->usr_bit_depth = 8;
|
||||
# ifdef PNG_WRITE_SUPPORTED
|
||||
png_ptr->usr_bit_depth = 8;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
2
pngwio.c
2
pngwio.c
@ -151,6 +151,7 @@ png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,
|
||||
# endif
|
||||
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
/* It is an error to read while writing a png file */
|
||||
if (png_ptr->read_data_fn != NULL)
|
||||
{
|
||||
@ -160,5 +161,6 @@ png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,
|
||||
"Can't set both read_data_fn and write_data_fn in the"
|
||||
" same structure");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* PNG_WRITE_SUPPORTED */
|
||||
|
173
pngwrite.c
173
pngwrite.c
@ -216,8 +216,13 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
|
||||
if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
|
||||
info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j<(int)info_ptr->num_trans; j++)
|
||||
int j, jend;
|
||||
|
||||
jend = info_ptr->num_trans;
|
||||
if (jend > PNG_MAX_PALETTE_LENGTH)
|
||||
jend = PNG_MAX_PALETTE_LENGTH;
|
||||
|
||||
for (j = 0; j<jend; ++j)
|
||||
info_ptr->trans_alpha[j] =
|
||||
(png_byte)(255 - info_ptr->trans_alpha[j]);
|
||||
}
|
||||
@ -927,42 +932,52 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
|
||||
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
|
||||
(method == PNG_INTRAPIXEL_DIFFERENCING))
|
||||
method = PNG_FILTER_TYPE_BASE;
|
||||
|
||||
#endif
|
||||
if (method == PNG_FILTER_TYPE_BASE)
|
||||
{
|
||||
switch (filters & (PNG_ALL_FILTERS | 0x07))
|
||||
|
||||
/* The only supported method, except for the check above, is
|
||||
* PNG_FILTER_TYPE_BASE. The code below does not use 'method' other than
|
||||
* for the check, so just keep going if png_app_error returns.
|
||||
*/
|
||||
if (method != PNG_FILTER_TYPE_BASE)
|
||||
png_app_error(png_ptr, "Unknown custom filter method");
|
||||
|
||||
/* If filter writing is not supported the 'filters' value must be zero,
|
||||
* otherwise the value must be a single, valid, filter value or a set of the
|
||||
* mask values. The defines in png.h are such that the filter masks used in
|
||||
* this API and internally are 1<<(3+value), value is in the range 0..4, so
|
||||
* this fits in a byte.
|
||||
*/
|
||||
# ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
/* Notice that PNG_NO_FILTERS is 0 and passes this test; this is OK
|
||||
* because filters then gets set to PNG_FILTER_NONE, as is required.
|
||||
*/
|
||||
if (filters < PNG_FILTER_VALUE_LAST)
|
||||
filters = 0x08 << filters;
|
||||
|
||||
else if ((filters & ~PNG_ALL_FILTERS) != 0)
|
||||
{
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
case 5:
|
||||
case 6:
|
||||
case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
|
||||
/* FALL THROUGH */
|
||||
#endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
case PNG_FILTER_VALUE_NONE:
|
||||
png_ptr->do_filter = PNG_FILTER_NONE; break;
|
||||
png_app_error(png_ptr, "png_set_filter: invalid filters mask/value");
|
||||
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
case PNG_FILTER_VALUE_SUB:
|
||||
png_ptr->do_filter = PNG_FILTER_SUB; break;
|
||||
/* For compatibility with the previous behavior assume a mask value was
|
||||
* passed and ignore the non-mask bits.
|
||||
*/
|
||||
filters &= PNG_ALL_FILTERS;
|
||||
|
||||
case PNG_FILTER_VALUE_UP:
|
||||
png_ptr->do_filter = PNG_FILTER_UP; break;
|
||||
|
||||
case PNG_FILTER_VALUE_AVG:
|
||||
png_ptr->do_filter = PNG_FILTER_AVG; break;
|
||||
|
||||
case PNG_FILTER_VALUE_PAETH:
|
||||
png_ptr->do_filter = PNG_FILTER_PAETH; break;
|
||||
|
||||
default:
|
||||
png_ptr->do_filter = (png_byte)filters; break;
|
||||
#else
|
||||
default:
|
||||
png_app_error(png_ptr, "Unknown row filter for method 0");
|
||||
#endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
/* For a possibly foolish consistency (it shouldn't matter) set
|
||||
* PNG_FILTER_NONE rather than 0.
|
||||
*/
|
||||
if (filters == 0)
|
||||
filters = PNG_FILTER_NONE;
|
||||
}
|
||||
# else
|
||||
/* PNG_FILTER_VALUE_NONE and PNG_NO_FILTERS are both 0. */
|
||||
if (filters != 0 && filters != PNG_FILTER_NONE)
|
||||
png_app_error(png_ptr, "png_set_filter: no filters supported");
|
||||
|
||||
filters = PNG_FILTER_NONE;
|
||||
# endif
|
||||
|
||||
# ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
/* If we have allocated the row_buf, this means we have already started
|
||||
* with the image and we should have allocated all of the filter buffers
|
||||
* that have been selected. If prev_row isn't already allocated, then
|
||||
@ -971,75 +986,45 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
|
||||
* wants to start and stop using particular filters during compression,
|
||||
* it should start out with all of the filters, and then add and
|
||||
* remove them after the start of compression.
|
||||
*
|
||||
* NOTE: this is a nasty constraint on the code, because it means that the
|
||||
* prev_row buffer must be maintained even if there are currently no
|
||||
* 'prev_row' requiring filters active.
|
||||
*/
|
||||
if (png_ptr->row_buf != NULL)
|
||||
{
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
|
||||
/* Repeat the checks in png_write_start_row; 1 pixel high or wide
|
||||
* images cannot benefit from certain filters. If this isn't done here
|
||||
* the check below will fire on 1 pixel high images.
|
||||
*/
|
||||
if (png_ptr->height == 1)
|
||||
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
|
||||
|
||||
if (png_ptr->width == 1)
|
||||
filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
|
||||
|
||||
if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0
|
||||
&& png_ptr->prev_row == NULL)
|
||||
{
|
||||
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
|
||||
/* This is the error case, however it is benign - the previous row
|
||||
* is not available so the filter can't be used. Just warn here.
|
||||
*/
|
||||
png_app_warning(png_ptr,
|
||||
"png_set_filter: UP/AVG/PAETH cannot be added after start");
|
||||
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
|
||||
}
|
||||
|
||||
if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
|
||||
{
|
||||
if (png_ptr->prev_row == NULL)
|
||||
{
|
||||
png_warning(png_ptr, "Can't add Up filter after starting");
|
||||
png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
|
||||
~PNG_FILTER_UP);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
|
||||
}
|
||||
}
|
||||
|
||||
if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
|
||||
{
|
||||
if (png_ptr->prev_row == NULL)
|
||||
{
|
||||
png_warning(png_ptr, "Can't add Average filter after starting");
|
||||
png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
|
||||
~PNG_FILTER_AVG);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
|
||||
}
|
||||
}
|
||||
|
||||
if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
|
||||
png_ptr->paeth_row == NULL)
|
||||
{
|
||||
if (png_ptr->prev_row == NULL)
|
||||
{
|
||||
png_warning(png_ptr, "Can't add Paeth filter after starting");
|
||||
png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
|
||||
}
|
||||
}
|
||||
|
||||
if (png_ptr->do_filter == PNG_NO_FILTERS)
|
||||
#endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
png_ptr->do_filter = PNG_FILTER_NONE;
|
||||
/* Allocate any required buffers that have not already been allocated.
|
||||
*/
|
||||
png_write_alloc_filter_row_buffers(png_ptr, filters);
|
||||
}
|
||||
}
|
||||
else
|
||||
png_error(png_ptr, "Unknown custom filter method");
|
||||
# endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
|
||||
/* Finally store the value.
|
||||
* TODO: this field could probably be removed if neither READ nor
|
||||
* WRITE_FILTER are supported.
|
||||
*/
|
||||
png_ptr->do_filter = (png_byte)filters; /* SAFE: checked above */
|
||||
}
|
||||
|
||||
/* This allows us to influence the way in which libpng chooses the "best"
|
||||
|
114
pngwutil.c
114
pngwutil.c
@ -1425,10 +1425,14 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
|
||||
if (num_trans <= 0 || num_trans > png_ptr->num_palette)
|
||||
{
|
||||
/* This is an error which can only be reliably detected late, change to
|
||||
* a png_app_warning here so that it will fail in debug. It should be
|
||||
* a png_app_error.
|
||||
*/
|
||||
png_app_warning(png_ptr,
|
||||
"Invalid number of transparent colors specified");
|
||||
"Invalid number of transparent colors specified");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1442,7 +1446,7 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
|
||||
/* One 16 bit value */
|
||||
if (tran->gray >= (1 << png_ptr->bit_depth))
|
||||
{
|
||||
png_app_warning(png_ptr,
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
|
||||
|
||||
return;
|
||||
@ -1474,7 +1478,8 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
|
||||
|
||||
else
|
||||
{
|
||||
png_app_warning(png_ptr, "Can't write tRNS with an alpha channel");
|
||||
/* Checked in png_set_tRNS */
|
||||
png_warning(png_ptr, "Can't write tRNS with an alpha channel");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1516,6 +1521,7 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
|
||||
if (buf[0] | buf[2] | buf[4])
|
||||
#endif
|
||||
{
|
||||
/* This can no longer happen because it is checked in png_set_tRNS */
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
|
||||
|
||||
@ -1529,6 +1535,7 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
|
||||
{
|
||||
if (back->gray >= (1 << png_ptr->bit_depth))
|
||||
{
|
||||
/* Also checked in png_set_tRNS */
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
|
||||
|
||||
@ -1931,6 +1938,47 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
png_write_alloc_filter_row_buffers(png_structrp png_ptr, int filters)
|
||||
/* Allocate row buffers for any filters that need them, this is also called
|
||||
* from png_set_filter if the filters are changed during write to ensure that
|
||||
* the required buffers exist. png_set_filter ensures that up/avg/paeth are
|
||||
* only set if png_ptr->prev_row is allocated.
|
||||
*/
|
||||
{
|
||||
/* The buffer size is determined just by the output row size, not any
|
||||
* processing requirements.
|
||||
*/
|
||||
png_alloc_size_t buf_size = png_ptr->rowbytes + 1;
|
||||
|
||||
if ((filters & PNG_FILTER_SUB) != 0 && png_ptr->sub_row == NULL)
|
||||
{
|
||||
png_ptr->sub_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
|
||||
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
|
||||
}
|
||||
|
||||
if ((filters & PNG_FILTER_UP) != 0 && png_ptr->up_row == NULL)
|
||||
{
|
||||
png_ptr->up_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
|
||||
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
|
||||
}
|
||||
|
||||
if ((filters & PNG_FILTER_AVG) != 0 && png_ptr->avg_row == NULL)
|
||||
{
|
||||
png_ptr->avg_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
|
||||
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
|
||||
}
|
||||
|
||||
if ((filters & PNG_FILTER_PAETH) != 0 && png_ptr->paeth_row == NULL)
|
||||
{
|
||||
png_ptr->paeth_row = png_voidcast(png_bytep, png_malloc(png_ptr,
|
||||
buf_size));
|
||||
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
|
||||
}
|
||||
}
|
||||
#endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
|
||||
/* Initializes the row writing capability of libpng */
|
||||
void /* PRIVATE */
|
||||
png_write_start_row(png_structrp png_ptr)
|
||||
@ -1951,11 +1999,18 @@ png_write_start_row(png_structrp png_ptr)
|
||||
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
int filters;
|
||||
#endif
|
||||
|
||||
png_alloc_size_t buf_size;
|
||||
int usr_pixel_depth;
|
||||
|
||||
png_debug(1, "in png_write_start_row");
|
||||
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
|
||||
usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
|
||||
buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;
|
||||
|
||||
@ -1964,49 +2019,34 @@ png_write_start_row(png_structrp png_ptr)
|
||||
png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
|
||||
|
||||
/* Set up row buffer */
|
||||
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
|
||||
png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
|
||||
|
||||
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
|
||||
|
||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||
/* Set up filtering buffer, if using this filter */
|
||||
if (png_ptr->do_filter & PNG_FILTER_SUB)
|
||||
{
|
||||
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
|
||||
filters = png_ptr->do_filter;
|
||||
|
||||
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
|
||||
}
|
||||
if (png_ptr->height == 1)
|
||||
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
|
||||
|
||||
/* We only need to keep the previous row if we are using one of these. */
|
||||
if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
|
||||
{
|
||||
/* Set up previous row buffer */
|
||||
png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size);
|
||||
if (png_ptr->width == 1)
|
||||
filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_UP)
|
||||
{
|
||||
png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
|
||||
png_ptr->rowbytes + 1);
|
||||
if (filters == 0)
|
||||
filters = PNG_FILTER_NONE;
|
||||
|
||||
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
|
||||
}
|
||||
/* We only need to keep the previous row if we are using one of the following
|
||||
* filters.
|
||||
*/
|
||||
if (filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
|
||||
png_ptr->prev_row = png_voidcast(png_bytep, png_calloc(png_ptr,
|
||||
buf_size));
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_AVG)
|
||||
{
|
||||
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
|
||||
png_ptr->rowbytes + 1);
|
||||
png_write_alloc_filter_row_buffers(png_ptr, filters);
|
||||
|
||||
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
|
||||
}
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_PAETH)
|
||||
{
|
||||
png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
|
||||
png_ptr->rowbytes + 1);
|
||||
|
||||
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
|
||||
}
|
||||
}
|
||||
png_ptr->do_filter = (png_byte)filters; /* in case it was changed above */
|
||||
#else
|
||||
png_ptr->do_filter = PNG_FILTER_NONE;
|
||||
#endif /* PNG_WRITE_FILTER_SUPPORTED */
|
||||
|
||||
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||
|
Loading…
x
Reference in New Issue
Block a user