[libpng17] Transformed rewrite: changed row_info, added checks. This introduces an

internal struct (png_transform_control) to replace row_info and uses
    that to implement affirms correctly.  The change also adds checks on
    the rowbytes calculation and additional checks on most transform
    implementations.
Added png_uint_16 range checking, pngvalid tRNS, fixed png_uint_16:
    review of previous checks, removal of some where SAFE. pngvalid: add
    testing of tRNS for better code coverage pngvalid: correct rgb-to-gray
    error calculations. Code coverage is still incomplete: see /*UNTESTED*/
    in pngrtran.c
This commit is contained in:
John Bowler 2015-03-30 21:32:41 -05:00 committed by Glenn Randers-Pehrson
parent 73ea393ab2
commit 673ae608ab
14 changed files with 1812 additions and 1451 deletions

View File

@ -1,5 +1,5 @@
Libpng 1.7.0beta59 - March 25, 2015
Libpng 1.7.0beta59 - March 31, 2015
This is not intended to be a public release. It will be replaced
within a few weeks by a public version or by another test version.
@ -779,6 +779,17 @@ Version 1.7.0beta58 [March 25, 2015]
condition on RELEASE (or not) builds and tidy up the #ifdef handling of
functions.
Version 1.7.0beta59 [March 31, 2015]
Transformed rewrite: changed row_info, added checks. This introduces an
internal struct (png_transform_control) to replace row_info and uses
that to implement affirms correctly. The change also adds checks on
the rowbytes calculation and additional checks on most transform
implementations.
Added png_uint_16 range checking, pngvalid tRNS, fixed png_uint_16:
review of previous checks, removal of some where SAFE. pngvalid: add
testing of tRNS for better code coverage pngvalid: correct rgb-to-gray
error calculations. Code coverage is still incomplete: see /*UNTESTED*/
in pngrtran.c
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit

12
CHANGES
View File

@ -5069,7 +5069,17 @@ Version 1.7.0beta58 [March 25, 2015]
condition on RELEASE (or not) builds and tidy up the #ifdef handling of
functions.
Version 1.7.0beta59 [March 25, 2015]
Version 1.7.0beta59 [March 31, 2015]
Transformed rewrite: changed row_info, added checks. This introduces an
internal struct (png_transform_control) to replace row_info and uses
that to implement affirms correctly. The change also adds checks on
the rowbytes calculation and additional checks on most transform
implementations.
Added png_uint_16 range checking, pngvalid tRNS, fixed png_uint_16:
review of previous checks, removal of some where SAFE. pngvalid: add
testing of tRNS for better code coverage pngvalid: correct rgb-to-gray
error calculations. Code coverage is still incomplete: see /*UNTESTED*/
in pngrtran.c
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit

View File

@ -73,8 +73,9 @@ done
# present bad things are happening.
#
# The autotools generated files:
libpng_autotools_files="Makefile.in aclocal.m4 config.guess config.h.in\
config.sub configure depcomp install-sh ltmain.sh missing test-driver"
libpng_autotools_files="Makefile.in aclocal.m4 config.guess config.h.in
config.h.in~ config.sub configure depcomp install-sh ltmain.sh missing\
test-driver"
#
# Files generated by versions of configue >2.68 or automake >1.13 (i.e. later
# versions than those required by configure.ac):

View File

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

4
png.c
View File

@ -689,13 +689,13 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
"libpng version 1.7.0beta59 - March 25, 2015" PNG_STRING_NEWLINE \
"libpng version 1.7.0beta59 - March 31, 2015" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2015 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
return "libpng version 1.7.0beta59 - March 25, 2015\
return "libpng version 1.7.0beta59 - March 31, 2015\
Copyright (c) 1998-2015 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";

View File

@ -395,6 +395,15 @@
*
* Note that these are not configurable: this is just the affirm code; there's
* no reason to allow configuration of these options.
*
* 'debug' is a version of 'affirm' that is completely removed from RELEASE
* builds. This is used when either an unexpected condition is completely
* handled or when it can't be handled even by png_error, for example after a
* memory overwrite.
*
* UNTESTED is used to mark code that has not been tested; it causes an assert
* if the code is executed and (therefore) tested. UNTESTED should not remain
* in release candidate code.
*/
#define PNG_AFFIRM_TEXT (PNG_RELEASE_BUILD ?\
(defined PNG_ERROR_TEXT_SUPPORTED) :\
@ -412,12 +421,21 @@
if (!(cond)) png_affirm(pp, PNG_SRC_LINE);\
while (0)
# define png_impossiblepp(pp, reason) png_affirm(pp, PNG_SRC_LINE)
# define debug(cond) do {} while (0)
# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
/* Make sure there are no 'UNTESTED' macros in released code: */
# define UNTESTED libpng untested code
# endif
#else
# define png_affirmpp(pp, cond)\
do\
if (!(cond)) png_affirm(pp, #cond, PNG_SRC_LINE);\
while (0)
# define png_impossiblepp(pp, reason) png_affirm(pp, reason, PNG_SRC_LINE)
# define debug(cond) png_affirmpp(png_ptr, cond)
# define UNTESTED png_affirm(png_ptr, "untested code", PNG_SRC_LINE);
#endif
#define affirm(cond) png_affirmpp(png_ptr, cond)
@ -909,6 +927,54 @@ PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]);
extern "C" {
#endif /* __cplusplus */
#if defined (PNG_READ_TRANSFORMS_SUPPORTED) ||\
defined (PNG_WRITE_TRANSFORMS_SUPPORTED)
/* Transform support. Prior to 1.7.0 the internal transform routines (not the
* APIs) took a png_row_infop, like the user transform function, but without
* the png_ptr because it was never used. In 1.7.0 a separate internal
* structure is used in place of this to allow both future development to
* change the structure.
*
* The values in this structure will normally be changed by transformation
* implementations.
*/
typedef struct
{
png_const_structrp png_ptr; /* png_struct for error handling and some
* transform parameters.
*/
png_uint_32 width; /* width of row */
unsigned int channels; /* number of channels (1, 2, 3, or 4) */
unsigned int bit_depth; /* bit depth of row */
unsigned int flags; /* As below */
# define PNG_INDEXED 1 /* Indexed/palette PNG */
# define PNG_RGB_SWAPPED 2 /* as in the PNG_BGR transformation */
# define PNG_FILLER_IN_ALPHA 4 /* 'alpha' channel is really just a filler */
# define PNG_ALPHA_SWAPPED 8 /* Alpha is in the first channel */
# define PNG_ALPHA_INVERTED 16 /* Alpha values inverted */
# define PNG_INVERTED 32 /* grayscale channel inverted */
# define PNG_BITS_SHIFTED 64 /* Channels not in range 1..(bit_depth-1) */
# define PNG_BYTE_SWAPPED 128 /* 'swab', i.e. pairs of bytes swapped */
# define PNG_PIXEL_SWAPPED 256 /* pixels swapped within bytes */
# define PNG_BAD_INDEX 512 /* Bad palette image index */
} png_transform_control, *png_transform_controlp;
/* Validation: channels and bit_depth can be set to anything required by
* the transform, but the result may not be encodable in PNG. PNG_USURPED
* must be set in this case. This macro detects the detectably unrepresentable
* case channels case.
*
* Channels: must be 1 when PNG_INDEXED is set, must be 1-4 otherwise, so:
*
* (channels-1) <= (((flags & PNG_INDEXED)-1) & 3)
*/
#define PNG_VALID_CHANNELS(ri)\
(((ri)->channels-1) <= ((((ri)->flags & PNG_INDEXED)-1) & 3))
typedef const png_transform_control *png_const_transform_controlp;
typedef const png_row_info *png_const_row_infop;
#endif /* TRANSFORMS */
/* Internal functions; these are not exported from a DLL however because they
* are used within several of the C source files they have to be C extern.
*
@ -1364,30 +1430,30 @@ PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,
/* Shared transform functions, defined in pngtran.c */
#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info,
png_bytep row, int at_start),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(
png_transform_controlp row_info, png_bytep row, int at_start),PNG_EMPTY);
#endif
#ifdef PNG_16BIT_SUPPORTED
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info,
PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_transform_controlp row_info,
png_bytep row),PNG_EMPTY);
#endif
#endif
#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
defined(PNG_WRITE_PACKSWAP_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info,
PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_transform_controlp row_info,
png_bytep row),PNG_EMPTY);
#endif
#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info,
PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_transform_controlp row_info,
png_bytep row),PNG_EMPTY);
#endif
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,
PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_transform_controlp row_info,
png_bytep row),PNG_EMPTY);
#endif
@ -1509,6 +1575,24 @@ PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */
/* Handle the transformations for reading and writing */
#if defined(PNG_READ_TRANSFORMS_SUPPORTED) ||\
defined(PNG_WRITE_TRANSFORMS_SUPPORTED)
/* Utility functions: */
PNG_INTERNAL_FUNCTION(void,png_init_transform_control,(
png_const_structrp png_ptr, png_transform_controlp out,
png_const_row_infop in),
PNG_EMPTY);
/* This function exists to ensure that overflow cannot happen even if there
* are bugs in the transforms or calculation of maximum_pixel_depth.
*/
PNG_INTERNAL_FUNCTION(size_t,png_transform_rowbytes,(
png_const_transform_controlp row_info),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_end_transform_control,(png_row_infop out,
png_const_transform_controlp in), PNG_EMPTY);
#endif /* TRANSFORMS */
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr,
png_row_infop row_info),PNG_EMPTY);
@ -1668,7 +1752,7 @@ PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,
#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes,
(png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY);
(png_structrp png_ptr, png_transform_controlp row_info),PNG_EMPTY);
#endif
#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)

View File

@ -948,15 +948,12 @@ png_read_destroy(png_structrp png_ptr)
}
png_ptr->free_me &= ~PNG_FREE_PLTE;
#if defined(PNG_tRNS_SUPPORTED) || \
defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
{
png_free(png_ptr, png_ptr->trans_alpha);
png_ptr->trans_alpha = NULL;
}
png_ptr->free_me &= ~PNG_FREE_TRNS;
#endif
inflateEnd(&png_ptr->zstream);

1916
pngrtran.c

File diff suppressed because it is too large Load Diff

View File

@ -4179,7 +4179,7 @@ png_read_start_row(png_structrp png_ptr)
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
#endif
int max_pixel_depth;
unsigned int max_pixel_depth;
png_size_t row_bytes;
png_debug(1, "in png_read_start_row");
@ -4344,7 +4344,7 @@ png_read_start_row(png_structrp png_ptr)
defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
if (png_ptr->transformations & PNG_USER_TRANSFORM)
{
int user_pixel_depth = png_ptr->user_transform_depth *
unsigned int user_pixel_depth = png_ptr->user_transform_depth *
png_ptr->user_transform_channels;
if (user_pixel_depth > max_pixel_depth)
@ -4355,7 +4355,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
/* This value is stored in png_struct and double checked in the row read
* code.
*/
png_ptr->maximum_pixel_depth = png_check_byte(png_ptr, max_pixel_depth);
png_ptr->maximum_pixel_depth = max_pixel_depth;
png_ptr->transformed_pixel_depth = 0; /* calculated on demand */
/* Align the width on the next larger 8 pixels. Mainly used

View File

@ -165,11 +165,16 @@ struct png_struct_def
* and faster.
*/
png_colorp palette; /* palette from the input file */
png_bytep trans_alpha; /* alpha values for paletted files */
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 */
/* TODO: usr_width is used in write, iwidth is used in read, the two fields
* could be made one.
*/
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 */
@ -181,7 +186,7 @@ struct png_struct_def
png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
png_uint_32 free_me; /* items libpng is responsible for freeing */
int maximum_pixel_depth; /* pixel depth used for the row buffers */
unsigned 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 */
#endif
@ -421,12 +426,6 @@ struct png_struct_def
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
#endif /* READ_GAMMA */
#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)

View File

@ -259,80 +259,89 @@ png_set_invert_mono(png_structrp png_ptr)
/* Invert monochrome grayscale data */
void /* PRIVATE */
png_do_invert(png_row_infop row_info, png_bytep row)
png_do_invert(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_invert");
# define png_ptr row_info->png_ptr
/* This test removed from libpng version 1.0.13 and 1.2.0:
* if (row_info->bit_depth == 1 &&
*/
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
if (row_info->channels == 1)
{
png_bytep rp = row;
png_size_t i;
png_size_t istop = row_info->rowbytes;
if (!(row_info->flags & PNG_INDEXED)) /* GRAY */
{
png_bytep rp = row + png_transform_rowbytes(row_info);
for (i = 0; i < istop; i++)
*rp++ ^= 0xff;
/* Don't care about the bit depth: */
while (rp > row)
*--rp ^= 0xff;
row_info->flags |= PNG_INVERTED;
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 8)
else if (row_info->channels == 2) /* GRAY ALPHA */
{
png_bytep rp = row;
png_size_t i;
png_size_t istop = row_info->rowbytes;
if (row_info->bit_depth == 8)
{
png_bytep rp;
for (i = 0; i < istop; i += 2)
*rp ^= 0xff, rp += 2;
row_info->flags |= PNG_INVERTED;
rp = row + png_transform_rowbytes(row_info);
/* Go backwards, so rp[-1] is alpha and rp[-2] is gray: */
while (rp >= row+2)
rp -= 2, *rp ^= 0xff;
}
# ifdef PNG_16BIT_SUPPORTED
else if (row_info->bit_depth == 16)
{
png_bytep rp;
row_info->flags |= PNG_INVERTED;
rp = row + png_transform_rowbytes(row_info);
/* The same, but now we have GGAA: */
while (rp >= row+4)
rp -= 3, *rp ^= 0xff, *--rp ^= 0xff;
}
# endif
}
#ifdef PNG_16BIT_SUPPORTED
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 16)
{
png_bytep rp = row;
png_size_t i;
png_size_t istop = row_info->rowbytes;
for (i = 0; i < istop; i += 4)
*rp++ ^= 0xff, *rp++ ^= 0xff, rp += 2;
}
#endif
# undef png_ptr
}
#endif
#endif /* READ_INVERT || WRITE_INVERT */
#ifdef PNG_16BIT_SUPPORTED
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
/* Swaps byte order on 16 bit depth images */
void /* PRIVATE */
png_do_swap(png_row_infop row_info, png_bytep row)
png_do_swap(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_swap");
# define png_ptr row_info->png_ptr
if (row_info->bit_depth == 16)
{
png_bytep rp = row;
png_uint_32 i;
png_uint_32 istop= row_info->width * row_info->channels;
png_bytep rp;
for (i = 0; i < istop; i++, rp += 2)
row_info->flags |= PNG_BYTE_SWAPPED;
rp = row + png_transform_rowbytes(row_info);
while (rp >= row+2)
{
#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED
/* Feature added to libpng-1.6.11 for testing purposes, not
* enabled by default.
*/
*(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp);
#else
png_byte t = *rp;
*rp = *(rp + 1);
*(rp + 1) = t;
#endif
png_byte save = *--rp;
*rp = rp[-1], --rp;
*rp = save;
}
}
# undef png_ptr
}
#endif
#endif
#endif /* READ_SWAP || WRITE_SWAP */
#endif /* 16_BIT */
#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
static PNG_CONST png_byte onebppswaptable[256] = {
@ -442,16 +451,16 @@ static PNG_CONST png_byte fourbppswaptable[256] = {
/* Swaps pixel packing order within bytes */
void /* PRIVATE */
png_do_packswap(png_row_infop row_info, png_bytep row)
png_do_packswap(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_packswap");
# define png_ptr row_info->png_ptr
if (row_info->bit_depth < 8)
{
png_bytep rp;
png_const_bytep end, table;
end = row + row_info->rowbytes;
png_bytep ep;
png_const_bytep table;
if (row_info->bit_depth == 1)
table = onebppswaptable;
@ -465,11 +474,15 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
else
return;
for (rp = row; rp < end; rp++)
*rp = table[*rp];
row_info->flags |= PNG_PIXEL_SWAPPED;
ep = row + png_transform_rowbytes(row_info);
while (row < ep)
*row = table[*row], ++row;
}
# undef png_ptr
}
#endif /* PACKSWAP || WRITE_PACKSWAP */
#endif /* READ_PACKSWAP || WRITE_PACKSWAP */
#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
@ -482,11 +495,14 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
* end (not in the middle) of each pixel.
*/
void /* PRIVATE */
png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
png_do_strip_channel(png_transform_controlp row_info, png_bytep row,
int at_start)
{
png_bytep sp = row; /* source pointer */
png_bytep dp = row; /* destination pointer */
png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */
png_const_bytep sp = row; /* source pointer */
png_bytep dp = row; /* destination pointer */
png_const_bytep ep = row + png_transform_rowbytes(row_info); /* beyond end */
# define png_ptr row_info->png_ptr
/* At the start sp will point to the first byte to copy and dp to where
* it is copied to. ep always points just beyond the end of the row, so
@ -509,8 +525,6 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
/* For a 1 pixel wide image there is nothing to do */
while (sp < ep)
*dp++ = *sp, sp += 2;
row_info->pixel_depth = 8;
}
else if (row_info->bit_depth == 16)
@ -522,18 +536,13 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
while (sp < ep)
*dp++ = *sp++, *dp++ = *sp, sp += 3;
row_info->pixel_depth = 16;
}
else
return; /* bad bit depth */
row_info->channels = 1;
/* Finally fix the color type if it records an alpha channel */
if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
row_info->color_type = PNG_COLOR_TYPE_GRAY;
debug(dp == row + png_transform_rowbytes(row_info));
}
/* RGBA, RGBX, XRGB cases */
@ -549,8 +558,6 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
/* Note that the loop adds 3 to dp and 4 to sp each time. */
while (sp < ep)
*dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2;
row_info->pixel_depth = 24;
}
else if (row_info->bit_depth == 16)
@ -567,104 +574,80 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
*dp++ = *sp++, *dp++ = *sp++;
*dp++ = *sp++, *dp++ = *sp, sp += 3;
}
row_info->pixel_depth = 48;
}
else
return; /* bad bit depth */
row_info->channels = 3;
/* Finally fix the color type if it records an alpha channel */
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
row_info->color_type = PNG_COLOR_TYPE_RGB;
debug(dp == row + png_transform_rowbytes(row_info));
}
else
return; /* The filler channel has gone already */
/* Fix the rowbytes value. */
row_info->rowbytes = dp-row;
# undef png_ptr
}
#endif
#endif /* WRITE_FILLER || READ_STRIP_ALPHA */
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
/* Swaps red and blue bytes within a pixel */
void /* PRIVATE */
png_do_bgr(png_row_infop row_info, png_bytep row)
png_do_bgr(png_transform_controlp row_info, png_bytep row)
{
unsigned int channels;
png_debug(1, "in png_do_bgr");
if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
# define png_ptr row_info->png_ptr
channels = row_info->channels;
if (channels == 3 || channels == 4)
{
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info);
if (row_info->bit_depth == 8)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
{
png_bytep rp;
png_uint_32 i;
ep -= channels; /* Last pixel */
row_info->flags ^= PNG_RGB_SWAPPED;
for (i = 0, rp = row; i < row_width; i++, rp += 3)
{
png_byte save = *rp;
*rp = *(rp + 2);
*(rp + 2) = save;
}
while (row <= ep)
{
png_byte save = row[0];
row[0] = row[2];
row[2] = save;
row += channels;
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
png_uint_32 i;
for (i = 0, rp = row; i < row_width; i++, rp += 4)
{
png_byte save = *rp;
*rp = *(rp + 2);
*(rp + 2) = save;
}
}
debug(row == ep+channels);
}
#ifdef PNG_16BIT_SUPPORTED
else if (row_info->bit_depth == 16)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
# ifdef PNG_16BIT_SUPPORTED
else if (row_info->bit_depth == 16)
{
png_bytep rp;
png_uint_32 i;
channels *= 2; /* now in bytes */
for (i = 0, rp = row; i < row_width; i++, rp += 6)
ep -= channels; /* Last pixel */
row_info->flags |= PNG_RGB_SWAPPED;
while (row <= ep)
{
png_byte save = *rp;
*rp = *(rp + 4);
*(rp + 4) = save;
save = *(rp + 1);
*(rp + 1) = *(rp + 5);
*(rp + 5) = save;
}
}
png_byte save = row[0];
row[0] = row[4];
row[4] = save;
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
png_uint_32 i;
save = row[1];
row[1] = row[5];
row[5] = save;
for (i = 0, rp = row; i < row_width; i++, rp += 8)
{
png_byte save = *rp;
*rp = *(rp + 4);
*(rp + 4) = save;
save = *(rp + 1);
*(rp + 1) = *(rp + 5);
*(rp + 5) = save;
row += channels;
}
debug(row == ep+channels);
}
}
#endif
# endif
}
# undef png_ptr
}
#endif /* READ_BGR || WRITE_BGR */
@ -672,19 +655,24 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
/* Added at libpng-1.5.10 */
void /* PRIVATE */
png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
png_do_check_palette_indexes(png_structrp png_ptr,
png_transform_controlp row_info)
{
if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
{
/* Calculations moved outside switch in an attempt to stop different
* compiler warnings. 'padding' is in *bits* within the last byte, it is
* an 'int' because pixel_depth becomes an 'int' in the expression below,
* and this calculation is used because it avoids warnings that other
* forms produced on either GCC or MSVC.
/* Padding is the unused bits in the last byte: 8 - bits-in-last-byte,
* which reduces to 7 & (-total_bits), so we don't care about overflow
* in the unsigned calculation here:
*/
unsigned int padding =
7 & -(row_info->bit_depth * row_info->channels * row_info->width);
png_bytep rp = png_ptr->row_buf + png_transform_rowbytes(row_info);
/* Note that png_ptr->row_buf starts with a filter byte, so rp is
* currently pointing to the last byte in the row, not just after
* it.
*/
int padding = (-row_info->pixel_depth * row_info->width) & 7;
png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
switch (row_info->bit_depth)
{
@ -771,6 +759,136 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
}
#endif /* CHECK_FOR_INVALID_INDEX */
#if defined(PNG_READ_TRANSFORMS_SUPPORTED) ||\
defined(PNG_WRITE_TRANSFORMS_SUPPORTED)
/* Utility functions: */
void
png_init_transform_control(png_const_structrp png_ptr,
png_transform_controlp out, png_const_row_infop row_info)
{
out->png_ptr = png_ptr;
/* At the start expect row_info to be consistent with png_ptr: */
if (png_ptr->mode & PNG_IS_READ_STRUCT)
{
debug(png_ptr->iwidth == row_info->width);
debug(png_ptr->color_type == row_info->color_type);
debug(png_ptr->bit_depth == row_info->bit_depth);
}
out->width = row_info->width;
out->flags = 0;
out->bit_depth = row_info->bit_depth;
switch (row_info->color_type)
{
case PNG_COLOR_TYPE_GRAY:
out->channels = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
out->channels = 2;
break;
case PNG_COLOR_TYPE_PALETTE:
affirm(!(png_ptr->mode & PNG_IS_READ_STRUCT) ||
png_ptr->palette != NULL);
out->flags |= PNG_INDEXED;
out->channels = 1;
break;
case PNG_COLOR_TYPE_RGB:
out->channels = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
out->channels = 4;
break;
default:
impossible("invalid PNG color type");
}
}
size_t
png_transform_rowbytes(png_const_transform_controlp row_info)
{
# define png_ptr row_info->png_ptr
/* For this not to overflow the pixel depth calculation must not overflow
* and the pixel depth must be less than maximum_pixel_depth.
*/
/* The release code uses PNG_ROWBYTES, so make sure that it will not
* overflow. To test this it is necessary to generate some very wide
* images and ensure that the code errors out before getting here.
*/
unsigned int channels = row_info->channels;
unsigned int bit_depth = row_info->bit_depth;
unsigned int pixel_bits = channels * bit_depth;
size_t width = row_info->width;
affirm(bit_depth < 256 && channels < 256 &&
pixel_bits <= png_ptr->maximum_pixel_depth);
return PNG_ROWBYTES(pixel_bits, width);
# undef png_ptr
}
static unsigned int
transform_color_type(png_const_transform_controlp row_info)
{
const unsigned int ch = row_info->channels - 1;
const unsigned int indexed = row_info->flags & PNG_INDEXED;
/* That is 0, 1, 2, 3 for G/PALETTE, GA, RGB, RGBA. Check the
* numbers:
*/
# if PNG_INDEXED != PNG_COLOR_MASK_PALETTE ||\
PNG_FILLER_IN_ALPHA != PNG_COLOR_MASK_ALPHA ||\
PNG_COLOR_MASK_PALETTE != 1 ||\
PNG_COLOR_MASK_COLOR != 2 ||\
PNG_COLOR_MASK_ALPHA != 4
# error Unexpected PNG color type defines
# endif
/* The following preserves all the bits in row_info->channels except the
* top bit and generates a correct PNG color type for the defined values
* and an incorrect one for all undefined cases.
*
* Note that when PNG_FILLER_IN_ALPHA is set in the flags
*/
return indexed /*PALETTE*/ |
((ch & 2) ^ (indexed << 1) /*COLOR*/) |
(((ch & 1) << 2/*ALPHA*/) & ~row_info->flags) |
((ch & ~3) << 1 /*INVALID*/);
}
void
png_end_transform_control(png_row_infop out, png_const_transform_controlp in)
{
# define png_ptr in->png_ptr /* for affirm/impossible */
out->width = in->width;
out->rowbytes = png_transform_rowbytes(in);
out->color_type = png_check_byte(png_ptr, transform_color_type(in));
out->bit_depth = png_check_byte(png_ptr, in->bit_depth);
out->channels = png_check_byte(png_ptr, in->channels);
out->pixel_depth = png_check_byte(png_ptr, in->channels * in->bit_depth);
# ifdef PNG_WARNINGS_SUPPORTED
if ((in->flags & PNG_BAD_INDEX) != 0)
png_warning(png_ptr, "palette image had bad index");
# endif
/* At the end expect row_info to be consistent with png_ptr: */
if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
{
debug(png_ptr->color_type == out->color_type);
debug(png_ptr->bit_depth == out->bit_depth);
}
# undef png_ptr
}
#endif /* READ_TRANSFORMS | WRITE_TRANSFORMS */
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

View File

@ -882,7 +882,12 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
/* Check for out-of-range palette index */
if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
png_ptr->num_palette_max >= 0)
png_do_check_palette_indexes(png_ptr, &row_info);
{
png_transform_control display;
png_init_transform_control(png_ptr, &display, &row_info);
png_do_check_palette_indexes(png_ptr, &display);
}
#endif
/* Find a filter if necessary, filter the row and write it out. */

View File

@ -17,160 +17,111 @@
#ifdef PNG_WRITE_SUPPORTED
#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
/* This is here because png_row_info doesn't contain a png_ptr, so at present
* the transform routines can't signal an error. Instead we pass '0' as
* as png_ptr to png_check_byte in the non-release cases and do a hard cast
* in release.
*
* TODO: fix this.
*/
#ifdef PNG_RANGE_CHECK_SUPPORTED
# define CB(b) png_check_byte(0, b)
# define CU(u) png_check_u16(0, u)
#else
# define CB(b) ((png_byte)(b))
# define CU(u) ((png_uint_16)(u))
#endif
#ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
/* Pack pixels into bytes. Get the true bit depth from png_ptr. The
* row_info bit depth should be 8 (one pixel per byte). The channels
* should be 1 (this only happens on grayscale and paletted images).
*/
static void
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
png_do_pack(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_pack");
if (row_info->bit_depth == 8 &&
row_info->channels == 1)
# define png_ptr row_info->png_ptr
/* The comment suggests the following must be true.
* TODO: test this.
*/
affirm(row_info->bit_depth == 8 && row_info->channels == 1);
{
switch ((int)bit_depth)
switch (png_ptr->bit_depth)
{
case 1:
{
png_bytep sp, dp;
int mask, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info);
png_bytep dp = row;
unsigned int mask = 0x80, v = 0;
sp = row;
dp = row;
mask = 0x80;
v = 0;
for (i = 0; i < row_width; i++)
while (row < ep)
{
if (*sp != 0)
if (*row++ != 0)
v |= mask;
sp++;
mask >>= 1;
if (mask > 1)
mask >>= 1;
else
if (mask == 0)
{
mask = 0x80;
*dp = CB(v);
dp++;
*dp++ = (png_byte)/*SAFE*/v;
v = 0;
}
}
if (mask != 0x80)
*dp = CB(v);
*dp++ = (png_byte)/*SAFE*/v;
row_info->bit_depth = 1;
break;
}
case 2:
{
png_bytep sp, dp;
int shift, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info);
png_bytep dp = row;
unsigned int shift = 8, v = 0;
sp = row;
dp = row;
shift = 6;
v = 0;
for (i = 0; i < row_width; i++)
while (row < ep)
{
png_byte value;
value = PNG_BYTE(*sp & 0x03);
v |= (value << shift);
shift -= 2;
v |= (*row++ & 0x3) << shift;
if (shift == 0)
{
shift = 6;
*dp = CB(v);
dp++;
shift = 8;
*dp++ = png_check_byte(png_ptr, v);
v = 0;
}
else
shift -= 2;
sp++;
}
if (shift != 6)
*dp = CB(v);
if (shift != 8)
*dp++ = png_check_byte(png_ptr, v);
row_info->bit_depth = 2;
break;
}
case 4:
{
png_bytep sp, dp;
int shift, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info);
png_bytep dp = row;
unsigned int shift = 8, v = 0;
sp = row;
dp = row;
shift = 4;
v = 0;
for (i = 0; i < row_width; i++)
while (row < ep)
{
png_byte value;
value = PNG_BYTE(*sp & 0x0f);
v |= (value << shift);
shift -= 4;
v |= ((*row++ & 0xf) << shift);
if (shift == 0)
{
shift = 4;
*dp = CB(v);
dp++;
shift = 8;
*dp++ = png_check_byte(png_ptr, v);
v = 0;
}
else
shift -= 4;
sp++;
}
if (shift != 4)
*dp = CB(v);
if (shift != 8)
*dp++ = png_check_byte(png_ptr, v);
row_info->bit_depth = 4;
break;
}
default:
break;
}
row_info->bit_depth = CB(bit_depth);
row_info->pixel_depth = CB(bit_depth * row_info->channels);
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
row_info->width);
}
# undef png_ptr
}
#endif
@ -181,19 +132,26 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
* bit depth 4, but the pixels only had values from 0 to 7, you
* would pass 3 as bit_depth, and this routine would translate the
* data to 0 to 15.
*
* NOTE: this is horrible complexity for no value. Once people suggested they
* were selling 16-bit displays with 5:6:5 bits spread R:G:B but so far as I
* could determine these displays produced intermediate grey (uncolored) colors,
* which is impossible with a true 5:6:5, so most likely 5:6:5 was marketing.
*/
static void
png_do_shift(png_row_infop row_info, png_bytep row,
png_const_color_8p bit_depth)
png_do_shift(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_shift");
if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
# define png_ptr row_info->png_ptr
if (!(row_info->flags & PNG_INDEXED) && (row_info->channels-1) <= 3)
{
png_const_color_8p bit_depth = &png_ptr->shift;
int shift_start[4], shift_dec[4];
int channels = 0;
if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
if (row_info->channels == 3 || row_info->channels == 4)
{
shift_start[channels] = row_info->bit_depth - bit_depth->red;
shift_dec[channels] = bit_depth->red;
@ -208,27 +166,29 @@ png_do_shift(png_row_infop row_info, png_bytep row,
channels++;
}
else
else /* 1 or 2 channels */
{
shift_start[channels] = row_info->bit_depth - bit_depth->gray;
shift_dec[channels] = bit_depth->gray;
channels++;
}
if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
if (row_info->channels == 2 || row_info->channels == 4)
{
shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
shift_dec[channels] = bit_depth->alpha;
channels++;
}
/* With low row depths, could only be grayscale, so one channel */
/* With low res depths, could only be grayscale, so one channel */
if (row_info->bit_depth < 8)
{
png_bytep bp = row;
png_size_t i;
unsigned int mask;
png_size_t row_bytes = row_info->rowbytes;
size_t row_bytes = png_transform_rowbytes(row_info);
affirm(row_info->channels == 1);
if (bit_depth->gray == 1 && row_info->bit_depth == 2)
mask = 0x55;
@ -256,7 +216,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
out |= (v >> (-j)) & mask;
}
*bp = CB(out);
*bp = png_check_byte(png_ptr, out);
}
}
@ -285,7 +245,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
out |= v >> (-j);
}
*bp = CB(out);
*bp = png_check_byte(png_ptr, out);
}
}
@ -312,200 +272,174 @@ png_do_shift(png_row_infop row_info, png_bytep row,
else
value |= v >> (-j);
}
*bp++ = CB(value >> 8);
*bp++ = png_check_byte(png_ptr, value >> 8);
*bp++ = PNG_BYTE(value);
}
}
}
# undef png_ptr
}
#endif
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
static void
png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
png_do_write_swap_alpha(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_write_swap_alpha");
# define png_ptr row_info->png_ptr
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
if (row_info->channels == 4)
{
if (row_info->bit_depth == 8)
{
/* This converts from ARGB to RGBA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 4;
for (i = 0, sp = dp = row; i < row_width; i++)
/* This converts from ARGB to RGBA */
while (row <= ep)
{
png_byte save = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save;
png_byte save = row[0];
row[0] = row[1];
row[1] = row[2];
row[2] = row[3];
row[3] = save;
row += 4;
}
debug(row == ep+4);
}
#ifdef PNG_WRITE_16BIT_SUPPORTED
else
else if (row_info->bit_depth == 16)
{
/* This converts from AARRGGBB to RRGGBBAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 8;
for (i = 0, sp = dp = row; i < row_width; i++)
while (row <= ep)
{
png_byte save[2];
save[0] = *(sp++);
save[1] = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save[0];
*(dp++) = save[1];
png_byte s0 = row[0];
png_byte s1 = row[1];
memmove(row, row+2, 6);
row[6] = s0;
row[7] = s1;
row += 8;
}
debug(row == ep+8);
}
#endif /* WRITE_16BIT */
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
else if (row_info->channels == 2)
{
if (row_info->bit_depth == 8)
{
/* This converts from AG to GA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 2;
for (i = 0, sp = dp = row; i < row_width; i++)
/* This converts from ARGB to RGBA */
while (row <= ep)
{
png_byte save = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save;
png_byte save = *row;
*row = row[1], ++row;
*row++ = save;
}
debug(row == ep+2);
}
#ifdef PNG_WRITE_16BIT_SUPPORTED
else
{
/* This converts from AAGG to GGAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 4;
for (i = 0, sp = dp = row; i < row_width; i++)
while (row <= ep)
{
png_byte save[2];
save[0] = *(sp++);
save[1] = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save[0];
*(dp++) = save[1];
png_byte save = row[0];
row[0] = row[2];
row[2] = save;
save = row[1];
row[1] = row[3];
row[3] = save;
row += 4;
}
debug(row == ep+4);
}
#endif /* WRITE_16BIT */
}
}
# undef png_ptr
}
#endif
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
static void
png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
png_do_write_invert_alpha(png_transform_controlp row_info, png_bytep row)
{
png_debug(1, "in png_do_write_invert_alpha");
# define png_ptr row_info->png_ptr
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
if (row_info->channels == 4)
{
if (row_info->bit_depth == 8)
{
/* This inverts the alpha channel in RGBA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 1;
for (i = 0, sp = dp = row; i < row_width; i++)
{
/* Does nothing
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*/
sp+=3; dp = sp;
*(dp++) = CB(255 - *(sp++));
}
row += 3; /* alpha channel */
while (row <= ep)
*row ^= 0xff, row += 4;
}
#ifdef PNG_WRITE_16BIT_SUPPORTED
else
else if (row_info->bit_depth == 16)
{
/* This inverts the alpha channel in RRGGBBAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 2;
for (i = 0, sp = dp = row; i < row_width; i++)
{
/* Does nothing
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*/
sp+=6; dp = sp;
*(dp++) = CB(255 - *(sp++));
*(dp++) = CB(255 - *(sp++));
}
row += 6;
while (row <= ep)
row[0] ^= 0xff, row[1] ^= 0xff, row += 8;
}
#endif /* WRITE_16BIT */
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
else if (row_info->channels == 2)
{
if (row_info->bit_depth == 8)
{
/* This inverts the alpha channel in GA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 1;
for (i = 0, sp = dp = row; i < row_width; i++)
{
*(dp++) = *(sp++);
*(dp++) = CB(255 - *(sp++));
}
++row;
while (row <= ep)
*row ^= 0xff, row += 2;
}
#ifdef PNG_WRITE_16BIT_SUPPORTED
else
{
/* This inverts the alpha channel in GGAA */
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_const_bytep ep = row + png_transform_rowbytes(row_info) - 2;
for (i = 0, sp = dp = row; i < row_width; i++)
{
/* Does nothing
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*/
sp+=2; dp = sp;
*(dp++) = CB(255 - *(sp++));
*(dp++) = CB(255 - *(sp++));
}
row += 2;
while (row <= ep)
row[0] ^= 0xff, row[1] ^= 0xff, row += 4;
}
#endif /* WRITE_16BIT */
}
}
# undef png_ptr
}
#endif
@ -513,8 +447,10 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
* transformations is significant.
*/
void /* PRIVATE */
png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info_in)
{
png_transform_control display;
png_debug(1, "in png_do_write_transformations");
if (png_ptr == NULL)
@ -526,7 +462,7 @@ png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
(*(png_ptr->write_user_transform_fn)) /* User write transform
function */
(png_ptr, /* png_ptr */
row_info, /* row_info: */
row_info_in, /* row_info: */
/* png_uint_32 width; width of row */
/* png_size_t rowbytes; number of bytes in row */
/* png_byte color_type; color type of pixels */
@ -536,55 +472,65 @@ png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
png_init_transform_control(png_ptr, &display, row_info_in);
#ifdef PNG_WRITE_FILLER_SUPPORTED
if ((png_ptr->transformations & PNG_FILLER) != 0)
png_do_strip_channel(row_info, png_ptr->row_buf + 1,
png_do_strip_channel(&display, png_ptr->row_buf + 1,
!(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
#endif
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
png_do_packswap(row_info, png_ptr->row_buf + 1);
png_do_packswap(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_PACK_SUPPORTED
if ((png_ptr->transformations & PNG_PACK) != 0)
png_do_pack(row_info, png_ptr->row_buf + 1,
(png_uint_32)png_ptr->bit_depth);
png_do_pack(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_SWAP_SUPPORTED
# ifdef PNG_16BIT_SUPPORTED
if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
png_do_swap(row_info, png_ptr->row_buf + 1);
png_do_swap(&display, png_ptr->row_buf + 1);
# endif
#endif
#ifdef PNG_WRITE_SHIFT_SUPPORTED
if ((png_ptr->transformations & PNG_SHIFT) != 0)
png_do_shift(row_info, png_ptr->row_buf + 1,
&(png_ptr->shift));
png_do_shift(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
png_do_write_swap_alpha(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
png_do_write_invert_alpha(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_BGR_SUPPORTED
if ((png_ptr->transformations & PNG_BGR) != 0)
png_do_bgr(row_info, png_ptr->row_buf + 1);
png_do_bgr(&display, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_INVERT_SUPPORTED
if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
png_do_invert(row_info, png_ptr->row_buf + 1);
png_do_invert(&display, png_ptr->row_buf + 1);
#endif
/* Clear the flags; they are irrelevant because the write code is
* reversing transformations to get PNG data but the shared transformation
* code assumes input PNG data. Only PNG_INDEXED is required.
*/
if ((display.flags & PNG_BAD_INDEX) != 0)
png_error(png_ptr, "palette data has out of range index");
display.flags &= PNG_INDEXED;
png_end_transform_control(row_info_in, &display);
}
#endif /* WRITE_TRANSFORMS */
#endif /* WRITE */

View File

@ -2006,7 +2006,7 @@ png_write_start_row(png_structrp png_ptr)
#endif
png_alloc_size_t buf_size;
int usr_pixel_depth;
unsigned int usr_pixel_depth;
png_debug(1, "in png_write_start_row");
@ -2018,7 +2018,7 @@ png_write_start_row(png_structrp png_ptr)
/* 1.5.6: added to allow checking in the row write code. */
png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;
png_ptr->maximum_pixel_depth = png_check_byte(png_ptr, usr_pixel_depth);
png_ptr->maximum_pixel_depth = usr_pixel_depth;
/* Set up row buffer */
png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));