# HG changeset patch # User Vin Shelton # Date 1323317837 18000 # Node ID 51ced9b8fb63e4be59ea611b58128c400e3df987 # Parent 032a91928d47b36ae3dd98885767d9e0202892f7 Clean up PNG handling. Fix crash in issue570. diff -r 032a91928d47b36ae3dd98885767d9e0202892f7 -r 51ced9b8fb63e4be59ea611b58128c400e3df987 src/glyphs-eimage.c --- a/src/glyphs-eimage.c Sat Dec 03 20:04:12 2011 -0500 +++ b/src/glyphs-eimage.c Wed Dec 07 23:17:17 2011 -0500 @@ -935,13 +935,22 @@ png_read_info (png_ptr, info_ptr); { - int y; + int y, padding; unsigned char **row_pointers; height = info_ptr->height; width = info_ptr->width; - /* Wow, allocate all the memory. Truly, exciting. */ - unwind.eimage = xnew_array_and_zero (unsigned char, width * height * 3); + /* Wow, allocate all the memory. Truly, exciting. + Well, yes, there's excitement to be had. It turns out that libpng + strips in place, so the last row overruns the buffer if depth is 16 + or there's an alpha channel. This is a crash on Linux. So we need + to add padding. + The worst case is reducing 8 bytes (16-bit RGBA) to 3 (8-bit RGB). */ + + padding = 5 * width; + unwind.eimage = xnew_array_and_zero (unsigned char, + width * height * 3 + padding); + /* libpng expects that the image buffer passed in contains a picture to draw on top of if the png has any transparencies. This could be a good place to pass that in... */ @@ -996,9 +1005,6 @@ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png_ptr); - /* we can't handle alpha values */ - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha (png_ptr); /* tell libpng to strip 16 bit depth files down to 8 bits */ if (info_ptr->bit_depth == 16) png_set_strip_16 (png_ptr); @@ -1011,6 +1017,13 @@ png_set_packing (png_ptr); } + /* we can't handle alpha values + png_read_update_info ensures the alpha flag is set when one of + the transforms above causes an alpha channel to be generated */ + png_read_update_info (png_ptr, info_ptr); + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha (png_ptr); + png_read_image (png_ptr, row_pointers); png_read_end (png_ptr, info_ptr);