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