diff options
| author | William M. Perry | 1999-12-31 15:47:49 +0000 |
|---|---|---|
| committer | William M. Perry | 1999-12-31 15:47:49 +0000 |
| commit | 63448a4dc2fbe334435eeef39fa03e3b350a866a (patch) | |
| tree | d53faca06956fc5e80299e2f76504e073e0bcca8 | |
| parent | c880678e3e327af3cd1d4230843a84bbe6303964 (diff) | |
| download | emacs-63448a4dc2fbe334435eeef39fa03e3b350a866a.tar.gz emacs-63448a4dc2fbe334435eeef39fa03e3b350a866a.zip | |
Changes to xfns.c to support reading images from a memory buffer instead of forcing them to be on disk. GIF/JPEG/PNG/TIFF currently support this.
| -rw-r--r-- | src/ChangeLog | 37 | ||||
| -rw-r--r-- | src/xfns.c | 493 |
2 files changed, 388 insertions, 142 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 079be7210c9..8992497582b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,18 +1,37 @@ | |||
| 1 | 1999-12-31 William M. Perry <wmperry@aventail.com> | ||
| 2 | |||
| 3 | * xfns.c (jpeg_format): Added the :data keyword | ||
| 4 | (jpeg_image_p): JPEG is valid with :file _or_ :data | ||
| 5 | (jpeg_memory_src): Defined new JPEG image source to read from a | ||
| 6 | memory buffer. | ||
| 7 | (jpeg_load): Pay attention to the :data keyword if specified. | ||
| 8 | Instantiates a jpeg_memory_src instead of jpeg_stdio_src if | ||
| 9 | found. | ||
| 10 | (png_format): Added the :data keyword | ||
| 11 | (png_image_p): PNG is valid with :file _or_ :data | ||
| 12 | (png_read_from_memory): New PNG read function to read from a | ||
| 13 | memory buffer. | ||
| 14 | (png_load): Pay attention to the :data keyword if specified. Uses | ||
| 15 | png_set_read_fn() instead of png_init_io() if specified. | ||
| 16 | (tiff_format): Added the :data keyword for TIFF images. | ||
| 17 | (tiff_image_p): TIFF is valid with :file _or_ :data | ||
| 18 | (tiff_read_from_memory): Defined new TIFF I/O functions to read | ||
| 19 | from a memory buffer. | ||
| 20 | (tiff_load): Pay attention to the :data keyword if specified. | ||
| 21 | Uses TIFFClientOpen() instead of TIFFOpen() if specified. | ||
| 22 | (gif_format): Added the :data keyword | ||
| 23 | (gif_image_p): GIF is valid with :file _or_ :data | ||
| 24 | (gif_read_from_memory): New GIF input function to read from a | ||
| 25 | memory buffer. | ||
| 26 | (gif_load): Pay attention tot he :data keyword. Uses DGifOpen() | ||
| 27 | instead of DGifOpenFileName() if specified. | ||
| 28 | |||
| 1 | 1999-12-31 Gerd Moellmann <gerd@gnu.org> | 29 | 1999-12-31 Gerd Moellmann <gerd@gnu.org> |
| 2 | 30 | ||
| 3 | * xdisp.c (next_element_from_buffer): Change assertion at the end | 31 | * xdisp.c (next_element_from_buffer): Change assertion at the end |
| 4 | because it doesn't hold when there's an overlay string at the end | 32 | because it doesn't hold when there's an overlay string at the end |
| 5 | from which we deliver an image. | 33 | from which we deliver an image. |
| 6 | 34 | ||
| 7 | 1999-12-31 William M. Perry <wmperry@gnu.org> | ||
| 8 | |||
| 9 | * xfns.c (enum jpeg_keyword_index): Add JPEG_DATA. | ||
| 10 | (jpeg_format): Add :data. | ||
| 11 | (jpeg_image_p): Handle :data. | ||
| 12 | (our_fill_input_buffer, our_skip_input_data, our_term_source) | ||
| 13 | (jpeg_memory_src): New functions. | ||
| 14 | (jpeg_load): Read image from string data. | ||
| 15 | |||
| 16 | 1999-12-30 Eli Zaretskii <eliz@is.elta.co.il> | 35 | 1999-12-30 Eli Zaretskii <eliz@is.elta.co.il> |
| 17 | 36 | ||
| 18 | * msdos.c (IT_update_begin): Don't dereference members of struct | 37 | * msdos.c (IT_update_begin): Don't dereference members of struct |
diff --git a/src/xfns.c b/src/xfns.c index 1752c13c7d3..f17455ef05a 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -19,6 +19,9 @@ along with GNU Emacs; see the file COPYING. If not, write to | |||
| 19 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 20 | Boston, MA 02111-1307, USA. */ | 20 | Boston, MA 02111-1307, USA. */ |
| 21 | 21 | ||
| 22 | /* Ability to read images from memory instead of a file added by | ||
| 23 | William Perry <wmperry@gnu.org> */ | ||
| 24 | |||
| 22 | /* Image support (XBM, XPM, PBM, JPEG, TIFF, GIF, PNG, GS). tooltips, | 25 | /* Image support (XBM, XPM, PBM, JPEG, TIFF, GIF, PNG, GS). tooltips, |
| 23 | tool-bars, busy-cursor, file selection dialog added by Gerd | 26 | tool-bars, busy-cursor, file selection dialog added by Gerd |
| 24 | Moellmann <gerd@gnu.org>. */ | 27 | Moellmann <gerd@gnu.org>. */ |
| @@ -7922,6 +7925,7 @@ Lisp_Object Qpng; | |||
| 7922 | enum png_keyword_index | 7925 | enum png_keyword_index |
| 7923 | { | 7926 | { |
| 7924 | PNG_TYPE, | 7927 | PNG_TYPE, |
| 7928 | PNG_DATA, | ||
| 7925 | PNG_FILE, | 7929 | PNG_FILE, |
| 7926 | PNG_ASCENT, | 7930 | PNG_ASCENT, |
| 7927 | PNG_MARGIN, | 7931 | PNG_MARGIN, |
| @@ -7937,7 +7941,8 @@ enum png_keyword_index | |||
| 7937 | static struct image_keyword png_format[PNG_LAST] = | 7941 | static struct image_keyword png_format[PNG_LAST] = |
| 7938 | { | 7942 | { |
| 7939 | {":type", IMAGE_SYMBOL_VALUE, 1}, | 7943 | {":type", IMAGE_SYMBOL_VALUE, 1}, |
| 7940 | {":file", IMAGE_STRING_VALUE, 1}, | 7944 | {":data", IMAGE_STRING_VALUE, 0}, |
| 7945 | {":file", IMAGE_STRING_VALUE, 0}, | ||
| 7941 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | 7946 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, |
| 7942 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | 7947 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, |
| 7943 | {":relief", IMAGE_INTEGER_VALUE, 0}, | 7948 | {":relief", IMAGE_INTEGER_VALUE, 0}, |
| @@ -7970,6 +7975,13 @@ png_image_p (object) | |||
| 7970 | || (fmt[PNG_ASCENT].count | 7975 | || (fmt[PNG_ASCENT].count |
| 7971 | && XFASTINT (fmt[PNG_ASCENT].value) > 100)) | 7976 | && XFASTINT (fmt[PNG_ASCENT].value) > 100)) |
| 7972 | return 0; | 7977 | return 0; |
| 7978 | |||
| 7979 | /* Must specify either the :data or :file keyword. This should | ||
| 7980 | ** probably be moved up into parse_image_spec, since it seems to be | ||
| 7981 | ** a general requirement. | ||
| 7982 | */ | ||
| 7983 | if (!fmt[PNG_FILE].count && !fmt[PNG_DATA].count) | ||
| 7984 | return 0; | ||
| 7973 | return 1; | 7985 | return 1; |
| 7974 | } | 7986 | } |
| 7975 | 7987 | ||
| @@ -7997,6 +8009,28 @@ my_png_warning (png_ptr, msg) | |||
| 7997 | image_error ("PNG warning: %s", build_string (msg), Qnil); | 8009 | image_error ("PNG warning: %s", build_string (msg), Qnil); |
| 7998 | } | 8010 | } |
| 7999 | 8011 | ||
| 8012 | /* Memory source for PNG decoding. Originally written for XEmacs by | ||
| 8013 | William Perry <wmperry@gnu.org>, who has paperwork on file, and so | ||
| 8014 | it is safe to use. */ | ||
| 8015 | struct png_memory_storage | ||
| 8016 | { | ||
| 8017 | unsigned char *bytes; /* The data */ | ||
| 8018 | size_t len; /* How big is it? */ | ||
| 8019 | int index; /* Where are we? */ | ||
| 8020 | }; | ||
| 8021 | |||
| 8022 | static void | ||
| 8023 | png_read_from_memory(png_structp png_ptr, png_bytep data, | ||
| 8024 | png_size_t length) | ||
| 8025 | { | ||
| 8026 | struct png_memory_storage *tbr = | ||
| 8027 | (struct png_memory_storage *) png_get_io_ptr (png_ptr); | ||
| 8028 | |||
| 8029 | if (length > (tbr->len - tbr->index)) | ||
| 8030 | png_error (png_ptr, (png_const_charp) "Read Error"); | ||
| 8031 | memcpy (data,tbr->bytes + tbr->index,length); | ||
| 8032 | tbr->index = tbr->index + length; | ||
| 8033 | } | ||
| 8000 | 8034 | ||
| 8001 | /* Load PNG image IMG for use on frame F. Value is non-zero if | 8035 | /* Load PNG image IMG for use on frame F. Value is non-zero if |
| 8002 | successful. */ | 8036 | successful. */ |
| @@ -8007,12 +8041,13 @@ png_load (f, img) | |||
| 8007 | struct image *img; | 8041 | struct image *img; |
| 8008 | { | 8042 | { |
| 8009 | Lisp_Object file, specified_file; | 8043 | Lisp_Object file, specified_file; |
| 8044 | Lisp_Object specified_data; | ||
| 8010 | int x, y, i; | 8045 | int x, y, i; |
| 8011 | XImage *ximg, *mask_img = NULL; | 8046 | XImage *ximg, *mask_img = NULL; |
| 8012 | struct gcpro gcpro1; | 8047 | struct gcpro gcpro1; |
| 8013 | png_struct *png_ptr = NULL; | 8048 | png_struct *png_ptr = NULL; |
| 8014 | png_info *info_ptr = NULL, *end_info = NULL; | 8049 | png_info *info_ptr = NULL, *end_info = NULL; |
| 8015 | FILE *fp; | 8050 | FILE *fp = NULL; |
| 8016 | png_byte sig[8]; | 8051 | png_byte sig[8]; |
| 8017 | png_byte *pixels = NULL; | 8052 | png_byte *pixels = NULL; |
| 8018 | png_byte **rows = NULL; | 8053 | png_byte **rows = NULL; |
| @@ -8024,44 +8059,69 @@ png_load (f, img) | |||
| 8024 | char *gamma_str; | 8059 | char *gamma_str; |
| 8025 | double screen_gamma, image_gamma; | 8060 | double screen_gamma, image_gamma; |
| 8026 | int intent; | 8061 | int intent; |
| 8062 | struct png_memory_storage tbr; /* Data to be read */ | ||
| 8027 | 8063 | ||
| 8028 | /* Find out what file to load. */ | 8064 | /* Find out what file to load. */ |
| 8029 | specified_file = image_spec_value (img->spec, QCfile, NULL); | 8065 | specified_file = image_spec_value (img->spec, QCfile, NULL); |
| 8030 | file = x_find_image_file (specified_file); | 8066 | specified_data = image_spec_value (img->spec, QCdata, NULL); |
| 8031 | GCPRO1 (file); | ||
| 8032 | if (!STRINGP (file)) | ||
| 8033 | { | ||
| 8034 | image_error ("Cannot find image file %s", specified_file, Qnil); | ||
| 8035 | UNGCPRO; | ||
| 8036 | return 0; | ||
| 8037 | } | ||
| 8038 | 8067 | ||
| 8039 | /* Open the image file. */ | 8068 | if (NILP (specified_data)) |
| 8040 | fp = fopen (XSTRING (file)->data, "rb"); | 8069 | { |
| 8041 | if (!fp) | 8070 | file = x_find_image_file (specified_file); |
| 8042 | { | 8071 | GCPRO1 (file); |
| 8043 | image_error ("Cannot open image file %s", file, Qnil); | 8072 | if (!STRINGP (file)) |
| 8044 | UNGCPRO; | 8073 | { |
| 8045 | fclose (fp); | 8074 | image_error ("Cannot find image file %s", specified_file, Qnil); |
| 8046 | return 0; | 8075 | UNGCPRO; |
| 8047 | } | 8076 | return 0; |
| 8077 | } | ||
| 8048 | 8078 | ||
| 8049 | /* Check PNG signature. */ | 8079 | /* Open the image file. */ |
| 8050 | if (fread (sig, 1, sizeof sig, fp) != sizeof sig | 8080 | fp = fopen (XSTRING (file)->data, "rb"); |
| 8051 | || !png_check_sig (sig, sizeof sig)) | 8081 | if (!fp) |
| 8052 | { | 8082 | { |
| 8053 | image_error ("Not a PNG file: %s", file, Qnil); | 8083 | image_error ("Cannot open image file %s", file, Qnil); |
| 8054 | UNGCPRO; | 8084 | UNGCPRO; |
| 8055 | fclose (fp); | 8085 | fclose (fp); |
| 8056 | return 0; | 8086 | return 0; |
| 8057 | } | 8087 | } |
| 8088 | |||
| 8089 | /* Check PNG signature. */ | ||
| 8090 | if (fread (sig, 1, sizeof sig, fp) != sizeof sig | ||
| 8091 | || !png_check_sig (sig, sizeof sig)) | ||
| 8092 | { | ||
| 8093 | image_error ("Not a PNG file: %s", file, Qnil); | ||
| 8094 | UNGCPRO; | ||
| 8095 | fclose (fp); | ||
| 8096 | return 0; | ||
| 8097 | } | ||
| 8098 | } | ||
| 8099 | else | ||
| 8100 | { | ||
| 8101 | /* Read from memory */ | ||
| 8102 | tbr.bytes = XSTRING (specified_data)->data; | ||
| 8103 | tbr.len = STRING_BYTES (XSTRING (specified_data)); | ||
| 8104 | tbr.index = 0; | ||
| 8105 | |||
| 8106 | /* Chekc PNG signature */ | ||
| 8107 | if ((tbr.len < sizeof(sig)) || | ||
| 8108 | !png_check_sig (tbr.bytes, sizeof(sig))) | ||
| 8109 | { | ||
| 8110 | image_error ("Not a PNG file: %s", file, Qnil); | ||
| 8111 | UNGCPRO; | ||
| 8112 | return 0; | ||
| 8113 | } | ||
| 8114 | |||
| 8115 | /* Need to skip past the signature */ | ||
| 8116 | tbr.bytes += sizeof(sig); | ||
| 8117 | } | ||
| 8058 | 8118 | ||
| 8059 | /* Initialize read and info structs for PNG lib. */ | 8119 | /* Initialize read and info structs for PNG lib. */ |
| 8060 | png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, | 8120 | png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, |
| 8061 | my_png_error, my_png_warning); | 8121 | my_png_error, my_png_warning); |
| 8062 | if (!png_ptr) | 8122 | if (!png_ptr) |
| 8063 | { | 8123 | { |
| 8064 | fclose (fp); | 8124 | if (fp) fclose (fp); |
| 8065 | UNGCPRO; | 8125 | UNGCPRO; |
| 8066 | return 0; | 8126 | return 0; |
| 8067 | } | 8127 | } |
| @@ -8070,7 +8130,7 @@ png_load (f, img) | |||
| 8070 | if (!info_ptr) | 8130 | if (!info_ptr) |
| 8071 | { | 8131 | { |
| 8072 | png_destroy_read_struct (&png_ptr, NULL, NULL); | 8132 | png_destroy_read_struct (&png_ptr, NULL, NULL); |
| 8073 | fclose (fp); | 8133 | if (fp) fclose (fp); |
| 8074 | UNGCPRO; | 8134 | UNGCPRO; |
| 8075 | return 0; | 8135 | return 0; |
| 8076 | } | 8136 | } |
| @@ -8079,7 +8139,7 @@ png_load (f, img) | |||
| 8079 | if (!end_info) | 8139 | if (!end_info) |
| 8080 | { | 8140 | { |
| 8081 | png_destroy_read_struct (&png_ptr, &info_ptr, NULL); | 8141 | png_destroy_read_struct (&png_ptr, &info_ptr, NULL); |
| 8082 | fclose (fp); | 8142 | if (fp) fclose (fp); |
| 8083 | UNGCPRO; | 8143 | UNGCPRO; |
| 8084 | return 0; | 8144 | return 0; |
| 8085 | } | 8145 | } |
| @@ -8093,14 +8153,17 @@ png_load (f, img) | |||
| 8093 | png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); | 8153 | png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); |
| 8094 | xfree (pixels); | 8154 | xfree (pixels); |
| 8095 | xfree (rows); | 8155 | xfree (rows); |
| 8096 | if (fp) | 8156 | if (fp) fclose (fp); |
| 8097 | fclose (fp); | ||
| 8098 | UNGCPRO; | 8157 | UNGCPRO; |
| 8099 | return 0; | 8158 | return 0; |
| 8100 | } | 8159 | } |
| 8101 | 8160 | ||
| 8102 | /* Read image info. */ | 8161 | /* Read image info. */ |
| 8103 | png_init_io (png_ptr, fp); | 8162 | if (!NILP (specified_data)) |
| 8163 | png_set_read_fn (png_ptr,(void *) &tbr, png_read_from_memory); | ||
| 8164 | else | ||
| 8165 | png_init_io (png_ptr, fp); | ||
| 8166 | |||
| 8104 | png_set_sig_bytes (png_ptr, sizeof sig); | 8167 | png_set_sig_bytes (png_ptr, sizeof sig); |
| 8105 | png_read_info (png_ptr, info_ptr); | 8168 | png_read_info (png_ptr, info_ptr); |
| 8106 | png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, | 8169 | png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, |
| @@ -8209,7 +8272,7 @@ png_load (f, img) | |||
| 8209 | /* Read the entire image. */ | 8272 | /* Read the entire image. */ |
| 8210 | png_read_image (png_ptr, rows); | 8273 | png_read_image (png_ptr, rows); |
| 8211 | png_read_end (png_ptr, info_ptr); | 8274 | png_read_end (png_ptr, info_ptr); |
| 8212 | fclose (fp); | 8275 | if (fp) fclose (fp); |
| 8213 | fp = NULL; | 8276 | fp = NULL; |
| 8214 | 8277 | ||
| 8215 | BLOCK_INPUT; | 8278 | BLOCK_INPUT; |
| @@ -8391,7 +8454,7 @@ jpeg_image_p (object) | |||
| 8391 | 8454 | ||
| 8392 | if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg) | 8455 | if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg) |
| 8393 | || (fmt[JPEG_ASCENT].count | 8456 | || (fmt[JPEG_ASCENT].count |
| 8394 | && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) | 8457 | && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) |
| 8395 | return 0; | 8458 | return 0; |
| 8396 | 8459 | ||
| 8397 | /* Must specify either the :data or :file keyword. This should | 8460 | /* Must specify either the :data or :file keyword. This should |
| @@ -8415,7 +8478,6 @@ my_error_exit (cinfo) | |||
| 8415 | longjmp (mgr->setjmp_buffer, 1); | 8478 | longjmp (mgr->setjmp_buffer, 1); |
| 8416 | } | 8479 | } |
| 8417 | 8480 | ||
| 8418 | |||
| 8419 | /* Init source method for JPEG data source manager. Called by | 8481 | /* Init source method for JPEG data source manager. Called by |
| 8420 | jpeg_read_header() before any data is actually read. See | 8482 | jpeg_read_header() before any data is actually read. See |
| 8421 | libjpeg.doc from the JPEG lib distribution. */ | 8483 | libjpeg.doc from the JPEG lib distribution. */ |
| @@ -8514,7 +8576,6 @@ jpeg_memory_src (cinfo, data, len) | |||
| 8514 | src->next_input_byte = data; | 8576 | src->next_input_byte = data; |
| 8515 | } | 8577 | } |
| 8516 | 8578 | ||
| 8517 | |||
| 8518 | /* Load image IMG for use on frame F. Patterned after example.c | 8579 | /* Load image IMG for use on frame F. Patterned after example.c |
| 8519 | from the JPEG lib. */ | 8580 | from the JPEG lib. */ |
| 8520 | 8581 | ||
| @@ -8562,41 +8623,41 @@ jpeg_load (f, img) | |||
| 8562 | } | 8623 | } |
| 8563 | 8624 | ||
| 8564 | /* Customize libjpeg's error handling to call my_error_exit | 8625 | /* Customize libjpeg's error handling to call my_error_exit |
| 8565 | when an error is detected. This function will perform | 8626 | when an error is detected. This function will perform |
| 8566 | a longjmp. */ | 8627 | a longjmp. */ |
| 8567 | mgr.pub.error_exit = my_error_exit; | 8628 | mgr.pub.error_exit = my_error_exit; |
| 8568 | cinfo.err = jpeg_std_error (&mgr.pub); | 8629 | cinfo.err = jpeg_std_error (&mgr.pub); |
| 8569 | 8630 | ||
| 8570 | if ((rc = setjmp (mgr.setjmp_buffer)) != 0) | 8631 | if ((rc = setjmp (mgr.setjmp_buffer)) != 0) |
| 8571 | { | 8632 | { |
| 8572 | if (rc == 1) | 8633 | if (rc == 1) |
| 8573 | { | 8634 | { |
| 8574 | /* Called from my_error_exit. Display a JPEG error. */ | 8635 | /* Called from my_error_exit. Display a JPEG error. */ |
| 8575 | char buffer[JMSG_LENGTH_MAX]; | 8636 | char buffer[JMSG_LENGTH_MAX]; |
| 8576 | cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); | 8637 | cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); |
| 8577 | image_error ("Error reading JPEG file `%s': %s", file, | 8638 | image_error ("Error reading JPEG file `%s': %s", file, |
| 8578 | build_string (buffer)); | 8639 | build_string (buffer)); |
| 8579 | } | 8640 | } |
| 8580 | 8641 | ||
| 8581 | /* Close the input file and destroy the JPEG object. */ | 8642 | /* Close the input file and destroy the JPEG object. */ |
| 8582 | if (fp) fclose (fp); | 8643 | if (fp) fclose (fp); |
| 8583 | jpeg_destroy_decompress (&cinfo); | 8644 | jpeg_destroy_decompress (&cinfo); |
| 8584 | 8645 | ||
| 8585 | BLOCK_INPUT; | 8646 | BLOCK_INPUT; |
| 8586 | 8647 | ||
| 8587 | /* If we already have an XImage, free that. */ | 8648 | /* If we already have an XImage, free that. */ |
| 8588 | x_destroy_x_image (ximg); | 8649 | x_destroy_x_image (ximg); |
| 8589 | 8650 | ||
| 8590 | /* Free pixmap and colors. */ | 8651 | /* Free pixmap and colors. */ |
| 8591 | x_clear_image (f, img); | 8652 | x_clear_image (f, img); |
| 8592 | 8653 | ||
| 8593 | UNBLOCK_INPUT; | 8654 | UNBLOCK_INPUT; |
| 8594 | UNGCPRO; | 8655 | UNGCPRO; |
| 8595 | return 0; | 8656 | return 0; |
| 8596 | } | 8657 | } |
| 8597 | 8658 | ||
| 8598 | /* Create the JPEG decompression object. Let it read from fp. | 8659 | /* Create the JPEG decompression object. Let it read from fp. |
| 8599 | Read the JPEG image header. */ | 8660 | Read the JPEG image header. */ |
| 8600 | jpeg_create_decompress (&cinfo); | 8661 | jpeg_create_decompress (&cinfo); |
| 8601 | 8662 | ||
| 8602 | if (NILP (specified_data)) | 8663 | if (NILP (specified_data)) |
| @@ -8604,11 +8665,11 @@ jpeg_load (f, img) | |||
| 8604 | else | 8665 | else |
| 8605 | jpeg_memory_src (&cinfo, XSTRING (specified_data)->data, | 8666 | jpeg_memory_src (&cinfo, XSTRING (specified_data)->data, |
| 8606 | STRING_BYTES (XSTRING (specified_data))); | 8667 | STRING_BYTES (XSTRING (specified_data))); |
| 8607 | 8668 | ||
| 8608 | jpeg_read_header (&cinfo, TRUE); | 8669 | jpeg_read_header (&cinfo, TRUE); |
| 8609 | 8670 | ||
| 8610 | /* Customize decompression so that color quantization will be used. | 8671 | /* Customize decompression so that color quantization will be used. |
| 8611 | Start decompression. */ | 8672 | Start decompression. */ |
| 8612 | cinfo.quantize_colors = TRUE; | 8673 | cinfo.quantize_colors = TRUE; |
| 8613 | jpeg_start_decompress (&cinfo); | 8674 | jpeg_start_decompress (&cinfo); |
| 8614 | width = img->width = cinfo.output_width; | 8675 | width = img->width = cinfo.output_width; |
| @@ -8618,59 +8679,59 @@ jpeg_load (f, img) | |||
| 8618 | 8679 | ||
| 8619 | /* Create X image and pixmap. */ | 8680 | /* Create X image and pixmap. */ |
| 8620 | if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, | 8681 | if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, |
| 8621 | &img->pixmap)) | 8682 | &img->pixmap)) |
| 8622 | { | 8683 | { |
| 8623 | UNBLOCK_INPUT; | 8684 | UNBLOCK_INPUT; |
| 8624 | longjmp (mgr.setjmp_buffer, 2); | 8685 | longjmp (mgr.setjmp_buffer, 2); |
| 8625 | } | 8686 | } |
| 8626 | 8687 | ||
| 8627 | /* Allocate colors. When color quantization is used, | 8688 | /* Allocate colors. When color quantization is used, |
| 8628 | cinfo.actual_number_of_colors has been set with the number of | 8689 | cinfo.actual_number_of_colors has been set with the number of |
| 8629 | colors generated, and cinfo.colormap is a two-dimensional array | 8690 | colors generated, and cinfo.colormap is a two-dimensional array |
| 8630 | of color indices in the range 0..cinfo.actual_number_of_colors. | 8691 | of color indices in the range 0..cinfo.actual_number_of_colors. |
| 8631 | No more than 255 colors will be generated. */ | 8692 | No more than 255 colors will be generated. */ |
| 8632 | { | 8693 | { |
| 8633 | int i, ir, ig, ib; | 8694 | int i, ir, ig, ib; |
| 8634 | 8695 | ||
| 8635 | if (cinfo.out_color_components > 2) | 8696 | if (cinfo.out_color_components > 2) |
| 8636 | ir = 0, ig = 1, ib = 2; | 8697 | ir = 0, ig = 1, ib = 2; |
| 8637 | else if (cinfo.out_color_components > 1) | 8698 | else if (cinfo.out_color_components > 1) |
| 8638 | ir = 0, ig = 1, ib = 0; | 8699 | ir = 0, ig = 1, ib = 0; |
| 8639 | else | 8700 | else |
| 8640 | ir = 0, ig = 0, ib = 0; | 8701 | ir = 0, ig = 0, ib = 0; |
| 8641 | 8702 | ||
| 8642 | /* Use the color table mechanism because it handles colors that | 8703 | /* Use the color table mechanism because it handles colors that |
| 8643 | cannot be allocated nicely. Such colors will be replaced with | 8704 | cannot be allocated nicely. Such colors will be replaced with |
| 8644 | a default color, and we don't have to care about which colors | 8705 | a default color, and we don't have to care about which colors |
| 8645 | can be freed safely, and which can't. */ | 8706 | can be freed safely, and which can't. */ |
| 8646 | init_color_table (); | 8707 | init_color_table (); |
| 8647 | colors = (unsigned long *) alloca (cinfo.actual_number_of_colors | 8708 | colors = (unsigned long *) alloca (cinfo.actual_number_of_colors |
| 8648 | * sizeof *colors); | 8709 | * sizeof *colors); |
| 8649 | 8710 | ||
| 8650 | for (i = 0; i < cinfo.actual_number_of_colors; ++i) | 8711 | for (i = 0; i < cinfo.actual_number_of_colors; ++i) |
| 8651 | { | 8712 | { |
| 8652 | /* Multiply RGB values with 255 because X expects RGB values | 8713 | /* Multiply RGB values with 255 because X expects RGB values |
| 8653 | in the range 0..0xffff. */ | 8714 | in the range 0..0xffff. */ |
| 8654 | int r = cinfo.colormap[ir][i] << 8; | 8715 | int r = cinfo.colormap[ir][i] << 8; |
| 8655 | int g = cinfo.colormap[ig][i] << 8; | 8716 | int g = cinfo.colormap[ig][i] << 8; |
| 8656 | int b = cinfo.colormap[ib][i] << 8; | 8717 | int b = cinfo.colormap[ib][i] << 8; |
| 8657 | colors[i] = lookup_rgb_color (f, r, g, b); | 8718 | colors[i] = lookup_rgb_color (f, r, g, b); |
| 8658 | } | 8719 | } |
| 8659 | 8720 | ||
| 8660 | /* Remember those colors actually allocated. */ | 8721 | /* Remember those colors actually allocated. */ |
| 8661 | img->colors = colors_in_color_table (&img->ncolors); | 8722 | img->colors = colors_in_color_table (&img->ncolors); |
| 8662 | free_color_table (); | 8723 | free_color_table (); |
| 8663 | } | 8724 | } |
| 8664 | 8725 | ||
| 8665 | /* Read pixels. */ | 8726 | /* Read pixels. */ |
| 8666 | row_stride = width * cinfo.output_components; | 8727 | row_stride = width * cinfo.output_components; |
| 8667 | buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, | 8728 | buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, |
| 8668 | row_stride, 1); | 8729 | row_stride, 1); |
| 8669 | for (y = 0; y < height; ++y) | 8730 | for (y = 0; y < height; ++y) |
| 8670 | { | 8731 | { |
| 8671 | jpeg_read_scanlines (&cinfo, buffer, 1); | 8732 | jpeg_read_scanlines (&cinfo, buffer, 1); |
| 8672 | for (x = 0; x < cinfo.output_width; ++x) | 8733 | for (x = 0; x < cinfo.output_width; ++x) |
| 8673 | XPutPixel (ximg, x, y, colors[buffer[0][x]]); | 8734 | XPutPixel (ximg, x, y, colors[buffer[0][x]]); |
| 8674 | } | 8735 | } |
| 8675 | 8736 | ||
| 8676 | /* Clean up. */ | 8737 | /* Clean up. */ |
| @@ -8710,6 +8771,7 @@ Lisp_Object Qtiff; | |||
| 8710 | enum tiff_keyword_index | 8771 | enum tiff_keyword_index |
| 8711 | { | 8772 | { |
| 8712 | TIFF_TYPE, | 8773 | TIFF_TYPE, |
| 8774 | TIFF_DATA, | ||
| 8713 | TIFF_FILE, | 8775 | TIFF_FILE, |
| 8714 | TIFF_ASCENT, | 8776 | TIFF_ASCENT, |
| 8715 | TIFF_MARGIN, | 8777 | TIFF_MARGIN, |
| @@ -8725,7 +8787,8 @@ enum tiff_keyword_index | |||
| 8725 | static struct image_keyword tiff_format[TIFF_LAST] = | 8787 | static struct image_keyword tiff_format[TIFF_LAST] = |
| 8726 | { | 8788 | { |
| 8727 | {":type", IMAGE_SYMBOL_VALUE, 1}, | 8789 | {":type", IMAGE_SYMBOL_VALUE, 1}, |
| 8728 | {":file", IMAGE_STRING_VALUE, 1}, | 8790 | {":data", IMAGE_STRING_VALUE, 0}, |
| 8791 | {":file", IMAGE_STRING_VALUE, 0}, | ||
| 8729 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | 8792 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, |
| 8730 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | 8793 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, |
| 8731 | {":relief", IMAGE_INTEGER_VALUE, 0}, | 8794 | {":relief", IMAGE_INTEGER_VALUE, 0}, |
| @@ -8758,9 +8821,92 @@ tiff_image_p (object) | |||
| 8758 | || (fmt[TIFF_ASCENT].count | 8821 | || (fmt[TIFF_ASCENT].count |
| 8759 | && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) | 8822 | && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) |
| 8760 | return 0; | 8823 | return 0; |
| 8824 | /* Must specify either the :data or :file keyword. This should | ||
| 8825 | ** probably be moved up into parse_image_spec, since it seems to be | ||
| 8826 | ** a general requirement. | ||
| 8827 | */ | ||
| 8828 | if (!fmt[TIFF_FILE].count && !fmt[TIFF_DATA].count) | ||
| 8829 | return 0; | ||
| 8761 | return 1; | 8830 | return 1; |
| 8762 | } | 8831 | } |
| 8763 | 8832 | ||
| 8833 | /* Reading from a memory buffer for TIFF images | ||
| 8834 | Based on the PNG memory source, but we have to provide a lot of | ||
| 8835 | extra functions. Blah. | ||
| 8836 | |||
| 8837 | We really only need to implement read and seek, but I am not | ||
| 8838 | convinced that the TIFF library is smart enough not to destroy | ||
| 8839 | itself if we only hand it the function pointers we need to | ||
| 8840 | override. */ | ||
| 8841 | typedef struct { | ||
| 8842 | unsigned char *bytes; | ||
| 8843 | size_t len; | ||
| 8844 | int index; | ||
| 8845 | } tiff_memory_source; | ||
| 8846 | |||
| 8847 | static size_t tiff_read_from_memory(thandle_t data, tdata_t buf, tsize_t size) | ||
| 8848 | { | ||
| 8849 | tiff_memory_source *src = (tiff_memory_source *)data; | ||
| 8850 | |||
| 8851 | if (size > src->len - src->index) | ||
| 8852 | return (size_t) -1; | ||
| 8853 | memcpy(buf, src->bytes + src->index, size); | ||
| 8854 | src->index += size; | ||
| 8855 | return size; | ||
| 8856 | } | ||
| 8857 | |||
| 8858 | static size_t tiff_write_from_memory(thandle_t data, tdata_t buf, tsize_t size) | ||
| 8859 | { | ||
| 8860 | return (size_t) -1; | ||
| 8861 | } | ||
| 8862 | |||
| 8863 | static toff_t tiff_seek_in_memory(thandle_t data, toff_t off, int whence) | ||
| 8864 | { | ||
| 8865 | tiff_memory_source *src = (tiff_memory_source *)data; | ||
| 8866 | int idx; | ||
| 8867 | |||
| 8868 | switch (whence) | ||
| 8869 | { | ||
| 8870 | case SEEK_SET: /* Go from beginning of source */ | ||
| 8871 | idx = off; | ||
| 8872 | break; | ||
| 8873 | case SEEK_END: /* Go from end of source */ | ||
| 8874 | idx = src->len + off; | ||
| 8875 | break; | ||
| 8876 | case SEEK_CUR: /* Go from current position */ | ||
| 8877 | idx = src->index + off; | ||
| 8878 | break; | ||
| 8879 | default: /* Invalid `whence' */ | ||
| 8880 | return(-1); | ||
| 8881 | } | ||
| 8882 | if ((idx > src->len) || (idx < 0)) | ||
| 8883 | return -1; | ||
| 8884 | src->index = idx; | ||
| 8885 | return src->index; | ||
| 8886 | } | ||
| 8887 | |||
| 8888 | static int tiff_close_memory(thandle_t data) | ||
| 8889 | { | ||
| 8890 | /* NOOP */ | ||
| 8891 | return(0); | ||
| 8892 | } | ||
| 8893 | |||
| 8894 | static int tiff_mmap_memory(thandle_t data, tdata_t *pbase, toff_t *psize) | ||
| 8895 | { | ||
| 8896 | /* It is already _IN_ memory. */ | ||
| 8897 | return(0); | ||
| 8898 | } | ||
| 8899 | |||
| 8900 | static void tiff_unmap_memory(thandle_t data, tdata_t base, toff_t size) | ||
| 8901 | { | ||
| 8902 | /* We don't need to do this. */ | ||
| 8903 | return; | ||
| 8904 | } | ||
| 8905 | |||
| 8906 | static toff_t tiff_size_of_memory(thandle_t data) | ||
| 8907 | { | ||
| 8908 | return(((tiff_memory_source *) data)->len); | ||
| 8909 | } | ||
| 8764 | 8910 | ||
| 8765 | /* Load TIFF image IMG for use on frame F. Value is non-zero if | 8911 | /* Load TIFF image IMG for use on frame F. Value is non-zero if |
| 8766 | successful. */ | 8912 | successful. */ |
| @@ -8771,31 +8917,62 @@ tiff_load (f, img) | |||
| 8771 | struct image *img; | 8917 | struct image *img; |
| 8772 | { | 8918 | { |
| 8773 | Lisp_Object file, specified_file; | 8919 | Lisp_Object file, specified_file; |
| 8920 | Lisp_Object specified_data; | ||
| 8774 | TIFF *tiff; | 8921 | TIFF *tiff; |
| 8775 | int width, height, x, y; | 8922 | int width, height, x, y; |
| 8776 | uint32 *buf; | 8923 | uint32 *buf; |
| 8777 | int rc; | 8924 | int rc; |
| 8778 | XImage *ximg; | 8925 | XImage *ximg; |
| 8779 | struct gcpro gcpro1; | 8926 | struct gcpro gcpro1; |
| 8927 | tiff_memory_source memsrc; | ||
| 8780 | 8928 | ||
| 8781 | specified_file = image_spec_value (img->spec, QCfile, NULL); | 8929 | specified_file = image_spec_value (img->spec, QCfile, NULL); |
| 8782 | file = x_find_image_file (specified_file); | 8930 | specified_data = image_spec_value (img->spec, QCdata, NULL); |
| 8783 | GCPRO1 (file); | 8931 | |
| 8784 | if (!STRINGP (file)) | 8932 | if (NILP (specified_data)) |
| 8785 | { | 8933 | { |
| 8786 | image_error ("Cannot find image file %s", file, Qnil); | 8934 | /* Read from a file */ |
| 8787 | UNGCPRO; | 8935 | file = x_find_image_file (specified_file); |
| 8788 | return 0; | 8936 | GCPRO1 (file); |
| 8789 | } | 8937 | if (!STRINGP (file)) |
| 8790 | 8938 | { | |
| 8791 | /* Try to open the image file. */ | 8939 | image_error ("Cannot find image file %s", file, Qnil); |
| 8792 | tiff = TIFFOpen (XSTRING (file)->data, "r"); | 8940 | UNGCPRO; |
| 8793 | if (tiff == NULL) | 8941 | return 0; |
| 8794 | { | 8942 | } |
| 8795 | image_error ("Cannot open `%s'", file, Qnil); | 8943 | |
| 8796 | UNGCPRO; | 8944 | /* Try to open the image file. */ |
| 8797 | return 0; | 8945 | tiff = TIFFOpen (XSTRING (file)->data, "r"); |
| 8798 | } | 8946 | if (tiff == NULL) |
| 8947 | { | ||
| 8948 | image_error ("Cannot open `%s'", file, Qnil); | ||
| 8949 | UNGCPRO; | ||
| 8950 | return 0; | ||
| 8951 | } | ||
| 8952 | } | ||
| 8953 | else | ||
| 8954 | { | ||
| 8955 | /* Memory source! */ | ||
| 8956 | memsrc.bytes = XSTRING (specified_data)->data; | ||
| 8957 | memsrc.len = STRING_BYTES (XSTRING (specified_data)); | ||
| 8958 | memsrc.index = 0; | ||
| 8959 | |||
| 8960 | tiff = TIFFClientOpen ("memory_source", "r", &memsrc, | ||
| 8961 | (TIFFReadWriteProc)tiff_read_from_memory, | ||
| 8962 | (TIFFReadWriteProc)tiff_write_from_memory, | ||
| 8963 | tiff_seek_in_memory, | ||
| 8964 | tiff_close_memory, | ||
| 8965 | tiff_size_of_memory, | ||
| 8966 | tiff_mmap_memory, | ||
| 8967 | tiff_unmap_memory); | ||
| 8968 | |||
| 8969 | if (!tiff) | ||
| 8970 | { | ||
| 8971 | image_error ("Cannot open memory source `%s'. ", specified_data, Qnil); | ||
| 8972 | UNGCPRO; | ||
| 8973 | return 0; | ||
| 8974 | } | ||
| 8975 | } | ||
| 8799 | 8976 | ||
| 8800 | /* Get width and height of the image, and allocate a raster buffer | 8977 | /* Get width and height of the image, and allocate a raster buffer |
| 8801 | of width x height 32-bit values. */ | 8978 | of width x height 32-bit values. */ |
| @@ -8884,6 +9061,7 @@ Lisp_Object Qgif; | |||
| 8884 | enum gif_keyword_index | 9061 | enum gif_keyword_index |
| 8885 | { | 9062 | { |
| 8886 | GIF_TYPE, | 9063 | GIF_TYPE, |
| 9064 | GIF_DATA, | ||
| 8887 | GIF_FILE, | 9065 | GIF_FILE, |
| 8888 | GIF_ASCENT, | 9066 | GIF_ASCENT, |
| 8889 | GIF_MARGIN, | 9067 | GIF_MARGIN, |
| @@ -8900,7 +9078,8 @@ enum gif_keyword_index | |||
| 8900 | static struct image_keyword gif_format[GIF_LAST] = | 9078 | static struct image_keyword gif_format[GIF_LAST] = |
| 8901 | { | 9079 | { |
| 8902 | {":type", IMAGE_SYMBOL_VALUE, 1}, | 9080 | {":type", IMAGE_SYMBOL_VALUE, 1}, |
| 8903 | {":file", IMAGE_STRING_VALUE, 1}, | 9081 | {":data", IMAGE_STRING_VALUE, 0}, |
| 9082 | {":file", IMAGE_STRING_VALUE, 0}, | ||
| 8904 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | 9083 | {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, |
| 8905 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | 9084 | {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, |
| 8906 | {":relief", IMAGE_INTEGER_VALUE, 0}, | 9085 | {":relief", IMAGE_INTEGER_VALUE, 0}, |
| @@ -8934,9 +9113,35 @@ gif_image_p (object) | |||
| 8934 | || (fmt[GIF_ASCENT].count | 9113 | || (fmt[GIF_ASCENT].count |
| 8935 | && XFASTINT (fmt[GIF_ASCENT].value) > 100)) | 9114 | && XFASTINT (fmt[GIF_ASCENT].value) > 100)) |
| 8936 | return 0; | 9115 | return 0; |
| 9116 | /* Must specify either the :data or :file keyword. This should | ||
| 9117 | ** probably be moved up into parse_image_spec, since it seems to be | ||
| 9118 | ** a general requirement. | ||
| 9119 | */ | ||
| 9120 | if (!fmt[GIF_FILE].count && !fmt[GIF_DATA].count) | ||
| 9121 | return 0; | ||
| 8937 | return 1; | 9122 | return 1; |
| 8938 | } | 9123 | } |
| 8939 | 9124 | ||
| 9125 | /* Reading a GIF image from memory | ||
| 9126 | Based on the PNG memory stuff to a certain extent. */ | ||
| 9127 | |||
| 9128 | typedef struct { | ||
| 9129 | unsigned char *bytes; | ||
| 9130 | size_t len; | ||
| 9131 | int index; | ||
| 9132 | } gif_memory_source; | ||
| 9133 | |||
| 9134 | static int gif_read_from_memory(GifFileType *file, GifByteType *buf, int len) | ||
| 9135 | { | ||
| 9136 | gif_memory_source *src = (gif_memory_source *) file->UserData; | ||
| 9137 | |||
| 9138 | if (len > (src->len - src->index)) | ||
| 9139 | return -1; | ||
| 9140 | |||
| 9141 | memcpy(buf, src->bytes + src->index, len); | ||
| 9142 | src->index += len; | ||
| 9143 | return len; | ||
| 9144 | } | ||
| 8940 | 9145 | ||
| 8941 | /* Load GIF image IMG for use on frame F. Value is non-zero if | 9146 | /* Load GIF image IMG for use on frame F. Value is non-zero if |
| 8942 | successful. */ | 9147 | successful. */ |
| @@ -8947,6 +9152,7 @@ gif_load (f, img) | |||
| 8947 | struct image *img; | 9152 | struct image *img; |
| 8948 | { | 9153 | { |
| 8949 | Lisp_Object file, specified_file; | 9154 | Lisp_Object file, specified_file; |
| 9155 | Lisp_Object specified_data; | ||
| 8950 | int rc, width, height, x, y, i; | 9156 | int rc, width, height, x, y, i; |
| 8951 | XImage *ximg; | 9157 | XImage *ximg; |
| 8952 | ColorMapObject *gif_color_map; | 9158 | ColorMapObject *gif_color_map; |
| @@ -8955,25 +9161,46 @@ gif_load (f, img) | |||
| 8955 | struct gcpro gcpro1; | 9161 | struct gcpro gcpro1; |
| 8956 | Lisp_Object image; | 9162 | Lisp_Object image; |
| 8957 | int ino, image_left, image_top, image_width, image_height; | 9163 | int ino, image_left, image_top, image_width, image_height; |
| 9164 | gif_memory_source memsrc; | ||
| 8958 | 9165 | ||
| 8959 | specified_file = image_spec_value (img->spec, QCfile, NULL); | 9166 | specified_file = image_spec_value (img->spec, QCfile, NULL); |
| 8960 | file = x_find_image_file (specified_file); | 9167 | specified_data = image_spec_value (img->spec, QCdata, NULL); |
| 8961 | GCPRO1 (file); | 9168 | |
| 8962 | if (!STRINGP (file)) | 9169 | if (NILP (specified_data)) |
| 8963 | { | 9170 | { |
| 8964 | image_error ("Cannot find image file %s", specified_file, Qnil); | 9171 | file = x_find_image_file (specified_file); |
| 8965 | UNGCPRO; | 9172 | GCPRO1 (file); |
| 8966 | return 0; | 9173 | if (!STRINGP (file)) |
| 8967 | } | 9174 | { |
| 9175 | image_error ("Cannot find image file %s", specified_file, Qnil); | ||
| 9176 | UNGCPRO; | ||
| 9177 | return 0; | ||
| 9178 | } | ||
| 8968 | 9179 | ||
| 8969 | /* Open the GIF file. */ | 9180 | /* Open the GIF file. */ |
| 8970 | gif = DGifOpenFileName (XSTRING (file)->data); | 9181 | gif = DGifOpenFileName (XSTRING (file)->data); |
| 8971 | if (gif == NULL) | 9182 | if (gif == NULL) |
| 8972 | { | 9183 | { |
| 8973 | image_error ("Cannot open `%s'", file, Qnil); | 9184 | image_error ("Cannot open `%s'", file, Qnil); |
| 8974 | UNGCPRO; | 9185 | UNGCPRO; |
| 8975 | return 0; | 9186 | return 0; |
| 8976 | } | 9187 | } |
| 9188 | } | ||
| 9189 | else | ||
| 9190 | { | ||
| 9191 | /* Read from memory! */ | ||
| 9192 | memsrc.bytes = XSTRING (specified_data)->data; | ||
| 9193 | memsrc.len = STRING_BYTES (XSTRING (specified_data)); | ||
| 9194 | memsrc.index = 0; | ||
| 9195 | |||
| 9196 | gif = DGifOpen(&memsrc, gif_read_from_memory); | ||
| 9197 | if (!gif) | ||
| 9198 | { | ||
| 9199 | image_error ("Cannot open memory source `%s'",specified_data, Qnil); | ||
| 9200 | UNGCPRO; | ||
| 9201 | return 0; | ||
| 9202 | } | ||
| 9203 | } | ||
| 8977 | 9204 | ||
| 8978 | /* Read entire contents. */ | 9205 | /* Read entire contents. */ |
| 8979 | rc = DGifSlurp (gif); | 9206 | rc = DGifSlurp (gif); |