Mercurial > hg > xemacs-beta
annotate src/glyphs-eimage.c @ 4882:eab9498ecc0e
merge most of rest of redisplay-x.c and redisplay-gtk.c into redisplay-xlike-inc.c
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-18 Ben Wing <ben@xemacs.org>
* redisplay-gtk.c:
* redisplay-gtk.c (gtk_bevel_area):
* redisplay-x.c:
* redisplay-x.c (THIS_IS_X):
* redisplay-xlike-inc.c:
* redisplay-xlike-inc.c (XLIKE_text_width_single_run):
* redisplay-xlike-inc.c (XLIKE_text_width):
* redisplay-xlike-inc.c (XLIKE_output_display_block):
* redisplay-xlike-inc.c (XLIKE_get_gc):
* redisplay-xlike-inc.c (XLIKE_output_string):
* redisplay-xlike-inc.c (XLIKE_OUTPUT_XLIKE_PIXMAP):
* redisplay-xlike-inc.c (XLIKE_output_pixmap):
* redisplay-xlike-inc.c (XLIKE_output_vertical_divider):
* redisplay-xlike-inc.c (XLIKE_output_blank):
* redisplay-xlike-inc.c (XLIKE_output_horizontal_line):
* redisplay-xlike-inc.c (XLIKE_clear_region):
* redisplay-xlike-inc.c (XLIKE_output_eol_cursor):
* redisplay-xlike-inc.c (XLIKE_clear_frame_window):
* redisplay-xlike-inc.c (XLIKE_clear_frame):
* redisplay-xlike-inc.c (XLIKE_flash):
* redisplay-xlike-inc.c (console_type_create_redisplay_XLIKE):
Move lots more code into redisplay-xlike-inc.c. Use macros to
isolate the code that differs among X vs. GTK, to reduce the need
for ifdefs in the middle of the code. Now, redisplay-x.c and
redisplay-gtk.c only contain a few functions whose implementation
is completely different from one to the other, or which are not
present at all in one of them.
GTK code not currently tested, but it has bitrotted somewhat
any. Doing this will help keep it less bitrotty.
* depend: Regenerate.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 18 Jan 2010 08:44:49 -0600 |
parents | 95c4ced5c07c |
children | 19a72041c5ed |
rev | line source |
---|---|
428 | 1 /* EImage-specific Lisp objects. |
2 Copyright (C) 1993, 1994, 1998 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Board of Trustees, University of Illinois. | |
4 Copyright (C) 1995 Tinker Systems | |
2959 | 5 Copyright (C) 1995, 1996, 2001, 2002, 2004, 2005 Ben Wing |
428 | 6 Copyright (C) 1995 Sun Microsystems |
7 | |
8 This file is part of XEmacs. | |
9 | |
10 XEmacs is free software; you can redistribute it and/or modify it | |
11 under the terms of the GNU General Public License as published by the | |
12 Free Software Foundation; either version 2, or (at your option) any | |
13 later version. | |
14 | |
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 for more details. | |
19 | |
20 You should have received a copy of the GNU General Public License | |
21 along with XEmacs; see the file COPYING. If not, write to | |
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
23 Boston, MA 02111-1307, USA. */ | |
24 | |
25 /* Synched up with: Not in FSF. */ | |
26 | |
2959 | 27 /* Originally part of glyphs.c. |
28 | |
428 | 29 GIF/JPEG support added by Ben Wing for 19.14 |
30 PNG support added by Bill Perry for 19.14 | |
31 Improved GIF/JPEG support added by Bill Perry for 19.14 | |
32 Cleanup/simplification of error handling by Ben Wing for 19.14 | |
33 GIF support changed to external Gifreader lib by Jareth Hein for 21.0 | |
34 Many changes for color work and optimizations by Jareth Hein for 21.0 | |
35 Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0 | |
36 TIFF code by Jareth Hein for 21.0 | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
37 GIF support changed to external giflib by Jerry James for 21.5 |
428 | 38 TODO: |
39 Convert images.el to C and stick it in here? | |
3094 | 40 This file is really repetitious; can we refactor? |
428 | 41 */ |
42 | |
43 #include <config.h> | |
44 #include "lisp.h" | |
45 #include "lstream.h" | |
46 #include "console.h" | |
872 | 47 #include "device-impl.h" |
428 | 48 #include "faces.h" |
49 #include "glyphs.h" | |
872 | 50 #include "objects-impl.h" |
428 | 51 |
52 #include "buffer.h" | |
53 #include "frame.h" | |
54 #include "opaque.h" | |
442 | 55 #include "window.h" |
428 | 56 |
57 #include "sysfile.h" | |
58 | |
59 #ifdef HAVE_PNG | |
1743 | 60 |
61 BEGIN_C_DECLS | |
62 | |
647 | 63 #define message message_ /* Yuck */ |
428 | 64 #include <png.h> |
647 | 65 #undef message |
1743 | 66 |
67 END_C_DECLS | |
68 | |
428 | 69 #else |
70 #include <setjmp.h> | |
71 #endif | |
72 #include "file-coding.h" | |
73 | |
74 #ifdef HAVE_TIFF | |
75 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tiff); | |
76 Lisp_Object Qtiff; | |
77 #endif | |
78 | |
79 #ifdef HAVE_JPEG | |
80 DEFINE_IMAGE_INSTANTIATOR_FORMAT (jpeg); | |
81 Lisp_Object Qjpeg; | |
82 #endif | |
83 | |
84 #ifdef HAVE_GIF | |
85 DEFINE_IMAGE_INSTANTIATOR_FORMAT (gif); | |
86 Lisp_Object Qgif; | |
87 #endif | |
88 | |
89 #ifdef HAVE_PNG | |
90 DEFINE_IMAGE_INSTANTIATOR_FORMAT (png); | |
91 Lisp_Object Qpng; | |
92 #endif | |
93 | |
94 | |
95 #ifdef HAVE_JPEG | |
96 | |
97 /********************************************************************** | |
98 * JPEG * | |
99 **********************************************************************/ | |
100 | |
1743 | 101 BEGIN_C_DECLS |
102 | |
4854 | 103 #ifdef WIN32_ANY |
104 /* #### Yuck! More horrifitude. tiffio.h, below, and sysfile.h above, | |
105 include <windows.h>, which defines INT32 and INT16, the former | |
106 differently and incompatibly from jmorecfg.h, included by jpeglib.h. We | |
107 can disable the stuff in jmorecfg.h by defining XMD_H (clever, huh?); | |
108 then we define these typedefs the way that <windows.h> wants them (which | |
109 is more correct, anyway; jmorecfg.h defines INT32 as `long'). */ | |
2500 | 110 #define XMD_H |
111 typedef signed int INT32; | |
112 typedef signed short INT16; | |
4326
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
113 |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
114 /* And another one... jmorecfg.h defines the 'boolean' type as int, |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
115 which conflicts with the standard Windows 'boolean' definition as |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
116 unsigned char. Ref: http://www.asmail.be/msg0054688232.html */ |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
117 #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
118 typedef unsigned char boolean; |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
119 #endif |
a5ff7e67ac1b
Don't let libtiff override the size of a boolean, Win32. From Ron Isaacson.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3839
diff
changeset
|
120 #define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ |
2500 | 121 #endif |
122 | |
428 | 123 #include <jpeglib.h> |
124 #include <jerror.h> | |
1743 | 125 |
126 END_C_DECLS | |
428 | 127 |
128 /*#define USE_TEMP_FILES_FOR_JPEG_IMAGES 1*/ | |
129 static void | |
130 jpeg_validate (Lisp_Object instantiator) | |
131 { | |
132 file_or_data_must_be_present (instantiator); | |
133 } | |
134 | |
135 static Lisp_Object | |
442 | 136 jpeg_normalize (Lisp_Object inst, Lisp_Object console_type, |
2286 | 137 Lisp_Object UNUSED (dest_mask)) |
428 | 138 { |
139 return simple_image_type_normalize (inst, console_type, Qjpeg); | |
140 } | |
141 | |
142 static int | |
143 jpeg_possible_dest_types (void) | |
144 { | |
145 return IMAGE_COLOR_PIXMAP_MASK; | |
146 } | |
147 | |
148 /* To survive the otherwise baffling complexity of making sure | |
149 everything gets cleaned up in the presence of an error, we | |
150 use an unwind_protect(). */ | |
151 | |
152 struct jpeg_unwind_data | |
153 { | |
154 /* Stream that we need to close */ | |
155 FILE *instream; | |
156 /* Object that holds state info for JPEG decoding */ | |
157 struct jpeg_decompress_struct *cinfo_ptr; | |
158 /* EImage data */ | |
2367 | 159 Binbyte *eimage; |
428 | 160 }; |
161 | |
162 static Lisp_Object | |
163 jpeg_instantiate_unwind (Lisp_Object unwind_obj) | |
164 { | |
165 struct jpeg_unwind_data *data = | |
166 (struct jpeg_unwind_data *) get_opaque_ptr (unwind_obj); | |
167 | |
168 free_opaque_ptr (unwind_obj); | |
169 if (data->cinfo_ptr) | |
170 jpeg_destroy_decompress (data->cinfo_ptr); | |
171 | |
172 if (data->instream) | |
771 | 173 retry_fclose (data->instream); |
428 | 174 |
1726 | 175 if (data->eimage) |
2367 | 176 xfree (data->eimage, Binbyte *); |
428 | 177 |
178 return Qnil; | |
179 } | |
180 | |
181 /* | |
182 * ERROR HANDLING: | |
183 * | |
184 * The JPEG library's standard error handler (jerror.c) is divided into | |
185 * several "methods" which you can override individually. This lets you | |
186 * adjust the behavior without duplicating a lot of code, which you might | |
187 * have to update with each future release. | |
188 * | |
189 * Our example here shows how to override the "error_exit" method so that | |
190 * control is returned to the library's caller when a fatal error occurs, | |
191 * rather than calling exit() as the standard error_exit method does. | |
192 * | |
193 * We use C's setjmp/longjmp facility to return control. This means that the | |
194 * routine which calls the JPEG library must first execute a setjmp() call to | |
195 * establish the return point. We want the replacement error_exit to do a | |
196 * longjmp(). But we need to make the setjmp buffer accessible to the | |
197 * error_exit routine. To do this, we make a private extension of the | |
198 * standard JPEG error handler object. (If we were using C++, we'd say we | |
199 * were making a subclass of the regular error handler.) | |
200 * | |
201 * Here's the extended error handler struct: | |
202 */ | |
203 | |
204 struct my_jpeg_error_mgr | |
205 { | |
206 struct jpeg_error_mgr pub; /* "public" fields */ | |
207 jmp_buf setjmp_buffer; /* for return to caller */ | |
208 }; | |
209 | |
210 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
211 METHODDEF(void) | |
212 #else | |
213 METHODDEF void | |
214 #endif | |
2286 | 215 our_init_source (j_decompress_ptr UNUSED (cinfo)) |
428 | 216 { |
217 } | |
218 | |
219 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
220 METHODDEF(boolean) | |
221 #else | |
222 METHODDEF boolean | |
223 #endif | |
224 our_fill_input_buffer (j_decompress_ptr cinfo) | |
225 { | |
226 /* Insert a fake EOI marker */ | |
227 struct jpeg_source_mgr *src = cinfo->src; | |
228 static JOCTET buffer[2]; | |
229 | |
230 buffer[0] = (JOCTET) 0xFF; | |
231 buffer[1] = (JOCTET) JPEG_EOI; | |
232 | |
233 src->next_input_byte = buffer; | |
234 src->bytes_in_buffer = 2; | |
235 return TRUE; | |
236 } | |
237 | |
238 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
239 METHODDEF(void) | |
240 #else | |
241 METHODDEF void | |
242 #endif | |
243 our_skip_input_data (j_decompress_ptr cinfo, long num_bytes) | |
244 { | |
245 struct jpeg_source_mgr *src = NULL; | |
246 | |
247 src = (struct jpeg_source_mgr *) cinfo->src; | |
248 | |
249 if (!src) | |
647 | 250 return; |
251 else if (num_bytes > (long) src->bytes_in_buffer) | |
428 | 252 { |
647 | 253 ERREXIT (cinfo, JERR_INPUT_EOF); |
254 /*NOTREACHED*/ | |
255 } | |
428 | 256 |
257 src->bytes_in_buffer -= num_bytes; | |
258 src->next_input_byte += num_bytes; | |
259 } | |
260 | |
261 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
262 METHODDEF(void) | |
263 #else | |
264 METHODDEF void | |
265 #endif | |
2286 | 266 our_term_source (j_decompress_ptr UNUSED (cinfo)) |
428 | 267 { |
268 } | |
269 | |
270 typedef struct | |
271 { | |
272 struct jpeg_source_mgr pub; | |
273 } our_jpeg_source_mgr; | |
274 | |
275 static void | |
665 | 276 jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, Bytecount len) |
428 | 277 { |
278 struct jpeg_source_mgr *src; | |
279 | |
280 if (cinfo->src == NULL) | |
281 { /* first time for this JPEG object? */ | |
282 cinfo->src = (struct jpeg_source_mgr *) | |
283 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
284 sizeof(our_jpeg_source_mgr)); | |
285 src = (struct jpeg_source_mgr *) cinfo->src; | |
286 src->next_input_byte = data; | |
287 } | |
288 src = (struct jpeg_source_mgr *) cinfo->src; | |
289 src->init_source = our_init_source; | |
290 src->fill_input_buffer = our_fill_input_buffer; | |
291 src->skip_input_data = our_skip_input_data; | |
292 src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ | |
293 src->term_source = our_term_source; | |
294 src->bytes_in_buffer = len; | |
295 src->next_input_byte = data; | |
296 } | |
297 | |
298 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
299 METHODDEF(void) | |
300 #else | |
301 METHODDEF void | |
302 #endif | |
303 my_jpeg_error_exit (j_common_ptr cinfo) | |
304 { | |
305 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ | |
306 struct my_jpeg_error_mgr *myerr = (struct my_jpeg_error_mgr *) cinfo->err; | |
307 | |
308 /* Return control to the setjmp point */ | |
309 longjmp (myerr->setjmp_buffer, 1); | |
310 } | |
311 | |
312 #if defined(JPEG_LIB_VERSION) && (JPEG_LIB_VERSION >= 61) | |
313 METHODDEF(void) | |
314 #else | |
315 METHODDEF void | |
316 #endif | |
317 my_jpeg_output_message (j_common_ptr cinfo) | |
318 { | |
771 | 319 Extbyte buffer[JMSG_LENGTH_MAX]; |
867 | 320 Ibyte *intbuf; |
428 | 321 |
322 /* Create the message */ | |
323 (*cinfo->err->format_message) (cinfo, buffer); | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4708
diff
changeset
|
324 EXTERNAL_TO_C_STRING (buffer, intbuf, Qjpeg_error_message_encoding); |
771 | 325 warn_when_safe (Qjpeg, Qinfo, "%s", intbuf); |
428 | 326 } |
327 | |
328 /* The code in this routine is based on example.c from the JPEG library | |
329 source code and from gif_instantiate() */ | |
330 static void | |
331 jpeg_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2959 | 332 Lisp_Object pointer_fg, Lisp_Object pointer_bg, |
428 | 333 int dest_mask, Lisp_Object domain) |
334 { | |
440 | 335 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
428 | 336 /* It is OK for the unwind data to be local to this function, |
337 because the unwind-protect is always executed when this | |
338 stack frame is still valid. */ | |
339 struct jpeg_unwind_data unwind; | |
340 int speccount = specpdl_depth (); | |
341 | |
342 /* This struct contains the JPEG decompression parameters and pointers to | |
343 * working space (which is allocated as needed by the JPEG library). | |
344 */ | |
345 struct jpeg_decompress_struct cinfo; | |
346 /* We use our private extension JPEG error handler. | |
347 * Note that this struct must live as long as the main JPEG parameter | |
348 * struct, to avoid dangling-pointer problems. | |
349 */ | |
350 struct my_jpeg_error_mgr jerr; | |
351 | |
352 /* Step -1: First record our unwind-protect, which will clean up after | |
353 any exit, normal or not */ | |
354 | |
355 xzero (unwind); | |
356 record_unwind_protect (jpeg_instantiate_unwind, make_opaque_ptr (&unwind)); | |
357 | |
358 /* Step 1: allocate and initialize JPEG decompression object */ | |
359 | |
360 /* We set up the normal JPEG error routines, then override error_exit. */ | |
361 cinfo.err = jpeg_std_error (&jerr.pub); | |
362 jerr.pub.error_exit = my_jpeg_error_exit; | |
363 jerr.pub.output_message = my_jpeg_output_message; | |
364 | |
365 /* Establish the setjmp return context for my_error_exit to use. */ | |
366 if (setjmp (jerr.setjmp_buffer)) | |
367 { | |
368 /* If we get here, the JPEG code has signaled an error. | |
369 * We need to clean up the JPEG object, close the input file, and return. | |
370 */ | |
371 | |
372 { | |
373 Lisp_Object errstring; | |
771 | 374 Extbyte buffer[JMSG_LENGTH_MAX]; |
428 | 375 |
376 /* Create the message */ | |
377 (*cinfo.err->format_message) ((j_common_ptr) &cinfo, buffer); | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4708
diff
changeset
|
378 errstring = build_ext_string (buffer, Qjpeg_error_message_encoding); |
428 | 379 |
380 signal_image_error_2 ("JPEG decoding error", | |
381 errstring, instantiator); | |
382 } | |
383 } | |
384 | |
385 /* Now we can initialize the JPEG decompression object. */ | |
386 jpeg_create_decompress (&cinfo); | |
387 unwind.cinfo_ptr = &cinfo; | |
388 | |
389 /* Step 2: specify data source (eg, a file) */ | |
390 | |
391 { | |
392 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
2367 | 393 const Binbyte *bytes; |
665 | 394 Bytecount len; |
428 | 395 |
396 /* #### This is a definite problem under Mule due to the amount of | |
397 stack data it might allocate. Need to be able to convert and | |
398 write out to a file. */ | |
440 | 399 TO_EXTERNAL_FORMAT (LISP_STRING, data, ALLOCA, (bytes, len), Qbinary); |
428 | 400 jpeg_memory_src (&cinfo, (JOCTET *) bytes, len); |
401 } | |
402 | |
403 /* Step 3: read file parameters with jpeg_read_header() */ | |
404 | |
405 jpeg_read_header (&cinfo, TRUE); | |
406 /* We can ignore the return value from jpeg_read_header since | |
407 * (a) suspension is not possible with the stdio data source, and | |
408 * (b) we passed TRUE to reject a tables-only JPEG file as an error. | |
409 * See libjpeg.doc for more info. | |
410 */ | |
411 | |
412 { | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
413 UINT_64_BIT pixels_sq; |
428 | 414 int jpeg_gray = 0; /* if we're dealing with a grayscale */ |
415 /* Step 4: set parameters for decompression. */ | |
416 | |
417 /* Now that we're using EImages, send all data as 24bit color. | |
418 The backend routine will take care of any necessary reductions. | |
419 We do have to handle the grayscale case ourselves, however. */ | |
420 if (cinfo.jpeg_color_space == JCS_GRAYSCALE) | |
421 { | |
422 cinfo.out_color_space = JCS_GRAYSCALE; | |
423 jpeg_gray = 1; | |
424 } | |
425 else | |
426 { | |
427 /* we're relying on the jpeg driver to do any other conversions, | |
428 or signal an error if the conversion isn't supported. */ | |
429 cinfo.out_color_space = JCS_RGB; | |
430 } | |
431 | |
432 /* Step 5: Start decompressor */ | |
433 jpeg_start_decompress (&cinfo); | |
434 | |
435 /* Step 6: Read in the data and put into EImage format (8bit RGB triples)*/ | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
436 pixels_sq = |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
437 (UINT_64_BIT) cinfo.output_width * (UINT_64_BIT) cinfo.output_height; |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
438 if (pixels_sq > ((size_t) -1) / 3) |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
439 signal_image_error ("JPEG image too large to instantiate", instantiator); |
2367 | 440 unwind.eimage = |
441 xnew_binbytes (cinfo.output_width * cinfo.output_height * 3); | |
428 | 442 if (!unwind.eimage) |
443 signal_image_error("Unable to allocate enough memory for image", instantiator); | |
444 | |
445 { | |
446 JSAMPARRAY row_buffer; /* Output row buffer */ | |
447 JSAMPLE *jp; | |
448 int row_stride; /* physical row width in output buffer */ | |
2367 | 449 Binbyte *op = unwind.eimage; |
428 | 450 |
451 /* We may need to do some setup of our own at this point before reading | |
452 * the data. After jpeg_start_decompress() we have the correct scaled | |
453 * output image dimensions available | |
454 * We need to make an output work buffer of the right size. | |
455 */ | |
456 /* JSAMPLEs per row in output buffer. */ | |
457 row_stride = cinfo.output_width * cinfo.output_components; | |
458 /* Make a one-row-high sample array that will go away when done | |
459 with image */ | |
460 row_buffer = ((*cinfo.mem->alloc_sarray) | |
461 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1)); | |
462 | |
463 /* Here we use the library's state variable cinfo.output_scanline as the | |
464 * loop counter, so that we don't have to keep track ourselves. | |
465 */ | |
466 while (cinfo.output_scanline < cinfo.output_height) | |
467 { | |
468 int i; | |
469 | |
470 /* jpeg_read_scanlines expects an array of pointers to scanlines. | |
471 * Here the array is only one element long, but you could ask for | |
472 * more than one scanline at a time if that's more convenient. | |
473 */ | |
474 (void) jpeg_read_scanlines (&cinfo, row_buffer, 1); | |
475 jp = row_buffer[0]; | |
647 | 476 for (i = 0; i < (int) cinfo.output_width; i++) |
428 | 477 { |
478 int clr; | |
479 if (jpeg_gray) | |
480 { | |
2367 | 481 Binbyte val; |
428 | 482 #if (BITS_IN_JSAMPLE == 8) |
2367 | 483 val = (Binbyte) *jp++; |
428 | 484 #else /* other option is 12 */ |
2367 | 485 val = (Binbyte) (*jp++ >> 4); |
428 | 486 #endif |
487 for (clr = 0; clr < 3; clr++) /* copy the same value into RGB */ | |
488 *op++ = val; | |
489 } | |
490 else | |
491 { | |
492 for (clr = 0; clr < 3; clr++) | |
493 #if (BITS_IN_JSAMPLE == 8) | |
2367 | 494 *op++ = (Binbyte)*jp++; |
428 | 495 #else /* other option is 12 */ |
2367 | 496 *op++ = (Binbyte)(*jp++ >> 4); |
428 | 497 #endif |
498 } | |
499 } | |
500 } | |
501 } | |
502 } | |
503 | |
504 /* Step 6.5: Create the pixmap and set up the image instance */ | |
505 /* now instantiate */ | |
442 | 506 MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain), |
428 | 507 init_image_instance_from_eimage, |
508 (ii, cinfo.output_width, cinfo.output_height, 1, | |
509 unwind.eimage, dest_mask, | |
2959 | 510 instantiator, pointer_fg, pointer_bg, domain)); |
428 | 511 |
512 /* Step 7: Finish decompression */ | |
513 | |
514 jpeg_finish_decompress (&cinfo); | |
515 /* We can ignore the return value since suspension is not possible | |
516 * with the stdio data source. | |
517 */ | |
518 | |
519 /* And we're done! */ | |
520 /* This will clean up everything else. */ | |
771 | 521 unbind_to (speccount); |
428 | 522 } |
523 | |
524 #endif /* HAVE_JPEG */ | |
525 | |
526 #ifdef HAVE_GIF | |
527 /********************************************************************** | |
528 * GIF * | |
529 **********************************************************************/ | |
530 | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
531 #include <gif_lib.h> |
428 | 532 |
533 static void | |
534 gif_validate (Lisp_Object instantiator) | |
535 { | |
536 file_or_data_must_be_present (instantiator); | |
537 } | |
538 | |
539 static Lisp_Object | |
442 | 540 gif_normalize (Lisp_Object inst, Lisp_Object console_type, |
2286 | 541 Lisp_Object UNUSED (dest_mask)) |
428 | 542 { |
543 return simple_image_type_normalize (inst, console_type, Qgif); | |
544 } | |
545 | |
546 static int | |
547 gif_possible_dest_types (void) | |
548 { | |
549 return IMAGE_COLOR_PIXMAP_MASK; | |
550 } | |
551 | |
552 /* To survive the otherwise baffling complexity of making sure | |
553 everything gets cleaned up in the presence of an error, we | |
554 use an unwind_protect(). */ | |
555 | |
556 struct gif_unwind_data | |
557 { | |
2367 | 558 Binbyte *eimage; |
428 | 559 /* Object that holds the decoded data from a GIF file */ |
560 GifFileType *giffile; | |
561 }; | |
562 | |
563 static Lisp_Object | |
564 gif_instantiate_unwind (Lisp_Object unwind_obj) | |
565 { | |
566 struct gif_unwind_data *data = | |
567 (struct gif_unwind_data *) get_opaque_ptr (unwind_obj); | |
568 | |
569 free_opaque_ptr (unwind_obj); | |
570 if (data->giffile) | |
571 { | |
572 DGifCloseFile (data->giffile); | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
573 FreeSavedImages(data->giffile); |
428 | 574 } |
647 | 575 if (data->eimage) |
2367 | 576 xfree (data->eimage, Binbyte *); |
428 | 577 |
578 return Qnil; | |
579 } | |
580 | |
581 typedef struct gif_memory_storage | |
582 { | |
2367 | 583 Binbyte *bytes; /* The data */ |
665 | 584 Bytecount len; /* How big is it? */ |
585 Bytecount index; /* Where are we? */ | |
428 | 586 } gif_memory_storage; |
587 | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
588 static int |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
589 gif_read_from_memory (GifFileType *gif, GifByteType *buf, int size) |
428 | 590 { |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
591 gif_memory_storage *mem = (gif_memory_storage *) gif->UserData; |
428 | 592 |
593 if (size > (mem->len - mem->index)) | |
647 | 594 return -1; |
595 memcpy (buf, mem->bytes + mem->index, size); | |
428 | 596 mem->index = mem->index + size; |
597 return size; | |
598 } | |
599 | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
600 static const char * |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
601 gif_decode_error_string () |
428 | 602 { |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
603 switch (GifLastError ()) |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
604 { |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
605 case D_GIF_ERR_OPEN_FAILED: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
606 return "GIF error: unable to open"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
607 case D_GIF_ERR_READ_FAILED: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
608 return "GIF error: read failed"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
609 case D_GIF_ERR_NOT_GIF_FILE: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
610 return "GIF error: not a GIF file"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
611 case D_GIF_ERR_NO_SCRN_DSCR: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
612 return "GIF error: no Screen Descriptor detected"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
613 case D_GIF_ERR_NO_IMAG_DSCR: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
614 return "GIF error: no Image Descriptor detected"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
615 case D_GIF_ERR_NO_COLOR_MAP: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
616 return "GIF error: no global or local color map"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
617 case D_GIF_ERR_WRONG_RECORD: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
618 return "GIF error: wrong record type"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
619 case D_GIF_ERR_DATA_TOO_BIG: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
620 return "GIF error: image is larger than indicated by header"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
621 case D_GIF_ERR_NOT_ENOUGH_MEM: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
622 return "GIF error: out of memory"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
623 case D_GIF_ERR_CLOSE_FAILED: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
624 return "GIF error: failed to close file"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
625 case D_GIF_ERR_NOT_READABLE: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
626 return "GIF error: file is not readable"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
627 case D_GIF_ERR_IMAGE_DEFECT: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
628 return "GIF error: image is defective"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
629 case D_GIF_ERR_EOF_TOO_SOON: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
630 return "GIF error: image EOF detected before image complete"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
631 default: |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
632 return "GIF error: unknown error"; |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
633 } |
428 | 634 } |
635 | |
636 static void | |
637 gif_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2959 | 638 Lisp_Object pointer_fg, Lisp_Object pointer_bg, |
428 | 639 int dest_mask, Lisp_Object domain) |
640 { | |
440 | 641 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
428 | 642 /* It is OK for the unwind data to be local to this function, |
643 because the unwind-protect is always executed when this | |
644 stack frame is still valid. */ | |
645 struct gif_unwind_data unwind; | |
646 int speccount = specpdl_depth (); | |
647 gif_memory_storage mem_struct; | |
2367 | 648 Binbyte *bytes; |
665 | 649 Bytecount len; |
428 | 650 int height = 0; |
651 int width = 0; | |
652 | |
653 xzero (unwind); | |
654 record_unwind_protect (gif_instantiate_unwind, make_opaque_ptr (&unwind)); | |
655 | |
656 /* 1. Now decode the data. */ | |
657 | |
658 { | |
659 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
660 | |
661 assert (!NILP (data)); | |
662 | |
440 | 663 TO_EXTERNAL_FORMAT (LISP_STRING, data, ALLOCA, (bytes, len), Qbinary); |
428 | 664 mem_struct.bytes = bytes; |
665 mem_struct.len = len; | |
666 mem_struct.index = 0; | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
667 unwind.giffile = DGifOpen (&mem_struct, gif_read_from_memory); |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
668 if (unwind.giffile == NULL) |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
669 signal_image_error (gif_decode_error_string (), instantiator); |
428 | 670 |
671 /* Then slurp the image into memory, decoding along the way. | |
672 The result is the image in a simple one-byte-per-pixel | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
673 format. */ |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
674 if (DGifSlurp (unwind.giffile) == GIF_ERROR) |
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
675 signal_image_error (gif_decode_error_string (), instantiator); |
428 | 676 } |
677 | |
678 /* 3. Now create the EImage(s) */ | |
679 { | |
680 ColorMapObject *cmo = unwind.giffile->SColorMap; | |
681 int i, j, row, pass, interlace, slice; | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
682 UINT_64_BIT pixels_sq; |
2367 | 683 Binbyte *eip; |
428 | 684 /* interlaced gifs have rows in this order: |
685 0, 8, 16, ..., 4, 12, 20, ..., 2, 6, 10, ..., 1, 3, 5, ... */ | |
686 static int InterlacedOffset[] = { 0, 4, 2, 1 }; | |
687 static int InterlacedJumps[] = { 8, 8, 4, 2 }; | |
688 | |
689 height = unwind.giffile->SHeight; | |
690 width = unwind.giffile->SWidth; | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
691 pixels_sq = (UINT_64_BIT) width * (UINT_64_BIT) height; |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
692 if (pixels_sq > ((size_t) -1) / (3 * unwind.giffile->ImageCount)) |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
693 signal_image_error ("GIF image too large to instantiate", instantiator); |
2367 | 694 unwind.eimage = |
695 xnew_binbytes (width * height * 3 * unwind.giffile->ImageCount); | |
428 | 696 if (!unwind.eimage) |
697 signal_image_error("Unable to allocate enough memory for image", instantiator); | |
698 | |
699 /* write the data in EImage format (8bit RGB triples) */ | |
700 | |
701 for (slice = 0; slice < unwind.giffile->ImageCount; slice++) | |
702 { | |
638 | 703 /* We check here that the current image covers the full "screen" size. */ |
428 | 704 if (unwind.giffile->SavedImages[slice].ImageDesc.Height != height |
705 || unwind.giffile->SavedImages[slice].ImageDesc.Width != width | |
706 || unwind.giffile->SavedImages[slice].ImageDesc.Left != 0 | |
707 || unwind.giffile->SavedImages[slice].ImageDesc.Top != 0) | |
708 signal_image_error ("Image in GIF file is not full size", | |
709 instantiator); | |
710 | |
711 interlace = unwind.giffile->SavedImages[slice].ImageDesc.Interlace; | |
712 pass = 0; | |
713 row = interlace ? InterlacedOffset[pass] : 0; | |
714 eip = unwind.eimage + (width * height * 3 * slice); | |
715 for (i = 0; i < height; i++) | |
716 { | |
717 if (interlace) | |
718 if (row >= height) { | |
719 row = InterlacedOffset[++pass]; | |
720 while (row >= height) | |
721 row = InterlacedOffset[++pass]; | |
722 } | |
723 eip = unwind.eimage + (width * height * 3 * slice) + (row * width * 3); | |
724 for (j = 0; j < width; j++) | |
725 { | |
2367 | 726 Binbyte pixel = |
428 | 727 unwind.giffile->SavedImages[slice].RasterBits[(i * width) + j]; |
728 *eip++ = cmo->Colors[pixel].Red; | |
729 *eip++ = cmo->Colors[pixel].Green; | |
730 *eip++ = cmo->Colors[pixel].Blue; | |
731 } | |
732 row += interlace ? InterlacedJumps[pass] : 1; | |
733 } | |
734 } | |
735 | |
736 /* now instantiate */ | |
442 | 737 MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain), |
428 | 738 init_image_instance_from_eimage, |
2959 | 739 (ii, width, height, unwind.giffile->ImageCount, |
740 unwind.eimage, dest_mask, instantiator, pointer_fg, | |
741 pointer_bg, domain)); | |
428 | 742 } |
743 | |
744 /* We read the gif successfully. If we have more than one slice then | |
745 animate the gif. */ | |
746 if (unwind.giffile->ImageCount > 1) | |
747 { | |
748 /* See if there is a timeout value. In theory there could be one | |
4708
1cecc3e9f0a0
Use giflib or libungif to provide GIF support, instead of using internal
Jerry James <james@xemacs.org>
parents:
4698
diff
changeset
|
749 for every image - but that makes the implementation way too |
428 | 750 complicated for now so we just take the first. */ |
751 unsigned short timeout = 0; | |
752 Lisp_Object tid; | |
753 | |
754 if (unwind.giffile->SavedImages[0].Function == GRAPHICS_EXT_FUNC_CODE | |
755 && | |
756 unwind.giffile->SavedImages[0].ExtensionBlockCount) | |
757 { | |
758 timeout = (unsigned short) | |
438 | 759 ((unwind.giffile->SavedImages[0].ExtensionBlocks[0].Bytes[2] << 8) + |
428 | 760 unwind.giffile-> SavedImages[0].ExtensionBlocks[0].Bytes[1]) * 10; |
761 } | |
762 | |
763 /* Too short a timeout will crucify us performance-wise. */ | |
764 tid = add_glyph_animated_timeout (timeout > 10 ? timeout : 10, image_instance); | |
765 | |
766 if (!NILP (tid)) | |
767 IMAGE_INSTANCE_PIXMAP_TIMEOUT (ii) = XINT (tid); | |
768 } | |
438 | 769 |
771 | 770 unbind_to (speccount); |
428 | 771 } |
772 | |
773 #endif /* HAVE_GIF */ | |
774 | |
775 | |
776 #ifdef HAVE_PNG | |
777 | |
778 /********************************************************************** | |
779 * PNG * | |
780 **********************************************************************/ | |
781 static void | |
782 png_validate (Lisp_Object instantiator) | |
783 { | |
784 file_or_data_must_be_present (instantiator); | |
785 } | |
786 | |
787 static Lisp_Object | |
442 | 788 png_normalize (Lisp_Object inst, Lisp_Object console_type, |
2286 | 789 Lisp_Object UNUSED (dest_mask)) |
428 | 790 { |
791 return simple_image_type_normalize (inst, console_type, Qpng); | |
792 } | |
793 | |
794 static int | |
795 png_possible_dest_types (void) | |
796 { | |
797 return IMAGE_COLOR_PIXMAP_MASK; | |
798 } | |
799 | |
800 struct png_memory_storage | |
801 { | |
2367 | 802 const Binbyte *bytes; /* The data */ |
665 | 803 Bytecount len; /* How big is it? */ |
804 Bytecount index; /* Where are we? */ | |
428 | 805 }; |
806 | |
807 static void | |
647 | 808 png_read_from_memory (png_structp png_ptr, png_bytep data, |
809 png_size_t length) | |
428 | 810 { |
811 struct png_memory_storage *tbr = | |
812 (struct png_memory_storage *) png_get_io_ptr (png_ptr); | |
813 | |
665 | 814 if ((Bytecount) length > (tbr->len - tbr->index)) |
428 | 815 png_error (png_ptr, (png_const_charp) "Read Error"); |
647 | 816 memcpy (data, tbr->bytes + tbr->index,length); |
428 | 817 tbr->index = tbr->index + length; |
818 } | |
819 | |
820 struct png_error_struct | |
821 { | |
442 | 822 const char *err_str; |
428 | 823 jmp_buf setjmp_buffer; /* for return to caller */ |
824 }; | |
825 | |
826 /* jh 98/03/12 - #### AARRRGH! libpng includes jmp_buf inside its own | |
827 structure, and there are cases where the size can be different from | |
828 between inside the library, and inside the code! To do an end run | |
829 around this, use our own error functions, and don't rely on things | |
830 passed in the png_ptr to them. This is an ugly hack and must | |
831 go away when the lisp engine is threaded! */ | |
832 static struct png_error_struct png_err_stct; | |
833 | |
834 static void | |
2286 | 835 png_error_func (png_structp UNUSED (png_ptr), png_const_charp msg) |
428 | 836 { |
837 png_err_stct.err_str = msg; | |
838 longjmp (png_err_stct.setjmp_buffer, 1); | |
839 } | |
840 | |
841 static void | |
2286 | 842 png_warning_func (png_structp UNUSED (png_ptr), png_const_charp msg) |
428 | 843 { |
3734 | 844 DECLARE_EISTRING (eimsg); |
845 | |
846 eicpy_ext(eimsg, msg, Qbinary); | |
847 warn_when_safe (Qpng, Qinfo, "%s", eidata(eimsg)); | |
428 | 848 } |
849 | |
850 struct png_unwind_data | |
851 { | |
852 FILE *instream; | |
2367 | 853 Binbyte *eimage; |
428 | 854 png_structp png_ptr; |
855 png_infop info_ptr; | |
856 }; | |
857 | |
858 static Lisp_Object | |
859 png_instantiate_unwind (Lisp_Object unwind_obj) | |
860 { | |
861 struct png_unwind_data *data = | |
862 (struct png_unwind_data *) get_opaque_ptr (unwind_obj); | |
863 | |
864 free_opaque_ptr (unwind_obj); | |
865 if (data->png_ptr) | |
3839 | 866 { |
867 /* ensure we can't get here again */ | |
868 png_structp tmp = data->png_ptr; | |
869 data->png_ptr = NULL; | |
870 png_destroy_read_struct (&tmp, &(data->info_ptr), (png_infopp)NULL); | |
871 } | |
872 | |
428 | 873 if (data->instream) |
771 | 874 retry_fclose (data->instream); |
428 | 875 |
1726 | 876 if (data->eimage) |
2367 | 877 xfree(data->eimage, Binbyte *); |
428 | 878 |
879 return Qnil; | |
880 } | |
881 | |
882 static void | |
883 png_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2959 | 884 Lisp_Object pointer_fg, Lisp_Object pointer_bg, |
428 | 885 int dest_mask, Lisp_Object domain) |
886 { | |
440 | 887 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
428 | 888 struct png_unwind_data unwind; |
889 int speccount = specpdl_depth (); | |
890 int height, width; | |
891 struct png_memory_storage tbr; /* Data to be read */ | |
892 | |
893 /* PNG variables */ | |
894 png_structp png_ptr; | |
895 png_infop info_ptr; | |
896 | |
3839 | 897 xzero (unwind); |
898 record_unwind_protect (png_instantiate_unwind, make_opaque_ptr (&unwind)); | |
899 | |
900 if (setjmp (png_err_stct.setjmp_buffer)) | |
901 { | |
902 /* Something blew up: | |
903 just display the error (cleanup happens in the unwind) */ | |
904 signal_image_error_2 ("Error decoding PNG", | |
905 build_string(png_err_stct.err_str), | |
906 instantiator); | |
907 } | |
908 | |
428 | 909 /* Initialize all PNG structures */ |
3839 | 910 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, |
911 (void *) &png_err_stct, | |
428 | 912 png_error_func, png_warning_func); |
913 if (!png_ptr) | |
914 signal_image_error ("Error obtaining memory for png_read", instantiator); | |
3839 | 915 unwind.png_ptr = png_ptr; |
916 | |
428 | 917 info_ptr = png_create_info_struct (png_ptr); |
918 if (!info_ptr) | |
919 { | |
3839 | 920 unwind.png_ptr = NULL; /* avoid re-calling png_destroy_read_struct |
921 when unwinding */ | |
428 | 922 png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL); |
923 signal_image_error ("Error obtaining memory for png_read", instantiator); | |
924 } | |
925 unwind.info_ptr = info_ptr; | |
926 | |
927 /* This code is a mixture of stuff from Ben's GIF/JPEG stuff from | |
928 this file, example.c from the libpng 0.81 distribution, and the | |
929 pngtopnm sources. -WMP- | |
930 */ | |
931 /* It has been further modified to handle the API changes for 0.96, | |
932 and is no longer usable for previous versions. jh | |
933 */ | |
934 | |
935 /* Initialize the IO layer and read in header information */ | |
936 { | |
937 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
2367 | 938 const Binbyte *bytes; |
665 | 939 Bytecount len; |
428 | 940 |
941 assert (!NILP (data)); | |
942 | |
943 /* #### This is a definite problem under Mule due to the amount of | |
944 stack data it might allocate. Need to think about using Lstreams */ | |
440 | 945 TO_EXTERNAL_FORMAT (LISP_STRING, data, ALLOCA, (bytes, len), Qbinary); |
428 | 946 tbr.bytes = bytes; |
947 tbr.len = len; | |
948 tbr.index = 0; | |
949 png_set_read_fn (png_ptr,(void *) &tbr, png_read_from_memory); | |
950 } | |
951 | |
952 png_read_info (png_ptr, info_ptr); | |
953 | |
954 { | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
955 int y, padding; |
2367 | 956 Binbyte **row_pointers; |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
957 UINT_64_BIT pixels_sq; |
428 | 958 height = info_ptr->height; |
959 width = info_ptr->width; | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
960 pixels_sq = (UINT_64_BIT) width * (UINT_64_BIT) height; |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
961 if (pixels_sq > ((size_t) -1) / 3) |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
962 signal_image_error ("PNG image too large to instantiate", instantiator); |
428 | 963 |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
964 /* Wow, allocate all the memory. Truly, exciting. |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
965 Well, yes, there's excitement to be had. It turns out that libpng |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
966 strips in place, so the last row overruns the buffer if depth is 16 |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
967 or there's an alpha channel. This is a crash on Linux. So we need |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
968 to add padding. |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
969 The worst case is reducing 8 bytes (16-bit RGBA) to 3 (8-bit RGB). */ |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
970 |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
971 padding = 5 * width; |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
972 unwind.eimage = xnew_array_and_zero (Binbyte, |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
973 (size_t) (pixels_sq * 3 + padding)); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
974 |
428 | 975 /* libpng expects that the image buffer passed in contains a |
976 picture to draw on top of if the png has any transparencies. | |
977 This could be a good place to pass that in... */ | |
978 | |
979 row_pointers = xnew_array (png_byte *, height); | |
980 for (y = 0; y < height; y++) | |
981 row_pointers[y] = unwind.eimage + (width * 3 * y); | |
982 | |
983 { | |
984 /* if the png specifies a background chunk, go ahead and | |
985 use it, else use what we can get from the default face. */ | |
986 png_color_16 my_background, *image_background; | |
987 Lisp_Object bkgd = Qnil; | |
988 | |
989 my_background.red = 0x7fff; | |
990 my_background.green = 0x7fff; | |
991 my_background.blue = 0x7fff; | |
992 bkgd = FACE_BACKGROUND (Vdefault_face, domain); | |
993 if (!COLOR_INSTANCEP (bkgd)) | |
994 { | |
995 warn_when_safe (Qpng, Qinfo, "Couldn't get background color!"); | |
996 } | |
997 else | |
998 { | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
999 Lisp_Color_Instance *c = XCOLOR_INSTANCE (bkgd); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1000 Lisp_Object rgb = MAYBE_LISP_DEVMETH (XDEVICE (c->device), |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1001 color_instance_rgb_components, |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1002 (c)); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1003 #define GETCOLOR(col) my_background.col = (unsigned short) XINT (XCAR (rgb)) |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1004 GETCOLOR(red); rgb = XCDR (rgb); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1005 GETCOLOR(green); rgb = XCDR (rgb); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1006 GETCOLOR(blue); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1007 #undef GETCOLOR |
428 | 1008 } |
1009 | |
1010 if (png_get_bKGD (png_ptr, info_ptr, &image_background)) | |
1011 png_set_background (png_ptr, image_background, | |
1012 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); | |
1013 else | |
1014 png_set_background (png_ptr, &my_background, | |
1015 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); | |
1016 } | |
1017 | |
1018 /* Now that we're using EImage, ask for 8bit RGB triples for any type | |
1019 of image*/ | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1020 /* convert palette images to RGB */ |
428 | 1021 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1022 png_set_palette_to_rgb (png_ptr); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1023 /* convert grayscale images to RGB */ |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1024 else if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || |
428 | 1025 info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) |
1026 png_set_gray_to_rgb (png_ptr); | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1027 /* pad images with depth < 8 bits */ |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1028 else if (info_ptr->bit_depth < 8) |
428 | 1029 { |
1030 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) | |
1031 png_set_expand (png_ptr); | |
1032 else | |
1033 png_set_packing (png_ptr); | |
1034 } | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1035 /* strip 16-bit depth files down to 8 bits */ |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1036 if (info_ptr->bit_depth == 16) |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1037 png_set_strip_16 (png_ptr); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1038 /* strip alpha channel |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1039 #### shouldn't we handle this? |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1040 first call png_read_update_info in case above transformations |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1041 have generated an alpha channel */ |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1042 png_read_update_info(png_ptr, info_ptr); |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1043 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1044 png_set_strip_alpha (png_ptr); |
428 | 1045 |
1046 png_read_image (png_ptr, row_pointers); | |
1047 png_read_end (png_ptr, info_ptr); | |
1048 | |
4698
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1049 /* #### There should be some way to pass this type of data down |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1050 * into the glyph code, where you can get to it from lisp |
a9493cab536f
Fix crash due to mishandling transparency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4682
diff
changeset
|
1051 * anyway. - WMP */ |
428 | 1052 { |
1053 int i; | |
3734 | 1054 DECLARE_EISTRING (key); |
1055 DECLARE_EISTRING (text); | |
428 | 1056 |
1057 for (i = 0 ; i < info_ptr->num_text ; i++) | |
1058 { | |
1059 /* How paranoid do I have to be about no trailing NULLs, and | |
1060 using (int)info_ptr->text[i].text_length, and strncpy and a temp | |
1061 string somewhere? */ | |
3734 | 1062 eireset(key); |
1063 eireset(text); | |
1064 eicpy_ext(key, info_ptr->text[i].key, Qbinary); | |
1065 eicpy_ext(text, info_ptr->text[i].text, Qbinary); | |
428 | 1066 |
1067 warn_when_safe (Qpng, Qinfo, "%s - %s", | |
3734 | 1068 eidata(key), eidata(text)); |
428 | 1069 } |
1070 } | |
1071 | |
2367 | 1072 xfree (row_pointers, Binbyte **); |
428 | 1073 } |
1074 | |
1075 /* now instantiate */ | |
442 | 1076 MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain), |
428 | 1077 init_image_instance_from_eimage, |
1078 (ii, width, height, 1, unwind.eimage, dest_mask, | |
2959 | 1079 instantiator, pointer_fg, pointer_bg, domain)); |
428 | 1080 |
1081 /* This will clean up everything else. */ | |
771 | 1082 unbind_to (speccount); |
428 | 1083 } |
1084 | |
1085 #endif /* HAVE_PNG */ | |
1086 | |
1087 | |
1088 #ifdef HAVE_TIFF | |
1089 #include "tiffio.h" | |
1090 | |
1091 /********************************************************************** | |
1092 * TIFF * | |
1093 **********************************************************************/ | |
1094 static void | |
1095 tiff_validate (Lisp_Object instantiator) | |
1096 { | |
1097 file_or_data_must_be_present (instantiator); | |
1098 } | |
1099 | |
1100 static Lisp_Object | |
442 | 1101 tiff_normalize (Lisp_Object inst, Lisp_Object console_type, |
2286 | 1102 Lisp_Object UNUSED (dest_mask)) |
428 | 1103 { |
1104 return simple_image_type_normalize (inst, console_type, Qtiff); | |
1105 } | |
1106 | |
1107 static int | |
1108 tiff_possible_dest_types (void) | |
1109 { | |
1110 return IMAGE_COLOR_PIXMAP_MASK; | |
1111 } | |
1112 | |
1113 struct tiff_unwind_data | |
1114 { | |
2367 | 1115 Binbyte *eimage; |
428 | 1116 /* Object that holds the decoded data from a TIFF file */ |
1117 TIFF *tiff; | |
1118 }; | |
1119 | |
1120 static Lisp_Object | |
1121 tiff_instantiate_unwind (Lisp_Object unwind_obj) | |
1122 { | |
1123 struct tiff_unwind_data *data = | |
1124 (struct tiff_unwind_data *) get_opaque_ptr (unwind_obj); | |
1125 | |
1126 free_opaque_ptr (unwind_obj); | |
1127 if (data->tiff) | |
1128 { | |
1129 TIFFClose(data->tiff); | |
1130 } | |
1131 if (data->eimage) | |
2367 | 1132 xfree (data->eimage, Binbyte *); |
428 | 1133 |
1134 return Qnil; | |
1135 } | |
1136 | |
1137 typedef struct tiff_memory_storage | |
1138 { | |
2367 | 1139 Binbyte *bytes; /* The data */ |
665 | 1140 Bytecount len; /* How big is it? */ |
1141 Bytecount index; /* Where are we? */ | |
428 | 1142 } tiff_memory_storage; |
1143 | |
1144 static size_t | |
647 | 1145 tiff_memory_read (thandle_t data, tdata_t buf, tsize_t size) |
428 | 1146 { |
647 | 1147 tiff_memory_storage *mem = (tiff_memory_storage *) data; |
428 | 1148 |
665 | 1149 if ((Bytecount) size > (mem->len - mem->index)) |
428 | 1150 return (size_t) -1; |
647 | 1151 memcpy (buf, mem->bytes + mem->index, size); |
428 | 1152 mem->index = mem->index + size; |
1153 return size; | |
1154 } | |
1155 | |
647 | 1156 static size_t |
2286 | 1157 tiff_memory_write (thandle_t UNUSED (data), tdata_t UNUSED (buf), |
1158 tsize_t UNUSED (size)) | |
428 | 1159 { |
2500 | 1160 ABORT(); |
2270 | 1161 return 0; |
428 | 1162 } |
1163 | |
647 | 1164 static toff_t |
1165 tiff_memory_seek (thandle_t data, toff_t off, int whence) | |
428 | 1166 { |
647 | 1167 tiff_memory_storage *mem = (tiff_memory_storage *) data; |
428 | 1168 int newidx; |
647 | 1169 switch(whence) |
1170 { | |
1171 case SEEK_SET: | |
1172 newidx = off; | |
1173 break; | |
1174 case SEEK_END: | |
1175 newidx = mem->len + off; | |
1176 break; | |
1177 case SEEK_CUR: | |
1178 newidx = mem->index + off; | |
1179 break; | |
1180 default: | |
1181 fprintf (stderr, "Eh? invalid seek mode in tiff_memory_seek\n"); | |
1182 return (toff_t) -1; | |
1183 } | |
428 | 1184 |
1185 if ((newidx > mem->len) || (newidx < 0)) | |
593 | 1186 return (toff_t) -1; |
428 | 1187 |
1188 mem->index = newidx; | |
1189 return newidx; | |
1190 } | |
1191 | |
1192 static int | |
2286 | 1193 tiff_memory_close (thandle_t UNUSED (data)) |
428 | 1194 { |
1195 return 0; | |
1196 } | |
1197 | |
1198 static int | |
2286 | 1199 tiff_map_noop (thandle_t UNUSED (data), tdata_t* UNUSED (pbase), |
1200 toff_t* UNUSED (psize)) | |
428 | 1201 { |
1202 return 0; | |
1203 } | |
1204 | |
1205 static void | |
2286 | 1206 tiff_unmap_noop (thandle_t UNUSED (data), tdata_t UNUSED (pbase), |
1207 toff_t UNUSED (psize)) | |
428 | 1208 { |
1209 return; | |
1210 } | |
1211 | |
1212 static toff_t | |
647 | 1213 tiff_memory_size (thandle_t data) |
428 | 1214 { |
1215 tiff_memory_storage *mem = (tiff_memory_storage*)data; | |
1216 return mem->len; | |
1217 } | |
1218 | |
1219 struct tiff_error_struct | |
1220 { | |
438 | 1221 #ifdef HAVE_VSNPRINTF |
428 | 1222 char err_str[256]; |
1223 #else | |
1224 char err_str[1024]; /* return the error string */ | |
1225 #endif | |
1226 jmp_buf setjmp_buffer; /* for return to caller */ | |
1227 }; | |
1228 | |
1229 /* jh 98/03/12 - ###This struct for passing data to the error functions | |
1230 is an ugly hack caused by the fact that libtiff (as of v3.4) doesn't | |
1231 have any place to store error func data. This should be rectified | |
1232 before XEmacs gets threads! */ | |
1233 static struct tiff_error_struct tiff_err_data; | |
1234 | |
1235 static void | |
2286 | 1236 tiff_error_func (const char *UNUSED (module), const char *fmt, ...) |
428 | 1237 { |
1238 va_list vargs; | |
1239 | |
1240 va_start (vargs, fmt); | |
438 | 1241 #ifdef HAVE_VSNPRINTF |
428 | 1242 vsnprintf (tiff_err_data.err_str, 255, fmt, vargs); |
1243 #else | |
1244 /* pray this doesn't overflow... */ | |
1245 vsprintf (tiff_err_data.err_str, fmt, vargs); | |
1246 #endif | |
1247 va_end (vargs); | |
1248 /* return to setjmp point */ | |
1249 longjmp (tiff_err_data.setjmp_buffer, 1); | |
1250 } | |
1251 | |
1252 static void | |
647 | 1253 tiff_warning_func (const char *module, const char *fmt, ...) |
428 | 1254 { |
1255 va_list vargs; | |
438 | 1256 #ifdef HAVE_VSNPRINTF |
428 | 1257 char warn_str[256]; |
1258 #else | |
1259 char warn_str[1024]; | |
1260 #endif | |
3734 | 1261 DECLARE_EISTRING (eimodule); |
1262 DECLARE_EISTRING (eiwarnstr); | |
428 | 1263 |
1264 va_start (vargs, fmt); | |
438 | 1265 #ifdef HAVE_VSNPRINTF |
428 | 1266 vsnprintf (warn_str, 255, fmt, vargs); |
1267 #else | |
1268 vsprintf (warn_str, fmt, vargs); | |
1269 #endif | |
1270 va_end (vargs); | |
3734 | 1271 |
1272 eicpy_ext(eimodule, module, Qbinary); | |
1273 eicpy_ext(eiwarnstr, warn_str, Qbinary); | |
1274 | |
428 | 1275 warn_when_safe (Qtiff, Qinfo, "%s - %s", |
3734 | 1276 eidata(eimodule), |
1277 eidata(eiwarnstr)); | |
428 | 1278 } |
1279 | |
1280 static void | |
1281 tiff_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2959 | 1282 Lisp_Object pointer_fg, Lisp_Object pointer_bg, |
428 | 1283 int dest_mask, Lisp_Object domain) |
1284 { | |
440 | 1285 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
428 | 1286 tiff_memory_storage mem_struct; |
1287 /* It is OK for the unwind data to be local to this function, | |
1288 because the unwind-protect is always executed when this | |
1289 stack frame is still valid. */ | |
1290 struct tiff_unwind_data unwind; | |
1291 int speccount = specpdl_depth (); | |
1292 uint32 width, height; | |
1293 | |
1294 xzero (unwind); | |
1295 record_unwind_protect (tiff_instantiate_unwind, make_opaque_ptr (&unwind)); | |
1296 | |
1297 /* set up error facilities */ | |
1298 if (setjmp (tiff_err_data.setjmp_buffer)) | |
1299 { | |
1300 /* An error was signaled. No clean up is needed, as unwind handles that | |
1301 for us. Just pass the error along. */ | |
1302 signal_image_error_2 ("TIFF decoding error", | |
1303 build_string(tiff_err_data.err_str), | |
1304 instantiator); | |
1305 } | |
1306 TIFFSetErrorHandler ((TIFFErrorHandler)tiff_error_func); | |
1307 TIFFSetWarningHandler ((TIFFErrorHandler)tiff_warning_func); | |
1308 { | |
1309 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
2367 | 1310 Binbyte *bytes; |
665 | 1311 Bytecount len; |
428 | 1312 |
1313 uint32 *raster; | |
2367 | 1314 Binbyte *ep; |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
1315 UINT_64_BIT pixels_sq; |
428 | 1316 |
1317 assert (!NILP (data)); | |
1318 | |
1319 /* #### This is a definite problem under Mule due to the amount of | |
1320 stack data it might allocate. Think about Lstreams... */ | |
440 | 1321 TO_EXTERNAL_FORMAT (LISP_STRING, data, |
1322 ALLOCA, (bytes, len), | |
1323 Qbinary); | |
428 | 1324 mem_struct.bytes = bytes; |
1325 mem_struct.len = len; | |
1326 mem_struct.index = 0; | |
1327 | |
442 | 1328 unwind.tiff = TIFFClientOpen ("memfile", "r", (thandle_t) &mem_struct, |
428 | 1329 (TIFFReadWriteProc)tiff_memory_read, |
1330 (TIFFReadWriteProc)tiff_memory_write, | |
1331 tiff_memory_seek, tiff_memory_close, tiff_memory_size, | |
1332 tiff_map_noop, tiff_unmap_noop); | |
1333 if (!unwind.tiff) | |
440 | 1334 signal_image_error ("Insufficient memory to instantiate TIFF image", instantiator); |
428 | 1335 |
1336 TIFFGetField (unwind.tiff, TIFFTAG_IMAGEWIDTH, &width); | |
1337 TIFFGetField (unwind.tiff, TIFFTAG_IMAGELENGTH, &height); | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
1338 pixels_sq = (UINT_64_BIT) width * (UINT_64_BIT) height; |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
1339 if (pixels_sq >= 1 << 29) |
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
1340 signal_image_error ("TIFF image too large to instantiate", instantiator); |
4682
648f4a0dac3e
Fix build problems on WIN32 platforms caused by the large image crash fix.
Jerry James <james@xemacs.org>
parents:
4646
diff
changeset
|
1341 unwind.eimage = xnew_binbytes ((size_t) pixels_sq * 3); |
428 | 1342 |
440 | 1343 /* #### This is little more than proof-of-concept/function testing. |
428 | 1344 It needs to be reimplemented via scanline reads for both memory |
1345 compactness. */ | |
4646
6c6bfdb80a0c
Prevent integer overflow and subsequent crashes when attempting to load large
Jerry James <james@xemacs.org>
parents:
4326
diff
changeset
|
1346 raster = (uint32*) _TIFFmalloc ((tsize_t) (pixels_sq * sizeof (uint32))); |
428 | 1347 if (raster != NULL) |
1348 { | |
647 | 1349 int i, j; |
428 | 1350 uint32 *rp; |
1351 ep = unwind.eimage; | |
1352 rp = raster; | |
1353 if (TIFFReadRGBAImage (unwind.tiff, width, height, raster, 0)) | |
1354 { | |
1355 for (i = height - 1; i >= 0; i--) | |
1356 { | |
1357 /* This is to get around weirdness in the libtiff library where properly | |
1358 made TIFFs will come out upside down. libtiff bug or jhod-brainlock? */ | |
1359 rp = raster + (i * width); | |
647 | 1360 for (j = 0; j < (int) width; j++) |
428 | 1361 { |
2367 | 1362 *ep++ = (Binbyte)TIFFGetR(*rp); |
1363 *ep++ = (Binbyte)TIFFGetG(*rp); | |
1364 *ep++ = (Binbyte)TIFFGetB(*rp); | |
428 | 1365 rp++; |
1366 } | |
1367 } | |
1368 } | |
1369 _TIFFfree (raster); | |
1370 } else | |
1371 signal_image_error ("Unable to allocate memory for TIFFReadRGBA", instantiator); | |
1372 | |
1373 } | |
1374 | |
1375 /* now instantiate */ | |
442 | 1376 MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain), |
428 | 1377 init_image_instance_from_eimage, |
1378 (ii, width, height, 1, unwind.eimage, dest_mask, | |
2959 | 1379 instantiator, pointer_fg, pointer_bg, domain)); |
428 | 1380 |
771 | 1381 unbind_to (speccount); |
428 | 1382 } |
1383 | |
1384 #endif /* HAVE_TIFF */ | |
1385 | |
1386 | |
1387 /************************************************************************/ | |
1388 /* initialization */ | |
1389 /************************************************************************/ | |
1390 | |
1391 void | |
1392 syms_of_glyphs_eimage (void) | |
1393 { | |
1394 } | |
1395 | |
1396 void | |
1397 image_instantiator_format_create_glyphs_eimage (void) | |
1398 { | |
1399 /* image-instantiator types */ | |
1400 #ifdef HAVE_JPEG | |
1401 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (jpeg, "jpeg"); | |
1402 | |
1403 IIFORMAT_HAS_METHOD (jpeg, validate); | |
1404 IIFORMAT_HAS_METHOD (jpeg, normalize); | |
1405 IIFORMAT_HAS_METHOD (jpeg, possible_dest_types); | |
1406 IIFORMAT_HAS_METHOD (jpeg, instantiate); | |
1407 | |
1408 IIFORMAT_VALID_KEYWORD (jpeg, Q_data, check_valid_string); | |
1409 IIFORMAT_VALID_KEYWORD (jpeg, Q_file, check_valid_string); | |
1410 #endif | |
1411 | |
1412 #ifdef HAVE_GIF | |
1413 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (gif, "gif"); | |
1414 | |
1415 IIFORMAT_HAS_METHOD (gif, validate); | |
1416 IIFORMAT_HAS_METHOD (gif, normalize); | |
1417 IIFORMAT_HAS_METHOD (gif, possible_dest_types); | |
1418 IIFORMAT_HAS_METHOD (gif, instantiate); | |
1419 | |
1420 IIFORMAT_VALID_KEYWORD (gif, Q_data, check_valid_string); | |
1421 IIFORMAT_VALID_KEYWORD (gif, Q_file, check_valid_string); | |
1422 #endif | |
1423 | |
1424 #ifdef HAVE_PNG | |
1425 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (png, "png"); | |
1426 | |
1427 IIFORMAT_HAS_METHOD (png, validate); | |
1428 IIFORMAT_HAS_METHOD (png, normalize); | |
1429 IIFORMAT_HAS_METHOD (png, possible_dest_types); | |
1430 IIFORMAT_HAS_METHOD (png, instantiate); | |
1431 | |
1432 IIFORMAT_VALID_KEYWORD (png, Q_data, check_valid_string); | |
1433 IIFORMAT_VALID_KEYWORD (png, Q_file, check_valid_string); | |
1434 #endif | |
1435 | |
1436 #ifdef HAVE_TIFF | |
1437 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tiff, "tiff"); | |
1438 | |
1439 IIFORMAT_HAS_METHOD (tiff, validate); | |
1440 IIFORMAT_HAS_METHOD (tiff, normalize); | |
1441 IIFORMAT_HAS_METHOD (tiff, possible_dest_types); | |
1442 IIFORMAT_HAS_METHOD (tiff, instantiate); | |
1443 | |
1444 IIFORMAT_VALID_KEYWORD (tiff, Q_data, check_valid_string); | |
1445 IIFORMAT_VALID_KEYWORD (tiff, Q_file, check_valid_string); | |
1446 #endif | |
1447 | |
1448 } | |
1449 | |
1450 void | |
1451 vars_of_glyphs_eimage (void) | |
1452 { | |
1453 #ifdef HAVE_JPEG | |
1454 Fprovide (Qjpeg); | |
1455 #endif | |
1456 | |
1457 #ifdef HAVE_GIF | |
1458 Fprovide (Qgif); | |
1459 #endif | |
1460 | |
1461 #ifdef HAVE_PNG | |
1462 Fprovide (Qpng); | |
1463 #endif | |
1464 | |
1465 #ifdef HAVE_TIFF | |
1466 Fprovide (Qtiff); | |
1467 #endif | |
1468 | |
1469 } |