Mercurial > hg > xemacs-beta
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 */ |