(Display) [HAVE_NTGUI]: Redefine while loading xpm.h to avoid name clash.
[bpt/emacs.git] / src / image.c
1 /* Functions for image support on window system.
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04
3 Free Software Foundation.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <math.h>
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 /* This makes the fields of a Display accessible, in Xlib header files. */
32
33 #define XLIB_ILLEGAL_ACCESS
34
35 #include "lisp.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "dispextern.h"
39 #include "blockinput.h"
40 #include "systime.h"
41 #include <epaths.h>
42
43
44 #ifdef HAVE_X_WINDOWS
45 #include "xterm.h"
46 #include <sys/types.h>
47 #include <sys/stat.h>
48
49 #define COLOR_TABLE_SUPPORT 1
50
51 typedef struct x_bitmap_record Bitmap_Record;
52 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
53 #define NO_PIXMAP None
54
55 #define RGB_PIXEL_COLOR unsigned long
56
57 #define PIX_MASK_RETAIN(f) 0
58 #define PIX_MASK_DRAW(f) 1
59 #endif /* HAVE_X_WINDOWS */
60
61
62 #ifdef HAVE_NTGUI
63 #include "w32term.h"
64
65 /* W32_TODO : Color tables on W32. */
66 #undef COLOR_TABLE_SUPPORT
67
68 typedef struct w32_bitmap_record Bitmap_Record;
69 #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
70 #define NO_PIXMAP 0
71
72 #define RGB_PIXEL_COLOR COLORREF
73
74 #define PIX_MASK_RETAIN(f) 0
75 #define PIX_MASK_DRAW(f) 1
76
77 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
78 #define x_defined_color w32_defined_color
79 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
80 #endif /* HAVE_NTGUI */
81
82
83 #ifdef MAC_OS
84 #include "macterm.h"
85 #ifndef MAC_OSX
86 #include <alloca.h>
87 #endif
88 #ifdef MAC_OSX
89 #include <sys/stat.h>
90 #include <QuickTime/QuickTime.h>
91 #else /* not MAC_OSX */
92 #include <Windows.h>
93 #include <Gestalt.h>
94 #include <TextUtils.h>
95 #endif /* not MAC_OSX */
96
97 /* MAC_TODO : Color tables on Mac. */
98 #undef COLOR_TABLE_SUPPORT
99
100 #define ZPixmap 0 /* arbitrary */
101 typedef struct mac_bitmap_record Bitmap_Record;
102
103 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
104 #define NO_PIXMAP 0
105
106 #define RGB_PIXEL_COLOR unsigned long
107
108 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
109 #define x_defined_color mac_defined_color
110 #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
111 #define XDrawLine(display, w, gc, x1, y1, x2, y2) \
112 mac_draw_line_to_pixmap(display, w, gc, x1, y1, x2, y2)
113
114 #endif /* MAC_OS */
115
116
117 /* Search path for bitmap files. */
118
119 Lisp_Object Vx_bitmap_file_path;
120
121
122 static void x_disable_image P_ ((struct frame *, struct image *));
123 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
124 Lisp_Object));
125
126 static void init_color_table P_ ((void));
127 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
128 #ifdef COLOR_TABLE_SUPPORT
129 static void free_color_table P_ ((void));
130 static unsigned long *colors_in_color_table P_ ((int *n));
131 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
132 #endif
133
134 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
135 id, which is just an int that this section returns. Bitmaps are
136 reference counted so they can be shared among frames.
137
138 Bitmap indices are guaranteed to be > 0, so a negative number can
139 be used to indicate no bitmap.
140
141 If you use x_create_bitmap_from_data, then you must keep track of
142 the bitmaps yourself. That is, creating a bitmap from the same
143 data more than once will not be caught. */
144
145 #ifdef MAC_OS
146
147 static XImagePtr
148 XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
149 Display *display; /* not used */
150 Pixmap pixmap;
151 int x, y; /* not used */
152 unsigned int width, height; /* not used */
153 unsigned long plane_mask; /* not used */
154 int format; /* not used */
155 {
156 #if GLYPH_DEBUG
157 xassert (x == 0 && y == 0);
158 {
159 Rect ri, rp;
160 SetRect (&ri, 0, 0, width, height);
161 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
162 }
163 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
164 #endif
165
166 LockPixels (GetGWorldPixMap (pixmap));
167
168 return pixmap;
169 }
170
171 static void
172 XPutPixel (ximage, x, y, pixel)
173 XImagePtr ximage;
174 int x, y;
175 unsigned long pixel;
176 {
177 RGBColor color;
178
179 SetGWorld (ximage, NULL);
180
181 color.red = RED16_FROM_ULONG (pixel);
182 color.green = GREEN16_FROM_ULONG (pixel);
183 color.blue = BLUE16_FROM_ULONG (pixel);
184 SetCPixel (x, y, &color);
185 }
186
187 static unsigned long
188 XGetPixel (ximage, x, y)
189 XImagePtr ximage;
190 int x, y;
191 {
192 RGBColor color;
193
194 SetGWorld (ximage, NULL);
195
196 GetCPixel (x, y, &color);
197 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
198 }
199
200 static void
201 XDestroyImage (ximg)
202 XImagePtr ximg;
203 {
204 UnlockPixels (GetGWorldPixMap (ximg));
205 }
206 #endif
207
208
209 /* Functions to access the contents of a bitmap, given an id. */
210
211 int
212 x_bitmap_height (f, id)
213 FRAME_PTR f;
214 int id;
215 {
216 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
217 }
218
219 int
220 x_bitmap_width (f, id)
221 FRAME_PTR f;
222 int id;
223 {
224 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
225 }
226
227 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
228 int
229 x_bitmap_pixmap (f, id)
230 FRAME_PTR f;
231 int id;
232 {
233 return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
234 }
235 #endif
236
237 #ifdef HAVE_X_WINDOWS
238 int
239 x_bitmap_mask (f, id)
240 FRAME_PTR f;
241 int id;
242 {
243 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
244 }
245 #endif
246
247 /* Allocate a new bitmap record. Returns index of new record. */
248
249 static int
250 x_allocate_bitmap_record (f)
251 FRAME_PTR f;
252 {
253 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
254 int i;
255
256 if (dpyinfo->bitmaps == NULL)
257 {
258 dpyinfo->bitmaps_size = 10;
259 dpyinfo->bitmaps
260 = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
261 dpyinfo->bitmaps_last = 1;
262 return 1;
263 }
264
265 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
266 return ++dpyinfo->bitmaps_last;
267
268 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
269 if (dpyinfo->bitmaps[i].refcount == 0)
270 return i + 1;
271
272 dpyinfo->bitmaps_size *= 2;
273 dpyinfo->bitmaps
274 = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
275 dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
276 return ++dpyinfo->bitmaps_last;
277 }
278
279 /* Add one reference to the reference count of the bitmap with id ID. */
280
281 void
282 x_reference_bitmap (f, id)
283 FRAME_PTR f;
284 int id;
285 {
286 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
287 }
288
289 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
290
291 int
292 x_create_bitmap_from_data (f, bits, width, height)
293 struct frame *f;
294 char *bits;
295 unsigned int width, height;
296 {
297 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
298 int id;
299
300 #ifdef HAVE_X_WINDOWS
301 Pixmap bitmap;
302 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
303 bits, width, height);
304 if (! bitmap)
305 return -1;
306 #endif /* HAVE_X_WINDOWS */
307
308 #ifdef HAVE_NTGUI
309 Pixmap bitmap;
310 bitmap = CreateBitmap (width, height,
311 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
312 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
313 bits);
314 if (! bitmap)
315 return -1;
316 #endif /* HAVE_NTGUI */
317
318 #ifdef MAC_OS
319 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
320 if (width % 16 != 0)
321 return -1;
322 #endif
323
324 id = x_allocate_bitmap_record (f);
325 #ifdef MAC_OS
326 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
327 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
328 return -1;
329 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
330 #endif /* MAC_OS */
331
332 dpyinfo->bitmaps[id - 1].file = NULL;
333 dpyinfo->bitmaps[id - 1].height = height;
334 dpyinfo->bitmaps[id - 1].width = width;
335 dpyinfo->bitmaps[id - 1].refcount = 1;
336
337 #ifdef HAVE_X_WINDOWS
338 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
339 dpyinfo->bitmaps[id - 1].have_mask = 0;
340 dpyinfo->bitmaps[id - 1].depth = 1;
341 #endif /* HAVE_X_WINDOWS */
342
343 #ifdef HAVE_NTGUI
344 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
345 dpyinfo->bitmaps[id - 1].hinst = NULL;
346 dpyinfo->bitmaps[id - 1].depth = 1;
347 #endif /* HAVE_NTGUI */
348
349 return id;
350 }
351
352 /* Create bitmap from file FILE for frame F. */
353
354 int
355 x_create_bitmap_from_file (f, file)
356 struct frame *f;
357 Lisp_Object file;
358 {
359 #ifdef MAC_OS
360 return -1; /* MAC_TODO : bitmap support */
361 #endif /* MAC_OS */
362
363 #ifdef HAVE_NTGUI
364 return -1; /* W32_TODO : bitmap support */
365 #endif /* HAVE_NTGUI */
366
367 #ifdef HAVE_X_WINDOWS
368 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
369 unsigned int width, height;
370 Pixmap bitmap;
371 int xhot, yhot, result, id;
372 Lisp_Object found;
373 int fd;
374 char *filename;
375
376 /* Look for an existing bitmap with the same name. */
377 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
378 {
379 if (dpyinfo->bitmaps[id].refcount
380 && dpyinfo->bitmaps[id].file
381 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
382 {
383 ++dpyinfo->bitmaps[id].refcount;
384 return id + 1;
385 }
386 }
387
388 /* Search bitmap-file-path for the file, if appropriate. */
389 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
390 if (fd < 0)
391 return -1;
392 emacs_close (fd);
393
394 filename = (char *) SDATA (found);
395
396 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
397 filename, &width, &height, &bitmap, &xhot, &yhot);
398 if (result != BitmapSuccess)
399 return -1;
400
401 id = x_allocate_bitmap_record (f);
402 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
403 dpyinfo->bitmaps[id - 1].have_mask = 0;
404 dpyinfo->bitmaps[id - 1].refcount = 1;
405 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
406 dpyinfo->bitmaps[id - 1].depth = 1;
407 dpyinfo->bitmaps[id - 1].height = height;
408 dpyinfo->bitmaps[id - 1].width = width;
409 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
410
411 return id;
412 #endif /* HAVE_X_WINDOWS */
413 }
414
415 /* Free bitmap B. */
416
417 static void
418 Free_Bitmap_Record (dpyinfo, bm)
419 Display_Info *dpyinfo;
420 Bitmap_Record *bm;
421 {
422 #ifdef HAVE_X_WINDOWS
423 XFreePixmap (dpyinfo->display, bm->pixmap);
424 if (bm->have_mask)
425 XFreePixmap (dpyinfo->display, bm->mask);
426 #endif /* HAVE_X_WINDOWS */
427
428 #ifdef HAVE_NTGUI
429 DeleteObject (bm->pixmap);
430 #endif /* HAVE_NTGUI */
431
432 #ifdef MAC_OS
433 xfree (bm->bitmap_data); /* Added ++kfs */
434 bm->bitmap_data = NULL;
435 #endif /* MAC_OS */
436
437 if (bm->file)
438 {
439 xfree (bm->file);
440 bm->file = NULL;
441 }
442 }
443
444 /* Remove reference to bitmap with id number ID. */
445
446 void
447 x_destroy_bitmap (f, id)
448 FRAME_PTR f;
449 int id;
450 {
451 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
452
453 if (id > 0)
454 {
455 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
456
457 if (--bm->refcount == 0)
458 {
459 BLOCK_INPUT;
460 Free_Bitmap_Record (dpyinfo, bm);
461 UNBLOCK_INPUT;
462 }
463 }
464 }
465
466 /* Free all the bitmaps for the display specified by DPYINFO. */
467
468 void
469 x_destroy_all_bitmaps (dpyinfo)
470 Display_Info *dpyinfo;
471 {
472 int i;
473 Bitmap_Record *bm = dpyinfo->bitmaps;
474
475 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
476 if (bm->refcount > 0)
477 Free_Bitmap_Record (dpyinfo, bm);
478
479 dpyinfo->bitmaps_last = 0;
480 }
481
482
483 #ifdef HAVE_X_WINDOWS
484
485 /* Useful functions defined in the section
486 `Image type independent image structures' below. */
487
488 static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
489 unsigned long height));
490
491 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
492 int depth, XImagePtr *ximg,
493 Pixmap *pixmap));
494
495 static void x_destroy_x_image P_ ((XImagePtr ximg));
496
497
498 /* Create a mask of a bitmap. Note is this not a perfect mask.
499 It's nicer with some borders in this context */
500
501 int
502 x_create_bitmap_mask (f, id)
503 struct frame *f;
504 int id;
505 {
506 Pixmap pixmap, mask;
507 XImagePtr ximg, mask_img;
508 unsigned long width, height;
509 int result;
510 unsigned long bg;
511 unsigned long x, y, xp, xm, yp, ym;
512 GC gc;
513
514 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
515
516 if (!(id > 0))
517 return -1;
518
519 pixmap = x_bitmap_pixmap (f, id);
520 width = x_bitmap_width (f, id);
521 height = x_bitmap_height (f, id);
522
523 BLOCK_INPUT;
524 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
525 ~0, ZPixmap);
526
527 if (!ximg)
528 {
529 UNBLOCK_INPUT;
530 return -1;
531 }
532
533 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
534
535 UNBLOCK_INPUT;
536 if (!result)
537 {
538 XDestroyImage (ximg);
539 return -1;
540 }
541
542 bg = four_corners_best (ximg, width, height);
543
544 for (y = 0; y < ximg->height; ++y)
545 {
546 for (x = 0; x < ximg->width; ++x)
547 {
548 xp = x != ximg->width - 1 ? x + 1 : 0;
549 xm = x != 0 ? x - 1 : ximg->width - 1;
550 yp = y != ximg->height - 1 ? y + 1 : 0;
551 ym = y != 0 ? y - 1 : ximg->height - 1;
552 if (XGetPixel (ximg, x, y) == bg
553 && XGetPixel (ximg, x, yp) == bg
554 && XGetPixel (ximg, x, ym) == bg
555 && XGetPixel (ximg, xp, y) == bg
556 && XGetPixel (ximg, xp, yp) == bg
557 && XGetPixel (ximg, xp, ym) == bg
558 && XGetPixel (ximg, xm, y) == bg
559 && XGetPixel (ximg, xm, yp) == bg
560 && XGetPixel (ximg, xm, ym) == bg)
561 XPutPixel (mask_img, x, y, 0);
562 else
563 XPutPixel (mask_img, x, y, 1);
564 }
565 }
566
567 xassert (interrupt_input_blocked);
568 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
569 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
570 width, height);
571 XFreeGC (FRAME_X_DISPLAY (f), gc);
572
573 dpyinfo->bitmaps[id - 1].have_mask = 1;
574 dpyinfo->bitmaps[id - 1].mask = mask;
575
576 XDestroyImage (ximg);
577 x_destroy_x_image (mask_img);
578
579 return 0;
580 }
581
582 #endif /* HAVE_X_WINDOWS */
583
584
585 /***********************************************************************
586 Image types
587 ***********************************************************************/
588
589 /* Value is the number of elements of vector VECTOR. */
590
591 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
592
593 /* List of supported image types. Use define_image_type to add new
594 types. Use lookup_image_type to find a type for a given symbol. */
595
596 static struct image_type *image_types;
597
598 /* The symbol `xbm' which is used as the type symbol for XBM images. */
599
600 Lisp_Object Qxbm;
601
602 /* Keywords. */
603
604 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
605 extern Lisp_Object QCdata, QCtype;
606 extern Lisp_Object Qcenter;
607 Lisp_Object QCascent, QCmargin, QCrelief;
608 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
609 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
610
611 /* Other symbols. */
612
613 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
614
615 /* Time in seconds after which images should be removed from the cache
616 if not displayed. */
617
618 Lisp_Object Vimage_cache_eviction_delay;
619
620 /* Function prototypes. */
621
622 static void define_image_type P_ ((struct image_type *type));
623 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
624 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
625 static void x_laplace P_ ((struct frame *, struct image *));
626 static void x_emboss P_ ((struct frame *, struct image *));
627 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
628 Lisp_Object));
629
630
631 /* Define a new image type from TYPE. This adds a copy of TYPE to
632 image_types and adds the symbol *TYPE->type to Vimage_types. */
633
634 static void
635 define_image_type (type)
636 struct image_type *type;
637 {
638 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
639 The initialized data segment is read-only. */
640 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
641 bcopy (type, p, sizeof *p);
642 p->next = image_types;
643 image_types = p;
644 Vimage_types = Fcons (*p->type, Vimage_types);
645 }
646
647
648 /* Look up image type SYMBOL, and return a pointer to its image_type
649 structure. Value is null if SYMBOL is not a known image type. */
650
651 static INLINE struct image_type *
652 lookup_image_type (symbol)
653 Lisp_Object symbol;
654 {
655 struct image_type *type;
656
657 for (type = image_types; type; type = type->next)
658 if (EQ (symbol, *type->type))
659 break;
660
661 return type;
662 }
663
664
665 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
666 valid image specification is a list whose car is the symbol
667 `image', and whose rest is a property list. The property list must
668 contain a value for key `:type'. That value must be the name of a
669 supported image type. The rest of the property list depends on the
670 image type. */
671
672 int
673 valid_image_p (object)
674 Lisp_Object object;
675 {
676 int valid_p = 0;
677
678 if (IMAGEP (object))
679 {
680 Lisp_Object tem;
681
682 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
683 if (EQ (XCAR (tem), QCtype))
684 {
685 tem = XCDR (tem);
686 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
687 {
688 struct image_type *type;
689 type = lookup_image_type (XCAR (tem));
690 if (type)
691 valid_p = type->valid_p (object);
692 }
693
694 break;
695 }
696 }
697
698 return valid_p;
699 }
700
701
702 /* Log error message with format string FORMAT and argument ARG.
703 Signaling an error, e.g. when an image cannot be loaded, is not a
704 good idea because this would interrupt redisplay, and the error
705 message display would lead to another redisplay. This function
706 therefore simply displays a message. */
707
708 static void
709 image_error (format, arg1, arg2)
710 char *format;
711 Lisp_Object arg1, arg2;
712 {
713 add_to_log (format, arg1, arg2);
714 }
715
716
717 \f
718 /***********************************************************************
719 Image specifications
720 ***********************************************************************/
721
722 enum image_value_type
723 {
724 IMAGE_DONT_CHECK_VALUE_TYPE,
725 IMAGE_STRING_VALUE,
726 IMAGE_STRING_OR_NIL_VALUE,
727 IMAGE_SYMBOL_VALUE,
728 IMAGE_POSITIVE_INTEGER_VALUE,
729 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
730 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
731 IMAGE_ASCENT_VALUE,
732 IMAGE_INTEGER_VALUE,
733 IMAGE_FUNCTION_VALUE,
734 IMAGE_NUMBER_VALUE,
735 IMAGE_BOOL_VALUE
736 };
737
738 /* Structure used when parsing image specifications. */
739
740 struct image_keyword
741 {
742 /* Name of keyword. */
743 char *name;
744
745 /* The type of value allowed. */
746 enum image_value_type type;
747
748 /* Non-zero means key must be present. */
749 int mandatory_p;
750
751 /* Used to recognize duplicate keywords in a property list. */
752 int count;
753
754 /* The value that was found. */
755 Lisp_Object value;
756 };
757
758
759 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
760 int, Lisp_Object));
761 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
762
763
764 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
765 has the format (image KEYWORD VALUE ...). One of the keyword/
766 value pairs must be `:type TYPE'. KEYWORDS is a vector of
767 image_keywords structures of size NKEYWORDS describing other
768 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
769
770 static int
771 parse_image_spec (spec, keywords, nkeywords, type)
772 Lisp_Object spec;
773 struct image_keyword *keywords;
774 int nkeywords;
775 Lisp_Object type;
776 {
777 int i;
778 Lisp_Object plist;
779
780 if (!IMAGEP (spec))
781 return 0;
782
783 plist = XCDR (spec);
784 while (CONSP (plist))
785 {
786 Lisp_Object key, value;
787
788 /* First element of a pair must be a symbol. */
789 key = XCAR (plist);
790 plist = XCDR (plist);
791 if (!SYMBOLP (key))
792 return 0;
793
794 /* There must follow a value. */
795 if (!CONSP (plist))
796 return 0;
797 value = XCAR (plist);
798 plist = XCDR (plist);
799
800 /* Find key in KEYWORDS. Error if not found. */
801 for (i = 0; i < nkeywords; ++i)
802 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
803 break;
804
805 if (i == nkeywords)
806 continue;
807
808 /* Record that we recognized the keyword. If a keywords
809 was found more than once, it's an error. */
810 keywords[i].value = value;
811 ++keywords[i].count;
812
813 if (keywords[i].count > 1)
814 return 0;
815
816 /* Check type of value against allowed type. */
817 switch (keywords[i].type)
818 {
819 case IMAGE_STRING_VALUE:
820 if (!STRINGP (value))
821 return 0;
822 break;
823
824 case IMAGE_STRING_OR_NIL_VALUE:
825 if (!STRINGP (value) && !NILP (value))
826 return 0;
827 break;
828
829 case IMAGE_SYMBOL_VALUE:
830 if (!SYMBOLP (value))
831 return 0;
832 break;
833
834 case IMAGE_POSITIVE_INTEGER_VALUE:
835 if (!INTEGERP (value) || XINT (value) <= 0)
836 return 0;
837 break;
838
839 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
840 if (INTEGERP (value) && XINT (value) >= 0)
841 break;
842 if (CONSP (value)
843 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
844 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
845 break;
846 return 0;
847
848 case IMAGE_ASCENT_VALUE:
849 if (SYMBOLP (value) && EQ (value, Qcenter))
850 break;
851 else if (INTEGERP (value)
852 && XINT (value) >= 0
853 && XINT (value) <= 100)
854 break;
855 return 0;
856
857 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
858 if (!INTEGERP (value) || XINT (value) < 0)
859 return 0;
860 break;
861
862 case IMAGE_DONT_CHECK_VALUE_TYPE:
863 break;
864
865 case IMAGE_FUNCTION_VALUE:
866 value = indirect_function (value);
867 if (SUBRP (value)
868 || COMPILEDP (value)
869 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
870 break;
871 return 0;
872
873 case IMAGE_NUMBER_VALUE:
874 if (!INTEGERP (value) && !FLOATP (value))
875 return 0;
876 break;
877
878 case IMAGE_INTEGER_VALUE:
879 if (!INTEGERP (value))
880 return 0;
881 break;
882
883 case IMAGE_BOOL_VALUE:
884 if (!NILP (value) && !EQ (value, Qt))
885 return 0;
886 break;
887
888 default:
889 abort ();
890 break;
891 }
892
893 if (EQ (key, QCtype) && !EQ (type, value))
894 return 0;
895 }
896
897 /* Check that all mandatory fields are present. */
898 for (i = 0; i < nkeywords; ++i)
899 if (keywords[i].mandatory_p && keywords[i].count == 0)
900 return 0;
901
902 return NILP (plist);
903 }
904
905
906 /* Return the value of KEY in image specification SPEC. Value is nil
907 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
908 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
909
910 static Lisp_Object
911 image_spec_value (spec, key, found)
912 Lisp_Object spec, key;
913 int *found;
914 {
915 Lisp_Object tail;
916
917 xassert (valid_image_p (spec));
918
919 for (tail = XCDR (spec);
920 CONSP (tail) && CONSP (XCDR (tail));
921 tail = XCDR (XCDR (tail)))
922 {
923 if (EQ (XCAR (tail), key))
924 {
925 if (found)
926 *found = 1;
927 return XCAR (XCDR (tail));
928 }
929 }
930
931 if (found)
932 *found = 0;
933 return Qnil;
934 }
935
936
937 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
938 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
939 PIXELS non-nil means return the size in pixels, otherwise return the
940 size in canonical character units.
941 FRAME is the frame on which the image will be displayed. FRAME nil
942 or omitted means use the selected frame. */)
943 (spec, pixels, frame)
944 Lisp_Object spec, pixels, frame;
945 {
946 Lisp_Object size;
947
948 size = Qnil;
949 if (valid_image_p (spec))
950 {
951 struct frame *f = check_x_frame (frame);
952 int id = lookup_image (f, spec);
953 struct image *img = IMAGE_FROM_ID (f, id);
954 int width = img->width + 2 * img->hmargin;
955 int height = img->height + 2 * img->vmargin;
956
957 if (NILP (pixels))
958 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
959 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
960 else
961 size = Fcons (make_number (width), make_number (height));
962 }
963 else
964 error ("Invalid image specification");
965
966 return size;
967 }
968
969
970 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
971 doc: /* Return t if image SPEC has a mask bitmap.
972 FRAME is the frame on which the image will be displayed. FRAME nil
973 or omitted means use the selected frame. */)
974 (spec, frame)
975 Lisp_Object spec, frame;
976 {
977 Lisp_Object mask;
978
979 mask = Qnil;
980 if (valid_image_p (spec))
981 {
982 struct frame *f = check_x_frame (frame);
983 int id = lookup_image (f, spec);
984 struct image *img = IMAGE_FROM_ID (f, id);
985 if (img->mask)
986 mask = Qt;
987 }
988 else
989 error ("Invalid image specification");
990
991 return mask;
992 }
993
994 \f
995 /***********************************************************************
996 Image type independent image structures
997 ***********************************************************************/
998
999 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
1000 static void free_image P_ ((struct frame *f, struct image *img));
1001
1002
1003 /* Allocate and return a new image structure for image specification
1004 SPEC. SPEC has a hash value of HASH. */
1005
1006 static struct image *
1007 make_image (spec, hash)
1008 Lisp_Object spec;
1009 unsigned hash;
1010 {
1011 struct image *img = (struct image *) xmalloc (sizeof *img);
1012
1013 xassert (valid_image_p (spec));
1014 bzero (img, sizeof *img);
1015 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1016 xassert (img->type != NULL);
1017 img->spec = spec;
1018 img->data.lisp_val = Qnil;
1019 img->ascent = DEFAULT_IMAGE_ASCENT;
1020 img->hash = hash;
1021 return img;
1022 }
1023
1024
1025 /* Free image IMG which was used on frame F, including its resources. */
1026
1027 static void
1028 free_image (f, img)
1029 struct frame *f;
1030 struct image *img;
1031 {
1032 if (img)
1033 {
1034 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1035
1036 /* Remove IMG from the hash table of its cache. */
1037 if (img->prev)
1038 img->prev->next = img->next;
1039 else
1040 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1041
1042 if (img->next)
1043 img->next->prev = img->prev;
1044
1045 c->images[img->id] = NULL;
1046
1047 /* Free resources, then free IMG. */
1048 img->type->free (f, img);
1049 xfree (img);
1050 }
1051 }
1052
1053
1054 /* Prepare image IMG for display on frame F. Must be called before
1055 drawing an image. */
1056
1057 void
1058 prepare_image_for_display (f, img)
1059 struct frame *f;
1060 struct image *img;
1061 {
1062 EMACS_TIME t;
1063
1064 /* We're about to display IMG, so set its timestamp to `now'. */
1065 EMACS_GET_TIME (t);
1066 img->timestamp = EMACS_SECS (t);
1067
1068 /* If IMG doesn't have a pixmap yet, load it now, using the image
1069 type dependent loader function. */
1070 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1071 img->load_failed_p = img->type->load (f, img) == 0;
1072 }
1073
1074
1075 /* Value is the number of pixels for the ascent of image IMG when
1076 drawn in face FACE. */
1077
1078 int
1079 image_ascent (img, face, slice)
1080 struct image *img;
1081 struct face *face;
1082 struct glyph_slice *slice;
1083 {
1084 int height;
1085 int ascent;
1086
1087 if (slice->height == img->height)
1088 height = img->height + img->vmargin;
1089 else if (slice->y == 0)
1090 height = slice->height + img->vmargin;
1091 else
1092 height = slice->height;
1093
1094 if (img->ascent == CENTERED_IMAGE_ASCENT)
1095 {
1096 if (face->font)
1097 {
1098 #ifdef HAVE_NTGUI
1099 /* W32 specific version. Why?. ++kfs */
1100 ascent = height / 2 - (FONT_DESCENT(face->font)
1101 - FONT_BASE(face->font)) / 2;
1102 #else
1103 /* This expression is arranged so that if the image can't be
1104 exactly centered, it will be moved slightly up. This is
1105 because a typical font is `top-heavy' (due to the presence
1106 uppercase letters), so the image placement should err towards
1107 being top-heavy too. It also just generally looks better. */
1108 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
1109 #endif /* HAVE_NTGUI */
1110 }
1111 else
1112 ascent = height / 2;
1113 }
1114 else
1115 ascent = (int) (height * img->ascent / 100.0);
1116
1117 return ascent;
1118 }
1119
1120 \f
1121 /* Image background colors. */
1122
1123 /* Find the "best" corner color of a bitmap.
1124 On W32, XIMG is assumed to a device context with the bitmap selected. */
1125
1126 static RGB_PIXEL_COLOR
1127 four_corners_best (ximg, width, height)
1128 XImagePtr_or_DC ximg;
1129 unsigned long width, height;
1130 {
1131 RGB_PIXEL_COLOR corners[4], best;
1132 int i, best_count;
1133
1134 /* Get the colors at the corners of ximg. */
1135 corners[0] = GET_PIXEL (ximg, 0, 0);
1136 corners[1] = GET_PIXEL (ximg, width - 1, 0);
1137 corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
1138 corners[3] = GET_PIXEL (ximg, 0, height - 1);
1139
1140 /* Choose the most frequently found color as background. */
1141 for (i = best_count = 0; i < 4; ++i)
1142 {
1143 int j, n;
1144
1145 for (j = n = 0; j < 4; ++j)
1146 if (corners[i] == corners[j])
1147 ++n;
1148
1149 if (n > best_count)
1150 best = corners[i], best_count = n;
1151 }
1152
1153 return best;
1154 }
1155
1156 /* Portability macros */
1157
1158 #ifdef HAVE_NTGUI
1159
1160 #define Destroy_Image(img_dc, prev) \
1161 do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
1162
1163 #define Free_Pixmap(display, pixmap) \
1164 DeleteObject (pixmap)
1165
1166 #else
1167
1168 #define Destroy_Image(ximg, dummy) \
1169 XDestroyImage (ximg)
1170
1171 #define Free_Pixmap(display, pixmap) \
1172 XFreePixmap (display, pixmap)
1173
1174 #endif /* HAVE_NTGUI */
1175
1176
1177 /* Return the `background' field of IMG. If IMG doesn't have one yet,
1178 it is guessed heuristically. If non-zero, XIMG is an existing
1179 XImage object (or device context with the image selected on W32) to
1180 use for the heuristic. */
1181
1182 RGB_PIXEL_COLOR
1183 image_background (img, f, ximg)
1184 struct image *img;
1185 struct frame *f;
1186 XImagePtr_or_DC ximg;
1187 {
1188 if (! img->background_valid)
1189 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1190 {
1191 int free_ximg = !ximg;
1192 #ifdef HAVE_NTGUI
1193 HGDIOBJ prev;
1194 #endif /* HAVE_NTGUI */
1195
1196 if (free_ximg)
1197 {
1198 #ifndef HAVE_NTGUI
1199 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
1200 0, 0, img->width, img->height, ~0, ZPixmap);
1201 #else
1202 HDC frame_dc = get_frame_dc (f);
1203 ximg = CreateCompatibleDC (frame_dc);
1204 release_frame_dc (f, frame_dc);
1205 prev = SelectObject (ximg, img->pixmap);
1206 #endif /* !HAVE_NTGUI */
1207 }
1208
1209 img->background = four_corners_best (ximg, img->width, img->height);
1210
1211 if (free_ximg)
1212 Destroy_Image (ximg, prev);
1213
1214 img->background_valid = 1;
1215 }
1216
1217 return img->background;
1218 }
1219
1220 /* Return the `background_transparent' field of IMG. If IMG doesn't
1221 have one yet, it is guessed heuristically. If non-zero, MASK is an
1222 existing XImage object to use for the heuristic. */
1223
1224 int
1225 image_background_transparent (img, f, mask)
1226 struct image *img;
1227 struct frame *f;
1228 XImagePtr_or_DC mask;
1229 {
1230 if (! img->background_transparent_valid)
1231 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1232 {
1233 if (img->mask)
1234 {
1235 int free_mask = !mask;
1236 #ifdef HAVE_NTGUI
1237 HGDIOBJ prev;
1238 #endif /* HAVE_NTGUI */
1239
1240 if (free_mask)
1241 {
1242 #ifndef HAVE_NTGUI
1243 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
1244 0, 0, img->width, img->height, ~0, ZPixmap);
1245 #else
1246 HDC frame_dc = get_frame_dc (f);
1247 mask = CreateCompatibleDC (frame_dc);
1248 release_frame_dc (f, frame_dc);
1249 prev = SelectObject (mask, img->mask);
1250 #endif /* HAVE_NTGUI */
1251 }
1252
1253 img->background_transparent
1254 = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
1255
1256 if (free_mask)
1257 Destroy_Image (mask, prev);
1258 }
1259 else
1260 img->background_transparent = 0;
1261
1262 img->background_transparent_valid = 1;
1263 }
1264
1265 return img->background_transparent;
1266 }
1267
1268 \f
1269 /***********************************************************************
1270 Helper functions for X image types
1271 ***********************************************************************/
1272
1273 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
1274 int, int));
1275 static void x_clear_image P_ ((struct frame *f, struct image *img));
1276 static unsigned long x_alloc_image_color P_ ((struct frame *f,
1277 struct image *img,
1278 Lisp_Object color_name,
1279 unsigned long dflt));
1280
1281
1282 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
1283 free the pixmap if any. MASK_P non-zero means clear the mask
1284 pixmap if any. COLORS_P non-zero means free colors allocated for
1285 the image, if any. */
1286
1287 static void
1288 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
1289 struct frame *f;
1290 struct image *img;
1291 int pixmap_p, mask_p, colors_p;
1292 {
1293 if (pixmap_p && img->pixmap)
1294 {
1295 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
1296 img->pixmap = NO_PIXMAP;
1297 img->background_valid = 0;
1298 }
1299
1300 if (mask_p && img->mask)
1301 {
1302 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1303 img->mask = NO_PIXMAP;
1304 img->background_transparent_valid = 0;
1305 }
1306
1307 if (colors_p && img->ncolors)
1308 {
1309 /* MAC_TODO: color table support. */
1310 /* W32_TODO: color table support. */
1311 #ifdef HAVE_X_WINDOWS
1312 x_free_colors (f, img->colors, img->ncolors);
1313 #endif /* HAVE_X_WINDOWS */
1314 xfree (img->colors);
1315 img->colors = NULL;
1316 img->ncolors = 0;
1317 }
1318 }
1319
1320 /* Free X resources of image IMG which is used on frame F. */
1321
1322 static void
1323 x_clear_image (f, img)
1324 struct frame *f;
1325 struct image *img;
1326 {
1327 BLOCK_INPUT;
1328 x_clear_image_1 (f, img, 1, 1, 1);
1329 UNBLOCK_INPUT;
1330 }
1331
1332
1333 /* Allocate color COLOR_NAME for image IMG on frame F. If color
1334 cannot be allocated, use DFLT. Add a newly allocated color to
1335 IMG->colors, so that it can be freed again. Value is the pixel
1336 color. */
1337
1338 static unsigned long
1339 x_alloc_image_color (f, img, color_name, dflt)
1340 struct frame *f;
1341 struct image *img;
1342 Lisp_Object color_name;
1343 unsigned long dflt;
1344 {
1345 XColor color;
1346 unsigned long result;
1347
1348 xassert (STRINGP (color_name));
1349
1350 if (x_defined_color (f, SDATA (color_name), &color, 1))
1351 {
1352 /* This isn't called frequently so we get away with simply
1353 reallocating the color vector to the needed size, here. */
1354 ++img->ncolors;
1355 img->colors =
1356 (unsigned long *) xrealloc (img->colors,
1357 img->ncolors * sizeof *img->colors);
1358 img->colors[img->ncolors - 1] = color.pixel;
1359 result = color.pixel;
1360 }
1361 else
1362 result = dflt;
1363
1364 return result;
1365 }
1366
1367
1368 \f
1369 /***********************************************************************
1370 Image Cache
1371 ***********************************************************************/
1372
1373 static void cache_image P_ ((struct frame *f, struct image *img));
1374 static void postprocess_image P_ ((struct frame *, struct image *));
1375
1376 /* Return a new, initialized image cache that is allocated from the
1377 heap. Call free_image_cache to free an image cache. */
1378
1379 struct image_cache *
1380 make_image_cache ()
1381 {
1382 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
1383 int size;
1384
1385 bzero (c, sizeof *c);
1386 c->size = 50;
1387 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
1388 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
1389 c->buckets = (struct image **) xmalloc (size);
1390 bzero (c->buckets, size);
1391 return c;
1392 }
1393
1394
1395 /* Free image cache of frame F. Be aware that X frames share images
1396 caches. */
1397
1398 void
1399 free_image_cache (f)
1400 struct frame *f;
1401 {
1402 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1403 if (c)
1404 {
1405 int i;
1406
1407 /* Cache should not be referenced by any frame when freed. */
1408 xassert (c->refcount == 0);
1409
1410 for (i = 0; i < c->used; ++i)
1411 free_image (f, c->images[i]);
1412 xfree (c->images);
1413 xfree (c->buckets);
1414 xfree (c);
1415 FRAME_X_IMAGE_CACHE (f) = NULL;
1416 }
1417 }
1418
1419
1420 /* Clear image cache of frame F. FORCE_P non-zero means free all
1421 images. FORCE_P zero means clear only images that haven't been
1422 displayed for some time. Should be called from time to time to
1423 reduce the number of loaded images. If image-eviction-seconds is
1424 non-nil, this frees images in the cache which weren't displayed for
1425 at least that many seconds. */
1426
1427 void
1428 clear_image_cache (f, force_p)
1429 struct frame *f;
1430 int force_p;
1431 {
1432 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1433
1434 if (c && INTEGERP (Vimage_cache_eviction_delay))
1435 {
1436 EMACS_TIME t;
1437 unsigned long old;
1438 int i, nfreed;
1439
1440 EMACS_GET_TIME (t);
1441 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
1442
1443 /* Block input so that we won't be interrupted by a SIGIO
1444 while being in an inconsistent state. */
1445 BLOCK_INPUT;
1446
1447 for (i = nfreed = 0; i < c->used; ++i)
1448 {
1449 struct image *img = c->images[i];
1450 if (img != NULL
1451 && (force_p || img->timestamp < old))
1452 {
1453 free_image (f, img);
1454 ++nfreed;
1455 }
1456 }
1457
1458 /* We may be clearing the image cache because, for example,
1459 Emacs was iconified for a longer period of time. In that
1460 case, current matrices may still contain references to
1461 images freed above. So, clear these matrices. */
1462 if (nfreed)
1463 {
1464 Lisp_Object tail, frame;
1465
1466 FOR_EACH_FRAME (tail, frame)
1467 {
1468 struct frame *f = XFRAME (frame);
1469 if (FRAME_WINDOW_P (f)
1470 && FRAME_X_IMAGE_CACHE (f) == c)
1471 clear_current_matrices (f);
1472 }
1473
1474 ++windows_or_buffers_changed;
1475 }
1476
1477 UNBLOCK_INPUT;
1478 }
1479 }
1480
1481
1482 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
1483 0, 1, 0,
1484 doc: /* Clear the image cache of FRAME.
1485 FRAME nil or omitted means use the selected frame.
1486 FRAME t means clear the image caches of all frames. */)
1487 (frame)
1488 Lisp_Object frame;
1489 {
1490 if (EQ (frame, Qt))
1491 {
1492 Lisp_Object tail;
1493
1494 FOR_EACH_FRAME (tail, frame)
1495 if (FRAME_WINDOW_P (XFRAME (frame)))
1496 clear_image_cache (XFRAME (frame), 1);
1497 }
1498 else
1499 clear_image_cache (check_x_frame (frame), 1);
1500
1501 return Qnil;
1502 }
1503
1504
1505 /* Compute masks and transform image IMG on frame F, as specified
1506 by the image's specification, */
1507
1508 static void
1509 postprocess_image (f, img)
1510 struct frame *f;
1511 struct image *img;
1512 {
1513 /* Manipulation of the image's mask. */
1514 if (img->pixmap)
1515 {
1516 Lisp_Object conversion, spec;
1517 Lisp_Object mask;
1518
1519 spec = img->spec;
1520
1521 /* `:heuristic-mask t'
1522 `:mask heuristic'
1523 means build a mask heuristically.
1524 `:heuristic-mask (R G B)'
1525 `:mask (heuristic (R G B))'
1526 means build a mask from color (R G B) in the
1527 image.
1528 `:mask nil'
1529 means remove a mask, if any. */
1530
1531 mask = image_spec_value (spec, QCheuristic_mask, NULL);
1532 if (!NILP (mask))
1533 x_build_heuristic_mask (f, img, mask);
1534 else
1535 {
1536 int found_p;
1537
1538 mask = image_spec_value (spec, QCmask, &found_p);
1539
1540 if (EQ (mask, Qheuristic))
1541 x_build_heuristic_mask (f, img, Qt);
1542 else if (CONSP (mask)
1543 && EQ (XCAR (mask), Qheuristic))
1544 {
1545 if (CONSP (XCDR (mask)))
1546 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
1547 else
1548 x_build_heuristic_mask (f, img, XCDR (mask));
1549 }
1550 else if (NILP (mask) && found_p && img->mask)
1551 {
1552 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1553 img->mask = NO_PIXMAP;
1554 }
1555 }
1556
1557
1558 /* Should we apply an image transformation algorithm? */
1559 conversion = image_spec_value (spec, QCconversion, NULL);
1560 if (EQ (conversion, Qdisabled))
1561 x_disable_image (f, img);
1562 else if (EQ (conversion, Qlaplace))
1563 x_laplace (f, img);
1564 else if (EQ (conversion, Qemboss))
1565 x_emboss (f, img);
1566 else if (CONSP (conversion)
1567 && EQ (XCAR (conversion), Qedge_detection))
1568 {
1569 Lisp_Object tem;
1570 tem = XCDR (conversion);
1571 if (CONSP (tem))
1572 x_edge_detection (f, img,
1573 Fplist_get (tem, QCmatrix),
1574 Fplist_get (tem, QCcolor_adjustment));
1575 }
1576 }
1577 }
1578
1579
1580 /* Return the id of image with Lisp specification SPEC on frame F.
1581 SPEC must be a valid Lisp image specification (see valid_image_p). */
1582
1583 int
1584 lookup_image (f, spec)
1585 struct frame *f;
1586 Lisp_Object spec;
1587 {
1588 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1589 struct image *img;
1590 int i;
1591 unsigned hash;
1592 struct gcpro gcpro1;
1593 EMACS_TIME now;
1594
1595 /* F must be a window-system frame, and SPEC must be a valid image
1596 specification. */
1597 xassert (FRAME_WINDOW_P (f));
1598 xassert (valid_image_p (spec));
1599
1600 GCPRO1 (spec);
1601
1602 /* Look up SPEC in the hash table of the image cache. */
1603 hash = sxhash (spec, 0);
1604 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1605
1606 for (img = c->buckets[i]; img; img = img->next)
1607 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
1608 break;
1609
1610 /* If not found, create a new image and cache it. */
1611 if (img == NULL)
1612 {
1613 extern Lisp_Object Qpostscript;
1614
1615 BLOCK_INPUT;
1616 img = make_image (spec, hash);
1617 cache_image (f, img);
1618 img->load_failed_p = img->type->load (f, img) == 0;
1619
1620 /* If we can't load the image, and we don't have a width and
1621 height, use some arbitrary width and height so that we can
1622 draw a rectangle for it. */
1623 if (img->load_failed_p)
1624 {
1625 Lisp_Object value;
1626
1627 value = image_spec_value (spec, QCwidth, NULL);
1628 img->width = (INTEGERP (value)
1629 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
1630 value = image_spec_value (spec, QCheight, NULL);
1631 img->height = (INTEGERP (value)
1632 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
1633 }
1634 else
1635 {
1636 /* Handle image type independent image attributes
1637 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
1638 `:background COLOR'. */
1639 Lisp_Object ascent, margin, relief, bg;
1640
1641 ascent = image_spec_value (spec, QCascent, NULL);
1642 if (INTEGERP (ascent))
1643 img->ascent = XFASTINT (ascent);
1644 else if (EQ (ascent, Qcenter))
1645 img->ascent = CENTERED_IMAGE_ASCENT;
1646
1647 margin = image_spec_value (spec, QCmargin, NULL);
1648 if (INTEGERP (margin) && XINT (margin) >= 0)
1649 img->vmargin = img->hmargin = XFASTINT (margin);
1650 else if (CONSP (margin) && INTEGERP (XCAR (margin))
1651 && INTEGERP (XCDR (margin)))
1652 {
1653 if (XINT (XCAR (margin)) > 0)
1654 img->hmargin = XFASTINT (XCAR (margin));
1655 if (XINT (XCDR (margin)) > 0)
1656 img->vmargin = XFASTINT (XCDR (margin));
1657 }
1658
1659 relief = image_spec_value (spec, QCrelief, NULL);
1660 if (INTEGERP (relief))
1661 {
1662 img->relief = XINT (relief);
1663 img->hmargin += abs (img->relief);
1664 img->vmargin += abs (img->relief);
1665 }
1666
1667 if (! img->background_valid)
1668 {
1669 bg = image_spec_value (img->spec, QCbackground, NULL);
1670 if (!NILP (bg))
1671 {
1672 img->background
1673 = x_alloc_image_color (f, img, bg,
1674 FRAME_BACKGROUND_PIXEL (f));
1675 img->background_valid = 1;
1676 }
1677 }
1678
1679 /* Do image transformations and compute masks, unless we
1680 don't have the image yet. */
1681 if (!EQ (*img->type->type, Qpostscript))
1682 postprocess_image (f, img);
1683 }
1684
1685 UNBLOCK_INPUT;
1686 }
1687
1688 /* We're using IMG, so set its timestamp to `now'. */
1689 EMACS_GET_TIME (now);
1690 img->timestamp = EMACS_SECS (now);
1691
1692 UNGCPRO;
1693
1694 /* Value is the image id. */
1695 return img->id;
1696 }
1697
1698
1699 /* Cache image IMG in the image cache of frame F. */
1700
1701 static void
1702 cache_image (f, img)
1703 struct frame *f;
1704 struct image *img;
1705 {
1706 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1707 int i;
1708
1709 /* Find a free slot in c->images. */
1710 for (i = 0; i < c->used; ++i)
1711 if (c->images[i] == NULL)
1712 break;
1713
1714 /* If no free slot found, maybe enlarge c->images. */
1715 if (i == c->used && c->used == c->size)
1716 {
1717 c->size *= 2;
1718 c->images = (struct image **) xrealloc (c->images,
1719 c->size * sizeof *c->images);
1720 }
1721
1722 /* Add IMG to c->images, and assign IMG an id. */
1723 c->images[i] = img;
1724 img->id = i;
1725 if (i == c->used)
1726 ++c->used;
1727
1728 /* Add IMG to the cache's hash table. */
1729 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
1730 img->next = c->buckets[i];
1731 if (img->next)
1732 img->next->prev = img;
1733 img->prev = NULL;
1734 c->buckets[i] = img;
1735 }
1736
1737
1738 /* Call FN on every image in the image cache of frame F. Used to mark
1739 Lisp Objects in the image cache. */
1740
1741 void
1742 forall_images_in_image_cache (f, fn)
1743 struct frame *f;
1744 void (*fn) P_ ((struct image *img));
1745 {
1746 if (FRAME_LIVE_P (f) && FRAME_WINDOW_P (f))
1747 {
1748 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1749 if (c)
1750 {
1751 int i;
1752 for (i = 0; i < c->used; ++i)
1753 if (c->images[i])
1754 fn (c->images[i]);
1755 }
1756 }
1757 }
1758
1759
1760 \f
1761 /***********************************************************************
1762 X / MAC / W32 support code
1763 ***********************************************************************/
1764
1765 #ifdef HAVE_NTGUI
1766
1767 /* Macro for defining functions that will be loaded from image DLLs. */
1768 #define DEF_IMGLIB_FN(func) FARPROC fn_##func
1769
1770 /* Macro for loading those image functions from the library. */
1771 #define LOAD_IMGLIB_FN(lib,func) { \
1772 fn_##func = (void *) GetProcAddress (lib, #func); \
1773 if (!fn_##func) return 0; \
1774 }
1775
1776 #endif /* HAVE_NTGUI */
1777
1778 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
1779 XImagePtr *, Pixmap *));
1780 static void x_destroy_x_image P_ ((XImagePtr));
1781 static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
1782
1783
1784 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
1785 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
1786 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
1787 via xmalloc. Print error messages via image_error if an error
1788 occurs. Value is non-zero if successful.
1789
1790 On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
1791 should indicate the bit depth of the image. */
1792
1793 static int
1794 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
1795 struct frame *f;
1796 int width, height, depth;
1797 XImagePtr *ximg;
1798 Pixmap *pixmap;
1799 {
1800 #ifdef HAVE_X_WINDOWS
1801 Display *display = FRAME_X_DISPLAY (f);
1802 Window window = FRAME_X_WINDOW (f);
1803 Screen *screen = FRAME_X_SCREEN (f);
1804
1805 xassert (interrupt_input_blocked);
1806
1807 if (depth <= 0)
1808 depth = DefaultDepthOfScreen (screen);
1809 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
1810 depth, ZPixmap, 0, NULL, width, height,
1811 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
1812 if (*ximg == NULL)
1813 {
1814 image_error ("Unable to allocate X image", Qnil, Qnil);
1815 return 0;
1816 }
1817
1818 /* Allocate image raster. */
1819 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
1820
1821 /* Allocate a pixmap of the same size. */
1822 *pixmap = XCreatePixmap (display, window, width, height, depth);
1823 if (*pixmap == NO_PIXMAP)
1824 {
1825 x_destroy_x_image (*ximg);
1826 *ximg = NULL;
1827 image_error ("Unable to create X pixmap", Qnil, Qnil);
1828 return 0;
1829 }
1830
1831 return 1;
1832 #endif /* HAVE_X_WINDOWS */
1833
1834 #ifdef HAVE_NTGUI
1835
1836 BITMAPINFOHEADER *header;
1837 HDC hdc;
1838 int scanline_width_bits;
1839 int remainder;
1840 int palette_colors = 0;
1841
1842 if (depth == 0)
1843 depth = 24;
1844
1845 if (depth != 1 && depth != 4 && depth != 8
1846 && depth != 16 && depth != 24 && depth != 32)
1847 {
1848 image_error ("Invalid image bit depth specified", Qnil, Qnil);
1849 return 0;
1850 }
1851
1852 scanline_width_bits = width * depth;
1853 remainder = scanline_width_bits % 32;
1854
1855 if (remainder)
1856 scanline_width_bits += 32 - remainder;
1857
1858 /* Bitmaps with a depth less than 16 need a palette. */
1859 /* BITMAPINFO structure already contains the first RGBQUAD. */
1860 if (depth < 16)
1861 palette_colors = 1 << depth - 1;
1862
1863 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
1864 if (*ximg == NULL)
1865 {
1866 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
1867 return 0;
1868 }
1869
1870 header = &((*ximg)->info.bmiHeader);
1871 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
1872 header->biSize = sizeof (*header);
1873 header->biWidth = width;
1874 header->biHeight = -height; /* negative indicates a top-down bitmap. */
1875 header->biPlanes = 1;
1876 header->biBitCount = depth;
1877 header->biCompression = BI_RGB;
1878 header->biClrUsed = palette_colors;
1879
1880 /* TODO: fill in palette. */
1881 if (depth == 1)
1882 {
1883 (*ximg)->info.bmiColors[0].rgbBlue = 0;
1884 (*ximg)->info.bmiColors[0].rgbGreen = 0;
1885 (*ximg)->info.bmiColors[0].rgbRed = 0;
1886 (*ximg)->info.bmiColors[0].rgbReserved = 0;
1887 (*ximg)->info.bmiColors[1].rgbBlue = 255;
1888 (*ximg)->info.bmiColors[1].rgbGreen = 255;
1889 (*ximg)->info.bmiColors[1].rgbRed = 255;
1890 (*ximg)->info.bmiColors[1].rgbReserved = 0;
1891 }
1892
1893 hdc = get_frame_dc (f);
1894
1895 /* Create a DIBSection and raster array for the bitmap,
1896 and store its handle in *pixmap. */
1897 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
1898 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
1899 &((*ximg)->data), NULL, 0);
1900
1901 /* Realize display palette and garbage all frames. */
1902 release_frame_dc (f, hdc);
1903
1904 if (*pixmap == NULL)
1905 {
1906 DWORD err = GetLastError();
1907 Lisp_Object errcode;
1908 /* All system errors are < 10000, so the following is safe. */
1909 XSETINT (errcode, (int) err);
1910 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
1911 x_destroy_x_image (*ximg);
1912 return 0;
1913 }
1914
1915 return 1;
1916
1917 #endif /* HAVE_NTGUI */
1918
1919 #ifdef MAC_OS
1920 Display *display = FRAME_X_DISPLAY (f);
1921 Window window = FRAME_X_WINDOW (f);
1922
1923 xassert (interrupt_input_blocked);
1924
1925 /* Allocate a pixmap of the same size. */
1926 *pixmap = XCreatePixmap (display, window, width, height, depth);
1927 if (*pixmap == NO_PIXMAP)
1928 {
1929 x_destroy_x_image (*ximg);
1930 *ximg = NULL;
1931 image_error ("Unable to create X pixmap", Qnil, Qnil);
1932 return 0;
1933 }
1934
1935 LockPixels (GetGWorldPixMap (*pixmap));
1936 *ximg = *pixmap;
1937 return 1;
1938
1939 #endif /* MAC_OS */
1940 }
1941
1942
1943 /* Destroy XImage XIMG. Free XIMG->data. */
1944
1945 static void
1946 x_destroy_x_image (ximg)
1947 XImagePtr ximg;
1948 {
1949 xassert (interrupt_input_blocked);
1950 if (ximg)
1951 {
1952 #ifdef HAVE_X_WINDOWS
1953 xfree (ximg->data);
1954 ximg->data = NULL;
1955 XDestroyImage (ximg);
1956 #endif /* HAVE_X_WINDOWS */
1957 #ifdef HAVE_NTGUI
1958 /* Data will be freed by DestroyObject. */
1959 ximg->data = NULL;
1960 xfree (ximg);
1961 #endif /* HAVE_NTGUI */
1962 #ifdef MAC_OS
1963 XDestroyImage (ximg);
1964 #endif /* MAC_OS */
1965 }
1966 }
1967
1968
1969 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
1970 are width and height of both the image and pixmap. */
1971
1972 static void
1973 x_put_x_image (f, ximg, pixmap, width, height)
1974 struct frame *f;
1975 XImagePtr ximg;
1976 Pixmap pixmap;
1977 int width, height;
1978 {
1979 #ifdef HAVE_X_WINDOWS
1980 GC gc;
1981
1982 xassert (interrupt_input_blocked);
1983 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
1984 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
1985 XFreeGC (FRAME_X_DISPLAY (f), gc);
1986 #endif /* HAVE_X_WINDOWS */
1987
1988 #ifdef HAVE_NTGUI
1989 #if 0 /* I don't think this is necessary looking at where it is used. */
1990 HDC hdc = get_frame_dc (f);
1991 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
1992 release_frame_dc (f, hdc);
1993 #endif
1994 #endif /* HAVE_NTGUI */
1995
1996 #ifdef MAC_OS
1997 xassert (ximg == pixmap);
1998 #endif /* MAC_OS */
1999 }
2000
2001 \f
2002 /***********************************************************************
2003 File Handling
2004 ***********************************************************************/
2005
2006 static unsigned char *slurp_file P_ ((char *, int *));
2007
2008
2009 /* Find image file FILE. Look in data-directory, then
2010 x-bitmap-file-path. Value is the full name of the file found, or
2011 nil if not found. */
2012
2013 Lisp_Object
2014 x_find_image_file (file)
2015 Lisp_Object file;
2016 {
2017 Lisp_Object file_found, search_path;
2018 struct gcpro gcpro1, gcpro2;
2019 int fd;
2020
2021 file_found = Qnil;
2022 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
2023 GCPRO2 (file_found, search_path);
2024
2025 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
2026 fd = openp (search_path, file, Qnil, &file_found, Qnil);
2027
2028 if (fd == -1)
2029 file_found = Qnil;
2030 else
2031 close (fd);
2032
2033 UNGCPRO;
2034 return file_found;
2035 }
2036
2037
2038 /* Read FILE into memory. Value is a pointer to a buffer allocated
2039 with xmalloc holding FILE's contents. Value is null if an error
2040 occurred. *SIZE is set to the size of the file. */
2041
2042 static unsigned char *
2043 slurp_file (file, size)
2044 char *file;
2045 int *size;
2046 {
2047 FILE *fp = NULL;
2048 unsigned char *buf = NULL;
2049 struct stat st;
2050
2051 if (stat (file, &st) == 0
2052 && (fp = fopen (file, "rb")) != NULL
2053 && (buf = (char *) xmalloc (st.st_size),
2054 fread (buf, 1, st.st_size, fp) == st.st_size))
2055 {
2056 *size = st.st_size;
2057 fclose (fp);
2058 }
2059 else
2060 {
2061 if (fp)
2062 fclose (fp);
2063 if (buf)
2064 {
2065 xfree (buf);
2066 buf = NULL;
2067 }
2068 }
2069
2070 return buf;
2071 }
2072
2073
2074 \f
2075 #ifdef MAC_OS
2076
2077 /***********************************************************************
2078 MAC Image Load Functions
2079 ***********************************************************************/
2080
2081 static int image_load_quicktime P_ ((struct frame *, struct image *img,
2082 OSType));
2083 #ifdef MAC_OSX
2084 static int image_load_quartz2d P_ ((struct frame *, struct image *img, int));
2085 #endif
2086
2087 static OSErr
2088 find_image_fsspec (specified_file, file, fss)
2089 Lisp_Object specified_file, *file;
2090 FSSpec *fss;
2091 {
2092 #if TARGET_API_MAC_CARBON
2093 FSRef fsr;
2094 #else
2095 Str255 mac_pathname;
2096 #endif
2097 OSErr err;
2098
2099 *file = x_find_image_file (specified_file);
2100 if (!STRINGP (*file))
2101 return fnfErr; /* file or directory not found;
2102 incomplete pathname */
2103 /* Try to open the image file. */
2104 #if TARGET_API_MAC_CARBON
2105 err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
2106 if (err == noErr)
2107 err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
2108 #else
2109 if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
2110 return fnfErr;
2111 c2pstr (mac_pathname);
2112 err = FSMakeFSSpec (0, 0, mac_pathname, fss);
2113 #endif
2114 return err;
2115 }
2116
2117 static int
2118 image_load_qt_1 (f, img, type, fss, dh)
2119 struct frame *f;
2120 struct image *img;
2121 OSType type;
2122 FSSpec *fss;
2123 Handle dh;
2124 {
2125 OSErr err;
2126 GraphicsImportComponent gi;
2127 Rect rect;
2128 int width, height;
2129 short draw_all_pixels;
2130 Lisp_Object specified_bg;
2131 XColor color;
2132 XImagePtr ximg;
2133 RGBColor bg_color;
2134
2135 err = OpenADefaultComponent (GraphicsImporterComponentType,
2136 type, &gi);
2137 if (err != noErr)
2138 {
2139 image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
2140 return 0;
2141 }
2142 if (dh == NULL)
2143 {
2144 /* read from file system spec */
2145 err = GraphicsImportSetDataFile (gi, fss);
2146 if (err != noErr)
2147 {
2148 image_error ("Cannot set fsspec to graphics importer for '%s'",
2149 img->spec, Qnil);
2150 goto error;
2151 }
2152 }
2153 else
2154 {
2155 /* read from data handle */
2156 err = GraphicsImportSetDataHandle (gi, dh);
2157 if (err != noErr)
2158 {
2159 image_error ("Cannot set data handle to graphics importer for `%s'",
2160 img->spec, Qnil);
2161 goto error;
2162 }
2163 }
2164 err = GraphicsImportGetNaturalBounds (gi, &rect);
2165 if (err != noErr)
2166 {
2167 image_error ("Error reading `%s'", img->spec, Qnil);
2168 goto error;
2169 }
2170 width = img->width = rect.right - rect.left;
2171 height = img->height = rect.bottom - rect.top;
2172 err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
2173 #if 0
2174 /* Don't check the error code here. It may have an undocumented
2175 value -32766. */
2176 if (err != noErr)
2177 {
2178 image_error ("Error reading `%s'", img->spec, Qnil);
2179 goto error;
2180 }
2181 #endif
2182 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2183 {
2184 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2185 if (!STRINGP (specified_bg) ||
2186 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2187 {
2188 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2189 color.red = RED16_FROM_ULONG (color.pixel);
2190 color.green = GREEN16_FROM_ULONG (color.pixel);
2191 color.blue = BLUE16_FROM_ULONG (color.pixel);
2192 }
2193 }
2194
2195 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2196 goto error;
2197 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2198 {
2199 SetGWorld (ximg, NULL);
2200 bg_color.red = color.red;
2201 bg_color.green = color.green;
2202 bg_color.blue = color.blue;
2203 RGBBackColor (&bg_color);
2204 #if TARGET_API_MAC_CARBON
2205 GetPortBounds (ximg, &rect);
2206 EraseRect (&rect);
2207 #else
2208 EraseRect (&(ximg->portRect));
2209 #endif
2210 }
2211 GraphicsImportSetGWorld (gi, ximg, NULL);
2212 GraphicsImportDraw (gi);
2213 CloseComponent (gi);
2214
2215 /* Maybe fill in the background field while we have ximg handy. */
2216 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2217 IMAGE_BACKGROUND (img, f, ximg);
2218
2219 /* Put the image into the pixmap. */
2220 x_put_x_image (f, ximg, img->pixmap, width, height);
2221 x_destroy_x_image (ximg);
2222 return 1;
2223
2224 error:
2225 CloseComponent (gi);
2226 return 0;
2227 }
2228
2229
2230 /* Load an image using the QuickTime Graphics Importer.
2231 Note: The alpha channel does not work for PNG images. */
2232 static int
2233 image_load_quicktime (f, img, type)
2234 struct frame *f;
2235 struct image *img;
2236 OSType type;
2237 {
2238 Lisp_Object specified_file;
2239 Lisp_Object specified_data;
2240 OSErr err;
2241
2242 specified_file = image_spec_value (img->spec, QCfile, NULL);
2243 specified_data = image_spec_value (img->spec, QCdata, NULL);
2244
2245 if (NILP (specified_data))
2246 {
2247 /* Read from a file */
2248 Lisp_Object file;
2249 FSSpec fss;
2250
2251 err = find_image_fsspec (specified_file, &file, &fss);
2252 if (err != noErr)
2253 {
2254 if (err == fnfErr)
2255 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2256 else
2257 image_error ("Cannot open `%s'", file, Qnil);
2258 return 0;
2259 }
2260 return image_load_qt_1 (f, img, type, &fss, NULL);
2261 }
2262 else
2263 {
2264 /* Memory source! */
2265 int success_p;
2266 Handle dh;
2267
2268 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
2269 if (err != noErr)
2270 {
2271 image_error ("Cannot allocate data handle for `%s'",
2272 img->spec, Qnil);
2273 return 0;
2274 }
2275 success_p = image_load_qt_1 (f, img, type, NULL, dh);
2276 DisposeHandle (dh);
2277 return success_p;
2278 }
2279 }
2280
2281
2282 #ifdef MAC_OSX
2283 /* Load a PNG/JPEG image using Quartz 2D decoding routines.
2284 CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2.
2285 So don't use this function directly but determine at runtime
2286 whether it exists. */
2287 typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType)
2288 (CGDataProviderRef, const float [], bool, CGColorRenderingIntent);
2289 static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider;
2290
2291
2292 static void
2293 init_image_func_pointer ()
2294 {
2295 if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider"))
2296 {
2297 MyCGImageCreateWithPNGDataProvider
2298 = (CGImageCreateWithPNGDataProviderProcType)
2299 NSAddressOfSymbol (NSLookupAndBindSymbol
2300 ("_CGImageCreateWithPNGDataProvider"));
2301 }
2302 else
2303 MyCGImageCreateWithPNGDataProvider = NULL;
2304 }
2305
2306
2307 static int
2308 image_load_quartz2d (f, img, png_p)
2309 struct frame *f;
2310 struct image *img;
2311 int png_p;
2312 {
2313 Lisp_Object file, specified_file;
2314 Lisp_Object specified_data, specified_bg;
2315 struct gcpro gcpro1;
2316 CGDataProviderRef source;
2317 CGImageRef image;
2318 int width, height;
2319 XColor color;
2320 XImagePtr ximg = NULL;
2321 CGContextRef context;
2322 CGRect rectangle;
2323
2324 /* Open the file. */
2325 specified_file = image_spec_value (img->spec, QCfile, NULL);
2326 specified_data = image_spec_value (img->spec, QCdata, NULL);
2327
2328 file = Qnil;
2329 GCPRO1 (file);
2330
2331 if (NILP (specified_data))
2332 {
2333 CFStringRef path;
2334 CFURLRef url;
2335
2336 file = x_find_image_file (specified_file);
2337 if (!STRINGP (file))
2338 {
2339 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2340 UNGCPRO;
2341 return 0;
2342 }
2343 path = CFStringCreateWithCString (NULL, SDATA (file),
2344 kCFStringEncodingUTF8);
2345 url = CFURLCreateWithFileSystemPath (NULL, path,
2346 kCFURLPOSIXPathStyle, 0);
2347 CFRelease (path);
2348 source = CGDataProviderCreateWithURL (url);
2349 CFRelease (url);
2350 }
2351 else
2352 source = CGDataProviderCreateWithData (NULL, SDATA (specified_data),
2353 SBYTES (specified_data), NULL);
2354
2355 if (png_p)
2356 image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE,
2357 kCGRenderingIntentDefault);
2358 else
2359 image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE,
2360 kCGRenderingIntentDefault);
2361
2362 CGDataProviderRelease (source);
2363 if (image == NULL)
2364 {
2365 UNGCPRO;
2366 image_error ("Error reading image `%s'", img->spec, Qnil);
2367 return 0;
2368 }
2369
2370 if (png_p)
2371 {
2372 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2373 if (!STRINGP (specified_bg) ||
2374 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2375 {
2376 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2377 color.red = RED16_FROM_ULONG (color.pixel);
2378 color.green = GREEN16_FROM_ULONG (color.pixel);
2379 color.blue = BLUE16_FROM_ULONG (color.pixel);
2380 }
2381 }
2382 width = img->width = CGImageGetWidth (image);
2383 height = img->height = CGImageGetHeight (image);
2384 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2385 {
2386 CGImageRelease (image);
2387 UNGCPRO;
2388 return 0;
2389 }
2390 rectangle = CGRectMake (0, 0, width, height);
2391 QDBeginCGContext (ximg, &context);
2392 if (png_p)
2393 {
2394 CGContextSetRGBFillColor (context, color.red / 65535.0,
2395 color.green / 65535.0,
2396 color.blue / 65535.0, 1.0);
2397 CGContextFillRect (context, rectangle);
2398 }
2399 CGContextDrawImage (context, rectangle, image);
2400 QDEndCGContext (ximg, &context);
2401 CGImageRelease (image);
2402
2403 /* Maybe fill in the background field while we have ximg handy. */
2404 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2405 IMAGE_BACKGROUND (img, f, ximg);
2406
2407 /* Put the image into the pixmap. */
2408 x_put_x_image (f, ximg, img->pixmap, width, height);
2409 x_destroy_x_image (ximg);
2410 UNGCPRO;
2411 return 1;
2412 }
2413 #endif
2414
2415 #endif /* MAC_OS */
2416
2417 \f
2418 /***********************************************************************
2419 XBM images
2420 ***********************************************************************/
2421
2422 static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
2423 static int xbm_load P_ ((struct frame *f, struct image *img));
2424 static int xbm_load_image P_ ((struct frame *f, struct image *img,
2425 unsigned char *, unsigned char *));
2426 static int xbm_image_p P_ ((Lisp_Object object));
2427 static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
2428 int *, int *, unsigned char **));
2429 static int xbm_file_p P_ ((Lisp_Object));
2430
2431
2432 /* Indices of image specification fields in xbm_format, below. */
2433
2434 enum xbm_keyword_index
2435 {
2436 XBM_TYPE,
2437 XBM_FILE,
2438 XBM_WIDTH,
2439 XBM_HEIGHT,
2440 XBM_DATA,
2441 XBM_FOREGROUND,
2442 XBM_BACKGROUND,
2443 XBM_ASCENT,
2444 XBM_MARGIN,
2445 XBM_RELIEF,
2446 XBM_ALGORITHM,
2447 XBM_HEURISTIC_MASK,
2448 XBM_MASK,
2449 XBM_LAST
2450 };
2451
2452 /* Vector of image_keyword structures describing the format
2453 of valid XBM image specifications. */
2454
2455 static struct image_keyword xbm_format[XBM_LAST] =
2456 {
2457 {":type", IMAGE_SYMBOL_VALUE, 1},
2458 {":file", IMAGE_STRING_VALUE, 0},
2459 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2460 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2461 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2462 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
2463 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
2464 {":ascent", IMAGE_ASCENT_VALUE, 0},
2465 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
2466 {":relief", IMAGE_INTEGER_VALUE, 0},
2467 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2468 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2469 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
2470 };
2471
2472 /* Structure describing the image type XBM. */
2473
2474 static struct image_type xbm_type =
2475 {
2476 &Qxbm,
2477 xbm_image_p,
2478 xbm_load,
2479 x_clear_image,
2480 NULL
2481 };
2482
2483 /* Tokens returned from xbm_scan. */
2484
2485 enum xbm_token
2486 {
2487 XBM_TK_IDENT = 256,
2488 XBM_TK_NUMBER
2489 };
2490
2491
2492 /* Return non-zero if OBJECT is a valid XBM-type image specification.
2493 A valid specification is a list starting with the symbol `image'
2494 The rest of the list is a property list which must contain an
2495 entry `:type xbm..
2496
2497 If the specification specifies a file to load, it must contain
2498 an entry `:file FILENAME' where FILENAME is a string.
2499
2500 If the specification is for a bitmap loaded from memory it must
2501 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
2502 WIDTH and HEIGHT are integers > 0. DATA may be:
2503
2504 1. a string large enough to hold the bitmap data, i.e. it must
2505 have a size >= (WIDTH + 7) / 8 * HEIGHT
2506
2507 2. a bool-vector of size >= WIDTH * HEIGHT
2508
2509 3. a vector of strings or bool-vectors, one for each line of the
2510 bitmap.
2511
2512 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
2513 may not be specified in this case because they are defined in the
2514 XBM file.
2515
2516 Both the file and data forms may contain the additional entries
2517 `:background COLOR' and `:foreground COLOR'. If not present,
2518 foreground and background of the frame on which the image is
2519 displayed is used. */
2520
2521 static int
2522 xbm_image_p (object)
2523 Lisp_Object object;
2524 {
2525 struct image_keyword kw[XBM_LAST];
2526
2527 bcopy (xbm_format, kw, sizeof kw);
2528 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
2529 return 0;
2530
2531 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
2532
2533 if (kw[XBM_FILE].count)
2534 {
2535 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
2536 return 0;
2537 }
2538 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
2539 {
2540 /* In-memory XBM file. */
2541 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
2542 return 0;
2543 }
2544 else
2545 {
2546 Lisp_Object data;
2547 int width, height;
2548
2549 /* Entries for `:width', `:height' and `:data' must be present. */
2550 if (!kw[XBM_WIDTH].count
2551 || !kw[XBM_HEIGHT].count
2552 || !kw[XBM_DATA].count)
2553 return 0;
2554
2555 data = kw[XBM_DATA].value;
2556 width = XFASTINT (kw[XBM_WIDTH].value);
2557 height = XFASTINT (kw[XBM_HEIGHT].value);
2558
2559 /* Check type of data, and width and height against contents of
2560 data. */
2561 if (VECTORP (data))
2562 {
2563 int i;
2564
2565 /* Number of elements of the vector must be >= height. */
2566 if (XVECTOR (data)->size < height)
2567 return 0;
2568
2569 /* Each string or bool-vector in data must be large enough
2570 for one line of the image. */
2571 for (i = 0; i < height; ++i)
2572 {
2573 Lisp_Object elt = XVECTOR (data)->contents[i];
2574
2575 if (STRINGP (elt))
2576 {
2577 if (SCHARS (elt)
2578 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
2579 return 0;
2580 }
2581 else if (BOOL_VECTOR_P (elt))
2582 {
2583 if (XBOOL_VECTOR (elt)->size < width)
2584 return 0;
2585 }
2586 else
2587 return 0;
2588 }
2589 }
2590 else if (STRINGP (data))
2591 {
2592 if (SCHARS (data)
2593 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
2594 return 0;
2595 }
2596 else if (BOOL_VECTOR_P (data))
2597 {
2598 if (XBOOL_VECTOR (data)->size < width * height)
2599 return 0;
2600 }
2601 else
2602 return 0;
2603 }
2604
2605 return 1;
2606 }
2607
2608
2609 /* Scan a bitmap file. FP is the stream to read from. Value is
2610 either an enumerator from enum xbm_token, or a character for a
2611 single-character token, or 0 at end of file. If scanning an
2612 identifier, store the lexeme of the identifier in SVAL. If
2613 scanning a number, store its value in *IVAL. */
2614
2615 static int
2616 xbm_scan (s, end, sval, ival)
2617 unsigned char **s, *end;
2618 char *sval;
2619 int *ival;
2620 {
2621 unsigned int c;
2622
2623 loop:
2624
2625 /* Skip white space. */
2626 while (*s < end && (c = *(*s)++, isspace (c)))
2627 ;
2628
2629 if (*s >= end)
2630 c = 0;
2631 else if (isdigit (c))
2632 {
2633 int value = 0, digit;
2634
2635 if (c == '0' && *s < end)
2636 {
2637 c = *(*s)++;
2638 if (c == 'x' || c == 'X')
2639 {
2640 while (*s < end)
2641 {
2642 c = *(*s)++;
2643 if (isdigit (c))
2644 digit = c - '0';
2645 else if (c >= 'a' && c <= 'f')
2646 digit = c - 'a' + 10;
2647 else if (c >= 'A' && c <= 'F')
2648 digit = c - 'A' + 10;
2649 else
2650 break;
2651 value = 16 * value + digit;
2652 }
2653 }
2654 else if (isdigit (c))
2655 {
2656 value = c - '0';
2657 while (*s < end
2658 && (c = *(*s)++, isdigit (c)))
2659 value = 8 * value + c - '0';
2660 }
2661 }
2662 else
2663 {
2664 value = c - '0';
2665 while (*s < end
2666 && (c = *(*s)++, isdigit (c)))
2667 value = 10 * value + c - '0';
2668 }
2669
2670 if (*s < end)
2671 *s = *s - 1;
2672 *ival = value;
2673 c = XBM_TK_NUMBER;
2674 }
2675 else if (isalpha (c) || c == '_')
2676 {
2677 *sval++ = c;
2678 while (*s < end
2679 && (c = *(*s)++, (isalnum (c) || c == '_')))
2680 *sval++ = c;
2681 *sval = 0;
2682 if (*s < end)
2683 *s = *s - 1;
2684 c = XBM_TK_IDENT;
2685 }
2686 else if (c == '/' && **s == '*')
2687 {
2688 /* C-style comment. */
2689 ++*s;
2690 while (**s && (**s != '*' || *(*s + 1) != '/'))
2691 ++*s;
2692 if (**s)
2693 {
2694 *s += 2;
2695 goto loop;
2696 }
2697 }
2698
2699 return c;
2700 }
2701
2702 #ifdef HAVE_NTGUI
2703
2704 /* Create a Windows bitmap from X bitmap data. */
2705 static HBITMAP
2706 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
2707 {
2708 static unsigned char swap_nibble[16]
2709 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
2710 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
2711 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
2712 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
2713 int i, j, w1, w2;
2714 unsigned char *bits, *p;
2715 HBITMAP bmp;
2716
2717 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
2718 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
2719 bits = (unsigned char *) alloca (height * w2);
2720 bzero (bits, height * w2);
2721 for (i = 0; i < height; i++)
2722 {
2723 p = bits + i*w2;
2724 for (j = 0; j < w1; j++)
2725 {
2726 /* Bitswap XBM bytes to match how Windows does things. */
2727 unsigned char c = *data++;
2728 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
2729 | (swap_nibble[(c>>4) & 0xf]));
2730 }
2731 }
2732 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
2733
2734 return bmp;
2735 }
2736
2737 static void convert_mono_to_color_image (f, img, foreground, background)
2738 struct frame *f;
2739 struct image *img;
2740 COLORREF foreground, background;
2741 {
2742 HDC hdc, old_img_dc, new_img_dc;
2743 HGDIOBJ old_prev, new_prev;
2744 HBITMAP new_pixmap;
2745
2746 hdc = get_frame_dc (f);
2747 old_img_dc = CreateCompatibleDC (hdc);
2748 new_img_dc = CreateCompatibleDC (hdc);
2749 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
2750 release_frame_dc (f, hdc);
2751 old_prev = SelectObject (old_img_dc, img->pixmap);
2752 new_prev = SelectObject (new_img_dc, new_pixmap);
2753 SetTextColor (new_img_dc, foreground);
2754 SetBkColor (new_img_dc, background);
2755
2756 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
2757 0, 0, SRCCOPY);
2758
2759 SelectObject (old_img_dc, old_prev);
2760 SelectObject (new_img_dc, new_prev);
2761 DeleteDC (old_img_dc);
2762 DeleteDC (new_img_dc);
2763 DeleteObject (img->pixmap);
2764 if (new_pixmap == 0)
2765 fprintf (stderr, "Failed to convert image to color.\n");
2766 else
2767 img->pixmap = new_pixmap;
2768 }
2769
2770 #define XBM_BIT_SHUFFLE(b) (~(b))
2771
2772 #else
2773
2774 #define XBM_BIT_SHUFFLE(b) (b)
2775
2776 #endif /* HAVE_NTGUI */
2777
2778
2779 static void
2780 Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
2781 struct frame *f;
2782 struct image *img;
2783 char *data;
2784 RGB_PIXEL_COLOR fg, bg;
2785 int non_default_colors;
2786 {
2787 #ifdef HAVE_NTGUI
2788 img->pixmap
2789 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
2790
2791 /* If colors were specified, transfer the bitmap to a color one. */
2792 if (non_default_colors)
2793 convert_mono_to_color_image (f, img, fg, bg);
2794 #else
2795 img->pixmap
2796 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
2797 FRAME_X_WINDOW (f),
2798 data,
2799 img->width, img->height,
2800 fg, bg,
2801 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
2802 #endif /* HAVE_NTGUI */
2803 }
2804
2805
2806
2807 /* Replacement for XReadBitmapFileData which isn't available under old
2808 X versions. CONTENTS is a pointer to a buffer to parse; END is the
2809 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
2810 the image. Return in *DATA the bitmap data allocated with xmalloc.
2811 Value is non-zero if successful. DATA null means just test if
2812 CONTENTS looks like an in-memory XBM file. */
2813
2814 static int
2815 xbm_read_bitmap_data (contents, end, width, height, data)
2816 unsigned char *contents, *end;
2817 int *width, *height;
2818 unsigned char **data;
2819 {
2820 unsigned char *s = contents;
2821 char buffer[BUFSIZ];
2822 int padding_p = 0;
2823 int v10 = 0;
2824 int bytes_per_line, i, nbytes;
2825 unsigned char *p;
2826 int value;
2827 int LA1;
2828
2829 #define match() \
2830 LA1 = xbm_scan (&s, end, buffer, &value)
2831
2832 #define expect(TOKEN) \
2833 if (LA1 != (TOKEN)) \
2834 goto failure; \
2835 else \
2836 match ()
2837
2838 #define expect_ident(IDENT) \
2839 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2840 match (); \
2841 else \
2842 goto failure
2843
2844 *width = *height = -1;
2845 if (data)
2846 *data = NULL;
2847 LA1 = xbm_scan (&s, end, buffer, &value);
2848
2849 /* Parse defines for width, height and hot-spots. */
2850 while (LA1 == '#')
2851 {
2852 match ();
2853 expect_ident ("define");
2854 expect (XBM_TK_IDENT);
2855
2856 if (LA1 == XBM_TK_NUMBER);
2857 {
2858 char *p = strrchr (buffer, '_');
2859 p = p ? p + 1 : buffer;
2860 if (strcmp (p, "width") == 0)
2861 *width = value;
2862 else if (strcmp (p, "height") == 0)
2863 *height = value;
2864 }
2865 expect (XBM_TK_NUMBER);
2866 }
2867
2868 if (*width < 0 || *height < 0)
2869 goto failure;
2870 else if (data == NULL)
2871 goto success;
2872
2873 /* Parse bits. Must start with `static'. */
2874 expect_ident ("static");
2875 if (LA1 == XBM_TK_IDENT)
2876 {
2877 if (strcmp (buffer, "unsigned") == 0)
2878 {
2879 match ();
2880 expect_ident ("char");
2881 }
2882 else if (strcmp (buffer, "short") == 0)
2883 {
2884 match ();
2885 v10 = 1;
2886 if (*width % 16 && *width % 16 < 9)
2887 padding_p = 1;
2888 }
2889 else if (strcmp (buffer, "char") == 0)
2890 match ();
2891 else
2892 goto failure;
2893 }
2894 else
2895 goto failure;
2896
2897 expect (XBM_TK_IDENT);
2898 expect ('[');
2899 expect (']');
2900 expect ('=');
2901 expect ('{');
2902
2903 bytes_per_line = (*width + 7) / 8 + padding_p;
2904 nbytes = bytes_per_line * *height;
2905 p = *data = (char *) xmalloc (nbytes);
2906
2907 if (v10)
2908 {
2909 for (i = 0; i < nbytes; i += 2)
2910 {
2911 int val = value;
2912 expect (XBM_TK_NUMBER);
2913
2914 *p++ = XBM_BIT_SHUFFLE (val);
2915 if (!padding_p || ((i + 2) % bytes_per_line))
2916 *p++ = XBM_BIT_SHUFFLE (value >> 8);
2917
2918 if (LA1 == ',' || LA1 == '}')
2919 match ();
2920 else
2921 goto failure;
2922 }
2923 }
2924 else
2925 {
2926 for (i = 0; i < nbytes; ++i)
2927 {
2928 int val = value;
2929 expect (XBM_TK_NUMBER);
2930
2931 *p++ = XBM_BIT_SHUFFLE (val);
2932
2933 if (LA1 == ',' || LA1 == '}')
2934 match ();
2935 else
2936 goto failure;
2937 }
2938 }
2939
2940 success:
2941 return 1;
2942
2943 failure:
2944
2945 if (data && *data)
2946 {
2947 xfree (*data);
2948 *data = NULL;
2949 }
2950 return 0;
2951
2952 #undef match
2953 #undef expect
2954 #undef expect_ident
2955 }
2956
2957
2958 /* Load XBM image IMG which will be displayed on frame F from buffer
2959 CONTENTS. END is the end of the buffer. Value is non-zero if
2960 successful. */
2961
2962 static int
2963 xbm_load_image (f, img, contents, end)
2964 struct frame *f;
2965 struct image *img;
2966 unsigned char *contents, *end;
2967 {
2968 int rc;
2969 unsigned char *data;
2970 int success_p = 0;
2971
2972 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
2973 if (rc)
2974 {
2975 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
2976 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
2977 int non_default_colors = 0;
2978 Lisp_Object value;
2979
2980 xassert (img->width > 0 && img->height > 0);
2981
2982 /* Get foreground and background colors, maybe allocate colors. */
2983 value = image_spec_value (img->spec, QCforeground, NULL);
2984 if (!NILP (value))
2985 {
2986 foreground = x_alloc_image_color (f, img, value, foreground);
2987 non_default_colors = 1;
2988 }
2989 value = image_spec_value (img->spec, QCbackground, NULL);
2990 if (!NILP (value))
2991 {
2992 background = x_alloc_image_color (f, img, value, background);
2993 img->background = background;
2994 img->background_valid = 1;
2995 non_default_colors = 1;
2996 }
2997
2998 Create_Pixmap_From_Bitmap_Data (f, img, data,
2999 foreground, background,
3000 non_default_colors);
3001 xfree (data);
3002
3003 if (img->pixmap == NO_PIXMAP)
3004 {
3005 x_clear_image (f, img);
3006 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3007 }
3008 else
3009 success_p = 1;
3010 }
3011 else
3012 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3013
3014 return success_p;
3015 }
3016
3017
3018 /* Value is non-zero if DATA looks like an in-memory XBM file. */
3019
3020 static int
3021 xbm_file_p (data)
3022 Lisp_Object data;
3023 {
3024 int w, h;
3025 return (STRINGP (data)
3026 && xbm_read_bitmap_data (SDATA (data),
3027 (SDATA (data)
3028 + SBYTES (data)),
3029 &w, &h, NULL));
3030 }
3031
3032
3033 /* Fill image IMG which is used on frame F with pixmap data. Value is
3034 non-zero if successful. */
3035
3036 static int
3037 xbm_load (f, img)
3038 struct frame *f;
3039 struct image *img;
3040 {
3041 int success_p = 0;
3042 Lisp_Object file_name;
3043
3044 xassert (xbm_image_p (img->spec));
3045
3046 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3047 file_name = image_spec_value (img->spec, QCfile, NULL);
3048 if (STRINGP (file_name))
3049 {
3050 Lisp_Object file;
3051 unsigned char *contents;
3052 int size;
3053 struct gcpro gcpro1;
3054
3055 file = x_find_image_file (file_name);
3056 GCPRO1 (file);
3057 if (!STRINGP (file))
3058 {
3059 image_error ("Cannot find image file `%s'", file_name, Qnil);
3060 UNGCPRO;
3061 return 0;
3062 }
3063
3064 contents = slurp_file (SDATA (file), &size);
3065 if (contents == NULL)
3066 {
3067 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3068 UNGCPRO;
3069 return 0;
3070 }
3071
3072 success_p = xbm_load_image (f, img, contents, contents + size);
3073 UNGCPRO;
3074 }
3075 else
3076 {
3077 struct image_keyword fmt[XBM_LAST];
3078 Lisp_Object data;
3079 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3080 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3081 int non_default_colors = 0;
3082 char *bits;
3083 int parsed_p;
3084 int in_memory_file_p = 0;
3085
3086 /* See if data looks like an in-memory XBM file. */
3087 data = image_spec_value (img->spec, QCdata, NULL);
3088 in_memory_file_p = xbm_file_p (data);
3089
3090 /* Parse the image specification. */
3091 bcopy (xbm_format, fmt, sizeof fmt);
3092 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3093 xassert (parsed_p);
3094
3095 /* Get specified width, and height. */
3096 if (!in_memory_file_p)
3097 {
3098 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3099 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3100 xassert (img->width > 0 && img->height > 0);
3101 }
3102
3103 /* Get foreground and background colors, maybe allocate colors. */
3104 if (fmt[XBM_FOREGROUND].count
3105 && STRINGP (fmt[XBM_FOREGROUND].value))
3106 {
3107 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3108 foreground);
3109 non_default_colors = 1;
3110 }
3111
3112 if (fmt[XBM_BACKGROUND].count
3113 && STRINGP (fmt[XBM_BACKGROUND].value))
3114 {
3115 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3116 background);
3117 non_default_colors = 1;
3118 }
3119
3120 if (in_memory_file_p)
3121 success_p = xbm_load_image (f, img, SDATA (data),
3122 (SDATA (data)
3123 + SBYTES (data)));
3124 else
3125 {
3126 if (VECTORP (data))
3127 {
3128 int i;
3129 char *p;
3130 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3131
3132 p = bits = (char *) alloca (nbytes * img->height);
3133 for (i = 0; i < img->height; ++i, p += nbytes)
3134 {
3135 Lisp_Object line = XVECTOR (data)->contents[i];
3136 if (STRINGP (line))
3137 bcopy (SDATA (line), p, nbytes);
3138 else
3139 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3140 }
3141 }
3142 else if (STRINGP (data))
3143 bits = SDATA (data);
3144 else
3145 bits = XBOOL_VECTOR (data)->data;
3146
3147 /* Create the pixmap. */
3148
3149 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3150 foreground, background,
3151 non_default_colors);
3152 if (img->pixmap)
3153 success_p = 1;
3154 else
3155 {
3156 image_error ("Unable to create pixmap for XBM image `%s'",
3157 img->spec, Qnil);
3158 x_clear_image (f, img);
3159 }
3160 }
3161 }
3162
3163 return success_p;
3164 }
3165
3166
3167 \f
3168 /***********************************************************************
3169 XPM images
3170 ***********************************************************************/
3171
3172 #ifdef HAVE_XPM
3173
3174 static int xpm_image_p P_ ((Lisp_Object object));
3175 static int xpm_load P_ ((struct frame *f, struct image *img));
3176 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3177
3178 #ifdef HAVE_NTGUI
3179 /* Indicate to xpm.h that we don't have Xlib. */
3180 #define FOR_MSW
3181 /* simx.h in xpm defines XColor and XImage differently than Emacs. */
3182 /* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
3183 #define XColor xpm_XColor
3184 #define XImage xpm_XImage
3185 #define Display xpm_Display
3186 #define PIXEL_ALREADY_TYPEDEFED
3187 #include "X11/xpm.h"
3188 #undef FOR_MSW
3189 #undef XColor
3190 #undef XImage
3191 #undef Display
3192 #undef PIXEL_ALREADY_TYPEDEFED
3193 #else
3194 #include "X11/xpm.h"
3195 #endif /* HAVE_NTGUI */
3196
3197 /* The symbol `xpm' identifying XPM-format images. */
3198
3199 Lisp_Object Qxpm;
3200
3201 /* Indices of image specification fields in xpm_format, below. */
3202
3203 enum xpm_keyword_index
3204 {
3205 XPM_TYPE,
3206 XPM_FILE,
3207 XPM_DATA,
3208 XPM_ASCENT,
3209 XPM_MARGIN,
3210 XPM_RELIEF,
3211 XPM_ALGORITHM,
3212 XPM_HEURISTIC_MASK,
3213 XPM_MASK,
3214 XPM_COLOR_SYMBOLS,
3215 XPM_BACKGROUND,
3216 XPM_LAST
3217 };
3218
3219 /* Vector of image_keyword structures describing the format
3220 of valid XPM image specifications. */
3221
3222 static struct image_keyword xpm_format[XPM_LAST] =
3223 {
3224 {":type", IMAGE_SYMBOL_VALUE, 1},
3225 {":file", IMAGE_STRING_VALUE, 0},
3226 {":data", IMAGE_STRING_VALUE, 0},
3227 {":ascent", IMAGE_ASCENT_VALUE, 0},
3228 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3229 {":relief", IMAGE_INTEGER_VALUE, 0},
3230 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3231 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3232 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3233 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3234 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3235 };
3236
3237 /* Structure describing the image type XPM. */
3238
3239 static struct image_type xpm_type =
3240 {
3241 &Qxpm,
3242 xpm_image_p,
3243 xpm_load,
3244 x_clear_image,
3245 NULL
3246 };
3247
3248 #ifdef HAVE_X_WINDOWS
3249
3250 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3251 functions for allocating image colors. Our own functions handle
3252 color allocation failures more gracefully than the ones on the XPM
3253 lib. */
3254
3255 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3256 #define ALLOC_XPM_COLORS
3257 #endif
3258 #endif /* HAVE_X_WINDOWS */
3259
3260 #ifdef ALLOC_XPM_COLORS
3261
3262 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3263 static void xpm_free_color_cache P_ ((void));
3264 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3265 static int xpm_color_bucket P_ ((char *));
3266 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3267 XColor *, int));
3268
3269 /* An entry in a hash table used to cache color definitions of named
3270 colors. This cache is necessary to speed up XPM image loading in
3271 case we do color allocations ourselves. Without it, we would need
3272 a call to XParseColor per pixel in the image. */
3273
3274 struct xpm_cached_color
3275 {
3276 /* Next in collision chain. */
3277 struct xpm_cached_color *next;
3278
3279 /* Color definition (RGB and pixel color). */
3280 XColor color;
3281
3282 /* Color name. */
3283 char name[1];
3284 };
3285
3286 /* The hash table used for the color cache, and its bucket vector
3287 size. */
3288
3289 #define XPM_COLOR_CACHE_BUCKETS 1001
3290 struct xpm_cached_color **xpm_color_cache;
3291
3292 /* Initialize the color cache. */
3293
3294 static void
3295 xpm_init_color_cache (f, attrs)
3296 struct frame *f;
3297 XpmAttributes *attrs;
3298 {
3299 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3300 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3301 memset (xpm_color_cache, 0, nbytes);
3302 init_color_table ();
3303
3304 if (attrs->valuemask & XpmColorSymbols)
3305 {
3306 int i;
3307 XColor color;
3308
3309 for (i = 0; i < attrs->numsymbols; ++i)
3310 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3311 attrs->colorsymbols[i].value, &color))
3312 {
3313 color.pixel = lookup_rgb_color (f, color.red, color.green,
3314 color.blue);
3315 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3316 }
3317 }
3318 }
3319
3320 /* Free the color cache. */
3321
3322 static void
3323 xpm_free_color_cache ()
3324 {
3325 struct xpm_cached_color *p, *next;
3326 int i;
3327
3328 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3329 for (p = xpm_color_cache[i]; p; p = next)
3330 {
3331 next = p->next;
3332 xfree (p);
3333 }
3334
3335 xfree (xpm_color_cache);
3336 xpm_color_cache = NULL;
3337 free_color_table ();
3338 }
3339
3340 /* Return the bucket index for color named COLOR_NAME in the color
3341 cache. */
3342
3343 static int
3344 xpm_color_bucket (color_name)
3345 char *color_name;
3346 {
3347 unsigned h = 0;
3348 char *s;
3349
3350 for (s = color_name; *s; ++s)
3351 h = (h << 2) ^ *s;
3352 return h %= XPM_COLOR_CACHE_BUCKETS;
3353 }
3354
3355
3356 /* On frame F, cache values COLOR for color with name COLOR_NAME.
3357 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3358 entry added. */
3359
3360 static struct xpm_cached_color *
3361 xpm_cache_color (f, color_name, color, bucket)
3362 struct frame *f;
3363 char *color_name;
3364 XColor *color;
3365 int bucket;
3366 {
3367 size_t nbytes;
3368 struct xpm_cached_color *p;
3369
3370 if (bucket < 0)
3371 bucket = xpm_color_bucket (color_name);
3372
3373 nbytes = sizeof *p + strlen (color_name);
3374 p = (struct xpm_cached_color *) xmalloc (nbytes);
3375 strcpy (p->name, color_name);
3376 p->color = *color;
3377 p->next = xpm_color_cache[bucket];
3378 xpm_color_cache[bucket] = p;
3379 return p;
3380 }
3381
3382 /* Look up color COLOR_NAME for frame F in the color cache. If found,
3383 return the cached definition in *COLOR. Otherwise, make a new
3384 entry in the cache and allocate the color. Value is zero if color
3385 allocation failed. */
3386
3387 static int
3388 xpm_lookup_color (f, color_name, color)
3389 struct frame *f;
3390 char *color_name;
3391 XColor *color;
3392 {
3393 struct xpm_cached_color *p;
3394 int h = xpm_color_bucket (color_name);
3395
3396 for (p = xpm_color_cache[h]; p; p = p->next)
3397 if (strcmp (p->name, color_name) == 0)
3398 break;
3399
3400 if (p != NULL)
3401 *color = p->color;
3402 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3403 color_name, color))
3404 {
3405 color->pixel = lookup_rgb_color (f, color->red, color->green,
3406 color->blue);
3407 p = xpm_cache_color (f, color_name, color, h);
3408 }
3409 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3410 with transparency, and it's useful. */
3411 else if (strcmp ("opaque", color_name) == 0)
3412 {
3413 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3414 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3415 p = xpm_cache_color (f, color_name, color, h);
3416 }
3417
3418 return p != NULL;
3419 }
3420
3421
3422 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3423 CLOSURE is a pointer to the frame on which we allocate the
3424 color. Return in *COLOR the allocated color. Value is non-zero
3425 if successful. */
3426
3427 static int
3428 xpm_alloc_color (dpy, cmap, color_name, color, closure)
3429 Display *dpy;
3430 Colormap cmap;
3431 char *color_name;
3432 XColor *color;
3433 void *closure;
3434 {
3435 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3436 }
3437
3438
3439 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3440 is a pointer to the frame on which we allocate the color. Value is
3441 non-zero if successful. */
3442
3443 static int
3444 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3445 Display *dpy;
3446 Colormap cmap;
3447 Pixel *pixels;
3448 int npixels;
3449 void *closure;
3450 {
3451 return 1;
3452 }
3453
3454 #endif /* ALLOC_XPM_COLORS */
3455
3456
3457 #ifdef HAVE_NTGUI
3458
3459 /* XPM library details. */
3460
3461 DEF_IMGLIB_FN (XpmFreeAttributes);
3462 DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3463 DEF_IMGLIB_FN (XpmReadFileToImage);
3464 DEF_IMGLIB_FN (XImageFree);
3465
3466
3467 static int
3468 init_xpm_functions (void)
3469 {
3470 HMODULE library;
3471
3472 if (!(library = LoadLibrary ("libXpm.dll")))
3473 return 0;
3474
3475 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3476 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3477 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3478 LOAD_IMGLIB_FN (library, XImageFree);
3479 return 1;
3480 }
3481
3482 #endif /* HAVE_NTGUI */
3483
3484
3485 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3486 for XPM images. Such a list must consist of conses whose car and
3487 cdr are strings. */
3488
3489 static int
3490 xpm_valid_color_symbols_p (color_symbols)
3491 Lisp_Object color_symbols;
3492 {
3493 while (CONSP (color_symbols))
3494 {
3495 Lisp_Object sym = XCAR (color_symbols);
3496 if (!CONSP (sym)
3497 || !STRINGP (XCAR (sym))
3498 || !STRINGP (XCDR (sym)))
3499 break;
3500 color_symbols = XCDR (color_symbols);
3501 }
3502
3503 return NILP (color_symbols);
3504 }
3505
3506
3507 /* Value is non-zero if OBJECT is a valid XPM image specification. */
3508
3509 static int
3510 xpm_image_p (object)
3511 Lisp_Object object;
3512 {
3513 struct image_keyword fmt[XPM_LAST];
3514 bcopy (xpm_format, fmt, sizeof fmt);
3515 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3516 /* Either `:file' or `:data' must be present. */
3517 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3518 /* Either no `:color-symbols' or it's a list of conses
3519 whose car and cdr are strings. */
3520 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3521 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3522 }
3523
3524
3525 /* Load image IMG which will be displayed on frame F. Value is
3526 non-zero if successful. */
3527
3528 static int
3529 xpm_load (f, img)
3530 struct frame *f;
3531 struct image *img;
3532 {
3533 int rc;
3534 XpmAttributes attrs;
3535 Lisp_Object specified_file, color_symbols;
3536 #ifdef HAVE_NTGUI
3537 HDC hdc;
3538 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3539 #endif /* HAVE_NTGUI */
3540
3541 /* Configure the XPM lib. Use the visual of frame F. Allocate
3542 close colors. Return colors allocated. */
3543 bzero (&attrs, sizeof attrs);
3544
3545 #ifndef HAVE_NTGUI
3546 attrs.visual = FRAME_X_VISUAL (f);
3547 attrs.colormap = FRAME_X_COLORMAP (f);
3548 attrs.valuemask |= XpmVisual;
3549 attrs.valuemask |= XpmColormap;
3550 #endif /* HAVE_NTGUI */
3551
3552 #ifdef ALLOC_XPM_COLORS
3553 /* Allocate colors with our own functions which handle
3554 failing color allocation more gracefully. */
3555 attrs.color_closure = f;
3556 attrs.alloc_color = xpm_alloc_color;
3557 attrs.free_colors = xpm_free_colors;
3558 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3559 #else /* not ALLOC_XPM_COLORS */
3560 /* Let the XPM lib allocate colors. */
3561 attrs.valuemask |= XpmReturnAllocPixels;
3562 #ifdef XpmAllocCloseColors
3563 attrs.alloc_close_colors = 1;
3564 attrs.valuemask |= XpmAllocCloseColors;
3565 #else /* not XpmAllocCloseColors */
3566 attrs.closeness = 600;
3567 attrs.valuemask |= XpmCloseness;
3568 #endif /* not XpmAllocCloseColors */
3569 #endif /* ALLOC_XPM_COLORS */
3570
3571 /* If image specification contains symbolic color definitions, add
3572 these to `attrs'. */
3573 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3574 if (CONSP (color_symbols))
3575 {
3576 Lisp_Object tail;
3577 XpmColorSymbol *xpm_syms;
3578 int i, size;
3579
3580 attrs.valuemask |= XpmColorSymbols;
3581
3582 /* Count number of symbols. */
3583 attrs.numsymbols = 0;
3584 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3585 ++attrs.numsymbols;
3586
3587 /* Allocate an XpmColorSymbol array. */
3588 size = attrs.numsymbols * sizeof *xpm_syms;
3589 xpm_syms = (XpmColorSymbol *) alloca (size);
3590 bzero (xpm_syms, size);
3591 attrs.colorsymbols = xpm_syms;
3592
3593 /* Fill the color symbol array. */
3594 for (tail = color_symbols, i = 0;
3595 CONSP (tail);
3596 ++i, tail = XCDR (tail))
3597 {
3598 Lisp_Object name = XCAR (XCAR (tail));
3599 Lisp_Object color = XCDR (XCAR (tail));
3600 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3601 strcpy (xpm_syms[i].name, SDATA (name));
3602 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3603 strcpy (xpm_syms[i].value, SDATA (color));
3604 }
3605 }
3606
3607 /* Create a pixmap for the image, either from a file, or from a
3608 string buffer containing data in the same format as an XPM file. */
3609 #ifdef ALLOC_XPM_COLORS
3610 xpm_init_color_cache (f, &attrs);
3611 #endif
3612
3613 specified_file = image_spec_value (img->spec, QCfile, NULL);
3614
3615 #ifdef HAVE_NTGUI
3616 {
3617 HDC frame_dc = get_frame_dc (f);
3618 hdc = CreateCompatibleDC (frame_dc);
3619 release_frame_dc (f, frame_dc);
3620 }
3621 #endif /* HAVE_NTGUI */
3622
3623 if (STRINGP (specified_file))
3624 {
3625 Lisp_Object file = x_find_image_file (specified_file);
3626 if (!STRINGP (file))
3627 {
3628 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3629 return 0;
3630 }
3631
3632 #ifdef HAVE_NTGUI
3633 /* XpmReadFileToPixmap is not available in the Windows port of
3634 libxpm. But XpmReadFileToImage almost does what we want. */
3635 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3636 &xpm_image, &xpm_mask,
3637 &attrs);
3638 #else
3639 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3640 SDATA (file), &img->pixmap, &img->mask,
3641 &attrs);
3642 #endif /* HAVE_NTGUI */
3643 }
3644 else
3645 {
3646 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3647 #ifdef HAVE_NTGUI
3648 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3649 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3650 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3651 &xpm_image, &xpm_mask,
3652 &attrs);
3653 #else
3654 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3655 SDATA (buffer),
3656 &img->pixmap, &img->mask,
3657 &attrs);
3658 #endif /* HAVE_NTGUI */
3659 }
3660
3661 if (rc == XpmSuccess)
3662 {
3663 #if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3664 img->colors = colors_in_color_table (&img->ncolors);
3665 #else /* not ALLOC_XPM_COLORS */
3666 int i;
3667
3668 #ifdef HAVE_NTGUI
3669 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3670 plus some duplicate attributes. */
3671 if (xpm_image && xpm_image->bitmap)
3672 {
3673 img->pixmap = xpm_image->bitmap;
3674 /* XImageFree in libXpm frees XImage struct without destroying
3675 the bitmap, which is what we want. */
3676 fn_XImageFree (xpm_image);
3677 }
3678 if (xpm_mask && xpm_mask->bitmap)
3679 {
3680 /* The mask appears to be inverted compared with what we expect.
3681 TODO: invert our expectations. See other places where we
3682 have to invert bits because our idea of masks is backwards. */
3683 HGDIOBJ old_obj;
3684 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3685
3686 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3687 SelectObject (hdc, old_obj);
3688
3689 img->mask = xpm_mask->bitmap;
3690 fn_XImageFree (xpm_mask);
3691 DeleteDC (hdc);
3692 }
3693
3694 DeleteDC (hdc);
3695 #endif /* HAVE_NTGUI */
3696
3697 /* Remember allocated colors. */
3698 img->ncolors = attrs.nalloc_pixels;
3699 img->colors = (unsigned long *) xmalloc (img->ncolors
3700 * sizeof *img->colors);
3701 for (i = 0; i < attrs.nalloc_pixels; ++i)
3702 {
3703 img->colors[i] = attrs.alloc_pixels[i];
3704 #ifdef DEBUG_X_COLORS
3705 register_color (img->colors[i]);
3706 #endif
3707 }
3708 #endif /* not ALLOC_XPM_COLORS */
3709
3710 img->width = attrs.width;
3711 img->height = attrs.height;
3712 xassert (img->width > 0 && img->height > 0);
3713
3714 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3715 #ifdef HAVE_NTGUI
3716 fn_XpmFreeAttributes (&attrs);
3717 #else
3718 XpmFreeAttributes (&attrs);
3719 #endif /* HAVE_NTGUI */
3720 }
3721 else
3722 {
3723 #ifdef HAVE_NTGUI
3724 DeleteDC (hdc);
3725 #endif /* HAVE_NTGUI */
3726
3727 switch (rc)
3728 {
3729 case XpmOpenFailed:
3730 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3731 break;
3732
3733 case XpmFileInvalid:
3734 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3735 break;
3736
3737 case XpmNoMemory:
3738 image_error ("Out of memory (%s)", img->spec, Qnil);
3739 break;
3740
3741 case XpmColorFailed:
3742 image_error ("Color allocation error (%s)", img->spec, Qnil);
3743 break;
3744
3745 default:
3746 image_error ("Unknown error (%s)", img->spec, Qnil);
3747 break;
3748 }
3749 }
3750
3751 #ifdef ALLOC_XPM_COLORS
3752 xpm_free_color_cache ();
3753 #endif
3754 return rc == XpmSuccess;
3755 }
3756
3757 #endif /* HAVE_XPM */
3758
3759 \f
3760 /***********************************************************************
3761 Color table
3762 ***********************************************************************/
3763
3764 #ifdef COLOR_TABLE_SUPPORT
3765
3766 /* An entry in the color table mapping an RGB color to a pixel color. */
3767
3768 struct ct_color
3769 {
3770 int r, g, b;
3771 unsigned long pixel;
3772
3773 /* Next in color table collision list. */
3774 struct ct_color *next;
3775 };
3776
3777 /* The bucket vector size to use. Must be prime. */
3778
3779 #define CT_SIZE 101
3780
3781 /* Value is a hash of the RGB color given by R, G, and B. */
3782
3783 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
3784
3785 /* The color hash table. */
3786
3787 struct ct_color **ct_table;
3788
3789 /* Number of entries in the color table. */
3790
3791 int ct_colors_allocated;
3792
3793 /* Initialize the color table. */
3794
3795 static void
3796 init_color_table ()
3797 {
3798 int size = CT_SIZE * sizeof (*ct_table);
3799 ct_table = (struct ct_color **) xmalloc (size);
3800 bzero (ct_table, size);
3801 ct_colors_allocated = 0;
3802 }
3803
3804
3805 /* Free memory associated with the color table. */
3806
3807 static void
3808 free_color_table ()
3809 {
3810 int i;
3811 struct ct_color *p, *next;
3812
3813 for (i = 0; i < CT_SIZE; ++i)
3814 for (p = ct_table[i]; p; p = next)
3815 {
3816 next = p->next;
3817 xfree (p);
3818 }
3819
3820 xfree (ct_table);
3821 ct_table = NULL;
3822 }
3823
3824
3825 /* Value is a pixel color for RGB color R, G, B on frame F. If an
3826 entry for that color already is in the color table, return the
3827 pixel color of that entry. Otherwise, allocate a new color for R,
3828 G, B, and make an entry in the color table. */
3829
3830 static unsigned long
3831 lookup_rgb_color (f, r, g, b)
3832 struct frame *f;
3833 int r, g, b;
3834 {
3835 unsigned hash = CT_HASH_RGB (r, g, b);
3836 int i = hash % CT_SIZE;
3837 struct ct_color *p;
3838 Display_Info *dpyinfo;
3839
3840 /* Handle TrueColor visuals specially, which improves performance by
3841 two orders of magnitude. Freeing colors on TrueColor visuals is
3842 a nop, and pixel colors specify RGB values directly. See also
3843 the Xlib spec, chapter 3.1. */
3844 dpyinfo = FRAME_X_DISPLAY_INFO (f);
3845 if (dpyinfo->red_bits > 0)
3846 {
3847 unsigned long pr, pg, pb;
3848
3849 /* Apply gamma-correction like normal color allocation does. */
3850 if (f->gamma)
3851 {
3852 XColor color;
3853 color.red = r, color.green = g, color.blue = b;
3854 gamma_correct (f, &color);
3855 r = color.red, g = color.green, b = color.blue;
3856 }
3857
3858 /* Scale down RGB values to the visual's bits per RGB, and shift
3859 them to the right position in the pixel color. Note that the
3860 original RGB values are 16-bit values, as usual in X. */
3861 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
3862 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
3863 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
3864
3865 /* Assemble the pixel color. */
3866 return pr | pg | pb;
3867 }
3868
3869 for (p = ct_table[i]; p; p = p->next)
3870 if (p->r == r && p->g == g && p->b == b)
3871 break;
3872
3873 if (p == NULL)
3874 {
3875
3876 #ifdef HAVE_X_WINDOWS
3877 XColor color;
3878 Colormap cmap;
3879 int rc;
3880
3881 color.red = r;
3882 color.green = g;
3883 color.blue = b;
3884
3885 cmap = FRAME_X_COLORMAP (f);
3886 rc = x_alloc_nearest_color (f, cmap, &color);
3887 if (rc)
3888 {
3889 ++ct_colors_allocated;
3890 p = (struct ct_color *) xmalloc (sizeof *p);
3891 p->r = r;
3892 p->g = g;
3893 p->b = b;
3894 p->pixel = color.pixel;
3895 p->next = ct_table[i];
3896 ct_table[i] = p;
3897 }
3898 else
3899 return FRAME_FOREGROUND_PIXEL (f);
3900
3901 #else
3902 COLORREF color;
3903 #ifdef HAVE_NTGUI
3904 color = PALETTERGB (r, g, b);
3905 #else
3906 color = RGB_TO_ULONG (r, g, b);
3907 #endif /* HAVE_NTGUI */
3908 ++ct_colors_allocated;
3909 p = (struct ct_color *) xmalloc (sizeof *p);
3910 p->r = r;
3911 p->g = g;
3912 p->b = b;
3913 p->pixel = color;
3914 p->next = ct_table[i];
3915 ct_table[i] = p;
3916 #endif /* HAVE_X_WINDOWS */
3917
3918 }
3919
3920 return p->pixel;
3921 }
3922
3923
3924 /* Look up pixel color PIXEL which is used on frame F in the color
3925 table. If not already present, allocate it. Value is PIXEL. */
3926
3927 static unsigned long
3928 lookup_pixel_color (f, pixel)
3929 struct frame *f;
3930 unsigned long pixel;
3931 {
3932 int i = pixel % CT_SIZE;
3933 struct ct_color *p;
3934
3935 for (p = ct_table[i]; p; p = p->next)
3936 if (p->pixel == pixel)
3937 break;
3938
3939 if (p == NULL)
3940 {
3941 XColor color;
3942 Colormap cmap;
3943 int rc;
3944
3945 #ifdef HAVE_X_WINDOWS
3946 cmap = FRAME_X_COLORMAP (f);
3947 color.pixel = pixel;
3948 x_query_color (f, &color);
3949 rc = x_alloc_nearest_color (f, cmap, &color);
3950 #else
3951 BLOCK_INPUT;
3952 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
3953 color.pixel = pixel;
3954 XQueryColor (NULL, cmap, &color);
3955 rc = x_alloc_nearest_color (f, cmap, &color);
3956 UNBLOCK_INPUT;
3957 #endif /* HAVE_X_WINDOWS */
3958
3959 if (rc)
3960 {
3961 ++ct_colors_allocated;
3962
3963 p = (struct ct_color *) xmalloc (sizeof *p);
3964 p->r = color.red;
3965 p->g = color.green;
3966 p->b = color.blue;
3967 p->pixel = pixel;
3968 p->next = ct_table[i];
3969 ct_table[i] = p;
3970 }
3971 else
3972 return FRAME_FOREGROUND_PIXEL (f);
3973 }
3974 return p->pixel;
3975 }
3976
3977
3978 /* Value is a vector of all pixel colors contained in the color table,
3979 allocated via xmalloc. Set *N to the number of colors. */
3980
3981 static unsigned long *
3982 colors_in_color_table (n)
3983 int *n;
3984 {
3985 int i, j;
3986 struct ct_color *p;
3987 unsigned long *colors;
3988
3989 if (ct_colors_allocated == 0)
3990 {
3991 *n = 0;
3992 colors = NULL;
3993 }
3994 else
3995 {
3996 colors = (unsigned long *) xmalloc (ct_colors_allocated
3997 * sizeof *colors);
3998 *n = ct_colors_allocated;
3999
4000 for (i = j = 0; i < CT_SIZE; ++i)
4001 for (p = ct_table[i]; p; p = p->next)
4002 colors[j++] = p->pixel;
4003 }
4004
4005 return colors;
4006 }
4007
4008 #else /* COLOR_TABLE_SUPPORT */
4009
4010 static unsigned long
4011 lookup_rgb_color (f, r, g, b)
4012 struct frame *f;
4013 int r, g, b;
4014 {
4015 unsigned long pixel;
4016
4017 #ifdef MAC_OS
4018 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4019 gamma_correct (f, &pixel);
4020 #endif /* MAC_OS */
4021
4022 #ifdef HAVE_NTGUI
4023 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4024 #endif /* HAVE_NTGUI */
4025
4026 return pixel;
4027 }
4028
4029 static void
4030 init_color_table ()
4031 {
4032 }
4033 #endif /* COLOR_TABLE_SUPPORT */
4034
4035 \f
4036 /***********************************************************************
4037 Algorithms
4038 ***********************************************************************/
4039
4040 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4041 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4042 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4043
4044 #ifdef HAVE_NTGUI
4045 static void XPutPixel (XImagePtr , int, int, COLORREF);
4046 #endif /* HAVE_NTGUI */
4047
4048 /* Non-zero means draw a cross on images having `:conversion
4049 disabled'. */
4050
4051 int cross_disabled_images;
4052
4053 /* Edge detection matrices for different edge-detection
4054 strategies. */
4055
4056 static int emboss_matrix[9] = {
4057 /* x - 1 x x + 1 */
4058 2, -1, 0, /* y - 1 */
4059 -1, 0, 1, /* y */
4060 0, 1, -2 /* y + 1 */
4061 };
4062
4063 static int laplace_matrix[9] = {
4064 /* x - 1 x x + 1 */
4065 1, 0, 0, /* y - 1 */
4066 0, 0, 0, /* y */
4067 0, 0, -1 /* y + 1 */
4068 };
4069
4070 /* Value is the intensity of the color whose red/green/blue values
4071 are R, G, and B. */
4072
4073 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4074
4075
4076 /* On frame F, return an array of XColor structures describing image
4077 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4078 non-zero means also fill the red/green/blue members of the XColor
4079 structures. Value is a pointer to the array of XColors structures,
4080 allocated with xmalloc; it must be freed by the caller. */
4081
4082 static XColor *
4083 x_to_xcolors (f, img, rgb_p)
4084 struct frame *f;
4085 struct image *img;
4086 int rgb_p;
4087 {
4088 int x, y;
4089 XColor *colors, *p;
4090 XImagePtr_or_DC ximg;
4091 #ifdef HAVE_NTGUI
4092 HDC hdc;
4093 HGDIOBJ prev;
4094 #endif /* HAVE_NTGUI */
4095
4096 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4097
4098 #ifndef HAVE_NTGUI
4099 /* Get the X image IMG->pixmap. */
4100 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4101 0, 0, img->width, img->height, ~0, ZPixmap);
4102 #else
4103 /* Load the image into a memory device context. */
4104 hdc = get_frame_dc (f);
4105 ximg = CreateCompatibleDC (hdc);
4106 release_frame_dc (f, hdc);
4107 prev = SelectObject (ximg, img->pixmap);
4108 #endif /* HAVE_NTGUI */
4109
4110 /* Fill the `pixel' members of the XColor array. I wished there
4111 were an easy and portable way to circumvent XGetPixel. */
4112 p = colors;
4113 for (y = 0; y < img->height; ++y)
4114 {
4115 XColor *row = p;
4116
4117 #ifdef HAVE_X_WINDOWS
4118 for (x = 0; x < img->width; ++x, ++p)
4119 p->pixel = XGetPixel (ximg, x, y);
4120 if (rgb_p)
4121 x_query_colors (f, row, img->width);
4122
4123 #else
4124
4125 for (x = 0; x < img->width; ++x, ++p)
4126 {
4127 /* W32_TODO: palette support needed here? */
4128 p->pixel = GET_PIXEL (ximg, x, y);
4129 if (rgb_p)
4130 {
4131 #ifdef MAC_OS
4132 p->red = RED16_FROM_ULONG (p->pixel);
4133 p->green = GREEN16_FROM_ULONG (p->pixel);
4134 p->blue = BLUE16_FROM_ULONG (p->pixel);
4135 #endif /* MAC_OS */
4136 #ifdef HAVE_NTGUI
4137 p->red = 256 * GetRValue (p->pixel);
4138 p->green = 256 * GetGValue (p->pixel);
4139 p->blue = 256 * GetBValue (p->pixel);
4140 #endif /* HAVE_NTGUI */
4141 }
4142 }
4143 #endif /* HAVE_X_WINDOWS */
4144 }
4145
4146 Destroy_Image (ximg, prev);
4147
4148 return colors;
4149 }
4150
4151 #ifdef HAVE_NTGUI
4152
4153 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4154 created with CreateDIBSection, with the pointer to the bit values
4155 stored in ximg->data. */
4156
4157 static void XPutPixel (ximg, x, y, color)
4158 XImagePtr ximg;
4159 int x, y;
4160 COLORREF color;
4161 {
4162 int width = ximg->info.bmiHeader.biWidth;
4163 int height = ximg->info.bmiHeader.biHeight;
4164 unsigned char * pixel;
4165
4166 /* True color images. */
4167 if (ximg->info.bmiHeader.biBitCount == 24)
4168 {
4169 int rowbytes = width * 3;
4170 /* Ensure scanlines are aligned on 4 byte boundaries. */
4171 if (rowbytes % 4)
4172 rowbytes += 4 - (rowbytes % 4);
4173
4174 pixel = ximg->data + y * rowbytes + x * 3;
4175 /* Windows bitmaps are in BGR order. */
4176 *pixel = GetBValue (color);
4177 *(pixel + 1) = GetGValue (color);
4178 *(pixel + 2) = GetRValue (color);
4179 }
4180 /* Monochrome images. */
4181 else if (ximg->info.bmiHeader.biBitCount == 1)
4182 {
4183 int rowbytes = width / 8;
4184 /* Ensure scanlines are aligned on 4 byte boundaries. */
4185 if (rowbytes % 4)
4186 rowbytes += 4 - (rowbytes % 4);
4187 pixel = ximg->data + y * rowbytes + x / 8;
4188 /* Filter out palette info. */
4189 if (color & 0x00ffffff)
4190 *pixel = *pixel | (1 << x % 8);
4191 else
4192 *pixel = *pixel & ~(1 << x % 8);
4193 }
4194 else
4195 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4196 }
4197
4198 #endif /* HAVE_NTGUI */
4199
4200 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
4201 RGB members are set. F is the frame on which this all happens.
4202 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4203
4204 static void
4205 x_from_xcolors (f, img, colors)
4206 struct frame *f;
4207 struct image *img;
4208 XColor *colors;
4209 {
4210 int x, y;
4211 XImagePtr oimg;
4212 Pixmap pixmap;
4213 XColor *p;
4214
4215 init_color_table ();
4216
4217 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4218 &oimg, &pixmap);
4219 p = colors;
4220 for (y = 0; y < img->height; ++y)
4221 for (x = 0; x < img->width; ++x, ++p)
4222 {
4223 unsigned long pixel;
4224 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4225 XPutPixel (oimg, x, y, pixel);
4226 }
4227
4228 xfree (colors);
4229 x_clear_image_1 (f, img, 1, 0, 1);
4230
4231 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4232 x_destroy_x_image (oimg);
4233 img->pixmap = pixmap;
4234 #ifdef COLOR_TABLE_SUPPORT
4235 img->colors = colors_in_color_table (&img->ncolors);
4236 free_color_table ();
4237 #endif /* COLOR_TABLE_SUPPORT */
4238 }
4239
4240
4241 /* On frame F, perform edge-detection on image IMG.
4242
4243 MATRIX is a nine-element array specifying the transformation
4244 matrix. See emboss_matrix for an example.
4245
4246 COLOR_ADJUST is a color adjustment added to each pixel of the
4247 outgoing image. */
4248
4249 static void
4250 x_detect_edges (f, img, matrix, color_adjust)
4251 struct frame *f;
4252 struct image *img;
4253 int matrix[9], color_adjust;
4254 {
4255 XColor *colors = x_to_xcolors (f, img, 1);
4256 XColor *new, *p;
4257 int x, y, i, sum;
4258
4259 for (i = sum = 0; i < 9; ++i)
4260 sum += abs (matrix[i]);
4261
4262 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4263
4264 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4265
4266 for (y = 0; y < img->height; ++y)
4267 {
4268 p = COLOR (new, 0, y);
4269 p->red = p->green = p->blue = 0xffff/2;
4270 p = COLOR (new, img->width - 1, y);
4271 p->red = p->green = p->blue = 0xffff/2;
4272 }
4273
4274 for (x = 1; x < img->width - 1; ++x)
4275 {
4276 p = COLOR (new, x, 0);
4277 p->red = p->green = p->blue = 0xffff/2;
4278 p = COLOR (new, x, img->height - 1);
4279 p->red = p->green = p->blue = 0xffff/2;
4280 }
4281
4282 for (y = 1; y < img->height - 1; ++y)
4283 {
4284 p = COLOR (new, 1, y);
4285
4286 for (x = 1; x < img->width - 1; ++x, ++p)
4287 {
4288 int r, g, b, y1, x1;
4289
4290 r = g = b = i = 0;
4291 for (y1 = y - 1; y1 < y + 2; ++y1)
4292 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4293 if (matrix[i])
4294 {
4295 XColor *t = COLOR (colors, x1, y1);
4296 r += matrix[i] * t->red;
4297 g += matrix[i] * t->green;
4298 b += matrix[i] * t->blue;
4299 }
4300
4301 r = (r / sum + color_adjust) & 0xffff;
4302 g = (g / sum + color_adjust) & 0xffff;
4303 b = (b / sum + color_adjust) & 0xffff;
4304 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4305 }
4306 }
4307
4308 xfree (colors);
4309 x_from_xcolors (f, img, new);
4310
4311 #undef COLOR
4312 }
4313
4314
4315 /* Perform the pre-defined `emboss' edge-detection on image IMG
4316 on frame F. */
4317
4318 static void
4319 x_emboss (f, img)
4320 struct frame *f;
4321 struct image *img;
4322 {
4323 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4324 }
4325
4326
4327 /* Transform image IMG which is used on frame F with a Laplace
4328 edge-detection algorithm. The result is an image that can be used
4329 to draw disabled buttons, for example. */
4330
4331 static void
4332 x_laplace (f, img)
4333 struct frame *f;
4334 struct image *img;
4335 {
4336 x_detect_edges (f, img, laplace_matrix, 45000);
4337 }
4338
4339
4340 /* Perform edge-detection on image IMG on frame F, with specified
4341 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
4342
4343 MATRIX must be either
4344
4345 - a list of at least 9 numbers in row-major form
4346 - a vector of at least 9 numbers
4347
4348 COLOR_ADJUST nil means use a default; otherwise it must be a
4349 number. */
4350
4351 static void
4352 x_edge_detection (f, img, matrix, color_adjust)
4353 struct frame *f;
4354 struct image *img;
4355 Lisp_Object matrix, color_adjust;
4356 {
4357 int i = 0;
4358 int trans[9];
4359
4360 if (CONSP (matrix))
4361 {
4362 for (i = 0;
4363 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
4364 ++i, matrix = XCDR (matrix))
4365 trans[i] = XFLOATINT (XCAR (matrix));
4366 }
4367 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
4368 {
4369 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
4370 trans[i] = XFLOATINT (AREF (matrix, i));
4371 }
4372
4373 if (NILP (color_adjust))
4374 color_adjust = make_number (0xffff / 2);
4375
4376 if (i == 9 && NUMBERP (color_adjust))
4377 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
4378 }
4379
4380
4381 /* Transform image IMG on frame F so that it looks disabled. */
4382
4383 static void
4384 x_disable_image (f, img)
4385 struct frame *f;
4386 struct image *img;
4387 {
4388 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4389 #ifdef HAVE_NTGUI
4390 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
4391 #else
4392 int n_planes = dpyinfo->n_planes;
4393 #endif /* HAVE_NTGUI */
4394
4395 if (n_planes >= 2)
4396 {
4397 /* Color (or grayscale). Convert to gray, and equalize. Just
4398 drawing such images with a stipple can look very odd, so
4399 we're using this method instead. */
4400 XColor *colors = x_to_xcolors (f, img, 1);
4401 XColor *p, *end;
4402 const int h = 15000;
4403 const int l = 30000;
4404
4405 for (p = colors, end = colors + img->width * img->height;
4406 p < end;
4407 ++p)
4408 {
4409 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
4410 int i2 = (0xffff - h - l) * i / 0xffff + l;
4411 p->red = p->green = p->blue = i2;
4412 }
4413
4414 x_from_xcolors (f, img, colors);
4415 }
4416
4417 /* Draw a cross over the disabled image, if we must or if we
4418 should. */
4419 if (n_planes < 2 || cross_disabled_images)
4420 {
4421 #ifndef HAVE_NTGUI
4422 Display *dpy = FRAME_X_DISPLAY (f);
4423 GC gc;
4424
4425 #ifdef MAC_OS
4426 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
4427 #define MaskForeground(f) PIX_MASK_DRAW (f)
4428 #else
4429 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
4430 #define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4431 #endif
4432
4433 gc = XCreateGC_pixmap (dpy, img->pixmap);
4434 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
4435 XDrawLine (dpy, img->pixmap, gc, 0, 0,
4436 img->width - 1, img->height - 1);
4437 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
4438 img->width - 1, 0);
4439 XFreeGC (dpy, gc);
4440
4441 if (img->mask)
4442 {
4443 gc = XCreateGC_pixmap (dpy, img->mask);
4444 XSetForeground (dpy, gc, MaskForeground (f));
4445 XDrawLine (dpy, img->mask, gc, 0, 0,
4446 img->width - 1, img->height - 1);
4447 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
4448 img->width - 1, 0);
4449 XFreeGC (dpy, gc);
4450 }
4451 #else
4452 HDC hdc, bmpdc;
4453 HGDIOBJ prev;
4454
4455 hdc = get_frame_dc (f);
4456 bmpdc = CreateCompatibleDC (hdc);
4457 release_frame_dc (f, hdc);
4458
4459 prev = SelectObject (bmpdc, img->pixmap);
4460
4461 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
4462 MoveToEx (bmpdc, 0, 0, NULL);
4463 LineTo (bmpdc, img->width - 1, img->height - 1);
4464 MoveToEx (bmpdc, 0, img->height - 1, NULL);
4465 LineTo (bmpdc, img->width - 1, 0);
4466
4467 if (img->mask)
4468 {
4469 SelectObject (bmpdc, img->mask);
4470 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
4471 MoveToEx (bmpdc, 0, 0, NULL);
4472 LineTo (bmpdc, img->width - 1, img->height - 1);
4473 MoveToEx (bmpdc, 0, img->height - 1, NULL);
4474 LineTo (bmpdc, img->width - 1, 0);
4475 }
4476 SelectObject (bmpdc, prev);
4477 DeleteDC (bmpdc);
4478 #endif /* HAVE_NTGUI */
4479 }
4480 }
4481
4482
4483 /* Build a mask for image IMG which is used on frame F. FILE is the
4484 name of an image file, for error messages. HOW determines how to
4485 determine the background color of IMG. If it is a list '(R G B)',
4486 with R, G, and B being integers >= 0, take that as the color of the
4487 background. Otherwise, determine the background color of IMG
4488 heuristically. Value is non-zero if successful. */
4489
4490 static int
4491 x_build_heuristic_mask (f, img, how)
4492 struct frame *f;
4493 struct image *img;
4494 Lisp_Object how;
4495 {
4496 XImagePtr_or_DC ximg;
4497 #ifndef HAVE_NTGUI
4498 XImagePtr mask_img;
4499 #else
4500 HDC frame_dc;
4501 HGDIOBJ prev;
4502 char *mask_img;
4503 int row_width;
4504 #endif /* HAVE_NTGUI */
4505 int x, y, rc, use_img_background;
4506 unsigned long bg = 0;
4507
4508 if (img->mask)
4509 {
4510 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4511 img->mask = NO_PIXMAP;
4512 img->background_transparent_valid = 0;
4513 }
4514
4515 #ifndef HAVE_NTGUI
4516 /* Create an image and pixmap serving as mask. */
4517 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
4518 &mask_img, &img->mask);
4519 if (!rc)
4520 return 0;
4521
4522 /* Get the X image of IMG->pixmap. */
4523 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
4524 img->width, img->height,
4525 ~0, ZPixmap);
4526 #else
4527 /* Create the bit array serving as mask. */
4528 row_width = (img->width + 7) / 8;
4529 mask_img = xmalloc (row_width * img->height);
4530 bzero (mask_img, row_width * img->height);
4531
4532 /* Create a memory device context for IMG->pixmap. */
4533 frame_dc = get_frame_dc (f);
4534 ximg = CreateCompatibleDC (frame_dc);
4535 release_frame_dc (f, frame_dc);
4536 prev = SelectObject (ximg, img->pixmap);
4537 #endif /* HAVE_NTGUI */
4538
4539 /* Determine the background color of ximg. If HOW is `(R G B)'
4540 take that as color. Otherwise, use the image's background color. */
4541 use_img_background = 1;
4542
4543 if (CONSP (how))
4544 {
4545 int rgb[3], i;
4546
4547 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
4548 {
4549 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
4550 how = XCDR (how);
4551 }
4552
4553 if (i == 3 && NILP (how))
4554 {
4555 char color_name[30];
4556 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
4557 bg = (
4558 #ifdef HAVE_NTGUI
4559 0x00ffffff & /* Filter out palette info. */
4560 #endif /* HAVE_NTGUI */
4561 x_alloc_image_color (f, img, build_string (color_name), 0));
4562 use_img_background = 0;
4563 }
4564 }
4565
4566 if (use_img_background)
4567 bg = four_corners_best (ximg, img->width, img->height);
4568
4569 /* Set all bits in mask_img to 1 whose color in ximg is different
4570 from the background color bg. */
4571 #ifndef HAVE_NTGUI
4572 for (y = 0; y < img->height; ++y)
4573 for (x = 0; x < img->width; ++x)
4574 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
4575 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
4576
4577 /* Fill in the background_transparent field while we have the mask handy. */
4578 image_background_transparent (img, f, mask_img);
4579
4580 /* Put mask_img into img->mask. */
4581 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
4582 x_destroy_x_image (mask_img);
4583
4584 #else
4585 for (y = 0; y < img->height; ++y)
4586 for (x = 0; x < img->width; ++x)
4587 {
4588 COLORREF p = GetPixel (ximg, x, y);
4589 if (p != bg)
4590 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
4591 }
4592
4593 /* Create the mask image. */
4594 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
4595 mask_img);
4596 /* Fill in the background_transparent field while we have the mask handy. */
4597 SelectObject (ximg, img->mask);
4598 image_background_transparent (img, f, ximg);
4599
4600 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
4601 xfree (mask_img);
4602 #endif /* HAVE_NTGUI */
4603
4604 Destroy_Image (ximg, prev);
4605
4606 return 1;
4607 }
4608
4609 \f
4610 /***********************************************************************
4611 PBM (mono, gray, color)
4612 ***********************************************************************/
4613
4614 static int pbm_image_p P_ ((Lisp_Object object));
4615 static int pbm_load P_ ((struct frame *f, struct image *img));
4616 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
4617
4618 /* The symbol `pbm' identifying images of this type. */
4619
4620 Lisp_Object Qpbm;
4621
4622 /* Indices of image specification fields in gs_format, below. */
4623
4624 enum pbm_keyword_index
4625 {
4626 PBM_TYPE,
4627 PBM_FILE,
4628 PBM_DATA,
4629 PBM_ASCENT,
4630 PBM_MARGIN,
4631 PBM_RELIEF,
4632 PBM_ALGORITHM,
4633 PBM_HEURISTIC_MASK,
4634 PBM_MASK,
4635 PBM_FOREGROUND,
4636 PBM_BACKGROUND,
4637 PBM_LAST
4638 };
4639
4640 /* Vector of image_keyword structures describing the format
4641 of valid user-defined image specifications. */
4642
4643 static struct image_keyword pbm_format[PBM_LAST] =
4644 {
4645 {":type", IMAGE_SYMBOL_VALUE, 1},
4646 {":file", IMAGE_STRING_VALUE, 0},
4647 {":data", IMAGE_STRING_VALUE, 0},
4648 {":ascent", IMAGE_ASCENT_VALUE, 0},
4649 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
4650 {":relief", IMAGE_INTEGER_VALUE, 0},
4651 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4652 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4653 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4654 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
4655 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
4656 };
4657
4658 /* Structure describing the image type `pbm'. */
4659
4660 static struct image_type pbm_type =
4661 {
4662 &Qpbm,
4663 pbm_image_p,
4664 pbm_load,
4665 x_clear_image,
4666 NULL
4667 };
4668
4669
4670 /* Return non-zero if OBJECT is a valid PBM image specification. */
4671
4672 static int
4673 pbm_image_p (object)
4674 Lisp_Object object;
4675 {
4676 struct image_keyword fmt[PBM_LAST];
4677
4678 bcopy (pbm_format, fmt, sizeof fmt);
4679
4680 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
4681 return 0;
4682
4683 /* Must specify either :data or :file. */
4684 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
4685 }
4686
4687
4688 /* Scan a decimal number from *S and return it. Advance *S while
4689 reading the number. END is the end of the string. Value is -1 at
4690 end of input. */
4691
4692 static int
4693 pbm_scan_number (s, end)
4694 unsigned char **s, *end;
4695 {
4696 int c = 0, val = -1;
4697
4698 while (*s < end)
4699 {
4700 /* Skip white-space. */
4701 while (*s < end && (c = *(*s)++, isspace (c)))
4702 ;
4703
4704 if (c == '#')
4705 {
4706 /* Skip comment to end of line. */
4707 while (*s < end && (c = *(*s)++, c != '\n'))
4708 ;
4709 }
4710 else if (isdigit (c))
4711 {
4712 /* Read decimal number. */
4713 val = c - '0';
4714 while (*s < end && (c = *(*s)++, isdigit (c)))
4715 val = 10 * val + c - '0';
4716 break;
4717 }
4718 else
4719 break;
4720 }
4721
4722 return val;
4723 }
4724
4725
4726 #ifdef HAVE_NTGUI
4727 #if 0 /* Unused. ++kfs */
4728
4729 /* Read FILE into memory. Value is a pointer to a buffer allocated
4730 with xmalloc holding FILE's contents. Value is null if an error
4731 occurred. *SIZE is set to the size of the file. */
4732
4733 static char *
4734 pbm_read_file (file, size)
4735 Lisp_Object file;
4736 int *size;
4737 {
4738 FILE *fp = NULL;
4739 char *buf = NULL;
4740 struct stat st;
4741
4742 if (stat (SDATA (file), &st) == 0
4743 && (fp = fopen (SDATA (file), "rb")) != NULL
4744 && (buf = (char *) xmalloc (st.st_size),
4745 fread (buf, 1, st.st_size, fp) == st.st_size))
4746 {
4747 *size = st.st_size;
4748 fclose (fp);
4749 }
4750 else
4751 {
4752 if (fp)
4753 fclose (fp);
4754 if (buf)
4755 {
4756 xfree (buf);
4757 buf = NULL;
4758 }
4759 }
4760
4761 return buf;
4762 }
4763 #endif
4764 #endif /* HAVE_NTGUI */
4765
4766 /* Load PBM image IMG for use on frame F. */
4767
4768 static int
4769 pbm_load (f, img)
4770 struct frame *f;
4771 struct image *img;
4772 {
4773 int raw_p, x, y;
4774 int width, height, max_color_idx = 0;
4775 XImagePtr ximg;
4776 Lisp_Object file, specified_file;
4777 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
4778 struct gcpro gcpro1;
4779 unsigned char *contents = NULL;
4780 unsigned char *end, *p;
4781 int size;
4782
4783 specified_file = image_spec_value (img->spec, QCfile, NULL);
4784 file = Qnil;
4785 GCPRO1 (file);
4786
4787 if (STRINGP (specified_file))
4788 {
4789 file = x_find_image_file (specified_file);
4790 if (!STRINGP (file))
4791 {
4792 image_error ("Cannot find image file `%s'", specified_file, Qnil);
4793 UNGCPRO;
4794 return 0;
4795 }
4796
4797 contents = slurp_file (SDATA (file), &size);
4798 if (contents == NULL)
4799 {
4800 image_error ("Error reading `%s'", file, Qnil);
4801 UNGCPRO;
4802 return 0;
4803 }
4804
4805 p = contents;
4806 end = contents + size;
4807 }
4808 else
4809 {
4810 Lisp_Object data;
4811 data = image_spec_value (img->spec, QCdata, NULL);
4812 p = SDATA (data);
4813 end = p + SBYTES (data);
4814 }
4815
4816 /* Check magic number. */
4817 if (end - p < 2 || *p++ != 'P')
4818 {
4819 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
4820 error:
4821 xfree (contents);
4822 UNGCPRO;
4823 return 0;
4824 }
4825
4826 switch (*p++)
4827 {
4828 case '1':
4829 raw_p = 0, type = PBM_MONO;
4830 break;
4831
4832 case '2':
4833 raw_p = 0, type = PBM_GRAY;
4834 break;
4835
4836 case '3':
4837 raw_p = 0, type = PBM_COLOR;
4838 break;
4839
4840 case '4':
4841 raw_p = 1, type = PBM_MONO;
4842 break;
4843
4844 case '5':
4845 raw_p = 1, type = PBM_GRAY;
4846 break;
4847
4848 case '6':
4849 raw_p = 1, type = PBM_COLOR;
4850 break;
4851
4852 default:
4853 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
4854 goto error;
4855 }
4856
4857 /* Read width, height, maximum color-component. Characters
4858 starting with `#' up to the end of a line are ignored. */
4859 width = pbm_scan_number (&p, end);
4860 height = pbm_scan_number (&p, end);
4861
4862 if (type != PBM_MONO)
4863 {
4864 max_color_idx = pbm_scan_number (&p, end);
4865 if (raw_p && max_color_idx > 255)
4866 max_color_idx = 255;
4867 }
4868
4869 if (width < 0
4870 || height < 0
4871 || (type != PBM_MONO && max_color_idx < 0))
4872 goto error;
4873
4874 if (!x_create_x_image_and_pixmap (f, width, height, 0,
4875 &ximg, &img->pixmap))
4876 goto error;
4877
4878 /* Initialize the color hash table. */
4879 init_color_table ();
4880
4881 if (type == PBM_MONO)
4882 {
4883 int c = 0, g;
4884 struct image_keyword fmt[PBM_LAST];
4885 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
4886 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
4887
4888 /* Parse the image specification. */
4889 bcopy (pbm_format, fmt, sizeof fmt);
4890 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
4891
4892 /* Get foreground and background colors, maybe allocate colors. */
4893 if (fmt[PBM_FOREGROUND].count
4894 && STRINGP (fmt[PBM_FOREGROUND].value))
4895 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
4896 if (fmt[PBM_BACKGROUND].count
4897 && STRINGP (fmt[PBM_BACKGROUND].value))
4898 {
4899 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
4900 img->background = bg;
4901 img->background_valid = 1;
4902 }
4903
4904 for (y = 0; y < height; ++y)
4905 for (x = 0; x < width; ++x)
4906 {
4907 if (raw_p)
4908 {
4909 if ((x & 7) == 0)
4910 c = *p++;
4911 g = c & 0x80;
4912 c <<= 1;
4913 }
4914 else
4915 g = pbm_scan_number (&p, end);
4916
4917 XPutPixel (ximg, x, y, g ? fg : bg);
4918 }
4919 }
4920 else
4921 {
4922 for (y = 0; y < height; ++y)
4923 for (x = 0; x < width; ++x)
4924 {
4925 int r, g, b;
4926
4927 if (type == PBM_GRAY)
4928 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
4929 else if (raw_p)
4930 {
4931 r = *p++;
4932 g = *p++;
4933 b = *p++;
4934 }
4935 else
4936 {
4937 r = pbm_scan_number (&p, end);
4938 g = pbm_scan_number (&p, end);
4939 b = pbm_scan_number (&p, end);
4940 }
4941
4942 if (r < 0 || g < 0 || b < 0)
4943 {
4944 x_destroy_x_image (ximg);
4945 image_error ("Invalid pixel value in image `%s'",
4946 img->spec, Qnil);
4947 goto error;
4948 }
4949
4950 /* RGB values are now in the range 0..max_color_idx.
4951 Scale this to the range 0..0xffff supported by X. */
4952 r = (double) r * 65535 / max_color_idx;
4953 g = (double) g * 65535 / max_color_idx;
4954 b = (double) b * 65535 / max_color_idx;
4955 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
4956 }
4957 }
4958
4959 #ifdef COLOR_TABLE_SUPPORT
4960 /* Store in IMG->colors the colors allocated for the image, and
4961 free the color table. */
4962 img->colors = colors_in_color_table (&img->ncolors);
4963 free_color_table ();
4964 #endif /* COLOR_TABLE_SUPPORT */
4965
4966 img->width = width;
4967 img->height = height;
4968
4969 /* Maybe fill in the background field while we have ximg handy. */
4970
4971 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
4972 IMAGE_BACKGROUND (img, f, ximg);
4973
4974 /* Put the image into a pixmap. */
4975 x_put_x_image (f, ximg, img->pixmap, width, height);
4976 x_destroy_x_image (ximg);
4977
4978 /* X and W32 versions did it here, MAC version above. ++kfs
4979 img->width = width;
4980 img->height = height; */
4981
4982 UNGCPRO;
4983 xfree (contents);
4984 return 1;
4985 }
4986
4987 \f
4988 /***********************************************************************
4989 PNG
4990 ***********************************************************************/
4991
4992 #if defined (HAVE_PNG) || defined (MAC_OS)
4993
4994 /* Function prototypes. */
4995
4996 static int png_image_p P_ ((Lisp_Object object));
4997 static int png_load P_ ((struct frame *f, struct image *img));
4998
4999 /* The symbol `png' identifying images of this type. */
5000
5001 Lisp_Object Qpng;
5002
5003 /* Indices of image specification fields in png_format, below. */
5004
5005 enum png_keyword_index
5006 {
5007 PNG_TYPE,
5008 PNG_DATA,
5009 PNG_FILE,
5010 PNG_ASCENT,
5011 PNG_MARGIN,
5012 PNG_RELIEF,
5013 PNG_ALGORITHM,
5014 PNG_HEURISTIC_MASK,
5015 PNG_MASK,
5016 PNG_BACKGROUND,
5017 PNG_LAST
5018 };
5019
5020 /* Vector of image_keyword structures describing the format
5021 of valid user-defined image specifications. */
5022
5023 static struct image_keyword png_format[PNG_LAST] =
5024 {
5025 {":type", IMAGE_SYMBOL_VALUE, 1},
5026 {":data", IMAGE_STRING_VALUE, 0},
5027 {":file", IMAGE_STRING_VALUE, 0},
5028 {":ascent", IMAGE_ASCENT_VALUE, 0},
5029 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5030 {":relief", IMAGE_INTEGER_VALUE, 0},
5031 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5032 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5033 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5034 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5035 };
5036
5037 /* Structure describing the image type `png'. */
5038
5039 static struct image_type png_type =
5040 {
5041 &Qpng,
5042 png_image_p,
5043 png_load,
5044 x_clear_image,
5045 NULL
5046 };
5047
5048 /* Return non-zero if OBJECT is a valid PNG image specification. */
5049
5050 static int
5051 png_image_p (object)
5052 Lisp_Object object;
5053 {
5054 struct image_keyword fmt[PNG_LAST];
5055 bcopy (png_format, fmt, sizeof fmt);
5056
5057 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5058 return 0;
5059
5060 /* Must specify either the :data or :file keyword. */
5061 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5062 }
5063
5064 #endif /* HAVE_PNG || MAC_OS */
5065
5066
5067 #ifdef HAVE_PNG
5068
5069 #if defined HAVE_LIBPNG_PNG_H
5070 # include <libpng/png.h>
5071 #else
5072 # include <png.h>
5073 #endif
5074
5075 #ifdef HAVE_NTGUI
5076 /* PNG library details. */
5077
5078 DEF_IMGLIB_FN (png_get_io_ptr);
5079 DEF_IMGLIB_FN (png_check_sig);
5080 DEF_IMGLIB_FN (png_create_read_struct);
5081 DEF_IMGLIB_FN (png_create_info_struct);
5082 DEF_IMGLIB_FN (png_destroy_read_struct);
5083 DEF_IMGLIB_FN (png_set_read_fn);
5084 DEF_IMGLIB_FN (png_init_io);
5085 DEF_IMGLIB_FN (png_set_sig_bytes);
5086 DEF_IMGLIB_FN (png_read_info);
5087 DEF_IMGLIB_FN (png_get_IHDR);
5088 DEF_IMGLIB_FN (png_get_valid);
5089 DEF_IMGLIB_FN (png_set_strip_16);
5090 DEF_IMGLIB_FN (png_set_expand);
5091 DEF_IMGLIB_FN (png_set_gray_to_rgb);
5092 DEF_IMGLIB_FN (png_set_background);
5093 DEF_IMGLIB_FN (png_get_bKGD);
5094 DEF_IMGLIB_FN (png_read_update_info);
5095 DEF_IMGLIB_FN (png_get_channels);
5096 DEF_IMGLIB_FN (png_get_rowbytes);
5097 DEF_IMGLIB_FN (png_read_image);
5098 DEF_IMGLIB_FN (png_read_end);
5099 DEF_IMGLIB_FN (png_error);
5100
5101 static int
5102 init_png_functions (void)
5103 {
5104 HMODULE library;
5105
5106 /* Ensure zlib is loaded. Try debug version first. */
5107 if (!LoadLibrary ("zlibd.dll")
5108 && !LoadLibrary ("zlib.dll"))
5109 return 0;
5110
5111 /* Try loading libpng under probable names. */
5112 if (!(library = LoadLibrary ("libpng13d.dll"))
5113 && !(library = LoadLibrary ("libpng13.dll"))
5114 && !(library = LoadLibrary ("libpng12d.dll"))
5115 && !(library = LoadLibrary ("libpng12.dll"))
5116 && !(library = LoadLibrary ("libpng.dll")))
5117 return 0;
5118
5119 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5120 LOAD_IMGLIB_FN (library, png_check_sig);
5121 LOAD_IMGLIB_FN (library, png_create_read_struct);
5122 LOAD_IMGLIB_FN (library, png_create_info_struct);
5123 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5124 LOAD_IMGLIB_FN (library, png_set_read_fn);
5125 LOAD_IMGLIB_FN (library, png_init_io);
5126 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5127 LOAD_IMGLIB_FN (library, png_read_info);
5128 LOAD_IMGLIB_FN (library, png_get_IHDR);
5129 LOAD_IMGLIB_FN (library, png_get_valid);
5130 LOAD_IMGLIB_FN (library, png_set_strip_16);
5131 LOAD_IMGLIB_FN (library, png_set_expand);
5132 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5133 LOAD_IMGLIB_FN (library, png_set_background);
5134 LOAD_IMGLIB_FN (library, png_get_bKGD);
5135 LOAD_IMGLIB_FN (library, png_read_update_info);
5136 LOAD_IMGLIB_FN (library, png_get_channels);
5137 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5138 LOAD_IMGLIB_FN (library, png_read_image);
5139 LOAD_IMGLIB_FN (library, png_read_end);
5140 LOAD_IMGLIB_FN (library, png_error);
5141 return 1;
5142 }
5143 #else
5144
5145 #define fn_png_get_io_ptr png_get_io_ptr
5146 #define fn_png_check_sig png_check_sig
5147 #define fn_png_create_read_struct png_create_read_struct
5148 #define fn_png_create_info_struct png_create_info_struct
5149 #define fn_png_destroy_read_struct png_destroy_read_struct
5150 #define fn_png_set_read_fn png_set_read_fn
5151 #define fn_png_init_io png_init_io
5152 #define fn_png_set_sig_bytes png_set_sig_bytes
5153 #define fn_png_read_info png_read_info
5154 #define fn_png_get_IHDR png_get_IHDR
5155 #define fn_png_get_valid png_get_valid
5156 #define fn_png_set_strip_16 png_set_strip_16
5157 #define fn_png_set_expand png_set_expand
5158 #define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5159 #define fn_png_set_background png_set_background
5160 #define fn_png_get_bKGD png_get_bKGD
5161 #define fn_png_read_update_info png_read_update_info
5162 #define fn_png_get_channels png_get_channels
5163 #define fn_png_get_rowbytes png_get_rowbytes
5164 #define fn_png_read_image png_read_image
5165 #define fn_png_read_end png_read_end
5166 #define fn_png_error png_error
5167
5168 #endif /* HAVE_NTGUI */
5169
5170 /* Error and warning handlers installed when the PNG library
5171 is initialized. */
5172
5173 static void
5174 my_png_error (png_ptr, msg)
5175 png_struct *png_ptr;
5176 char *msg;
5177 {
5178 xassert (png_ptr != NULL);
5179 image_error ("PNG error: %s", build_string (msg), Qnil);
5180 longjmp (png_ptr->jmpbuf, 1);
5181 }
5182
5183
5184 static void
5185 my_png_warning (png_ptr, msg)
5186 png_struct *png_ptr;
5187 char *msg;
5188 {
5189 xassert (png_ptr != NULL);
5190 image_error ("PNG warning: %s", build_string (msg), Qnil);
5191 }
5192
5193 /* Memory source for PNG decoding. */
5194
5195 struct png_memory_storage
5196 {
5197 unsigned char *bytes; /* The data */
5198 size_t len; /* How big is it? */
5199 int index; /* Where are we? */
5200 };
5201
5202
5203 /* Function set as reader function when reading PNG image from memory.
5204 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5205 bytes from the input to DATA. */
5206
5207 static void
5208 png_read_from_memory (png_ptr, data, length)
5209 png_structp png_ptr;
5210 png_bytep data;
5211 png_size_t length;
5212 {
5213 struct png_memory_storage *tbr
5214 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5215
5216 if (length > tbr->len - tbr->index)
5217 fn_png_error (png_ptr, "Read error");
5218
5219 bcopy (tbr->bytes + tbr->index, data, length);
5220 tbr->index = tbr->index + length;
5221 }
5222
5223 /* Load PNG image IMG for use on frame F. Value is non-zero if
5224 successful. */
5225
5226 static int
5227 png_load (f, img)
5228 struct frame *f;
5229 struct image *img;
5230 {
5231 Lisp_Object file, specified_file;
5232 Lisp_Object specified_data;
5233 int x, y, i;
5234 XImagePtr ximg, mask_img = NULL;
5235 struct gcpro gcpro1;
5236 png_struct *png_ptr = NULL;
5237 png_info *info_ptr = NULL, *end_info = NULL;
5238 FILE *volatile fp = NULL;
5239 png_byte sig[8];
5240 png_byte * volatile pixels = NULL;
5241 png_byte ** volatile rows = NULL;
5242 png_uint_32 width, height;
5243 int bit_depth, color_type, interlace_type;
5244 png_byte channels;
5245 png_uint_32 row_bytes;
5246 int transparent_p;
5247 double screen_gamma;
5248 struct png_memory_storage tbr; /* Data to be read */
5249
5250 /* Find out what file to load. */
5251 specified_file = image_spec_value (img->spec, QCfile, NULL);
5252 specified_data = image_spec_value (img->spec, QCdata, NULL);
5253 file = Qnil;
5254 GCPRO1 (file);
5255
5256 if (NILP (specified_data))
5257 {
5258 file = x_find_image_file (specified_file);
5259 if (!STRINGP (file))
5260 {
5261 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5262 UNGCPRO;
5263 return 0;
5264 }
5265
5266 /* Open the image file. */
5267 fp = fopen (SDATA (file), "rb");
5268 if (!fp)
5269 {
5270 image_error ("Cannot open image file `%s'", file, Qnil);
5271 UNGCPRO;
5272 fclose (fp);
5273 return 0;
5274 }
5275
5276 /* Check PNG signature. */
5277 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
5278 || !fn_png_check_sig (sig, sizeof sig))
5279 {
5280 image_error ("Not a PNG file: `%s'", file, Qnil);
5281 UNGCPRO;
5282 fclose (fp);
5283 return 0;
5284 }
5285 }
5286 else
5287 {
5288 /* Read from memory. */
5289 tbr.bytes = SDATA (specified_data);
5290 tbr.len = SBYTES (specified_data);
5291 tbr.index = 0;
5292
5293 /* Check PNG signature. */
5294 if (tbr.len < sizeof sig
5295 || !fn_png_check_sig (tbr.bytes, sizeof sig))
5296 {
5297 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5298 UNGCPRO;
5299 return 0;
5300 }
5301
5302 /* Need to skip past the signature. */
5303 tbr.bytes += sizeof (sig);
5304 }
5305
5306 /* Initialize read and info structs for PNG lib. */
5307 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
5308 my_png_error, my_png_warning);
5309 if (!png_ptr)
5310 {
5311 if (fp) fclose (fp);
5312 UNGCPRO;
5313 return 0;
5314 }
5315
5316 info_ptr = fn_png_create_info_struct (png_ptr);
5317 if (!info_ptr)
5318 {
5319 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
5320 if (fp) fclose (fp);
5321 UNGCPRO;
5322 return 0;
5323 }
5324
5325 end_info = fn_png_create_info_struct (png_ptr);
5326 if (!end_info)
5327 {
5328 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
5329 if (fp) fclose (fp);
5330 UNGCPRO;
5331 return 0;
5332 }
5333
5334 /* Set error jump-back. We come back here when the PNG library
5335 detects an error. */
5336 if (setjmp (png_ptr->jmpbuf))
5337 {
5338 error:
5339 if (png_ptr)
5340 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
5341 xfree (pixels);
5342 xfree (rows);
5343 if (fp) fclose (fp);
5344 UNGCPRO;
5345 return 0;
5346 }
5347
5348 /* Read image info. */
5349 if (!NILP (specified_data))
5350 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
5351 else
5352 fn_png_init_io (png_ptr, fp);
5353
5354 fn_png_set_sig_bytes (png_ptr, sizeof sig);
5355 fn_png_read_info (png_ptr, info_ptr);
5356 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
5357 &interlace_type, NULL, NULL);
5358
5359 /* If image contains simply transparency data, we prefer to
5360 construct a clipping mask. */
5361 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
5362 transparent_p = 1;
5363 else
5364 transparent_p = 0;
5365
5366 /* This function is easier to write if we only have to handle
5367 one data format: RGB or RGBA with 8 bits per channel. Let's
5368 transform other formats into that format. */
5369
5370 /* Strip more than 8 bits per channel. */
5371 if (bit_depth == 16)
5372 fn_png_set_strip_16 (png_ptr);
5373
5374 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
5375 if available. */
5376 fn_png_set_expand (png_ptr);
5377
5378 /* Convert grayscale images to RGB. */
5379 if (color_type == PNG_COLOR_TYPE_GRAY
5380 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
5381 fn_png_set_gray_to_rgb (png_ptr);
5382
5383 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
5384
5385 #if 0 /* Avoid double gamma correction for PNG images. */
5386 { /* Tell the PNG lib to handle gamma correction for us. */
5387 int intent;
5388 double image_gamma;
5389 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
5390 if (png_get_sRGB (png_ptr, info_ptr, &intent))
5391 /* The libpng documentation says this is right in this case. */
5392 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5393 else
5394 #endif
5395 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
5396 /* Image contains gamma information. */
5397 png_set_gamma (png_ptr, screen_gamma, image_gamma);
5398 else
5399 /* Use the standard default for the image gamma. */
5400 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5401 }
5402 #endif /* if 0 */
5403
5404 /* Handle alpha channel by combining the image with a background
5405 color. Do this only if a real alpha channel is supplied. For
5406 simple transparency, we prefer a clipping mask. */
5407 if (!transparent_p)
5408 {
5409 png_color_16 *image_bg;
5410 Lisp_Object specified_bg
5411 = image_spec_value (img->spec, QCbackground, NULL);
5412
5413 if (STRINGP (specified_bg))
5414 /* The user specified `:background', use that. */
5415 {
5416 /* W32 version incorrectly used COLORREF here!! ++kfs */
5417 XColor color;
5418 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
5419 {
5420 png_color_16 user_bg;
5421
5422 bzero (&user_bg, sizeof user_bg);
5423 user_bg.red = color.red >> 8;
5424 user_bg.green = color.green >> 8;
5425 user_bg.blue = color.blue >> 8;
5426
5427 fn_png_set_background (png_ptr, &user_bg,
5428 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5429 }
5430 }
5431 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
5432 /* Image contains a background color with which to
5433 combine the image. */
5434 fn_png_set_background (png_ptr, image_bg,
5435 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
5436 else
5437 {
5438 /* Image does not contain a background color with which
5439 to combine the image data via an alpha channel. Use
5440 the frame's background instead. */
5441 #ifdef HAVE_X_WINDOWS
5442 XColor color;
5443 png_color_16 frame_background;
5444
5445 color.pixel = FRAME_BACKGROUND_PIXEL (f);
5446 x_query_color (f, &color);
5447
5448 bzero (&frame_background, sizeof frame_background);
5449 frame_background.red = color.red >> 8;
5450 frame_background.green = color.green >> 8;
5451 frame_background.blue = color.blue >> 8;
5452 #endif /* HAVE_X_WINDOWS */
5453
5454 #ifdef HAVE_NTGUI
5455 COLORREF color;
5456 png_color_16 frame_background;
5457 color = FRAME_BACKGROUND_PIXEL (f);
5458 #if 0 /* W32 TODO : Colormap support. */
5459 x_query_color (f, &color);
5460 #endif
5461 bzero (&frame_background, sizeof frame_background);
5462 frame_background.red = GetRValue (color);
5463 frame_background.green = GetGValue (color);
5464 frame_background.blue = GetBValue (color);
5465 #endif /* HAVE_NTGUI */
5466
5467 #ifdef MAC_OS
5468 unsigned long color;
5469 png_color_16 frame_background;
5470 color = FRAME_BACKGROUND_PIXEL (f);
5471 #if 0 /* MAC/W32 TODO : Colormap support. */
5472 x_query_color (f, &color);
5473 #endif
5474 bzero (&frame_background, sizeof frame_background);
5475 frame_background.red = RED_FROM_ULONG (color);
5476 frame_background.green = GREEN_FROM_ULONG (color);
5477 frame_background.blue = BLUE_FROM_ULONG (color);
5478 #endif /* MAC_OS */
5479
5480 fn_png_set_background (png_ptr, &frame_background,
5481 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5482 }
5483 }
5484
5485 /* Update info structure. */
5486 fn_png_read_update_info (png_ptr, info_ptr);
5487
5488 /* Get number of channels. Valid values are 1 for grayscale images
5489 and images with a palette, 2 for grayscale images with transparency
5490 information (alpha channel), 3 for RGB images, and 4 for RGB
5491 images with alpha channel, i.e. RGBA. If conversions above were
5492 sufficient we should only have 3 or 4 channels here. */
5493 channels = fn_png_get_channels (png_ptr, info_ptr);
5494 xassert (channels == 3 || channels == 4);
5495
5496 /* Number of bytes needed for one row of the image. */
5497 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
5498
5499 /* Allocate memory for the image. */
5500 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
5501 rows = (png_byte **) xmalloc (height * sizeof *rows);
5502 for (i = 0; i < height; ++i)
5503 rows[i] = pixels + i * row_bytes;
5504
5505 /* Read the entire image. */
5506 fn_png_read_image (png_ptr, rows);
5507 fn_png_read_end (png_ptr, info_ptr);
5508 if (fp)
5509 {
5510 fclose (fp);
5511 fp = NULL;
5512 }
5513
5514 /* Create the X image and pixmap. */
5515 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
5516 &img->pixmap))
5517 goto error;
5518
5519 /* Create an image and pixmap serving as mask if the PNG image
5520 contains an alpha channel. */
5521 if (channels == 4
5522 && !transparent_p
5523 && !x_create_x_image_and_pixmap (f, width, height, 1,
5524 &mask_img, &img->mask))
5525 {
5526 x_destroy_x_image (ximg);
5527 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
5528 img->pixmap = NO_PIXMAP;
5529 goto error;
5530 }
5531
5532 /* Fill the X image and mask from PNG data. */
5533 init_color_table ();
5534
5535 for (y = 0; y < height; ++y)
5536 {
5537 png_byte *p = rows[y];
5538
5539 for (x = 0; x < width; ++x)
5540 {
5541 unsigned r, g, b;
5542
5543 r = *p++ << 8;
5544 g = *p++ << 8;
5545 b = *p++ << 8;
5546 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5547 /* An alpha channel, aka mask channel, associates variable
5548 transparency with an image. Where other image formats
5549 support binary transparency---fully transparent or fully
5550 opaque---PNG allows up to 254 levels of partial transparency.
5551 The PNG library implements partial transparency by combining
5552 the image with a specified background color.
5553
5554 I'm not sure how to handle this here nicely: because the
5555 background on which the image is displayed may change, for
5556 real alpha channel support, it would be necessary to create
5557 a new image for each possible background.
5558
5559 What I'm doing now is that a mask is created if we have
5560 boolean transparency information. Otherwise I'm using
5561 the frame's background color to combine the image with. */
5562
5563 if (channels == 4)
5564 {
5565 if (mask_img)
5566 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
5567 ++p;
5568 }
5569 }
5570 }
5571
5572 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5573 /* Set IMG's background color from the PNG image, unless the user
5574 overrode it. */
5575 {
5576 png_color_16 *bg;
5577 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
5578 {
5579 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
5580 img->background_valid = 1;
5581 }
5582 }
5583
5584 #ifdef COLOR_TABLE_SUPPORT
5585 /* Remember colors allocated for this image. */
5586 img->colors = colors_in_color_table (&img->ncolors);
5587 free_color_table ();
5588 #endif /* COLOR_TABLE_SUPPORT */
5589
5590 /* Clean up. */
5591 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
5592 xfree (rows);
5593 xfree (pixels);
5594
5595 img->width = width;
5596 img->height = height;
5597
5598 /* Maybe fill in the background field while we have ximg handy. */
5599 IMAGE_BACKGROUND (img, f, ximg);
5600
5601 /* Put the image into the pixmap, then free the X image and its buffer. */
5602 x_put_x_image (f, ximg, img->pixmap, width, height);
5603 x_destroy_x_image (ximg);
5604
5605 /* Same for the mask. */
5606 if (mask_img)
5607 {
5608 /* Fill in the background_transparent field while we have the mask
5609 handy. */
5610 image_background_transparent (img, f, mask_img);
5611
5612 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5613 x_destroy_x_image (mask_img);
5614 }
5615
5616 UNGCPRO;
5617 return 1;
5618 }
5619
5620 #else /* HAVE_PNG */
5621
5622 #ifdef MAC_OS
5623 static int
5624 png_load (f, img)
5625 struct frame *f;
5626 struct image *img;
5627 {
5628 #ifdef MAC_OSX
5629 if (MyCGImageCreateWithPNGDataProvider)
5630 return image_load_quartz2d (f, img, 1);
5631 else
5632 #endif
5633 return image_load_quicktime (f, img, kQTFileTypePNG);
5634 }
5635 #endif /* MAC_OS */
5636
5637 #endif /* !HAVE_PNG */
5638
5639
5640 \f
5641 /***********************************************************************
5642 JPEG
5643 ***********************************************************************/
5644
5645 #if defined (HAVE_JPEG) || defined (MAC_OS)
5646
5647 static int jpeg_image_p P_ ((Lisp_Object object));
5648 static int jpeg_load P_ ((struct frame *f, struct image *img));
5649
5650 /* The symbol `jpeg' identifying images of this type. */
5651
5652 Lisp_Object Qjpeg;
5653
5654 /* Indices of image specification fields in gs_format, below. */
5655
5656 enum jpeg_keyword_index
5657 {
5658 JPEG_TYPE,
5659 JPEG_DATA,
5660 JPEG_FILE,
5661 JPEG_ASCENT,
5662 JPEG_MARGIN,
5663 JPEG_RELIEF,
5664 JPEG_ALGORITHM,
5665 JPEG_HEURISTIC_MASK,
5666 JPEG_MASK,
5667 JPEG_BACKGROUND,
5668 JPEG_LAST
5669 };
5670
5671 /* Vector of image_keyword structures describing the format
5672 of valid user-defined image specifications. */
5673
5674 static struct image_keyword jpeg_format[JPEG_LAST] =
5675 {
5676 {":type", IMAGE_SYMBOL_VALUE, 1},
5677 {":data", IMAGE_STRING_VALUE, 0},
5678 {":file", IMAGE_STRING_VALUE, 0},
5679 {":ascent", IMAGE_ASCENT_VALUE, 0},
5680 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5681 {":relief", IMAGE_INTEGER_VALUE, 0},
5682 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5683 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5684 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5685 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5686 };
5687
5688 /* Structure describing the image type `jpeg'. */
5689
5690 static struct image_type jpeg_type =
5691 {
5692 &Qjpeg,
5693 jpeg_image_p,
5694 jpeg_load,
5695 x_clear_image,
5696 NULL
5697 };
5698
5699 /* Return non-zero if OBJECT is a valid JPEG image specification. */
5700
5701 static int
5702 jpeg_image_p (object)
5703 Lisp_Object object;
5704 {
5705 struct image_keyword fmt[JPEG_LAST];
5706
5707 bcopy (jpeg_format, fmt, sizeof fmt);
5708
5709 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
5710 return 0;
5711
5712 /* Must specify either the :data or :file keyword. */
5713 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
5714 }
5715
5716 #endif /* HAVE_JPEG || MAC_OS */
5717
5718 #ifdef HAVE_JPEG
5719
5720 /* Work around a warning about HAVE_STDLIB_H being redefined in
5721 jconfig.h. */
5722 #ifdef HAVE_STDLIB_H
5723 #define HAVE_STDLIB_H_1
5724 #undef HAVE_STDLIB_H
5725 #endif /* HAVE_STLIB_H */
5726
5727 #include <jpeglib.h>
5728 #include <jerror.h>
5729 #include <setjmp.h>
5730
5731 #ifdef HAVE_STLIB_H_1
5732 #define HAVE_STDLIB_H 1
5733 #endif
5734
5735 #ifdef HAVE_NTGUI
5736
5737 /* JPEG library details. */
5738 DEF_IMGLIB_FN (jpeg_CreateDecompress);
5739 DEF_IMGLIB_FN (jpeg_start_decompress);
5740 DEF_IMGLIB_FN (jpeg_finish_decompress);
5741 DEF_IMGLIB_FN (jpeg_destroy_decompress);
5742 DEF_IMGLIB_FN (jpeg_read_header);
5743 DEF_IMGLIB_FN (jpeg_read_scanlines);
5744 DEF_IMGLIB_FN (jpeg_stdio_src);
5745 DEF_IMGLIB_FN (jpeg_std_error);
5746 DEF_IMGLIB_FN (jpeg_resync_to_restart);
5747
5748 static int
5749 init_jpeg_functions (void)
5750 {
5751 HMODULE library;
5752
5753 if (!(library = LoadLibrary ("libjpeg.dll"))
5754 && !(library = LoadLibrary ("jpeg-62.dll"))
5755 && !(library = LoadLibrary ("jpeg.dll")))
5756 return 0;
5757
5758 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
5759 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
5760 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
5761 LOAD_IMGLIB_FN (library, jpeg_read_header);
5762 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
5763 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
5764 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
5765 LOAD_IMGLIB_FN (library, jpeg_std_error);
5766 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
5767 return 1;
5768 }
5769
5770 /* Wrapper since we can't directly assign the function pointer
5771 to another function pointer that was declared more completely easily. */
5772 static boolean
5773 jpeg_resync_to_restart_wrapper(cinfo, desired)
5774 j_decompress_ptr cinfo;
5775 int desired;
5776 {
5777 return fn_jpeg_resync_to_restart (cinfo, desired);
5778 }
5779
5780 #else
5781
5782 #define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
5783 #define fn_jpeg_start_decompress jpeg_start_decompress
5784 #define fn_jpeg_finish_decompress jpeg_finish_decompress
5785 #define fn_jpeg_destroy_decompress jpeg_destroy_decompress
5786 #define fn_jpeg_read_header jpeg_read_header
5787 #define fn_jpeg_read_scanlines jpeg_read_scanlines
5788 #define fn_jpeg_stdio_src jpeg_stdio_src
5789 #define fn_jpeg_std_error jpeg_std_error
5790 #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
5791
5792 #endif /* HAVE_NTGUI */
5793
5794 struct my_jpeg_error_mgr
5795 {
5796 struct jpeg_error_mgr pub;
5797 jmp_buf setjmp_buffer;
5798 };
5799
5800
5801 static void
5802 my_error_exit (cinfo)
5803 j_common_ptr cinfo;
5804 {
5805 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
5806 longjmp (mgr->setjmp_buffer, 1);
5807 }
5808
5809
5810 /* Init source method for JPEG data source manager. Called by
5811 jpeg_read_header() before any data is actually read. See
5812 libjpeg.doc from the JPEG lib distribution. */
5813
5814 static void
5815 our_init_source (cinfo)
5816 j_decompress_ptr cinfo;
5817 {
5818 }
5819
5820
5821 /* Fill input buffer method for JPEG data source manager. Called
5822 whenever more data is needed. We read the whole image in one step,
5823 so this only adds a fake end of input marker at the end. */
5824
5825 static boolean
5826 our_fill_input_buffer (cinfo)
5827 j_decompress_ptr cinfo;
5828 {
5829 /* Insert a fake EOI marker. */
5830 struct jpeg_source_mgr *src = cinfo->src;
5831 static JOCTET buffer[2];
5832
5833 buffer[0] = (JOCTET) 0xFF;
5834 buffer[1] = (JOCTET) JPEG_EOI;
5835
5836 src->next_input_byte = buffer;
5837 src->bytes_in_buffer = 2;
5838 return TRUE;
5839 }
5840
5841
5842 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
5843 is the JPEG data source manager. */
5844
5845 static void
5846 our_skip_input_data (cinfo, num_bytes)
5847 j_decompress_ptr cinfo;
5848 long num_bytes;
5849 {
5850 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
5851
5852 if (src)
5853 {
5854 if (num_bytes > src->bytes_in_buffer)
5855 ERREXIT (cinfo, JERR_INPUT_EOF);
5856
5857 src->bytes_in_buffer -= num_bytes;
5858 src->next_input_byte += num_bytes;
5859 }
5860 }
5861
5862
5863 /* Method to terminate data source. Called by
5864 jpeg_finish_decompress() after all data has been processed. */
5865
5866 static void
5867 our_term_source (cinfo)
5868 j_decompress_ptr cinfo;
5869 {
5870 }
5871
5872
5873 /* Set up the JPEG lib for reading an image from DATA which contains
5874 LEN bytes. CINFO is the decompression info structure created for
5875 reading the image. */
5876
5877 static void
5878 jpeg_memory_src (cinfo, data, len)
5879 j_decompress_ptr cinfo;
5880 JOCTET *data;
5881 unsigned int len;
5882 {
5883 struct jpeg_source_mgr *src;
5884
5885 if (cinfo->src == NULL)
5886 {
5887 /* First time for this JPEG object? */
5888 cinfo->src = (struct jpeg_source_mgr *)
5889 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
5890 sizeof (struct jpeg_source_mgr));
5891 src = (struct jpeg_source_mgr *) cinfo->src;
5892 src->next_input_byte = data;
5893 }
5894
5895 src = (struct jpeg_source_mgr *) cinfo->src;
5896 src->init_source = our_init_source;
5897 src->fill_input_buffer = our_fill_input_buffer;
5898 src->skip_input_data = our_skip_input_data;
5899 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
5900 src->term_source = our_term_source;
5901 src->bytes_in_buffer = len;
5902 src->next_input_byte = data;
5903 }
5904
5905
5906 /* Load image IMG for use on frame F. Patterned after example.c
5907 from the JPEG lib. */
5908
5909 static int
5910 jpeg_load (f, img)
5911 struct frame *f;
5912 struct image *img;
5913 {
5914 struct jpeg_decompress_struct cinfo;
5915 struct my_jpeg_error_mgr mgr;
5916 Lisp_Object file, specified_file;
5917 Lisp_Object specified_data;
5918 FILE * volatile fp = NULL;
5919 JSAMPARRAY buffer;
5920 int row_stride, x, y;
5921 XImagePtr ximg = NULL;
5922 int rc;
5923 unsigned long *colors;
5924 int width, height;
5925 struct gcpro gcpro1;
5926
5927 /* Open the JPEG file. */
5928 specified_file = image_spec_value (img->spec, QCfile, NULL);
5929 specified_data = image_spec_value (img->spec, QCdata, NULL);
5930 file = Qnil;
5931 GCPRO1 (file);
5932
5933 if (NILP (specified_data))
5934 {
5935 file = x_find_image_file (specified_file);
5936 if (!STRINGP (file))
5937 {
5938 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5939 UNGCPRO;
5940 return 0;
5941 }
5942
5943 fp = fopen (SDATA (file), "rb");
5944 if (fp == NULL)
5945 {
5946 image_error ("Cannot open `%s'", file, Qnil);
5947 UNGCPRO;
5948 return 0;
5949 }
5950 }
5951
5952 /* Customize libjpeg's error handling to call my_error_exit when an
5953 error is detected. This function will perform a longjmp. */
5954 cinfo.err = fn_jpeg_std_error (&mgr.pub);
5955 mgr.pub.error_exit = my_error_exit;
5956
5957 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
5958 {
5959 if (rc == 1)
5960 {
5961 /* Called from my_error_exit. Display a JPEG error. */
5962 char buffer[JMSG_LENGTH_MAX];
5963 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
5964 image_error ("Error reading JPEG image `%s': %s", img->spec,
5965 build_string (buffer));
5966 }
5967
5968 /* Close the input file and destroy the JPEG object. */
5969 if (fp)
5970 fclose ((FILE *) fp);
5971 fn_jpeg_destroy_decompress (&cinfo);
5972
5973 /* If we already have an XImage, free that. */
5974 x_destroy_x_image (ximg);
5975
5976 /* Free pixmap and colors. */
5977 x_clear_image (f, img);
5978
5979 UNGCPRO;
5980 return 0;
5981 }
5982
5983 /* Create the JPEG decompression object. Let it read from fp.
5984 Read the JPEG image header. */
5985 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
5986
5987 if (NILP (specified_data))
5988 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
5989 else
5990 jpeg_memory_src (&cinfo, SDATA (specified_data),
5991 SBYTES (specified_data));
5992
5993 fn_jpeg_read_header (&cinfo, TRUE);
5994
5995 /* Customize decompression so that color quantization will be used.
5996 Start decompression. */
5997 cinfo.quantize_colors = TRUE;
5998 fn_jpeg_start_decompress (&cinfo);
5999 width = img->width = cinfo.output_width;
6000 height = img->height = cinfo.output_height;
6001
6002 /* Create X image and pixmap. */
6003 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6004 longjmp (mgr.setjmp_buffer, 2);
6005
6006 /* Allocate colors. When color quantization is used,
6007 cinfo.actual_number_of_colors has been set with the number of
6008 colors generated, and cinfo.colormap is a two-dimensional array
6009 of color indices in the range 0..cinfo.actual_number_of_colors.
6010 No more than 255 colors will be generated. */
6011 {
6012 int i, ir, ig, ib;
6013
6014 if (cinfo.out_color_components > 2)
6015 ir = 0, ig = 1, ib = 2;
6016 else if (cinfo.out_color_components > 1)
6017 ir = 0, ig = 1, ib = 0;
6018 else
6019 ir = 0, ig = 0, ib = 0;
6020
6021 /* Use the color table mechanism because it handles colors that
6022 cannot be allocated nicely. Such colors will be replaced with
6023 a default color, and we don't have to care about which colors
6024 can be freed safely, and which can't. */
6025 init_color_table ();
6026 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6027 * sizeof *colors);
6028
6029 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6030 {
6031 /* Multiply RGB values with 255 because X expects RGB values
6032 in the range 0..0xffff. */
6033 int r = cinfo.colormap[ir][i] << 8;
6034 int g = cinfo.colormap[ig][i] << 8;
6035 int b = cinfo.colormap[ib][i] << 8;
6036 colors[i] = lookup_rgb_color (f, r, g, b);
6037 }
6038
6039 #ifdef COLOR_TABLE_SUPPORT
6040 /* Remember those colors actually allocated. */
6041 img->colors = colors_in_color_table (&img->ncolors);
6042 free_color_table ();
6043 #endif /* COLOR_TABLE_SUPPORT */
6044 }
6045
6046 /* Read pixels. */
6047 row_stride = width * cinfo.output_components;
6048 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6049 row_stride, 1);
6050 for (y = 0; y < height; ++y)
6051 {
6052 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6053 for (x = 0; x < cinfo.output_width; ++x)
6054 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6055 }
6056
6057 /* Clean up. */
6058 fn_jpeg_finish_decompress (&cinfo);
6059 fn_jpeg_destroy_decompress (&cinfo);
6060 if (fp)
6061 fclose ((FILE *) fp);
6062
6063 /* Maybe fill in the background field while we have ximg handy. */
6064 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6065 IMAGE_BACKGROUND (img, f, ximg);
6066
6067 /* Put the image into the pixmap. */
6068 x_put_x_image (f, ximg, img->pixmap, width, height);
6069 x_destroy_x_image (ximg);
6070 UNGCPRO;
6071 return 1;
6072 }
6073
6074 #else /* HAVE_JPEG */
6075
6076 #ifdef MAC_OS
6077 static int
6078 jpeg_load (f, img)
6079 struct frame *f;
6080 struct image *img;
6081 {
6082 #ifdef MAC_OSX
6083 return image_load_quartz2d (f, img, 0);
6084 #else
6085 return image_load_quicktime (f, img, kQTFileTypeJPEG);
6086 #endif
6087 }
6088 #endif /* MAC_OS */
6089
6090 #endif /* !HAVE_JPEG */
6091
6092
6093 \f
6094 /***********************************************************************
6095 TIFF
6096 ***********************************************************************/
6097
6098 #if defined (HAVE_TIFF) || defined (MAC_OS)
6099
6100 static int tiff_image_p P_ ((Lisp_Object object));
6101 static int tiff_load P_ ((struct frame *f, struct image *img));
6102
6103 /* The symbol `tiff' identifying images of this type. */
6104
6105 Lisp_Object Qtiff;
6106
6107 /* Indices of image specification fields in tiff_format, below. */
6108
6109 enum tiff_keyword_index
6110 {
6111 TIFF_TYPE,
6112 TIFF_DATA,
6113 TIFF_FILE,
6114 TIFF_ASCENT,
6115 TIFF_MARGIN,
6116 TIFF_RELIEF,
6117 TIFF_ALGORITHM,
6118 TIFF_HEURISTIC_MASK,
6119 TIFF_MASK,
6120 TIFF_BACKGROUND,
6121 TIFF_LAST
6122 };
6123
6124 /* Vector of image_keyword structures describing the format
6125 of valid user-defined image specifications. */
6126
6127 static struct image_keyword tiff_format[TIFF_LAST] =
6128 {
6129 {":type", IMAGE_SYMBOL_VALUE, 1},
6130 {":data", IMAGE_STRING_VALUE, 0},
6131 {":file", IMAGE_STRING_VALUE, 0},
6132 {":ascent", IMAGE_ASCENT_VALUE, 0},
6133 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6134 {":relief", IMAGE_INTEGER_VALUE, 0},
6135 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6136 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6137 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6138 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6139 };
6140
6141 /* Structure describing the image type `tiff'. */
6142
6143 static struct image_type tiff_type =
6144 {
6145 &Qtiff,
6146 tiff_image_p,
6147 tiff_load,
6148 x_clear_image,
6149 NULL
6150 };
6151
6152 /* Return non-zero if OBJECT is a valid TIFF image specification. */
6153
6154 static int
6155 tiff_image_p (object)
6156 Lisp_Object object;
6157 {
6158 struct image_keyword fmt[TIFF_LAST];
6159 bcopy (tiff_format, fmt, sizeof fmt);
6160
6161 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6162 return 0;
6163
6164 /* Must specify either the :data or :file keyword. */
6165 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6166 }
6167
6168 #endif /* HAVE_TIFF || MAC_OS */
6169
6170 #ifdef HAVE_TIFF
6171
6172 #include <tiffio.h>
6173
6174 #ifdef HAVE_NTGUI
6175
6176 /* TIFF library details. */
6177 DEF_IMGLIB_FN (TIFFSetErrorHandler);
6178 DEF_IMGLIB_FN (TIFFSetWarningHandler);
6179 DEF_IMGLIB_FN (TIFFOpen);
6180 DEF_IMGLIB_FN (TIFFClientOpen);
6181 DEF_IMGLIB_FN (TIFFGetField);
6182 DEF_IMGLIB_FN (TIFFReadRGBAImage);
6183 DEF_IMGLIB_FN (TIFFClose);
6184
6185 static int
6186 init_tiff_functions (void)
6187 {
6188 HMODULE library;
6189
6190 if (!(library = LoadLibrary ("libtiff.dll")))
6191 return 0;
6192
6193 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6194 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6195 LOAD_IMGLIB_FN (library, TIFFOpen);
6196 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6197 LOAD_IMGLIB_FN (library, TIFFGetField);
6198 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
6199 LOAD_IMGLIB_FN (library, TIFFClose);
6200 return 1;
6201 }
6202
6203 #else
6204
6205 #define fn_TIFFSetErrorHandler TIFFSetErrorHandler
6206 #define fn_TIFFSetWarningHandler TIFFSetWarningHandler
6207 #define fn_TIFFOpen TIFFOpen
6208 #define fn_TIFFClientOpen TIFFClientOpen
6209 #define fn_TIFFGetField TIFFGetField
6210 #define fn_TIFFReadRGBAImage TIFFReadRGBAImage
6211 #define fn_TIFFClose TIFFClose
6212
6213 #endif /* HAVE_NTGUI */
6214
6215
6216 /* Reading from a memory buffer for TIFF images Based on the PNG
6217 memory source, but we have to provide a lot of extra functions.
6218 Blah.
6219
6220 We really only need to implement read and seek, but I am not
6221 convinced that the TIFF library is smart enough not to destroy
6222 itself if we only hand it the function pointers we need to
6223 override. */
6224
6225 typedef struct
6226 {
6227 unsigned char *bytes;
6228 size_t len;
6229 int index;
6230 }
6231 tiff_memory_source;
6232
6233 static size_t
6234 tiff_read_from_memory (data, buf, size)
6235 thandle_t data;
6236 tdata_t buf;
6237 tsize_t size;
6238 {
6239 tiff_memory_source *src = (tiff_memory_source *) data;
6240
6241 if (size > src->len - src->index)
6242 return (size_t) -1;
6243 bcopy (src->bytes + src->index, buf, size);
6244 src->index += size;
6245 return size;
6246 }
6247
6248 static size_t
6249 tiff_write_from_memory (data, buf, size)
6250 thandle_t data;
6251 tdata_t buf;
6252 tsize_t size;
6253 {
6254 return (size_t) -1;
6255 }
6256
6257 static toff_t
6258 tiff_seek_in_memory (data, off, whence)
6259 thandle_t data;
6260 toff_t off;
6261 int whence;
6262 {
6263 tiff_memory_source *src = (tiff_memory_source *) data;
6264 int idx;
6265
6266 switch (whence)
6267 {
6268 case SEEK_SET: /* Go from beginning of source. */
6269 idx = off;
6270 break;
6271
6272 case SEEK_END: /* Go from end of source. */
6273 idx = src->len + off;
6274 break;
6275
6276 case SEEK_CUR: /* Go from current position. */
6277 idx = src->index + off;
6278 break;
6279
6280 default: /* Invalid `whence'. */
6281 return -1;
6282 }
6283
6284 if (idx > src->len || idx < 0)
6285 return -1;
6286
6287 src->index = idx;
6288 return src->index;
6289 }
6290
6291 static int
6292 tiff_close_memory (data)
6293 thandle_t data;
6294 {
6295 /* NOOP */
6296 return 0;
6297 }
6298
6299 static int
6300 tiff_mmap_memory (data, pbase, psize)
6301 thandle_t data;
6302 tdata_t *pbase;
6303 toff_t *psize;
6304 {
6305 /* It is already _IN_ memory. */
6306 return 0;
6307 }
6308
6309 static void
6310 tiff_unmap_memory (data, base, size)
6311 thandle_t data;
6312 tdata_t base;
6313 toff_t size;
6314 {
6315 /* We don't need to do this. */
6316 }
6317
6318 static toff_t
6319 tiff_size_of_memory (data)
6320 thandle_t data;
6321 {
6322 return ((tiff_memory_source *) data)->len;
6323 }
6324
6325
6326 static void
6327 tiff_error_handler (title, format, ap)
6328 const char *title, *format;
6329 va_list ap;
6330 {
6331 char buf[512];
6332 int len;
6333
6334 len = sprintf (buf, "TIFF error: %s ", title);
6335 vsprintf (buf + len, format, ap);
6336 add_to_log (buf, Qnil, Qnil);
6337 }
6338
6339
6340 static void
6341 tiff_warning_handler (title, format, ap)
6342 const char *title, *format;
6343 va_list ap;
6344 {
6345 char buf[512];
6346 int len;
6347
6348 len = sprintf (buf, "TIFF warning: %s ", title);
6349 vsprintf (buf + len, format, ap);
6350 add_to_log (buf, Qnil, Qnil);
6351 }
6352
6353
6354 /* Load TIFF image IMG for use on frame F. Value is non-zero if
6355 successful. */
6356
6357 static int
6358 tiff_load (f, img)
6359 struct frame *f;
6360 struct image *img;
6361 {
6362 Lisp_Object file, specified_file;
6363 Lisp_Object specified_data;
6364 TIFF *tiff;
6365 int width, height, x, y;
6366 uint32 *buf;
6367 int rc;
6368 XImagePtr ximg;
6369 struct gcpro gcpro1;
6370 tiff_memory_source memsrc;
6371
6372 specified_file = image_spec_value (img->spec, QCfile, NULL);
6373 specified_data = image_spec_value (img->spec, QCdata, NULL);
6374 file = Qnil;
6375 GCPRO1 (file);
6376
6377 fn_TIFFSetErrorHandler (tiff_error_handler);
6378 fn_TIFFSetWarningHandler (tiff_warning_handler);
6379
6380 if (NILP (specified_data))
6381 {
6382 /* Read from a file */
6383 file = x_find_image_file (specified_file);
6384 if (!STRINGP (file))
6385 {
6386 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6387 UNGCPRO;
6388 return 0;
6389 }
6390
6391 /* Try to open the image file. */
6392 tiff = fn_TIFFOpen (SDATA (file), "r");
6393 if (tiff == NULL)
6394 {
6395 image_error ("Cannot open `%s'", file, Qnil);
6396 UNGCPRO;
6397 return 0;
6398 }
6399 }
6400 else
6401 {
6402 /* Memory source! */
6403 memsrc.bytes = SDATA (specified_data);
6404 memsrc.len = SBYTES (specified_data);
6405 memsrc.index = 0;
6406
6407 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
6408 (TIFFReadWriteProc) tiff_read_from_memory,
6409 (TIFFReadWriteProc) tiff_write_from_memory,
6410 tiff_seek_in_memory,
6411 tiff_close_memory,
6412 tiff_size_of_memory,
6413 tiff_mmap_memory,
6414 tiff_unmap_memory);
6415
6416 if (!tiff)
6417 {
6418 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
6419 UNGCPRO;
6420 return 0;
6421 }
6422 }
6423
6424 /* Get width and height of the image, and allocate a raster buffer
6425 of width x height 32-bit values. */
6426 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
6427 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6428 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
6429
6430 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
6431 fn_TIFFClose (tiff);
6432 if (!rc)
6433 {
6434 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
6435 xfree (buf);
6436 UNGCPRO;
6437 return 0;
6438 }
6439
6440 /* Create the X image and pixmap. */
6441 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6442 {
6443 xfree (buf);
6444 UNGCPRO;
6445 return 0;
6446 }
6447
6448 /* Initialize the color table. */
6449 init_color_table ();
6450
6451 /* Process the pixel raster. Origin is in the lower-left corner. */
6452 for (y = 0; y < height; ++y)
6453 {
6454 uint32 *row = buf + y * width;
6455
6456 for (x = 0; x < width; ++x)
6457 {
6458 uint32 abgr = row[x];
6459 int r = TIFFGetR (abgr) << 8;
6460 int g = TIFFGetG (abgr) << 8;
6461 int b = TIFFGetB (abgr) << 8;
6462 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
6463 }
6464 }
6465
6466 #ifdef COLOR_TABLE_SUPPORT
6467 /* Remember the colors allocated for the image. Free the color table. */
6468 img->colors = colors_in_color_table (&img->ncolors);
6469 free_color_table ();
6470 #endif /* COLOR_TABLE_SUPPORT */
6471
6472 img->width = width;
6473 img->height = height;
6474
6475 /* Maybe fill in the background field while we have ximg handy. */
6476 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6477 IMAGE_BACKGROUND (img, f, ximg);
6478
6479 /* Put the image into the pixmap, then free the X image and its buffer. */
6480 x_put_x_image (f, ximg, img->pixmap, width, height);
6481 x_destroy_x_image (ximg);
6482 xfree (buf);
6483
6484 UNGCPRO;
6485 return 1;
6486 }
6487
6488 #else /* HAVE_TIFF */
6489
6490 #ifdef MAC_OS
6491 static int
6492 tiff_load (f, img)
6493 struct frame *f;
6494 struct image *img;
6495 {
6496 return image_load_quicktime (f, img, kQTFileTypeTIFF);
6497 }
6498 #endif /* MAC_OS */
6499
6500 #endif /* !HAVE_TIFF */
6501
6502
6503 \f
6504 /***********************************************************************
6505 GIF
6506 ***********************************************************************/
6507
6508 #if defined (HAVE_GIF) || defined (MAC_OS)
6509
6510 static int gif_image_p P_ ((Lisp_Object object));
6511 static int gif_load P_ ((struct frame *f, struct image *img));
6512
6513 /* The symbol `gif' identifying images of this type. */
6514
6515 Lisp_Object Qgif;
6516
6517 /* Indices of image specification fields in gif_format, below. */
6518
6519 enum gif_keyword_index
6520 {
6521 GIF_TYPE,
6522 GIF_DATA,
6523 GIF_FILE,
6524 GIF_ASCENT,
6525 GIF_MARGIN,
6526 GIF_RELIEF,
6527 GIF_ALGORITHM,
6528 GIF_HEURISTIC_MASK,
6529 GIF_MASK,
6530 GIF_IMAGE,
6531 GIF_BACKGROUND,
6532 GIF_LAST
6533 };
6534
6535 /* Vector of image_keyword structures describing the format
6536 of valid user-defined image specifications. */
6537
6538 static struct image_keyword gif_format[GIF_LAST] =
6539 {
6540 {":type", IMAGE_SYMBOL_VALUE, 1},
6541 {":data", IMAGE_STRING_VALUE, 0},
6542 {":file", IMAGE_STRING_VALUE, 0},
6543 {":ascent", IMAGE_ASCENT_VALUE, 0},
6544 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6545 {":relief", IMAGE_INTEGER_VALUE, 0},
6546 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6547 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6548 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6549 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6550 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6551 };
6552
6553 /* Structure describing the image type `gif'. */
6554
6555 static struct image_type gif_type =
6556 {
6557 &Qgif,
6558 gif_image_p,
6559 gif_load,
6560 x_clear_image,
6561 NULL
6562 };
6563
6564 /* Return non-zero if OBJECT is a valid GIF image specification. */
6565
6566 static int
6567 gif_image_p (object)
6568 Lisp_Object object;
6569 {
6570 struct image_keyword fmt[GIF_LAST];
6571 bcopy (gif_format, fmt, sizeof fmt);
6572
6573 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
6574 return 0;
6575
6576 /* Must specify either the :data or :file keyword. */
6577 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
6578 }
6579
6580 #endif /* HAVE_GIF || MAC_OS */
6581
6582 #ifdef HAVE_GIF
6583
6584 #if defined (HAVE_NTGUI) || defined (MAC_OS)
6585 /* avoid conflict with QuickdrawText.h */
6586 #define DrawText gif_DrawText
6587 #include <gif_lib.h>
6588 #undef DrawText
6589
6590 #else /* HAVE_NTGUI || MAC_OS */
6591
6592 #include <gif_lib.h>
6593
6594 #endif /* HAVE_NTGUI || MAC_OS */
6595
6596
6597 #ifdef HAVE_NTGUI
6598
6599 /* GIF library details. */
6600 DEF_IMGLIB_FN (DGifCloseFile);
6601 DEF_IMGLIB_FN (DGifSlurp);
6602 DEF_IMGLIB_FN (DGifOpen);
6603 DEF_IMGLIB_FN (DGifOpenFileName);
6604
6605 static int
6606 init_gif_functions (void)
6607 {
6608 HMODULE library;
6609
6610 if (!(library = LoadLibrary ("libungif.dll")))
6611 return 0;
6612
6613 LOAD_IMGLIB_FN (library, DGifCloseFile);
6614 LOAD_IMGLIB_FN (library, DGifSlurp);
6615 LOAD_IMGLIB_FN (library, DGifOpen);
6616 LOAD_IMGLIB_FN (library, DGifOpenFileName);
6617 return 1;
6618 }
6619
6620 #else
6621
6622 #define fn_DGifCloseFile DGifCloseFile
6623 #define fn_DGifSlurp DGifSlurp
6624 #define fn_DGifOpen DGifOpen
6625 #define fn_DGifOpenFileName DGifOpenFileName
6626
6627 #endif /* HAVE_NTGUI */
6628
6629 /* Reading a GIF image from memory
6630 Based on the PNG memory stuff to a certain extent. */
6631
6632 typedef struct
6633 {
6634 unsigned char *bytes;
6635 size_t len;
6636 int index;
6637 }
6638 gif_memory_source;
6639
6640 /* Make the current memory source available to gif_read_from_memory.
6641 It's done this way because not all versions of libungif support
6642 a UserData field in the GifFileType structure. */
6643 static gif_memory_source *current_gif_memory_src;
6644
6645 static int
6646 gif_read_from_memory (file, buf, len)
6647 GifFileType *file;
6648 GifByteType *buf;
6649 int len;
6650 {
6651 gif_memory_source *src = current_gif_memory_src;
6652
6653 if (len > src->len - src->index)
6654 return -1;
6655
6656 bcopy (src->bytes + src->index, buf, len);
6657 src->index += len;
6658 return len;
6659 }
6660
6661
6662 /* Load GIF image IMG for use on frame F. Value is non-zero if
6663 successful. */
6664
6665 static int
6666 gif_load (f, img)
6667 struct frame *f;
6668 struct image *img;
6669 {
6670 Lisp_Object file, specified_file;
6671 Lisp_Object specified_data;
6672 int rc, width, height, x, y, i;
6673 XImagePtr ximg;
6674 ColorMapObject *gif_color_map;
6675 unsigned long pixel_colors[256];
6676 GifFileType *gif;
6677 struct gcpro gcpro1;
6678 Lisp_Object image;
6679 int ino, image_left, image_top, image_width, image_height;
6680 gif_memory_source memsrc;
6681 unsigned char *raster;
6682
6683 specified_file = image_spec_value (img->spec, QCfile, NULL);
6684 specified_data = image_spec_value (img->spec, QCdata, NULL);
6685 file = Qnil;
6686 GCPRO1 (file);
6687
6688 if (NILP (specified_data))
6689 {
6690 file = x_find_image_file (specified_file);
6691 if (!STRINGP (file))
6692 {
6693 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6694 UNGCPRO;
6695 return 0;
6696 }
6697
6698 /* Open the GIF file. */
6699 gif = fn_DGifOpenFileName (SDATA (file));
6700 if (gif == NULL)
6701 {
6702 image_error ("Cannot open `%s'", file, Qnil);
6703 UNGCPRO;
6704 return 0;
6705 }
6706 }
6707 else
6708 {
6709 /* Read from memory! */
6710 current_gif_memory_src = &memsrc;
6711 memsrc.bytes = SDATA (specified_data);
6712 memsrc.len = SBYTES (specified_data);
6713 memsrc.index = 0;
6714
6715 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
6716 if (!gif)
6717 {
6718 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
6719 UNGCPRO;
6720 return 0;
6721 }
6722 }
6723
6724 /* Read entire contents. */
6725 rc = fn_DGifSlurp (gif);
6726 if (rc == GIF_ERROR)
6727 {
6728 image_error ("Error reading `%s'", img->spec, Qnil);
6729 fn_DGifCloseFile (gif);
6730 UNGCPRO;
6731 return 0;
6732 }
6733
6734 image = image_spec_value (img->spec, QCindex, NULL);
6735 ino = INTEGERP (image) ? XFASTINT (image) : 0;
6736 if (ino >= gif->ImageCount)
6737 {
6738 image_error ("Invalid image number `%s' in image `%s'",
6739 image, img->spec);
6740 fn_DGifCloseFile (gif);
6741 UNGCPRO;
6742 return 0;
6743 }
6744
6745 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
6746 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
6747
6748 /* Create the X image and pixmap. */
6749 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6750 {
6751 fn_DGifCloseFile (gif);
6752 UNGCPRO;
6753 return 0;
6754 }
6755
6756 /* Allocate colors. */
6757 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
6758 if (!gif_color_map)
6759 gif_color_map = gif->SColorMap;
6760 init_color_table ();
6761 bzero (pixel_colors, sizeof pixel_colors);
6762
6763 for (i = 0; i < gif_color_map->ColorCount; ++i)
6764 {
6765 int r = gif_color_map->Colors[i].Red << 8;
6766 int g = gif_color_map->Colors[i].Green << 8;
6767 int b = gif_color_map->Colors[i].Blue << 8;
6768 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
6769 }
6770
6771 #ifdef COLOR_TABLE_SUPPORT
6772 img->colors = colors_in_color_table (&img->ncolors);
6773 free_color_table ();
6774 #endif /* COLOR_TABLE_SUPPORT */
6775
6776 /* Clear the part of the screen image that are not covered by
6777 the image from the GIF file. Full animated GIF support
6778 requires more than can be done here (see the gif89 spec,
6779 disposal methods). Let's simply assume that the part
6780 not covered by a sub-image is in the frame's background color. */
6781 image_top = gif->SavedImages[ino].ImageDesc.Top;
6782 image_left = gif->SavedImages[ino].ImageDesc.Left;
6783 image_width = gif->SavedImages[ino].ImageDesc.Width;
6784 image_height = gif->SavedImages[ino].ImageDesc.Height;
6785
6786 for (y = 0; y < image_top; ++y)
6787 for (x = 0; x < width; ++x)
6788 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6789
6790 for (y = image_top + image_height; y < height; ++y)
6791 for (x = 0; x < width; ++x)
6792 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6793
6794 for (y = image_top; y < image_top + image_height; ++y)
6795 {
6796 for (x = 0; x < image_left; ++x)
6797 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6798 for (x = image_left + image_width; x < width; ++x)
6799 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6800 }
6801
6802 /* Read the GIF image into the X image. We use a local variable
6803 `raster' here because RasterBits below is a char *, and invites
6804 problems with bytes >= 0x80. */
6805 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
6806
6807 if (gif->SavedImages[ino].ImageDesc.Interlace)
6808 {
6809 static int interlace_start[] = {0, 4, 2, 1};
6810 static int interlace_increment[] = {8, 8, 4, 2};
6811 int pass;
6812 int row = interlace_start[0];
6813
6814 pass = 0;
6815
6816 for (y = 0; y < image_height; y++)
6817 {
6818 if (row >= image_height)
6819 {
6820 row = interlace_start[++pass];
6821 while (row >= image_height)
6822 row = interlace_start[++pass];
6823 }
6824
6825 for (x = 0; x < image_width; x++)
6826 {
6827 int i = raster[(y * image_width) + x];
6828 XPutPixel (ximg, x + image_left, row + image_top,
6829 pixel_colors[i]);
6830 }
6831
6832 row += interlace_increment[pass];
6833 }
6834 }
6835 else
6836 {
6837 for (y = 0; y < image_height; ++y)
6838 for (x = 0; x < image_width; ++x)
6839 {
6840 int i = raster[y * image_width + x];
6841 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
6842 }
6843 }
6844
6845 fn_DGifCloseFile (gif);
6846
6847 /* Maybe fill in the background field while we have ximg handy. */
6848 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6849 IMAGE_BACKGROUND (img, f, ximg);
6850
6851 /* Put the image into the pixmap, then free the X image and its buffer. */
6852 x_put_x_image (f, ximg, img->pixmap, width, height);
6853 x_destroy_x_image (ximg);
6854
6855 UNGCPRO;
6856 return 1;
6857 }
6858
6859 #else
6860
6861 #ifdef MAC_OS
6862 static int
6863 gif_load (f, img)
6864 struct frame *f;
6865 struct image *img;
6866 {
6867 Lisp_Object specified_file, file;
6868 Lisp_Object specified_data;
6869 OSErr err;
6870 Boolean graphic_p, movie_p, prefer_graphic_p;
6871 Handle dh = NULL;
6872 Movie movie = NULL;
6873 Lisp_Object image;
6874 Track track = NULL;
6875 Media media = NULL;
6876 long nsamples;
6877 Rect rect;
6878 Lisp_Object specified_bg;
6879 XColor color;
6880 RGBColor bg_color;
6881 int width, height;
6882 XImagePtr ximg;
6883 TimeValue time;
6884 struct gcpro gcpro1;
6885 int ino;
6886
6887 specified_file = image_spec_value (img->spec, QCfile, NULL);
6888 specified_data = image_spec_value (img->spec, QCdata, NULL);
6889
6890 if (NILP (specified_data))
6891 {
6892 /* Read from a file */
6893 FSSpec fss;
6894 short refnum;
6895
6896 err = find_image_fsspec (specified_file, &file, &fss);
6897 if (err != noErr)
6898 {
6899 if (err == fnfErr)
6900 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6901 else
6902 goto open_error;
6903 }
6904
6905 err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0,
6906 &graphic_p, &movie_p, &prefer_graphic_p, 0);
6907 if (err != noErr)
6908 goto open_error;
6909
6910 if (!graphic_p && !movie_p)
6911 goto open_error;
6912 if (prefer_graphic_p)
6913 return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL);
6914 err = OpenMovieFile (&fss, &refnum, fsRdPerm);
6915 if (err != noErr)
6916 goto open_error;
6917 err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL);
6918 CloseMovieFile (refnum);
6919 if (err != noErr)
6920 {
6921 image_error ("Error reading `%s'", file, Qnil);
6922 return 0;
6923 }
6924 }
6925 else
6926 {
6927 /* Memory source! */
6928 Handle dref = NULL;
6929 long file_type_atom[3];
6930
6931 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
6932 if (err != noErr)
6933 {
6934 image_error ("Cannot allocate data handle for `%s'",
6935 img->spec, Qnil);
6936 goto error;
6937 }
6938
6939 file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3);
6940 file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
6941 file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF);
6942 err = PtrToHand (&dh, &dref, sizeof (Handle));
6943 if (err == noErr)
6944 /* no file name */
6945 err = PtrAndHand ("\p", dref, 1);
6946 if (err == noErr)
6947 err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3);
6948 if (err != noErr)
6949 {
6950 image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil);
6951 goto error;
6952 }
6953 err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p,
6954 &movie_p, &prefer_graphic_p, 0);
6955 if (err != noErr)
6956 goto open_error;
6957
6958 if (!graphic_p && !movie_p)
6959 goto open_error;
6960 if (prefer_graphic_p)
6961 {
6962 int success_p;
6963
6964 DisposeHandle (dref);
6965 success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh);
6966 DisposeHandle (dh);
6967 return success_p;
6968 }
6969 err = NewMovieFromDataRef (&movie, 0, NULL, dref,
6970 HandleDataHandlerSubType);
6971 DisposeHandle (dref);
6972 if (err != noErr)
6973 goto open_error;
6974 }
6975
6976 image = image_spec_value (img->spec, QCindex, NULL);
6977 ino = INTEGERP (image) ? XFASTINT (image) : 0;
6978 track = GetMovieIndTrack (movie, 1);
6979 media = GetTrackMedia (track);
6980 nsamples = GetMediaSampleCount (media);
6981 if (ino >= nsamples)
6982 {
6983 image_error ("Invalid image number `%s' in image `%s'",
6984 image, img->spec);
6985 goto error;
6986 }
6987
6988 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
6989 if (!STRINGP (specified_bg) ||
6990 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
6991 {
6992 color.pixel = FRAME_BACKGROUND_PIXEL (f);
6993 color.red = RED16_FROM_ULONG (color.pixel);
6994 color.green = GREEN16_FROM_ULONG (color.pixel);
6995 color.blue = BLUE16_FROM_ULONG (color.pixel);
6996 }
6997 GetMovieBox (movie, &rect);
6998 width = img->width = rect.right - rect.left;
6999 height = img->height = rect.bottom - rect.top;
7000 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7001 goto error;
7002
7003 SetGWorld (ximg, NULL);
7004 bg_color.red = color.red;
7005 bg_color.green = color.green;
7006 bg_color.blue = color.blue;
7007 RGBBackColor (&bg_color);
7008 SetMovieActive (movie, TRUE);
7009 SetMovieGWorld (movie, ximg, NULL);
7010 SampleNumToMediaTime (media, ino + 1, &time, NULL);
7011 SetMovieTimeValue (movie, time);
7012 MoviesTask (movie, 0L);
7013 DisposeTrackMedia (media);
7014 DisposeMovieTrack (track);
7015 DisposeMovie (movie);
7016 if (dh)
7017 DisposeHandle (dh);
7018 /* Maybe fill in the background field while we have ximg handy. */
7019 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7020 IMAGE_BACKGROUND (img, f, ximg);
7021
7022 /* Put the image into the pixmap. */
7023 x_put_x_image (f, ximg, img->pixmap, width, height);
7024 x_destroy_x_image (ximg);
7025 return 1;
7026
7027 open_error:
7028 image_error ("Cannot open `%s'", file, Qnil);
7029 error:
7030 if (media)
7031 DisposeTrackMedia (media);
7032 if (track)
7033 DisposeMovieTrack (track);
7034 if (movie)
7035 DisposeMovie (movie);
7036 if (dh)
7037 DisposeHandle (dh);
7038 return 0;
7039 }
7040 #endif /* MAC_OS */
7041
7042 #endif /* HAVE_GIF */
7043
7044
7045 \f
7046 /***********************************************************************
7047 Ghostscript
7048 ***********************************************************************/
7049
7050 #ifdef HAVE_X_WINDOWS
7051 #define HAVE_GHOSTSCRIPT 1
7052 #endif /* HAVE_X_WINDOWS */
7053
7054 /* The symbol `postscript' identifying images of this type. */
7055
7056 Lisp_Object Qpostscript;
7057
7058 #ifdef HAVE_GHOSTSCRIPT
7059
7060 static int gs_image_p P_ ((Lisp_Object object));
7061 static int gs_load P_ ((struct frame *f, struct image *img));
7062 static void gs_clear_image P_ ((struct frame *f, struct image *img));
7063
7064 /* Keyword symbols. */
7065
7066 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
7067
7068 /* Indices of image specification fields in gs_format, below. */
7069
7070 enum gs_keyword_index
7071 {
7072 GS_TYPE,
7073 GS_PT_WIDTH,
7074 GS_PT_HEIGHT,
7075 GS_FILE,
7076 GS_LOADER,
7077 GS_BOUNDING_BOX,
7078 GS_ASCENT,
7079 GS_MARGIN,
7080 GS_RELIEF,
7081 GS_ALGORITHM,
7082 GS_HEURISTIC_MASK,
7083 GS_MASK,
7084 GS_BACKGROUND,
7085 GS_LAST
7086 };
7087
7088 /* Vector of image_keyword structures describing the format
7089 of valid user-defined image specifications. */
7090
7091 static struct image_keyword gs_format[GS_LAST] =
7092 {
7093 {":type", IMAGE_SYMBOL_VALUE, 1},
7094 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7095 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7096 {":file", IMAGE_STRING_VALUE, 1},
7097 {":loader", IMAGE_FUNCTION_VALUE, 0},
7098 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7099 {":ascent", IMAGE_ASCENT_VALUE, 0},
7100 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7101 {":relief", IMAGE_INTEGER_VALUE, 0},
7102 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7103 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7104 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7105 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7106 };
7107
7108 /* Structure describing the image type `ghostscript'. */
7109
7110 static struct image_type gs_type =
7111 {
7112 &Qpostscript,
7113 gs_image_p,
7114 gs_load,
7115 gs_clear_image,
7116 NULL
7117 };
7118
7119
7120 /* Free X resources of Ghostscript image IMG which is used on frame F. */
7121
7122 static void
7123 gs_clear_image (f, img)
7124 struct frame *f;
7125 struct image *img;
7126 {
7127 /* IMG->data.ptr_val may contain a recorded colormap. */
7128 xfree (img->data.ptr_val);
7129 x_clear_image (f, img);
7130 }
7131
7132
7133 /* Return non-zero if OBJECT is a valid Ghostscript image
7134 specification. */
7135
7136 static int
7137 gs_image_p (object)
7138 Lisp_Object object;
7139 {
7140 struct image_keyword fmt[GS_LAST];
7141 Lisp_Object tem;
7142 int i;
7143
7144 bcopy (gs_format, fmt, sizeof fmt);
7145
7146 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
7147 return 0;
7148
7149 /* Bounding box must be a list or vector containing 4 integers. */
7150 tem = fmt[GS_BOUNDING_BOX].value;
7151 if (CONSP (tem))
7152 {
7153 for (i = 0; i < 4; ++i, tem = XCDR (tem))
7154 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
7155 return 0;
7156 if (!NILP (tem))
7157 return 0;
7158 }
7159 else if (VECTORP (tem))
7160 {
7161 if (XVECTOR (tem)->size != 4)
7162 return 0;
7163 for (i = 0; i < 4; ++i)
7164 if (!INTEGERP (XVECTOR (tem)->contents[i]))
7165 return 0;
7166 }
7167 else
7168 return 0;
7169
7170 return 1;
7171 }
7172
7173
7174 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
7175 if successful. */
7176
7177 static int
7178 gs_load (f, img)
7179 struct frame *f;
7180 struct image *img;
7181 {
7182 char buffer[100];
7183 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
7184 struct gcpro gcpro1, gcpro2;
7185 Lisp_Object frame;
7186 double in_width, in_height;
7187 Lisp_Object pixel_colors = Qnil;
7188
7189 /* Compute pixel size of pixmap needed from the given size in the
7190 image specification. Sizes in the specification are in pt. 1 pt
7191 = 1/72 in, xdpi and ydpi are stored in the frame's X display
7192 info. */
7193 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
7194 in_width = XFASTINT (pt_width) / 72.0;
7195 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
7196 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
7197 in_height = XFASTINT (pt_height) / 72.0;
7198 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
7199
7200 /* Create the pixmap. */
7201 xassert (img->pixmap == NO_PIXMAP);
7202
7203 /* Only W32 version did BLOCK_INPUT here. ++kfs */
7204 BLOCK_INPUT;
7205 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7206 img->width, img->height,
7207 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
7208 UNBLOCK_INPUT;
7209
7210 if (!img->pixmap)
7211 {
7212 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
7213 return 0;
7214 }
7215
7216 /* Call the loader to fill the pixmap. It returns a process object
7217 if successful. We do not record_unwind_protect here because
7218 other places in redisplay like calling window scroll functions
7219 don't either. Let the Lisp loader use `unwind-protect' instead. */
7220 GCPRO2 (window_and_pixmap_id, pixel_colors);
7221
7222 sprintf (buffer, "%lu %lu",
7223 (unsigned long) FRAME_X_WINDOW (f),
7224 (unsigned long) img->pixmap);
7225 window_and_pixmap_id = build_string (buffer);
7226
7227 sprintf (buffer, "%lu %lu",
7228 FRAME_FOREGROUND_PIXEL (f),
7229 FRAME_BACKGROUND_PIXEL (f));
7230 pixel_colors = build_string (buffer);
7231
7232 XSETFRAME (frame, f);
7233 loader = image_spec_value (img->spec, QCloader, NULL);
7234 if (NILP (loader))
7235 loader = intern ("gs-load-image");
7236
7237 img->data.lisp_val = call6 (loader, frame, img->spec,
7238 make_number (img->width),
7239 make_number (img->height),
7240 window_and_pixmap_id,
7241 pixel_colors);
7242 UNGCPRO;
7243 return PROCESSP (img->data.lisp_val);
7244 }
7245
7246
7247 /* Kill the Ghostscript process that was started to fill PIXMAP on
7248 frame F. Called from XTread_socket when receiving an event
7249 telling Emacs that Ghostscript has finished drawing. */
7250
7251 void
7252 x_kill_gs_process (pixmap, f)
7253 Pixmap pixmap;
7254 struct frame *f;
7255 {
7256 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7257 int class, i;
7258 struct image *img;
7259
7260 /* Find the image containing PIXMAP. */
7261 for (i = 0; i < c->used; ++i)
7262 if (c->images[i]->pixmap == pixmap)
7263 break;
7264
7265 /* Should someone in between have cleared the image cache, for
7266 instance, give up. */
7267 if (i == c->used)
7268 return;
7269
7270 /* Kill the GS process. We should have found PIXMAP in the image
7271 cache and its image should contain a process object. */
7272 img = c->images[i];
7273 xassert (PROCESSP (img->data.lisp_val));
7274 Fkill_process (img->data.lisp_val, Qnil);
7275 img->data.lisp_val = Qnil;
7276
7277 #if defined (HAVE_X_WINDOWS)
7278
7279 /* On displays with a mutable colormap, figure out the colors
7280 allocated for the image by looking at the pixels of an XImage for
7281 img->pixmap. */
7282 class = FRAME_X_VISUAL (f)->class;
7283 if (class != StaticColor && class != StaticGray && class != TrueColor)
7284 {
7285 XImagePtr ximg;
7286
7287 BLOCK_INPUT;
7288
7289 /* Try to get an XImage for img->pixmep. */
7290 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7291 0, 0, img->width, img->height, ~0, ZPixmap);
7292 if (ximg)
7293 {
7294 int x, y;
7295
7296 /* Initialize the color table. */
7297 init_color_table ();
7298
7299 /* For each pixel of the image, look its color up in the
7300 color table. After having done so, the color table will
7301 contain an entry for each color used by the image. */
7302 for (y = 0; y < img->height; ++y)
7303 for (x = 0; x < img->width; ++x)
7304 {
7305 unsigned long pixel = XGetPixel (ximg, x, y);
7306 lookup_pixel_color (f, pixel);
7307 }
7308
7309 /* Record colors in the image. Free color table and XImage. */
7310 #ifdef COLOR_TABLE_SUPPORT
7311 img->colors = colors_in_color_table (&img->ncolors);
7312 free_color_table ();
7313 #endif
7314 XDestroyImage (ximg);
7315
7316 #if 0 /* This doesn't seem to be the case. If we free the colors
7317 here, we get a BadAccess later in x_clear_image when
7318 freeing the colors. */
7319 /* We have allocated colors once, but Ghostscript has also
7320 allocated colors on behalf of us. So, to get the
7321 reference counts right, free them once. */
7322 if (img->ncolors)
7323 x_free_colors (f, img->colors, img->ncolors);
7324 #endif
7325 }
7326 else
7327 image_error ("Cannot get X image of `%s'; colors will not be freed",
7328 img->spec, Qnil);
7329
7330 UNBLOCK_INPUT;
7331 }
7332 #endif /* HAVE_X_WINDOWS */
7333
7334 /* Now that we have the pixmap, compute mask and transform the
7335 image if requested. */
7336 BLOCK_INPUT;
7337 postprocess_image (f, img);
7338 UNBLOCK_INPUT;
7339 }
7340
7341 #endif /* HAVE_GHOSTSCRIPT */
7342
7343 \f
7344 /***********************************************************************
7345 Tests
7346 ***********************************************************************/
7347
7348 #if GLYPH_DEBUG
7349
7350 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
7351 doc: /* Value is non-nil if SPEC is a valid image specification. */)
7352 (spec)
7353 Lisp_Object spec;
7354 {
7355 return valid_image_p (spec) ? Qt : Qnil;
7356 }
7357
7358
7359 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
7360 (spec)
7361 Lisp_Object spec;
7362 {
7363 int id = -1;
7364
7365 if (valid_image_p (spec))
7366 id = lookup_image (SELECTED_FRAME (), spec);
7367
7368 debug_print (spec);
7369 return make_number (id);
7370 }
7371
7372 #endif /* GLYPH_DEBUG != 0 */
7373
7374
7375 /***********************************************************************
7376 Initialization
7377 ***********************************************************************/
7378
7379 void
7380 syms_of_image ()
7381 {
7382 QCascent = intern (":ascent");
7383 staticpro (&QCascent);
7384 QCmargin = intern (":margin");
7385 staticpro (&QCmargin);
7386 QCrelief = intern (":relief");
7387 staticpro (&QCrelief);
7388 QCconversion = intern (":conversion");
7389 staticpro (&QCconversion);
7390 QCcolor_symbols = intern (":color-symbols");
7391 staticpro (&QCcolor_symbols);
7392 QCheuristic_mask = intern (":heuristic-mask");
7393 staticpro (&QCheuristic_mask);
7394 QCindex = intern (":index");
7395 staticpro (&QCindex);
7396 QCmatrix = intern (":matrix");
7397 staticpro (&QCmatrix);
7398 QCcolor_adjustment = intern (":color-adjustment");
7399 staticpro (&QCcolor_adjustment);
7400 QCmask = intern (":mask");
7401 staticpro (&QCmask);
7402
7403 Qlaplace = intern ("laplace");
7404 staticpro (&Qlaplace);
7405 Qemboss = intern ("emboss");
7406 staticpro (&Qemboss);
7407 Qedge_detection = intern ("edge-detection");
7408 staticpro (&Qedge_detection);
7409 Qheuristic = intern ("heuristic");
7410 staticpro (&Qheuristic);
7411
7412 Qpostscript = intern ("postscript");
7413 staticpro (&Qpostscript);
7414 #ifdef HAVE_GHOSTSCRIPT
7415 QCloader = intern (":loader");
7416 staticpro (&QCloader);
7417 QCbounding_box = intern (":bounding-box");
7418 staticpro (&QCbounding_box);
7419 QCpt_width = intern (":pt-width");
7420 staticpro (&QCpt_width);
7421 QCpt_height = intern (":pt-height");
7422 staticpro (&QCpt_height);
7423 #endif /* HAVE_GHOSTSCRIPT */
7424
7425 Qpbm = intern ("pbm");
7426 staticpro (&Qpbm);
7427
7428 Qxbm = intern ("xbm");
7429 staticpro (&Qxbm);
7430
7431 #ifdef HAVE_XPM
7432 Qxpm = intern ("xpm");
7433 staticpro (&Qxpm);
7434 #endif
7435
7436 #if defined (HAVE_JPEG) || defined (MAC_OS)
7437 Qjpeg = intern ("jpeg");
7438 staticpro (&Qjpeg);
7439 #endif
7440
7441 #if defined (HAVE_TIFF) || defined (MAC_OS)
7442 Qtiff = intern ("tiff");
7443 staticpro (&Qtiff);
7444 #endif
7445
7446 #if defined (HAVE_GIF) || defined (MAC_OS)
7447 Qgif = intern ("gif");
7448 staticpro (&Qgif);
7449 #endif
7450
7451 #if defined (HAVE_PNG) || defined (MAC_OS)
7452 Qpng = intern ("png");
7453 staticpro (&Qpng);
7454 #endif
7455
7456 defsubr (&Sclear_image_cache);
7457 defsubr (&Simage_size);
7458 defsubr (&Simage_mask_p);
7459
7460 #if GLYPH_DEBUG
7461 defsubr (&Simagep);
7462 defsubr (&Slookup_image);
7463 #endif
7464
7465 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
7466 doc: /* Non-nil means always draw a cross over disabled images.
7467 Disabled images are those having an `:conversion disabled' property.
7468 A cross is always drawn on black & white displays. */);
7469 cross_disabled_images = 0;
7470
7471 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
7472 doc: /* List of directories to search for window system bitmap files. */);
7473 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
7474
7475 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
7476 doc: /* Time after which cached images are removed from the cache.
7477 When an image has not been displayed this many seconds, remove it
7478 from the image cache. Value must be an integer or nil with nil
7479 meaning don't clear the cache. */);
7480 Vimage_cache_eviction_delay = make_number (30 * 60);
7481 }
7482
7483
7484 #ifdef HAVE_NTGUI
7485 /* Image types that rely on external libraries are loaded dynamically
7486 if the library is available. */
7487 #define IF_LIB_AVAILABLE(init_lib_fn) if (init_lib_fn())
7488 #else
7489 #define IF_LIB_AVAILABLE(init_func) /* Load unconditionally */
7490 #endif /* HAVE_NTGUI */
7491
7492 void
7493 init_image ()
7494 {
7495 image_types = NULL;
7496 Vimage_types = Qnil;
7497
7498 define_image_type (&xbm_type);
7499 define_image_type (&pbm_type);
7500
7501 #ifdef HAVE_XPM
7502 IF_LIB_AVAILABLE(init_xpm_functions)
7503 define_image_type (&xpm_type);
7504 #endif
7505
7506 #if defined (HAVE_JPEG) || defined (MAC_OS)
7507 IF_LIB_AVAILABLE(init_jpeg_functions)
7508 define_image_type (&jpeg_type);
7509 #endif
7510
7511 #if defined (HAVE_TIFF) || defined (MAC_OS)
7512 IF_LIB_AVAILABLE(init_tiff_functions)
7513 define_image_type (&tiff_type);
7514 #endif
7515
7516 #if defined (HAVE_GIF) || defined (MAC_OS)
7517 IF_LIB_AVAILABLE(init_gif_functions)
7518 define_image_type (&gif_type);
7519 #endif
7520
7521 #if defined (HAVE_PNG) || defined (MAC_OS)
7522 IF_LIB_AVAILABLE(init_png_functions)
7523 define_image_type (&png_type);
7524 #endif
7525
7526 #ifdef HAVE_GHOSTSCRIPT
7527 define_image_type (&gs_type);
7528 #endif
7529
7530 #ifdef MAC_OS
7531 /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */
7532 EnterMovies ();
7533 #ifdef MAC_OSX
7534 init_image_func_pointer ();
7535 #endif
7536 #endif
7537 }
7538
7539 /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
7540 (do not change this comment) */