comparison src/glyphs-eimage.c @ 4698:a9493cab536f

Fix crash due to mishandling transparency.
author Stephen J. Turnbull <stephen@xemacs.org>
date Wed, 23 Sep 2009 20:04:51 +0900
parents 648f4a0dac3e
children 1cecc3e9f0a0
comparison
equal deleted inserted replaced
4697:0d6d0edf1253 4698:a9493cab536f
952 } 952 }
953 953
954 png_read_info (png_ptr, info_ptr); 954 png_read_info (png_ptr, info_ptr);
955 955
956 { 956 {
957 int y; 957 int y, padding;
958 Binbyte **row_pointers; 958 Binbyte **row_pointers;
959 UINT_64_BIT pixels_sq; 959 UINT_64_BIT pixels_sq;
960 height = info_ptr->height; 960 height = info_ptr->height;
961 width = info_ptr->width; 961 width = info_ptr->width;
962 pixels_sq = (UINT_64_BIT) width * (UINT_64_BIT) height; 962 pixels_sq = (UINT_64_BIT) width * (UINT_64_BIT) height;
963 if (pixels_sq > ((size_t) -1) / 3) 963 if (pixels_sq > ((size_t) -1) / 3)
964 signal_image_error ("PNG image too large to instantiate", instantiator); 964 signal_image_error ("PNG image too large to instantiate", instantiator);
965 965
966 /* Wow, allocate all the memory. Truly, exciting. */ 966 /* Wow, allocate all the memory. Truly, exciting.
967 unwind.eimage = xnew_array_and_zero (Binbyte, (size_t) (pixels_sq * 3)); 967 Well, yes, there's excitement to be had. It turns out that libpng
968 strips in place, so the last row overruns the buffer if depth is 16
969 or there's an alpha channel. This is a crash on Linux. So we need
970 to add padding.
971 The worst case is reducing 8 bytes (16-bit RGBA) to 3 (8-bit RGB). */
972
973 padding = 5 * width;
974 unwind.eimage = xnew_array_and_zero (Binbyte,
975 (size_t) (pixels_sq * 3 + padding));
976
968 /* libpng expects that the image buffer passed in contains a 977 /* libpng expects that the image buffer passed in contains a
969 picture to draw on top of if the png has any transparencies. 978 picture to draw on top of if the png has any transparencies.
970 This could be a good place to pass that in... */ 979 This could be a good place to pass that in... */
971 980
972 row_pointers = xnew_array (png_byte *, height); 981 row_pointers = xnew_array (png_byte *, height);
973
974 for (y = 0; y < height; y++) 982 for (y = 0; y < height; y++)
975 row_pointers[y] = unwind.eimage + (width * 3 * y); 983 row_pointers[y] = unwind.eimage + (width * 3 * y);
976 984
977 { 985 {
978 /* if the png specifies a background chunk, go ahead and 986 /* if the png specifies a background chunk, go ahead and
988 { 996 {
989 warn_when_safe (Qpng, Qinfo, "Couldn't get background color!"); 997 warn_when_safe (Qpng, Qinfo, "Couldn't get background color!");
990 } 998 }
991 else 999 else
992 { 1000 {
993 Lisp_Color_Instance *c; 1001 Lisp_Color_Instance *c = XCOLOR_INSTANCE (bkgd);
994 Lisp_Object rgblist; 1002 Lisp_Object rgb = MAYBE_LISP_DEVMETH (XDEVICE (c->device),
995 1003 color_instance_rgb_components,
996 c = XCOLOR_INSTANCE (bkgd); 1004 (c));
997 rgblist = MAYBE_LISP_DEVMETH (XDEVICE (c->device), 1005 #define GETCOLOR(col) my_background.col = (unsigned short) XINT (XCAR (rgb))
998 color_instance_rgb_components, 1006 GETCOLOR(red); rgb = XCDR (rgb);
999 (c)); 1007 GETCOLOR(green); rgb = XCDR (rgb);
1000 my_background.red = (unsigned short) XINT (XCAR (rgblist)); 1008 GETCOLOR(blue);
1001 my_background.green = (unsigned short) XINT (XCAR (XCDR (rgblist))); 1009 #undef GETCOLOR
1002 my_background.blue = (unsigned short) XINT (XCAR (XCDR (XCDR (rgblist))));
1003 } 1010 }
1004 1011
1005 if (png_get_bKGD (png_ptr, info_ptr, &image_background)) 1012 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
1006 png_set_background (png_ptr, image_background, 1013 png_set_background (png_ptr, image_background,
1007 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); 1014 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
1010 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); 1017 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
1011 } 1018 }
1012 1019
1013 /* Now that we're using EImage, ask for 8bit RGB triples for any type 1020 /* Now that we're using EImage, ask for 8bit RGB triples for any type
1014 of image*/ 1021 of image*/
1015 /* convert palette images to full RGB */ 1022 /* convert palette images to RGB */
1016 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 1023 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1017 png_set_expand (png_ptr); 1024 png_set_palette_to_rgb (png_ptr);
1018 /* send grayscale images to RGB too */ 1025 /* convert grayscale images to RGB */
1019 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || 1026 else if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
1020 info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 1027 info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1021 png_set_gray_to_rgb (png_ptr); 1028 png_set_gray_to_rgb (png_ptr);
1022 /* we can't handle alpha values */ 1029 /* pad images with depth < 8 bits */
1023 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) 1030 else if (info_ptr->bit_depth < 8)
1024 png_set_strip_alpha (png_ptr);
1025 /* tell libpng to strip 16 bit depth files down to 8 bits */
1026 if (info_ptr->bit_depth == 16)
1027 png_set_strip_16 (png_ptr);
1028 /* if the image is < 8 bits, pad it out */
1029 if (info_ptr->bit_depth < 8)
1030 { 1031 {
1031 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) 1032 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)
1032 png_set_expand (png_ptr); 1033 png_set_expand (png_ptr);
1033 else 1034 else
1034 png_set_packing (png_ptr); 1035 png_set_packing (png_ptr);
1035 } 1036 }
1037 /* strip 16-bit depth files down to 8 bits */
1038 if (info_ptr->bit_depth == 16)
1039 png_set_strip_16 (png_ptr);
1040 /* strip alpha channel
1041 #### shouldn't we handle this?
1042 first call png_read_update_info in case above transformations
1043 have generated an alpha channel */
1044 png_read_update_info(png_ptr, info_ptr);
1045 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1046 png_set_strip_alpha (png_ptr);
1036 1047
1037 png_read_image (png_ptr, row_pointers); 1048 png_read_image (png_ptr, row_pointers);
1038 png_read_end (png_ptr, info_ptr); 1049 png_read_end (png_ptr, info_ptr);
1039 1050
1040 #if 1 /* def PNG_SHOW_COMMENTS */ 1051 /* #### There should be some way to pass this type of data down
1041 /* #### 1052 * into the glyph code, where you can get to it from lisp
1042 * I turn this off by default now, because the !%^@#!% comments 1053 * anyway. - WMP */
1043 * show up every time the image is instantiated, which can get
1044 * really really annoying. There should be some way to pass this
1045 * type of data down into the glyph code, where you can get to it
1046 * from lisp anyway. - WMP
1047 */
1048 /* #### I've turned this on, since these warnings are now
1049 unobtrusive. */
1050 { 1054 {
1051 int i; 1055 int i;
1052 DECLARE_EISTRING (key); 1056 DECLARE_EISTRING (key);
1053 DECLARE_EISTRING (text); 1057 DECLARE_EISTRING (text);
1054 1058
1064 1068
1065 warn_when_safe (Qpng, Qinfo, "%s - %s", 1069 warn_when_safe (Qpng, Qinfo, "%s - %s",
1066 eidata(key), eidata(text)); 1070 eidata(key), eidata(text));
1067 } 1071 }
1068 } 1072 }
1069 #endif
1070 1073
1071 xfree (row_pointers, Binbyte **); 1074 xfree (row_pointers, Binbyte **);
1072 } 1075 }
1073 1076
1074 /* now instantiate */ 1077 /* now instantiate */