[libpng15] Fixes to alpha swap on read, simplified write and filler add code

This commit is contained in:
John Bowler 2011-11-08 21:35:16 -06:00 committed by Glenn Randers-Pehrson
parent d4973837b2
commit e6fb691c49
3 changed files with 46 additions and 21 deletions

View File

@ -1804,10 +1804,12 @@ png_image_read_end(png_voidp argument)
else /* output needs an alpha channel */ else /* output needs an alpha channel */
{ {
/* This is tricky because it happens before the swap operation has /* This is tricky because it happens before the swap operation has
* been accomplished, so always add the alpha channel after the * been accomplished however the swap does *not* swap the added
* component channels. * alpha channel (weird API), so it must be added in the correct
* place.
*/ */
png_uint_32 filler; /* opaque filler */ png_uint_32 filler; /* opaque filler */
int where;
if (linear) if (linear)
filler = 65535; filler = 65535;
@ -1815,9 +1817,21 @@ png_image_read_end(png_voidp argument)
else else
filler = 255; filler = 255;
png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); # ifdef PNG_FORMAT_AFIRST_SUPPORTED
if (format & PNG_FORMAT_FLAG_AFIRST)
{
where = PNG_FILLER_BEFORE;
change &= ~PNG_FORMAT_FLAG_AFIRST;
} }
else
# endif
where = PNG_FILLER_AFTER;
png_set_add_alpha(png_ptr, filler, where);
}
/* This stops the (irrelevant) call to swap_alpha below. */
change &= ~PNG_FORMAT_FLAG_ALPHA; change &= ~PNG_FORMAT_FLAG_ALPHA;
} }
@ -1841,7 +1855,7 @@ png_image_read_end(png_voidp argument)
} }
# ifdef PNG_FORMAT_BGR_SUPPORTED # ifdef PNG_FORMAT_BGR_SUPPORTED
if (format & PNG_FORMAT_FLAG_BGR) if (change & PNG_FORMAT_FLAG_BGR)
{ {
/* Check only the output format; PNG is never BGR, don't do this if /* Check only the output format; PNG is never BGR, don't do this if
* the output is gray, but fix up the 'format' value in that case. * the output is gray, but fix up the 'format' value in that case.
@ -1857,7 +1871,7 @@ png_image_read_end(png_voidp argument)
# endif # endif
# ifdef PNG_FORMAT_AFIRST_SUPPORTED # ifdef PNG_FORMAT_AFIRST_SUPPORTED
if (format & PNG_FORMAT_FLAG_AFIRST) if (change & PNG_FORMAT_FLAG_AFIRST)
{ {
/* Only relevant if there is an alpha channel - it's particularly /* Only relevant if there is an alpha channel - it's particularly
* important to handle this correctly because do_local_compose may * important to handle this correctly because do_local_compose may
@ -1924,7 +1938,9 @@ png_image_read_end(png_voidp argument)
# endif # endif
# ifdef PNG_FORMAT_AFIRST_SUPPORTED # ifdef PNG_FORMAT_AFIRST_SUPPORTED
if (png_ptr->transformations & PNG_SWAP_ALPHA) if (png_ptr->transformations & PNG_SWAP_ALPHA ||
((png_ptr->transformations & PNG_ADD_ALPHA) != 0 &&
(png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0))
info_format |= PNG_FORMAT_FLAG_AFIRST; info_format |= PNG_FORMAT_FLAG_AFIRST;
# endif # endif

View File

@ -3900,6 +3900,16 @@ png_read_start_row(png_structp png_ptr)
max_pixel_depth = png_ptr->pixel_depth; max_pixel_depth = png_ptr->pixel_depth;
/* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of
* calculations to calculate the final pixel depth, then
* png_do_read_transforms actually does the transforms. This means that the
* code which effectively calculates this value is actually repeated in three
* separate places. They must all match. Innocent changes to the order of
* transformations can and will break libpng in a way that causes memory
* overwrites.
*
* TODO: fix this.
*/
#ifdef PNG_READ_PACK_SUPPORTED #ifdef PNG_READ_PACK_SUPPORTED
if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
max_pixel_depth = 8; max_pixel_depth = 8;
@ -3958,10 +3968,7 @@ png_read_start_row(png_structp png_ptr)
#ifdef PNG_READ_FILLER_SUPPORTED #ifdef PNG_READ_FILLER_SUPPORTED
if (png_ptr->transformations & (PNG_FILLER)) if (png_ptr->transformations & (PNG_FILLER))
{ {
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
max_pixel_depth = 32;
else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{ {
if (max_pixel_depth <= 8) if (max_pixel_depth <= 8)
max_pixel_depth = 16; max_pixel_depth = 16;
@ -3970,7 +3977,8 @@ png_read_start_row(png_structp png_ptr)
max_pixel_depth = 32; max_pixel_depth = 32;
} }
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{ {
if (max_pixel_depth <= 32) if (max_pixel_depth <= 32)
max_pixel_depth = 32; max_pixel_depth = 32;

View File

@ -1805,7 +1805,7 @@ png_write_image_16bit(png_voidp argument)
++out_ptr; ++out_ptr;
} }
png_write_row(png_ptr, (png_bytep)output_row); png_write_row(png_ptr, display->local_row);
input_row += display->row_bytes/(sizeof (png_uint_16)); input_row += display->row_bytes/(sizeof (png_uint_16));
} }
@ -1911,7 +1911,7 @@ png_write_image_8bit(png_voidp argument)
++out_ptr; ++out_ptr;
} /* while out_ptr < row_end */ } /* while out_ptr < row_end */
png_write_row(png_ptr, output_row); png_write_row(png_ptr, display->local_row);
input_row += display->row_bytes/(sizeof (png_uint_16)); input_row += display->row_bytes/(sizeof (png_uint_16));
} /* while y */ } /* while y */
} }
@ -1998,11 +1998,9 @@ png_image_write_main(png_voidp argument)
/* Now set up the data transformations (*after* the header is written), /* Now set up the data transformations (*after* the header is written),
* remove the handled transformations from the 'format' flags for checking. * remove the handled transformations from the 'format' flags for checking.
*
* First check for a little endian system if writing 16 bit files.
*/ */
format &= ~(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
PNG_FORMAT_FLAG_ALPHA);
/* Check for a little endian system if writing 16 bit files. */
if (write_16bit) if (write_16bit)
{ {
PNG_CONST png_uint_16 le = 0x0001; PNG_CONST png_uint_16 le = 0x0001;
@ -2014,6 +2012,7 @@ png_image_write_main(png_voidp argument)
# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
if (format & PNG_FORMAT_FLAG_BGR) if (format & PNG_FORMAT_FLAG_BGR)
{ {
if (format & PNG_FORMAT_FLAG_COLOR)
png_set_bgr(png_ptr); png_set_bgr(png_ptr);
format &= ~PNG_FORMAT_FLAG_BGR; format &= ~PNG_FORMAT_FLAG_BGR;
} }
@ -2022,13 +2021,15 @@ png_image_write_main(png_voidp argument)
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
if (format & PNG_FORMAT_FLAG_AFIRST) if (format & PNG_FORMAT_FLAG_AFIRST)
{ {
if (format & PNG_FORMAT_FLAG_ALPHA)
png_set_swap_alpha(png_ptr); png_set_swap_alpha(png_ptr);
format &= ~PNG_FORMAT_FLAG_AFIRST; format &= ~PNG_FORMAT_FLAG_AFIRST;
} }
# endif # endif
/* That should have handled all the transforms. */ /* That should have handled all (both) the transforms. */
if (format != 0) if ((format & ~(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
PNG_FORMAT_FLAG_ALPHA)) != 0)
png_error(png_ptr, "png_write_image: unsupported transformation"); png_error(png_ptr, "png_write_image: unsupported transformation");
{ {