# HG changeset patch
# User Vin Shelton <acs@xemacs.org>
# 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);
 
