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