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