[libpng15] Fixes to alpha swap on read, simplified write and filler add code
diff --git a/pngread.c b/pngread.c
index f6ab7e5..18ed042 100644
--- a/pngread.c
+++ b/pngread.c
@@ -1804,10 +1804,12 @@
else /* output needs an alpha channel */
{
/* This is tricky because it happens before the swap operation has
- * been accomplished, so always add the alpha channel after the
- * component channels.
+ * been accomplished however the swap does *not* swap the added
+ * alpha channel (weird API), so it must be added in the correct
+ * place.
*/
png_uint_32 filler; /* opaque filler */
+ int where;
if (linear)
filler = 65535;
@@ -1815,9 +1817,21 @@
else
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;
}
@@ -1841,7 +1855,7 @@
}
# 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
* the output is gray, but fix up the 'format' value in that case.
@@ -1857,7 +1871,7 @@
# endif
# 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
* important to handle this correctly because do_local_compose may
@@ -1924,7 +1938,9 @@
# endif
# 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;
# endif
diff --git a/pngrutil.c b/pngrutil.c
index c04974b..fc450ea 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -3900,6 +3900,16 @@
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
if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
max_pixel_depth = 8;
@@ -3958,10 +3968,7 @@
#ifdef PNG_READ_FILLER_SUPPORTED
if (png_ptr->transformations & (PNG_FILLER))
{
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
- max_pixel_depth = 32;
-
- else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
if (max_pixel_depth <= 8)
max_pixel_depth = 16;
@@ -3970,7 +3977,8 @@
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)
max_pixel_depth = 32;
diff --git a/pngwrite.c b/pngwrite.c
index 594e8e3..def53b0 100644
--- a/pngwrite.c
+++ b/pngwrite.c
@@ -1805,7 +1805,7 @@
++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));
}
@@ -1911,7 +1911,7 @@
++out_ptr;
} /* 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));
} /* while y */
}
@@ -1998,11 +1998,9 @@
/* Now set up the data transformations (*after* the header is written),
* 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)
{
PNG_CONST png_uint_16 le = 0x0001;
@@ -2014,7 +2012,8 @@
# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
if (format & PNG_FORMAT_FLAG_BGR)
{
- png_set_bgr(png_ptr);
+ if (format & PNG_FORMAT_FLAG_COLOR)
+ png_set_bgr(png_ptr);
format &= ~PNG_FORMAT_FLAG_BGR;
}
# endif
@@ -2022,13 +2021,15 @@
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
if (format & PNG_FORMAT_FLAG_AFIRST)
{
- png_set_swap_alpha(png_ptr);
+ if (format & PNG_FORMAT_FLAG_ALPHA)
+ png_set_swap_alpha(png_ptr);
format &= ~PNG_FORMAT_FLAG_AFIRST;
}
# endif
- /* That should have handled all the transforms. */
- if (format != 0)
+ /* That should have handled all (both) the transforms. */
+ if ((format & ~(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
+ PNG_FORMAT_FLAG_ALPHA)) != 0)
png_error(png_ptr, "png_write_image: unsupported transformation");
{