diff --git a/pngread.c b/pngread.c index f6ab7e55b..18ed0420d 100644 --- a/pngread.c +++ b/pngread.c @@ -1804,10 +1804,12 @@ png_image_read_end(png_voidp argument) 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 @@ png_image_read_end(png_voidp argument) 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 @@ png_image_read_end(png_voidp argument) } # 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 @@ png_image_read_end(png_voidp argument) # 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 @@ png_image_read_end(png_voidp argument) # 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 c04974b09..fc450ea63 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -3900,6 +3900,16 @@ png_read_start_row(png_structp png_ptr) 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 @@ png_read_start_row(png_structp png_ptr) #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 @@ png_read_start_row(png_structp png_ptr) 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 594e8e3d5..def53b08b 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1805,7 +1805,7 @@ png_write_image_16bit(png_voidp argument) ++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 @@ png_write_image_8bit(png_voidp argument) ++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 @@ png_image_write_main(png_voidp argument) /* 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 @@ png_image_write_main(png_voidp argument) # 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 @@ png_image_write_main(png_voidp argument) # 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"); {