(Vimage_types): Move from xdisp.c.
[emacs.git] / src / image.c
blob3eccf0f001e2ca3b19507b63655b3c2fd960ddfc
1 /* Functions for image support on window system.
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04
3 Free Software Foundation.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <ctype.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
32 /* This makes the fields of a Display accessible, in Xlib header files. */
34 #define XLIB_ILLEGAL_ACCESS
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>
45 #ifdef HAVE_X_WINDOWS
46 #include "xterm.h"
47 #include <sys/types.h>
48 #include <sys/stat.h>
50 #define COLOR_TABLE_SUPPORT 1
52 typedef struct x_bitmap_record Bitmap_Record;
53 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
54 #define NO_PIXMAP None
56 #define RGB_PIXEL_COLOR unsigned long
58 #define PIX_MASK_RETAIN(f) 0
59 #define PIX_MASK_DRAW(f) 1
60 #endif /* HAVE_X_WINDOWS */
63 #ifdef HAVE_NTGUI
64 #include "w32term.h"
66 /* W32_TODO : Color tables on W32. */
67 #undef COLOR_TABLE_SUPPORT
69 typedef struct w32_bitmap_record Bitmap_Record;
70 #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
71 #define NO_PIXMAP 0
73 #define RGB_PIXEL_COLOR COLORREF
75 #define PIX_MASK_RETAIN(f) 0
76 #define PIX_MASK_DRAW(f) 1
78 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
79 #define x_defined_color w32_defined_color
80 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
81 #endif /* HAVE_NTGUI */
84 #ifdef MAC_OS
85 #include "macterm.h"
86 #ifndef MAC_OSX
87 #include <alloca.h>
88 #endif
89 #ifdef MAC_OSX
90 #include <sys/stat.h>
91 #include <QuickTime/QuickTime.h>
92 #else /* not MAC_OSX */
93 #include <Windows.h>
94 #include <Gestalt.h>
95 #include <TextUtils.h>
96 #endif /* not MAC_OSX */
98 /* MAC_TODO : Color tables on Mac. */
99 #undef COLOR_TABLE_SUPPORT
101 #define ZPixmap 0 /* arbitrary */
102 typedef struct mac_bitmap_record Bitmap_Record;
104 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
105 #define NO_PIXMAP 0
107 #define RGB_PIXEL_COLOR unsigned long
109 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
110 #define x_defined_color mac_defined_color
111 #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
112 #define XDrawLine(display, w, gc, x1, y1, x2, y2) \
113 mac_draw_line_to_pixmap(display, w, gc, x1, y1, x2, y2)
115 #endif /* MAC_OS */
118 /* Search path for bitmap files. */
120 Lisp_Object Vx_bitmap_file_path;
123 static void x_disable_image P_ ((struct frame *, struct image *));
124 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
125 Lisp_Object));
127 static void init_color_table P_ ((void));
128 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
129 #ifdef COLOR_TABLE_SUPPORT
130 static void free_color_table P_ ((void));
131 static unsigned long *colors_in_color_table P_ ((int *n));
132 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
133 #endif
135 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
136 id, which is just an int that this section returns. Bitmaps are
137 reference counted so they can be shared among frames.
139 Bitmap indices are guaranteed to be > 0, so a negative number can
140 be used to indicate no bitmap.
142 If you use x_create_bitmap_from_data, then you must keep track of
143 the bitmaps yourself. That is, creating a bitmap from the same
144 data more than once will not be caught. */
146 #ifdef MAC_OS
148 static XImagePtr
149 XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
150 Display *display; /* not used */
151 Pixmap pixmap;
152 int x, y; /* not used */
153 unsigned int width, height; /* not used */
154 unsigned long plane_mask; /* not used */
155 int format; /* not used */
157 #if GLYPH_DEBUG
158 xassert (x == 0 && y == 0);
160 Rect ri, rp;
161 SetRect (&ri, 0, 0, width, height);
162 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
164 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
165 #endif
167 LockPixels (GetGWorldPixMap (pixmap));
169 return pixmap;
172 static void
173 XPutPixel (ximage, x, y, pixel)
174 XImagePtr ximage;
175 int x, y;
176 unsigned long pixel;
178 CGrafPtr old_port;
179 GDHandle old_gdh;
180 RGBColor color;
182 GetGWorld (&old_port, &old_gdh);
183 SetGWorld (ximage, NULL);
185 color.red = RED16_FROM_ULONG (pixel);
186 color.green = GREEN16_FROM_ULONG (pixel);
187 color.blue = BLUE16_FROM_ULONG (pixel);
188 SetCPixel (x, y, &color);
190 SetGWorld (old_port, old_gdh);
193 static unsigned long
194 XGetPixel (ximage, x, y)
195 XImagePtr ximage;
196 int x, y;
198 CGrafPtr old_port;
199 GDHandle old_gdh;
200 RGBColor color;
202 GetGWorld (&old_port, &old_gdh);
203 SetGWorld (ximage, NULL);
205 GetCPixel (x, y, &color);
207 SetGWorld (old_port, old_gdh);
208 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
211 static void
212 XDestroyImage (ximg)
213 XImagePtr ximg;
215 UnlockPixels (GetGWorldPixMap (ximg));
217 #endif /* MAC_OS */
220 /* Functions to access the contents of a bitmap, given an id. */
223 x_bitmap_height (f, id)
224 FRAME_PTR f;
225 int id;
227 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
231 x_bitmap_width (f, id)
232 FRAME_PTR f;
233 int id;
235 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
238 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
240 x_bitmap_pixmap (f, id)
241 FRAME_PTR f;
242 int id;
244 return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
246 #endif
248 #ifdef HAVE_X_WINDOWS
250 x_bitmap_mask (f, id)
251 FRAME_PTR f;
252 int id;
254 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
256 #endif
258 /* Allocate a new bitmap record. Returns index of new record. */
260 static int
261 x_allocate_bitmap_record (f)
262 FRAME_PTR f;
264 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
265 int i;
267 if (dpyinfo->bitmaps == NULL)
269 dpyinfo->bitmaps_size = 10;
270 dpyinfo->bitmaps
271 = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
272 dpyinfo->bitmaps_last = 1;
273 return 1;
276 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
277 return ++dpyinfo->bitmaps_last;
279 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
280 if (dpyinfo->bitmaps[i].refcount == 0)
281 return i + 1;
283 dpyinfo->bitmaps_size *= 2;
284 dpyinfo->bitmaps
285 = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
286 dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
287 return ++dpyinfo->bitmaps_last;
290 /* Add one reference to the reference count of the bitmap with id ID. */
292 void
293 x_reference_bitmap (f, id)
294 FRAME_PTR f;
295 int id;
297 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
300 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
303 x_create_bitmap_from_data (f, bits, width, height)
304 struct frame *f;
305 char *bits;
306 unsigned int width, height;
308 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
309 int id;
311 #ifdef HAVE_X_WINDOWS
312 Pixmap bitmap;
313 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
314 bits, width, height);
315 if (! bitmap)
316 return -1;
317 #endif /* HAVE_X_WINDOWS */
319 #ifdef HAVE_NTGUI
320 Pixmap bitmap;
321 bitmap = CreateBitmap (width, height,
322 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
323 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
324 bits);
325 if (! bitmap)
326 return -1;
327 #endif /* HAVE_NTGUI */
329 #ifdef MAC_OS
330 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
331 if (width % 16 != 0)
332 return -1;
333 #endif
335 id = x_allocate_bitmap_record (f);
336 #ifdef MAC_OS
337 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
338 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
339 return -1;
340 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
341 #endif /* MAC_OS */
343 dpyinfo->bitmaps[id - 1].file = NULL;
344 dpyinfo->bitmaps[id - 1].height = height;
345 dpyinfo->bitmaps[id - 1].width = width;
346 dpyinfo->bitmaps[id - 1].refcount = 1;
348 #ifdef HAVE_X_WINDOWS
349 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
350 dpyinfo->bitmaps[id - 1].have_mask = 0;
351 dpyinfo->bitmaps[id - 1].depth = 1;
352 #endif /* HAVE_X_WINDOWS */
354 #ifdef HAVE_NTGUI
355 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
356 dpyinfo->bitmaps[id - 1].hinst = NULL;
357 dpyinfo->bitmaps[id - 1].depth = 1;
358 #endif /* HAVE_NTGUI */
360 return id;
363 /* Create bitmap from file FILE for frame F. */
366 x_create_bitmap_from_file (f, file)
367 struct frame *f;
368 Lisp_Object file;
370 #ifdef MAC_OS
371 return -1; /* MAC_TODO : bitmap support */
372 #endif /* MAC_OS */
374 #ifdef HAVE_NTGUI
375 return -1; /* W32_TODO : bitmap support */
376 #endif /* HAVE_NTGUI */
378 #ifdef HAVE_X_WINDOWS
379 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
380 unsigned int width, height;
381 Pixmap bitmap;
382 int xhot, yhot, result, id;
383 Lisp_Object found;
384 int fd;
385 char *filename;
387 /* Look for an existing bitmap with the same name. */
388 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
390 if (dpyinfo->bitmaps[id].refcount
391 && dpyinfo->bitmaps[id].file
392 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
394 ++dpyinfo->bitmaps[id].refcount;
395 return id + 1;
399 /* Search bitmap-file-path for the file, if appropriate. */
400 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
401 if (fd < 0)
402 return -1;
403 emacs_close (fd);
405 filename = (char *) SDATA (found);
407 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
408 filename, &width, &height, &bitmap, &xhot, &yhot);
409 if (result != BitmapSuccess)
410 return -1;
412 id = x_allocate_bitmap_record (f);
413 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
414 dpyinfo->bitmaps[id - 1].have_mask = 0;
415 dpyinfo->bitmaps[id - 1].refcount = 1;
416 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
417 dpyinfo->bitmaps[id - 1].depth = 1;
418 dpyinfo->bitmaps[id - 1].height = height;
419 dpyinfo->bitmaps[id - 1].width = width;
420 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
422 return id;
423 #endif /* HAVE_X_WINDOWS */
426 /* Free bitmap B. */
428 static void
429 Free_Bitmap_Record (dpyinfo, bm)
430 Display_Info *dpyinfo;
431 Bitmap_Record *bm;
433 #ifdef HAVE_X_WINDOWS
434 XFreePixmap (dpyinfo->display, bm->pixmap);
435 if (bm->have_mask)
436 XFreePixmap (dpyinfo->display, bm->mask);
437 #endif /* HAVE_X_WINDOWS */
439 #ifdef HAVE_NTGUI
440 DeleteObject (bm->pixmap);
441 #endif /* HAVE_NTGUI */
443 #ifdef MAC_OS
444 xfree (bm->bitmap_data); /* Added ++kfs */
445 bm->bitmap_data = NULL;
446 #endif /* MAC_OS */
448 if (bm->file)
450 xfree (bm->file);
451 bm->file = NULL;
455 /* Remove reference to bitmap with id number ID. */
457 void
458 x_destroy_bitmap (f, id)
459 FRAME_PTR f;
460 int id;
462 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
464 if (id > 0)
466 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
468 if (--bm->refcount == 0)
470 BLOCK_INPUT;
471 Free_Bitmap_Record (dpyinfo, bm);
472 UNBLOCK_INPUT;
477 /* Free all the bitmaps for the display specified by DPYINFO. */
479 void
480 x_destroy_all_bitmaps (dpyinfo)
481 Display_Info *dpyinfo;
483 int i;
484 Bitmap_Record *bm = dpyinfo->bitmaps;
486 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
487 if (bm->refcount > 0)
488 Free_Bitmap_Record (dpyinfo, bm);
490 dpyinfo->bitmaps_last = 0;
494 #ifdef HAVE_X_WINDOWS
496 /* Useful functions defined in the section
497 `Image type independent image structures' below. */
499 static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
500 unsigned long height));
502 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
503 int depth, XImagePtr *ximg,
504 Pixmap *pixmap));
506 static void x_destroy_x_image P_ ((XImagePtr ximg));
509 /* Create a mask of a bitmap. Note is this not a perfect mask.
510 It's nicer with some borders in this context */
513 x_create_bitmap_mask (f, id)
514 struct frame *f;
515 int id;
517 Pixmap pixmap, mask;
518 XImagePtr ximg, mask_img;
519 unsigned long width, height;
520 int result;
521 unsigned long bg;
522 unsigned long x, y, xp, xm, yp, ym;
523 GC gc;
525 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
527 if (!(id > 0))
528 return -1;
530 pixmap = x_bitmap_pixmap (f, id);
531 width = x_bitmap_width (f, id);
532 height = x_bitmap_height (f, id);
534 BLOCK_INPUT;
535 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
536 ~0, ZPixmap);
538 if (!ximg)
540 UNBLOCK_INPUT;
541 return -1;
544 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
546 UNBLOCK_INPUT;
547 if (!result)
549 XDestroyImage (ximg);
550 return -1;
553 bg = four_corners_best (ximg, width, height);
555 for (y = 0; y < ximg->height; ++y)
557 for (x = 0; x < ximg->width; ++x)
559 xp = x != ximg->width - 1 ? x + 1 : 0;
560 xm = x != 0 ? x - 1 : ximg->width - 1;
561 yp = y != ximg->height - 1 ? y + 1 : 0;
562 ym = y != 0 ? y - 1 : ximg->height - 1;
563 if (XGetPixel (ximg, x, y) == bg
564 && XGetPixel (ximg, x, yp) == bg
565 && XGetPixel (ximg, x, ym) == bg
566 && XGetPixel (ximg, xp, y) == bg
567 && XGetPixel (ximg, xp, yp) == bg
568 && XGetPixel (ximg, xp, ym) == bg
569 && XGetPixel (ximg, xm, y) == bg
570 && XGetPixel (ximg, xm, yp) == bg
571 && XGetPixel (ximg, xm, ym) == bg)
572 XPutPixel (mask_img, x, y, 0);
573 else
574 XPutPixel (mask_img, x, y, 1);
578 xassert (interrupt_input_blocked);
579 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
580 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
581 width, height);
582 XFreeGC (FRAME_X_DISPLAY (f), gc);
584 dpyinfo->bitmaps[id - 1].have_mask = 1;
585 dpyinfo->bitmaps[id - 1].mask = mask;
587 XDestroyImage (ximg);
588 x_destroy_x_image (mask_img);
590 return 0;
593 #endif /* HAVE_X_WINDOWS */
596 /***********************************************************************
597 Image types
598 ***********************************************************************/
600 /* Value is the number of elements of vector VECTOR. */
602 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
604 /* List of supported image types. Use define_image_type to add new
605 types. Use lookup_image_type to find a type for a given symbol. */
607 static struct image_type *image_types;
609 /* A list of symbols, one for each supported image type. */
611 Lisp_Object Vimage_types;
613 /* Cache for delayed-loading image types. */
615 static Lisp_Object Vimage_type_cache;
617 /* The symbol `xbm' which is used as the type symbol for XBM images. */
619 Lisp_Object Qxbm;
621 /* Keywords. */
623 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
624 extern Lisp_Object QCdata, QCtype;
625 extern Lisp_Object Qcenter;
626 Lisp_Object QCascent, QCmargin, QCrelief;
627 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
628 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
630 /* Other symbols. */
632 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
634 /* Time in seconds after which images should be removed from the cache
635 if not displayed. */
637 Lisp_Object Vimage_cache_eviction_delay;
639 /* Function prototypes. */
641 static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
642 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
643 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
644 static void x_laplace P_ ((struct frame *, struct image *));
645 static void x_emboss P_ ((struct frame *, struct image *));
646 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
647 Lisp_Object));
649 #define CACHE_IMAGE_TYPE(type, status) \
650 do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
652 #define ADD_IMAGE_TYPE(type) \
653 do { Vimage_types = Fcons (type, Vimage_types); } while (0)
655 /* Define a new image type from TYPE. This adds a copy of TYPE to
656 image_types and caches the loading status of TYPE. */
658 static Lisp_Object
659 define_image_type (type, loaded)
660 struct image_type *type;
661 int loaded;
663 Lisp_Object success;
665 if (!loaded)
666 success = Qnil;
667 else
669 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
670 The initialized data segment is read-only. */
671 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
672 bcopy (type, p, sizeof *p);
673 p->next = image_types;
674 image_types = p;
675 success = Qt;
678 CACHE_IMAGE_TYPE(*type->type, success);
679 return success;
683 /* Look up image type SYMBOL, and return a pointer to its image_type
684 structure. Value is null if SYMBOL is not a known image type. */
686 static INLINE struct image_type *
687 lookup_image_type (symbol)
688 Lisp_Object symbol;
690 struct image_type *type;
692 for (type = image_types; type; type = type->next)
693 if (EQ (symbol, *type->type))
694 break;
696 return type;
700 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
701 valid image specification is a list whose car is the symbol
702 `image', and whose rest is a property list. The property list must
703 contain a value for key `:type'. That value must be the name of a
704 supported image type. The rest of the property list depends on the
705 image type. */
708 valid_image_p (object)
709 Lisp_Object object;
711 int valid_p = 0;
713 if (IMAGEP (object))
715 Lisp_Object tem;
717 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
718 if (EQ (XCAR (tem), QCtype))
720 tem = XCDR (tem);
721 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
723 struct image_type *type;
724 type = lookup_image_type (XCAR (tem));
725 if (type)
726 valid_p = type->valid_p (object);
729 break;
733 return valid_p;
737 /* Log error message with format string FORMAT and argument ARG.
738 Signaling an error, e.g. when an image cannot be loaded, is not a
739 good idea because this would interrupt redisplay, and the error
740 message display would lead to another redisplay. This function
741 therefore simply displays a message. */
743 static void
744 image_error (format, arg1, arg2)
745 char *format;
746 Lisp_Object arg1, arg2;
748 add_to_log (format, arg1, arg2);
753 /***********************************************************************
754 Image specifications
755 ***********************************************************************/
757 enum image_value_type
759 IMAGE_DONT_CHECK_VALUE_TYPE,
760 IMAGE_STRING_VALUE,
761 IMAGE_STRING_OR_NIL_VALUE,
762 IMAGE_SYMBOL_VALUE,
763 IMAGE_POSITIVE_INTEGER_VALUE,
764 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
765 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
766 IMAGE_ASCENT_VALUE,
767 IMAGE_INTEGER_VALUE,
768 IMAGE_FUNCTION_VALUE,
769 IMAGE_NUMBER_VALUE,
770 IMAGE_BOOL_VALUE
773 /* Structure used when parsing image specifications. */
775 struct image_keyword
777 /* Name of keyword. */
778 char *name;
780 /* The type of value allowed. */
781 enum image_value_type type;
783 /* Non-zero means key must be present. */
784 int mandatory_p;
786 /* Used to recognize duplicate keywords in a property list. */
787 int count;
789 /* The value that was found. */
790 Lisp_Object value;
794 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
795 int, Lisp_Object));
796 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
799 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
800 has the format (image KEYWORD VALUE ...). One of the keyword/
801 value pairs must be `:type TYPE'. KEYWORDS is a vector of
802 image_keywords structures of size NKEYWORDS describing other
803 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
805 static int
806 parse_image_spec (spec, keywords, nkeywords, type)
807 Lisp_Object spec;
808 struct image_keyword *keywords;
809 int nkeywords;
810 Lisp_Object type;
812 int i;
813 Lisp_Object plist;
815 if (!IMAGEP (spec))
816 return 0;
818 plist = XCDR (spec);
819 while (CONSP (plist))
821 Lisp_Object key, value;
823 /* First element of a pair must be a symbol. */
824 key = XCAR (plist);
825 plist = XCDR (plist);
826 if (!SYMBOLP (key))
827 return 0;
829 /* There must follow a value. */
830 if (!CONSP (plist))
831 return 0;
832 value = XCAR (plist);
833 plist = XCDR (plist);
835 /* Find key in KEYWORDS. Error if not found. */
836 for (i = 0; i < nkeywords; ++i)
837 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
838 break;
840 if (i == nkeywords)
841 continue;
843 /* Record that we recognized the keyword. If a keywords
844 was found more than once, it's an error. */
845 keywords[i].value = value;
846 ++keywords[i].count;
848 if (keywords[i].count > 1)
849 return 0;
851 /* Check type of value against allowed type. */
852 switch (keywords[i].type)
854 case IMAGE_STRING_VALUE:
855 if (!STRINGP (value))
856 return 0;
857 break;
859 case IMAGE_STRING_OR_NIL_VALUE:
860 if (!STRINGP (value) && !NILP (value))
861 return 0;
862 break;
864 case IMAGE_SYMBOL_VALUE:
865 if (!SYMBOLP (value))
866 return 0;
867 break;
869 case IMAGE_POSITIVE_INTEGER_VALUE:
870 if (!INTEGERP (value) || XINT (value) <= 0)
871 return 0;
872 break;
874 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
875 if (INTEGERP (value) && XINT (value) >= 0)
876 break;
877 if (CONSP (value)
878 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
879 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
880 break;
881 return 0;
883 case IMAGE_ASCENT_VALUE:
884 if (SYMBOLP (value) && EQ (value, Qcenter))
885 break;
886 else if (INTEGERP (value)
887 && XINT (value) >= 0
888 && XINT (value) <= 100)
889 break;
890 return 0;
892 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
893 if (!INTEGERP (value) || XINT (value) < 0)
894 return 0;
895 break;
897 case IMAGE_DONT_CHECK_VALUE_TYPE:
898 break;
900 case IMAGE_FUNCTION_VALUE:
901 value = indirect_function (value);
902 if (SUBRP (value)
903 || COMPILEDP (value)
904 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
905 break;
906 return 0;
908 case IMAGE_NUMBER_VALUE:
909 if (!INTEGERP (value) && !FLOATP (value))
910 return 0;
911 break;
913 case IMAGE_INTEGER_VALUE:
914 if (!INTEGERP (value))
915 return 0;
916 break;
918 case IMAGE_BOOL_VALUE:
919 if (!NILP (value) && !EQ (value, Qt))
920 return 0;
921 break;
923 default:
924 abort ();
925 break;
928 if (EQ (key, QCtype) && !EQ (type, value))
929 return 0;
932 /* Check that all mandatory fields are present. */
933 for (i = 0; i < nkeywords; ++i)
934 if (keywords[i].mandatory_p && keywords[i].count == 0)
935 return 0;
937 return NILP (plist);
941 /* Return the value of KEY in image specification SPEC. Value is nil
942 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
943 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
945 static Lisp_Object
946 image_spec_value (spec, key, found)
947 Lisp_Object spec, key;
948 int *found;
950 Lisp_Object tail;
952 xassert (valid_image_p (spec));
954 for (tail = XCDR (spec);
955 CONSP (tail) && CONSP (XCDR (tail));
956 tail = XCDR (XCDR (tail)))
958 if (EQ (XCAR (tail), key))
960 if (found)
961 *found = 1;
962 return XCAR (XCDR (tail));
966 if (found)
967 *found = 0;
968 return Qnil;
972 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
973 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
974 PIXELS non-nil means return the size in pixels, otherwise return the
975 size in canonical character units.
976 FRAME is the frame on which the image will be displayed. FRAME nil
977 or omitted means use the selected frame. */)
978 (spec, pixels, frame)
979 Lisp_Object spec, pixels, frame;
981 Lisp_Object size;
983 size = Qnil;
984 if (valid_image_p (spec))
986 struct frame *f = check_x_frame (frame);
987 int id = lookup_image (f, spec);
988 struct image *img = IMAGE_FROM_ID (f, id);
989 int width = img->width + 2 * img->hmargin;
990 int height = img->height + 2 * img->vmargin;
992 if (NILP (pixels))
993 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
994 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
995 else
996 size = Fcons (make_number (width), make_number (height));
998 else
999 error ("Invalid image specification");
1001 return size;
1005 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
1006 doc: /* Return t if image SPEC has a mask bitmap.
1007 FRAME is the frame on which the image will be displayed. FRAME nil
1008 or omitted means use the selected frame. */)
1009 (spec, frame)
1010 Lisp_Object spec, frame;
1012 Lisp_Object mask;
1014 mask = Qnil;
1015 if (valid_image_p (spec))
1017 struct frame *f = check_x_frame (frame);
1018 int id = lookup_image (f, spec);
1019 struct image *img = IMAGE_FROM_ID (f, id);
1020 if (img->mask)
1021 mask = Qt;
1023 else
1024 error ("Invalid image specification");
1026 return mask;
1030 /***********************************************************************
1031 Image type independent image structures
1032 ***********************************************************************/
1034 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
1035 static void free_image P_ ((struct frame *f, struct image *img));
1038 /* Allocate and return a new image structure for image specification
1039 SPEC. SPEC has a hash value of HASH. */
1041 static struct image *
1042 make_image (spec, hash)
1043 Lisp_Object spec;
1044 unsigned hash;
1046 struct image *img = (struct image *) xmalloc (sizeof *img);
1048 xassert (valid_image_p (spec));
1049 bzero (img, sizeof *img);
1050 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1051 xassert (img->type != NULL);
1052 img->spec = spec;
1053 img->data.lisp_val = Qnil;
1054 img->ascent = DEFAULT_IMAGE_ASCENT;
1055 img->hash = hash;
1056 return img;
1060 /* Free image IMG which was used on frame F, including its resources. */
1062 static void
1063 free_image (f, img)
1064 struct frame *f;
1065 struct image *img;
1067 if (img)
1069 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1071 /* Remove IMG from the hash table of its cache. */
1072 if (img->prev)
1073 img->prev->next = img->next;
1074 else
1075 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1077 if (img->next)
1078 img->next->prev = img->prev;
1080 c->images[img->id] = NULL;
1082 /* Free resources, then free IMG. */
1083 img->type->free (f, img);
1084 xfree (img);
1089 /* Prepare image IMG for display on frame F. Must be called before
1090 drawing an image. */
1092 void
1093 prepare_image_for_display (f, img)
1094 struct frame *f;
1095 struct image *img;
1097 EMACS_TIME t;
1099 /* We're about to display IMG, so set its timestamp to `now'. */
1100 EMACS_GET_TIME (t);
1101 img->timestamp = EMACS_SECS (t);
1103 /* If IMG doesn't have a pixmap yet, load it now, using the image
1104 type dependent loader function. */
1105 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1106 img->load_failed_p = img->type->load (f, img) == 0;
1110 /* Value is the number of pixels for the ascent of image IMG when
1111 drawn in face FACE. */
1114 image_ascent (img, face, slice)
1115 struct image *img;
1116 struct face *face;
1117 struct glyph_slice *slice;
1119 int height;
1120 int ascent;
1122 if (slice->height == img->height)
1123 height = img->height + img->vmargin;
1124 else if (slice->y == 0)
1125 height = slice->height + img->vmargin;
1126 else
1127 height = slice->height;
1129 if (img->ascent == CENTERED_IMAGE_ASCENT)
1131 if (face->font)
1133 #ifdef HAVE_NTGUI
1134 /* W32 specific version. Why?. ++kfs */
1135 ascent = height / 2 - (FONT_DESCENT(face->font)
1136 - FONT_BASE(face->font)) / 2;
1137 #else
1138 /* This expression is arranged so that if the image can't be
1139 exactly centered, it will be moved slightly up. This is
1140 because a typical font is `top-heavy' (due to the presence
1141 uppercase letters), so the image placement should err towards
1142 being top-heavy too. It also just generally looks better. */
1143 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
1144 #endif /* HAVE_NTGUI */
1146 else
1147 ascent = height / 2;
1149 else
1150 ascent = (int) (height * img->ascent / 100.0);
1152 return ascent;
1156 /* Image background colors. */
1158 /* Find the "best" corner color of a bitmap.
1159 On W32, XIMG is assumed to a device context with the bitmap selected. */
1161 static RGB_PIXEL_COLOR
1162 four_corners_best (ximg, width, height)
1163 XImagePtr_or_DC ximg;
1164 unsigned long width, height;
1166 RGB_PIXEL_COLOR corners[4], best;
1167 int i, best_count;
1169 /* Get the colors at the corners of ximg. */
1170 corners[0] = GET_PIXEL (ximg, 0, 0);
1171 corners[1] = GET_PIXEL (ximg, width - 1, 0);
1172 corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
1173 corners[3] = GET_PIXEL (ximg, 0, height - 1);
1175 /* Choose the most frequently found color as background. */
1176 for (i = best_count = 0; i < 4; ++i)
1178 int j, n;
1180 for (j = n = 0; j < 4; ++j)
1181 if (corners[i] == corners[j])
1182 ++n;
1184 if (n > best_count)
1185 best = corners[i], best_count = n;
1188 return best;
1191 /* Portability macros */
1193 #ifdef HAVE_NTGUI
1195 #define Destroy_Image(img_dc, prev) \
1196 do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
1198 #define Free_Pixmap(display, pixmap) \
1199 DeleteObject (pixmap)
1201 #else
1203 #define Destroy_Image(ximg, dummy) \
1204 XDestroyImage (ximg)
1206 #define Free_Pixmap(display, pixmap) \
1207 XFreePixmap (display, pixmap)
1209 #endif /* HAVE_NTGUI */
1212 /* Return the `background' field of IMG. If IMG doesn't have one yet,
1213 it is guessed heuristically. If non-zero, XIMG is an existing
1214 XImage object (or device context with the image selected on W32) to
1215 use for the heuristic. */
1217 RGB_PIXEL_COLOR
1218 image_background (img, f, ximg)
1219 struct image *img;
1220 struct frame *f;
1221 XImagePtr_or_DC ximg;
1223 if (! img->background_valid)
1224 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1226 int free_ximg = !ximg;
1227 #ifdef HAVE_NTGUI
1228 HGDIOBJ prev;
1229 #endif /* HAVE_NTGUI */
1231 if (free_ximg)
1233 #ifndef HAVE_NTGUI
1234 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
1235 0, 0, img->width, img->height, ~0, ZPixmap);
1236 #else
1237 HDC frame_dc = get_frame_dc (f);
1238 ximg = CreateCompatibleDC (frame_dc);
1239 release_frame_dc (f, frame_dc);
1240 prev = SelectObject (ximg, img->pixmap);
1241 #endif /* !HAVE_NTGUI */
1244 img->background = four_corners_best (ximg, img->width, img->height);
1246 if (free_ximg)
1247 Destroy_Image (ximg, prev);
1249 img->background_valid = 1;
1252 return img->background;
1255 /* Return the `background_transparent' field of IMG. If IMG doesn't
1256 have one yet, it is guessed heuristically. If non-zero, MASK is an
1257 existing XImage object to use for the heuristic. */
1260 image_background_transparent (img, f, mask)
1261 struct image *img;
1262 struct frame *f;
1263 XImagePtr_or_DC mask;
1265 if (! img->background_transparent_valid)
1266 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1268 if (img->mask)
1270 int free_mask = !mask;
1271 #ifdef HAVE_NTGUI
1272 HGDIOBJ prev;
1273 #endif /* HAVE_NTGUI */
1275 if (free_mask)
1277 #ifndef HAVE_NTGUI
1278 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
1279 0, 0, img->width, img->height, ~0, ZPixmap);
1280 #else
1281 HDC frame_dc = get_frame_dc (f);
1282 mask = CreateCompatibleDC (frame_dc);
1283 release_frame_dc (f, frame_dc);
1284 prev = SelectObject (mask, img->mask);
1285 #endif /* HAVE_NTGUI */
1288 img->background_transparent
1289 = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
1291 if (free_mask)
1292 Destroy_Image (mask, prev);
1294 else
1295 img->background_transparent = 0;
1297 img->background_transparent_valid = 1;
1300 return img->background_transparent;
1304 /***********************************************************************
1305 Helper functions for X image types
1306 ***********************************************************************/
1308 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
1309 int, int));
1310 static void x_clear_image P_ ((struct frame *f, struct image *img));
1311 static unsigned long x_alloc_image_color P_ ((struct frame *f,
1312 struct image *img,
1313 Lisp_Object color_name,
1314 unsigned long dflt));
1317 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
1318 free the pixmap if any. MASK_P non-zero means clear the mask
1319 pixmap if any. COLORS_P non-zero means free colors allocated for
1320 the image, if any. */
1322 static void
1323 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
1324 struct frame *f;
1325 struct image *img;
1326 int pixmap_p, mask_p, colors_p;
1328 if (pixmap_p && img->pixmap)
1330 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
1331 img->pixmap = NO_PIXMAP;
1332 img->background_valid = 0;
1335 if (mask_p && img->mask)
1337 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1338 img->mask = NO_PIXMAP;
1339 img->background_transparent_valid = 0;
1342 if (colors_p && img->ncolors)
1344 /* MAC_TODO: color table support. */
1345 /* W32_TODO: color table support. */
1346 #ifdef HAVE_X_WINDOWS
1347 x_free_colors (f, img->colors, img->ncolors);
1348 #endif /* HAVE_X_WINDOWS */
1349 xfree (img->colors);
1350 img->colors = NULL;
1351 img->ncolors = 0;
1355 /* Free X resources of image IMG which is used on frame F. */
1357 static void
1358 x_clear_image (f, img)
1359 struct frame *f;
1360 struct image *img;
1362 BLOCK_INPUT;
1363 x_clear_image_1 (f, img, 1, 1, 1);
1364 UNBLOCK_INPUT;
1368 /* Allocate color COLOR_NAME for image IMG on frame F. If color
1369 cannot be allocated, use DFLT. Add a newly allocated color to
1370 IMG->colors, so that it can be freed again. Value is the pixel
1371 color. */
1373 static unsigned long
1374 x_alloc_image_color (f, img, color_name, dflt)
1375 struct frame *f;
1376 struct image *img;
1377 Lisp_Object color_name;
1378 unsigned long dflt;
1380 XColor color;
1381 unsigned long result;
1383 xassert (STRINGP (color_name));
1385 if (x_defined_color (f, SDATA (color_name), &color, 1))
1387 /* This isn't called frequently so we get away with simply
1388 reallocating the color vector to the needed size, here. */
1389 ++img->ncolors;
1390 img->colors =
1391 (unsigned long *) xrealloc (img->colors,
1392 img->ncolors * sizeof *img->colors);
1393 img->colors[img->ncolors - 1] = color.pixel;
1394 result = color.pixel;
1396 else
1397 result = dflt;
1399 return result;
1404 /***********************************************************************
1405 Image Cache
1406 ***********************************************************************/
1408 static void cache_image P_ ((struct frame *f, struct image *img));
1409 static void postprocess_image P_ ((struct frame *, struct image *));
1411 /* Return a new, initialized image cache that is allocated from the
1412 heap. Call free_image_cache to free an image cache. */
1414 struct image_cache *
1415 make_image_cache ()
1417 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
1418 int size;
1420 bzero (c, sizeof *c);
1421 c->size = 50;
1422 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
1423 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
1424 c->buckets = (struct image **) xmalloc (size);
1425 bzero (c->buckets, size);
1426 return c;
1430 /* Free image cache of frame F. Be aware that X frames share images
1431 caches. */
1433 void
1434 free_image_cache (f)
1435 struct frame *f;
1437 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1438 if (c)
1440 int i;
1442 /* Cache should not be referenced by any frame when freed. */
1443 xassert (c->refcount == 0);
1445 for (i = 0; i < c->used; ++i)
1446 free_image (f, c->images[i]);
1447 xfree (c->images);
1448 xfree (c->buckets);
1449 xfree (c);
1450 FRAME_X_IMAGE_CACHE (f) = NULL;
1455 /* Clear image cache of frame F. FORCE_P non-zero means free all
1456 images. FORCE_P zero means clear only images that haven't been
1457 displayed for some time. Should be called from time to time to
1458 reduce the number of loaded images. If image-eviction-seconds is
1459 non-nil, this frees images in the cache which weren't displayed for
1460 at least that many seconds. */
1462 void
1463 clear_image_cache (f, force_p)
1464 struct frame *f;
1465 int force_p;
1467 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1469 if (c && INTEGERP (Vimage_cache_eviction_delay))
1471 EMACS_TIME t;
1472 unsigned long old;
1473 int i, nfreed;
1475 EMACS_GET_TIME (t);
1476 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
1478 /* Block input so that we won't be interrupted by a SIGIO
1479 while being in an inconsistent state. */
1480 BLOCK_INPUT;
1482 for (i = nfreed = 0; i < c->used; ++i)
1484 struct image *img = c->images[i];
1485 if (img != NULL
1486 && (force_p || img->timestamp < old))
1488 free_image (f, img);
1489 ++nfreed;
1493 /* We may be clearing the image cache because, for example,
1494 Emacs was iconified for a longer period of time. In that
1495 case, current matrices may still contain references to
1496 images freed above. So, clear these matrices. */
1497 if (nfreed)
1499 Lisp_Object tail, frame;
1501 FOR_EACH_FRAME (tail, frame)
1503 struct frame *f = XFRAME (frame);
1504 if (FRAME_WINDOW_P (f)
1505 && FRAME_X_IMAGE_CACHE (f) == c)
1506 clear_current_matrices (f);
1509 ++windows_or_buffers_changed;
1512 UNBLOCK_INPUT;
1517 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
1518 0, 1, 0,
1519 doc: /* Clear the image cache of FRAME.
1520 FRAME nil or omitted means use the selected frame.
1521 FRAME t means clear the image caches of all frames. */)
1522 (frame)
1523 Lisp_Object frame;
1525 if (EQ (frame, Qt))
1527 Lisp_Object tail;
1529 FOR_EACH_FRAME (tail, frame)
1530 if (FRAME_WINDOW_P (XFRAME (frame)))
1531 clear_image_cache (XFRAME (frame), 1);
1533 else
1534 clear_image_cache (check_x_frame (frame), 1);
1536 return Qnil;
1540 /* Compute masks and transform image IMG on frame F, as specified
1541 by the image's specification, */
1543 static void
1544 postprocess_image (f, img)
1545 struct frame *f;
1546 struct image *img;
1548 /* Manipulation of the image's mask. */
1549 if (img->pixmap)
1551 Lisp_Object conversion, spec;
1552 Lisp_Object mask;
1554 spec = img->spec;
1556 /* `:heuristic-mask t'
1557 `:mask heuristic'
1558 means build a mask heuristically.
1559 `:heuristic-mask (R G B)'
1560 `:mask (heuristic (R G B))'
1561 means build a mask from color (R G B) in the
1562 image.
1563 `:mask nil'
1564 means remove a mask, if any. */
1566 mask = image_spec_value (spec, QCheuristic_mask, NULL);
1567 if (!NILP (mask))
1568 x_build_heuristic_mask (f, img, mask);
1569 else
1571 int found_p;
1573 mask = image_spec_value (spec, QCmask, &found_p);
1575 if (EQ (mask, Qheuristic))
1576 x_build_heuristic_mask (f, img, Qt);
1577 else if (CONSP (mask)
1578 && EQ (XCAR (mask), Qheuristic))
1580 if (CONSP (XCDR (mask)))
1581 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
1582 else
1583 x_build_heuristic_mask (f, img, XCDR (mask));
1585 else if (NILP (mask) && found_p && img->mask)
1587 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1588 img->mask = NO_PIXMAP;
1593 /* Should we apply an image transformation algorithm? */
1594 conversion = image_spec_value (spec, QCconversion, NULL);
1595 if (EQ (conversion, Qdisabled))
1596 x_disable_image (f, img);
1597 else if (EQ (conversion, Qlaplace))
1598 x_laplace (f, img);
1599 else if (EQ (conversion, Qemboss))
1600 x_emboss (f, img);
1601 else if (CONSP (conversion)
1602 && EQ (XCAR (conversion), Qedge_detection))
1604 Lisp_Object tem;
1605 tem = XCDR (conversion);
1606 if (CONSP (tem))
1607 x_edge_detection (f, img,
1608 Fplist_get (tem, QCmatrix),
1609 Fplist_get (tem, QCcolor_adjustment));
1615 /* Return the id of image with Lisp specification SPEC on frame F.
1616 SPEC must be a valid Lisp image specification (see valid_image_p). */
1619 lookup_image (f, spec)
1620 struct frame *f;
1621 Lisp_Object spec;
1623 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1624 #ifdef _MSC_VER
1625 /* Work around a problem with MinGW builds of graphics libraries
1626 not honoring calling conventions. */
1627 static
1628 #endif
1629 struct image *img;
1630 int i;
1631 unsigned hash;
1632 struct gcpro gcpro1;
1633 EMACS_TIME now;
1635 /* F must be a window-system frame, and SPEC must be a valid image
1636 specification. */
1637 xassert (FRAME_WINDOW_P (f));
1638 xassert (valid_image_p (spec));
1640 GCPRO1 (spec);
1642 /* Look up SPEC in the hash table of the image cache. */
1643 hash = sxhash (spec, 0);
1644 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1646 for (img = c->buckets[i]; img; img = img->next)
1647 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
1648 break;
1650 /* If not found, create a new image and cache it. */
1651 if (img == NULL)
1653 extern Lisp_Object Qpostscript;
1655 BLOCK_INPUT;
1656 img = make_image (spec, hash);
1657 cache_image (f, img);
1658 img->load_failed_p = img->type->load (f, img) == 0;
1660 /* If we can't load the image, and we don't have a width and
1661 height, use some arbitrary width and height so that we can
1662 draw a rectangle for it. */
1663 if (img->load_failed_p)
1665 Lisp_Object value;
1667 value = image_spec_value (spec, QCwidth, NULL);
1668 img->width = (INTEGERP (value)
1669 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
1670 value = image_spec_value (spec, QCheight, NULL);
1671 img->height = (INTEGERP (value)
1672 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
1674 else
1676 /* Handle image type independent image attributes
1677 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
1678 `:background COLOR'. */
1679 Lisp_Object ascent, margin, relief, bg;
1681 ascent = image_spec_value (spec, QCascent, NULL);
1682 if (INTEGERP (ascent))
1683 img->ascent = XFASTINT (ascent);
1684 else if (EQ (ascent, Qcenter))
1685 img->ascent = CENTERED_IMAGE_ASCENT;
1687 margin = image_spec_value (spec, QCmargin, NULL);
1688 if (INTEGERP (margin) && XINT (margin) >= 0)
1689 img->vmargin = img->hmargin = XFASTINT (margin);
1690 else if (CONSP (margin) && INTEGERP (XCAR (margin))
1691 && INTEGERP (XCDR (margin)))
1693 if (XINT (XCAR (margin)) > 0)
1694 img->hmargin = XFASTINT (XCAR (margin));
1695 if (XINT (XCDR (margin)) > 0)
1696 img->vmargin = XFASTINT (XCDR (margin));
1699 relief = image_spec_value (spec, QCrelief, NULL);
1700 if (INTEGERP (relief))
1702 img->relief = XINT (relief);
1703 img->hmargin += abs (img->relief);
1704 img->vmargin += abs (img->relief);
1707 if (! img->background_valid)
1709 bg = image_spec_value (img->spec, QCbackground, NULL);
1710 if (!NILP (bg))
1712 img->background
1713 = x_alloc_image_color (f, img, bg,
1714 FRAME_BACKGROUND_PIXEL (f));
1715 img->background_valid = 1;
1719 /* Do image transformations and compute masks, unless we
1720 don't have the image yet. */
1721 if (!EQ (*img->type->type, Qpostscript))
1722 postprocess_image (f, img);
1725 UNBLOCK_INPUT;
1728 /* We're using IMG, so set its timestamp to `now'. */
1729 EMACS_GET_TIME (now);
1730 img->timestamp = EMACS_SECS (now);
1732 UNGCPRO;
1734 /* Value is the image id. */
1735 return img->id;
1739 /* Cache image IMG in the image cache of frame F. */
1741 static void
1742 cache_image (f, img)
1743 struct frame *f;
1744 struct image *img;
1746 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1747 int i;
1749 /* Find a free slot in c->images. */
1750 for (i = 0; i < c->used; ++i)
1751 if (c->images[i] == NULL)
1752 break;
1754 /* If no free slot found, maybe enlarge c->images. */
1755 if (i == c->used && c->used == c->size)
1757 c->size *= 2;
1758 c->images = (struct image **) xrealloc (c->images,
1759 c->size * sizeof *c->images);
1762 /* Add IMG to c->images, and assign IMG an id. */
1763 c->images[i] = img;
1764 img->id = i;
1765 if (i == c->used)
1766 ++c->used;
1768 /* Add IMG to the cache's hash table. */
1769 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
1770 img->next = c->buckets[i];
1771 if (img->next)
1772 img->next->prev = img;
1773 img->prev = NULL;
1774 c->buckets[i] = img;
1778 /* Call FN on every image in the image cache of frame F. Used to mark
1779 Lisp Objects in the image cache. */
1781 void
1782 forall_images_in_image_cache (f, fn)
1783 struct frame *f;
1784 void (*fn) P_ ((struct image *img));
1786 if (FRAME_LIVE_P (f) && FRAME_WINDOW_P (f))
1788 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1789 if (c)
1791 int i;
1792 for (i = 0; i < c->used; ++i)
1793 if (c->images[i])
1794 fn (c->images[i]);
1801 /***********************************************************************
1802 X / MAC / W32 support code
1803 ***********************************************************************/
1805 #ifdef HAVE_NTGUI
1807 /* Macro for defining functions that will be loaded from image DLLs. */
1808 #define DEF_IMGLIB_FN(func) FARPROC fn_##func
1810 /* Macro for loading those image functions from the library. */
1811 #define LOAD_IMGLIB_FN(lib,func) { \
1812 fn_##func = (void *) GetProcAddress (lib, #func); \
1813 if (!fn_##func) return 0; \
1816 /* Load a DLL implementing an image type.
1817 The `image-library-alist' variable associates a symbol,
1818 identifying an image type, to a list of possible filenames.
1819 The function returns NULL if no library could be loaded for
1820 the given image type, or if the library was previously loaded;
1821 else the handle of the DLL. */
1822 static HMODULE
1823 w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
1825 HMODULE library = NULL;
1827 if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
1829 Lisp_Object dlls = Fassq (type, libraries);
1831 if (CONSP (dlls))
1832 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
1834 CHECK_STRING_CAR (dlls);
1835 if (library = LoadLibrary (SDATA (XCAR (dlls))))
1836 break;
1840 return library;
1843 #endif /* HAVE_NTGUI */
1845 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
1846 XImagePtr *, Pixmap *));
1847 static void x_destroy_x_image P_ ((XImagePtr));
1848 static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
1851 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
1852 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
1853 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
1854 via xmalloc. Print error messages via image_error if an error
1855 occurs. Value is non-zero if successful.
1857 On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
1858 should indicate the bit depth of the image. */
1860 static int
1861 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
1862 struct frame *f;
1863 int width, height, depth;
1864 XImagePtr *ximg;
1865 Pixmap *pixmap;
1867 #ifdef HAVE_X_WINDOWS
1868 Display *display = FRAME_X_DISPLAY (f);
1869 Window window = FRAME_X_WINDOW (f);
1870 Screen *screen = FRAME_X_SCREEN (f);
1872 xassert (interrupt_input_blocked);
1874 if (depth <= 0)
1875 depth = DefaultDepthOfScreen (screen);
1876 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
1877 depth, ZPixmap, 0, NULL, width, height,
1878 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
1879 if (*ximg == NULL)
1881 image_error ("Unable to allocate X image", Qnil, Qnil);
1882 return 0;
1885 /* Allocate image raster. */
1886 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
1888 /* Allocate a pixmap of the same size. */
1889 *pixmap = XCreatePixmap (display, window, width, height, depth);
1890 if (*pixmap == NO_PIXMAP)
1892 x_destroy_x_image (*ximg);
1893 *ximg = NULL;
1894 image_error ("Unable to create X pixmap", Qnil, Qnil);
1895 return 0;
1898 return 1;
1899 #endif /* HAVE_X_WINDOWS */
1901 #ifdef HAVE_NTGUI
1903 BITMAPINFOHEADER *header;
1904 HDC hdc;
1905 int scanline_width_bits;
1906 int remainder;
1907 int palette_colors = 0;
1909 if (depth == 0)
1910 depth = 24;
1912 if (depth != 1 && depth != 4 && depth != 8
1913 && depth != 16 && depth != 24 && depth != 32)
1915 image_error ("Invalid image bit depth specified", Qnil, Qnil);
1916 return 0;
1919 scanline_width_bits = width * depth;
1920 remainder = scanline_width_bits % 32;
1922 if (remainder)
1923 scanline_width_bits += 32 - remainder;
1925 /* Bitmaps with a depth less than 16 need a palette. */
1926 /* BITMAPINFO structure already contains the first RGBQUAD. */
1927 if (depth < 16)
1928 palette_colors = 1 << depth - 1;
1930 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
1931 if (*ximg == NULL)
1933 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
1934 return 0;
1937 header = &((*ximg)->info.bmiHeader);
1938 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
1939 header->biSize = sizeof (*header);
1940 header->biWidth = width;
1941 header->biHeight = -height; /* negative indicates a top-down bitmap. */
1942 header->biPlanes = 1;
1943 header->biBitCount = depth;
1944 header->biCompression = BI_RGB;
1945 header->biClrUsed = palette_colors;
1947 /* TODO: fill in palette. */
1948 if (depth == 1)
1950 (*ximg)->info.bmiColors[0].rgbBlue = 0;
1951 (*ximg)->info.bmiColors[0].rgbGreen = 0;
1952 (*ximg)->info.bmiColors[0].rgbRed = 0;
1953 (*ximg)->info.bmiColors[0].rgbReserved = 0;
1954 (*ximg)->info.bmiColors[1].rgbBlue = 255;
1955 (*ximg)->info.bmiColors[1].rgbGreen = 255;
1956 (*ximg)->info.bmiColors[1].rgbRed = 255;
1957 (*ximg)->info.bmiColors[1].rgbReserved = 0;
1960 hdc = get_frame_dc (f);
1962 /* Create a DIBSection and raster array for the bitmap,
1963 and store its handle in *pixmap. */
1964 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
1965 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
1966 &((*ximg)->data), NULL, 0);
1968 /* Realize display palette and garbage all frames. */
1969 release_frame_dc (f, hdc);
1971 if (*pixmap == NULL)
1973 DWORD err = GetLastError();
1974 Lisp_Object errcode;
1975 /* All system errors are < 10000, so the following is safe. */
1976 XSETINT (errcode, (int) err);
1977 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
1978 x_destroy_x_image (*ximg);
1979 return 0;
1982 return 1;
1984 #endif /* HAVE_NTGUI */
1986 #ifdef MAC_OS
1987 Display *display = FRAME_X_DISPLAY (f);
1988 Window window = FRAME_X_WINDOW (f);
1990 xassert (interrupt_input_blocked);
1992 /* Allocate a pixmap of the same size. */
1993 *pixmap = XCreatePixmap (display, window, width, height, depth);
1994 if (*pixmap == NO_PIXMAP)
1996 x_destroy_x_image (*ximg);
1997 *ximg = NULL;
1998 image_error ("Unable to create X pixmap", Qnil, Qnil);
1999 return 0;
2002 LockPixels (GetGWorldPixMap (*pixmap));
2003 *ximg = *pixmap;
2004 return 1;
2006 #endif /* MAC_OS */
2010 /* Destroy XImage XIMG. Free XIMG->data. */
2012 static void
2013 x_destroy_x_image (ximg)
2014 XImagePtr ximg;
2016 xassert (interrupt_input_blocked);
2017 if (ximg)
2019 #ifdef HAVE_X_WINDOWS
2020 xfree (ximg->data);
2021 ximg->data = NULL;
2022 XDestroyImage (ximg);
2023 #endif /* HAVE_X_WINDOWS */
2024 #ifdef HAVE_NTGUI
2025 /* Data will be freed by DestroyObject. */
2026 ximg->data = NULL;
2027 xfree (ximg);
2028 #endif /* HAVE_NTGUI */
2029 #ifdef MAC_OS
2030 XDestroyImage (ximg);
2031 #endif /* MAC_OS */
2036 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
2037 are width and height of both the image and pixmap. */
2039 static void
2040 x_put_x_image (f, ximg, pixmap, width, height)
2041 struct frame *f;
2042 XImagePtr ximg;
2043 Pixmap pixmap;
2044 int width, height;
2046 #ifdef HAVE_X_WINDOWS
2047 GC gc;
2049 xassert (interrupt_input_blocked);
2050 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
2051 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
2052 XFreeGC (FRAME_X_DISPLAY (f), gc);
2053 #endif /* HAVE_X_WINDOWS */
2055 #ifdef HAVE_NTGUI
2056 #if 0 /* I don't think this is necessary looking at where it is used. */
2057 HDC hdc = get_frame_dc (f);
2058 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
2059 release_frame_dc (f, hdc);
2060 #endif
2061 #endif /* HAVE_NTGUI */
2063 #ifdef MAC_OS
2064 xassert (ximg == pixmap);
2065 #endif /* MAC_OS */
2069 /***********************************************************************
2070 File Handling
2071 ***********************************************************************/
2073 static unsigned char *slurp_file P_ ((char *, int *));
2076 /* Find image file FILE. Look in data-directory, then
2077 x-bitmap-file-path. Value is the full name of the file found, or
2078 nil if not found. */
2080 Lisp_Object
2081 x_find_image_file (file)
2082 Lisp_Object file;
2084 Lisp_Object file_found, search_path;
2085 struct gcpro gcpro1, gcpro2;
2086 int fd;
2088 file_found = Qnil;
2089 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
2090 GCPRO2 (file_found, search_path);
2092 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
2093 fd = openp (search_path, file, Qnil, &file_found, Qnil);
2095 if (fd == -1)
2096 file_found = Qnil;
2097 else
2098 close (fd);
2100 UNGCPRO;
2101 return file_found;
2105 /* Read FILE into memory. Value is a pointer to a buffer allocated
2106 with xmalloc holding FILE's contents. Value is null if an error
2107 occurred. *SIZE is set to the size of the file. */
2109 static unsigned char *
2110 slurp_file (file, size)
2111 char *file;
2112 int *size;
2114 FILE *fp = NULL;
2115 unsigned char *buf = NULL;
2116 struct stat st;
2118 if (stat (file, &st) == 0
2119 && (fp = fopen (file, "rb")) != NULL
2120 && (buf = (char *) xmalloc (st.st_size),
2121 fread (buf, 1, st.st_size, fp) == st.st_size))
2123 *size = st.st_size;
2124 fclose (fp);
2126 else
2128 if (fp)
2129 fclose (fp);
2130 if (buf)
2132 xfree (buf);
2133 buf = NULL;
2137 return buf;
2142 #ifdef MAC_OS
2144 /***********************************************************************
2145 MAC Image Load Functions
2146 ***********************************************************************/
2148 static int image_load_quicktime P_ ((struct frame *, struct image *img,
2149 OSType));
2150 #ifdef MAC_OSX
2151 static int image_load_quartz2d P_ ((struct frame *, struct image *img, int));
2152 #endif
2154 static OSErr
2155 find_image_fsspec (specified_file, file, fss)
2156 Lisp_Object specified_file, *file;
2157 FSSpec *fss;
2159 #if TARGET_API_MAC_CARBON
2160 FSRef fsr;
2161 #else
2162 Str255 mac_pathname;
2163 #endif
2164 OSErr err;
2166 *file = x_find_image_file (specified_file);
2167 if (!STRINGP (*file))
2168 return fnfErr; /* file or directory not found;
2169 incomplete pathname */
2170 /* Try to open the image file. */
2171 #if TARGET_API_MAC_CARBON
2172 err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
2173 if (err == noErr)
2174 err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
2175 #else
2176 if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
2177 return fnfErr;
2178 c2pstr (mac_pathname);
2179 err = FSMakeFSSpec (0, 0, mac_pathname, fss);
2180 #endif
2181 return err;
2184 static int
2185 image_load_qt_1 (f, img, type, fss, dh)
2186 struct frame *f;
2187 struct image *img;
2188 OSType type;
2189 FSSpec *fss;
2190 Handle dh;
2192 OSErr err;
2193 GraphicsImportComponent gi;
2194 Rect rect;
2195 int width, height;
2196 short draw_all_pixels;
2197 Lisp_Object specified_bg;
2198 XColor color;
2199 XImagePtr ximg;
2200 RGBColor bg_color;
2202 err = OpenADefaultComponent (GraphicsImporterComponentType,
2203 type, &gi);
2204 if (err != noErr)
2206 image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
2207 return 0;
2209 if (dh == NULL)
2211 /* read from file system spec */
2212 err = GraphicsImportSetDataFile (gi, fss);
2213 if (err != noErr)
2215 image_error ("Cannot set fsspec to graphics importer for '%s'",
2216 img->spec, Qnil);
2217 goto error;
2220 else
2222 /* read from data handle */
2223 err = GraphicsImportSetDataHandle (gi, dh);
2224 if (err != noErr)
2226 image_error ("Cannot set data handle to graphics importer for `%s'",
2227 img->spec, Qnil);
2228 goto error;
2231 err = GraphicsImportGetNaturalBounds (gi, &rect);
2232 if (err != noErr)
2234 image_error ("Error reading `%s'", img->spec, Qnil);
2235 goto error;
2237 width = img->width = rect.right - rect.left;
2238 height = img->height = rect.bottom - rect.top;
2239 err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
2240 #if 0
2241 /* Don't check the error code here. It may have an undocumented
2242 value -32766. */
2243 if (err != noErr)
2245 image_error ("Error reading `%s'", img->spec, Qnil);
2246 goto error;
2248 #endif
2249 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2251 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2252 if (!STRINGP (specified_bg) ||
2253 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2255 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2256 color.red = RED16_FROM_ULONG (color.pixel);
2257 color.green = GREEN16_FROM_ULONG (color.pixel);
2258 color.blue = BLUE16_FROM_ULONG (color.pixel);
2262 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2263 goto error;
2264 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2266 CGrafPtr old_port;
2267 GDHandle old_gdh;
2269 GetGWorld (&old_port, &old_gdh);
2270 SetGWorld (ximg, NULL);
2271 bg_color.red = color.red;
2272 bg_color.green = color.green;
2273 bg_color.blue = color.blue;
2274 RGBBackColor (&bg_color);
2275 #if TARGET_API_MAC_CARBON
2276 GetPortBounds (ximg, &rect);
2277 EraseRect (&rect);
2278 #else
2279 EraseRect (&(ximg->portRect));
2280 #endif
2281 SetGWorld (old_port, old_gdh);
2283 GraphicsImportSetGWorld (gi, ximg, NULL);
2284 GraphicsImportDraw (gi);
2285 CloseComponent (gi);
2287 /* Maybe fill in the background field while we have ximg handy. */
2288 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2289 IMAGE_BACKGROUND (img, f, ximg);
2291 /* Put the image into the pixmap. */
2292 x_put_x_image (f, ximg, img->pixmap, width, height);
2293 x_destroy_x_image (ximg);
2294 return 1;
2296 error:
2297 CloseComponent (gi);
2298 return 0;
2302 /* Load an image using the QuickTime Graphics Importer.
2303 Note: The alpha channel does not work for PNG images. */
2304 static int
2305 image_load_quicktime (f, img, type)
2306 struct frame *f;
2307 struct image *img;
2308 OSType type;
2310 Lisp_Object specified_file;
2311 Lisp_Object specified_data;
2312 OSErr err;
2314 specified_file = image_spec_value (img->spec, QCfile, NULL);
2315 specified_data = image_spec_value (img->spec, QCdata, NULL);
2317 if (NILP (specified_data))
2319 /* Read from a file */
2320 Lisp_Object file;
2321 FSSpec fss;
2323 err = find_image_fsspec (specified_file, &file, &fss);
2324 if (err != noErr)
2326 if (err == fnfErr)
2327 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2328 else
2329 image_error ("Cannot open `%s'", file, Qnil);
2330 return 0;
2332 return image_load_qt_1 (f, img, type, &fss, NULL);
2334 else
2336 /* Memory source! */
2337 int success_p;
2338 Handle dh;
2340 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
2341 if (err != noErr)
2343 image_error ("Cannot allocate data handle for `%s'",
2344 img->spec, Qnil);
2345 return 0;
2347 success_p = image_load_qt_1 (f, img, type, NULL, dh);
2348 DisposeHandle (dh);
2349 return success_p;
2354 #ifdef MAC_OSX
2355 /* Load a PNG/JPEG image using Quartz 2D decoding routines.
2356 CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2.
2357 So don't use this function directly but determine at runtime
2358 whether it exists. */
2359 typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType)
2360 (CGDataProviderRef, const float [], bool, CGColorRenderingIntent);
2361 static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider;
2364 static void
2365 init_image_func_pointer ()
2367 if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider"))
2369 MyCGImageCreateWithPNGDataProvider
2370 = (CGImageCreateWithPNGDataProviderProcType)
2371 NSAddressOfSymbol (NSLookupAndBindSymbol
2372 ("_CGImageCreateWithPNGDataProvider"));
2374 else
2375 MyCGImageCreateWithPNGDataProvider = NULL;
2379 static int
2380 image_load_quartz2d (f, img, png_p)
2381 struct frame *f;
2382 struct image *img;
2383 int png_p;
2385 Lisp_Object file, specified_file;
2386 Lisp_Object specified_data, specified_bg;
2387 struct gcpro gcpro1;
2388 CGDataProviderRef source;
2389 CGImageRef image;
2390 int width, height;
2391 XColor color;
2392 XImagePtr ximg = NULL;
2393 CGContextRef context;
2394 CGRect rectangle;
2396 /* Open the file. */
2397 specified_file = image_spec_value (img->spec, QCfile, NULL);
2398 specified_data = image_spec_value (img->spec, QCdata, NULL);
2400 file = Qnil;
2401 GCPRO1 (file);
2403 if (NILP (specified_data))
2405 CFStringRef path;
2406 CFURLRef url;
2408 file = x_find_image_file (specified_file);
2409 if (!STRINGP (file))
2411 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2412 UNGCPRO;
2413 return 0;
2415 path = CFStringCreateWithCString (NULL, SDATA (file),
2416 kCFStringEncodingUTF8);
2417 url = CFURLCreateWithFileSystemPath (NULL, path,
2418 kCFURLPOSIXPathStyle, 0);
2419 CFRelease (path);
2420 source = CGDataProviderCreateWithURL (url);
2421 CFRelease (url);
2423 else
2424 source = CGDataProviderCreateWithData (NULL, SDATA (specified_data),
2425 SBYTES (specified_data), NULL);
2427 if (png_p)
2428 image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE,
2429 kCGRenderingIntentDefault);
2430 else
2431 image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE,
2432 kCGRenderingIntentDefault);
2434 CGDataProviderRelease (source);
2435 if (image == NULL)
2437 UNGCPRO;
2438 image_error ("Error reading image `%s'", img->spec, Qnil);
2439 return 0;
2442 if (png_p)
2444 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2445 if (!STRINGP (specified_bg) ||
2446 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2448 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2449 color.red = RED16_FROM_ULONG (color.pixel);
2450 color.green = GREEN16_FROM_ULONG (color.pixel);
2451 color.blue = BLUE16_FROM_ULONG (color.pixel);
2454 width = img->width = CGImageGetWidth (image);
2455 height = img->height = CGImageGetHeight (image);
2456 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2458 CGImageRelease (image);
2459 UNGCPRO;
2460 return 0;
2462 rectangle = CGRectMake (0, 0, width, height);
2463 QDBeginCGContext (ximg, &context);
2464 if (png_p)
2466 CGContextSetRGBFillColor (context, color.red / 65535.0,
2467 color.green / 65535.0,
2468 color.blue / 65535.0, 1.0);
2469 CGContextFillRect (context, rectangle);
2471 CGContextDrawImage (context, rectangle, image);
2472 QDEndCGContext (ximg, &context);
2473 CGImageRelease (image);
2475 /* Maybe fill in the background field while we have ximg handy. */
2476 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2477 IMAGE_BACKGROUND (img, f, ximg);
2479 /* Put the image into the pixmap. */
2480 x_put_x_image (f, ximg, img->pixmap, width, height);
2481 x_destroy_x_image (ximg);
2482 UNGCPRO;
2483 return 1;
2485 #endif
2487 #endif /* MAC_OS */
2490 /***********************************************************************
2491 XBM images
2492 ***********************************************************************/
2494 static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
2495 static int xbm_load P_ ((struct frame *f, struct image *img));
2496 static int xbm_load_image P_ ((struct frame *f, struct image *img,
2497 unsigned char *, unsigned char *));
2498 static int xbm_image_p P_ ((Lisp_Object object));
2499 static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
2500 int *, int *, unsigned char **));
2501 static int xbm_file_p P_ ((Lisp_Object));
2504 /* Indices of image specification fields in xbm_format, below. */
2506 enum xbm_keyword_index
2508 XBM_TYPE,
2509 XBM_FILE,
2510 XBM_WIDTH,
2511 XBM_HEIGHT,
2512 XBM_DATA,
2513 XBM_FOREGROUND,
2514 XBM_BACKGROUND,
2515 XBM_ASCENT,
2516 XBM_MARGIN,
2517 XBM_RELIEF,
2518 XBM_ALGORITHM,
2519 XBM_HEURISTIC_MASK,
2520 XBM_MASK,
2521 XBM_LAST
2524 /* Vector of image_keyword structures describing the format
2525 of valid XBM image specifications. */
2527 static struct image_keyword xbm_format[XBM_LAST] =
2529 {":type", IMAGE_SYMBOL_VALUE, 1},
2530 {":file", IMAGE_STRING_VALUE, 0},
2531 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2532 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2533 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2534 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
2535 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
2536 {":ascent", IMAGE_ASCENT_VALUE, 0},
2537 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
2538 {":relief", IMAGE_INTEGER_VALUE, 0},
2539 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2540 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2541 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
2544 /* Structure describing the image type XBM. */
2546 static struct image_type xbm_type =
2548 &Qxbm,
2549 xbm_image_p,
2550 xbm_load,
2551 x_clear_image,
2552 NULL
2555 /* Tokens returned from xbm_scan. */
2557 enum xbm_token
2559 XBM_TK_IDENT = 256,
2560 XBM_TK_NUMBER
2564 /* Return non-zero if OBJECT is a valid XBM-type image specification.
2565 A valid specification is a list starting with the symbol `image'
2566 The rest of the list is a property list which must contain an
2567 entry `:type xbm..
2569 If the specification specifies a file to load, it must contain
2570 an entry `:file FILENAME' where FILENAME is a string.
2572 If the specification is for a bitmap loaded from memory it must
2573 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
2574 WIDTH and HEIGHT are integers > 0. DATA may be:
2576 1. a string large enough to hold the bitmap data, i.e. it must
2577 have a size >= (WIDTH + 7) / 8 * HEIGHT
2579 2. a bool-vector of size >= WIDTH * HEIGHT
2581 3. a vector of strings or bool-vectors, one for each line of the
2582 bitmap.
2584 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
2585 may not be specified in this case because they are defined in the
2586 XBM file.
2588 Both the file and data forms may contain the additional entries
2589 `:background COLOR' and `:foreground COLOR'. If not present,
2590 foreground and background of the frame on which the image is
2591 displayed is used. */
2593 static int
2594 xbm_image_p (object)
2595 Lisp_Object object;
2597 struct image_keyword kw[XBM_LAST];
2599 bcopy (xbm_format, kw, sizeof kw);
2600 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
2601 return 0;
2603 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
2605 if (kw[XBM_FILE].count)
2607 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
2608 return 0;
2610 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
2612 /* In-memory XBM file. */
2613 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
2614 return 0;
2616 else
2618 Lisp_Object data;
2619 int width, height;
2621 /* Entries for `:width', `:height' and `:data' must be present. */
2622 if (!kw[XBM_WIDTH].count
2623 || !kw[XBM_HEIGHT].count
2624 || !kw[XBM_DATA].count)
2625 return 0;
2627 data = kw[XBM_DATA].value;
2628 width = XFASTINT (kw[XBM_WIDTH].value);
2629 height = XFASTINT (kw[XBM_HEIGHT].value);
2631 /* Check type of data, and width and height against contents of
2632 data. */
2633 if (VECTORP (data))
2635 int i;
2637 /* Number of elements of the vector must be >= height. */
2638 if (XVECTOR (data)->size < height)
2639 return 0;
2641 /* Each string or bool-vector in data must be large enough
2642 for one line of the image. */
2643 for (i = 0; i < height; ++i)
2645 Lisp_Object elt = XVECTOR (data)->contents[i];
2647 if (STRINGP (elt))
2649 if (SCHARS (elt)
2650 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
2651 return 0;
2653 else if (BOOL_VECTOR_P (elt))
2655 if (XBOOL_VECTOR (elt)->size < width)
2656 return 0;
2658 else
2659 return 0;
2662 else if (STRINGP (data))
2664 if (SCHARS (data)
2665 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
2666 return 0;
2668 else if (BOOL_VECTOR_P (data))
2670 if (XBOOL_VECTOR (data)->size < width * height)
2671 return 0;
2673 else
2674 return 0;
2677 return 1;
2681 /* Scan a bitmap file. FP is the stream to read from. Value is
2682 either an enumerator from enum xbm_token, or a character for a
2683 single-character token, or 0 at end of file. If scanning an
2684 identifier, store the lexeme of the identifier in SVAL. If
2685 scanning a number, store its value in *IVAL. */
2687 static int
2688 xbm_scan (s, end, sval, ival)
2689 unsigned char **s, *end;
2690 char *sval;
2691 int *ival;
2693 unsigned int c;
2695 loop:
2697 /* Skip white space. */
2698 while (*s < end && (c = *(*s)++, isspace (c)))
2701 if (*s >= end)
2702 c = 0;
2703 else if (isdigit (c))
2705 int value = 0, digit;
2707 if (c == '0' && *s < end)
2709 c = *(*s)++;
2710 if (c == 'x' || c == 'X')
2712 while (*s < end)
2714 c = *(*s)++;
2715 if (isdigit (c))
2716 digit = c - '0';
2717 else if (c >= 'a' && c <= 'f')
2718 digit = c - 'a' + 10;
2719 else if (c >= 'A' && c <= 'F')
2720 digit = c - 'A' + 10;
2721 else
2722 break;
2723 value = 16 * value + digit;
2726 else if (isdigit (c))
2728 value = c - '0';
2729 while (*s < end
2730 && (c = *(*s)++, isdigit (c)))
2731 value = 8 * value + c - '0';
2734 else
2736 value = c - '0';
2737 while (*s < end
2738 && (c = *(*s)++, isdigit (c)))
2739 value = 10 * value + c - '0';
2742 if (*s < end)
2743 *s = *s - 1;
2744 *ival = value;
2745 c = XBM_TK_NUMBER;
2747 else if (isalpha (c) || c == '_')
2749 *sval++ = c;
2750 while (*s < end
2751 && (c = *(*s)++, (isalnum (c) || c == '_')))
2752 *sval++ = c;
2753 *sval = 0;
2754 if (*s < end)
2755 *s = *s - 1;
2756 c = XBM_TK_IDENT;
2758 else if (c == '/' && **s == '*')
2760 /* C-style comment. */
2761 ++*s;
2762 while (**s && (**s != '*' || *(*s + 1) != '/'))
2763 ++*s;
2764 if (**s)
2766 *s += 2;
2767 goto loop;
2771 return c;
2774 #ifdef HAVE_NTGUI
2776 /* Create a Windows bitmap from X bitmap data. */
2777 static HBITMAP
2778 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
2780 static unsigned char swap_nibble[16]
2781 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
2782 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
2783 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
2784 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
2785 int i, j, w1, w2;
2786 unsigned char *bits, *p;
2787 HBITMAP bmp;
2789 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
2790 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
2791 bits = (unsigned char *) alloca (height * w2);
2792 bzero (bits, height * w2);
2793 for (i = 0; i < height; i++)
2795 p = bits + i*w2;
2796 for (j = 0; j < w1; j++)
2798 /* Bitswap XBM bytes to match how Windows does things. */
2799 unsigned char c = *data++;
2800 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
2801 | (swap_nibble[(c>>4) & 0xf]));
2804 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
2806 return bmp;
2809 static void convert_mono_to_color_image (f, img, foreground, background)
2810 struct frame *f;
2811 struct image *img;
2812 COLORREF foreground, background;
2814 HDC hdc, old_img_dc, new_img_dc;
2815 HGDIOBJ old_prev, new_prev;
2816 HBITMAP new_pixmap;
2818 hdc = get_frame_dc (f);
2819 old_img_dc = CreateCompatibleDC (hdc);
2820 new_img_dc = CreateCompatibleDC (hdc);
2821 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
2822 release_frame_dc (f, hdc);
2823 old_prev = SelectObject (old_img_dc, img->pixmap);
2824 new_prev = SelectObject (new_img_dc, new_pixmap);
2825 SetTextColor (new_img_dc, foreground);
2826 SetBkColor (new_img_dc, background);
2828 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
2829 0, 0, SRCCOPY);
2831 SelectObject (old_img_dc, old_prev);
2832 SelectObject (new_img_dc, new_prev);
2833 DeleteDC (old_img_dc);
2834 DeleteDC (new_img_dc);
2835 DeleteObject (img->pixmap);
2836 if (new_pixmap == 0)
2837 fprintf (stderr, "Failed to convert image to color.\n");
2838 else
2839 img->pixmap = new_pixmap;
2842 #define XBM_BIT_SHUFFLE(b) (~(b))
2844 #else
2846 #define XBM_BIT_SHUFFLE(b) (b)
2848 #endif /* HAVE_NTGUI */
2851 static void
2852 Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
2853 struct frame *f;
2854 struct image *img;
2855 char *data;
2856 RGB_PIXEL_COLOR fg, bg;
2857 int non_default_colors;
2859 #ifdef HAVE_NTGUI
2860 img->pixmap
2861 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
2863 /* If colors were specified, transfer the bitmap to a color one. */
2864 if (non_default_colors)
2865 convert_mono_to_color_image (f, img, fg, bg);
2866 #else
2867 img->pixmap
2868 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
2869 FRAME_X_WINDOW (f),
2870 data,
2871 img->width, img->height,
2872 fg, bg,
2873 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
2874 #endif /* HAVE_NTGUI */
2879 /* Replacement for XReadBitmapFileData which isn't available under old
2880 X versions. CONTENTS is a pointer to a buffer to parse; END is the
2881 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
2882 the image. Return in *DATA the bitmap data allocated with xmalloc.
2883 Value is non-zero if successful. DATA null means just test if
2884 CONTENTS looks like an in-memory XBM file. */
2886 static int
2887 xbm_read_bitmap_data (contents, end, width, height, data)
2888 unsigned char *contents, *end;
2889 int *width, *height;
2890 unsigned char **data;
2892 unsigned char *s = contents;
2893 char buffer[BUFSIZ];
2894 int padding_p = 0;
2895 int v10 = 0;
2896 int bytes_per_line, i, nbytes;
2897 unsigned char *p;
2898 int value;
2899 int LA1;
2901 #define match() \
2902 LA1 = xbm_scan (&s, end, buffer, &value)
2904 #define expect(TOKEN) \
2905 if (LA1 != (TOKEN)) \
2906 goto failure; \
2907 else \
2908 match ()
2910 #define expect_ident(IDENT) \
2911 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2912 match (); \
2913 else \
2914 goto failure
2916 *width = *height = -1;
2917 if (data)
2918 *data = NULL;
2919 LA1 = xbm_scan (&s, end, buffer, &value);
2921 /* Parse defines for width, height and hot-spots. */
2922 while (LA1 == '#')
2924 match ();
2925 expect_ident ("define");
2926 expect (XBM_TK_IDENT);
2928 if (LA1 == XBM_TK_NUMBER);
2930 char *p = strrchr (buffer, '_');
2931 p = p ? p + 1 : buffer;
2932 if (strcmp (p, "width") == 0)
2933 *width = value;
2934 else if (strcmp (p, "height") == 0)
2935 *height = value;
2937 expect (XBM_TK_NUMBER);
2940 if (*width < 0 || *height < 0)
2941 goto failure;
2942 else if (data == NULL)
2943 goto success;
2945 /* Parse bits. Must start with `static'. */
2946 expect_ident ("static");
2947 if (LA1 == XBM_TK_IDENT)
2949 if (strcmp (buffer, "unsigned") == 0)
2951 match ();
2952 expect_ident ("char");
2954 else if (strcmp (buffer, "short") == 0)
2956 match ();
2957 v10 = 1;
2958 if (*width % 16 && *width % 16 < 9)
2959 padding_p = 1;
2961 else if (strcmp (buffer, "char") == 0)
2962 match ();
2963 else
2964 goto failure;
2966 else
2967 goto failure;
2969 expect (XBM_TK_IDENT);
2970 expect ('[');
2971 expect (']');
2972 expect ('=');
2973 expect ('{');
2975 bytes_per_line = (*width + 7) / 8 + padding_p;
2976 nbytes = bytes_per_line * *height;
2977 p = *data = (char *) xmalloc (nbytes);
2979 if (v10)
2981 for (i = 0; i < nbytes; i += 2)
2983 int val = value;
2984 expect (XBM_TK_NUMBER);
2986 *p++ = XBM_BIT_SHUFFLE (val);
2987 if (!padding_p || ((i + 2) % bytes_per_line))
2988 *p++ = XBM_BIT_SHUFFLE (value >> 8);
2990 if (LA1 == ',' || LA1 == '}')
2991 match ();
2992 else
2993 goto failure;
2996 else
2998 for (i = 0; i < nbytes; ++i)
3000 int val = value;
3001 expect (XBM_TK_NUMBER);
3003 *p++ = XBM_BIT_SHUFFLE (val);
3005 if (LA1 == ',' || LA1 == '}')
3006 match ();
3007 else
3008 goto failure;
3012 success:
3013 return 1;
3015 failure:
3017 if (data && *data)
3019 xfree (*data);
3020 *data = NULL;
3022 return 0;
3024 #undef match
3025 #undef expect
3026 #undef expect_ident
3030 /* Load XBM image IMG which will be displayed on frame F from buffer
3031 CONTENTS. END is the end of the buffer. Value is non-zero if
3032 successful. */
3034 static int
3035 xbm_load_image (f, img, contents, end)
3036 struct frame *f;
3037 struct image *img;
3038 unsigned char *contents, *end;
3040 int rc;
3041 unsigned char *data;
3042 int success_p = 0;
3044 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
3045 if (rc)
3047 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3048 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3049 int non_default_colors = 0;
3050 Lisp_Object value;
3052 xassert (img->width > 0 && img->height > 0);
3054 /* Get foreground and background colors, maybe allocate colors. */
3055 value = image_spec_value (img->spec, QCforeground, NULL);
3056 if (!NILP (value))
3058 foreground = x_alloc_image_color (f, img, value, foreground);
3059 non_default_colors = 1;
3061 value = image_spec_value (img->spec, QCbackground, NULL);
3062 if (!NILP (value))
3064 background = x_alloc_image_color (f, img, value, background);
3065 img->background = background;
3066 img->background_valid = 1;
3067 non_default_colors = 1;
3070 Create_Pixmap_From_Bitmap_Data (f, img, data,
3071 foreground, background,
3072 non_default_colors);
3073 xfree (data);
3075 if (img->pixmap == NO_PIXMAP)
3077 x_clear_image (f, img);
3078 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3080 else
3081 success_p = 1;
3083 else
3084 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3086 return success_p;
3090 /* Value is non-zero if DATA looks like an in-memory XBM file. */
3092 static int
3093 xbm_file_p (data)
3094 Lisp_Object data;
3096 int w, h;
3097 return (STRINGP (data)
3098 && xbm_read_bitmap_data (SDATA (data),
3099 (SDATA (data)
3100 + SBYTES (data)),
3101 &w, &h, NULL));
3105 /* Fill image IMG which is used on frame F with pixmap data. Value is
3106 non-zero if successful. */
3108 static int
3109 xbm_load (f, img)
3110 struct frame *f;
3111 struct image *img;
3113 int success_p = 0;
3114 Lisp_Object file_name;
3116 xassert (xbm_image_p (img->spec));
3118 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3119 file_name = image_spec_value (img->spec, QCfile, NULL);
3120 if (STRINGP (file_name))
3122 Lisp_Object file;
3123 unsigned char *contents;
3124 int size;
3125 struct gcpro gcpro1;
3127 file = x_find_image_file (file_name);
3128 GCPRO1 (file);
3129 if (!STRINGP (file))
3131 image_error ("Cannot find image file `%s'", file_name, Qnil);
3132 UNGCPRO;
3133 return 0;
3136 contents = slurp_file (SDATA (file), &size);
3137 if (contents == NULL)
3139 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3140 UNGCPRO;
3141 return 0;
3144 success_p = xbm_load_image (f, img, contents, contents + size);
3145 UNGCPRO;
3147 else
3149 struct image_keyword fmt[XBM_LAST];
3150 Lisp_Object data;
3151 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3152 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3153 int non_default_colors = 0;
3154 char *bits;
3155 int parsed_p;
3156 int in_memory_file_p = 0;
3158 /* See if data looks like an in-memory XBM file. */
3159 data = image_spec_value (img->spec, QCdata, NULL);
3160 in_memory_file_p = xbm_file_p (data);
3162 /* Parse the image specification. */
3163 bcopy (xbm_format, fmt, sizeof fmt);
3164 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3165 xassert (parsed_p);
3167 /* Get specified width, and height. */
3168 if (!in_memory_file_p)
3170 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3171 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3172 xassert (img->width > 0 && img->height > 0);
3175 /* Get foreground and background colors, maybe allocate colors. */
3176 if (fmt[XBM_FOREGROUND].count
3177 && STRINGP (fmt[XBM_FOREGROUND].value))
3179 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3180 foreground);
3181 non_default_colors = 1;
3184 if (fmt[XBM_BACKGROUND].count
3185 && STRINGP (fmt[XBM_BACKGROUND].value))
3187 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3188 background);
3189 non_default_colors = 1;
3192 if (in_memory_file_p)
3193 success_p = xbm_load_image (f, img, SDATA (data),
3194 (SDATA (data)
3195 + SBYTES (data)));
3196 else
3198 if (VECTORP (data))
3200 int i;
3201 char *p;
3202 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3204 p = bits = (char *) alloca (nbytes * img->height);
3205 for (i = 0; i < img->height; ++i, p += nbytes)
3207 Lisp_Object line = XVECTOR (data)->contents[i];
3208 if (STRINGP (line))
3209 bcopy (SDATA (line), p, nbytes);
3210 else
3211 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3214 else if (STRINGP (data))
3215 bits = SDATA (data);
3216 else
3217 bits = XBOOL_VECTOR (data)->data;
3219 /* Create the pixmap. */
3221 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3222 foreground, background,
3223 non_default_colors);
3224 if (img->pixmap)
3225 success_p = 1;
3226 else
3228 image_error ("Unable to create pixmap for XBM image `%s'",
3229 img->spec, Qnil);
3230 x_clear_image (f, img);
3235 return success_p;
3240 /***********************************************************************
3241 XPM images
3242 ***********************************************************************/
3244 #if defined (HAVE_XPM) || defined (MAC_OS)
3246 static int xpm_image_p P_ ((Lisp_Object object));
3247 static int xpm_load P_ ((struct frame *f, struct image *img));
3248 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3250 #endif /* HAVE_XPM || MAC_OS */
3252 #ifdef HAVE_XPM
3253 #ifdef HAVE_NTGUI
3254 /* Indicate to xpm.h that we don't have Xlib. */
3255 #define FOR_MSW
3256 /* simx.h in xpm defines XColor and XImage differently than Emacs. */
3257 /* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
3258 #define XColor xpm_XColor
3259 #define XImage xpm_XImage
3260 #define Display xpm_Display
3261 #define PIXEL_ALREADY_TYPEDEFED
3262 #include "X11/xpm.h"
3263 #undef FOR_MSW
3264 #undef XColor
3265 #undef XImage
3266 #undef Display
3267 #undef PIXEL_ALREADY_TYPEDEFED
3268 #else
3269 #include "X11/xpm.h"
3270 #endif /* HAVE_NTGUI */
3271 #endif /* HAVE_XPM */
3273 #if defined (HAVE_XPM) || defined (MAC_OS)
3274 /* The symbol `xpm' identifying XPM-format images. */
3276 Lisp_Object Qxpm;
3278 /* Indices of image specification fields in xpm_format, below. */
3280 enum xpm_keyword_index
3282 XPM_TYPE,
3283 XPM_FILE,
3284 XPM_DATA,
3285 XPM_ASCENT,
3286 XPM_MARGIN,
3287 XPM_RELIEF,
3288 XPM_ALGORITHM,
3289 XPM_HEURISTIC_MASK,
3290 XPM_MASK,
3291 XPM_COLOR_SYMBOLS,
3292 XPM_BACKGROUND,
3293 XPM_LAST
3296 /* Vector of image_keyword structures describing the format
3297 of valid XPM image specifications. */
3299 static struct image_keyword xpm_format[XPM_LAST] =
3301 {":type", IMAGE_SYMBOL_VALUE, 1},
3302 {":file", IMAGE_STRING_VALUE, 0},
3303 {":data", IMAGE_STRING_VALUE, 0},
3304 {":ascent", IMAGE_ASCENT_VALUE, 0},
3305 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3306 {":relief", IMAGE_INTEGER_VALUE, 0},
3307 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3308 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3309 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3310 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3311 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3314 /* Structure describing the image type XPM. */
3316 static struct image_type xpm_type =
3318 &Qxpm,
3319 xpm_image_p,
3320 xpm_load,
3321 x_clear_image,
3322 NULL
3325 #ifdef HAVE_X_WINDOWS
3327 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3328 functions for allocating image colors. Our own functions handle
3329 color allocation failures more gracefully than the ones on the XPM
3330 lib. */
3332 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3333 #define ALLOC_XPM_COLORS
3334 #endif
3335 #endif /* HAVE_X_WINDOWS */
3337 #ifdef ALLOC_XPM_COLORS
3339 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3340 static void xpm_free_color_cache P_ ((void));
3341 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3342 static int xpm_color_bucket P_ ((char *));
3343 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3344 XColor *, int));
3346 /* An entry in a hash table used to cache color definitions of named
3347 colors. This cache is necessary to speed up XPM image loading in
3348 case we do color allocations ourselves. Without it, we would need
3349 a call to XParseColor per pixel in the image. */
3351 struct xpm_cached_color
3353 /* Next in collision chain. */
3354 struct xpm_cached_color *next;
3356 /* Color definition (RGB and pixel color). */
3357 XColor color;
3359 /* Color name. */
3360 char name[1];
3363 /* The hash table used for the color cache, and its bucket vector
3364 size. */
3366 #define XPM_COLOR_CACHE_BUCKETS 1001
3367 struct xpm_cached_color **xpm_color_cache;
3369 /* Initialize the color cache. */
3371 static void
3372 xpm_init_color_cache (f, attrs)
3373 struct frame *f;
3374 XpmAttributes *attrs;
3376 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3377 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3378 memset (xpm_color_cache, 0, nbytes);
3379 init_color_table ();
3381 if (attrs->valuemask & XpmColorSymbols)
3383 int i;
3384 XColor color;
3386 for (i = 0; i < attrs->numsymbols; ++i)
3387 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3388 attrs->colorsymbols[i].value, &color))
3390 color.pixel = lookup_rgb_color (f, color.red, color.green,
3391 color.blue);
3392 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3397 /* Free the color cache. */
3399 static void
3400 xpm_free_color_cache ()
3402 struct xpm_cached_color *p, *next;
3403 int i;
3405 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3406 for (p = xpm_color_cache[i]; p; p = next)
3408 next = p->next;
3409 xfree (p);
3412 xfree (xpm_color_cache);
3413 xpm_color_cache = NULL;
3414 free_color_table ();
3417 /* Return the bucket index for color named COLOR_NAME in the color
3418 cache. */
3420 static int
3421 xpm_color_bucket (color_name)
3422 char *color_name;
3424 unsigned h = 0;
3425 char *s;
3427 for (s = color_name; *s; ++s)
3428 h = (h << 2) ^ *s;
3429 return h %= XPM_COLOR_CACHE_BUCKETS;
3433 /* On frame F, cache values COLOR for color with name COLOR_NAME.
3434 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3435 entry added. */
3437 static struct xpm_cached_color *
3438 xpm_cache_color (f, color_name, color, bucket)
3439 struct frame *f;
3440 char *color_name;
3441 XColor *color;
3442 int bucket;
3444 size_t nbytes;
3445 struct xpm_cached_color *p;
3447 if (bucket < 0)
3448 bucket = xpm_color_bucket (color_name);
3450 nbytes = sizeof *p + strlen (color_name);
3451 p = (struct xpm_cached_color *) xmalloc (nbytes);
3452 strcpy (p->name, color_name);
3453 p->color = *color;
3454 p->next = xpm_color_cache[bucket];
3455 xpm_color_cache[bucket] = p;
3456 return p;
3459 /* Look up color COLOR_NAME for frame F in the color cache. If found,
3460 return the cached definition in *COLOR. Otherwise, make a new
3461 entry in the cache and allocate the color. Value is zero if color
3462 allocation failed. */
3464 static int
3465 xpm_lookup_color (f, color_name, color)
3466 struct frame *f;
3467 char *color_name;
3468 XColor *color;
3470 struct xpm_cached_color *p;
3471 int h = xpm_color_bucket (color_name);
3473 for (p = xpm_color_cache[h]; p; p = p->next)
3474 if (strcmp (p->name, color_name) == 0)
3475 break;
3477 if (p != NULL)
3478 *color = p->color;
3479 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3480 color_name, color))
3482 color->pixel = lookup_rgb_color (f, color->red, color->green,
3483 color->blue);
3484 p = xpm_cache_color (f, color_name, color, h);
3486 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3487 with transparency, and it's useful. */
3488 else if (strcmp ("opaque", color_name) == 0)
3490 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3491 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3492 p = xpm_cache_color (f, color_name, color, h);
3495 return p != NULL;
3499 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3500 CLOSURE is a pointer to the frame on which we allocate the
3501 color. Return in *COLOR the allocated color. Value is non-zero
3502 if successful. */
3504 static int
3505 xpm_alloc_color (dpy, cmap, color_name, color, closure)
3506 Display *dpy;
3507 Colormap cmap;
3508 char *color_name;
3509 XColor *color;
3510 void *closure;
3512 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3516 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3517 is a pointer to the frame on which we allocate the color. Value is
3518 non-zero if successful. */
3520 static int
3521 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3522 Display *dpy;
3523 Colormap cmap;
3524 Pixel *pixels;
3525 int npixels;
3526 void *closure;
3528 return 1;
3531 #endif /* ALLOC_XPM_COLORS */
3534 #ifdef HAVE_NTGUI
3536 /* XPM library details. */
3538 DEF_IMGLIB_FN (XpmFreeAttributes);
3539 DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3540 DEF_IMGLIB_FN (XpmReadFileToImage);
3541 DEF_IMGLIB_FN (XImageFree);
3543 static int
3544 init_xpm_functions (Lisp_Object libraries)
3546 HMODULE library;
3548 if (!(library = w32_delayed_load (libraries, Qxpm)))
3549 return 0;
3551 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3552 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3553 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3554 LOAD_IMGLIB_FN (library, XImageFree);
3555 return 1;
3558 #endif /* HAVE_NTGUI */
3561 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3562 for XPM images. Such a list must consist of conses whose car and
3563 cdr are strings. */
3565 static int
3566 xpm_valid_color_symbols_p (color_symbols)
3567 Lisp_Object color_symbols;
3569 while (CONSP (color_symbols))
3571 Lisp_Object sym = XCAR (color_symbols);
3572 if (!CONSP (sym)
3573 || !STRINGP (XCAR (sym))
3574 || !STRINGP (XCDR (sym)))
3575 break;
3576 color_symbols = XCDR (color_symbols);
3579 return NILP (color_symbols);
3583 /* Value is non-zero if OBJECT is a valid XPM image specification. */
3585 static int
3586 xpm_image_p (object)
3587 Lisp_Object object;
3589 struct image_keyword fmt[XPM_LAST];
3590 bcopy (xpm_format, fmt, sizeof fmt);
3591 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3592 /* Either `:file' or `:data' must be present. */
3593 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3594 /* Either no `:color-symbols' or it's a list of conses
3595 whose car and cdr are strings. */
3596 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3597 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3600 #endif /* HAVE_XPM || MAC_OS */
3602 /* Load image IMG which will be displayed on frame F. Value is
3603 non-zero if successful. */
3605 #ifdef HAVE_XPM
3607 static int
3608 xpm_load (f, img)
3609 struct frame *f;
3610 struct image *img;
3612 int rc;
3613 XpmAttributes attrs;
3614 Lisp_Object specified_file, color_symbols;
3615 #ifdef HAVE_NTGUI
3616 HDC hdc;
3617 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3618 #endif /* HAVE_NTGUI */
3620 /* Configure the XPM lib. Use the visual of frame F. Allocate
3621 close colors. Return colors allocated. */
3622 bzero (&attrs, sizeof attrs);
3624 #ifndef HAVE_NTGUI
3625 attrs.visual = FRAME_X_VISUAL (f);
3626 attrs.colormap = FRAME_X_COLORMAP (f);
3627 attrs.valuemask |= XpmVisual;
3628 attrs.valuemask |= XpmColormap;
3629 #endif /* HAVE_NTGUI */
3631 #ifdef ALLOC_XPM_COLORS
3632 /* Allocate colors with our own functions which handle
3633 failing color allocation more gracefully. */
3634 attrs.color_closure = f;
3635 attrs.alloc_color = xpm_alloc_color;
3636 attrs.free_colors = xpm_free_colors;
3637 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3638 #else /* not ALLOC_XPM_COLORS */
3639 /* Let the XPM lib allocate colors. */
3640 attrs.valuemask |= XpmReturnAllocPixels;
3641 #ifdef XpmAllocCloseColors
3642 attrs.alloc_close_colors = 1;
3643 attrs.valuemask |= XpmAllocCloseColors;
3644 #else /* not XpmAllocCloseColors */
3645 attrs.closeness = 600;
3646 attrs.valuemask |= XpmCloseness;
3647 #endif /* not XpmAllocCloseColors */
3648 #endif /* ALLOC_XPM_COLORS */
3650 /* If image specification contains symbolic color definitions, add
3651 these to `attrs'. */
3652 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3653 if (CONSP (color_symbols))
3655 Lisp_Object tail;
3656 XpmColorSymbol *xpm_syms;
3657 int i, size;
3659 attrs.valuemask |= XpmColorSymbols;
3661 /* Count number of symbols. */
3662 attrs.numsymbols = 0;
3663 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3664 ++attrs.numsymbols;
3666 /* Allocate an XpmColorSymbol array. */
3667 size = attrs.numsymbols * sizeof *xpm_syms;
3668 xpm_syms = (XpmColorSymbol *) alloca (size);
3669 bzero (xpm_syms, size);
3670 attrs.colorsymbols = xpm_syms;
3672 /* Fill the color symbol array. */
3673 for (tail = color_symbols, i = 0;
3674 CONSP (tail);
3675 ++i, tail = XCDR (tail))
3677 Lisp_Object name = XCAR (XCAR (tail));
3678 Lisp_Object color = XCDR (XCAR (tail));
3679 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3680 strcpy (xpm_syms[i].name, SDATA (name));
3681 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3682 strcpy (xpm_syms[i].value, SDATA (color));
3686 /* Create a pixmap for the image, either from a file, or from a
3687 string buffer containing data in the same format as an XPM file. */
3688 #ifdef ALLOC_XPM_COLORS
3689 xpm_init_color_cache (f, &attrs);
3690 #endif
3692 specified_file = image_spec_value (img->spec, QCfile, NULL);
3694 #ifdef HAVE_NTGUI
3696 HDC frame_dc = get_frame_dc (f);
3697 hdc = CreateCompatibleDC (frame_dc);
3698 release_frame_dc (f, frame_dc);
3700 #endif /* HAVE_NTGUI */
3702 if (STRINGP (specified_file))
3704 Lisp_Object file = x_find_image_file (specified_file);
3705 if (!STRINGP (file))
3707 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3708 return 0;
3711 #ifdef HAVE_NTGUI
3712 /* XpmReadFileToPixmap is not available in the Windows port of
3713 libxpm. But XpmReadFileToImage almost does what we want. */
3714 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3715 &xpm_image, &xpm_mask,
3716 &attrs);
3717 #else
3718 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3719 SDATA (file), &img->pixmap, &img->mask,
3720 &attrs);
3721 #endif /* HAVE_NTGUI */
3723 else
3725 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3726 #ifdef HAVE_NTGUI
3727 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3728 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3729 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3730 &xpm_image, &xpm_mask,
3731 &attrs);
3732 #else
3733 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3734 SDATA (buffer),
3735 &img->pixmap, &img->mask,
3736 &attrs);
3737 #endif /* HAVE_NTGUI */
3740 if (rc == XpmSuccess)
3742 #if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3743 img->colors = colors_in_color_table (&img->ncolors);
3744 #else /* not ALLOC_XPM_COLORS */
3745 int i;
3747 #ifdef HAVE_NTGUI
3748 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3749 plus some duplicate attributes. */
3750 if (xpm_image && xpm_image->bitmap)
3752 img->pixmap = xpm_image->bitmap;
3753 /* XImageFree in libXpm frees XImage struct without destroying
3754 the bitmap, which is what we want. */
3755 fn_XImageFree (xpm_image);
3757 if (xpm_mask && xpm_mask->bitmap)
3759 /* The mask appears to be inverted compared with what we expect.
3760 TODO: invert our expectations. See other places where we
3761 have to invert bits because our idea of masks is backwards. */
3762 HGDIOBJ old_obj;
3763 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3765 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3766 SelectObject (hdc, old_obj);
3768 img->mask = xpm_mask->bitmap;
3769 fn_XImageFree (xpm_mask);
3770 DeleteDC (hdc);
3773 DeleteDC (hdc);
3774 #endif /* HAVE_NTGUI */
3776 /* Remember allocated colors. */
3777 img->ncolors = attrs.nalloc_pixels;
3778 img->colors = (unsigned long *) xmalloc (img->ncolors
3779 * sizeof *img->colors);
3780 for (i = 0; i < attrs.nalloc_pixels; ++i)
3782 img->colors[i] = attrs.alloc_pixels[i];
3783 #ifdef DEBUG_X_COLORS
3784 register_color (img->colors[i]);
3785 #endif
3787 #endif /* not ALLOC_XPM_COLORS */
3789 img->width = attrs.width;
3790 img->height = attrs.height;
3791 xassert (img->width > 0 && img->height > 0);
3793 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3794 #ifdef HAVE_NTGUI
3795 fn_XpmFreeAttributes (&attrs);
3796 #else
3797 XpmFreeAttributes (&attrs);
3798 #endif /* HAVE_NTGUI */
3800 else
3802 #ifdef HAVE_NTGUI
3803 DeleteDC (hdc);
3804 #endif /* HAVE_NTGUI */
3806 switch (rc)
3808 case XpmOpenFailed:
3809 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3810 break;
3812 case XpmFileInvalid:
3813 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3814 break;
3816 case XpmNoMemory:
3817 image_error ("Out of memory (%s)", img->spec, Qnil);
3818 break;
3820 case XpmColorFailed:
3821 image_error ("Color allocation error (%s)", img->spec, Qnil);
3822 break;
3824 default:
3825 image_error ("Unknown error (%s)", img->spec, Qnil);
3826 break;
3830 #ifdef ALLOC_XPM_COLORS
3831 xpm_free_color_cache ();
3832 #endif
3833 return rc == XpmSuccess;
3836 #endif /* HAVE_XPM */
3838 #ifdef MAC_OS
3840 /* XPM support functions for Mac OS where libxpm is not available.
3841 Only XPM version 3 (without any extensions) is supported. */
3843 static int xpm_scan P_ ((unsigned char **, unsigned char *,
3844 unsigned char **, int *));
3845 static Lisp_Object xpm_make_color_table_v
3846 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3847 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3848 static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *,
3849 int, Lisp_Object));
3850 static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
3851 unsigned char *, int));
3852 static Lisp_Object xpm_make_color_table_h
3853 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3854 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3855 static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *,
3856 int, Lisp_Object));
3857 static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
3858 unsigned char *, int));
3859 static int xpm_str_to_color_key P_ ((char *));
3860 static int xpm_load_image P_ ((struct frame *, struct image *,
3861 unsigned char *, unsigned char *));
3863 /* Tokens returned from xpm_scan. */
3865 enum xpm_token
3867 XPM_TK_IDENT = 256,
3868 XPM_TK_STRING,
3869 XPM_TK_EOF
3872 /* Scan an XPM data and return a character (< 256) or a token defined
3873 by enum xpm_token above. *S and END are the start (inclusive) and
3874 the end (exclusive) addresses of the data, respectively. Advance
3875 *S while scanning. If token is either XPM_TK_IDENT or
3876 XPM_TK_STRING, *BEG and *LEN are set to the start address and the
3877 length of the corresponding token, respectively. */
3879 static int
3880 xpm_scan (s, end, beg, len)
3881 unsigned char **s, *end, **beg;
3882 int *len;
3884 int c;
3886 while (*s < end)
3888 /* Skip white-space. */
3889 while (*s < end && (c = *(*s)++, isspace (c)))
3892 /* gnus-pointer.xpm uses '-' in its identifier.
3893 sb-dir-plus.xpm uses '+' in its identifier. */
3894 if (isalpha (c) || c == '_' || c == '-' || c == '+')
3896 *beg = *s - 1;
3897 while (*s < end &&
3898 (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
3899 ++*s;
3900 *len = *s - *beg;
3901 return XPM_TK_IDENT;
3903 else if (c == '"')
3905 *beg = *s;
3906 while (*s < end && **s != '"')
3907 ++*s;
3908 *len = *s - *beg;
3909 if (*s < end)
3910 ++*s;
3911 return XPM_TK_STRING;
3913 else if (c == '/')
3915 if (*s < end && **s == '*')
3917 /* C-style comment. */
3918 ++*s;
3921 while (*s < end && *(*s)++ != '*')
3924 while (*s < end && **s != '/');
3925 if (*s < end)
3926 ++*s;
3928 else
3929 return c;
3931 else
3932 return c;
3935 return XPM_TK_EOF;
3938 /* Functions for color table lookup in XPM data. A Key is a string
3939 specifying the color of each pixel in XPM data. A value is either
3940 an integer that specifies a pixel color, Qt that specifies
3941 transparency, or Qnil for the unspecified color. If the length of
3942 the key string is one, a vector is used as a table. Otherwise, a
3943 hash table is used. */
3945 static Lisp_Object
3946 xpm_make_color_table_v (put_func, get_func)
3947 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3948 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3950 *put_func = xpm_put_color_table_v;
3951 *get_func = xpm_get_color_table_v;
3952 return Fmake_vector (make_number (256), Qnil);
3955 static void
3956 xpm_put_color_table_v (color_table, chars_start, chars_len, color)
3957 Lisp_Object color_table;
3958 unsigned char *chars_start;
3959 int chars_len;
3960 Lisp_Object color;
3962 XVECTOR (color_table)->contents[*chars_start] = color;
3965 static Lisp_Object
3966 xpm_get_color_table_v (color_table, chars_start, chars_len)
3967 Lisp_Object color_table;
3968 unsigned char *chars_start;
3969 int chars_len;
3971 return XVECTOR (color_table)->contents[*chars_start];
3974 static Lisp_Object
3975 xpm_make_color_table_h (put_func, get_func)
3976 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3977 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3979 *put_func = xpm_put_color_table_h;
3980 *get_func = xpm_get_color_table_h;
3981 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
3982 make_float (DEFAULT_REHASH_SIZE),
3983 make_float (DEFAULT_REHASH_THRESHOLD),
3984 Qnil, Qnil, Qnil);
3987 static void
3988 xpm_put_color_table_h (color_table, chars_start, chars_len, color)
3989 Lisp_Object color_table;
3990 unsigned char *chars_start;
3991 int chars_len;
3992 Lisp_Object color;
3994 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
3995 unsigned hash_code;
3996 Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
3998 hash_lookup (table, chars, &hash_code);
3999 hash_put (table, chars, color, hash_code);
4002 static Lisp_Object
4003 xpm_get_color_table_h (color_table, chars_start, chars_len)
4004 Lisp_Object color_table;
4005 unsigned char *chars_start;
4006 int chars_len;
4008 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4009 int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
4010 NULL);
4012 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
4015 enum xpm_color_key {
4016 XPM_COLOR_KEY_S,
4017 XPM_COLOR_KEY_M,
4018 XPM_COLOR_KEY_G4,
4019 XPM_COLOR_KEY_G,
4020 XPM_COLOR_KEY_C
4023 static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
4025 static int
4026 xpm_str_to_color_key (s)
4027 char *s;
4029 int i;
4031 for (i = 0;
4032 i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
4033 i++)
4034 if (strcmp (xpm_color_key_strings[i], s) == 0)
4035 return i;
4036 return -1;
4039 static int
4040 xpm_load_image (f, img, contents, end)
4041 struct frame *f;
4042 struct image *img;
4043 unsigned char *contents, *end;
4045 unsigned char *s = contents, *beg, *str;
4046 unsigned char buffer[BUFSIZ];
4047 int width, height, x, y;
4048 int num_colors, chars_per_pixel;
4049 int len, LA1;
4050 void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object);
4051 Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int);
4052 Lisp_Object frame, color_symbols, color_table;
4053 int best_key, have_mask = 0;
4054 XImagePtr ximg = NULL, mask_img = NULL;
4056 #define match() \
4057 LA1 = xpm_scan (&s, end, &beg, &len)
4059 #define expect(TOKEN) \
4060 if (LA1 != (TOKEN)) \
4061 goto failure; \
4062 else \
4063 match ()
4065 #define expect_ident(IDENT) \
4066 if (LA1 == XPM_TK_IDENT \
4067 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
4068 match (); \
4069 else \
4070 goto failure
4072 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
4073 goto failure;
4074 s += 9;
4075 match();
4076 expect_ident ("static");
4077 expect_ident ("char");
4078 expect ('*');
4079 expect (XPM_TK_IDENT);
4080 expect ('[');
4081 expect (']');
4082 expect ('=');
4083 expect ('{');
4084 expect (XPM_TK_STRING);
4085 if (len >= BUFSIZ)
4086 goto failure;
4087 memcpy (buffer, beg, len);
4088 buffer[len] = '\0';
4089 if (sscanf (buffer, "%d %d %d %d", &width, &height,
4090 &num_colors, &chars_per_pixel) != 4
4091 || width <= 0 || height <= 0
4092 || num_colors <= 0 || chars_per_pixel <= 0)
4093 goto failure;
4094 expect (',');
4096 XSETFRAME (frame, f);
4097 if (!NILP (Fxw_display_color_p (frame)))
4098 best_key = XPM_COLOR_KEY_C;
4099 else if (!NILP (Fx_display_grayscale_p (frame)))
4100 best_key = (XFASTINT (Fx_display_planes (frame)) > 2
4101 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
4102 else
4103 best_key = XPM_COLOR_KEY_M;
4105 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
4106 if (chars_per_pixel == 1)
4107 color_table = xpm_make_color_table_v (&put_color_table,
4108 &get_color_table);
4109 else
4110 color_table = xpm_make_color_table_h (&put_color_table,
4111 &get_color_table);
4113 while (num_colors-- > 0)
4115 unsigned char *color, *max_color;
4116 int key, next_key, max_key = 0;
4117 Lisp_Object symbol_color = Qnil, color_val;
4118 XColor cdef;
4120 expect (XPM_TK_STRING);
4121 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
4122 goto failure;
4123 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
4124 buffer[len - chars_per_pixel] = '\0';
4126 str = strtok (buffer, " \t");
4127 if (str == NULL)
4128 goto failure;
4129 key = xpm_str_to_color_key (str);
4130 if (key < 0)
4131 goto failure;
4134 color = strtok (NULL, " \t");
4135 if (color == NULL)
4136 goto failure;
4138 while (str = strtok (NULL, " \t"))
4140 next_key = xpm_str_to_color_key (str);
4141 if (next_key >= 0)
4142 break;
4143 color[strlen (color)] = ' ';
4146 if (key == XPM_COLOR_KEY_S)
4148 if (NILP (symbol_color))
4149 symbol_color = build_string (color);
4151 else if (max_key < key && key <= best_key)
4153 max_key = key;
4154 max_color = color;
4156 key = next_key;
4158 while (str);
4160 color_val = Qnil;
4161 if (!NILP (color_symbols) && !NILP (symbol_color))
4163 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
4165 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
4166 if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0)
4167 color_val = Qt;
4168 else if (x_defined_color (f, SDATA (XCDR (specified_color)),
4169 &cdef, 0))
4170 color_val = make_number (cdef.pixel);
4172 if (NILP (color_val) && max_key > 0)
4173 if (xstricmp (max_color, "None") == 0)
4174 color_val = Qt;
4175 else if (x_defined_color (f, max_color, &cdef, 0))
4176 color_val = make_number (cdef.pixel);
4177 if (!NILP (color_val))
4178 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
4180 expect (',');
4183 if (!x_create_x_image_and_pixmap (f, width, height, 0,
4184 &ximg, &img->pixmap)
4185 || !x_create_x_image_and_pixmap (f, width, height, 1,
4186 &mask_img, &img->mask))
4188 image_error ("Out of memory (%s)", img->spec, Qnil);
4189 goto error;
4192 for (y = 0; y < height; y++)
4194 expect (XPM_TK_STRING);
4195 str = beg;
4196 if (len < width * chars_per_pixel)
4197 goto failure;
4198 for (x = 0; x < width; x++, str += chars_per_pixel)
4200 Lisp_Object color_val =
4201 (*get_color_table) (color_table, str, chars_per_pixel);
4203 XPutPixel (ximg, x, y,
4204 (INTEGERP (color_val) ? XINT (color_val)
4205 : FRAME_FOREGROUND_PIXEL (f)));
4206 XPutPixel (mask_img, x, y,
4207 (!EQ (color_val, Qt) ? PIX_MASK_DRAW (f)
4208 : (have_mask = 1, PIX_MASK_RETAIN (f))));
4210 if (y + 1 < height)
4211 expect (',');
4214 img->width = width;
4215 img->height = height;
4217 x_put_x_image (f, ximg, img->pixmap, width, height);
4218 x_destroy_x_image (ximg);
4219 if (have_mask)
4221 x_put_x_image (f, mask_img, img->mask, width, height);
4222 x_destroy_x_image (mask_img);
4224 else
4226 x_destroy_x_image (mask_img);
4227 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4228 img->mask = NO_PIXMAP;
4231 return 1;
4233 failure:
4234 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
4235 error:
4236 x_destroy_x_image (ximg);
4237 x_destroy_x_image (mask_img);
4238 x_clear_image (f, img);
4239 return 0;
4241 #undef match
4242 #undef expect
4243 #undef expect_ident
4246 static int
4247 xpm_load (f, img)
4248 struct frame *f;
4249 struct image *img;
4251 int success_p = 0;
4252 Lisp_Object file_name;
4254 /* If IMG->spec specifies a file name, create a non-file spec from it. */
4255 file_name = image_spec_value (img->spec, QCfile, NULL);
4256 if (STRINGP (file_name))
4258 Lisp_Object file;
4259 unsigned char *contents;
4260 int size;
4261 struct gcpro gcpro1;
4263 file = x_find_image_file (file_name);
4264 GCPRO1 (file);
4265 if (!STRINGP (file))
4267 image_error ("Cannot find image file `%s'", file_name, Qnil);
4268 UNGCPRO;
4269 return 0;
4272 contents = slurp_file (SDATA (file), &size);
4273 if (contents == NULL)
4275 image_error ("Error loading XPM image `%s'", img->spec, Qnil);
4276 UNGCPRO;
4277 return 0;
4280 success_p = xpm_load_image (f, img, contents, contents + size);
4281 xfree (contents);
4282 UNGCPRO;
4284 else
4286 Lisp_Object data;
4288 data = image_spec_value (img->spec, QCdata, NULL);
4289 success_p = xpm_load_image (f, img, SDATA (data),
4290 SDATA (data) + SBYTES (data));
4293 return success_p;
4296 #endif /* MAC_OS */
4300 /***********************************************************************
4301 Color table
4302 ***********************************************************************/
4304 #ifdef COLOR_TABLE_SUPPORT
4306 /* An entry in the color table mapping an RGB color to a pixel color. */
4308 struct ct_color
4310 int r, g, b;
4311 unsigned long pixel;
4313 /* Next in color table collision list. */
4314 struct ct_color *next;
4317 /* The bucket vector size to use. Must be prime. */
4319 #define CT_SIZE 101
4321 /* Value is a hash of the RGB color given by R, G, and B. */
4323 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
4325 /* The color hash table. */
4327 struct ct_color **ct_table;
4329 /* Number of entries in the color table. */
4331 int ct_colors_allocated;
4333 /* Initialize the color table. */
4335 static void
4336 init_color_table ()
4338 int size = CT_SIZE * sizeof (*ct_table);
4339 ct_table = (struct ct_color **) xmalloc (size);
4340 bzero (ct_table, size);
4341 ct_colors_allocated = 0;
4345 /* Free memory associated with the color table. */
4347 static void
4348 free_color_table ()
4350 int i;
4351 struct ct_color *p, *next;
4353 for (i = 0; i < CT_SIZE; ++i)
4354 for (p = ct_table[i]; p; p = next)
4356 next = p->next;
4357 xfree (p);
4360 xfree (ct_table);
4361 ct_table = NULL;
4365 /* Value is a pixel color for RGB color R, G, B on frame F. If an
4366 entry for that color already is in the color table, return the
4367 pixel color of that entry. Otherwise, allocate a new color for R,
4368 G, B, and make an entry in the color table. */
4370 static unsigned long
4371 lookup_rgb_color (f, r, g, b)
4372 struct frame *f;
4373 int r, g, b;
4375 unsigned hash = CT_HASH_RGB (r, g, b);
4376 int i = hash % CT_SIZE;
4377 struct ct_color *p;
4378 Display_Info *dpyinfo;
4380 /* Handle TrueColor visuals specially, which improves performance by
4381 two orders of magnitude. Freeing colors on TrueColor visuals is
4382 a nop, and pixel colors specify RGB values directly. See also
4383 the Xlib spec, chapter 3.1. */
4384 dpyinfo = FRAME_X_DISPLAY_INFO (f);
4385 if (dpyinfo->red_bits > 0)
4387 unsigned long pr, pg, pb;
4389 /* Apply gamma-correction like normal color allocation does. */
4390 if (f->gamma)
4392 XColor color;
4393 color.red = r, color.green = g, color.blue = b;
4394 gamma_correct (f, &color);
4395 r = color.red, g = color.green, b = color.blue;
4398 /* Scale down RGB values to the visual's bits per RGB, and shift
4399 them to the right position in the pixel color. Note that the
4400 original RGB values are 16-bit values, as usual in X. */
4401 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
4402 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
4403 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
4405 /* Assemble the pixel color. */
4406 return pr | pg | pb;
4409 for (p = ct_table[i]; p; p = p->next)
4410 if (p->r == r && p->g == g && p->b == b)
4411 break;
4413 if (p == NULL)
4416 #ifdef HAVE_X_WINDOWS
4417 XColor color;
4418 Colormap cmap;
4419 int rc;
4421 color.red = r;
4422 color.green = g;
4423 color.blue = b;
4425 cmap = FRAME_X_COLORMAP (f);
4426 rc = x_alloc_nearest_color (f, cmap, &color);
4427 if (rc)
4429 ++ct_colors_allocated;
4430 p = (struct ct_color *) xmalloc (sizeof *p);
4431 p->r = r;
4432 p->g = g;
4433 p->b = b;
4434 p->pixel = color.pixel;
4435 p->next = ct_table[i];
4436 ct_table[i] = p;
4438 else
4439 return FRAME_FOREGROUND_PIXEL (f);
4441 #else
4442 COLORREF color;
4443 #ifdef HAVE_NTGUI
4444 color = PALETTERGB (r, g, b);
4445 #else
4446 color = RGB_TO_ULONG (r, g, b);
4447 #endif /* HAVE_NTGUI */
4448 ++ct_colors_allocated;
4449 p = (struct ct_color *) xmalloc (sizeof *p);
4450 p->r = r;
4451 p->g = g;
4452 p->b = b;
4453 p->pixel = color;
4454 p->next = ct_table[i];
4455 ct_table[i] = p;
4456 #endif /* HAVE_X_WINDOWS */
4460 return p->pixel;
4464 /* Look up pixel color PIXEL which is used on frame F in the color
4465 table. If not already present, allocate it. Value is PIXEL. */
4467 static unsigned long
4468 lookup_pixel_color (f, pixel)
4469 struct frame *f;
4470 unsigned long pixel;
4472 int i = pixel % CT_SIZE;
4473 struct ct_color *p;
4475 for (p = ct_table[i]; p; p = p->next)
4476 if (p->pixel == pixel)
4477 break;
4479 if (p == NULL)
4481 XColor color;
4482 Colormap cmap;
4483 int rc;
4485 #ifdef HAVE_X_WINDOWS
4486 cmap = FRAME_X_COLORMAP (f);
4487 color.pixel = pixel;
4488 x_query_color (f, &color);
4489 rc = x_alloc_nearest_color (f, cmap, &color);
4490 #else
4491 BLOCK_INPUT;
4492 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
4493 color.pixel = pixel;
4494 XQueryColor (NULL, cmap, &color);
4495 rc = x_alloc_nearest_color (f, cmap, &color);
4496 UNBLOCK_INPUT;
4497 #endif /* HAVE_X_WINDOWS */
4499 if (rc)
4501 ++ct_colors_allocated;
4503 p = (struct ct_color *) xmalloc (sizeof *p);
4504 p->r = color.red;
4505 p->g = color.green;
4506 p->b = color.blue;
4507 p->pixel = pixel;
4508 p->next = ct_table[i];
4509 ct_table[i] = p;
4511 else
4512 return FRAME_FOREGROUND_PIXEL (f);
4514 return p->pixel;
4518 /* Value is a vector of all pixel colors contained in the color table,
4519 allocated via xmalloc. Set *N to the number of colors. */
4521 static unsigned long *
4522 colors_in_color_table (n)
4523 int *n;
4525 int i, j;
4526 struct ct_color *p;
4527 unsigned long *colors;
4529 if (ct_colors_allocated == 0)
4531 *n = 0;
4532 colors = NULL;
4534 else
4536 colors = (unsigned long *) xmalloc (ct_colors_allocated
4537 * sizeof *colors);
4538 *n = ct_colors_allocated;
4540 for (i = j = 0; i < CT_SIZE; ++i)
4541 for (p = ct_table[i]; p; p = p->next)
4542 colors[j++] = p->pixel;
4545 return colors;
4548 #else /* COLOR_TABLE_SUPPORT */
4550 static unsigned long
4551 lookup_rgb_color (f, r, g, b)
4552 struct frame *f;
4553 int r, g, b;
4555 unsigned long pixel;
4557 #ifdef MAC_OS
4558 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4559 gamma_correct (f, &pixel);
4560 #endif /* MAC_OS */
4562 #ifdef HAVE_NTGUI
4563 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4564 #endif /* HAVE_NTGUI */
4566 return pixel;
4569 static void
4570 init_color_table ()
4573 #endif /* COLOR_TABLE_SUPPORT */
4576 /***********************************************************************
4577 Algorithms
4578 ***********************************************************************/
4580 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4581 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4582 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4584 #ifdef HAVE_NTGUI
4585 static void XPutPixel (XImagePtr , int, int, COLORREF);
4586 #endif /* HAVE_NTGUI */
4588 /* Non-zero means draw a cross on images having `:conversion
4589 disabled'. */
4591 int cross_disabled_images;
4593 /* Edge detection matrices for different edge-detection
4594 strategies. */
4596 static int emboss_matrix[9] = {
4597 /* x - 1 x x + 1 */
4598 2, -1, 0, /* y - 1 */
4599 -1, 0, 1, /* y */
4600 0, 1, -2 /* y + 1 */
4603 static int laplace_matrix[9] = {
4604 /* x - 1 x x + 1 */
4605 1, 0, 0, /* y - 1 */
4606 0, 0, 0, /* y */
4607 0, 0, -1 /* y + 1 */
4610 /* Value is the intensity of the color whose red/green/blue values
4611 are R, G, and B. */
4613 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4616 /* On frame F, return an array of XColor structures describing image
4617 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4618 non-zero means also fill the red/green/blue members of the XColor
4619 structures. Value is a pointer to the array of XColors structures,
4620 allocated with xmalloc; it must be freed by the caller. */
4622 static XColor *
4623 x_to_xcolors (f, img, rgb_p)
4624 struct frame *f;
4625 struct image *img;
4626 int rgb_p;
4628 int x, y;
4629 XColor *colors, *p;
4630 XImagePtr_or_DC ximg;
4631 #ifdef HAVE_NTGUI
4632 HDC hdc;
4633 HGDIOBJ prev;
4634 #endif /* HAVE_NTGUI */
4636 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4638 #ifndef HAVE_NTGUI
4639 /* Get the X image IMG->pixmap. */
4640 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4641 0, 0, img->width, img->height, ~0, ZPixmap);
4642 #else
4643 /* Load the image into a memory device context. */
4644 hdc = get_frame_dc (f);
4645 ximg = CreateCompatibleDC (hdc);
4646 release_frame_dc (f, hdc);
4647 prev = SelectObject (ximg, img->pixmap);
4648 #endif /* HAVE_NTGUI */
4650 /* Fill the `pixel' members of the XColor array. I wished there
4651 were an easy and portable way to circumvent XGetPixel. */
4652 p = colors;
4653 for (y = 0; y < img->height; ++y)
4655 XColor *row = p;
4657 #ifdef HAVE_X_WINDOWS
4658 for (x = 0; x < img->width; ++x, ++p)
4659 p->pixel = XGetPixel (ximg, x, y);
4660 if (rgb_p)
4661 x_query_colors (f, row, img->width);
4663 #else
4665 for (x = 0; x < img->width; ++x, ++p)
4667 /* W32_TODO: palette support needed here? */
4668 p->pixel = GET_PIXEL (ximg, x, y);
4669 if (rgb_p)
4671 #ifdef MAC_OS
4672 p->red = RED16_FROM_ULONG (p->pixel);
4673 p->green = GREEN16_FROM_ULONG (p->pixel);
4674 p->blue = BLUE16_FROM_ULONG (p->pixel);
4675 #endif /* MAC_OS */
4676 #ifdef HAVE_NTGUI
4677 p->red = 256 * GetRValue (p->pixel);
4678 p->green = 256 * GetGValue (p->pixel);
4679 p->blue = 256 * GetBValue (p->pixel);
4680 #endif /* HAVE_NTGUI */
4683 #endif /* HAVE_X_WINDOWS */
4686 Destroy_Image (ximg, prev);
4688 return colors;
4691 #ifdef HAVE_NTGUI
4693 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4694 created with CreateDIBSection, with the pointer to the bit values
4695 stored in ximg->data. */
4697 static void XPutPixel (ximg, x, y, color)
4698 XImagePtr ximg;
4699 int x, y;
4700 COLORREF color;
4702 int width = ximg->info.bmiHeader.biWidth;
4703 int height = ximg->info.bmiHeader.biHeight;
4704 unsigned char * pixel;
4706 /* True color images. */
4707 if (ximg->info.bmiHeader.biBitCount == 24)
4709 int rowbytes = width * 3;
4710 /* Ensure scanlines are aligned on 4 byte boundaries. */
4711 if (rowbytes % 4)
4712 rowbytes += 4 - (rowbytes % 4);
4714 pixel = ximg->data + y * rowbytes + x * 3;
4715 /* Windows bitmaps are in BGR order. */
4716 *pixel = GetBValue (color);
4717 *(pixel + 1) = GetGValue (color);
4718 *(pixel + 2) = GetRValue (color);
4720 /* Monochrome images. */
4721 else if (ximg->info.bmiHeader.biBitCount == 1)
4723 int rowbytes = width / 8;
4724 /* Ensure scanlines are aligned on 4 byte boundaries. */
4725 if (rowbytes % 4)
4726 rowbytes += 4 - (rowbytes % 4);
4727 pixel = ximg->data + y * rowbytes + x / 8;
4728 /* Filter out palette info. */
4729 if (color & 0x00ffffff)
4730 *pixel = *pixel | (1 << x % 8);
4731 else
4732 *pixel = *pixel & ~(1 << x % 8);
4734 else
4735 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4738 #endif /* HAVE_NTGUI */
4740 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
4741 RGB members are set. F is the frame on which this all happens.
4742 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4744 static void
4745 x_from_xcolors (f, img, colors)
4746 struct frame *f;
4747 struct image *img;
4748 XColor *colors;
4750 int x, y;
4751 XImagePtr oimg;
4752 Pixmap pixmap;
4753 XColor *p;
4755 init_color_table ();
4757 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4758 &oimg, &pixmap);
4759 p = colors;
4760 for (y = 0; y < img->height; ++y)
4761 for (x = 0; x < img->width; ++x, ++p)
4763 unsigned long pixel;
4764 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4765 XPutPixel (oimg, x, y, pixel);
4768 xfree (colors);
4769 x_clear_image_1 (f, img, 1, 0, 1);
4771 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4772 x_destroy_x_image (oimg);
4773 img->pixmap = pixmap;
4774 #ifdef COLOR_TABLE_SUPPORT
4775 img->colors = colors_in_color_table (&img->ncolors);
4776 free_color_table ();
4777 #endif /* COLOR_TABLE_SUPPORT */
4781 /* On frame F, perform edge-detection on image IMG.
4783 MATRIX is a nine-element array specifying the transformation
4784 matrix. See emboss_matrix for an example.
4786 COLOR_ADJUST is a color adjustment added to each pixel of the
4787 outgoing image. */
4789 static void
4790 x_detect_edges (f, img, matrix, color_adjust)
4791 struct frame *f;
4792 struct image *img;
4793 int matrix[9], color_adjust;
4795 XColor *colors = x_to_xcolors (f, img, 1);
4796 XColor *new, *p;
4797 int x, y, i, sum;
4799 for (i = sum = 0; i < 9; ++i)
4800 sum += abs (matrix[i]);
4802 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4804 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4806 for (y = 0; y < img->height; ++y)
4808 p = COLOR (new, 0, y);
4809 p->red = p->green = p->blue = 0xffff/2;
4810 p = COLOR (new, img->width - 1, y);
4811 p->red = p->green = p->blue = 0xffff/2;
4814 for (x = 1; x < img->width - 1; ++x)
4816 p = COLOR (new, x, 0);
4817 p->red = p->green = p->blue = 0xffff/2;
4818 p = COLOR (new, x, img->height - 1);
4819 p->red = p->green = p->blue = 0xffff/2;
4822 for (y = 1; y < img->height - 1; ++y)
4824 p = COLOR (new, 1, y);
4826 for (x = 1; x < img->width - 1; ++x, ++p)
4828 int r, g, b, y1, x1;
4830 r = g = b = i = 0;
4831 for (y1 = y - 1; y1 < y + 2; ++y1)
4832 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4833 if (matrix[i])
4835 XColor *t = COLOR (colors, x1, y1);
4836 r += matrix[i] * t->red;
4837 g += matrix[i] * t->green;
4838 b += matrix[i] * t->blue;
4841 r = (r / sum + color_adjust) & 0xffff;
4842 g = (g / sum + color_adjust) & 0xffff;
4843 b = (b / sum + color_adjust) & 0xffff;
4844 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4848 xfree (colors);
4849 x_from_xcolors (f, img, new);
4851 #undef COLOR
4855 /* Perform the pre-defined `emboss' edge-detection on image IMG
4856 on frame F. */
4858 static void
4859 x_emboss (f, img)
4860 struct frame *f;
4861 struct image *img;
4863 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4867 /* Transform image IMG which is used on frame F with a Laplace
4868 edge-detection algorithm. The result is an image that can be used
4869 to draw disabled buttons, for example. */
4871 static void
4872 x_laplace (f, img)
4873 struct frame *f;
4874 struct image *img;
4876 x_detect_edges (f, img, laplace_matrix, 45000);
4880 /* Perform edge-detection on image IMG on frame F, with specified
4881 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
4883 MATRIX must be either
4885 - a list of at least 9 numbers in row-major form
4886 - a vector of at least 9 numbers
4888 COLOR_ADJUST nil means use a default; otherwise it must be a
4889 number. */
4891 static void
4892 x_edge_detection (f, img, matrix, color_adjust)
4893 struct frame *f;
4894 struct image *img;
4895 Lisp_Object matrix, color_adjust;
4897 int i = 0;
4898 int trans[9];
4900 if (CONSP (matrix))
4902 for (i = 0;
4903 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
4904 ++i, matrix = XCDR (matrix))
4905 trans[i] = XFLOATINT (XCAR (matrix));
4907 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
4909 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
4910 trans[i] = XFLOATINT (AREF (matrix, i));
4913 if (NILP (color_adjust))
4914 color_adjust = make_number (0xffff / 2);
4916 if (i == 9 && NUMBERP (color_adjust))
4917 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
4921 /* Transform image IMG on frame F so that it looks disabled. */
4923 static void
4924 x_disable_image (f, img)
4925 struct frame *f;
4926 struct image *img;
4928 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4929 #ifdef HAVE_NTGUI
4930 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
4931 #else
4932 int n_planes = dpyinfo->n_planes;
4933 #endif /* HAVE_NTGUI */
4935 if (n_planes >= 2)
4937 /* Color (or grayscale). Convert to gray, and equalize. Just
4938 drawing such images with a stipple can look very odd, so
4939 we're using this method instead. */
4940 XColor *colors = x_to_xcolors (f, img, 1);
4941 XColor *p, *end;
4942 const int h = 15000;
4943 const int l = 30000;
4945 for (p = colors, end = colors + img->width * img->height;
4946 p < end;
4947 ++p)
4949 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
4950 int i2 = (0xffff - h - l) * i / 0xffff + l;
4951 p->red = p->green = p->blue = i2;
4954 x_from_xcolors (f, img, colors);
4957 /* Draw a cross over the disabled image, if we must or if we
4958 should. */
4959 if (n_planes < 2 || cross_disabled_images)
4961 #ifndef HAVE_NTGUI
4962 Display *dpy = FRAME_X_DISPLAY (f);
4963 GC gc;
4965 #ifdef MAC_OS
4966 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
4967 #define MaskForeground(f) PIX_MASK_DRAW (f)
4968 #else
4969 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
4970 #define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4971 #endif
4973 gc = XCreateGC_pixmap (dpy, img->pixmap);
4974 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
4975 XDrawLine (dpy, img->pixmap, gc, 0, 0,
4976 img->width - 1, img->height - 1);
4977 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
4978 img->width - 1, 0);
4979 XFreeGC (dpy, gc);
4981 if (img->mask)
4983 gc = XCreateGC_pixmap (dpy, img->mask);
4984 XSetForeground (dpy, gc, MaskForeground (f));
4985 XDrawLine (dpy, img->mask, gc, 0, 0,
4986 img->width - 1, img->height - 1);
4987 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
4988 img->width - 1, 0);
4989 XFreeGC (dpy, gc);
4991 #else
4992 HDC hdc, bmpdc;
4993 HGDIOBJ prev;
4995 hdc = get_frame_dc (f);
4996 bmpdc = CreateCompatibleDC (hdc);
4997 release_frame_dc (f, hdc);
4999 prev = SelectObject (bmpdc, img->pixmap);
5001 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
5002 MoveToEx (bmpdc, 0, 0, NULL);
5003 LineTo (bmpdc, img->width - 1, img->height - 1);
5004 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5005 LineTo (bmpdc, img->width - 1, 0);
5007 if (img->mask)
5009 SelectObject (bmpdc, img->mask);
5010 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
5011 MoveToEx (bmpdc, 0, 0, NULL);
5012 LineTo (bmpdc, img->width - 1, img->height - 1);
5013 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5014 LineTo (bmpdc, img->width - 1, 0);
5016 SelectObject (bmpdc, prev);
5017 DeleteDC (bmpdc);
5018 #endif /* HAVE_NTGUI */
5023 /* Build a mask for image IMG which is used on frame F. FILE is the
5024 name of an image file, for error messages. HOW determines how to
5025 determine the background color of IMG. If it is a list '(R G B)',
5026 with R, G, and B being integers >= 0, take that as the color of the
5027 background. Otherwise, determine the background color of IMG
5028 heuristically. Value is non-zero if successful. */
5030 static int
5031 x_build_heuristic_mask (f, img, how)
5032 struct frame *f;
5033 struct image *img;
5034 Lisp_Object how;
5036 XImagePtr_or_DC ximg;
5037 #ifndef HAVE_NTGUI
5038 XImagePtr mask_img;
5039 #else
5040 HDC frame_dc;
5041 HGDIOBJ prev;
5042 char *mask_img;
5043 int row_width;
5044 #endif /* HAVE_NTGUI */
5045 int x, y, rc, use_img_background;
5046 unsigned long bg = 0;
5048 if (img->mask)
5050 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
5051 img->mask = NO_PIXMAP;
5052 img->background_transparent_valid = 0;
5055 #ifndef HAVE_NTGUI
5056 /* Create an image and pixmap serving as mask. */
5057 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
5058 &mask_img, &img->mask);
5059 if (!rc)
5060 return 0;
5062 /* Get the X image of IMG->pixmap. */
5063 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
5064 img->width, img->height,
5065 ~0, ZPixmap);
5066 #else
5067 /* Create the bit array serving as mask. */
5068 row_width = (img->width + 7) / 8;
5069 mask_img = xmalloc (row_width * img->height);
5070 bzero (mask_img, row_width * img->height);
5072 /* Create a memory device context for IMG->pixmap. */
5073 frame_dc = get_frame_dc (f);
5074 ximg = CreateCompatibleDC (frame_dc);
5075 release_frame_dc (f, frame_dc);
5076 prev = SelectObject (ximg, img->pixmap);
5077 #endif /* HAVE_NTGUI */
5079 /* Determine the background color of ximg. If HOW is `(R G B)'
5080 take that as color. Otherwise, use the image's background color. */
5081 use_img_background = 1;
5083 if (CONSP (how))
5085 int rgb[3], i;
5087 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
5089 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
5090 how = XCDR (how);
5093 if (i == 3 && NILP (how))
5095 char color_name[30];
5096 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
5097 bg = (
5098 #ifdef HAVE_NTGUI
5099 0x00ffffff & /* Filter out palette info. */
5100 #endif /* HAVE_NTGUI */
5101 x_alloc_image_color (f, img, build_string (color_name), 0));
5102 use_img_background = 0;
5106 if (use_img_background)
5107 bg = four_corners_best (ximg, img->width, img->height);
5109 /* Set all bits in mask_img to 1 whose color in ximg is different
5110 from the background color bg. */
5111 #ifndef HAVE_NTGUI
5112 for (y = 0; y < img->height; ++y)
5113 for (x = 0; x < img->width; ++x)
5114 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
5115 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
5117 /* Fill in the background_transparent field while we have the mask handy. */
5118 image_background_transparent (img, f, mask_img);
5120 /* Put mask_img into img->mask. */
5121 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5122 x_destroy_x_image (mask_img);
5124 #else
5125 for (y = 0; y < img->height; ++y)
5126 for (x = 0; x < img->width; ++x)
5128 COLORREF p = GetPixel (ximg, x, y);
5129 if (p != bg)
5130 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
5133 /* Create the mask image. */
5134 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
5135 mask_img);
5136 /* Fill in the background_transparent field while we have the mask handy. */
5137 SelectObject (ximg, img->mask);
5138 image_background_transparent (img, f, ximg);
5140 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
5141 xfree (mask_img);
5142 #endif /* HAVE_NTGUI */
5144 Destroy_Image (ximg, prev);
5146 return 1;
5150 /***********************************************************************
5151 PBM (mono, gray, color)
5152 ***********************************************************************/
5154 static int pbm_image_p P_ ((Lisp_Object object));
5155 static int pbm_load P_ ((struct frame *f, struct image *img));
5156 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
5158 /* The symbol `pbm' identifying images of this type. */
5160 Lisp_Object Qpbm;
5162 /* Indices of image specification fields in gs_format, below. */
5164 enum pbm_keyword_index
5166 PBM_TYPE,
5167 PBM_FILE,
5168 PBM_DATA,
5169 PBM_ASCENT,
5170 PBM_MARGIN,
5171 PBM_RELIEF,
5172 PBM_ALGORITHM,
5173 PBM_HEURISTIC_MASK,
5174 PBM_MASK,
5175 PBM_FOREGROUND,
5176 PBM_BACKGROUND,
5177 PBM_LAST
5180 /* Vector of image_keyword structures describing the format
5181 of valid user-defined image specifications. */
5183 static struct image_keyword pbm_format[PBM_LAST] =
5185 {":type", IMAGE_SYMBOL_VALUE, 1},
5186 {":file", IMAGE_STRING_VALUE, 0},
5187 {":data", IMAGE_STRING_VALUE, 0},
5188 {":ascent", IMAGE_ASCENT_VALUE, 0},
5189 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5190 {":relief", IMAGE_INTEGER_VALUE, 0},
5191 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5192 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5193 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5194 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5195 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5198 /* Structure describing the image type `pbm'. */
5200 static struct image_type pbm_type =
5202 &Qpbm,
5203 pbm_image_p,
5204 pbm_load,
5205 x_clear_image,
5206 NULL
5210 /* Return non-zero if OBJECT is a valid PBM image specification. */
5212 static int
5213 pbm_image_p (object)
5214 Lisp_Object object;
5216 struct image_keyword fmt[PBM_LAST];
5218 bcopy (pbm_format, fmt, sizeof fmt);
5220 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
5221 return 0;
5223 /* Must specify either :data or :file. */
5224 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
5228 /* Scan a decimal number from *S and return it. Advance *S while
5229 reading the number. END is the end of the string. Value is -1 at
5230 end of input. */
5232 static int
5233 pbm_scan_number (s, end)
5234 unsigned char **s, *end;
5236 int c = 0, val = -1;
5238 while (*s < end)
5240 /* Skip white-space. */
5241 while (*s < end && (c = *(*s)++, isspace (c)))
5244 if (c == '#')
5246 /* Skip comment to end of line. */
5247 while (*s < end && (c = *(*s)++, c != '\n'))
5250 else if (isdigit (c))
5252 /* Read decimal number. */
5253 val = c - '0';
5254 while (*s < end && (c = *(*s)++, isdigit (c)))
5255 val = 10 * val + c - '0';
5256 break;
5258 else
5259 break;
5262 return val;
5266 #ifdef HAVE_NTGUI
5267 #if 0 /* Unused. ++kfs */
5269 /* Read FILE into memory. Value is a pointer to a buffer allocated
5270 with xmalloc holding FILE's contents. Value is null if an error
5271 occurred. *SIZE is set to the size of the file. */
5273 static char *
5274 pbm_read_file (file, size)
5275 Lisp_Object file;
5276 int *size;
5278 FILE *fp = NULL;
5279 char *buf = NULL;
5280 struct stat st;
5282 if (stat (SDATA (file), &st) == 0
5283 && (fp = fopen (SDATA (file), "rb")) != NULL
5284 && (buf = (char *) xmalloc (st.st_size),
5285 fread (buf, 1, st.st_size, fp) == st.st_size))
5287 *size = st.st_size;
5288 fclose (fp);
5290 else
5292 if (fp)
5293 fclose (fp);
5294 if (buf)
5296 xfree (buf);
5297 buf = NULL;
5301 return buf;
5303 #endif
5304 #endif /* HAVE_NTGUI */
5306 /* Load PBM image IMG for use on frame F. */
5308 static int
5309 pbm_load (f, img)
5310 struct frame *f;
5311 struct image *img;
5313 int raw_p, x, y;
5314 int width, height, max_color_idx = 0;
5315 XImagePtr ximg;
5316 Lisp_Object file, specified_file;
5317 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
5318 struct gcpro gcpro1;
5319 unsigned char *contents = NULL;
5320 unsigned char *end, *p;
5321 int size;
5323 specified_file = image_spec_value (img->spec, QCfile, NULL);
5324 file = Qnil;
5325 GCPRO1 (file);
5327 if (STRINGP (specified_file))
5329 file = x_find_image_file (specified_file);
5330 if (!STRINGP (file))
5332 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5333 UNGCPRO;
5334 return 0;
5337 contents = slurp_file (SDATA (file), &size);
5338 if (contents == NULL)
5340 image_error ("Error reading `%s'", file, Qnil);
5341 UNGCPRO;
5342 return 0;
5345 p = contents;
5346 end = contents + size;
5348 else
5350 Lisp_Object data;
5351 data = image_spec_value (img->spec, QCdata, NULL);
5352 p = SDATA (data);
5353 end = p + SBYTES (data);
5356 /* Check magic number. */
5357 if (end - p < 2 || *p++ != 'P')
5359 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5360 error:
5361 xfree (contents);
5362 UNGCPRO;
5363 return 0;
5366 switch (*p++)
5368 case '1':
5369 raw_p = 0, type = PBM_MONO;
5370 break;
5372 case '2':
5373 raw_p = 0, type = PBM_GRAY;
5374 break;
5376 case '3':
5377 raw_p = 0, type = PBM_COLOR;
5378 break;
5380 case '4':
5381 raw_p = 1, type = PBM_MONO;
5382 break;
5384 case '5':
5385 raw_p = 1, type = PBM_GRAY;
5386 break;
5388 case '6':
5389 raw_p = 1, type = PBM_COLOR;
5390 break;
5392 default:
5393 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5394 goto error;
5397 /* Read width, height, maximum color-component. Characters
5398 starting with `#' up to the end of a line are ignored. */
5399 width = pbm_scan_number (&p, end);
5400 height = pbm_scan_number (&p, end);
5402 if (type != PBM_MONO)
5404 max_color_idx = pbm_scan_number (&p, end);
5405 if (raw_p && max_color_idx > 255)
5406 max_color_idx = 255;
5409 if (width < 0
5410 || height < 0
5411 || (type != PBM_MONO && max_color_idx < 0))
5412 goto error;
5414 if (!x_create_x_image_and_pixmap (f, width, height, 0,
5415 &ximg, &img->pixmap))
5416 goto error;
5418 /* Initialize the color hash table. */
5419 init_color_table ();
5421 if (type == PBM_MONO)
5423 int c = 0, g;
5424 struct image_keyword fmt[PBM_LAST];
5425 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
5426 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
5428 /* Parse the image specification. */
5429 bcopy (pbm_format, fmt, sizeof fmt);
5430 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
5432 /* Get foreground and background colors, maybe allocate colors. */
5433 if (fmt[PBM_FOREGROUND].count
5434 && STRINGP (fmt[PBM_FOREGROUND].value))
5435 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
5436 if (fmt[PBM_BACKGROUND].count
5437 && STRINGP (fmt[PBM_BACKGROUND].value))
5439 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
5440 img->background = bg;
5441 img->background_valid = 1;
5444 for (y = 0; y < height; ++y)
5445 for (x = 0; x < width; ++x)
5447 if (raw_p)
5449 if ((x & 7) == 0)
5450 c = *p++;
5451 g = c & 0x80;
5452 c <<= 1;
5454 else
5455 g = pbm_scan_number (&p, end);
5457 XPutPixel (ximg, x, y, g ? fg : bg);
5460 else
5462 for (y = 0; y < height; ++y)
5463 for (x = 0; x < width; ++x)
5465 int r, g, b;
5467 if (type == PBM_GRAY)
5468 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
5469 else if (raw_p)
5471 r = *p++;
5472 g = *p++;
5473 b = *p++;
5475 else
5477 r = pbm_scan_number (&p, end);
5478 g = pbm_scan_number (&p, end);
5479 b = pbm_scan_number (&p, end);
5482 if (r < 0 || g < 0 || b < 0)
5484 x_destroy_x_image (ximg);
5485 image_error ("Invalid pixel value in image `%s'",
5486 img->spec, Qnil);
5487 goto error;
5490 /* RGB values are now in the range 0..max_color_idx.
5491 Scale this to the range 0..0xffff supported by X. */
5492 r = (double) r * 65535 / max_color_idx;
5493 g = (double) g * 65535 / max_color_idx;
5494 b = (double) b * 65535 / max_color_idx;
5495 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5499 #ifdef COLOR_TABLE_SUPPORT
5500 /* Store in IMG->colors the colors allocated for the image, and
5501 free the color table. */
5502 img->colors = colors_in_color_table (&img->ncolors);
5503 free_color_table ();
5504 #endif /* COLOR_TABLE_SUPPORT */
5506 img->width = width;
5507 img->height = height;
5509 /* Maybe fill in the background field while we have ximg handy. */
5511 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5512 IMAGE_BACKGROUND (img, f, ximg);
5514 /* Put the image into a pixmap. */
5515 x_put_x_image (f, ximg, img->pixmap, width, height);
5516 x_destroy_x_image (ximg);
5518 /* X and W32 versions did it here, MAC version above. ++kfs
5519 img->width = width;
5520 img->height = height; */
5522 UNGCPRO;
5523 xfree (contents);
5524 return 1;
5528 /***********************************************************************
5530 ***********************************************************************/
5532 #if defined (HAVE_PNG) || defined (MAC_OS)
5534 /* Function prototypes. */
5536 static int png_image_p P_ ((Lisp_Object object));
5537 static int png_load P_ ((struct frame *f, struct image *img));
5539 /* The symbol `png' identifying images of this type. */
5541 Lisp_Object Qpng;
5543 /* Indices of image specification fields in png_format, below. */
5545 enum png_keyword_index
5547 PNG_TYPE,
5548 PNG_DATA,
5549 PNG_FILE,
5550 PNG_ASCENT,
5551 PNG_MARGIN,
5552 PNG_RELIEF,
5553 PNG_ALGORITHM,
5554 PNG_HEURISTIC_MASK,
5555 PNG_MASK,
5556 PNG_BACKGROUND,
5557 PNG_LAST
5560 /* Vector of image_keyword structures describing the format
5561 of valid user-defined image specifications. */
5563 static struct image_keyword png_format[PNG_LAST] =
5565 {":type", IMAGE_SYMBOL_VALUE, 1},
5566 {":data", IMAGE_STRING_VALUE, 0},
5567 {":file", IMAGE_STRING_VALUE, 0},
5568 {":ascent", IMAGE_ASCENT_VALUE, 0},
5569 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5570 {":relief", IMAGE_INTEGER_VALUE, 0},
5571 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5572 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5573 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5574 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5577 /* Structure describing the image type `png'. */
5579 static struct image_type png_type =
5581 &Qpng,
5582 png_image_p,
5583 png_load,
5584 x_clear_image,
5585 NULL
5588 /* Return non-zero if OBJECT is a valid PNG image specification. */
5590 static int
5591 png_image_p (object)
5592 Lisp_Object object;
5594 struct image_keyword fmt[PNG_LAST];
5595 bcopy (png_format, fmt, sizeof fmt);
5597 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5598 return 0;
5600 /* Must specify either the :data or :file keyword. */
5601 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5604 #endif /* HAVE_PNG || MAC_OS */
5607 #ifdef HAVE_PNG
5609 #if defined HAVE_LIBPNG_PNG_H
5610 # include <libpng/png.h>
5611 #else
5612 # include <png.h>
5613 #endif
5615 #ifdef HAVE_NTGUI
5616 /* PNG library details. */
5618 DEF_IMGLIB_FN (png_get_io_ptr);
5619 DEF_IMGLIB_FN (png_check_sig);
5620 DEF_IMGLIB_FN (png_create_read_struct);
5621 DEF_IMGLIB_FN (png_create_info_struct);
5622 DEF_IMGLIB_FN (png_destroy_read_struct);
5623 DEF_IMGLIB_FN (png_set_read_fn);
5624 DEF_IMGLIB_FN (png_init_io);
5625 DEF_IMGLIB_FN (png_set_sig_bytes);
5626 DEF_IMGLIB_FN (png_read_info);
5627 DEF_IMGLIB_FN (png_get_IHDR);
5628 DEF_IMGLIB_FN (png_get_valid);
5629 DEF_IMGLIB_FN (png_set_strip_16);
5630 DEF_IMGLIB_FN (png_set_expand);
5631 DEF_IMGLIB_FN (png_set_gray_to_rgb);
5632 DEF_IMGLIB_FN (png_set_background);
5633 DEF_IMGLIB_FN (png_get_bKGD);
5634 DEF_IMGLIB_FN (png_read_update_info);
5635 DEF_IMGLIB_FN (png_get_channels);
5636 DEF_IMGLIB_FN (png_get_rowbytes);
5637 DEF_IMGLIB_FN (png_read_image);
5638 DEF_IMGLIB_FN (png_read_end);
5639 DEF_IMGLIB_FN (png_error);
5641 static int
5642 init_png_functions (Lisp_Object libraries)
5644 HMODULE library;
5646 /* Try loading libpng under probable names. */
5647 if (!(library = w32_delayed_load (libraries, Qpng)))
5648 return 0;
5650 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5651 LOAD_IMGLIB_FN (library, png_check_sig);
5652 LOAD_IMGLIB_FN (library, png_create_read_struct);
5653 LOAD_IMGLIB_FN (library, png_create_info_struct);
5654 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5655 LOAD_IMGLIB_FN (library, png_set_read_fn);
5656 LOAD_IMGLIB_FN (library, png_init_io);
5657 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5658 LOAD_IMGLIB_FN (library, png_read_info);
5659 LOAD_IMGLIB_FN (library, png_get_IHDR);
5660 LOAD_IMGLIB_FN (library, png_get_valid);
5661 LOAD_IMGLIB_FN (library, png_set_strip_16);
5662 LOAD_IMGLIB_FN (library, png_set_expand);
5663 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5664 LOAD_IMGLIB_FN (library, png_set_background);
5665 LOAD_IMGLIB_FN (library, png_get_bKGD);
5666 LOAD_IMGLIB_FN (library, png_read_update_info);
5667 LOAD_IMGLIB_FN (library, png_get_channels);
5668 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5669 LOAD_IMGLIB_FN (library, png_read_image);
5670 LOAD_IMGLIB_FN (library, png_read_end);
5671 LOAD_IMGLIB_FN (library, png_error);
5672 return 1;
5674 #else
5676 #define fn_png_get_io_ptr png_get_io_ptr
5677 #define fn_png_check_sig png_check_sig
5678 #define fn_png_create_read_struct png_create_read_struct
5679 #define fn_png_create_info_struct png_create_info_struct
5680 #define fn_png_destroy_read_struct png_destroy_read_struct
5681 #define fn_png_set_read_fn png_set_read_fn
5682 #define fn_png_init_io png_init_io
5683 #define fn_png_set_sig_bytes png_set_sig_bytes
5684 #define fn_png_read_info png_read_info
5685 #define fn_png_get_IHDR png_get_IHDR
5686 #define fn_png_get_valid png_get_valid
5687 #define fn_png_set_strip_16 png_set_strip_16
5688 #define fn_png_set_expand png_set_expand
5689 #define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5690 #define fn_png_set_background png_set_background
5691 #define fn_png_get_bKGD png_get_bKGD
5692 #define fn_png_read_update_info png_read_update_info
5693 #define fn_png_get_channels png_get_channels
5694 #define fn_png_get_rowbytes png_get_rowbytes
5695 #define fn_png_read_image png_read_image
5696 #define fn_png_read_end png_read_end
5697 #define fn_png_error png_error
5699 #endif /* HAVE_NTGUI */
5701 /* Error and warning handlers installed when the PNG library
5702 is initialized. */
5704 static void
5705 my_png_error (png_ptr, msg)
5706 png_struct *png_ptr;
5707 char *msg;
5709 xassert (png_ptr != NULL);
5710 image_error ("PNG error: %s", build_string (msg), Qnil);
5711 longjmp (png_ptr->jmpbuf, 1);
5715 static void
5716 my_png_warning (png_ptr, msg)
5717 png_struct *png_ptr;
5718 char *msg;
5720 xassert (png_ptr != NULL);
5721 image_error ("PNG warning: %s", build_string (msg), Qnil);
5724 /* Memory source for PNG decoding. */
5726 struct png_memory_storage
5728 unsigned char *bytes; /* The data */
5729 size_t len; /* How big is it? */
5730 int index; /* Where are we? */
5734 /* Function set as reader function when reading PNG image from memory.
5735 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5736 bytes from the input to DATA. */
5738 #ifdef _MSC_VER
5739 /* Work around a problem with MinGW builds of graphics libraries
5740 not honoring calling conventions. */
5741 #pragma optimize("g", off)
5742 #endif
5744 static void
5745 png_read_from_memory (png_ptr, data, length)
5746 png_structp png_ptr;
5747 png_bytep data;
5748 png_size_t length;
5750 struct png_memory_storage *tbr
5751 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5753 if (length > tbr->len - tbr->index)
5754 fn_png_error (png_ptr, "Read error");
5756 bcopy (tbr->bytes + tbr->index, data, length);
5757 tbr->index = tbr->index + length;
5760 #ifdef _MSC_VER
5761 /* Restore normal optimization, as specified on the command line. */
5762 #pragma optimize("", on)
5763 #endif
5765 /* Load PNG image IMG for use on frame F. Value is non-zero if
5766 successful. */
5768 static int
5769 png_load (f, img)
5770 struct frame *f;
5771 struct image *img;
5773 Lisp_Object file, specified_file;
5774 Lisp_Object specified_data;
5775 int x, y, i;
5776 XImagePtr ximg, mask_img = NULL;
5777 struct gcpro gcpro1;
5778 png_struct *png_ptr = NULL;
5779 png_info *info_ptr = NULL, *end_info = NULL;
5780 FILE *volatile fp = NULL;
5781 png_byte sig[8];
5782 png_byte * volatile pixels = NULL;
5783 png_byte ** volatile rows = NULL;
5784 png_uint_32 width, height;
5785 int bit_depth, color_type, interlace_type;
5786 png_byte channels;
5787 png_uint_32 row_bytes;
5788 int transparent_p;
5789 double screen_gamma;
5790 struct png_memory_storage tbr; /* Data to be read */
5792 /* Find out what file to load. */
5793 specified_file = image_spec_value (img->spec, QCfile, NULL);
5794 specified_data = image_spec_value (img->spec, QCdata, NULL);
5795 file = Qnil;
5796 GCPRO1 (file);
5798 if (NILP (specified_data))
5800 file = x_find_image_file (specified_file);
5801 if (!STRINGP (file))
5803 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5804 UNGCPRO;
5805 return 0;
5808 /* Open the image file. */
5809 fp = fopen (SDATA (file), "rb");
5810 if (!fp)
5812 image_error ("Cannot open image file `%s'", file, Qnil);
5813 UNGCPRO;
5814 fclose (fp);
5815 return 0;
5818 /* Check PNG signature. */
5819 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
5820 || !fn_png_check_sig (sig, sizeof sig))
5822 image_error ("Not a PNG file: `%s'", file, Qnil);
5823 UNGCPRO;
5824 fclose (fp);
5825 return 0;
5828 else
5830 /* Read from memory. */
5831 tbr.bytes = SDATA (specified_data);
5832 tbr.len = SBYTES (specified_data);
5833 tbr.index = 0;
5835 /* Check PNG signature. */
5836 if (tbr.len < sizeof sig
5837 || !fn_png_check_sig (tbr.bytes, sizeof sig))
5839 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5840 UNGCPRO;
5841 return 0;
5844 /* Need to skip past the signature. */
5845 tbr.bytes += sizeof (sig);
5848 /* Initialize read and info structs for PNG lib. */
5849 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
5850 my_png_error, my_png_warning);
5851 if (!png_ptr)
5853 if (fp) fclose (fp);
5854 UNGCPRO;
5855 return 0;
5858 info_ptr = fn_png_create_info_struct (png_ptr);
5859 if (!info_ptr)
5861 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
5862 if (fp) fclose (fp);
5863 UNGCPRO;
5864 return 0;
5867 end_info = fn_png_create_info_struct (png_ptr);
5868 if (!end_info)
5870 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
5871 if (fp) fclose (fp);
5872 UNGCPRO;
5873 return 0;
5876 /* Set error jump-back. We come back here when the PNG library
5877 detects an error. */
5878 if (setjmp (png_ptr->jmpbuf))
5880 error:
5881 if (png_ptr)
5882 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
5883 xfree (pixels);
5884 xfree (rows);
5885 if (fp) fclose (fp);
5886 UNGCPRO;
5887 return 0;
5890 /* Read image info. */
5891 if (!NILP (specified_data))
5892 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
5893 else
5894 fn_png_init_io (png_ptr, fp);
5896 fn_png_set_sig_bytes (png_ptr, sizeof sig);
5897 fn_png_read_info (png_ptr, info_ptr);
5898 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
5899 &interlace_type, NULL, NULL);
5901 /* If image contains simply transparency data, we prefer to
5902 construct a clipping mask. */
5903 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
5904 transparent_p = 1;
5905 else
5906 transparent_p = 0;
5908 /* This function is easier to write if we only have to handle
5909 one data format: RGB or RGBA with 8 bits per channel. Let's
5910 transform other formats into that format. */
5912 /* Strip more than 8 bits per channel. */
5913 if (bit_depth == 16)
5914 fn_png_set_strip_16 (png_ptr);
5916 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
5917 if available. */
5918 fn_png_set_expand (png_ptr);
5920 /* Convert grayscale images to RGB. */
5921 if (color_type == PNG_COLOR_TYPE_GRAY
5922 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
5923 fn_png_set_gray_to_rgb (png_ptr);
5925 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
5927 #if 0 /* Avoid double gamma correction for PNG images. */
5928 { /* Tell the PNG lib to handle gamma correction for us. */
5929 int intent;
5930 double image_gamma;
5931 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
5932 if (png_get_sRGB (png_ptr, info_ptr, &intent))
5933 /* The libpng documentation says this is right in this case. */
5934 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5935 else
5936 #endif
5937 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
5938 /* Image contains gamma information. */
5939 png_set_gamma (png_ptr, screen_gamma, image_gamma);
5940 else
5941 /* Use the standard default for the image gamma. */
5942 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5944 #endif /* if 0 */
5946 /* Handle alpha channel by combining the image with a background
5947 color. Do this only if a real alpha channel is supplied. For
5948 simple transparency, we prefer a clipping mask. */
5949 if (!transparent_p)
5951 png_color_16 *image_bg;
5952 Lisp_Object specified_bg
5953 = image_spec_value (img->spec, QCbackground, NULL);
5955 if (STRINGP (specified_bg))
5956 /* The user specified `:background', use that. */
5958 /* W32 version incorrectly used COLORREF here!! ++kfs */
5959 XColor color;
5960 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
5962 png_color_16 user_bg;
5964 bzero (&user_bg, sizeof user_bg);
5965 user_bg.red = color.red >> 8;
5966 user_bg.green = color.green >> 8;
5967 user_bg.blue = color.blue >> 8;
5969 fn_png_set_background (png_ptr, &user_bg,
5970 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5973 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
5974 /* Image contains a background color with which to
5975 combine the image. */
5976 fn_png_set_background (png_ptr, image_bg,
5977 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
5978 else
5980 /* Image does not contain a background color with which
5981 to combine the image data via an alpha channel. Use
5982 the frame's background instead. */
5983 #ifdef HAVE_X_WINDOWS
5984 XColor color;
5985 png_color_16 frame_background;
5987 color.pixel = FRAME_BACKGROUND_PIXEL (f);
5988 x_query_color (f, &color);
5990 bzero (&frame_background, sizeof frame_background);
5991 frame_background.red = color.red >> 8;
5992 frame_background.green = color.green >> 8;
5993 frame_background.blue = color.blue >> 8;
5994 #endif /* HAVE_X_WINDOWS */
5996 #ifdef HAVE_NTGUI
5997 COLORREF color;
5998 png_color_16 frame_background;
5999 color = FRAME_BACKGROUND_PIXEL (f);
6000 #if 0 /* W32 TODO : Colormap support. */
6001 x_query_color (f, &color);
6002 #endif
6003 bzero (&frame_background, sizeof frame_background);
6004 frame_background.red = GetRValue (color);
6005 frame_background.green = GetGValue (color);
6006 frame_background.blue = GetBValue (color);
6007 #endif /* HAVE_NTGUI */
6009 #ifdef MAC_OS
6010 unsigned long color;
6011 png_color_16 frame_background;
6012 color = FRAME_BACKGROUND_PIXEL (f);
6013 #if 0 /* MAC/W32 TODO : Colormap support. */
6014 x_query_color (f, &color);
6015 #endif
6016 bzero (&frame_background, sizeof frame_background);
6017 frame_background.red = RED_FROM_ULONG (color);
6018 frame_background.green = GREEN_FROM_ULONG (color);
6019 frame_background.blue = BLUE_FROM_ULONG (color);
6020 #endif /* MAC_OS */
6022 fn_png_set_background (png_ptr, &frame_background,
6023 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6027 /* Update info structure. */
6028 fn_png_read_update_info (png_ptr, info_ptr);
6030 /* Get number of channels. Valid values are 1 for grayscale images
6031 and images with a palette, 2 for grayscale images with transparency
6032 information (alpha channel), 3 for RGB images, and 4 for RGB
6033 images with alpha channel, i.e. RGBA. If conversions above were
6034 sufficient we should only have 3 or 4 channels here. */
6035 channels = fn_png_get_channels (png_ptr, info_ptr);
6036 xassert (channels == 3 || channels == 4);
6038 /* Number of bytes needed for one row of the image. */
6039 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6041 /* Allocate memory for the image. */
6042 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
6043 rows = (png_byte **) xmalloc (height * sizeof *rows);
6044 for (i = 0; i < height; ++i)
6045 rows[i] = pixels + i * row_bytes;
6047 /* Read the entire image. */
6048 fn_png_read_image (png_ptr, rows);
6049 fn_png_read_end (png_ptr, info_ptr);
6050 if (fp)
6052 fclose (fp);
6053 fp = NULL;
6056 /* Create the X image and pixmap. */
6057 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
6058 &img->pixmap))
6059 goto error;
6061 /* Create an image and pixmap serving as mask if the PNG image
6062 contains an alpha channel. */
6063 if (channels == 4
6064 && !transparent_p
6065 && !x_create_x_image_and_pixmap (f, width, height, 1,
6066 &mask_img, &img->mask))
6068 x_destroy_x_image (ximg);
6069 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
6070 img->pixmap = NO_PIXMAP;
6071 goto error;
6074 /* Fill the X image and mask from PNG data. */
6075 init_color_table ();
6077 for (y = 0; y < height; ++y)
6079 png_byte *p = rows[y];
6081 for (x = 0; x < width; ++x)
6083 unsigned r, g, b;
6085 r = *p++ << 8;
6086 g = *p++ << 8;
6087 b = *p++ << 8;
6088 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6089 /* An alpha channel, aka mask channel, associates variable
6090 transparency with an image. Where other image formats
6091 support binary transparency---fully transparent or fully
6092 opaque---PNG allows up to 254 levels of partial transparency.
6093 The PNG library implements partial transparency by combining
6094 the image with a specified background color.
6096 I'm not sure how to handle this here nicely: because the
6097 background on which the image is displayed may change, for
6098 real alpha channel support, it would be necessary to create
6099 a new image for each possible background.
6101 What I'm doing now is that a mask is created if we have
6102 boolean transparency information. Otherwise I'm using
6103 the frame's background color to combine the image with. */
6105 if (channels == 4)
6107 if (mask_img)
6108 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
6109 ++p;
6114 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6115 /* Set IMG's background color from the PNG image, unless the user
6116 overrode it. */
6118 png_color_16 *bg;
6119 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
6121 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
6122 img->background_valid = 1;
6126 #ifdef COLOR_TABLE_SUPPORT
6127 /* Remember colors allocated for this image. */
6128 img->colors = colors_in_color_table (&img->ncolors);
6129 free_color_table ();
6130 #endif /* COLOR_TABLE_SUPPORT */
6132 /* Clean up. */
6133 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6134 xfree (rows);
6135 xfree (pixels);
6137 img->width = width;
6138 img->height = height;
6140 /* Maybe fill in the background field while we have ximg handy. */
6141 IMAGE_BACKGROUND (img, f, ximg);
6143 /* Put the image into the pixmap, then free the X image and its buffer. */
6144 x_put_x_image (f, ximg, img->pixmap, width, height);
6145 x_destroy_x_image (ximg);
6147 /* Same for the mask. */
6148 if (mask_img)
6150 /* Fill in the background_transparent field while we have the mask
6151 handy. */
6152 image_background_transparent (img, f, mask_img);
6154 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6155 x_destroy_x_image (mask_img);
6158 UNGCPRO;
6159 return 1;
6162 #else /* HAVE_PNG */
6164 #ifdef MAC_OS
6165 static int
6166 png_load (f, img)
6167 struct frame *f;
6168 struct image *img;
6170 #ifdef MAC_OSX
6171 if (MyCGImageCreateWithPNGDataProvider)
6172 return image_load_quartz2d (f, img, 1);
6173 else
6174 #endif
6175 return image_load_quicktime (f, img, kQTFileTypePNG);
6177 #endif /* MAC_OS */
6179 #endif /* !HAVE_PNG */
6183 /***********************************************************************
6184 JPEG
6185 ***********************************************************************/
6187 #if defined (HAVE_JPEG) || defined (MAC_OS)
6189 static int jpeg_image_p P_ ((Lisp_Object object));
6190 static int jpeg_load P_ ((struct frame *f, struct image *img));
6192 /* The symbol `jpeg' identifying images of this type. */
6194 Lisp_Object Qjpeg;
6196 /* Indices of image specification fields in gs_format, below. */
6198 enum jpeg_keyword_index
6200 JPEG_TYPE,
6201 JPEG_DATA,
6202 JPEG_FILE,
6203 JPEG_ASCENT,
6204 JPEG_MARGIN,
6205 JPEG_RELIEF,
6206 JPEG_ALGORITHM,
6207 JPEG_HEURISTIC_MASK,
6208 JPEG_MASK,
6209 JPEG_BACKGROUND,
6210 JPEG_LAST
6213 /* Vector of image_keyword structures describing the format
6214 of valid user-defined image specifications. */
6216 static struct image_keyword jpeg_format[JPEG_LAST] =
6218 {":type", IMAGE_SYMBOL_VALUE, 1},
6219 {":data", IMAGE_STRING_VALUE, 0},
6220 {":file", IMAGE_STRING_VALUE, 0},
6221 {":ascent", IMAGE_ASCENT_VALUE, 0},
6222 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6223 {":relief", IMAGE_INTEGER_VALUE, 0},
6224 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6225 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6226 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6227 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6230 /* Structure describing the image type `jpeg'. */
6232 static struct image_type jpeg_type =
6234 &Qjpeg,
6235 jpeg_image_p,
6236 jpeg_load,
6237 x_clear_image,
6238 NULL
6241 /* Return non-zero if OBJECT is a valid JPEG image specification. */
6243 static int
6244 jpeg_image_p (object)
6245 Lisp_Object object;
6247 struct image_keyword fmt[JPEG_LAST];
6249 bcopy (jpeg_format, fmt, sizeof fmt);
6251 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6252 return 0;
6254 /* Must specify either the :data or :file keyword. */
6255 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
6258 #endif /* HAVE_JPEG || MAC_OS */
6260 #ifdef HAVE_JPEG
6262 /* Work around a warning about HAVE_STDLIB_H being redefined in
6263 jconfig.h. */
6264 #ifdef HAVE_STDLIB_H
6265 #define HAVE_STDLIB_H_1
6266 #undef HAVE_STDLIB_H
6267 #endif /* HAVE_STLIB_H */
6269 #include <jpeglib.h>
6270 #include <jerror.h>
6271 #include <setjmp.h>
6273 #ifdef HAVE_STLIB_H_1
6274 #define HAVE_STDLIB_H 1
6275 #endif
6277 #ifdef HAVE_NTGUI
6279 /* JPEG library details. */
6280 DEF_IMGLIB_FN (jpeg_CreateDecompress);
6281 DEF_IMGLIB_FN (jpeg_start_decompress);
6282 DEF_IMGLIB_FN (jpeg_finish_decompress);
6283 DEF_IMGLIB_FN (jpeg_destroy_decompress);
6284 DEF_IMGLIB_FN (jpeg_read_header);
6285 DEF_IMGLIB_FN (jpeg_read_scanlines);
6286 DEF_IMGLIB_FN (jpeg_stdio_src);
6287 DEF_IMGLIB_FN (jpeg_std_error);
6288 DEF_IMGLIB_FN (jpeg_resync_to_restart);
6290 static int
6291 init_jpeg_functions (Lisp_Object libraries)
6293 HMODULE library;
6295 if (!(library = w32_delayed_load (libraries, Qjpeg)))
6296 return 0;
6298 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
6299 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
6300 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
6301 LOAD_IMGLIB_FN (library, jpeg_read_header);
6302 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
6303 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
6304 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
6305 LOAD_IMGLIB_FN (library, jpeg_std_error);
6306 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
6307 return 1;
6310 /* Wrapper since we can't directly assign the function pointer
6311 to another function pointer that was declared more completely easily. */
6312 static boolean
6313 jpeg_resync_to_restart_wrapper(cinfo, desired)
6314 j_decompress_ptr cinfo;
6315 int desired;
6317 return fn_jpeg_resync_to_restart (cinfo, desired);
6320 #else
6322 #define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
6323 #define fn_jpeg_start_decompress jpeg_start_decompress
6324 #define fn_jpeg_finish_decompress jpeg_finish_decompress
6325 #define fn_jpeg_destroy_decompress jpeg_destroy_decompress
6326 #define fn_jpeg_read_header jpeg_read_header
6327 #define fn_jpeg_read_scanlines jpeg_read_scanlines
6328 #define fn_jpeg_stdio_src jpeg_stdio_src
6329 #define fn_jpeg_std_error jpeg_std_error
6330 #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
6332 #endif /* HAVE_NTGUI */
6334 struct my_jpeg_error_mgr
6336 struct jpeg_error_mgr pub;
6337 jmp_buf setjmp_buffer;
6341 static void
6342 my_error_exit (cinfo)
6343 j_common_ptr cinfo;
6345 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
6346 longjmp (mgr->setjmp_buffer, 1);
6350 /* Init source method for JPEG data source manager. Called by
6351 jpeg_read_header() before any data is actually read. See
6352 libjpeg.doc from the JPEG lib distribution. */
6354 static void
6355 our_init_source (cinfo)
6356 j_decompress_ptr cinfo;
6361 /* Fill input buffer method for JPEG data source manager. Called
6362 whenever more data is needed. We read the whole image in one step,
6363 so this only adds a fake end of input marker at the end. */
6365 static boolean
6366 our_fill_input_buffer (cinfo)
6367 j_decompress_ptr cinfo;
6369 /* Insert a fake EOI marker. */
6370 struct jpeg_source_mgr *src = cinfo->src;
6371 static JOCTET buffer[2];
6373 buffer[0] = (JOCTET) 0xFF;
6374 buffer[1] = (JOCTET) JPEG_EOI;
6376 src->next_input_byte = buffer;
6377 src->bytes_in_buffer = 2;
6378 return TRUE;
6382 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6383 is the JPEG data source manager. */
6385 static void
6386 our_skip_input_data (cinfo, num_bytes)
6387 j_decompress_ptr cinfo;
6388 long num_bytes;
6390 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
6392 if (src)
6394 if (num_bytes > src->bytes_in_buffer)
6395 ERREXIT (cinfo, JERR_INPUT_EOF);
6397 src->bytes_in_buffer -= num_bytes;
6398 src->next_input_byte += num_bytes;
6403 /* Method to terminate data source. Called by
6404 jpeg_finish_decompress() after all data has been processed. */
6406 static void
6407 our_term_source (cinfo)
6408 j_decompress_ptr cinfo;
6413 /* Set up the JPEG lib for reading an image from DATA which contains
6414 LEN bytes. CINFO is the decompression info structure created for
6415 reading the image. */
6417 static void
6418 jpeg_memory_src (cinfo, data, len)
6419 j_decompress_ptr cinfo;
6420 JOCTET *data;
6421 unsigned int len;
6423 struct jpeg_source_mgr *src;
6425 if (cinfo->src == NULL)
6427 /* First time for this JPEG object? */
6428 cinfo->src = (struct jpeg_source_mgr *)
6429 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6430 sizeof (struct jpeg_source_mgr));
6431 src = (struct jpeg_source_mgr *) cinfo->src;
6432 src->next_input_byte = data;
6435 src = (struct jpeg_source_mgr *) cinfo->src;
6436 src->init_source = our_init_source;
6437 src->fill_input_buffer = our_fill_input_buffer;
6438 src->skip_input_data = our_skip_input_data;
6439 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6440 src->term_source = our_term_source;
6441 src->bytes_in_buffer = len;
6442 src->next_input_byte = data;
6446 /* Load image IMG for use on frame F. Patterned after example.c
6447 from the JPEG lib. */
6449 static int
6450 jpeg_load (f, img)
6451 struct frame *f;
6452 struct image *img;
6454 struct jpeg_decompress_struct cinfo;
6455 struct my_jpeg_error_mgr mgr;
6456 Lisp_Object file, specified_file;
6457 Lisp_Object specified_data;
6458 FILE * volatile fp = NULL;
6459 JSAMPARRAY buffer;
6460 int row_stride, x, y;
6461 XImagePtr ximg = NULL;
6462 int rc;
6463 unsigned long *colors;
6464 int width, height;
6465 struct gcpro gcpro1;
6467 /* Open the JPEG file. */
6468 specified_file = image_spec_value (img->spec, QCfile, NULL);
6469 specified_data = image_spec_value (img->spec, QCdata, NULL);
6470 file = Qnil;
6471 GCPRO1 (file);
6473 if (NILP (specified_data))
6475 file = x_find_image_file (specified_file);
6476 if (!STRINGP (file))
6478 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6479 UNGCPRO;
6480 return 0;
6483 fp = fopen (SDATA (file), "rb");
6484 if (fp == NULL)
6486 image_error ("Cannot open `%s'", file, Qnil);
6487 UNGCPRO;
6488 return 0;
6492 /* Customize libjpeg's error handling to call my_error_exit when an
6493 error is detected. This function will perform a longjmp. */
6494 cinfo.err = fn_jpeg_std_error (&mgr.pub);
6495 mgr.pub.error_exit = my_error_exit;
6497 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
6499 if (rc == 1)
6501 /* Called from my_error_exit. Display a JPEG error. */
6502 char buffer[JMSG_LENGTH_MAX];
6503 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
6504 image_error ("Error reading JPEG image `%s': %s", img->spec,
6505 build_string (buffer));
6508 /* Close the input file and destroy the JPEG object. */
6509 if (fp)
6510 fclose ((FILE *) fp);
6511 fn_jpeg_destroy_decompress (&cinfo);
6513 /* If we already have an XImage, free that. */
6514 x_destroy_x_image (ximg);
6516 /* Free pixmap and colors. */
6517 x_clear_image (f, img);
6519 UNGCPRO;
6520 return 0;
6523 /* Create the JPEG decompression object. Let it read from fp.
6524 Read the JPEG image header. */
6525 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6527 if (NILP (specified_data))
6528 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
6529 else
6530 jpeg_memory_src (&cinfo, SDATA (specified_data),
6531 SBYTES (specified_data));
6533 fn_jpeg_read_header (&cinfo, TRUE);
6535 /* Customize decompression so that color quantization will be used.
6536 Start decompression. */
6537 cinfo.quantize_colors = TRUE;
6538 fn_jpeg_start_decompress (&cinfo);
6539 width = img->width = cinfo.output_width;
6540 height = img->height = cinfo.output_height;
6542 /* Create X image and pixmap. */
6543 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6544 longjmp (mgr.setjmp_buffer, 2);
6546 /* Allocate colors. When color quantization is used,
6547 cinfo.actual_number_of_colors has been set with the number of
6548 colors generated, and cinfo.colormap is a two-dimensional array
6549 of color indices in the range 0..cinfo.actual_number_of_colors.
6550 No more than 255 colors will be generated. */
6552 int i, ir, ig, ib;
6554 if (cinfo.out_color_components > 2)
6555 ir = 0, ig = 1, ib = 2;
6556 else if (cinfo.out_color_components > 1)
6557 ir = 0, ig = 1, ib = 0;
6558 else
6559 ir = 0, ig = 0, ib = 0;
6561 /* Use the color table mechanism because it handles colors that
6562 cannot be allocated nicely. Such colors will be replaced with
6563 a default color, and we don't have to care about which colors
6564 can be freed safely, and which can't. */
6565 init_color_table ();
6566 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6567 * sizeof *colors);
6569 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6571 /* Multiply RGB values with 255 because X expects RGB values
6572 in the range 0..0xffff. */
6573 int r = cinfo.colormap[ir][i] << 8;
6574 int g = cinfo.colormap[ig][i] << 8;
6575 int b = cinfo.colormap[ib][i] << 8;
6576 colors[i] = lookup_rgb_color (f, r, g, b);
6579 #ifdef COLOR_TABLE_SUPPORT
6580 /* Remember those colors actually allocated. */
6581 img->colors = colors_in_color_table (&img->ncolors);
6582 free_color_table ();
6583 #endif /* COLOR_TABLE_SUPPORT */
6586 /* Read pixels. */
6587 row_stride = width * cinfo.output_components;
6588 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6589 row_stride, 1);
6590 for (y = 0; y < height; ++y)
6592 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6593 for (x = 0; x < cinfo.output_width; ++x)
6594 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6597 /* Clean up. */
6598 fn_jpeg_finish_decompress (&cinfo);
6599 fn_jpeg_destroy_decompress (&cinfo);
6600 if (fp)
6601 fclose ((FILE *) fp);
6603 /* Maybe fill in the background field while we have ximg handy. */
6604 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6605 IMAGE_BACKGROUND (img, f, ximg);
6607 /* Put the image into the pixmap. */
6608 x_put_x_image (f, ximg, img->pixmap, width, height);
6609 x_destroy_x_image (ximg);
6610 UNGCPRO;
6611 return 1;
6614 #else /* HAVE_JPEG */
6616 #ifdef MAC_OS
6617 static int
6618 jpeg_load (f, img)
6619 struct frame *f;
6620 struct image *img;
6622 #ifdef MAC_OSX
6623 return image_load_quartz2d (f, img, 0);
6624 #else
6625 return image_load_quicktime (f, img, kQTFileTypeJPEG);
6626 #endif
6628 #endif /* MAC_OS */
6630 #endif /* !HAVE_JPEG */
6634 /***********************************************************************
6635 TIFF
6636 ***********************************************************************/
6638 #if defined (HAVE_TIFF) || defined (MAC_OS)
6640 static int tiff_image_p P_ ((Lisp_Object object));
6641 static int tiff_load P_ ((struct frame *f, struct image *img));
6643 /* The symbol `tiff' identifying images of this type. */
6645 Lisp_Object Qtiff;
6647 /* Indices of image specification fields in tiff_format, below. */
6649 enum tiff_keyword_index
6651 TIFF_TYPE,
6652 TIFF_DATA,
6653 TIFF_FILE,
6654 TIFF_ASCENT,
6655 TIFF_MARGIN,
6656 TIFF_RELIEF,
6657 TIFF_ALGORITHM,
6658 TIFF_HEURISTIC_MASK,
6659 TIFF_MASK,
6660 TIFF_BACKGROUND,
6661 TIFF_LAST
6664 /* Vector of image_keyword structures describing the format
6665 of valid user-defined image specifications. */
6667 static struct image_keyword tiff_format[TIFF_LAST] =
6669 {":type", IMAGE_SYMBOL_VALUE, 1},
6670 {":data", IMAGE_STRING_VALUE, 0},
6671 {":file", IMAGE_STRING_VALUE, 0},
6672 {":ascent", IMAGE_ASCENT_VALUE, 0},
6673 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6674 {":relief", IMAGE_INTEGER_VALUE, 0},
6675 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6676 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6677 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6678 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6681 /* Structure describing the image type `tiff'. */
6683 static struct image_type tiff_type =
6685 &Qtiff,
6686 tiff_image_p,
6687 tiff_load,
6688 x_clear_image,
6689 NULL
6692 /* Return non-zero if OBJECT is a valid TIFF image specification. */
6694 static int
6695 tiff_image_p (object)
6696 Lisp_Object object;
6698 struct image_keyword fmt[TIFF_LAST];
6699 bcopy (tiff_format, fmt, sizeof fmt);
6701 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6702 return 0;
6704 /* Must specify either the :data or :file keyword. */
6705 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6708 #endif /* HAVE_TIFF || MAC_OS */
6710 #ifdef HAVE_TIFF
6712 #include <tiffio.h>
6714 #ifdef HAVE_NTGUI
6716 /* TIFF library details. */
6717 DEF_IMGLIB_FN (TIFFSetErrorHandler);
6718 DEF_IMGLIB_FN (TIFFSetWarningHandler);
6719 DEF_IMGLIB_FN (TIFFOpen);
6720 DEF_IMGLIB_FN (TIFFClientOpen);
6721 DEF_IMGLIB_FN (TIFFGetField);
6722 DEF_IMGLIB_FN (TIFFReadRGBAImage);
6723 DEF_IMGLIB_FN (TIFFClose);
6725 static int
6726 init_tiff_functions (Lisp_Object libraries)
6728 HMODULE library;
6730 if (!(library = w32_delayed_load (libraries, Qtiff)))
6731 return 0;
6733 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6734 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6735 LOAD_IMGLIB_FN (library, TIFFOpen);
6736 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6737 LOAD_IMGLIB_FN (library, TIFFGetField);
6738 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
6739 LOAD_IMGLIB_FN (library, TIFFClose);
6740 return 1;
6743 #else
6745 #define fn_TIFFSetErrorHandler TIFFSetErrorHandler
6746 #define fn_TIFFSetWarningHandler TIFFSetWarningHandler
6747 #define fn_TIFFOpen TIFFOpen
6748 #define fn_TIFFClientOpen TIFFClientOpen
6749 #define fn_TIFFGetField TIFFGetField
6750 #define fn_TIFFReadRGBAImage TIFFReadRGBAImage
6751 #define fn_TIFFClose TIFFClose
6753 #endif /* HAVE_NTGUI */
6756 /* Reading from a memory buffer for TIFF images Based on the PNG
6757 memory source, but we have to provide a lot of extra functions.
6758 Blah.
6760 We really only need to implement read and seek, but I am not
6761 convinced that the TIFF library is smart enough not to destroy
6762 itself if we only hand it the function pointers we need to
6763 override. */
6765 typedef struct
6767 unsigned char *bytes;
6768 size_t len;
6769 int index;
6771 tiff_memory_source;
6773 static size_t
6774 tiff_read_from_memory (data, buf, size)
6775 thandle_t data;
6776 tdata_t buf;
6777 tsize_t size;
6779 tiff_memory_source *src = (tiff_memory_source *) data;
6781 if (size > src->len - src->index)
6782 return (size_t) -1;
6783 bcopy (src->bytes + src->index, buf, size);
6784 src->index += size;
6785 return size;
6788 static size_t
6789 tiff_write_from_memory (data, buf, size)
6790 thandle_t data;
6791 tdata_t buf;
6792 tsize_t size;
6794 return (size_t) -1;
6797 static toff_t
6798 tiff_seek_in_memory (data, off, whence)
6799 thandle_t data;
6800 toff_t off;
6801 int whence;
6803 tiff_memory_source *src = (tiff_memory_source *) data;
6804 int idx;
6806 switch (whence)
6808 case SEEK_SET: /* Go from beginning of source. */
6809 idx = off;
6810 break;
6812 case SEEK_END: /* Go from end of source. */
6813 idx = src->len + off;
6814 break;
6816 case SEEK_CUR: /* Go from current position. */
6817 idx = src->index + off;
6818 break;
6820 default: /* Invalid `whence'. */
6821 return -1;
6824 if (idx > src->len || idx < 0)
6825 return -1;
6827 src->index = idx;
6828 return src->index;
6831 static int
6832 tiff_close_memory (data)
6833 thandle_t data;
6835 /* NOOP */
6836 return 0;
6839 static int
6840 tiff_mmap_memory (data, pbase, psize)
6841 thandle_t data;
6842 tdata_t *pbase;
6843 toff_t *psize;
6845 /* It is already _IN_ memory. */
6846 return 0;
6849 static void
6850 tiff_unmap_memory (data, base, size)
6851 thandle_t data;
6852 tdata_t base;
6853 toff_t size;
6855 /* We don't need to do this. */
6858 static toff_t
6859 tiff_size_of_memory (data)
6860 thandle_t data;
6862 return ((tiff_memory_source *) data)->len;
6866 static void
6867 tiff_error_handler (title, format, ap)
6868 const char *title, *format;
6869 va_list ap;
6871 char buf[512];
6872 int len;
6874 len = sprintf (buf, "TIFF error: %s ", title);
6875 vsprintf (buf + len, format, ap);
6876 add_to_log (buf, Qnil, Qnil);
6880 static void
6881 tiff_warning_handler (title, format, ap)
6882 const char *title, *format;
6883 va_list ap;
6885 char buf[512];
6886 int len;
6888 len = sprintf (buf, "TIFF warning: %s ", title);
6889 vsprintf (buf + len, format, ap);
6890 add_to_log (buf, Qnil, Qnil);
6894 /* Load TIFF image IMG for use on frame F. Value is non-zero if
6895 successful. */
6897 static int
6898 tiff_load (f, img)
6899 struct frame *f;
6900 struct image *img;
6902 Lisp_Object file, specified_file;
6903 Lisp_Object specified_data;
6904 TIFF *tiff;
6905 int width, height, x, y;
6906 uint32 *buf;
6907 int rc;
6908 XImagePtr ximg;
6909 struct gcpro gcpro1;
6910 tiff_memory_source memsrc;
6912 specified_file = image_spec_value (img->spec, QCfile, NULL);
6913 specified_data = image_spec_value (img->spec, QCdata, NULL);
6914 file = Qnil;
6915 GCPRO1 (file);
6917 fn_TIFFSetErrorHandler (tiff_error_handler);
6918 fn_TIFFSetWarningHandler (tiff_warning_handler);
6920 if (NILP (specified_data))
6922 /* Read from a file */
6923 file = x_find_image_file (specified_file);
6924 if (!STRINGP (file))
6926 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6927 UNGCPRO;
6928 return 0;
6931 /* Try to open the image file. */
6932 tiff = fn_TIFFOpen (SDATA (file), "r");
6933 if (tiff == NULL)
6935 image_error ("Cannot open `%s'", file, Qnil);
6936 UNGCPRO;
6937 return 0;
6940 else
6942 /* Memory source! */
6943 memsrc.bytes = SDATA (specified_data);
6944 memsrc.len = SBYTES (specified_data);
6945 memsrc.index = 0;
6947 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
6948 (TIFFReadWriteProc) tiff_read_from_memory,
6949 (TIFFReadWriteProc) tiff_write_from_memory,
6950 tiff_seek_in_memory,
6951 tiff_close_memory,
6952 tiff_size_of_memory,
6953 tiff_mmap_memory,
6954 tiff_unmap_memory);
6956 if (!tiff)
6958 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
6959 UNGCPRO;
6960 return 0;
6964 /* Get width and height of the image, and allocate a raster buffer
6965 of width x height 32-bit values. */
6966 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
6967 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6968 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
6970 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
6971 fn_TIFFClose (tiff);
6972 if (!rc)
6974 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
6975 xfree (buf);
6976 UNGCPRO;
6977 return 0;
6980 /* Create the X image and pixmap. */
6981 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6983 xfree (buf);
6984 UNGCPRO;
6985 return 0;
6988 /* Initialize the color table. */
6989 init_color_table ();
6991 /* Process the pixel raster. Origin is in the lower-left corner. */
6992 for (y = 0; y < height; ++y)
6994 uint32 *row = buf + y * width;
6996 for (x = 0; x < width; ++x)
6998 uint32 abgr = row[x];
6999 int r = TIFFGetR (abgr) << 8;
7000 int g = TIFFGetG (abgr) << 8;
7001 int b = TIFFGetB (abgr) << 8;
7002 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
7006 #ifdef COLOR_TABLE_SUPPORT
7007 /* Remember the colors allocated for the image. Free the color table. */
7008 img->colors = colors_in_color_table (&img->ncolors);
7009 free_color_table ();
7010 #endif /* COLOR_TABLE_SUPPORT */
7012 img->width = width;
7013 img->height = height;
7015 /* Maybe fill in the background field while we have ximg handy. */
7016 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7017 IMAGE_BACKGROUND (img, f, ximg);
7019 /* Put the image into the pixmap, then free the X image and its buffer. */
7020 x_put_x_image (f, ximg, img->pixmap, width, height);
7021 x_destroy_x_image (ximg);
7022 xfree (buf);
7024 UNGCPRO;
7025 return 1;
7028 #else /* HAVE_TIFF */
7030 #ifdef MAC_OS
7031 static int
7032 tiff_load (f, img)
7033 struct frame *f;
7034 struct image *img;
7036 return image_load_quicktime (f, img, kQTFileTypeTIFF);
7038 #endif /* MAC_OS */
7040 #endif /* !HAVE_TIFF */
7044 /***********************************************************************
7046 ***********************************************************************/
7048 #if defined (HAVE_GIF) || defined (MAC_OS)
7050 static int gif_image_p P_ ((Lisp_Object object));
7051 static int gif_load P_ ((struct frame *f, struct image *img));
7053 /* The symbol `gif' identifying images of this type. */
7055 Lisp_Object Qgif;
7057 /* Indices of image specification fields in gif_format, below. */
7059 enum gif_keyword_index
7061 GIF_TYPE,
7062 GIF_DATA,
7063 GIF_FILE,
7064 GIF_ASCENT,
7065 GIF_MARGIN,
7066 GIF_RELIEF,
7067 GIF_ALGORITHM,
7068 GIF_HEURISTIC_MASK,
7069 GIF_MASK,
7070 GIF_IMAGE,
7071 GIF_BACKGROUND,
7072 GIF_LAST
7075 /* Vector of image_keyword structures describing the format
7076 of valid user-defined image specifications. */
7078 static struct image_keyword gif_format[GIF_LAST] =
7080 {":type", IMAGE_SYMBOL_VALUE, 1},
7081 {":data", IMAGE_STRING_VALUE, 0},
7082 {":file", IMAGE_STRING_VALUE, 0},
7083 {":ascent", IMAGE_ASCENT_VALUE, 0},
7084 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7085 {":relief", IMAGE_INTEGER_VALUE, 0},
7086 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7087 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7088 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7089 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7090 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7093 /* Structure describing the image type `gif'. */
7095 static struct image_type gif_type =
7097 &Qgif,
7098 gif_image_p,
7099 gif_load,
7100 x_clear_image,
7101 NULL
7104 /* Return non-zero if OBJECT is a valid GIF image specification. */
7106 static int
7107 gif_image_p (object)
7108 Lisp_Object object;
7110 struct image_keyword fmt[GIF_LAST];
7111 bcopy (gif_format, fmt, sizeof fmt);
7113 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
7114 return 0;
7116 /* Must specify either the :data or :file keyword. */
7117 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7120 #endif /* HAVE_GIF || MAC_OS */
7122 #ifdef HAVE_GIF
7124 #if defined (HAVE_NTGUI) || defined (MAC_OS)
7125 /* avoid conflict with QuickdrawText.h */
7126 #define DrawText gif_DrawText
7127 #include <gif_lib.h>
7128 #undef DrawText
7130 #else /* HAVE_NTGUI || MAC_OS */
7132 #include <gif_lib.h>
7134 #endif /* HAVE_NTGUI || MAC_OS */
7137 #ifdef HAVE_NTGUI
7139 /* GIF library details. */
7140 DEF_IMGLIB_FN (DGifCloseFile);
7141 DEF_IMGLIB_FN (DGifSlurp);
7142 DEF_IMGLIB_FN (DGifOpen);
7143 DEF_IMGLIB_FN (DGifOpenFileName);
7145 static int
7146 init_gif_functions (Lisp_Object libraries)
7148 HMODULE library;
7150 if (!(library = w32_delayed_load (libraries, Qgif)))
7151 return 0;
7153 LOAD_IMGLIB_FN (library, DGifCloseFile);
7154 LOAD_IMGLIB_FN (library, DGifSlurp);
7155 LOAD_IMGLIB_FN (library, DGifOpen);
7156 LOAD_IMGLIB_FN (library, DGifOpenFileName);
7157 return 1;
7160 #else
7162 #define fn_DGifCloseFile DGifCloseFile
7163 #define fn_DGifSlurp DGifSlurp
7164 #define fn_DGifOpen DGifOpen
7165 #define fn_DGifOpenFileName DGifOpenFileName
7167 #endif /* HAVE_NTGUI */
7169 /* Reading a GIF image from memory
7170 Based on the PNG memory stuff to a certain extent. */
7172 typedef struct
7174 unsigned char *bytes;
7175 size_t len;
7176 int index;
7178 gif_memory_source;
7180 /* Make the current memory source available to gif_read_from_memory.
7181 It's done this way because not all versions of libungif support
7182 a UserData field in the GifFileType structure. */
7183 static gif_memory_source *current_gif_memory_src;
7185 static int
7186 gif_read_from_memory (file, buf, len)
7187 GifFileType *file;
7188 GifByteType *buf;
7189 int len;
7191 gif_memory_source *src = current_gif_memory_src;
7193 if (len > src->len - src->index)
7194 return -1;
7196 bcopy (src->bytes + src->index, buf, len);
7197 src->index += len;
7198 return len;
7202 /* Load GIF image IMG for use on frame F. Value is non-zero if
7203 successful. */
7205 static int
7206 gif_load (f, img)
7207 struct frame *f;
7208 struct image *img;
7210 Lisp_Object file, specified_file;
7211 Lisp_Object specified_data;
7212 int rc, width, height, x, y, i;
7213 XImagePtr ximg;
7214 ColorMapObject *gif_color_map;
7215 unsigned long pixel_colors[256];
7216 GifFileType *gif;
7217 struct gcpro gcpro1;
7218 Lisp_Object image;
7219 int ino, image_left, image_top, image_width, image_height;
7220 gif_memory_source memsrc;
7221 unsigned char *raster;
7223 specified_file = image_spec_value (img->spec, QCfile, NULL);
7224 specified_data = image_spec_value (img->spec, QCdata, NULL);
7225 file = Qnil;
7226 GCPRO1 (file);
7228 if (NILP (specified_data))
7230 file = x_find_image_file (specified_file);
7231 if (!STRINGP (file))
7233 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7234 UNGCPRO;
7235 return 0;
7238 /* Open the GIF file. */
7239 gif = fn_DGifOpenFileName (SDATA (file));
7240 if (gif == NULL)
7242 image_error ("Cannot open `%s'", file, Qnil);
7243 UNGCPRO;
7244 return 0;
7247 else
7249 /* Read from memory! */
7250 current_gif_memory_src = &memsrc;
7251 memsrc.bytes = SDATA (specified_data);
7252 memsrc.len = SBYTES (specified_data);
7253 memsrc.index = 0;
7255 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
7256 if (!gif)
7258 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
7259 UNGCPRO;
7260 return 0;
7264 /* Read entire contents. */
7265 rc = fn_DGifSlurp (gif);
7266 if (rc == GIF_ERROR)
7268 image_error ("Error reading `%s'", img->spec, Qnil);
7269 fn_DGifCloseFile (gif);
7270 UNGCPRO;
7271 return 0;
7274 image = image_spec_value (img->spec, QCindex, NULL);
7275 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7276 if (ino >= gif->ImageCount)
7278 image_error ("Invalid image number `%s' in image `%s'",
7279 image, img->spec);
7280 fn_DGifCloseFile (gif);
7281 UNGCPRO;
7282 return 0;
7285 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
7286 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
7288 /* Create the X image and pixmap. */
7289 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7291 fn_DGifCloseFile (gif);
7292 UNGCPRO;
7293 return 0;
7296 /* Allocate colors. */
7297 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
7298 if (!gif_color_map)
7299 gif_color_map = gif->SColorMap;
7300 init_color_table ();
7301 bzero (pixel_colors, sizeof pixel_colors);
7303 for (i = 0; i < gif_color_map->ColorCount; ++i)
7305 int r = gif_color_map->Colors[i].Red << 8;
7306 int g = gif_color_map->Colors[i].Green << 8;
7307 int b = gif_color_map->Colors[i].Blue << 8;
7308 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7311 #ifdef COLOR_TABLE_SUPPORT
7312 img->colors = colors_in_color_table (&img->ncolors);
7313 free_color_table ();
7314 #endif /* COLOR_TABLE_SUPPORT */
7316 /* Clear the part of the screen image that are not covered by
7317 the image from the GIF file. Full animated GIF support
7318 requires more than can be done here (see the gif89 spec,
7319 disposal methods). Let's simply assume that the part
7320 not covered by a sub-image is in the frame's background color. */
7321 image_top = gif->SavedImages[ino].ImageDesc.Top;
7322 image_left = gif->SavedImages[ino].ImageDesc.Left;
7323 image_width = gif->SavedImages[ino].ImageDesc.Width;
7324 image_height = gif->SavedImages[ino].ImageDesc.Height;
7326 for (y = 0; y < image_top; ++y)
7327 for (x = 0; x < width; ++x)
7328 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7330 for (y = image_top + image_height; y < height; ++y)
7331 for (x = 0; x < width; ++x)
7332 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7334 for (y = image_top; y < image_top + image_height; ++y)
7336 for (x = 0; x < image_left; ++x)
7337 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7338 for (x = image_left + image_width; x < width; ++x)
7339 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7342 /* Read the GIF image into the X image. We use a local variable
7343 `raster' here because RasterBits below is a char *, and invites
7344 problems with bytes >= 0x80. */
7345 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7347 if (gif->SavedImages[ino].ImageDesc.Interlace)
7349 static int interlace_start[] = {0, 4, 2, 1};
7350 static int interlace_increment[] = {8, 8, 4, 2};
7351 int pass;
7352 int row = interlace_start[0];
7354 pass = 0;
7356 for (y = 0; y < image_height; y++)
7358 if (row >= image_height)
7360 row = interlace_start[++pass];
7361 while (row >= image_height)
7362 row = interlace_start[++pass];
7365 for (x = 0; x < image_width; x++)
7367 int i = raster[(y * image_width) + x];
7368 XPutPixel (ximg, x + image_left, row + image_top,
7369 pixel_colors[i]);
7372 row += interlace_increment[pass];
7375 else
7377 for (y = 0; y < image_height; ++y)
7378 for (x = 0; x < image_width; ++x)
7380 int i = raster[y * image_width + x];
7381 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
7385 fn_DGifCloseFile (gif);
7387 /* Maybe fill in the background field while we have ximg handy. */
7388 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7389 IMAGE_BACKGROUND (img, f, ximg);
7391 /* Put the image into the pixmap, then free the X image and its buffer. */
7392 x_put_x_image (f, ximg, img->pixmap, width, height);
7393 x_destroy_x_image (ximg);
7395 UNGCPRO;
7396 return 1;
7399 #else
7401 #ifdef MAC_OS
7402 static int
7403 gif_load (f, img)
7404 struct frame *f;
7405 struct image *img;
7407 Lisp_Object specified_file, file;
7408 Lisp_Object specified_data;
7409 OSErr err;
7410 Boolean graphic_p, movie_p, prefer_graphic_p;
7411 Handle dh = NULL;
7412 Movie movie = NULL;
7413 Lisp_Object image;
7414 Track track = NULL;
7415 Media media = NULL;
7416 long nsamples;
7417 Rect rect;
7418 Lisp_Object specified_bg;
7419 XColor color;
7420 RGBColor bg_color;
7421 int width, height;
7422 XImagePtr ximg;
7423 TimeValue time;
7424 struct gcpro gcpro1;
7425 int ino;
7426 CGrafPtr old_port;
7427 GDHandle old_gdh;
7429 specified_file = image_spec_value (img->spec, QCfile, NULL);
7430 specified_data = image_spec_value (img->spec, QCdata, NULL);
7432 if (NILP (specified_data))
7434 /* Read from a file */
7435 FSSpec fss;
7436 short refnum;
7438 err = find_image_fsspec (specified_file, &file, &fss);
7439 if (err != noErr)
7441 if (err == fnfErr)
7442 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7443 else
7444 goto open_error;
7447 err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0,
7448 &graphic_p, &movie_p, &prefer_graphic_p, 0);
7449 if (err != noErr)
7450 goto open_error;
7452 if (!graphic_p && !movie_p)
7453 goto open_error;
7454 if (prefer_graphic_p)
7455 return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL);
7456 err = OpenMovieFile (&fss, &refnum, fsRdPerm);
7457 if (err != noErr)
7458 goto open_error;
7459 err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL);
7460 CloseMovieFile (refnum);
7461 if (err != noErr)
7463 image_error ("Error reading `%s'", file, Qnil);
7464 return 0;
7467 else
7469 /* Memory source! */
7470 Handle dref = NULL;
7471 long file_type_atom[3];
7473 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
7474 if (err != noErr)
7476 image_error ("Cannot allocate data handle for `%s'",
7477 img->spec, Qnil);
7478 goto error;
7481 file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3);
7482 file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
7483 file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF);
7484 err = PtrToHand (&dh, &dref, sizeof (Handle));
7485 if (err == noErr)
7486 /* no file name */
7487 err = PtrAndHand ("\p", dref, 1);
7488 if (err == noErr)
7489 err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3);
7490 if (err != noErr)
7492 image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil);
7493 goto error;
7495 err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p,
7496 &movie_p, &prefer_graphic_p, 0);
7497 if (err != noErr)
7498 goto open_error;
7500 if (!graphic_p && !movie_p)
7501 goto open_error;
7502 if (prefer_graphic_p)
7504 int success_p;
7506 DisposeHandle (dref);
7507 success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh);
7508 DisposeHandle (dh);
7509 return success_p;
7511 err = NewMovieFromDataRef (&movie, 0, NULL, dref,
7512 HandleDataHandlerSubType);
7513 DisposeHandle (dref);
7514 if (err != noErr)
7515 goto open_error;
7518 image = image_spec_value (img->spec, QCindex, NULL);
7519 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7520 track = GetMovieIndTrack (movie, 1);
7521 media = GetTrackMedia (track);
7522 nsamples = GetMediaSampleCount (media);
7523 if (ino >= nsamples)
7525 image_error ("Invalid image number `%s' in image `%s'",
7526 image, img->spec);
7527 goto error;
7530 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
7531 if (!STRINGP (specified_bg) ||
7532 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
7534 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7535 color.red = RED16_FROM_ULONG (color.pixel);
7536 color.green = GREEN16_FROM_ULONG (color.pixel);
7537 color.blue = BLUE16_FROM_ULONG (color.pixel);
7539 GetMovieBox (movie, &rect);
7540 width = img->width = rect.right - rect.left;
7541 height = img->height = rect.bottom - rect.top;
7542 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7543 goto error;
7545 GetGWorld (&old_port, &old_gdh);
7546 SetGWorld (ximg, NULL);
7547 bg_color.red = color.red;
7548 bg_color.green = color.green;
7549 bg_color.blue = color.blue;
7550 RGBBackColor (&bg_color);
7551 SetGWorld (old_port, old_gdh);
7552 SetMovieActive (movie, TRUE);
7553 SetMovieGWorld (movie, ximg, NULL);
7554 SampleNumToMediaTime (media, ino + 1, &time, NULL);
7555 SetMovieTimeValue (movie, time);
7556 MoviesTask (movie, 0L);
7557 DisposeTrackMedia (media);
7558 DisposeMovieTrack (track);
7559 DisposeMovie (movie);
7560 if (dh)
7561 DisposeHandle (dh);
7562 /* Maybe fill in the background field while we have ximg handy. */
7563 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7564 IMAGE_BACKGROUND (img, f, ximg);
7566 /* Put the image into the pixmap. */
7567 x_put_x_image (f, ximg, img->pixmap, width, height);
7568 x_destroy_x_image (ximg);
7569 return 1;
7571 open_error:
7572 image_error ("Cannot open `%s'", file, Qnil);
7573 error:
7574 if (media)
7575 DisposeTrackMedia (media);
7576 if (track)
7577 DisposeMovieTrack (track);
7578 if (movie)
7579 DisposeMovie (movie);
7580 if (dh)
7581 DisposeHandle (dh);
7582 return 0;
7584 #endif /* MAC_OS */
7586 #endif /* HAVE_GIF */
7590 /***********************************************************************
7591 Ghostscript
7592 ***********************************************************************/
7594 #ifdef HAVE_X_WINDOWS
7595 #define HAVE_GHOSTSCRIPT 1
7596 #endif /* HAVE_X_WINDOWS */
7598 /* The symbol `postscript' identifying images of this type. */
7600 Lisp_Object Qpostscript;
7602 #ifdef HAVE_GHOSTSCRIPT
7604 static int gs_image_p P_ ((Lisp_Object object));
7605 static int gs_load P_ ((struct frame *f, struct image *img));
7606 static void gs_clear_image P_ ((struct frame *f, struct image *img));
7608 /* Keyword symbols. */
7610 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
7612 /* Indices of image specification fields in gs_format, below. */
7614 enum gs_keyword_index
7616 GS_TYPE,
7617 GS_PT_WIDTH,
7618 GS_PT_HEIGHT,
7619 GS_FILE,
7620 GS_LOADER,
7621 GS_BOUNDING_BOX,
7622 GS_ASCENT,
7623 GS_MARGIN,
7624 GS_RELIEF,
7625 GS_ALGORITHM,
7626 GS_HEURISTIC_MASK,
7627 GS_MASK,
7628 GS_BACKGROUND,
7629 GS_LAST
7632 /* Vector of image_keyword structures describing the format
7633 of valid user-defined image specifications. */
7635 static struct image_keyword gs_format[GS_LAST] =
7637 {":type", IMAGE_SYMBOL_VALUE, 1},
7638 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7639 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7640 {":file", IMAGE_STRING_VALUE, 1},
7641 {":loader", IMAGE_FUNCTION_VALUE, 0},
7642 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7643 {":ascent", IMAGE_ASCENT_VALUE, 0},
7644 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7645 {":relief", IMAGE_INTEGER_VALUE, 0},
7646 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7647 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7648 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7649 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7652 /* Structure describing the image type `ghostscript'. */
7654 static struct image_type gs_type =
7656 &Qpostscript,
7657 gs_image_p,
7658 gs_load,
7659 gs_clear_image,
7660 NULL
7664 /* Free X resources of Ghostscript image IMG which is used on frame F. */
7666 static void
7667 gs_clear_image (f, img)
7668 struct frame *f;
7669 struct image *img;
7671 /* IMG->data.ptr_val may contain a recorded colormap. */
7672 xfree (img->data.ptr_val);
7673 x_clear_image (f, img);
7677 /* Return non-zero if OBJECT is a valid Ghostscript image
7678 specification. */
7680 static int
7681 gs_image_p (object)
7682 Lisp_Object object;
7684 struct image_keyword fmt[GS_LAST];
7685 Lisp_Object tem;
7686 int i;
7688 bcopy (gs_format, fmt, sizeof fmt);
7690 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
7691 return 0;
7693 /* Bounding box must be a list or vector containing 4 integers. */
7694 tem = fmt[GS_BOUNDING_BOX].value;
7695 if (CONSP (tem))
7697 for (i = 0; i < 4; ++i, tem = XCDR (tem))
7698 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
7699 return 0;
7700 if (!NILP (tem))
7701 return 0;
7703 else if (VECTORP (tem))
7705 if (XVECTOR (tem)->size != 4)
7706 return 0;
7707 for (i = 0; i < 4; ++i)
7708 if (!INTEGERP (XVECTOR (tem)->contents[i]))
7709 return 0;
7711 else
7712 return 0;
7714 return 1;
7718 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
7719 if successful. */
7721 static int
7722 gs_load (f, img)
7723 struct frame *f;
7724 struct image *img;
7726 char buffer[100];
7727 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
7728 struct gcpro gcpro1, gcpro2;
7729 Lisp_Object frame;
7730 double in_width, in_height;
7731 Lisp_Object pixel_colors = Qnil;
7733 /* Compute pixel size of pixmap needed from the given size in the
7734 image specification. Sizes in the specification are in pt. 1 pt
7735 = 1/72 in, xdpi and ydpi are stored in the frame's X display
7736 info. */
7737 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
7738 in_width = XFASTINT (pt_width) / 72.0;
7739 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
7740 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
7741 in_height = XFASTINT (pt_height) / 72.0;
7742 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
7744 /* Create the pixmap. */
7745 xassert (img->pixmap == NO_PIXMAP);
7747 /* Only W32 version did BLOCK_INPUT here. ++kfs */
7748 BLOCK_INPUT;
7749 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7750 img->width, img->height,
7751 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
7752 UNBLOCK_INPUT;
7754 if (!img->pixmap)
7756 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
7757 return 0;
7760 /* Call the loader to fill the pixmap. It returns a process object
7761 if successful. We do not record_unwind_protect here because
7762 other places in redisplay like calling window scroll functions
7763 don't either. Let the Lisp loader use `unwind-protect' instead. */
7764 GCPRO2 (window_and_pixmap_id, pixel_colors);
7766 sprintf (buffer, "%lu %lu",
7767 (unsigned long) FRAME_X_WINDOW (f),
7768 (unsigned long) img->pixmap);
7769 window_and_pixmap_id = build_string (buffer);
7771 sprintf (buffer, "%lu %lu",
7772 FRAME_FOREGROUND_PIXEL (f),
7773 FRAME_BACKGROUND_PIXEL (f));
7774 pixel_colors = build_string (buffer);
7776 XSETFRAME (frame, f);
7777 loader = image_spec_value (img->spec, QCloader, NULL);
7778 if (NILP (loader))
7779 loader = intern ("gs-load-image");
7781 img->data.lisp_val = call6 (loader, frame, img->spec,
7782 make_number (img->width),
7783 make_number (img->height),
7784 window_and_pixmap_id,
7785 pixel_colors);
7786 UNGCPRO;
7787 return PROCESSP (img->data.lisp_val);
7791 /* Kill the Ghostscript process that was started to fill PIXMAP on
7792 frame F. Called from XTread_socket when receiving an event
7793 telling Emacs that Ghostscript has finished drawing. */
7795 void
7796 x_kill_gs_process (pixmap, f)
7797 Pixmap pixmap;
7798 struct frame *f;
7800 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7801 int class, i;
7802 struct image *img;
7804 /* Find the image containing PIXMAP. */
7805 for (i = 0; i < c->used; ++i)
7806 if (c->images[i]->pixmap == pixmap)
7807 break;
7809 /* Should someone in between have cleared the image cache, for
7810 instance, give up. */
7811 if (i == c->used)
7812 return;
7814 /* Kill the GS process. We should have found PIXMAP in the image
7815 cache and its image should contain a process object. */
7816 img = c->images[i];
7817 xassert (PROCESSP (img->data.lisp_val));
7818 Fkill_process (img->data.lisp_val, Qnil);
7819 img->data.lisp_val = Qnil;
7821 #if defined (HAVE_X_WINDOWS)
7823 /* On displays with a mutable colormap, figure out the colors
7824 allocated for the image by looking at the pixels of an XImage for
7825 img->pixmap. */
7826 class = FRAME_X_VISUAL (f)->class;
7827 if (class != StaticColor && class != StaticGray && class != TrueColor)
7829 XImagePtr ximg;
7831 BLOCK_INPUT;
7833 /* Try to get an XImage for img->pixmep. */
7834 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7835 0, 0, img->width, img->height, ~0, ZPixmap);
7836 if (ximg)
7838 int x, y;
7840 /* Initialize the color table. */
7841 init_color_table ();
7843 /* For each pixel of the image, look its color up in the
7844 color table. After having done so, the color table will
7845 contain an entry for each color used by the image. */
7846 for (y = 0; y < img->height; ++y)
7847 for (x = 0; x < img->width; ++x)
7849 unsigned long pixel = XGetPixel (ximg, x, y);
7850 lookup_pixel_color (f, pixel);
7853 /* Record colors in the image. Free color table and XImage. */
7854 #ifdef COLOR_TABLE_SUPPORT
7855 img->colors = colors_in_color_table (&img->ncolors);
7856 free_color_table ();
7857 #endif
7858 XDestroyImage (ximg);
7860 #if 0 /* This doesn't seem to be the case. If we free the colors
7861 here, we get a BadAccess later in x_clear_image when
7862 freeing the colors. */
7863 /* We have allocated colors once, but Ghostscript has also
7864 allocated colors on behalf of us. So, to get the
7865 reference counts right, free them once. */
7866 if (img->ncolors)
7867 x_free_colors (f, img->colors, img->ncolors);
7868 #endif
7870 else
7871 image_error ("Cannot get X image of `%s'; colors will not be freed",
7872 img->spec, Qnil);
7874 UNBLOCK_INPUT;
7876 #endif /* HAVE_X_WINDOWS */
7878 /* Now that we have the pixmap, compute mask and transform the
7879 image if requested. */
7880 BLOCK_INPUT;
7881 postprocess_image (f, img);
7882 UNBLOCK_INPUT;
7885 #endif /* HAVE_GHOSTSCRIPT */
7888 /***********************************************************************
7889 Tests
7890 ***********************************************************************/
7892 #if GLYPH_DEBUG
7894 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
7895 doc: /* Value is non-nil if SPEC is a valid image specification. */)
7896 (spec)
7897 Lisp_Object spec;
7899 return valid_image_p (spec) ? Qt : Qnil;
7903 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
7904 (spec)
7905 Lisp_Object spec;
7907 int id = -1;
7909 if (valid_image_p (spec))
7910 id = lookup_image (SELECTED_FRAME (), spec);
7912 debug_print (spec);
7913 return make_number (id);
7916 #endif /* GLYPH_DEBUG != 0 */
7919 /***********************************************************************
7920 Initialization
7921 ***********************************************************************/
7923 #ifdef HAVE_NTGUI
7924 /* Image types that rely on external libraries are loaded dynamically
7925 if the library is available. */
7926 #define CHECK_LIB_AVAILABLE(image_type, init_lib_fn) \
7927 define_image_type (image_type, init_lib_fn (libraries))
7928 #else
7929 #define CHECK_LIB_AVAILABLE(image_type, init_lib_fn) \
7930 define_image_type (image_type, TRUE)
7931 #endif /* HAVE_NTGUI */
7933 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
7934 doc: /* Initialize image library implementing image type TYPE.
7935 Return non-nil if TYPE is a supported image type.
7937 Image types pbm and xbm are prebuilt; other types are loaded here.
7938 Libraries to load are specified in alist LIBRARIES (usually, the value
7939 of `image-library-alist', which see. */)
7940 (type, libraries)
7942 Lisp_Object tested;
7944 /* Don't try to reload the library. */
7945 tested = Fassq (type, Vimage_type_cache);
7946 if (CONSP (tested))
7947 return XCDR (tested);
7949 #if defined (HAVE_XPM) || defined (MAC_OS)
7950 if (EQ (type, Qxpm))
7951 return CHECK_LIB_AVAILABLE(&xpm_type, init_xpm_functions);
7952 #endif
7954 #if defined (HAVE_JPEG) || defined (MAC_OS)
7955 if (EQ (type, Qjpeg))
7956 return CHECK_LIB_AVAILABLE(&jpeg_type, init_jpeg_functions);
7957 #endif
7959 #if defined (HAVE_TIFF) || defined (MAC_OS)
7960 if (EQ (type, Qtiff))
7961 return CHECK_LIB_AVAILABLE(&tiff_type, init_tiff_functions);
7962 #endif
7964 #if defined (HAVE_GIF) || defined (MAC_OS)
7965 if (EQ (type, Qgif))
7966 return CHECK_LIB_AVAILABLE(&gif_type, init_gif_functions);
7967 #endif
7969 #if defined (HAVE_PNG) || defined (MAC_OS)
7970 if (EQ (type, Qpng))
7971 return CHECK_LIB_AVAILABLE(&png_type, init_png_functions);
7972 #endif
7974 #ifdef HAVE_GHOSTSCRIPT
7975 if (EQ (type, Qpostscript))
7976 return CHECK_LIB_AVAILABLE(&gs_type, init_gs_functions);
7977 #endif
7979 /* If the type is not recognized, avoid testing it ever again. */
7980 CACHE_IMAGE_TYPE(type, Qnil);
7981 return Qnil;
7984 void
7985 syms_of_image ()
7987 /* Must be defined now becase we're going to update it below, while
7988 defining the supported image types. */
7989 DEFVAR_LISP ("image-types", &Vimage_types,
7990 doc: /* List of potentially supported image types.
7991 Each element of the list is a symbol for a image type, like 'jpeg or 'png.
7992 To check whether it is really supported, use `image-type-available-p'. */);
7993 Vimage_types = Qnil;
7995 Vimage_type_cache = Qnil;
7996 staticpro (&Vimage_type_cache);
7998 QCascent = intern (":ascent");
7999 staticpro (&QCascent);
8000 QCmargin = intern (":margin");
8001 staticpro (&QCmargin);
8002 QCrelief = intern (":relief");
8003 staticpro (&QCrelief);
8004 QCconversion = intern (":conversion");
8005 staticpro (&QCconversion);
8006 QCcolor_symbols = intern (":color-symbols");
8007 staticpro (&QCcolor_symbols);
8008 QCheuristic_mask = intern (":heuristic-mask");
8009 staticpro (&QCheuristic_mask);
8010 QCindex = intern (":index");
8011 staticpro (&QCindex);
8012 QCmatrix = intern (":matrix");
8013 staticpro (&QCmatrix);
8014 QCcolor_adjustment = intern (":color-adjustment");
8015 staticpro (&QCcolor_adjustment);
8016 QCmask = intern (":mask");
8017 staticpro (&QCmask);
8019 Qlaplace = intern ("laplace");
8020 staticpro (&Qlaplace);
8021 Qemboss = intern ("emboss");
8022 staticpro (&Qemboss);
8023 Qedge_detection = intern ("edge-detection");
8024 staticpro (&Qedge_detection);
8025 Qheuristic = intern ("heuristic");
8026 staticpro (&Qheuristic);
8028 Qpostscript = intern ("postscript");
8029 staticpro (&Qpostscript);
8030 #ifdef HAVE_GHOSTSCRIPT
8031 ADD_IMAGE_TYPE(Qpostscript);
8032 QCloader = intern (":loader");
8033 staticpro (&QCloader);
8034 QCbounding_box = intern (":bounding-box");
8035 staticpro (&QCbounding_box);
8036 QCpt_width = intern (":pt-width");
8037 staticpro (&QCpt_width);
8038 QCpt_height = intern (":pt-height");
8039 staticpro (&QCpt_height);
8040 #endif /* HAVE_GHOSTSCRIPT */
8042 Qpbm = intern ("pbm");
8043 staticpro (&Qpbm);
8044 ADD_IMAGE_TYPE(Qpbm);
8046 Qxbm = intern ("xbm");
8047 staticpro (&Qxbm);
8048 ADD_IMAGE_TYPE(Qxbm);
8050 #if defined (HAVE_XPM) || defined (MAC_OS)
8051 Qxpm = intern ("xpm");
8052 staticpro (&Qxpm);
8053 ADD_IMAGE_TYPE(Qxpm);
8054 #endif
8056 #if defined (HAVE_JPEG) || defined (MAC_OS)
8057 Qjpeg = intern ("jpeg");
8058 staticpro (&Qjpeg);
8059 ADD_IMAGE_TYPE(Qjpeg);
8060 #endif
8062 #if defined (HAVE_TIFF) || defined (MAC_OS)
8063 Qtiff = intern ("tiff");
8064 staticpro (&Qtiff);
8065 ADD_IMAGE_TYPE(Qtiff);
8066 #endif
8068 #if defined (HAVE_GIF) || defined (MAC_OS)
8069 Qgif = intern ("gif");
8070 staticpro (&Qgif);
8071 ADD_IMAGE_TYPE(Qgif);
8072 #endif
8074 #if defined (HAVE_PNG) || defined (MAC_OS)
8075 Qpng = intern ("png");
8076 staticpro (&Qpng);
8077 ADD_IMAGE_TYPE(Qpng);
8078 #endif
8080 defsubr (&Sinit_image_library);
8081 defsubr (&Sclear_image_cache);
8082 defsubr (&Simage_size);
8083 defsubr (&Simage_mask_p);
8085 #if GLYPH_DEBUG
8086 defsubr (&Simagep);
8087 defsubr (&Slookup_image);
8088 #endif
8090 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
8091 doc: /* Non-nil means always draw a cross over disabled images.
8092 Disabled images are those having an `:conversion disabled' property.
8093 A cross is always drawn on black & white displays. */);
8094 cross_disabled_images = 0;
8096 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
8097 doc: /* List of directories to search for window system bitmap files. */);
8098 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
8100 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
8101 doc: /* Time after which cached images are removed from the cache.
8102 When an image has not been displayed this many seconds, remove it
8103 from the image cache. Value must be an integer or nil with nil
8104 meaning don't clear the cache. */);
8105 Vimage_cache_eviction_delay = make_number (30 * 60);
8108 void
8109 init_image ()
8111 image_types = NULL;
8113 define_image_type (&xbm_type, TRUE);
8114 define_image_type (&pbm_type, TRUE);
8116 #ifdef MAC_OS
8117 /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */
8118 EnterMovies ();
8119 #ifdef MAC_OSX
8120 init_image_func_pointer ();
8121 #endif
8122 #endif
8125 /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
8126 (do not change this comment) */