2004-06-03 Karl Fogel <kfogel@red-bean.com>
[emacs.git] / src / image.c
blob3c53903b4b4cf88e9bf5fd3ae93b186a317064e1
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>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
31 /* This makes the fields of a Display accessible, in Xlib header files. */
33 #define XLIB_ILLEGAL_ACCESS
35 #include "lisp.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "dispextern.h"
39 #include "blockinput.h"
40 #include "systime.h"
41 #include <epaths.h>
44 #ifdef HAVE_X_WINDOWS
45 #include "xterm.h"
46 #include <sys/types.h>
47 #include <sys/stat.h>
49 #define COLOR_TABLE_SUPPORT 1
51 typedef struct x_bitmap_record Bitmap_Record;
52 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
53 #define NO_PIXMAP None
55 #define RGB_PIXEL_COLOR unsigned long
57 #define PIX_MASK_RETAIN(f) 0
58 #define PIX_MASK_DRAW(f) 1
59 #endif /* HAVE_X_WINDOWS */
62 #ifdef HAVE_NTGUI
63 #include "w32term.h"
65 /* W32_TODO : Color tables on W32. */
66 #undef COLOR_TABLE_SUPPORT
68 typedef struct w32_bitmap_record Bitmap_Record;
69 #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
70 #define NO_PIXMAP 0
72 #define RGB_PIXEL_COLOR COLORREF
74 #define PIX_MASK_RETAIN(f) 0
75 #define PIX_MASK_DRAW(f) 1
77 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
78 #define x_defined_color w32_defined_color
79 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
80 #endif /* HAVE_NTGUI */
83 #ifdef MAC_OS
84 #include "macterm.h"
85 #ifndef MAC_OSX
86 #include <alloca.h>
87 #endif
88 #ifdef MAC_OSX
89 #include <sys/stat.h>
90 #include <QuickTime/QuickTime.h>
91 #else /* not MAC_OSX */
92 #include <Windows.h>
93 #include <Gestalt.h>
94 #include <TextUtils.h>
95 #endif /* not MAC_OSX */
97 /* MAC_TODO : Color tables on Mac. */
98 #undef COLOR_TABLE_SUPPORT
100 #define ZPixmap 0 /* arbitrary */
101 typedef struct mac_bitmap_record Bitmap_Record;
103 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
104 #define NO_PIXMAP 0
106 #define RGB_PIXEL_COLOR unsigned long
108 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
109 #define x_defined_color mac_defined_color
110 #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
111 #define XDrawLine(display, w, gc, x1, y1, x2, y2) \
112 mac_draw_line_to_pixmap(display, w, gc, x1, y1, x2, y2)
114 #endif /* MAC_OS */
117 /* Search path for bitmap files. */
119 Lisp_Object Vx_bitmap_file_path;
122 static void x_disable_image P_ ((struct frame *, struct image *));
123 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
124 Lisp_Object));
126 static void init_color_table P_ ((void));
127 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
128 #ifdef COLOR_TABLE_SUPPORT
129 static void free_color_table P_ ((void));
130 static unsigned long *colors_in_color_table P_ ((int *n));
131 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
132 #endif
134 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
135 id, which is just an int that this section returns. Bitmaps are
136 reference counted so they can be shared among frames.
138 Bitmap indices are guaranteed to be > 0, so a negative number can
139 be used to indicate no bitmap.
141 If you use x_create_bitmap_from_data, then you must keep track of
142 the bitmaps yourself. That is, creating a bitmap from the same
143 data more than once will not be caught. */
145 #ifdef MAC_OS
147 static XImagePtr
148 XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
149 Display *display; /* not used */
150 Pixmap pixmap;
151 int x, y; /* not used */
152 unsigned int width, height; /* not used */
153 unsigned long plane_mask; /* not used */
154 int format; /* not used */
156 #if GLYPH_DEBUG
157 xassert (x == 0 && y == 0);
159 Rect ri, rp;
160 SetRect (&ri, 0, 0, width, height);
161 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
163 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
164 #endif
166 LockPixels (GetGWorldPixMap (pixmap));
168 return pixmap;
171 static void
172 XPutPixel (ximage, x, y, pixel)
173 XImagePtr ximage;
174 int x, y;
175 unsigned long pixel;
177 CGrafPtr old_port;
178 GDHandle old_gdh;
179 RGBColor color;
181 GetGWorld (&old_port, &old_gdh);
182 SetGWorld (ximage, NULL);
184 color.red = RED16_FROM_ULONG (pixel);
185 color.green = GREEN16_FROM_ULONG (pixel);
186 color.blue = BLUE16_FROM_ULONG (pixel);
187 SetCPixel (x, y, &color);
189 SetGWorld (old_port, old_gdh);
192 static unsigned long
193 XGetPixel (ximage, x, y)
194 XImagePtr ximage;
195 int x, y;
197 CGrafPtr old_port;
198 GDHandle old_gdh;
199 RGBColor color;
201 GetGWorld (&old_port, &old_gdh);
202 SetGWorld (ximage, NULL);
204 GetCPixel (x, y, &color);
206 SetGWorld (old_port, old_gdh);
207 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
210 static void
211 XDestroyImage (ximg)
212 XImagePtr ximg;
214 UnlockPixels (GetGWorldPixMap (ximg));
216 #endif /* MAC_OS */
219 /* Functions to access the contents of a bitmap, given an id. */
222 x_bitmap_height (f, id)
223 FRAME_PTR f;
224 int id;
226 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
230 x_bitmap_width (f, id)
231 FRAME_PTR f;
232 int id;
234 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
237 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
239 x_bitmap_pixmap (f, id)
240 FRAME_PTR f;
241 int id;
243 return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
245 #endif
247 #ifdef HAVE_X_WINDOWS
249 x_bitmap_mask (f, id)
250 FRAME_PTR f;
251 int id;
253 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
255 #endif
257 /* Allocate a new bitmap record. Returns index of new record. */
259 static int
260 x_allocate_bitmap_record (f)
261 FRAME_PTR f;
263 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
264 int i;
266 if (dpyinfo->bitmaps == NULL)
268 dpyinfo->bitmaps_size = 10;
269 dpyinfo->bitmaps
270 = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
271 dpyinfo->bitmaps_last = 1;
272 return 1;
275 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
276 return ++dpyinfo->bitmaps_last;
278 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
279 if (dpyinfo->bitmaps[i].refcount == 0)
280 return i + 1;
282 dpyinfo->bitmaps_size *= 2;
283 dpyinfo->bitmaps
284 = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
285 dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
286 return ++dpyinfo->bitmaps_last;
289 /* Add one reference to the reference count of the bitmap with id ID. */
291 void
292 x_reference_bitmap (f, id)
293 FRAME_PTR f;
294 int id;
296 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
299 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
302 x_create_bitmap_from_data (f, bits, width, height)
303 struct frame *f;
304 char *bits;
305 unsigned int width, height;
307 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
308 int id;
310 #ifdef HAVE_X_WINDOWS
311 Pixmap bitmap;
312 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
313 bits, width, height);
314 if (! bitmap)
315 return -1;
316 #endif /* HAVE_X_WINDOWS */
318 #ifdef HAVE_NTGUI
319 Pixmap bitmap;
320 bitmap = CreateBitmap (width, height,
321 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
322 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
323 bits);
324 if (! bitmap)
325 return -1;
326 #endif /* HAVE_NTGUI */
328 #ifdef MAC_OS
329 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
330 if (width % 16 != 0)
331 return -1;
332 #endif
334 id = x_allocate_bitmap_record (f);
335 #ifdef MAC_OS
336 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
337 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
338 return -1;
339 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
340 #endif /* MAC_OS */
342 dpyinfo->bitmaps[id - 1].file = NULL;
343 dpyinfo->bitmaps[id - 1].height = height;
344 dpyinfo->bitmaps[id - 1].width = width;
345 dpyinfo->bitmaps[id - 1].refcount = 1;
347 #ifdef HAVE_X_WINDOWS
348 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
349 dpyinfo->bitmaps[id - 1].have_mask = 0;
350 dpyinfo->bitmaps[id - 1].depth = 1;
351 #endif /* HAVE_X_WINDOWS */
353 #ifdef HAVE_NTGUI
354 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
355 dpyinfo->bitmaps[id - 1].hinst = NULL;
356 dpyinfo->bitmaps[id - 1].depth = 1;
357 #endif /* HAVE_NTGUI */
359 return id;
362 /* Create bitmap from file FILE for frame F. */
365 x_create_bitmap_from_file (f, file)
366 struct frame *f;
367 Lisp_Object file;
369 #ifdef MAC_OS
370 return -1; /* MAC_TODO : bitmap support */
371 #endif /* MAC_OS */
373 #ifdef HAVE_NTGUI
374 return -1; /* W32_TODO : bitmap support */
375 #endif /* HAVE_NTGUI */
377 #ifdef HAVE_X_WINDOWS
378 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
379 unsigned int width, height;
380 Pixmap bitmap;
381 int xhot, yhot, result, id;
382 Lisp_Object found;
383 int fd;
384 char *filename;
386 /* Look for an existing bitmap with the same name. */
387 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
389 if (dpyinfo->bitmaps[id].refcount
390 && dpyinfo->bitmaps[id].file
391 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
393 ++dpyinfo->bitmaps[id].refcount;
394 return id + 1;
398 /* Search bitmap-file-path for the file, if appropriate. */
399 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
400 if (fd < 0)
401 return -1;
402 emacs_close (fd);
404 filename = (char *) SDATA (found);
406 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
407 filename, &width, &height, &bitmap, &xhot, &yhot);
408 if (result != BitmapSuccess)
409 return -1;
411 id = x_allocate_bitmap_record (f);
412 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
413 dpyinfo->bitmaps[id - 1].have_mask = 0;
414 dpyinfo->bitmaps[id - 1].refcount = 1;
415 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
416 dpyinfo->bitmaps[id - 1].depth = 1;
417 dpyinfo->bitmaps[id - 1].height = height;
418 dpyinfo->bitmaps[id - 1].width = width;
419 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
421 return id;
422 #endif /* HAVE_X_WINDOWS */
425 /* Free bitmap B. */
427 static void
428 Free_Bitmap_Record (dpyinfo, bm)
429 Display_Info *dpyinfo;
430 Bitmap_Record *bm;
432 #ifdef HAVE_X_WINDOWS
433 XFreePixmap (dpyinfo->display, bm->pixmap);
434 if (bm->have_mask)
435 XFreePixmap (dpyinfo->display, bm->mask);
436 #endif /* HAVE_X_WINDOWS */
438 #ifdef HAVE_NTGUI
439 DeleteObject (bm->pixmap);
440 #endif /* HAVE_NTGUI */
442 #ifdef MAC_OS
443 xfree (bm->bitmap_data); /* Added ++kfs */
444 bm->bitmap_data = NULL;
445 #endif /* MAC_OS */
447 if (bm->file)
449 xfree (bm->file);
450 bm->file = NULL;
454 /* Remove reference to bitmap with id number ID. */
456 void
457 x_destroy_bitmap (f, id)
458 FRAME_PTR f;
459 int id;
461 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
463 if (id > 0)
465 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
467 if (--bm->refcount == 0)
469 BLOCK_INPUT;
470 Free_Bitmap_Record (dpyinfo, bm);
471 UNBLOCK_INPUT;
476 /* Free all the bitmaps for the display specified by DPYINFO. */
478 void
479 x_destroy_all_bitmaps (dpyinfo)
480 Display_Info *dpyinfo;
482 int i;
483 Bitmap_Record *bm = dpyinfo->bitmaps;
485 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
486 if (bm->refcount > 0)
487 Free_Bitmap_Record (dpyinfo, bm);
489 dpyinfo->bitmaps_last = 0;
493 #ifdef HAVE_X_WINDOWS
495 /* Useful functions defined in the section
496 `Image type independent image structures' below. */
498 static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
499 unsigned long height));
501 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
502 int depth, XImagePtr *ximg,
503 Pixmap *pixmap));
505 static void x_destroy_x_image P_ ((XImagePtr ximg));
508 /* Create a mask of a bitmap. Note is this not a perfect mask.
509 It's nicer with some borders in this context */
512 x_create_bitmap_mask (f, id)
513 struct frame *f;
514 int id;
516 Pixmap pixmap, mask;
517 XImagePtr ximg, mask_img;
518 unsigned long width, height;
519 int result;
520 unsigned long bg;
521 unsigned long x, y, xp, xm, yp, ym;
522 GC gc;
524 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
526 if (!(id > 0))
527 return -1;
529 pixmap = x_bitmap_pixmap (f, id);
530 width = x_bitmap_width (f, id);
531 height = x_bitmap_height (f, id);
533 BLOCK_INPUT;
534 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
535 ~0, ZPixmap);
537 if (!ximg)
539 UNBLOCK_INPUT;
540 return -1;
543 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
545 UNBLOCK_INPUT;
546 if (!result)
548 XDestroyImage (ximg);
549 return -1;
552 bg = four_corners_best (ximg, width, height);
554 for (y = 0; y < ximg->height; ++y)
556 for (x = 0; x < ximg->width; ++x)
558 xp = x != ximg->width - 1 ? x + 1 : 0;
559 xm = x != 0 ? x - 1 : ximg->width - 1;
560 yp = y != ximg->height - 1 ? y + 1 : 0;
561 ym = y != 0 ? y - 1 : ximg->height - 1;
562 if (XGetPixel (ximg, x, y) == bg
563 && XGetPixel (ximg, x, yp) == bg
564 && XGetPixel (ximg, x, ym) == bg
565 && XGetPixel (ximg, xp, y) == bg
566 && XGetPixel (ximg, xp, yp) == bg
567 && XGetPixel (ximg, xp, ym) == bg
568 && XGetPixel (ximg, xm, y) == bg
569 && XGetPixel (ximg, xm, yp) == bg
570 && XGetPixel (ximg, xm, ym) == bg)
571 XPutPixel (mask_img, x, y, 0);
572 else
573 XPutPixel (mask_img, x, y, 1);
577 xassert (interrupt_input_blocked);
578 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
579 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
580 width, height);
581 XFreeGC (FRAME_X_DISPLAY (f), gc);
583 dpyinfo->bitmaps[id - 1].have_mask = 1;
584 dpyinfo->bitmaps[id - 1].mask = mask;
586 XDestroyImage (ximg);
587 x_destroy_x_image (mask_img);
589 return 0;
592 #endif /* HAVE_X_WINDOWS */
595 /***********************************************************************
596 Image types
597 ***********************************************************************/
599 /* Value is the number of elements of vector VECTOR. */
601 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
603 /* List of supported image types. Use define_image_type to add new
604 types. Use lookup_image_type to find a type for a given symbol. */
606 static struct image_type *image_types;
608 /* The symbol `xbm' which is used as the type symbol for XBM images. */
610 Lisp_Object Qxbm;
612 /* Keywords. */
614 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
615 extern Lisp_Object QCdata, QCtype;
616 extern Lisp_Object Qcenter;
617 Lisp_Object QCascent, QCmargin, QCrelief;
618 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
619 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
621 /* Other symbols. */
623 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
625 /* Time in seconds after which images should be removed from the cache
626 if not displayed. */
628 Lisp_Object Vimage_cache_eviction_delay;
630 /* Function prototypes. */
632 static void define_image_type P_ ((struct image_type *type));
633 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
634 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
635 static void x_laplace P_ ((struct frame *, struct image *));
636 static void x_emboss P_ ((struct frame *, struct image *));
637 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
638 Lisp_Object));
641 /* Define a new image type from TYPE. This adds a copy of TYPE to
642 image_types and adds the symbol *TYPE->type to Vimage_types. */
644 static void
645 define_image_type (type)
646 struct image_type *type;
648 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
649 The initialized data segment is read-only. */
650 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
651 bcopy (type, p, sizeof *p);
652 p->next = image_types;
653 image_types = p;
654 Vimage_types = Fcons (*p->type, Vimage_types);
658 /* Look up image type SYMBOL, and return a pointer to its image_type
659 structure. Value is null if SYMBOL is not a known image type. */
661 static INLINE struct image_type *
662 lookup_image_type (symbol)
663 Lisp_Object symbol;
665 struct image_type *type;
667 for (type = image_types; type; type = type->next)
668 if (EQ (symbol, *type->type))
669 break;
671 return type;
675 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
676 valid image specification is a list whose car is the symbol
677 `image', and whose rest is a property list. The property list must
678 contain a value for key `:type'. That value must be the name of a
679 supported image type. The rest of the property list depends on the
680 image type. */
683 valid_image_p (object)
684 Lisp_Object object;
686 int valid_p = 0;
688 if (IMAGEP (object))
690 Lisp_Object tem;
692 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
693 if (EQ (XCAR (tem), QCtype))
695 tem = XCDR (tem);
696 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
698 struct image_type *type;
699 type = lookup_image_type (XCAR (tem));
700 if (type)
701 valid_p = type->valid_p (object);
704 break;
708 return valid_p;
712 /* Log error message with format string FORMAT and argument ARG.
713 Signaling an error, e.g. when an image cannot be loaded, is not a
714 good idea because this would interrupt redisplay, and the error
715 message display would lead to another redisplay. This function
716 therefore simply displays a message. */
718 static void
719 image_error (format, arg1, arg2)
720 char *format;
721 Lisp_Object arg1, arg2;
723 add_to_log (format, arg1, arg2);
728 /***********************************************************************
729 Image specifications
730 ***********************************************************************/
732 enum image_value_type
734 IMAGE_DONT_CHECK_VALUE_TYPE,
735 IMAGE_STRING_VALUE,
736 IMAGE_STRING_OR_NIL_VALUE,
737 IMAGE_SYMBOL_VALUE,
738 IMAGE_POSITIVE_INTEGER_VALUE,
739 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
740 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
741 IMAGE_ASCENT_VALUE,
742 IMAGE_INTEGER_VALUE,
743 IMAGE_FUNCTION_VALUE,
744 IMAGE_NUMBER_VALUE,
745 IMAGE_BOOL_VALUE
748 /* Structure used when parsing image specifications. */
750 struct image_keyword
752 /* Name of keyword. */
753 char *name;
755 /* The type of value allowed. */
756 enum image_value_type type;
758 /* Non-zero means key must be present. */
759 int mandatory_p;
761 /* Used to recognize duplicate keywords in a property list. */
762 int count;
764 /* The value that was found. */
765 Lisp_Object value;
769 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
770 int, Lisp_Object));
771 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
774 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
775 has the format (image KEYWORD VALUE ...). One of the keyword/
776 value pairs must be `:type TYPE'. KEYWORDS is a vector of
777 image_keywords structures of size NKEYWORDS describing other
778 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
780 static int
781 parse_image_spec (spec, keywords, nkeywords, type)
782 Lisp_Object spec;
783 struct image_keyword *keywords;
784 int nkeywords;
785 Lisp_Object type;
787 int i;
788 Lisp_Object plist;
790 if (!IMAGEP (spec))
791 return 0;
793 plist = XCDR (spec);
794 while (CONSP (plist))
796 Lisp_Object key, value;
798 /* First element of a pair must be a symbol. */
799 key = XCAR (plist);
800 plist = XCDR (plist);
801 if (!SYMBOLP (key))
802 return 0;
804 /* There must follow a value. */
805 if (!CONSP (plist))
806 return 0;
807 value = XCAR (plist);
808 plist = XCDR (plist);
810 /* Find key in KEYWORDS. Error if not found. */
811 for (i = 0; i < nkeywords; ++i)
812 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
813 break;
815 if (i == nkeywords)
816 continue;
818 /* Record that we recognized the keyword. If a keywords
819 was found more than once, it's an error. */
820 keywords[i].value = value;
821 ++keywords[i].count;
823 if (keywords[i].count > 1)
824 return 0;
826 /* Check type of value against allowed type. */
827 switch (keywords[i].type)
829 case IMAGE_STRING_VALUE:
830 if (!STRINGP (value))
831 return 0;
832 break;
834 case IMAGE_STRING_OR_NIL_VALUE:
835 if (!STRINGP (value) && !NILP (value))
836 return 0;
837 break;
839 case IMAGE_SYMBOL_VALUE:
840 if (!SYMBOLP (value))
841 return 0;
842 break;
844 case IMAGE_POSITIVE_INTEGER_VALUE:
845 if (!INTEGERP (value) || XINT (value) <= 0)
846 return 0;
847 break;
849 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
850 if (INTEGERP (value) && XINT (value) >= 0)
851 break;
852 if (CONSP (value)
853 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
854 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
855 break;
856 return 0;
858 case IMAGE_ASCENT_VALUE:
859 if (SYMBOLP (value) && EQ (value, Qcenter))
860 break;
861 else if (INTEGERP (value)
862 && XINT (value) >= 0
863 && XINT (value) <= 100)
864 break;
865 return 0;
867 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
868 if (!INTEGERP (value) || XINT (value) < 0)
869 return 0;
870 break;
872 case IMAGE_DONT_CHECK_VALUE_TYPE:
873 break;
875 case IMAGE_FUNCTION_VALUE:
876 value = indirect_function (value);
877 if (SUBRP (value)
878 || COMPILEDP (value)
879 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
880 break;
881 return 0;
883 case IMAGE_NUMBER_VALUE:
884 if (!INTEGERP (value) && !FLOATP (value))
885 return 0;
886 break;
888 case IMAGE_INTEGER_VALUE:
889 if (!INTEGERP (value))
890 return 0;
891 break;
893 case IMAGE_BOOL_VALUE:
894 if (!NILP (value) && !EQ (value, Qt))
895 return 0;
896 break;
898 default:
899 abort ();
900 break;
903 if (EQ (key, QCtype) && !EQ (type, value))
904 return 0;
907 /* Check that all mandatory fields are present. */
908 for (i = 0; i < nkeywords; ++i)
909 if (keywords[i].mandatory_p && keywords[i].count == 0)
910 return 0;
912 return NILP (plist);
916 /* Return the value of KEY in image specification SPEC. Value is nil
917 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
918 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
920 static Lisp_Object
921 image_spec_value (spec, key, found)
922 Lisp_Object spec, key;
923 int *found;
925 Lisp_Object tail;
927 xassert (valid_image_p (spec));
929 for (tail = XCDR (spec);
930 CONSP (tail) && CONSP (XCDR (tail));
931 tail = XCDR (XCDR (tail)))
933 if (EQ (XCAR (tail), key))
935 if (found)
936 *found = 1;
937 return XCAR (XCDR (tail));
941 if (found)
942 *found = 0;
943 return Qnil;
947 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
948 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
949 PIXELS non-nil means return the size in pixels, otherwise return the
950 size in canonical character units.
951 FRAME is the frame on which the image will be displayed. FRAME nil
952 or omitted means use the selected frame. */)
953 (spec, pixels, frame)
954 Lisp_Object spec, pixels, frame;
956 Lisp_Object size;
958 size = Qnil;
959 if (valid_image_p (spec))
961 struct frame *f = check_x_frame (frame);
962 int id = lookup_image (f, spec);
963 struct image *img = IMAGE_FROM_ID (f, id);
964 int width = img->width + 2 * img->hmargin;
965 int height = img->height + 2 * img->vmargin;
967 if (NILP (pixels))
968 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
969 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
970 else
971 size = Fcons (make_number (width), make_number (height));
973 else
974 error ("Invalid image specification");
976 return size;
980 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
981 doc: /* Return t if image SPEC has a mask bitmap.
982 FRAME is the frame on which the image will be displayed. FRAME nil
983 or omitted means use the selected frame. */)
984 (spec, frame)
985 Lisp_Object spec, frame;
987 Lisp_Object mask;
989 mask = Qnil;
990 if (valid_image_p (spec))
992 struct frame *f = check_x_frame (frame);
993 int id = lookup_image (f, spec);
994 struct image *img = IMAGE_FROM_ID (f, id);
995 if (img->mask)
996 mask = Qt;
998 else
999 error ("Invalid image specification");
1001 return mask;
1005 /***********************************************************************
1006 Image type independent image structures
1007 ***********************************************************************/
1009 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
1010 static void free_image P_ ((struct frame *f, struct image *img));
1013 /* Allocate and return a new image structure for image specification
1014 SPEC. SPEC has a hash value of HASH. */
1016 static struct image *
1017 make_image (spec, hash)
1018 Lisp_Object spec;
1019 unsigned hash;
1021 struct image *img = (struct image *) xmalloc (sizeof *img);
1023 xassert (valid_image_p (spec));
1024 bzero (img, sizeof *img);
1025 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1026 xassert (img->type != NULL);
1027 img->spec = spec;
1028 img->data.lisp_val = Qnil;
1029 img->ascent = DEFAULT_IMAGE_ASCENT;
1030 img->hash = hash;
1031 return img;
1035 /* Free image IMG which was used on frame F, including its resources. */
1037 static void
1038 free_image (f, img)
1039 struct frame *f;
1040 struct image *img;
1042 if (img)
1044 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1046 /* Remove IMG from the hash table of its cache. */
1047 if (img->prev)
1048 img->prev->next = img->next;
1049 else
1050 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1052 if (img->next)
1053 img->next->prev = img->prev;
1055 c->images[img->id] = NULL;
1057 /* Free resources, then free IMG. */
1058 img->type->free (f, img);
1059 xfree (img);
1064 /* Prepare image IMG for display on frame F. Must be called before
1065 drawing an image. */
1067 void
1068 prepare_image_for_display (f, img)
1069 struct frame *f;
1070 struct image *img;
1072 EMACS_TIME t;
1074 /* We're about to display IMG, so set its timestamp to `now'. */
1075 EMACS_GET_TIME (t);
1076 img->timestamp = EMACS_SECS (t);
1078 /* If IMG doesn't have a pixmap yet, load it now, using the image
1079 type dependent loader function. */
1080 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1081 img->load_failed_p = img->type->load (f, img) == 0;
1085 /* Value is the number of pixels for the ascent of image IMG when
1086 drawn in face FACE. */
1089 image_ascent (img, face, slice)
1090 struct image *img;
1091 struct face *face;
1092 struct glyph_slice *slice;
1094 int height;
1095 int ascent;
1097 if (slice->height == img->height)
1098 height = img->height + img->vmargin;
1099 else if (slice->y == 0)
1100 height = slice->height + img->vmargin;
1101 else
1102 height = slice->height;
1104 if (img->ascent == CENTERED_IMAGE_ASCENT)
1106 if (face->font)
1108 #ifdef HAVE_NTGUI
1109 /* W32 specific version. Why?. ++kfs */
1110 ascent = height / 2 - (FONT_DESCENT(face->font)
1111 - FONT_BASE(face->font)) / 2;
1112 #else
1113 /* This expression is arranged so that if the image can't be
1114 exactly centered, it will be moved slightly up. This is
1115 because a typical font is `top-heavy' (due to the presence
1116 uppercase letters), so the image placement should err towards
1117 being top-heavy too. It also just generally looks better. */
1118 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
1119 #endif /* HAVE_NTGUI */
1121 else
1122 ascent = height / 2;
1124 else
1125 ascent = (int) (height * img->ascent / 100.0);
1127 return ascent;
1131 /* Image background colors. */
1133 /* Find the "best" corner color of a bitmap.
1134 On W32, XIMG is assumed to a device context with the bitmap selected. */
1136 static RGB_PIXEL_COLOR
1137 four_corners_best (ximg, width, height)
1138 XImagePtr_or_DC ximg;
1139 unsigned long width, height;
1141 RGB_PIXEL_COLOR corners[4], best;
1142 int i, best_count;
1144 /* Get the colors at the corners of ximg. */
1145 corners[0] = GET_PIXEL (ximg, 0, 0);
1146 corners[1] = GET_PIXEL (ximg, width - 1, 0);
1147 corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
1148 corners[3] = GET_PIXEL (ximg, 0, height - 1);
1150 /* Choose the most frequently found color as background. */
1151 for (i = best_count = 0; i < 4; ++i)
1153 int j, n;
1155 for (j = n = 0; j < 4; ++j)
1156 if (corners[i] == corners[j])
1157 ++n;
1159 if (n > best_count)
1160 best = corners[i], best_count = n;
1163 return best;
1166 /* Portability macros */
1168 #ifdef HAVE_NTGUI
1170 #define Destroy_Image(img_dc, prev) \
1171 do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
1173 #define Free_Pixmap(display, pixmap) \
1174 DeleteObject (pixmap)
1176 #else
1178 #define Destroy_Image(ximg, dummy) \
1179 XDestroyImage (ximg)
1181 #define Free_Pixmap(display, pixmap) \
1182 XFreePixmap (display, pixmap)
1184 #endif /* HAVE_NTGUI */
1187 /* Return the `background' field of IMG. If IMG doesn't have one yet,
1188 it is guessed heuristically. If non-zero, XIMG is an existing
1189 XImage object (or device context with the image selected on W32) to
1190 use for the heuristic. */
1192 RGB_PIXEL_COLOR
1193 image_background (img, f, ximg)
1194 struct image *img;
1195 struct frame *f;
1196 XImagePtr_or_DC ximg;
1198 if (! img->background_valid)
1199 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1201 int free_ximg = !ximg;
1202 #ifdef HAVE_NTGUI
1203 HGDIOBJ prev;
1204 #endif /* HAVE_NTGUI */
1206 if (free_ximg)
1208 #ifndef HAVE_NTGUI
1209 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
1210 0, 0, img->width, img->height, ~0, ZPixmap);
1211 #else
1212 HDC frame_dc = get_frame_dc (f);
1213 ximg = CreateCompatibleDC (frame_dc);
1214 release_frame_dc (f, frame_dc);
1215 prev = SelectObject (ximg, img->pixmap);
1216 #endif /* !HAVE_NTGUI */
1219 img->background = four_corners_best (ximg, img->width, img->height);
1221 if (free_ximg)
1222 Destroy_Image (ximg, prev);
1224 img->background_valid = 1;
1227 return img->background;
1230 /* Return the `background_transparent' field of IMG. If IMG doesn't
1231 have one yet, it is guessed heuristically. If non-zero, MASK is an
1232 existing XImage object to use for the heuristic. */
1235 image_background_transparent (img, f, mask)
1236 struct image *img;
1237 struct frame *f;
1238 XImagePtr_or_DC mask;
1240 if (! img->background_transparent_valid)
1241 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1243 if (img->mask)
1245 int free_mask = !mask;
1246 #ifdef HAVE_NTGUI
1247 HGDIOBJ prev;
1248 #endif /* HAVE_NTGUI */
1250 if (free_mask)
1252 #ifndef HAVE_NTGUI
1253 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
1254 0, 0, img->width, img->height, ~0, ZPixmap);
1255 #else
1256 HDC frame_dc = get_frame_dc (f);
1257 mask = CreateCompatibleDC (frame_dc);
1258 release_frame_dc (f, frame_dc);
1259 prev = SelectObject (mask, img->mask);
1260 #endif /* HAVE_NTGUI */
1263 img->background_transparent
1264 = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
1266 if (free_mask)
1267 Destroy_Image (mask, prev);
1269 else
1270 img->background_transparent = 0;
1272 img->background_transparent_valid = 1;
1275 return img->background_transparent;
1279 /***********************************************************************
1280 Helper functions for X image types
1281 ***********************************************************************/
1283 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
1284 int, int));
1285 static void x_clear_image P_ ((struct frame *f, struct image *img));
1286 static unsigned long x_alloc_image_color P_ ((struct frame *f,
1287 struct image *img,
1288 Lisp_Object color_name,
1289 unsigned long dflt));
1292 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
1293 free the pixmap if any. MASK_P non-zero means clear the mask
1294 pixmap if any. COLORS_P non-zero means free colors allocated for
1295 the image, if any. */
1297 static void
1298 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
1299 struct frame *f;
1300 struct image *img;
1301 int pixmap_p, mask_p, colors_p;
1303 if (pixmap_p && img->pixmap)
1305 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
1306 img->pixmap = NO_PIXMAP;
1307 img->background_valid = 0;
1310 if (mask_p && img->mask)
1312 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1313 img->mask = NO_PIXMAP;
1314 img->background_transparent_valid = 0;
1317 if (colors_p && img->ncolors)
1319 /* MAC_TODO: color table support. */
1320 /* W32_TODO: color table support. */
1321 #ifdef HAVE_X_WINDOWS
1322 x_free_colors (f, img->colors, img->ncolors);
1323 #endif /* HAVE_X_WINDOWS */
1324 xfree (img->colors);
1325 img->colors = NULL;
1326 img->ncolors = 0;
1330 /* Free X resources of image IMG which is used on frame F. */
1332 static void
1333 x_clear_image (f, img)
1334 struct frame *f;
1335 struct image *img;
1337 BLOCK_INPUT;
1338 x_clear_image_1 (f, img, 1, 1, 1);
1339 UNBLOCK_INPUT;
1343 /* Allocate color COLOR_NAME for image IMG on frame F. If color
1344 cannot be allocated, use DFLT. Add a newly allocated color to
1345 IMG->colors, so that it can be freed again. Value is the pixel
1346 color. */
1348 static unsigned long
1349 x_alloc_image_color (f, img, color_name, dflt)
1350 struct frame *f;
1351 struct image *img;
1352 Lisp_Object color_name;
1353 unsigned long dflt;
1355 XColor color;
1356 unsigned long result;
1358 xassert (STRINGP (color_name));
1360 if (x_defined_color (f, SDATA (color_name), &color, 1))
1362 /* This isn't called frequently so we get away with simply
1363 reallocating the color vector to the needed size, here. */
1364 ++img->ncolors;
1365 img->colors =
1366 (unsigned long *) xrealloc (img->colors,
1367 img->ncolors * sizeof *img->colors);
1368 img->colors[img->ncolors - 1] = color.pixel;
1369 result = color.pixel;
1371 else
1372 result = dflt;
1374 return result;
1379 /***********************************************************************
1380 Image Cache
1381 ***********************************************************************/
1383 static void cache_image P_ ((struct frame *f, struct image *img));
1384 static void postprocess_image P_ ((struct frame *, struct image *));
1386 /* Return a new, initialized image cache that is allocated from the
1387 heap. Call free_image_cache to free an image cache. */
1389 struct image_cache *
1390 make_image_cache ()
1392 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
1393 int size;
1395 bzero (c, sizeof *c);
1396 c->size = 50;
1397 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
1398 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
1399 c->buckets = (struct image **) xmalloc (size);
1400 bzero (c->buckets, size);
1401 return c;
1405 /* Free image cache of frame F. Be aware that X frames share images
1406 caches. */
1408 void
1409 free_image_cache (f)
1410 struct frame *f;
1412 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1413 if (c)
1415 int i;
1417 /* Cache should not be referenced by any frame when freed. */
1418 xassert (c->refcount == 0);
1420 for (i = 0; i < c->used; ++i)
1421 free_image (f, c->images[i]);
1422 xfree (c->images);
1423 xfree (c->buckets);
1424 xfree (c);
1425 FRAME_X_IMAGE_CACHE (f) = NULL;
1430 /* Clear image cache of frame F. FORCE_P non-zero means free all
1431 images. FORCE_P zero means clear only images that haven't been
1432 displayed for some time. Should be called from time to time to
1433 reduce the number of loaded images. If image-eviction-seconds is
1434 non-nil, this frees images in the cache which weren't displayed for
1435 at least that many seconds. */
1437 void
1438 clear_image_cache (f, force_p)
1439 struct frame *f;
1440 int force_p;
1442 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1444 if (c && INTEGERP (Vimage_cache_eviction_delay))
1446 EMACS_TIME t;
1447 unsigned long old;
1448 int i, nfreed;
1450 EMACS_GET_TIME (t);
1451 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
1453 /* Block input so that we won't be interrupted by a SIGIO
1454 while being in an inconsistent state. */
1455 BLOCK_INPUT;
1457 for (i = nfreed = 0; i < c->used; ++i)
1459 struct image *img = c->images[i];
1460 if (img != NULL
1461 && (force_p || img->timestamp < old))
1463 free_image (f, img);
1464 ++nfreed;
1468 /* We may be clearing the image cache because, for example,
1469 Emacs was iconified for a longer period of time. In that
1470 case, current matrices may still contain references to
1471 images freed above. So, clear these matrices. */
1472 if (nfreed)
1474 Lisp_Object tail, frame;
1476 FOR_EACH_FRAME (tail, frame)
1478 struct frame *f = XFRAME (frame);
1479 if (FRAME_WINDOW_P (f)
1480 && FRAME_X_IMAGE_CACHE (f) == c)
1481 clear_current_matrices (f);
1484 ++windows_or_buffers_changed;
1487 UNBLOCK_INPUT;
1492 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
1493 0, 1, 0,
1494 doc: /* Clear the image cache of FRAME.
1495 FRAME nil or omitted means use the selected frame.
1496 FRAME t means clear the image caches of all frames. */)
1497 (frame)
1498 Lisp_Object frame;
1500 if (EQ (frame, Qt))
1502 Lisp_Object tail;
1504 FOR_EACH_FRAME (tail, frame)
1505 if (FRAME_WINDOW_P (XFRAME (frame)))
1506 clear_image_cache (XFRAME (frame), 1);
1508 else
1509 clear_image_cache (check_x_frame (frame), 1);
1511 return Qnil;
1515 /* Compute masks and transform image IMG on frame F, as specified
1516 by the image's specification, */
1518 static void
1519 postprocess_image (f, img)
1520 struct frame *f;
1521 struct image *img;
1523 /* Manipulation of the image's mask. */
1524 if (img->pixmap)
1526 Lisp_Object conversion, spec;
1527 Lisp_Object mask;
1529 spec = img->spec;
1531 /* `:heuristic-mask t'
1532 `:mask heuristic'
1533 means build a mask heuristically.
1534 `:heuristic-mask (R G B)'
1535 `:mask (heuristic (R G B))'
1536 means build a mask from color (R G B) in the
1537 image.
1538 `:mask nil'
1539 means remove a mask, if any. */
1541 mask = image_spec_value (spec, QCheuristic_mask, NULL);
1542 if (!NILP (mask))
1543 x_build_heuristic_mask (f, img, mask);
1544 else
1546 int found_p;
1548 mask = image_spec_value (spec, QCmask, &found_p);
1550 if (EQ (mask, Qheuristic))
1551 x_build_heuristic_mask (f, img, Qt);
1552 else if (CONSP (mask)
1553 && EQ (XCAR (mask), Qheuristic))
1555 if (CONSP (XCDR (mask)))
1556 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
1557 else
1558 x_build_heuristic_mask (f, img, XCDR (mask));
1560 else if (NILP (mask) && found_p && img->mask)
1562 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1563 img->mask = NO_PIXMAP;
1568 /* Should we apply an image transformation algorithm? */
1569 conversion = image_spec_value (spec, QCconversion, NULL);
1570 if (EQ (conversion, Qdisabled))
1571 x_disable_image (f, img);
1572 else if (EQ (conversion, Qlaplace))
1573 x_laplace (f, img);
1574 else if (EQ (conversion, Qemboss))
1575 x_emboss (f, img);
1576 else if (CONSP (conversion)
1577 && EQ (XCAR (conversion), Qedge_detection))
1579 Lisp_Object tem;
1580 tem = XCDR (conversion);
1581 if (CONSP (tem))
1582 x_edge_detection (f, img,
1583 Fplist_get (tem, QCmatrix),
1584 Fplist_get (tem, QCcolor_adjustment));
1590 /* Return the id of image with Lisp specification SPEC on frame F.
1591 SPEC must be a valid Lisp image specification (see valid_image_p). */
1594 lookup_image (f, spec)
1595 struct frame *f;
1596 Lisp_Object spec;
1598 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1599 #ifdef _MSC_VER
1600 /* Work around a problem with MinGW builds of graphics libraries
1601 not honoring calling conventions. */
1602 static
1603 #endif
1604 struct image *img;
1605 int i;
1606 unsigned hash;
1607 struct gcpro gcpro1;
1608 EMACS_TIME now;
1610 /* F must be a window-system frame, and SPEC must be a valid image
1611 specification. */
1612 xassert (FRAME_WINDOW_P (f));
1613 xassert (valid_image_p (spec));
1615 GCPRO1 (spec);
1617 /* Look up SPEC in the hash table of the image cache. */
1618 hash = sxhash (spec, 0);
1619 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1621 for (img = c->buckets[i]; img; img = img->next)
1622 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
1623 break;
1625 /* If not found, create a new image and cache it. */
1626 if (img == NULL)
1628 extern Lisp_Object Qpostscript;
1630 BLOCK_INPUT;
1631 img = make_image (spec, hash);
1632 cache_image (f, img);
1633 img->load_failed_p = img->type->load (f, img) == 0;
1635 /* If we can't load the image, and we don't have a width and
1636 height, use some arbitrary width and height so that we can
1637 draw a rectangle for it. */
1638 if (img->load_failed_p)
1640 Lisp_Object value;
1642 value = image_spec_value (spec, QCwidth, NULL);
1643 img->width = (INTEGERP (value)
1644 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
1645 value = image_spec_value (spec, QCheight, NULL);
1646 img->height = (INTEGERP (value)
1647 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
1649 else
1651 /* Handle image type independent image attributes
1652 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
1653 `:background COLOR'. */
1654 Lisp_Object ascent, margin, relief, bg;
1656 ascent = image_spec_value (spec, QCascent, NULL);
1657 if (INTEGERP (ascent))
1658 img->ascent = XFASTINT (ascent);
1659 else if (EQ (ascent, Qcenter))
1660 img->ascent = CENTERED_IMAGE_ASCENT;
1662 margin = image_spec_value (spec, QCmargin, NULL);
1663 if (INTEGERP (margin) && XINT (margin) >= 0)
1664 img->vmargin = img->hmargin = XFASTINT (margin);
1665 else if (CONSP (margin) && INTEGERP (XCAR (margin))
1666 && INTEGERP (XCDR (margin)))
1668 if (XINT (XCAR (margin)) > 0)
1669 img->hmargin = XFASTINT (XCAR (margin));
1670 if (XINT (XCDR (margin)) > 0)
1671 img->vmargin = XFASTINT (XCDR (margin));
1674 relief = image_spec_value (spec, QCrelief, NULL);
1675 if (INTEGERP (relief))
1677 img->relief = XINT (relief);
1678 img->hmargin += abs (img->relief);
1679 img->vmargin += abs (img->relief);
1682 if (! img->background_valid)
1684 bg = image_spec_value (img->spec, QCbackground, NULL);
1685 if (!NILP (bg))
1687 img->background
1688 = x_alloc_image_color (f, img, bg,
1689 FRAME_BACKGROUND_PIXEL (f));
1690 img->background_valid = 1;
1694 /* Do image transformations and compute masks, unless we
1695 don't have the image yet. */
1696 if (!EQ (*img->type->type, Qpostscript))
1697 postprocess_image (f, img);
1700 UNBLOCK_INPUT;
1703 /* We're using IMG, so set its timestamp to `now'. */
1704 EMACS_GET_TIME (now);
1705 img->timestamp = EMACS_SECS (now);
1707 UNGCPRO;
1709 /* Value is the image id. */
1710 return img->id;
1714 /* Cache image IMG in the image cache of frame F. */
1716 static void
1717 cache_image (f, img)
1718 struct frame *f;
1719 struct image *img;
1721 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1722 int i;
1724 /* Find a free slot in c->images. */
1725 for (i = 0; i < c->used; ++i)
1726 if (c->images[i] == NULL)
1727 break;
1729 /* If no free slot found, maybe enlarge c->images. */
1730 if (i == c->used && c->used == c->size)
1732 c->size *= 2;
1733 c->images = (struct image **) xrealloc (c->images,
1734 c->size * sizeof *c->images);
1737 /* Add IMG to c->images, and assign IMG an id. */
1738 c->images[i] = img;
1739 img->id = i;
1740 if (i == c->used)
1741 ++c->used;
1743 /* Add IMG to the cache's hash table. */
1744 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
1745 img->next = c->buckets[i];
1746 if (img->next)
1747 img->next->prev = img;
1748 img->prev = NULL;
1749 c->buckets[i] = img;
1753 /* Call FN on every image in the image cache of frame F. Used to mark
1754 Lisp Objects in the image cache. */
1756 void
1757 forall_images_in_image_cache (f, fn)
1758 struct frame *f;
1759 void (*fn) P_ ((struct image *img));
1761 if (FRAME_LIVE_P (f) && FRAME_WINDOW_P (f))
1763 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1764 if (c)
1766 int i;
1767 for (i = 0; i < c->used; ++i)
1768 if (c->images[i])
1769 fn (c->images[i]);
1776 /***********************************************************************
1777 X / MAC / W32 support code
1778 ***********************************************************************/
1780 #ifdef HAVE_NTGUI
1782 /* Macro for defining functions that will be loaded from image DLLs. */
1783 #define DEF_IMGLIB_FN(func) FARPROC fn_##func
1785 /* Macro for loading those image functions from the library. */
1786 #define LOAD_IMGLIB_FN(lib,func) { \
1787 fn_##func = (void *) GetProcAddress (lib, #func); \
1788 if (!fn_##func) return 0; \
1791 #endif /* HAVE_NTGUI */
1793 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
1794 XImagePtr *, Pixmap *));
1795 static void x_destroy_x_image P_ ((XImagePtr));
1796 static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
1799 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
1800 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
1801 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
1802 via xmalloc. Print error messages via image_error if an error
1803 occurs. Value is non-zero if successful.
1805 On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
1806 should indicate the bit depth of the image. */
1808 static int
1809 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
1810 struct frame *f;
1811 int width, height, depth;
1812 XImagePtr *ximg;
1813 Pixmap *pixmap;
1815 #ifdef HAVE_X_WINDOWS
1816 Display *display = FRAME_X_DISPLAY (f);
1817 Window window = FRAME_X_WINDOW (f);
1818 Screen *screen = FRAME_X_SCREEN (f);
1820 xassert (interrupt_input_blocked);
1822 if (depth <= 0)
1823 depth = DefaultDepthOfScreen (screen);
1824 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
1825 depth, ZPixmap, 0, NULL, width, height,
1826 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
1827 if (*ximg == NULL)
1829 image_error ("Unable to allocate X image", Qnil, Qnil);
1830 return 0;
1833 /* Allocate image raster. */
1834 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
1836 /* Allocate a pixmap of the same size. */
1837 *pixmap = XCreatePixmap (display, window, width, height, depth);
1838 if (*pixmap == NO_PIXMAP)
1840 x_destroy_x_image (*ximg);
1841 *ximg = NULL;
1842 image_error ("Unable to create X pixmap", Qnil, Qnil);
1843 return 0;
1846 return 1;
1847 #endif /* HAVE_X_WINDOWS */
1849 #ifdef HAVE_NTGUI
1851 BITMAPINFOHEADER *header;
1852 HDC hdc;
1853 int scanline_width_bits;
1854 int remainder;
1855 int palette_colors = 0;
1857 if (depth == 0)
1858 depth = 24;
1860 if (depth != 1 && depth != 4 && depth != 8
1861 && depth != 16 && depth != 24 && depth != 32)
1863 image_error ("Invalid image bit depth specified", Qnil, Qnil);
1864 return 0;
1867 scanline_width_bits = width * depth;
1868 remainder = scanline_width_bits % 32;
1870 if (remainder)
1871 scanline_width_bits += 32 - remainder;
1873 /* Bitmaps with a depth less than 16 need a palette. */
1874 /* BITMAPINFO structure already contains the first RGBQUAD. */
1875 if (depth < 16)
1876 palette_colors = 1 << depth - 1;
1878 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
1879 if (*ximg == NULL)
1881 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
1882 return 0;
1885 header = &((*ximg)->info.bmiHeader);
1886 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
1887 header->biSize = sizeof (*header);
1888 header->biWidth = width;
1889 header->biHeight = -height; /* negative indicates a top-down bitmap. */
1890 header->biPlanes = 1;
1891 header->biBitCount = depth;
1892 header->biCompression = BI_RGB;
1893 header->biClrUsed = palette_colors;
1895 /* TODO: fill in palette. */
1896 if (depth == 1)
1898 (*ximg)->info.bmiColors[0].rgbBlue = 0;
1899 (*ximg)->info.bmiColors[0].rgbGreen = 0;
1900 (*ximg)->info.bmiColors[0].rgbRed = 0;
1901 (*ximg)->info.bmiColors[0].rgbReserved = 0;
1902 (*ximg)->info.bmiColors[1].rgbBlue = 255;
1903 (*ximg)->info.bmiColors[1].rgbGreen = 255;
1904 (*ximg)->info.bmiColors[1].rgbRed = 255;
1905 (*ximg)->info.bmiColors[1].rgbReserved = 0;
1908 hdc = get_frame_dc (f);
1910 /* Create a DIBSection and raster array for the bitmap,
1911 and store its handle in *pixmap. */
1912 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
1913 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
1914 &((*ximg)->data), NULL, 0);
1916 /* Realize display palette and garbage all frames. */
1917 release_frame_dc (f, hdc);
1919 if (*pixmap == NULL)
1921 DWORD err = GetLastError();
1922 Lisp_Object errcode;
1923 /* All system errors are < 10000, so the following is safe. */
1924 XSETINT (errcode, (int) err);
1925 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
1926 x_destroy_x_image (*ximg);
1927 return 0;
1930 return 1;
1932 #endif /* HAVE_NTGUI */
1934 #ifdef MAC_OS
1935 Display *display = FRAME_X_DISPLAY (f);
1936 Window window = FRAME_X_WINDOW (f);
1938 xassert (interrupt_input_blocked);
1940 /* Allocate a pixmap of the same size. */
1941 *pixmap = XCreatePixmap (display, window, width, height, depth);
1942 if (*pixmap == NO_PIXMAP)
1944 x_destroy_x_image (*ximg);
1945 *ximg = NULL;
1946 image_error ("Unable to create X pixmap", Qnil, Qnil);
1947 return 0;
1950 LockPixels (GetGWorldPixMap (*pixmap));
1951 *ximg = *pixmap;
1952 return 1;
1954 #endif /* MAC_OS */
1958 /* Destroy XImage XIMG. Free XIMG->data. */
1960 static void
1961 x_destroy_x_image (ximg)
1962 XImagePtr ximg;
1964 xassert (interrupt_input_blocked);
1965 if (ximg)
1967 #ifdef HAVE_X_WINDOWS
1968 xfree (ximg->data);
1969 ximg->data = NULL;
1970 XDestroyImage (ximg);
1971 #endif /* HAVE_X_WINDOWS */
1972 #ifdef HAVE_NTGUI
1973 /* Data will be freed by DestroyObject. */
1974 ximg->data = NULL;
1975 xfree (ximg);
1976 #endif /* HAVE_NTGUI */
1977 #ifdef MAC_OS
1978 XDestroyImage (ximg);
1979 #endif /* MAC_OS */
1984 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
1985 are width and height of both the image and pixmap. */
1987 static void
1988 x_put_x_image (f, ximg, pixmap, width, height)
1989 struct frame *f;
1990 XImagePtr ximg;
1991 Pixmap pixmap;
1992 int width, height;
1994 #ifdef HAVE_X_WINDOWS
1995 GC gc;
1997 xassert (interrupt_input_blocked);
1998 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
1999 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
2000 XFreeGC (FRAME_X_DISPLAY (f), gc);
2001 #endif /* HAVE_X_WINDOWS */
2003 #ifdef HAVE_NTGUI
2004 #if 0 /* I don't think this is necessary looking at where it is used. */
2005 HDC hdc = get_frame_dc (f);
2006 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
2007 release_frame_dc (f, hdc);
2008 #endif
2009 #endif /* HAVE_NTGUI */
2011 #ifdef MAC_OS
2012 xassert (ximg == pixmap);
2013 #endif /* MAC_OS */
2017 /***********************************************************************
2018 File Handling
2019 ***********************************************************************/
2021 static unsigned char *slurp_file P_ ((char *, int *));
2024 /* Find image file FILE. Look in data-directory, then
2025 x-bitmap-file-path. Value is the full name of the file found, or
2026 nil if not found. */
2028 Lisp_Object
2029 x_find_image_file (file)
2030 Lisp_Object file;
2032 Lisp_Object file_found, search_path;
2033 struct gcpro gcpro1, gcpro2;
2034 int fd;
2036 file_found = Qnil;
2037 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
2038 GCPRO2 (file_found, search_path);
2040 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
2041 fd = openp (search_path, file, Qnil, &file_found, Qnil);
2043 if (fd == -1)
2044 file_found = Qnil;
2045 else
2046 close (fd);
2048 UNGCPRO;
2049 return file_found;
2053 /* Read FILE into memory. Value is a pointer to a buffer allocated
2054 with xmalloc holding FILE's contents. Value is null if an error
2055 occurred. *SIZE is set to the size of the file. */
2057 static unsigned char *
2058 slurp_file (file, size)
2059 char *file;
2060 int *size;
2062 FILE *fp = NULL;
2063 unsigned char *buf = NULL;
2064 struct stat st;
2066 if (stat (file, &st) == 0
2067 && (fp = fopen (file, "rb")) != NULL
2068 && (buf = (char *) xmalloc (st.st_size),
2069 fread (buf, 1, st.st_size, fp) == st.st_size))
2071 *size = st.st_size;
2072 fclose (fp);
2074 else
2076 if (fp)
2077 fclose (fp);
2078 if (buf)
2080 xfree (buf);
2081 buf = NULL;
2085 return buf;
2090 #ifdef MAC_OS
2092 /***********************************************************************
2093 MAC Image Load Functions
2094 ***********************************************************************/
2096 static int image_load_quicktime P_ ((struct frame *, struct image *img,
2097 OSType));
2098 #ifdef MAC_OSX
2099 static int image_load_quartz2d P_ ((struct frame *, struct image *img, int));
2100 #endif
2102 static OSErr
2103 find_image_fsspec (specified_file, file, fss)
2104 Lisp_Object specified_file, *file;
2105 FSSpec *fss;
2107 #if TARGET_API_MAC_CARBON
2108 FSRef fsr;
2109 #else
2110 Str255 mac_pathname;
2111 #endif
2112 OSErr err;
2114 *file = x_find_image_file (specified_file);
2115 if (!STRINGP (*file))
2116 return fnfErr; /* file or directory not found;
2117 incomplete pathname */
2118 /* Try to open the image file. */
2119 #if TARGET_API_MAC_CARBON
2120 err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
2121 if (err == noErr)
2122 err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
2123 #else
2124 if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
2125 return fnfErr;
2126 c2pstr (mac_pathname);
2127 err = FSMakeFSSpec (0, 0, mac_pathname, fss);
2128 #endif
2129 return err;
2132 static int
2133 image_load_qt_1 (f, img, type, fss, dh)
2134 struct frame *f;
2135 struct image *img;
2136 OSType type;
2137 FSSpec *fss;
2138 Handle dh;
2140 OSErr err;
2141 GraphicsImportComponent gi;
2142 Rect rect;
2143 int width, height;
2144 short draw_all_pixels;
2145 Lisp_Object specified_bg;
2146 XColor color;
2147 XImagePtr ximg;
2148 RGBColor bg_color;
2150 err = OpenADefaultComponent (GraphicsImporterComponentType,
2151 type, &gi);
2152 if (err != noErr)
2154 image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
2155 return 0;
2157 if (dh == NULL)
2159 /* read from file system spec */
2160 err = GraphicsImportSetDataFile (gi, fss);
2161 if (err != noErr)
2163 image_error ("Cannot set fsspec to graphics importer for '%s'",
2164 img->spec, Qnil);
2165 goto error;
2168 else
2170 /* read from data handle */
2171 err = GraphicsImportSetDataHandle (gi, dh);
2172 if (err != noErr)
2174 image_error ("Cannot set data handle to graphics importer for `%s'",
2175 img->spec, Qnil);
2176 goto error;
2179 err = GraphicsImportGetNaturalBounds (gi, &rect);
2180 if (err != noErr)
2182 image_error ("Error reading `%s'", img->spec, Qnil);
2183 goto error;
2185 width = img->width = rect.right - rect.left;
2186 height = img->height = rect.bottom - rect.top;
2187 err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
2188 #if 0
2189 /* Don't check the error code here. It may have an undocumented
2190 value -32766. */
2191 if (err != noErr)
2193 image_error ("Error reading `%s'", img->spec, Qnil);
2194 goto error;
2196 #endif
2197 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2199 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2200 if (!STRINGP (specified_bg) ||
2201 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2203 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2204 color.red = RED16_FROM_ULONG (color.pixel);
2205 color.green = GREEN16_FROM_ULONG (color.pixel);
2206 color.blue = BLUE16_FROM_ULONG (color.pixel);
2210 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2211 goto error;
2212 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2214 CGrafPtr old_port;
2215 GDHandle old_gdh;
2217 GetGWorld (&old_port, &old_gdh);
2218 SetGWorld (ximg, NULL);
2219 bg_color.red = color.red;
2220 bg_color.green = color.green;
2221 bg_color.blue = color.blue;
2222 RGBBackColor (&bg_color);
2223 #if TARGET_API_MAC_CARBON
2224 GetPortBounds (ximg, &rect);
2225 EraseRect (&rect);
2226 #else
2227 EraseRect (&(ximg->portRect));
2228 #endif
2229 SetGWorld (old_port, old_gdh);
2231 GraphicsImportSetGWorld (gi, ximg, NULL);
2232 GraphicsImportDraw (gi);
2233 CloseComponent (gi);
2235 /* Maybe fill in the background field while we have ximg handy. */
2236 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2237 IMAGE_BACKGROUND (img, f, ximg);
2239 /* Put the image into the pixmap. */
2240 x_put_x_image (f, ximg, img->pixmap, width, height);
2241 x_destroy_x_image (ximg);
2242 return 1;
2244 error:
2245 CloseComponent (gi);
2246 return 0;
2250 /* Load an image using the QuickTime Graphics Importer.
2251 Note: The alpha channel does not work for PNG images. */
2252 static int
2253 image_load_quicktime (f, img, type)
2254 struct frame *f;
2255 struct image *img;
2256 OSType type;
2258 Lisp_Object specified_file;
2259 Lisp_Object specified_data;
2260 OSErr err;
2262 specified_file = image_spec_value (img->spec, QCfile, NULL);
2263 specified_data = image_spec_value (img->spec, QCdata, NULL);
2265 if (NILP (specified_data))
2267 /* Read from a file */
2268 Lisp_Object file;
2269 FSSpec fss;
2271 err = find_image_fsspec (specified_file, &file, &fss);
2272 if (err != noErr)
2274 if (err == fnfErr)
2275 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2276 else
2277 image_error ("Cannot open `%s'", file, Qnil);
2278 return 0;
2280 return image_load_qt_1 (f, img, type, &fss, NULL);
2282 else
2284 /* Memory source! */
2285 int success_p;
2286 Handle dh;
2288 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
2289 if (err != noErr)
2291 image_error ("Cannot allocate data handle for `%s'",
2292 img->spec, Qnil);
2293 return 0;
2295 success_p = image_load_qt_1 (f, img, type, NULL, dh);
2296 DisposeHandle (dh);
2297 return success_p;
2302 #ifdef MAC_OSX
2303 /* Load a PNG/JPEG image using Quartz 2D decoding routines.
2304 CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2.
2305 So don't use this function directly but determine at runtime
2306 whether it exists. */
2307 typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType)
2308 (CGDataProviderRef, const float [], bool, CGColorRenderingIntent);
2309 static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider;
2312 static void
2313 init_image_func_pointer ()
2315 if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider"))
2317 MyCGImageCreateWithPNGDataProvider
2318 = (CGImageCreateWithPNGDataProviderProcType)
2319 NSAddressOfSymbol (NSLookupAndBindSymbol
2320 ("_CGImageCreateWithPNGDataProvider"));
2322 else
2323 MyCGImageCreateWithPNGDataProvider = NULL;
2327 static int
2328 image_load_quartz2d (f, img, png_p)
2329 struct frame *f;
2330 struct image *img;
2331 int png_p;
2333 Lisp_Object file, specified_file;
2334 Lisp_Object specified_data, specified_bg;
2335 struct gcpro gcpro1;
2336 CGDataProviderRef source;
2337 CGImageRef image;
2338 int width, height;
2339 XColor color;
2340 XImagePtr ximg = NULL;
2341 CGContextRef context;
2342 CGRect rectangle;
2344 /* Open the file. */
2345 specified_file = image_spec_value (img->spec, QCfile, NULL);
2346 specified_data = image_spec_value (img->spec, QCdata, NULL);
2348 file = Qnil;
2349 GCPRO1 (file);
2351 if (NILP (specified_data))
2353 CFStringRef path;
2354 CFURLRef url;
2356 file = x_find_image_file (specified_file);
2357 if (!STRINGP (file))
2359 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2360 UNGCPRO;
2361 return 0;
2363 path = CFStringCreateWithCString (NULL, SDATA (file),
2364 kCFStringEncodingUTF8);
2365 url = CFURLCreateWithFileSystemPath (NULL, path,
2366 kCFURLPOSIXPathStyle, 0);
2367 CFRelease (path);
2368 source = CGDataProviderCreateWithURL (url);
2369 CFRelease (url);
2371 else
2372 source = CGDataProviderCreateWithData (NULL, SDATA (specified_data),
2373 SBYTES (specified_data), NULL);
2375 if (png_p)
2376 image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE,
2377 kCGRenderingIntentDefault);
2378 else
2379 image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE,
2380 kCGRenderingIntentDefault);
2382 CGDataProviderRelease (source);
2383 if (image == NULL)
2385 UNGCPRO;
2386 image_error ("Error reading image `%s'", img->spec, Qnil);
2387 return 0;
2390 if (png_p)
2392 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2393 if (!STRINGP (specified_bg) ||
2394 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2396 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2397 color.red = RED16_FROM_ULONG (color.pixel);
2398 color.green = GREEN16_FROM_ULONG (color.pixel);
2399 color.blue = BLUE16_FROM_ULONG (color.pixel);
2402 width = img->width = CGImageGetWidth (image);
2403 height = img->height = CGImageGetHeight (image);
2404 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2406 CGImageRelease (image);
2407 UNGCPRO;
2408 return 0;
2410 rectangle = CGRectMake (0, 0, width, height);
2411 QDBeginCGContext (ximg, &context);
2412 if (png_p)
2414 CGContextSetRGBFillColor (context, color.red / 65535.0,
2415 color.green / 65535.0,
2416 color.blue / 65535.0, 1.0);
2417 CGContextFillRect (context, rectangle);
2419 CGContextDrawImage (context, rectangle, image);
2420 QDEndCGContext (ximg, &context);
2421 CGImageRelease (image);
2423 /* Maybe fill in the background field while we have ximg handy. */
2424 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2425 IMAGE_BACKGROUND (img, f, ximg);
2427 /* Put the image into the pixmap. */
2428 x_put_x_image (f, ximg, img->pixmap, width, height);
2429 x_destroy_x_image (ximg);
2430 UNGCPRO;
2431 return 1;
2433 #endif
2435 #endif /* MAC_OS */
2438 /***********************************************************************
2439 XBM images
2440 ***********************************************************************/
2442 static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
2443 static int xbm_load P_ ((struct frame *f, struct image *img));
2444 static int xbm_load_image P_ ((struct frame *f, struct image *img,
2445 unsigned char *, unsigned char *));
2446 static int xbm_image_p P_ ((Lisp_Object object));
2447 static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
2448 int *, int *, unsigned char **));
2449 static int xbm_file_p P_ ((Lisp_Object));
2452 /* Indices of image specification fields in xbm_format, below. */
2454 enum xbm_keyword_index
2456 XBM_TYPE,
2457 XBM_FILE,
2458 XBM_WIDTH,
2459 XBM_HEIGHT,
2460 XBM_DATA,
2461 XBM_FOREGROUND,
2462 XBM_BACKGROUND,
2463 XBM_ASCENT,
2464 XBM_MARGIN,
2465 XBM_RELIEF,
2466 XBM_ALGORITHM,
2467 XBM_HEURISTIC_MASK,
2468 XBM_MASK,
2469 XBM_LAST
2472 /* Vector of image_keyword structures describing the format
2473 of valid XBM image specifications. */
2475 static struct image_keyword xbm_format[XBM_LAST] =
2477 {":type", IMAGE_SYMBOL_VALUE, 1},
2478 {":file", IMAGE_STRING_VALUE, 0},
2479 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2480 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2481 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2482 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
2483 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
2484 {":ascent", IMAGE_ASCENT_VALUE, 0},
2485 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
2486 {":relief", IMAGE_INTEGER_VALUE, 0},
2487 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2488 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2489 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
2492 /* Structure describing the image type XBM. */
2494 static struct image_type xbm_type =
2496 &Qxbm,
2497 xbm_image_p,
2498 xbm_load,
2499 x_clear_image,
2500 NULL
2503 /* Tokens returned from xbm_scan. */
2505 enum xbm_token
2507 XBM_TK_IDENT = 256,
2508 XBM_TK_NUMBER
2512 /* Return non-zero if OBJECT is a valid XBM-type image specification.
2513 A valid specification is a list starting with the symbol `image'
2514 The rest of the list is a property list which must contain an
2515 entry `:type xbm..
2517 If the specification specifies a file to load, it must contain
2518 an entry `:file FILENAME' where FILENAME is a string.
2520 If the specification is for a bitmap loaded from memory it must
2521 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
2522 WIDTH and HEIGHT are integers > 0. DATA may be:
2524 1. a string large enough to hold the bitmap data, i.e. it must
2525 have a size >= (WIDTH + 7) / 8 * HEIGHT
2527 2. a bool-vector of size >= WIDTH * HEIGHT
2529 3. a vector of strings or bool-vectors, one for each line of the
2530 bitmap.
2532 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
2533 may not be specified in this case because they are defined in the
2534 XBM file.
2536 Both the file and data forms may contain the additional entries
2537 `:background COLOR' and `:foreground COLOR'. If not present,
2538 foreground and background of the frame on which the image is
2539 displayed is used. */
2541 static int
2542 xbm_image_p (object)
2543 Lisp_Object object;
2545 struct image_keyword kw[XBM_LAST];
2547 bcopy (xbm_format, kw, sizeof kw);
2548 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
2549 return 0;
2551 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
2553 if (kw[XBM_FILE].count)
2555 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
2556 return 0;
2558 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
2560 /* In-memory XBM file. */
2561 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
2562 return 0;
2564 else
2566 Lisp_Object data;
2567 int width, height;
2569 /* Entries for `:width', `:height' and `:data' must be present. */
2570 if (!kw[XBM_WIDTH].count
2571 || !kw[XBM_HEIGHT].count
2572 || !kw[XBM_DATA].count)
2573 return 0;
2575 data = kw[XBM_DATA].value;
2576 width = XFASTINT (kw[XBM_WIDTH].value);
2577 height = XFASTINT (kw[XBM_HEIGHT].value);
2579 /* Check type of data, and width and height against contents of
2580 data. */
2581 if (VECTORP (data))
2583 int i;
2585 /* Number of elements of the vector must be >= height. */
2586 if (XVECTOR (data)->size < height)
2587 return 0;
2589 /* Each string or bool-vector in data must be large enough
2590 for one line of the image. */
2591 for (i = 0; i < height; ++i)
2593 Lisp_Object elt = XVECTOR (data)->contents[i];
2595 if (STRINGP (elt))
2597 if (SCHARS (elt)
2598 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
2599 return 0;
2601 else if (BOOL_VECTOR_P (elt))
2603 if (XBOOL_VECTOR (elt)->size < width)
2604 return 0;
2606 else
2607 return 0;
2610 else if (STRINGP (data))
2612 if (SCHARS (data)
2613 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
2614 return 0;
2616 else if (BOOL_VECTOR_P (data))
2618 if (XBOOL_VECTOR (data)->size < width * height)
2619 return 0;
2621 else
2622 return 0;
2625 return 1;
2629 /* Scan a bitmap file. FP is the stream to read from. Value is
2630 either an enumerator from enum xbm_token, or a character for a
2631 single-character token, or 0 at end of file. If scanning an
2632 identifier, store the lexeme of the identifier in SVAL. If
2633 scanning a number, store its value in *IVAL. */
2635 static int
2636 xbm_scan (s, end, sval, ival)
2637 unsigned char **s, *end;
2638 char *sval;
2639 int *ival;
2641 unsigned int c;
2643 loop:
2645 /* Skip white space. */
2646 while (*s < end && (c = *(*s)++, isspace (c)))
2649 if (*s >= end)
2650 c = 0;
2651 else if (isdigit (c))
2653 int value = 0, digit;
2655 if (c == '0' && *s < end)
2657 c = *(*s)++;
2658 if (c == 'x' || c == 'X')
2660 while (*s < end)
2662 c = *(*s)++;
2663 if (isdigit (c))
2664 digit = c - '0';
2665 else if (c >= 'a' && c <= 'f')
2666 digit = c - 'a' + 10;
2667 else if (c >= 'A' && c <= 'F')
2668 digit = c - 'A' + 10;
2669 else
2670 break;
2671 value = 16 * value + digit;
2674 else if (isdigit (c))
2676 value = c - '0';
2677 while (*s < end
2678 && (c = *(*s)++, isdigit (c)))
2679 value = 8 * value + c - '0';
2682 else
2684 value = c - '0';
2685 while (*s < end
2686 && (c = *(*s)++, isdigit (c)))
2687 value = 10 * value + c - '0';
2690 if (*s < end)
2691 *s = *s - 1;
2692 *ival = value;
2693 c = XBM_TK_NUMBER;
2695 else if (isalpha (c) || c == '_')
2697 *sval++ = c;
2698 while (*s < end
2699 && (c = *(*s)++, (isalnum (c) || c == '_')))
2700 *sval++ = c;
2701 *sval = 0;
2702 if (*s < end)
2703 *s = *s - 1;
2704 c = XBM_TK_IDENT;
2706 else if (c == '/' && **s == '*')
2708 /* C-style comment. */
2709 ++*s;
2710 while (**s && (**s != '*' || *(*s + 1) != '/'))
2711 ++*s;
2712 if (**s)
2714 *s += 2;
2715 goto loop;
2719 return c;
2722 #ifdef HAVE_NTGUI
2724 /* Create a Windows bitmap from X bitmap data. */
2725 static HBITMAP
2726 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
2728 static unsigned char swap_nibble[16]
2729 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
2730 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
2731 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
2732 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
2733 int i, j, w1, w2;
2734 unsigned char *bits, *p;
2735 HBITMAP bmp;
2737 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
2738 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
2739 bits = (unsigned char *) alloca (height * w2);
2740 bzero (bits, height * w2);
2741 for (i = 0; i < height; i++)
2743 p = bits + i*w2;
2744 for (j = 0; j < w1; j++)
2746 /* Bitswap XBM bytes to match how Windows does things. */
2747 unsigned char c = *data++;
2748 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
2749 | (swap_nibble[(c>>4) & 0xf]));
2752 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
2754 return bmp;
2757 static void convert_mono_to_color_image (f, img, foreground, background)
2758 struct frame *f;
2759 struct image *img;
2760 COLORREF foreground, background;
2762 HDC hdc, old_img_dc, new_img_dc;
2763 HGDIOBJ old_prev, new_prev;
2764 HBITMAP new_pixmap;
2766 hdc = get_frame_dc (f);
2767 old_img_dc = CreateCompatibleDC (hdc);
2768 new_img_dc = CreateCompatibleDC (hdc);
2769 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
2770 release_frame_dc (f, hdc);
2771 old_prev = SelectObject (old_img_dc, img->pixmap);
2772 new_prev = SelectObject (new_img_dc, new_pixmap);
2773 SetTextColor (new_img_dc, foreground);
2774 SetBkColor (new_img_dc, background);
2776 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
2777 0, 0, SRCCOPY);
2779 SelectObject (old_img_dc, old_prev);
2780 SelectObject (new_img_dc, new_prev);
2781 DeleteDC (old_img_dc);
2782 DeleteDC (new_img_dc);
2783 DeleteObject (img->pixmap);
2784 if (new_pixmap == 0)
2785 fprintf (stderr, "Failed to convert image to color.\n");
2786 else
2787 img->pixmap = new_pixmap;
2790 #define XBM_BIT_SHUFFLE(b) (~(b))
2792 #else
2794 #define XBM_BIT_SHUFFLE(b) (b)
2796 #endif /* HAVE_NTGUI */
2799 static void
2800 Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
2801 struct frame *f;
2802 struct image *img;
2803 char *data;
2804 RGB_PIXEL_COLOR fg, bg;
2805 int non_default_colors;
2807 #ifdef HAVE_NTGUI
2808 img->pixmap
2809 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
2811 /* If colors were specified, transfer the bitmap to a color one. */
2812 if (non_default_colors)
2813 convert_mono_to_color_image (f, img, fg, bg);
2814 #else
2815 img->pixmap
2816 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
2817 FRAME_X_WINDOW (f),
2818 data,
2819 img->width, img->height,
2820 fg, bg,
2821 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
2822 #endif /* HAVE_NTGUI */
2827 /* Replacement for XReadBitmapFileData which isn't available under old
2828 X versions. CONTENTS is a pointer to a buffer to parse; END is the
2829 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
2830 the image. Return in *DATA the bitmap data allocated with xmalloc.
2831 Value is non-zero if successful. DATA null means just test if
2832 CONTENTS looks like an in-memory XBM file. */
2834 static int
2835 xbm_read_bitmap_data (contents, end, width, height, data)
2836 unsigned char *contents, *end;
2837 int *width, *height;
2838 unsigned char **data;
2840 unsigned char *s = contents;
2841 char buffer[BUFSIZ];
2842 int padding_p = 0;
2843 int v10 = 0;
2844 int bytes_per_line, i, nbytes;
2845 unsigned char *p;
2846 int value;
2847 int LA1;
2849 #define match() \
2850 LA1 = xbm_scan (&s, end, buffer, &value)
2852 #define expect(TOKEN) \
2853 if (LA1 != (TOKEN)) \
2854 goto failure; \
2855 else \
2856 match ()
2858 #define expect_ident(IDENT) \
2859 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2860 match (); \
2861 else \
2862 goto failure
2864 *width = *height = -1;
2865 if (data)
2866 *data = NULL;
2867 LA1 = xbm_scan (&s, end, buffer, &value);
2869 /* Parse defines for width, height and hot-spots. */
2870 while (LA1 == '#')
2872 match ();
2873 expect_ident ("define");
2874 expect (XBM_TK_IDENT);
2876 if (LA1 == XBM_TK_NUMBER);
2878 char *p = strrchr (buffer, '_');
2879 p = p ? p + 1 : buffer;
2880 if (strcmp (p, "width") == 0)
2881 *width = value;
2882 else if (strcmp (p, "height") == 0)
2883 *height = value;
2885 expect (XBM_TK_NUMBER);
2888 if (*width < 0 || *height < 0)
2889 goto failure;
2890 else if (data == NULL)
2891 goto success;
2893 /* Parse bits. Must start with `static'. */
2894 expect_ident ("static");
2895 if (LA1 == XBM_TK_IDENT)
2897 if (strcmp (buffer, "unsigned") == 0)
2899 match ();
2900 expect_ident ("char");
2902 else if (strcmp (buffer, "short") == 0)
2904 match ();
2905 v10 = 1;
2906 if (*width % 16 && *width % 16 < 9)
2907 padding_p = 1;
2909 else if (strcmp (buffer, "char") == 0)
2910 match ();
2911 else
2912 goto failure;
2914 else
2915 goto failure;
2917 expect (XBM_TK_IDENT);
2918 expect ('[');
2919 expect (']');
2920 expect ('=');
2921 expect ('{');
2923 bytes_per_line = (*width + 7) / 8 + padding_p;
2924 nbytes = bytes_per_line * *height;
2925 p = *data = (char *) xmalloc (nbytes);
2927 if (v10)
2929 for (i = 0; i < nbytes; i += 2)
2931 int val = value;
2932 expect (XBM_TK_NUMBER);
2934 *p++ = XBM_BIT_SHUFFLE (val);
2935 if (!padding_p || ((i + 2) % bytes_per_line))
2936 *p++ = XBM_BIT_SHUFFLE (value >> 8);
2938 if (LA1 == ',' || LA1 == '}')
2939 match ();
2940 else
2941 goto failure;
2944 else
2946 for (i = 0; i < nbytes; ++i)
2948 int val = value;
2949 expect (XBM_TK_NUMBER);
2951 *p++ = XBM_BIT_SHUFFLE (val);
2953 if (LA1 == ',' || LA1 == '}')
2954 match ();
2955 else
2956 goto failure;
2960 success:
2961 return 1;
2963 failure:
2965 if (data && *data)
2967 xfree (*data);
2968 *data = NULL;
2970 return 0;
2972 #undef match
2973 #undef expect
2974 #undef expect_ident
2978 /* Load XBM image IMG which will be displayed on frame F from buffer
2979 CONTENTS. END is the end of the buffer. Value is non-zero if
2980 successful. */
2982 static int
2983 xbm_load_image (f, img, contents, end)
2984 struct frame *f;
2985 struct image *img;
2986 unsigned char *contents, *end;
2988 int rc;
2989 unsigned char *data;
2990 int success_p = 0;
2992 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
2993 if (rc)
2995 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
2996 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
2997 int non_default_colors = 0;
2998 Lisp_Object value;
3000 xassert (img->width > 0 && img->height > 0);
3002 /* Get foreground and background colors, maybe allocate colors. */
3003 value = image_spec_value (img->spec, QCforeground, NULL);
3004 if (!NILP (value))
3006 foreground = x_alloc_image_color (f, img, value, foreground);
3007 non_default_colors = 1;
3009 value = image_spec_value (img->spec, QCbackground, NULL);
3010 if (!NILP (value))
3012 background = x_alloc_image_color (f, img, value, background);
3013 img->background = background;
3014 img->background_valid = 1;
3015 non_default_colors = 1;
3018 Create_Pixmap_From_Bitmap_Data (f, img, data,
3019 foreground, background,
3020 non_default_colors);
3021 xfree (data);
3023 if (img->pixmap == NO_PIXMAP)
3025 x_clear_image (f, img);
3026 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3028 else
3029 success_p = 1;
3031 else
3032 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3034 return success_p;
3038 /* Value is non-zero if DATA looks like an in-memory XBM file. */
3040 static int
3041 xbm_file_p (data)
3042 Lisp_Object data;
3044 int w, h;
3045 return (STRINGP (data)
3046 && xbm_read_bitmap_data (SDATA (data),
3047 (SDATA (data)
3048 + SBYTES (data)),
3049 &w, &h, NULL));
3053 /* Fill image IMG which is used on frame F with pixmap data. Value is
3054 non-zero if successful. */
3056 static int
3057 xbm_load (f, img)
3058 struct frame *f;
3059 struct image *img;
3061 int success_p = 0;
3062 Lisp_Object file_name;
3064 xassert (xbm_image_p (img->spec));
3066 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3067 file_name = image_spec_value (img->spec, QCfile, NULL);
3068 if (STRINGP (file_name))
3070 Lisp_Object file;
3071 unsigned char *contents;
3072 int size;
3073 struct gcpro gcpro1;
3075 file = x_find_image_file (file_name);
3076 GCPRO1 (file);
3077 if (!STRINGP (file))
3079 image_error ("Cannot find image file `%s'", file_name, Qnil);
3080 UNGCPRO;
3081 return 0;
3084 contents = slurp_file (SDATA (file), &size);
3085 if (contents == NULL)
3087 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3088 UNGCPRO;
3089 return 0;
3092 success_p = xbm_load_image (f, img, contents, contents + size);
3093 UNGCPRO;
3095 else
3097 struct image_keyword fmt[XBM_LAST];
3098 Lisp_Object data;
3099 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3100 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3101 int non_default_colors = 0;
3102 char *bits;
3103 int parsed_p;
3104 int in_memory_file_p = 0;
3106 /* See if data looks like an in-memory XBM file. */
3107 data = image_spec_value (img->spec, QCdata, NULL);
3108 in_memory_file_p = xbm_file_p (data);
3110 /* Parse the image specification. */
3111 bcopy (xbm_format, fmt, sizeof fmt);
3112 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3113 xassert (parsed_p);
3115 /* Get specified width, and height. */
3116 if (!in_memory_file_p)
3118 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3119 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3120 xassert (img->width > 0 && img->height > 0);
3123 /* Get foreground and background colors, maybe allocate colors. */
3124 if (fmt[XBM_FOREGROUND].count
3125 && STRINGP (fmt[XBM_FOREGROUND].value))
3127 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3128 foreground);
3129 non_default_colors = 1;
3132 if (fmt[XBM_BACKGROUND].count
3133 && STRINGP (fmt[XBM_BACKGROUND].value))
3135 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3136 background);
3137 non_default_colors = 1;
3140 if (in_memory_file_p)
3141 success_p = xbm_load_image (f, img, SDATA (data),
3142 (SDATA (data)
3143 + SBYTES (data)));
3144 else
3146 if (VECTORP (data))
3148 int i;
3149 char *p;
3150 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3152 p = bits = (char *) alloca (nbytes * img->height);
3153 for (i = 0; i < img->height; ++i, p += nbytes)
3155 Lisp_Object line = XVECTOR (data)->contents[i];
3156 if (STRINGP (line))
3157 bcopy (SDATA (line), p, nbytes);
3158 else
3159 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3162 else if (STRINGP (data))
3163 bits = SDATA (data);
3164 else
3165 bits = XBOOL_VECTOR (data)->data;
3167 /* Create the pixmap. */
3169 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3170 foreground, background,
3171 non_default_colors);
3172 if (img->pixmap)
3173 success_p = 1;
3174 else
3176 image_error ("Unable to create pixmap for XBM image `%s'",
3177 img->spec, Qnil);
3178 x_clear_image (f, img);
3183 return success_p;
3188 /***********************************************************************
3189 XPM images
3190 ***********************************************************************/
3192 #if defined (HAVE_XPM) || defined (MAC_OS)
3194 static int xpm_image_p P_ ((Lisp_Object object));
3195 static int xpm_load P_ ((struct frame *f, struct image *img));
3196 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3198 #endif /* HAVE_XPM || MAC_OS */
3200 #ifdef HAVE_XPM
3201 #ifdef HAVE_NTGUI
3202 /* Indicate to xpm.h that we don't have Xlib. */
3203 #define FOR_MSW
3204 /* simx.h in xpm defines XColor and XImage differently than Emacs. */
3205 /* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
3206 #define XColor xpm_XColor
3207 #define XImage xpm_XImage
3208 #define Display xpm_Display
3209 #define PIXEL_ALREADY_TYPEDEFED
3210 #include "X11/xpm.h"
3211 #undef FOR_MSW
3212 #undef XColor
3213 #undef XImage
3214 #undef Display
3215 #undef PIXEL_ALREADY_TYPEDEFED
3216 #else
3217 #include "X11/xpm.h"
3218 #endif /* HAVE_NTGUI */
3219 #endif /* HAVE_XPM */
3221 #if defined (HAVE_XPM) || defined (MAC_OS)
3222 /* The symbol `xpm' identifying XPM-format images. */
3224 Lisp_Object Qxpm;
3226 /* Indices of image specification fields in xpm_format, below. */
3228 enum xpm_keyword_index
3230 XPM_TYPE,
3231 XPM_FILE,
3232 XPM_DATA,
3233 XPM_ASCENT,
3234 XPM_MARGIN,
3235 XPM_RELIEF,
3236 XPM_ALGORITHM,
3237 XPM_HEURISTIC_MASK,
3238 XPM_MASK,
3239 XPM_COLOR_SYMBOLS,
3240 XPM_BACKGROUND,
3241 XPM_LAST
3244 /* Vector of image_keyword structures describing the format
3245 of valid XPM image specifications. */
3247 static struct image_keyword xpm_format[XPM_LAST] =
3249 {":type", IMAGE_SYMBOL_VALUE, 1},
3250 {":file", IMAGE_STRING_VALUE, 0},
3251 {":data", IMAGE_STRING_VALUE, 0},
3252 {":ascent", IMAGE_ASCENT_VALUE, 0},
3253 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3254 {":relief", IMAGE_INTEGER_VALUE, 0},
3255 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3256 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3257 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3258 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3259 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3262 /* Structure describing the image type XPM. */
3264 static struct image_type xpm_type =
3266 &Qxpm,
3267 xpm_image_p,
3268 xpm_load,
3269 x_clear_image,
3270 NULL
3273 #ifdef HAVE_X_WINDOWS
3275 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3276 functions for allocating image colors. Our own functions handle
3277 color allocation failures more gracefully than the ones on the XPM
3278 lib. */
3280 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3281 #define ALLOC_XPM_COLORS
3282 #endif
3283 #endif /* HAVE_X_WINDOWS */
3285 #ifdef ALLOC_XPM_COLORS
3287 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3288 static void xpm_free_color_cache P_ ((void));
3289 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3290 static int xpm_color_bucket P_ ((char *));
3291 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3292 XColor *, int));
3294 /* An entry in a hash table used to cache color definitions of named
3295 colors. This cache is necessary to speed up XPM image loading in
3296 case we do color allocations ourselves. Without it, we would need
3297 a call to XParseColor per pixel in the image. */
3299 struct xpm_cached_color
3301 /* Next in collision chain. */
3302 struct xpm_cached_color *next;
3304 /* Color definition (RGB and pixel color). */
3305 XColor color;
3307 /* Color name. */
3308 char name[1];
3311 /* The hash table used for the color cache, and its bucket vector
3312 size. */
3314 #define XPM_COLOR_CACHE_BUCKETS 1001
3315 struct xpm_cached_color **xpm_color_cache;
3317 /* Initialize the color cache. */
3319 static void
3320 xpm_init_color_cache (f, attrs)
3321 struct frame *f;
3322 XpmAttributes *attrs;
3324 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3325 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3326 memset (xpm_color_cache, 0, nbytes);
3327 init_color_table ();
3329 if (attrs->valuemask & XpmColorSymbols)
3331 int i;
3332 XColor color;
3334 for (i = 0; i < attrs->numsymbols; ++i)
3335 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3336 attrs->colorsymbols[i].value, &color))
3338 color.pixel = lookup_rgb_color (f, color.red, color.green,
3339 color.blue);
3340 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3345 /* Free the color cache. */
3347 static void
3348 xpm_free_color_cache ()
3350 struct xpm_cached_color *p, *next;
3351 int i;
3353 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3354 for (p = xpm_color_cache[i]; p; p = next)
3356 next = p->next;
3357 xfree (p);
3360 xfree (xpm_color_cache);
3361 xpm_color_cache = NULL;
3362 free_color_table ();
3365 /* Return the bucket index for color named COLOR_NAME in the color
3366 cache. */
3368 static int
3369 xpm_color_bucket (color_name)
3370 char *color_name;
3372 unsigned h = 0;
3373 char *s;
3375 for (s = color_name; *s; ++s)
3376 h = (h << 2) ^ *s;
3377 return h %= XPM_COLOR_CACHE_BUCKETS;
3381 /* On frame F, cache values COLOR for color with name COLOR_NAME.
3382 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3383 entry added. */
3385 static struct xpm_cached_color *
3386 xpm_cache_color (f, color_name, color, bucket)
3387 struct frame *f;
3388 char *color_name;
3389 XColor *color;
3390 int bucket;
3392 size_t nbytes;
3393 struct xpm_cached_color *p;
3395 if (bucket < 0)
3396 bucket = xpm_color_bucket (color_name);
3398 nbytes = sizeof *p + strlen (color_name);
3399 p = (struct xpm_cached_color *) xmalloc (nbytes);
3400 strcpy (p->name, color_name);
3401 p->color = *color;
3402 p->next = xpm_color_cache[bucket];
3403 xpm_color_cache[bucket] = p;
3404 return p;
3407 /* Look up color COLOR_NAME for frame F in the color cache. If found,
3408 return the cached definition in *COLOR. Otherwise, make a new
3409 entry in the cache and allocate the color. Value is zero if color
3410 allocation failed. */
3412 static int
3413 xpm_lookup_color (f, color_name, color)
3414 struct frame *f;
3415 char *color_name;
3416 XColor *color;
3418 struct xpm_cached_color *p;
3419 int h = xpm_color_bucket (color_name);
3421 for (p = xpm_color_cache[h]; p; p = p->next)
3422 if (strcmp (p->name, color_name) == 0)
3423 break;
3425 if (p != NULL)
3426 *color = p->color;
3427 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3428 color_name, color))
3430 color->pixel = lookup_rgb_color (f, color->red, color->green,
3431 color->blue);
3432 p = xpm_cache_color (f, color_name, color, h);
3434 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3435 with transparency, and it's useful. */
3436 else if (strcmp ("opaque", color_name) == 0)
3438 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3439 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3440 p = xpm_cache_color (f, color_name, color, h);
3443 return p != NULL;
3447 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3448 CLOSURE is a pointer to the frame on which we allocate the
3449 color. Return in *COLOR the allocated color. Value is non-zero
3450 if successful. */
3452 static int
3453 xpm_alloc_color (dpy, cmap, color_name, color, closure)
3454 Display *dpy;
3455 Colormap cmap;
3456 char *color_name;
3457 XColor *color;
3458 void *closure;
3460 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3464 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3465 is a pointer to the frame on which we allocate the color. Value is
3466 non-zero if successful. */
3468 static int
3469 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3470 Display *dpy;
3471 Colormap cmap;
3472 Pixel *pixels;
3473 int npixels;
3474 void *closure;
3476 return 1;
3479 #endif /* ALLOC_XPM_COLORS */
3482 #ifdef HAVE_NTGUI
3484 /* XPM library details. */
3486 DEF_IMGLIB_FN (XpmFreeAttributes);
3487 DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3488 DEF_IMGLIB_FN (XpmReadFileToImage);
3489 DEF_IMGLIB_FN (XImageFree);
3492 static int
3493 init_xpm_functions (void)
3495 HMODULE library;
3497 if (!(library = LoadLibrary ("libXpm.dll")))
3498 return 0;
3500 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3501 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3502 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3503 LOAD_IMGLIB_FN (library, XImageFree);
3504 return 1;
3507 #endif /* HAVE_NTGUI */
3510 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3511 for XPM images. Such a list must consist of conses whose car and
3512 cdr are strings. */
3514 static int
3515 xpm_valid_color_symbols_p (color_symbols)
3516 Lisp_Object color_symbols;
3518 while (CONSP (color_symbols))
3520 Lisp_Object sym = XCAR (color_symbols);
3521 if (!CONSP (sym)
3522 || !STRINGP (XCAR (sym))
3523 || !STRINGP (XCDR (sym)))
3524 break;
3525 color_symbols = XCDR (color_symbols);
3528 return NILP (color_symbols);
3532 /* Value is non-zero if OBJECT is a valid XPM image specification. */
3534 static int
3535 xpm_image_p (object)
3536 Lisp_Object object;
3538 struct image_keyword fmt[XPM_LAST];
3539 bcopy (xpm_format, fmt, sizeof fmt);
3540 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3541 /* Either `:file' or `:data' must be present. */
3542 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3543 /* Either no `:color-symbols' or it's a list of conses
3544 whose car and cdr are strings. */
3545 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3546 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3549 #endif /* HAVE_XPM || MAC_OS */
3551 /* Load image IMG which will be displayed on frame F. Value is
3552 non-zero if successful. */
3554 #ifdef HAVE_XPM
3556 static int
3557 xpm_load (f, img)
3558 struct frame *f;
3559 struct image *img;
3561 int rc;
3562 XpmAttributes attrs;
3563 Lisp_Object specified_file, color_symbols;
3564 #ifdef HAVE_NTGUI
3565 HDC hdc;
3566 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3567 #endif /* HAVE_NTGUI */
3569 /* Configure the XPM lib. Use the visual of frame F. Allocate
3570 close colors. Return colors allocated. */
3571 bzero (&attrs, sizeof attrs);
3573 #ifndef HAVE_NTGUI
3574 attrs.visual = FRAME_X_VISUAL (f);
3575 attrs.colormap = FRAME_X_COLORMAP (f);
3576 attrs.valuemask |= XpmVisual;
3577 attrs.valuemask |= XpmColormap;
3578 #endif /* HAVE_NTGUI */
3580 #ifdef ALLOC_XPM_COLORS
3581 /* Allocate colors with our own functions which handle
3582 failing color allocation more gracefully. */
3583 attrs.color_closure = f;
3584 attrs.alloc_color = xpm_alloc_color;
3585 attrs.free_colors = xpm_free_colors;
3586 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3587 #else /* not ALLOC_XPM_COLORS */
3588 /* Let the XPM lib allocate colors. */
3589 attrs.valuemask |= XpmReturnAllocPixels;
3590 #ifdef XpmAllocCloseColors
3591 attrs.alloc_close_colors = 1;
3592 attrs.valuemask |= XpmAllocCloseColors;
3593 #else /* not XpmAllocCloseColors */
3594 attrs.closeness = 600;
3595 attrs.valuemask |= XpmCloseness;
3596 #endif /* not XpmAllocCloseColors */
3597 #endif /* ALLOC_XPM_COLORS */
3599 /* If image specification contains symbolic color definitions, add
3600 these to `attrs'. */
3601 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3602 if (CONSP (color_symbols))
3604 Lisp_Object tail;
3605 XpmColorSymbol *xpm_syms;
3606 int i, size;
3608 attrs.valuemask |= XpmColorSymbols;
3610 /* Count number of symbols. */
3611 attrs.numsymbols = 0;
3612 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3613 ++attrs.numsymbols;
3615 /* Allocate an XpmColorSymbol array. */
3616 size = attrs.numsymbols * sizeof *xpm_syms;
3617 xpm_syms = (XpmColorSymbol *) alloca (size);
3618 bzero (xpm_syms, size);
3619 attrs.colorsymbols = xpm_syms;
3621 /* Fill the color symbol array. */
3622 for (tail = color_symbols, i = 0;
3623 CONSP (tail);
3624 ++i, tail = XCDR (tail))
3626 Lisp_Object name = XCAR (XCAR (tail));
3627 Lisp_Object color = XCDR (XCAR (tail));
3628 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3629 strcpy (xpm_syms[i].name, SDATA (name));
3630 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3631 strcpy (xpm_syms[i].value, SDATA (color));
3635 /* Create a pixmap for the image, either from a file, or from a
3636 string buffer containing data in the same format as an XPM file. */
3637 #ifdef ALLOC_XPM_COLORS
3638 xpm_init_color_cache (f, &attrs);
3639 #endif
3641 specified_file = image_spec_value (img->spec, QCfile, NULL);
3643 #ifdef HAVE_NTGUI
3645 HDC frame_dc = get_frame_dc (f);
3646 hdc = CreateCompatibleDC (frame_dc);
3647 release_frame_dc (f, frame_dc);
3649 #endif /* HAVE_NTGUI */
3651 if (STRINGP (specified_file))
3653 Lisp_Object file = x_find_image_file (specified_file);
3654 if (!STRINGP (file))
3656 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3657 return 0;
3660 #ifdef HAVE_NTGUI
3661 /* XpmReadFileToPixmap is not available in the Windows port of
3662 libxpm. But XpmReadFileToImage almost does what we want. */
3663 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3664 &xpm_image, &xpm_mask,
3665 &attrs);
3666 #else
3667 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3668 SDATA (file), &img->pixmap, &img->mask,
3669 &attrs);
3670 #endif /* HAVE_NTGUI */
3672 else
3674 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3675 #ifdef HAVE_NTGUI
3676 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3677 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3678 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3679 &xpm_image, &xpm_mask,
3680 &attrs);
3681 #else
3682 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3683 SDATA (buffer),
3684 &img->pixmap, &img->mask,
3685 &attrs);
3686 #endif /* HAVE_NTGUI */
3689 if (rc == XpmSuccess)
3691 #if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3692 img->colors = colors_in_color_table (&img->ncolors);
3693 #else /* not ALLOC_XPM_COLORS */
3694 int i;
3696 #ifdef HAVE_NTGUI
3697 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3698 plus some duplicate attributes. */
3699 if (xpm_image && xpm_image->bitmap)
3701 img->pixmap = xpm_image->bitmap;
3702 /* XImageFree in libXpm frees XImage struct without destroying
3703 the bitmap, which is what we want. */
3704 fn_XImageFree (xpm_image);
3706 if (xpm_mask && xpm_mask->bitmap)
3708 /* The mask appears to be inverted compared with what we expect.
3709 TODO: invert our expectations. See other places where we
3710 have to invert bits because our idea of masks is backwards. */
3711 HGDIOBJ old_obj;
3712 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3714 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3715 SelectObject (hdc, old_obj);
3717 img->mask = xpm_mask->bitmap;
3718 fn_XImageFree (xpm_mask);
3719 DeleteDC (hdc);
3722 DeleteDC (hdc);
3723 #endif /* HAVE_NTGUI */
3725 /* Remember allocated colors. */
3726 img->ncolors = attrs.nalloc_pixels;
3727 img->colors = (unsigned long *) xmalloc (img->ncolors
3728 * sizeof *img->colors);
3729 for (i = 0; i < attrs.nalloc_pixels; ++i)
3731 img->colors[i] = attrs.alloc_pixels[i];
3732 #ifdef DEBUG_X_COLORS
3733 register_color (img->colors[i]);
3734 #endif
3736 #endif /* not ALLOC_XPM_COLORS */
3738 img->width = attrs.width;
3739 img->height = attrs.height;
3740 xassert (img->width > 0 && img->height > 0);
3742 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3743 #ifdef HAVE_NTGUI
3744 fn_XpmFreeAttributes (&attrs);
3745 #else
3746 XpmFreeAttributes (&attrs);
3747 #endif /* HAVE_NTGUI */
3749 else
3751 #ifdef HAVE_NTGUI
3752 DeleteDC (hdc);
3753 #endif /* HAVE_NTGUI */
3755 switch (rc)
3757 case XpmOpenFailed:
3758 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3759 break;
3761 case XpmFileInvalid:
3762 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3763 break;
3765 case XpmNoMemory:
3766 image_error ("Out of memory (%s)", img->spec, Qnil);
3767 break;
3769 case XpmColorFailed:
3770 image_error ("Color allocation error (%s)", img->spec, Qnil);
3771 break;
3773 default:
3774 image_error ("Unknown error (%s)", img->spec, Qnil);
3775 break;
3779 #ifdef ALLOC_XPM_COLORS
3780 xpm_free_color_cache ();
3781 #endif
3782 return rc == XpmSuccess;
3785 #endif /* HAVE_XPM */
3787 #ifdef MAC_OS
3789 /* XPM support functions for Mac OS where libxpm is not available.
3790 Only XPM version 3 (without any extensions) is supported. */
3792 static int xpm_scan P_ ((unsigned char **, unsigned char *,
3793 unsigned char **, int *));
3794 static Lisp_Object xpm_make_color_table_v
3795 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3796 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3797 static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *,
3798 int, Lisp_Object));
3799 static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
3800 unsigned char *, int));
3801 static Lisp_Object xpm_make_color_table_h
3802 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3803 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3804 static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *,
3805 int, Lisp_Object));
3806 static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
3807 unsigned char *, int));
3808 static int xpm_str_to_color_key P_ ((char *));
3809 static int xpm_load_image P_ ((struct frame *, struct image *,
3810 unsigned char *, unsigned char *));
3812 /* Tokens returned from xpm_scan. */
3814 enum xpm_token
3816 XPM_TK_IDENT = 256,
3817 XPM_TK_STRING,
3818 XPM_TK_EOF
3821 /* Scan an XPM data and return a character (< 256) or a token defined
3822 by enum xpm_token above. *S and END are the start (inclusive) and
3823 the end (exclusive) addresses of the data, respectively. Advance
3824 *S while scanning. If token is either XPM_TK_IDENT or
3825 XPM_TK_STRING, *BEG and *LEN are set to the start address and the
3826 length of the corresponding token, respectively. */
3828 static int
3829 xpm_scan (s, end, beg, len)
3830 unsigned char **s, *end, **beg;
3831 int *len;
3833 int c;
3835 while (*s < end)
3837 /* Skip white-space. */
3838 while (*s < end && (c = *(*s)++, isspace (c)))
3841 /* gnus-pointer.xpm uses '-' in its identifier.
3842 sb-dir-plus.xpm uses '+' in its identifier. */
3843 if (isalpha (c) || c == '_' || c == '-' || c == '+')
3845 *beg = *s - 1;
3846 while (*s < end &&
3847 (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
3848 ++*s;
3849 *len = *s - *beg;
3850 return XPM_TK_IDENT;
3852 else if (c == '"')
3854 *beg = *s;
3855 while (*s < end && **s != '"')
3856 ++*s;
3857 *len = *s - *beg;
3858 if (*s < end)
3859 ++*s;
3860 return XPM_TK_STRING;
3862 else if (c == '/')
3864 if (*s < end && **s == '*')
3866 /* C-style comment. */
3867 ++*s;
3870 while (*s < end && *(*s)++ != '*')
3873 while (*s < end && **s != '/');
3874 if (*s < end)
3875 ++*s;
3877 else
3878 return c;
3880 else
3881 return c;
3884 return XPM_TK_EOF;
3887 /* Functions for color table lookup in XPM data. A Key is a string
3888 specifying the color of each pixel in XPM data. A value is either
3889 an integer that specifies a pixel color, Qt that specifies
3890 transparency, or Qnil for the unspecified color. If the length of
3891 the key string is one, a vector is used as a table. Otherwise, a
3892 hash table is used. */
3894 static Lisp_Object
3895 xpm_make_color_table_v (put_func, get_func)
3896 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3897 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3899 *put_func = xpm_put_color_table_v;
3900 *get_func = xpm_get_color_table_v;
3901 return Fmake_vector (make_number (256), Qnil);
3904 static void
3905 xpm_put_color_table_v (color_table, chars_start, chars_len, color)
3906 Lisp_Object color_table;
3907 unsigned char *chars_start;
3908 int chars_len;
3909 Lisp_Object color;
3911 XVECTOR (color_table)->contents[*chars_start] = color;
3914 static Lisp_Object
3915 xpm_get_color_table_v (color_table, chars_start, chars_len)
3916 Lisp_Object color_table;
3917 unsigned char *chars_start;
3918 int chars_len;
3920 return XVECTOR (color_table)->contents[*chars_start];
3923 static Lisp_Object
3924 xpm_make_color_table_h (put_func, get_func)
3925 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3926 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3928 *put_func = xpm_put_color_table_h;
3929 *get_func = xpm_get_color_table_h;
3930 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
3931 make_float (DEFAULT_REHASH_SIZE),
3932 make_float (DEFAULT_REHASH_THRESHOLD),
3933 Qnil, Qnil, Qnil);
3936 static void
3937 xpm_put_color_table_h (color_table, chars_start, chars_len, color)
3938 Lisp_Object color_table;
3939 unsigned char *chars_start;
3940 int chars_len;
3941 Lisp_Object color;
3943 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
3944 unsigned hash_code;
3945 Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
3947 hash_lookup (table, chars, &hash_code);
3948 hash_put (table, chars, color, hash_code);
3951 static Lisp_Object
3952 xpm_get_color_table_h (color_table, chars_start, chars_len)
3953 Lisp_Object color_table;
3954 unsigned char *chars_start;
3955 int chars_len;
3957 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
3958 int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
3959 NULL);
3961 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
3964 enum xpm_color_key {
3965 XPM_COLOR_KEY_S,
3966 XPM_COLOR_KEY_M,
3967 XPM_COLOR_KEY_G4,
3968 XPM_COLOR_KEY_G,
3969 XPM_COLOR_KEY_C
3972 static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
3974 static int
3975 xpm_str_to_color_key (s)
3976 char *s;
3978 int i;
3980 for (i = 0;
3981 i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
3982 i++)
3983 if (strcmp (xpm_color_key_strings[i], s) == 0)
3984 return i;
3985 return -1;
3988 static int
3989 xpm_load_image (f, img, contents, end)
3990 struct frame *f;
3991 struct image *img;
3992 unsigned char *contents, *end;
3994 unsigned char *s = contents, *beg, *str;
3995 unsigned char buffer[BUFSIZ];
3996 int width, height, x, y;
3997 int num_colors, chars_per_pixel;
3998 int len, LA1;
3999 void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object);
4000 Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int);
4001 Lisp_Object frame, color_symbols, color_table;
4002 int best_key, have_mask = 0;
4003 XImagePtr ximg = NULL, mask_img = NULL;
4005 #define match() \
4006 LA1 = xpm_scan (&s, end, &beg, &len)
4008 #define expect(TOKEN) \
4009 if (LA1 != (TOKEN)) \
4010 goto failure; \
4011 else \
4012 match ()
4014 #define expect_ident(IDENT) \
4015 if (LA1 == XPM_TK_IDENT \
4016 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
4017 match (); \
4018 else \
4019 goto failure
4021 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
4022 goto failure;
4023 s += 9;
4024 match();
4025 expect_ident ("static");
4026 expect_ident ("char");
4027 expect ('*');
4028 expect (XPM_TK_IDENT);
4029 expect ('[');
4030 expect (']');
4031 expect ('=');
4032 expect ('{');
4033 expect (XPM_TK_STRING);
4034 if (len >= BUFSIZ)
4035 goto failure;
4036 memcpy (buffer, beg, len);
4037 buffer[len] = '\0';
4038 if (sscanf (buffer, "%d %d %d %d", &width, &height,
4039 &num_colors, &chars_per_pixel) != 4
4040 || width <= 0 || height <= 0
4041 || num_colors <= 0 || chars_per_pixel <= 0)
4042 goto failure;
4043 expect (',');
4045 XSETFRAME (frame, f);
4046 if (!NILP (Fxw_display_color_p (frame)))
4047 best_key = XPM_COLOR_KEY_C;
4048 else if (!NILP (Fx_display_grayscale_p (frame)))
4049 best_key = (XFASTINT (Fx_display_planes (frame)) > 2
4050 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
4051 else
4052 best_key = XPM_COLOR_KEY_M;
4054 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
4055 if (chars_per_pixel == 1)
4056 color_table = xpm_make_color_table_v (&put_color_table,
4057 &get_color_table);
4058 else
4059 color_table = xpm_make_color_table_h (&put_color_table,
4060 &get_color_table);
4062 while (num_colors-- > 0)
4064 unsigned char *color, *max_color;
4065 int key, next_key, max_key = 0;
4066 Lisp_Object symbol_color = Qnil, color_val;
4067 XColor cdef;
4069 expect (XPM_TK_STRING);
4070 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
4071 goto failure;
4072 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
4073 buffer[len - chars_per_pixel] = '\0';
4075 str = strtok (buffer, " \t");
4076 if (str == NULL)
4077 goto failure;
4078 key = xpm_str_to_color_key (str);
4079 if (key < 0)
4080 goto failure;
4083 color = strtok (NULL, " \t");
4084 if (color == NULL)
4085 goto failure;
4087 while (str = strtok (NULL, " \t"))
4089 next_key = xpm_str_to_color_key (str);
4090 if (next_key >= 0)
4091 break;
4092 color[strlen (color)] = ' ';
4095 if (key == XPM_COLOR_KEY_S)
4097 if (NILP (symbol_color))
4098 symbol_color = build_string (color);
4100 else if (max_key < key && key <= best_key)
4102 max_key = key;
4103 max_color = color;
4105 key = next_key;
4107 while (str);
4109 color_val = Qnil;
4110 if (!NILP (color_symbols) && !NILP (symbol_color))
4112 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
4114 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
4115 if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0)
4116 color_val = Qt;
4117 else if (x_defined_color (f, SDATA (XCDR (specified_color)),
4118 &cdef, 0))
4119 color_val = make_number (cdef.pixel);
4121 if (NILP (color_val) && max_key > 0)
4122 if (xstricmp (max_color, "None") == 0)
4123 color_val = Qt;
4124 else if (x_defined_color (f, max_color, &cdef, 0))
4125 color_val = make_number (cdef.pixel);
4126 if (!NILP (color_val))
4127 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
4129 expect (',');
4132 if (!x_create_x_image_and_pixmap (f, width, height, 0,
4133 &ximg, &img->pixmap)
4134 || !x_create_x_image_and_pixmap (f, width, height, 1,
4135 &mask_img, &img->mask))
4137 image_error ("Out of memory (%s)", img->spec, Qnil);
4138 goto error;
4141 for (y = 0; y < height; y++)
4143 expect (XPM_TK_STRING);
4144 str = beg;
4145 if (len < width * chars_per_pixel)
4146 goto failure;
4147 for (x = 0; x < width; x++, str += chars_per_pixel)
4149 Lisp_Object color_val =
4150 (*get_color_table) (color_table, str, chars_per_pixel);
4152 XPutPixel (ximg, x, y,
4153 (INTEGERP (color_val) ? XINT (color_val)
4154 : FRAME_FOREGROUND_PIXEL (f)));
4155 XPutPixel (mask_img, x, y,
4156 (!EQ (color_val, Qt) ? PIX_MASK_DRAW (f)
4157 : (have_mask = 1, PIX_MASK_RETAIN (f))));
4159 if (y + 1 < height)
4160 expect (',');
4163 img->width = width;
4164 img->height = height;
4166 x_put_x_image (f, ximg, img->pixmap, width, height);
4167 x_destroy_x_image (ximg);
4168 if (have_mask)
4170 x_put_x_image (f, mask_img, img->mask, width, height);
4171 x_destroy_x_image (mask_img);
4173 else
4175 x_destroy_x_image (mask_img);
4176 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4177 img->mask = NO_PIXMAP;
4180 return 1;
4182 failure:
4183 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
4184 error:
4185 x_destroy_x_image (ximg);
4186 x_destroy_x_image (mask_img);
4187 x_clear_image (f, img);
4188 return 0;
4190 #undef match
4191 #undef expect
4192 #undef expect_ident
4195 static int
4196 xpm_load (f, img)
4197 struct frame *f;
4198 struct image *img;
4200 int success_p = 0;
4201 Lisp_Object file_name;
4203 /* If IMG->spec specifies a file name, create a non-file spec from it. */
4204 file_name = image_spec_value (img->spec, QCfile, NULL);
4205 if (STRINGP (file_name))
4207 Lisp_Object file;
4208 unsigned char *contents;
4209 int size;
4210 struct gcpro gcpro1;
4212 file = x_find_image_file (file_name);
4213 GCPRO1 (file);
4214 if (!STRINGP (file))
4216 image_error ("Cannot find image file `%s'", file_name, Qnil);
4217 UNGCPRO;
4218 return 0;
4221 contents = slurp_file (SDATA (file), &size);
4222 if (contents == NULL)
4224 image_error ("Error loading XPM image `%s'", img->spec, Qnil);
4225 UNGCPRO;
4226 return 0;
4229 success_p = xpm_load_image (f, img, contents, contents + size);
4230 xfree (contents);
4231 UNGCPRO;
4233 else
4235 Lisp_Object data;
4237 data = image_spec_value (img->spec, QCdata, NULL);
4238 success_p = xpm_load_image (f, img, SDATA (data),
4239 SDATA (data) + SBYTES (data));
4242 return success_p;
4245 #endif /* MAC_OS */
4249 /***********************************************************************
4250 Color table
4251 ***********************************************************************/
4253 #ifdef COLOR_TABLE_SUPPORT
4255 /* An entry in the color table mapping an RGB color to a pixel color. */
4257 struct ct_color
4259 int r, g, b;
4260 unsigned long pixel;
4262 /* Next in color table collision list. */
4263 struct ct_color *next;
4266 /* The bucket vector size to use. Must be prime. */
4268 #define CT_SIZE 101
4270 /* Value is a hash of the RGB color given by R, G, and B. */
4272 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
4274 /* The color hash table. */
4276 struct ct_color **ct_table;
4278 /* Number of entries in the color table. */
4280 int ct_colors_allocated;
4282 /* Initialize the color table. */
4284 static void
4285 init_color_table ()
4287 int size = CT_SIZE * sizeof (*ct_table);
4288 ct_table = (struct ct_color **) xmalloc (size);
4289 bzero (ct_table, size);
4290 ct_colors_allocated = 0;
4294 /* Free memory associated with the color table. */
4296 static void
4297 free_color_table ()
4299 int i;
4300 struct ct_color *p, *next;
4302 for (i = 0; i < CT_SIZE; ++i)
4303 for (p = ct_table[i]; p; p = next)
4305 next = p->next;
4306 xfree (p);
4309 xfree (ct_table);
4310 ct_table = NULL;
4314 /* Value is a pixel color for RGB color R, G, B on frame F. If an
4315 entry for that color already is in the color table, return the
4316 pixel color of that entry. Otherwise, allocate a new color for R,
4317 G, B, and make an entry in the color table. */
4319 static unsigned long
4320 lookup_rgb_color (f, r, g, b)
4321 struct frame *f;
4322 int r, g, b;
4324 unsigned hash = CT_HASH_RGB (r, g, b);
4325 int i = hash % CT_SIZE;
4326 struct ct_color *p;
4327 Display_Info *dpyinfo;
4329 /* Handle TrueColor visuals specially, which improves performance by
4330 two orders of magnitude. Freeing colors on TrueColor visuals is
4331 a nop, and pixel colors specify RGB values directly. See also
4332 the Xlib spec, chapter 3.1. */
4333 dpyinfo = FRAME_X_DISPLAY_INFO (f);
4334 if (dpyinfo->red_bits > 0)
4336 unsigned long pr, pg, pb;
4338 /* Apply gamma-correction like normal color allocation does. */
4339 if (f->gamma)
4341 XColor color;
4342 color.red = r, color.green = g, color.blue = b;
4343 gamma_correct (f, &color);
4344 r = color.red, g = color.green, b = color.blue;
4347 /* Scale down RGB values to the visual's bits per RGB, and shift
4348 them to the right position in the pixel color. Note that the
4349 original RGB values are 16-bit values, as usual in X. */
4350 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
4351 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
4352 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
4354 /* Assemble the pixel color. */
4355 return pr | pg | pb;
4358 for (p = ct_table[i]; p; p = p->next)
4359 if (p->r == r && p->g == g && p->b == b)
4360 break;
4362 if (p == NULL)
4365 #ifdef HAVE_X_WINDOWS
4366 XColor color;
4367 Colormap cmap;
4368 int rc;
4370 color.red = r;
4371 color.green = g;
4372 color.blue = b;
4374 cmap = FRAME_X_COLORMAP (f);
4375 rc = x_alloc_nearest_color (f, cmap, &color);
4376 if (rc)
4378 ++ct_colors_allocated;
4379 p = (struct ct_color *) xmalloc (sizeof *p);
4380 p->r = r;
4381 p->g = g;
4382 p->b = b;
4383 p->pixel = color.pixel;
4384 p->next = ct_table[i];
4385 ct_table[i] = p;
4387 else
4388 return FRAME_FOREGROUND_PIXEL (f);
4390 #else
4391 COLORREF color;
4392 #ifdef HAVE_NTGUI
4393 color = PALETTERGB (r, g, b);
4394 #else
4395 color = RGB_TO_ULONG (r, g, b);
4396 #endif /* HAVE_NTGUI */
4397 ++ct_colors_allocated;
4398 p = (struct ct_color *) xmalloc (sizeof *p);
4399 p->r = r;
4400 p->g = g;
4401 p->b = b;
4402 p->pixel = color;
4403 p->next = ct_table[i];
4404 ct_table[i] = p;
4405 #endif /* HAVE_X_WINDOWS */
4409 return p->pixel;
4413 /* Look up pixel color PIXEL which is used on frame F in the color
4414 table. If not already present, allocate it. Value is PIXEL. */
4416 static unsigned long
4417 lookup_pixel_color (f, pixel)
4418 struct frame *f;
4419 unsigned long pixel;
4421 int i = pixel % CT_SIZE;
4422 struct ct_color *p;
4424 for (p = ct_table[i]; p; p = p->next)
4425 if (p->pixel == pixel)
4426 break;
4428 if (p == NULL)
4430 XColor color;
4431 Colormap cmap;
4432 int rc;
4434 #ifdef HAVE_X_WINDOWS
4435 cmap = FRAME_X_COLORMAP (f);
4436 color.pixel = pixel;
4437 x_query_color (f, &color);
4438 rc = x_alloc_nearest_color (f, cmap, &color);
4439 #else
4440 BLOCK_INPUT;
4441 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
4442 color.pixel = pixel;
4443 XQueryColor (NULL, cmap, &color);
4444 rc = x_alloc_nearest_color (f, cmap, &color);
4445 UNBLOCK_INPUT;
4446 #endif /* HAVE_X_WINDOWS */
4448 if (rc)
4450 ++ct_colors_allocated;
4452 p = (struct ct_color *) xmalloc (sizeof *p);
4453 p->r = color.red;
4454 p->g = color.green;
4455 p->b = color.blue;
4456 p->pixel = pixel;
4457 p->next = ct_table[i];
4458 ct_table[i] = p;
4460 else
4461 return FRAME_FOREGROUND_PIXEL (f);
4463 return p->pixel;
4467 /* Value is a vector of all pixel colors contained in the color table,
4468 allocated via xmalloc. Set *N to the number of colors. */
4470 static unsigned long *
4471 colors_in_color_table (n)
4472 int *n;
4474 int i, j;
4475 struct ct_color *p;
4476 unsigned long *colors;
4478 if (ct_colors_allocated == 0)
4480 *n = 0;
4481 colors = NULL;
4483 else
4485 colors = (unsigned long *) xmalloc (ct_colors_allocated
4486 * sizeof *colors);
4487 *n = ct_colors_allocated;
4489 for (i = j = 0; i < CT_SIZE; ++i)
4490 for (p = ct_table[i]; p; p = p->next)
4491 colors[j++] = p->pixel;
4494 return colors;
4497 #else /* COLOR_TABLE_SUPPORT */
4499 static unsigned long
4500 lookup_rgb_color (f, r, g, b)
4501 struct frame *f;
4502 int r, g, b;
4504 unsigned long pixel;
4506 #ifdef MAC_OS
4507 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4508 gamma_correct (f, &pixel);
4509 #endif /* MAC_OS */
4511 #ifdef HAVE_NTGUI
4512 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4513 #endif /* HAVE_NTGUI */
4515 return pixel;
4518 static void
4519 init_color_table ()
4522 #endif /* COLOR_TABLE_SUPPORT */
4525 /***********************************************************************
4526 Algorithms
4527 ***********************************************************************/
4529 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4530 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4531 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4533 #ifdef HAVE_NTGUI
4534 static void XPutPixel (XImagePtr , int, int, COLORREF);
4535 #endif /* HAVE_NTGUI */
4537 /* Non-zero means draw a cross on images having `:conversion
4538 disabled'. */
4540 int cross_disabled_images;
4542 /* Edge detection matrices for different edge-detection
4543 strategies. */
4545 static int emboss_matrix[9] = {
4546 /* x - 1 x x + 1 */
4547 2, -1, 0, /* y - 1 */
4548 -1, 0, 1, /* y */
4549 0, 1, -2 /* y + 1 */
4552 static int laplace_matrix[9] = {
4553 /* x - 1 x x + 1 */
4554 1, 0, 0, /* y - 1 */
4555 0, 0, 0, /* y */
4556 0, 0, -1 /* y + 1 */
4559 /* Value is the intensity of the color whose red/green/blue values
4560 are R, G, and B. */
4562 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4565 /* On frame F, return an array of XColor structures describing image
4566 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4567 non-zero means also fill the red/green/blue members of the XColor
4568 structures. Value is a pointer to the array of XColors structures,
4569 allocated with xmalloc; it must be freed by the caller. */
4571 static XColor *
4572 x_to_xcolors (f, img, rgb_p)
4573 struct frame *f;
4574 struct image *img;
4575 int rgb_p;
4577 int x, y;
4578 XColor *colors, *p;
4579 XImagePtr_or_DC ximg;
4580 #ifdef HAVE_NTGUI
4581 HDC hdc;
4582 HGDIOBJ prev;
4583 #endif /* HAVE_NTGUI */
4585 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4587 #ifndef HAVE_NTGUI
4588 /* Get the X image IMG->pixmap. */
4589 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4590 0, 0, img->width, img->height, ~0, ZPixmap);
4591 #else
4592 /* Load the image into a memory device context. */
4593 hdc = get_frame_dc (f);
4594 ximg = CreateCompatibleDC (hdc);
4595 release_frame_dc (f, hdc);
4596 prev = SelectObject (ximg, img->pixmap);
4597 #endif /* HAVE_NTGUI */
4599 /* Fill the `pixel' members of the XColor array. I wished there
4600 were an easy and portable way to circumvent XGetPixel. */
4601 p = colors;
4602 for (y = 0; y < img->height; ++y)
4604 XColor *row = p;
4606 #ifdef HAVE_X_WINDOWS
4607 for (x = 0; x < img->width; ++x, ++p)
4608 p->pixel = XGetPixel (ximg, x, y);
4609 if (rgb_p)
4610 x_query_colors (f, row, img->width);
4612 #else
4614 for (x = 0; x < img->width; ++x, ++p)
4616 /* W32_TODO: palette support needed here? */
4617 p->pixel = GET_PIXEL (ximg, x, y);
4618 if (rgb_p)
4620 #ifdef MAC_OS
4621 p->red = RED16_FROM_ULONG (p->pixel);
4622 p->green = GREEN16_FROM_ULONG (p->pixel);
4623 p->blue = BLUE16_FROM_ULONG (p->pixel);
4624 #endif /* MAC_OS */
4625 #ifdef HAVE_NTGUI
4626 p->red = 256 * GetRValue (p->pixel);
4627 p->green = 256 * GetGValue (p->pixel);
4628 p->blue = 256 * GetBValue (p->pixel);
4629 #endif /* HAVE_NTGUI */
4632 #endif /* HAVE_X_WINDOWS */
4635 Destroy_Image (ximg, prev);
4637 return colors;
4640 #ifdef HAVE_NTGUI
4642 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4643 created with CreateDIBSection, with the pointer to the bit values
4644 stored in ximg->data. */
4646 static void XPutPixel (ximg, x, y, color)
4647 XImagePtr ximg;
4648 int x, y;
4649 COLORREF color;
4651 int width = ximg->info.bmiHeader.biWidth;
4652 int height = ximg->info.bmiHeader.biHeight;
4653 unsigned char * pixel;
4655 /* True color images. */
4656 if (ximg->info.bmiHeader.biBitCount == 24)
4658 int rowbytes = width * 3;
4659 /* Ensure scanlines are aligned on 4 byte boundaries. */
4660 if (rowbytes % 4)
4661 rowbytes += 4 - (rowbytes % 4);
4663 pixel = ximg->data + y * rowbytes + x * 3;
4664 /* Windows bitmaps are in BGR order. */
4665 *pixel = GetBValue (color);
4666 *(pixel + 1) = GetGValue (color);
4667 *(pixel + 2) = GetRValue (color);
4669 /* Monochrome images. */
4670 else if (ximg->info.bmiHeader.biBitCount == 1)
4672 int rowbytes = width / 8;
4673 /* Ensure scanlines are aligned on 4 byte boundaries. */
4674 if (rowbytes % 4)
4675 rowbytes += 4 - (rowbytes % 4);
4676 pixel = ximg->data + y * rowbytes + x / 8;
4677 /* Filter out palette info. */
4678 if (color & 0x00ffffff)
4679 *pixel = *pixel | (1 << x % 8);
4680 else
4681 *pixel = *pixel & ~(1 << x % 8);
4683 else
4684 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4687 #endif /* HAVE_NTGUI */
4689 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
4690 RGB members are set. F is the frame on which this all happens.
4691 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4693 static void
4694 x_from_xcolors (f, img, colors)
4695 struct frame *f;
4696 struct image *img;
4697 XColor *colors;
4699 int x, y;
4700 XImagePtr oimg;
4701 Pixmap pixmap;
4702 XColor *p;
4704 init_color_table ();
4706 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4707 &oimg, &pixmap);
4708 p = colors;
4709 for (y = 0; y < img->height; ++y)
4710 for (x = 0; x < img->width; ++x, ++p)
4712 unsigned long pixel;
4713 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4714 XPutPixel (oimg, x, y, pixel);
4717 xfree (colors);
4718 x_clear_image_1 (f, img, 1, 0, 1);
4720 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4721 x_destroy_x_image (oimg);
4722 img->pixmap = pixmap;
4723 #ifdef COLOR_TABLE_SUPPORT
4724 img->colors = colors_in_color_table (&img->ncolors);
4725 free_color_table ();
4726 #endif /* COLOR_TABLE_SUPPORT */
4730 /* On frame F, perform edge-detection on image IMG.
4732 MATRIX is a nine-element array specifying the transformation
4733 matrix. See emboss_matrix for an example.
4735 COLOR_ADJUST is a color adjustment added to each pixel of the
4736 outgoing image. */
4738 static void
4739 x_detect_edges (f, img, matrix, color_adjust)
4740 struct frame *f;
4741 struct image *img;
4742 int matrix[9], color_adjust;
4744 XColor *colors = x_to_xcolors (f, img, 1);
4745 XColor *new, *p;
4746 int x, y, i, sum;
4748 for (i = sum = 0; i < 9; ++i)
4749 sum += abs (matrix[i]);
4751 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4753 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4755 for (y = 0; y < img->height; ++y)
4757 p = COLOR (new, 0, y);
4758 p->red = p->green = p->blue = 0xffff/2;
4759 p = COLOR (new, img->width - 1, y);
4760 p->red = p->green = p->blue = 0xffff/2;
4763 for (x = 1; x < img->width - 1; ++x)
4765 p = COLOR (new, x, 0);
4766 p->red = p->green = p->blue = 0xffff/2;
4767 p = COLOR (new, x, img->height - 1);
4768 p->red = p->green = p->blue = 0xffff/2;
4771 for (y = 1; y < img->height - 1; ++y)
4773 p = COLOR (new, 1, y);
4775 for (x = 1; x < img->width - 1; ++x, ++p)
4777 int r, g, b, y1, x1;
4779 r = g = b = i = 0;
4780 for (y1 = y - 1; y1 < y + 2; ++y1)
4781 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4782 if (matrix[i])
4784 XColor *t = COLOR (colors, x1, y1);
4785 r += matrix[i] * t->red;
4786 g += matrix[i] * t->green;
4787 b += matrix[i] * t->blue;
4790 r = (r / sum + color_adjust) & 0xffff;
4791 g = (g / sum + color_adjust) & 0xffff;
4792 b = (b / sum + color_adjust) & 0xffff;
4793 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4797 xfree (colors);
4798 x_from_xcolors (f, img, new);
4800 #undef COLOR
4804 /* Perform the pre-defined `emboss' edge-detection on image IMG
4805 on frame F. */
4807 static void
4808 x_emboss (f, img)
4809 struct frame *f;
4810 struct image *img;
4812 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4816 /* Transform image IMG which is used on frame F with a Laplace
4817 edge-detection algorithm. The result is an image that can be used
4818 to draw disabled buttons, for example. */
4820 static void
4821 x_laplace (f, img)
4822 struct frame *f;
4823 struct image *img;
4825 x_detect_edges (f, img, laplace_matrix, 45000);
4829 /* Perform edge-detection on image IMG on frame F, with specified
4830 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
4832 MATRIX must be either
4834 - a list of at least 9 numbers in row-major form
4835 - a vector of at least 9 numbers
4837 COLOR_ADJUST nil means use a default; otherwise it must be a
4838 number. */
4840 static void
4841 x_edge_detection (f, img, matrix, color_adjust)
4842 struct frame *f;
4843 struct image *img;
4844 Lisp_Object matrix, color_adjust;
4846 int i = 0;
4847 int trans[9];
4849 if (CONSP (matrix))
4851 for (i = 0;
4852 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
4853 ++i, matrix = XCDR (matrix))
4854 trans[i] = XFLOATINT (XCAR (matrix));
4856 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
4858 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
4859 trans[i] = XFLOATINT (AREF (matrix, i));
4862 if (NILP (color_adjust))
4863 color_adjust = make_number (0xffff / 2);
4865 if (i == 9 && NUMBERP (color_adjust))
4866 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
4870 /* Transform image IMG on frame F so that it looks disabled. */
4872 static void
4873 x_disable_image (f, img)
4874 struct frame *f;
4875 struct image *img;
4877 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4878 #ifdef HAVE_NTGUI
4879 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
4880 #else
4881 int n_planes = dpyinfo->n_planes;
4882 #endif /* HAVE_NTGUI */
4884 if (n_planes >= 2)
4886 /* Color (or grayscale). Convert to gray, and equalize. Just
4887 drawing such images with a stipple can look very odd, so
4888 we're using this method instead. */
4889 XColor *colors = x_to_xcolors (f, img, 1);
4890 XColor *p, *end;
4891 const int h = 15000;
4892 const int l = 30000;
4894 for (p = colors, end = colors + img->width * img->height;
4895 p < end;
4896 ++p)
4898 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
4899 int i2 = (0xffff - h - l) * i / 0xffff + l;
4900 p->red = p->green = p->blue = i2;
4903 x_from_xcolors (f, img, colors);
4906 /* Draw a cross over the disabled image, if we must or if we
4907 should. */
4908 if (n_planes < 2 || cross_disabled_images)
4910 #ifndef HAVE_NTGUI
4911 Display *dpy = FRAME_X_DISPLAY (f);
4912 GC gc;
4914 #ifdef MAC_OS
4915 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
4916 #define MaskForeground(f) PIX_MASK_DRAW (f)
4917 #else
4918 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
4919 #define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4920 #endif
4922 gc = XCreateGC_pixmap (dpy, img->pixmap);
4923 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
4924 XDrawLine (dpy, img->pixmap, gc, 0, 0,
4925 img->width - 1, img->height - 1);
4926 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
4927 img->width - 1, 0);
4928 XFreeGC (dpy, gc);
4930 if (img->mask)
4932 gc = XCreateGC_pixmap (dpy, img->mask);
4933 XSetForeground (dpy, gc, MaskForeground (f));
4934 XDrawLine (dpy, img->mask, gc, 0, 0,
4935 img->width - 1, img->height - 1);
4936 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
4937 img->width - 1, 0);
4938 XFreeGC (dpy, gc);
4940 #else
4941 HDC hdc, bmpdc;
4942 HGDIOBJ prev;
4944 hdc = get_frame_dc (f);
4945 bmpdc = CreateCompatibleDC (hdc);
4946 release_frame_dc (f, hdc);
4948 prev = SelectObject (bmpdc, img->pixmap);
4950 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
4951 MoveToEx (bmpdc, 0, 0, NULL);
4952 LineTo (bmpdc, img->width - 1, img->height - 1);
4953 MoveToEx (bmpdc, 0, img->height - 1, NULL);
4954 LineTo (bmpdc, img->width - 1, 0);
4956 if (img->mask)
4958 SelectObject (bmpdc, img->mask);
4959 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
4960 MoveToEx (bmpdc, 0, 0, NULL);
4961 LineTo (bmpdc, img->width - 1, img->height - 1);
4962 MoveToEx (bmpdc, 0, img->height - 1, NULL);
4963 LineTo (bmpdc, img->width - 1, 0);
4965 SelectObject (bmpdc, prev);
4966 DeleteDC (bmpdc);
4967 #endif /* HAVE_NTGUI */
4972 /* Build a mask for image IMG which is used on frame F. FILE is the
4973 name of an image file, for error messages. HOW determines how to
4974 determine the background color of IMG. If it is a list '(R G B)',
4975 with R, G, and B being integers >= 0, take that as the color of the
4976 background. Otherwise, determine the background color of IMG
4977 heuristically. Value is non-zero if successful. */
4979 static int
4980 x_build_heuristic_mask (f, img, how)
4981 struct frame *f;
4982 struct image *img;
4983 Lisp_Object how;
4985 XImagePtr_or_DC ximg;
4986 #ifndef HAVE_NTGUI
4987 XImagePtr mask_img;
4988 #else
4989 HDC frame_dc;
4990 HGDIOBJ prev;
4991 char *mask_img;
4992 int row_width;
4993 #endif /* HAVE_NTGUI */
4994 int x, y, rc, use_img_background;
4995 unsigned long bg = 0;
4997 if (img->mask)
4999 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
5000 img->mask = NO_PIXMAP;
5001 img->background_transparent_valid = 0;
5004 #ifndef HAVE_NTGUI
5005 /* Create an image and pixmap serving as mask. */
5006 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
5007 &mask_img, &img->mask);
5008 if (!rc)
5009 return 0;
5011 /* Get the X image of IMG->pixmap. */
5012 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
5013 img->width, img->height,
5014 ~0, ZPixmap);
5015 #else
5016 /* Create the bit array serving as mask. */
5017 row_width = (img->width + 7) / 8;
5018 mask_img = xmalloc (row_width * img->height);
5019 bzero (mask_img, row_width * img->height);
5021 /* Create a memory device context for IMG->pixmap. */
5022 frame_dc = get_frame_dc (f);
5023 ximg = CreateCompatibleDC (frame_dc);
5024 release_frame_dc (f, frame_dc);
5025 prev = SelectObject (ximg, img->pixmap);
5026 #endif /* HAVE_NTGUI */
5028 /* Determine the background color of ximg. If HOW is `(R G B)'
5029 take that as color. Otherwise, use the image's background color. */
5030 use_img_background = 1;
5032 if (CONSP (how))
5034 int rgb[3], i;
5036 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
5038 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
5039 how = XCDR (how);
5042 if (i == 3 && NILP (how))
5044 char color_name[30];
5045 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
5046 bg = (
5047 #ifdef HAVE_NTGUI
5048 0x00ffffff & /* Filter out palette info. */
5049 #endif /* HAVE_NTGUI */
5050 x_alloc_image_color (f, img, build_string (color_name), 0));
5051 use_img_background = 0;
5055 if (use_img_background)
5056 bg = four_corners_best (ximg, img->width, img->height);
5058 /* Set all bits in mask_img to 1 whose color in ximg is different
5059 from the background color bg. */
5060 #ifndef HAVE_NTGUI
5061 for (y = 0; y < img->height; ++y)
5062 for (x = 0; x < img->width; ++x)
5063 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
5064 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
5066 /* Fill in the background_transparent field while we have the mask handy. */
5067 image_background_transparent (img, f, mask_img);
5069 /* Put mask_img into img->mask. */
5070 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5071 x_destroy_x_image (mask_img);
5073 #else
5074 for (y = 0; y < img->height; ++y)
5075 for (x = 0; x < img->width; ++x)
5077 COLORREF p = GetPixel (ximg, x, y);
5078 if (p != bg)
5079 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
5082 /* Create the mask image. */
5083 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
5084 mask_img);
5085 /* Fill in the background_transparent field while we have the mask handy. */
5086 SelectObject (ximg, img->mask);
5087 image_background_transparent (img, f, ximg);
5089 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
5090 xfree (mask_img);
5091 #endif /* HAVE_NTGUI */
5093 Destroy_Image (ximg, prev);
5095 return 1;
5099 /***********************************************************************
5100 PBM (mono, gray, color)
5101 ***********************************************************************/
5103 static int pbm_image_p P_ ((Lisp_Object object));
5104 static int pbm_load P_ ((struct frame *f, struct image *img));
5105 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
5107 /* The symbol `pbm' identifying images of this type. */
5109 Lisp_Object Qpbm;
5111 /* Indices of image specification fields in gs_format, below. */
5113 enum pbm_keyword_index
5115 PBM_TYPE,
5116 PBM_FILE,
5117 PBM_DATA,
5118 PBM_ASCENT,
5119 PBM_MARGIN,
5120 PBM_RELIEF,
5121 PBM_ALGORITHM,
5122 PBM_HEURISTIC_MASK,
5123 PBM_MASK,
5124 PBM_FOREGROUND,
5125 PBM_BACKGROUND,
5126 PBM_LAST
5129 /* Vector of image_keyword structures describing the format
5130 of valid user-defined image specifications. */
5132 static struct image_keyword pbm_format[PBM_LAST] =
5134 {":type", IMAGE_SYMBOL_VALUE, 1},
5135 {":file", IMAGE_STRING_VALUE, 0},
5136 {":data", IMAGE_STRING_VALUE, 0},
5137 {":ascent", IMAGE_ASCENT_VALUE, 0},
5138 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5139 {":relief", IMAGE_INTEGER_VALUE, 0},
5140 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5141 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5142 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5143 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5144 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5147 /* Structure describing the image type `pbm'. */
5149 static struct image_type pbm_type =
5151 &Qpbm,
5152 pbm_image_p,
5153 pbm_load,
5154 x_clear_image,
5155 NULL
5159 /* Return non-zero if OBJECT is a valid PBM image specification. */
5161 static int
5162 pbm_image_p (object)
5163 Lisp_Object object;
5165 struct image_keyword fmt[PBM_LAST];
5167 bcopy (pbm_format, fmt, sizeof fmt);
5169 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
5170 return 0;
5172 /* Must specify either :data or :file. */
5173 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
5177 /* Scan a decimal number from *S and return it. Advance *S while
5178 reading the number. END is the end of the string. Value is -1 at
5179 end of input. */
5181 static int
5182 pbm_scan_number (s, end)
5183 unsigned char **s, *end;
5185 int c = 0, val = -1;
5187 while (*s < end)
5189 /* Skip white-space. */
5190 while (*s < end && (c = *(*s)++, isspace (c)))
5193 if (c == '#')
5195 /* Skip comment to end of line. */
5196 while (*s < end && (c = *(*s)++, c != '\n'))
5199 else if (isdigit (c))
5201 /* Read decimal number. */
5202 val = c - '0';
5203 while (*s < end && (c = *(*s)++, isdigit (c)))
5204 val = 10 * val + c - '0';
5205 break;
5207 else
5208 break;
5211 return val;
5215 #ifdef HAVE_NTGUI
5216 #if 0 /* Unused. ++kfs */
5218 /* Read FILE into memory. Value is a pointer to a buffer allocated
5219 with xmalloc holding FILE's contents. Value is null if an error
5220 occurred. *SIZE is set to the size of the file. */
5222 static char *
5223 pbm_read_file (file, size)
5224 Lisp_Object file;
5225 int *size;
5227 FILE *fp = NULL;
5228 char *buf = NULL;
5229 struct stat st;
5231 if (stat (SDATA (file), &st) == 0
5232 && (fp = fopen (SDATA (file), "rb")) != NULL
5233 && (buf = (char *) xmalloc (st.st_size),
5234 fread (buf, 1, st.st_size, fp) == st.st_size))
5236 *size = st.st_size;
5237 fclose (fp);
5239 else
5241 if (fp)
5242 fclose (fp);
5243 if (buf)
5245 xfree (buf);
5246 buf = NULL;
5250 return buf;
5252 #endif
5253 #endif /* HAVE_NTGUI */
5255 /* Load PBM image IMG for use on frame F. */
5257 static int
5258 pbm_load (f, img)
5259 struct frame *f;
5260 struct image *img;
5262 int raw_p, x, y;
5263 int width, height, max_color_idx = 0;
5264 XImagePtr ximg;
5265 Lisp_Object file, specified_file;
5266 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
5267 struct gcpro gcpro1;
5268 unsigned char *contents = NULL;
5269 unsigned char *end, *p;
5270 int size;
5272 specified_file = image_spec_value (img->spec, QCfile, NULL);
5273 file = Qnil;
5274 GCPRO1 (file);
5276 if (STRINGP (specified_file))
5278 file = x_find_image_file (specified_file);
5279 if (!STRINGP (file))
5281 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5282 UNGCPRO;
5283 return 0;
5286 contents = slurp_file (SDATA (file), &size);
5287 if (contents == NULL)
5289 image_error ("Error reading `%s'", file, Qnil);
5290 UNGCPRO;
5291 return 0;
5294 p = contents;
5295 end = contents + size;
5297 else
5299 Lisp_Object data;
5300 data = image_spec_value (img->spec, QCdata, NULL);
5301 p = SDATA (data);
5302 end = p + SBYTES (data);
5305 /* Check magic number. */
5306 if (end - p < 2 || *p++ != 'P')
5308 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5309 error:
5310 xfree (contents);
5311 UNGCPRO;
5312 return 0;
5315 switch (*p++)
5317 case '1':
5318 raw_p = 0, type = PBM_MONO;
5319 break;
5321 case '2':
5322 raw_p = 0, type = PBM_GRAY;
5323 break;
5325 case '3':
5326 raw_p = 0, type = PBM_COLOR;
5327 break;
5329 case '4':
5330 raw_p = 1, type = PBM_MONO;
5331 break;
5333 case '5':
5334 raw_p = 1, type = PBM_GRAY;
5335 break;
5337 case '6':
5338 raw_p = 1, type = PBM_COLOR;
5339 break;
5341 default:
5342 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5343 goto error;
5346 /* Read width, height, maximum color-component. Characters
5347 starting with `#' up to the end of a line are ignored. */
5348 width = pbm_scan_number (&p, end);
5349 height = pbm_scan_number (&p, end);
5351 if (type != PBM_MONO)
5353 max_color_idx = pbm_scan_number (&p, end);
5354 if (raw_p && max_color_idx > 255)
5355 max_color_idx = 255;
5358 if (width < 0
5359 || height < 0
5360 || (type != PBM_MONO && max_color_idx < 0))
5361 goto error;
5363 if (!x_create_x_image_and_pixmap (f, width, height, 0,
5364 &ximg, &img->pixmap))
5365 goto error;
5367 /* Initialize the color hash table. */
5368 init_color_table ();
5370 if (type == PBM_MONO)
5372 int c = 0, g;
5373 struct image_keyword fmt[PBM_LAST];
5374 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
5375 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
5377 /* Parse the image specification. */
5378 bcopy (pbm_format, fmt, sizeof fmt);
5379 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
5381 /* Get foreground and background colors, maybe allocate colors. */
5382 if (fmt[PBM_FOREGROUND].count
5383 && STRINGP (fmt[PBM_FOREGROUND].value))
5384 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
5385 if (fmt[PBM_BACKGROUND].count
5386 && STRINGP (fmt[PBM_BACKGROUND].value))
5388 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
5389 img->background = bg;
5390 img->background_valid = 1;
5393 for (y = 0; y < height; ++y)
5394 for (x = 0; x < width; ++x)
5396 if (raw_p)
5398 if ((x & 7) == 0)
5399 c = *p++;
5400 g = c & 0x80;
5401 c <<= 1;
5403 else
5404 g = pbm_scan_number (&p, end);
5406 XPutPixel (ximg, x, y, g ? fg : bg);
5409 else
5411 for (y = 0; y < height; ++y)
5412 for (x = 0; x < width; ++x)
5414 int r, g, b;
5416 if (type == PBM_GRAY)
5417 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
5418 else if (raw_p)
5420 r = *p++;
5421 g = *p++;
5422 b = *p++;
5424 else
5426 r = pbm_scan_number (&p, end);
5427 g = pbm_scan_number (&p, end);
5428 b = pbm_scan_number (&p, end);
5431 if (r < 0 || g < 0 || b < 0)
5433 x_destroy_x_image (ximg);
5434 image_error ("Invalid pixel value in image `%s'",
5435 img->spec, Qnil);
5436 goto error;
5439 /* RGB values are now in the range 0..max_color_idx.
5440 Scale this to the range 0..0xffff supported by X. */
5441 r = (double) r * 65535 / max_color_idx;
5442 g = (double) g * 65535 / max_color_idx;
5443 b = (double) b * 65535 / max_color_idx;
5444 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5448 #ifdef COLOR_TABLE_SUPPORT
5449 /* Store in IMG->colors the colors allocated for the image, and
5450 free the color table. */
5451 img->colors = colors_in_color_table (&img->ncolors);
5452 free_color_table ();
5453 #endif /* COLOR_TABLE_SUPPORT */
5455 img->width = width;
5456 img->height = height;
5458 /* Maybe fill in the background field while we have ximg handy. */
5460 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5461 IMAGE_BACKGROUND (img, f, ximg);
5463 /* Put the image into a pixmap. */
5464 x_put_x_image (f, ximg, img->pixmap, width, height);
5465 x_destroy_x_image (ximg);
5467 /* X and W32 versions did it here, MAC version above. ++kfs
5468 img->width = width;
5469 img->height = height; */
5471 UNGCPRO;
5472 xfree (contents);
5473 return 1;
5477 /***********************************************************************
5479 ***********************************************************************/
5481 #if defined (HAVE_PNG) || defined (MAC_OS)
5483 /* Function prototypes. */
5485 static int png_image_p P_ ((Lisp_Object object));
5486 static int png_load P_ ((struct frame *f, struct image *img));
5488 /* The symbol `png' identifying images of this type. */
5490 Lisp_Object Qpng;
5492 /* Indices of image specification fields in png_format, below. */
5494 enum png_keyword_index
5496 PNG_TYPE,
5497 PNG_DATA,
5498 PNG_FILE,
5499 PNG_ASCENT,
5500 PNG_MARGIN,
5501 PNG_RELIEF,
5502 PNG_ALGORITHM,
5503 PNG_HEURISTIC_MASK,
5504 PNG_MASK,
5505 PNG_BACKGROUND,
5506 PNG_LAST
5509 /* Vector of image_keyword structures describing the format
5510 of valid user-defined image specifications. */
5512 static struct image_keyword png_format[PNG_LAST] =
5514 {":type", IMAGE_SYMBOL_VALUE, 1},
5515 {":data", IMAGE_STRING_VALUE, 0},
5516 {":file", IMAGE_STRING_VALUE, 0},
5517 {":ascent", IMAGE_ASCENT_VALUE, 0},
5518 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5519 {":relief", IMAGE_INTEGER_VALUE, 0},
5520 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5521 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5522 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5523 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5526 /* Structure describing the image type `png'. */
5528 static struct image_type png_type =
5530 &Qpng,
5531 png_image_p,
5532 png_load,
5533 x_clear_image,
5534 NULL
5537 /* Return non-zero if OBJECT is a valid PNG image specification. */
5539 static int
5540 png_image_p (object)
5541 Lisp_Object object;
5543 struct image_keyword fmt[PNG_LAST];
5544 bcopy (png_format, fmt, sizeof fmt);
5546 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5547 return 0;
5549 /* Must specify either the :data or :file keyword. */
5550 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5553 #endif /* HAVE_PNG || MAC_OS */
5556 #ifdef HAVE_PNG
5558 #if defined HAVE_LIBPNG_PNG_H
5559 # include <libpng/png.h>
5560 #else
5561 # include <png.h>
5562 #endif
5564 #ifdef HAVE_NTGUI
5565 /* PNG library details. */
5567 DEF_IMGLIB_FN (png_get_io_ptr);
5568 DEF_IMGLIB_FN (png_check_sig);
5569 DEF_IMGLIB_FN (png_create_read_struct);
5570 DEF_IMGLIB_FN (png_create_info_struct);
5571 DEF_IMGLIB_FN (png_destroy_read_struct);
5572 DEF_IMGLIB_FN (png_set_read_fn);
5573 DEF_IMGLIB_FN (png_init_io);
5574 DEF_IMGLIB_FN (png_set_sig_bytes);
5575 DEF_IMGLIB_FN (png_read_info);
5576 DEF_IMGLIB_FN (png_get_IHDR);
5577 DEF_IMGLIB_FN (png_get_valid);
5578 DEF_IMGLIB_FN (png_set_strip_16);
5579 DEF_IMGLIB_FN (png_set_expand);
5580 DEF_IMGLIB_FN (png_set_gray_to_rgb);
5581 DEF_IMGLIB_FN (png_set_background);
5582 DEF_IMGLIB_FN (png_get_bKGD);
5583 DEF_IMGLIB_FN (png_read_update_info);
5584 DEF_IMGLIB_FN (png_get_channels);
5585 DEF_IMGLIB_FN (png_get_rowbytes);
5586 DEF_IMGLIB_FN (png_read_image);
5587 DEF_IMGLIB_FN (png_read_end);
5588 DEF_IMGLIB_FN (png_error);
5590 static int
5591 init_png_functions (void)
5593 HMODULE library;
5595 /* Ensure zlib is loaded. Try debug version first. */
5596 if (!LoadLibrary ("zlibd.dll")
5597 && !LoadLibrary ("zlib.dll"))
5598 return 0;
5600 /* Try loading libpng under probable names. */
5601 if (!(library = LoadLibrary ("libpng13d.dll"))
5602 && !(library = LoadLibrary ("libpng13.dll"))
5603 && !(library = LoadLibrary ("libpng12d.dll"))
5604 && !(library = LoadLibrary ("libpng12.dll"))
5605 && !(library = LoadLibrary ("libpng.dll")))
5606 return 0;
5608 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5609 LOAD_IMGLIB_FN (library, png_check_sig);
5610 LOAD_IMGLIB_FN (library, png_create_read_struct);
5611 LOAD_IMGLIB_FN (library, png_create_info_struct);
5612 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5613 LOAD_IMGLIB_FN (library, png_set_read_fn);
5614 LOAD_IMGLIB_FN (library, png_init_io);
5615 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5616 LOAD_IMGLIB_FN (library, png_read_info);
5617 LOAD_IMGLIB_FN (library, png_get_IHDR);
5618 LOAD_IMGLIB_FN (library, png_get_valid);
5619 LOAD_IMGLIB_FN (library, png_set_strip_16);
5620 LOAD_IMGLIB_FN (library, png_set_expand);
5621 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5622 LOAD_IMGLIB_FN (library, png_set_background);
5623 LOAD_IMGLIB_FN (library, png_get_bKGD);
5624 LOAD_IMGLIB_FN (library, png_read_update_info);
5625 LOAD_IMGLIB_FN (library, png_get_channels);
5626 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5627 LOAD_IMGLIB_FN (library, png_read_image);
5628 LOAD_IMGLIB_FN (library, png_read_end);
5629 LOAD_IMGLIB_FN (library, png_error);
5630 return 1;
5632 #else
5634 #define fn_png_get_io_ptr png_get_io_ptr
5635 #define fn_png_check_sig png_check_sig
5636 #define fn_png_create_read_struct png_create_read_struct
5637 #define fn_png_create_info_struct png_create_info_struct
5638 #define fn_png_destroy_read_struct png_destroy_read_struct
5639 #define fn_png_set_read_fn png_set_read_fn
5640 #define fn_png_init_io png_init_io
5641 #define fn_png_set_sig_bytes png_set_sig_bytes
5642 #define fn_png_read_info png_read_info
5643 #define fn_png_get_IHDR png_get_IHDR
5644 #define fn_png_get_valid png_get_valid
5645 #define fn_png_set_strip_16 png_set_strip_16
5646 #define fn_png_set_expand png_set_expand
5647 #define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5648 #define fn_png_set_background png_set_background
5649 #define fn_png_get_bKGD png_get_bKGD
5650 #define fn_png_read_update_info png_read_update_info
5651 #define fn_png_get_channels png_get_channels
5652 #define fn_png_get_rowbytes png_get_rowbytes
5653 #define fn_png_read_image png_read_image
5654 #define fn_png_read_end png_read_end
5655 #define fn_png_error png_error
5657 #endif /* HAVE_NTGUI */
5659 /* Error and warning handlers installed when the PNG library
5660 is initialized. */
5662 static void
5663 my_png_error (png_ptr, msg)
5664 png_struct *png_ptr;
5665 char *msg;
5667 xassert (png_ptr != NULL);
5668 image_error ("PNG error: %s", build_string (msg), Qnil);
5669 longjmp (png_ptr->jmpbuf, 1);
5673 static void
5674 my_png_warning (png_ptr, msg)
5675 png_struct *png_ptr;
5676 char *msg;
5678 xassert (png_ptr != NULL);
5679 image_error ("PNG warning: %s", build_string (msg), Qnil);
5682 /* Memory source for PNG decoding. */
5684 struct png_memory_storage
5686 unsigned char *bytes; /* The data */
5687 size_t len; /* How big is it? */
5688 int index; /* Where are we? */
5692 /* Function set as reader function when reading PNG image from memory.
5693 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5694 bytes from the input to DATA. */
5696 #ifdef _MSC_VER
5697 /* Work around a problem with MinGW builds of graphics libraries
5698 not honoring calling conventions. */
5699 #pragma optimize("g", off)
5700 #endif
5702 static void
5703 png_read_from_memory (png_ptr, data, length)
5704 png_structp png_ptr;
5705 png_bytep data;
5706 png_size_t length;
5708 struct png_memory_storage *tbr
5709 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5711 if (length > tbr->len - tbr->index)
5712 fn_png_error (png_ptr, "Read error");
5714 bcopy (tbr->bytes + tbr->index, data, length);
5715 tbr->index = tbr->index + length;
5718 #ifdef _MSC_VER
5719 /* Restore normal optimization, as specified on the command line. */
5720 #pragma optimize("", on)
5721 #endif
5723 /* Load PNG image IMG for use on frame F. Value is non-zero if
5724 successful. */
5726 static int
5727 png_load (f, img)
5728 struct frame *f;
5729 struct image *img;
5731 Lisp_Object file, specified_file;
5732 Lisp_Object specified_data;
5733 int x, y, i;
5734 XImagePtr ximg, mask_img = NULL;
5735 struct gcpro gcpro1;
5736 png_struct *png_ptr = NULL;
5737 png_info *info_ptr = NULL, *end_info = NULL;
5738 FILE *volatile fp = NULL;
5739 png_byte sig[8];
5740 png_byte * volatile pixels = NULL;
5741 png_byte ** volatile rows = NULL;
5742 png_uint_32 width, height;
5743 int bit_depth, color_type, interlace_type;
5744 png_byte channels;
5745 png_uint_32 row_bytes;
5746 int transparent_p;
5747 double screen_gamma;
5748 struct png_memory_storage tbr; /* Data to be read */
5750 /* Find out what file to load. */
5751 specified_file = image_spec_value (img->spec, QCfile, NULL);
5752 specified_data = image_spec_value (img->spec, QCdata, NULL);
5753 file = Qnil;
5754 GCPRO1 (file);
5756 if (NILP (specified_data))
5758 file = x_find_image_file (specified_file);
5759 if (!STRINGP (file))
5761 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5762 UNGCPRO;
5763 return 0;
5766 /* Open the image file. */
5767 fp = fopen (SDATA (file), "rb");
5768 if (!fp)
5770 image_error ("Cannot open image file `%s'", file, Qnil);
5771 UNGCPRO;
5772 fclose (fp);
5773 return 0;
5776 /* Check PNG signature. */
5777 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
5778 || !fn_png_check_sig (sig, sizeof sig))
5780 image_error ("Not a PNG file: `%s'", file, Qnil);
5781 UNGCPRO;
5782 fclose (fp);
5783 return 0;
5786 else
5788 /* Read from memory. */
5789 tbr.bytes = SDATA (specified_data);
5790 tbr.len = SBYTES (specified_data);
5791 tbr.index = 0;
5793 /* Check PNG signature. */
5794 if (tbr.len < sizeof sig
5795 || !fn_png_check_sig (tbr.bytes, sizeof sig))
5797 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5798 UNGCPRO;
5799 return 0;
5802 /* Need to skip past the signature. */
5803 tbr.bytes += sizeof (sig);
5806 /* Initialize read and info structs for PNG lib. */
5807 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
5808 my_png_error, my_png_warning);
5809 if (!png_ptr)
5811 if (fp) fclose (fp);
5812 UNGCPRO;
5813 return 0;
5816 info_ptr = fn_png_create_info_struct (png_ptr);
5817 if (!info_ptr)
5819 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
5820 if (fp) fclose (fp);
5821 UNGCPRO;
5822 return 0;
5825 end_info = fn_png_create_info_struct (png_ptr);
5826 if (!end_info)
5828 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
5829 if (fp) fclose (fp);
5830 UNGCPRO;
5831 return 0;
5834 /* Set error jump-back. We come back here when the PNG library
5835 detects an error. */
5836 if (setjmp (png_ptr->jmpbuf))
5838 error:
5839 if (png_ptr)
5840 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
5841 xfree (pixels);
5842 xfree (rows);
5843 if (fp) fclose (fp);
5844 UNGCPRO;
5845 return 0;
5848 /* Read image info. */
5849 if (!NILP (specified_data))
5850 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
5851 else
5852 fn_png_init_io (png_ptr, fp);
5854 fn_png_set_sig_bytes (png_ptr, sizeof sig);
5855 fn_png_read_info (png_ptr, info_ptr);
5856 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
5857 &interlace_type, NULL, NULL);
5859 /* If image contains simply transparency data, we prefer to
5860 construct a clipping mask. */
5861 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
5862 transparent_p = 1;
5863 else
5864 transparent_p = 0;
5866 /* This function is easier to write if we only have to handle
5867 one data format: RGB or RGBA with 8 bits per channel. Let's
5868 transform other formats into that format. */
5870 /* Strip more than 8 bits per channel. */
5871 if (bit_depth == 16)
5872 fn_png_set_strip_16 (png_ptr);
5874 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
5875 if available. */
5876 fn_png_set_expand (png_ptr);
5878 /* Convert grayscale images to RGB. */
5879 if (color_type == PNG_COLOR_TYPE_GRAY
5880 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
5881 fn_png_set_gray_to_rgb (png_ptr);
5883 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
5885 #if 0 /* Avoid double gamma correction for PNG images. */
5886 { /* Tell the PNG lib to handle gamma correction for us. */
5887 int intent;
5888 double image_gamma;
5889 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
5890 if (png_get_sRGB (png_ptr, info_ptr, &intent))
5891 /* The libpng documentation says this is right in this case. */
5892 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5893 else
5894 #endif
5895 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
5896 /* Image contains gamma information. */
5897 png_set_gamma (png_ptr, screen_gamma, image_gamma);
5898 else
5899 /* Use the standard default for the image gamma. */
5900 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5902 #endif /* if 0 */
5904 /* Handle alpha channel by combining the image with a background
5905 color. Do this only if a real alpha channel is supplied. For
5906 simple transparency, we prefer a clipping mask. */
5907 if (!transparent_p)
5909 png_color_16 *image_bg;
5910 Lisp_Object specified_bg
5911 = image_spec_value (img->spec, QCbackground, NULL);
5913 if (STRINGP (specified_bg))
5914 /* The user specified `:background', use that. */
5916 /* W32 version incorrectly used COLORREF here!! ++kfs */
5917 XColor color;
5918 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
5920 png_color_16 user_bg;
5922 bzero (&user_bg, sizeof user_bg);
5923 user_bg.red = color.red >> 8;
5924 user_bg.green = color.green >> 8;
5925 user_bg.blue = color.blue >> 8;
5927 fn_png_set_background (png_ptr, &user_bg,
5928 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5931 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
5932 /* Image contains a background color with which to
5933 combine the image. */
5934 fn_png_set_background (png_ptr, image_bg,
5935 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
5936 else
5938 /* Image does not contain a background color with which
5939 to combine the image data via an alpha channel. Use
5940 the frame's background instead. */
5941 #ifdef HAVE_X_WINDOWS
5942 XColor color;
5943 png_color_16 frame_background;
5945 color.pixel = FRAME_BACKGROUND_PIXEL (f);
5946 x_query_color (f, &color);
5948 bzero (&frame_background, sizeof frame_background);
5949 frame_background.red = color.red >> 8;
5950 frame_background.green = color.green >> 8;
5951 frame_background.blue = color.blue >> 8;
5952 #endif /* HAVE_X_WINDOWS */
5954 #ifdef HAVE_NTGUI
5955 COLORREF color;
5956 png_color_16 frame_background;
5957 color = FRAME_BACKGROUND_PIXEL (f);
5958 #if 0 /* W32 TODO : Colormap support. */
5959 x_query_color (f, &color);
5960 #endif
5961 bzero (&frame_background, sizeof frame_background);
5962 frame_background.red = GetRValue (color);
5963 frame_background.green = GetGValue (color);
5964 frame_background.blue = GetBValue (color);
5965 #endif /* HAVE_NTGUI */
5967 #ifdef MAC_OS
5968 unsigned long color;
5969 png_color_16 frame_background;
5970 color = FRAME_BACKGROUND_PIXEL (f);
5971 #if 0 /* MAC/W32 TODO : Colormap support. */
5972 x_query_color (f, &color);
5973 #endif
5974 bzero (&frame_background, sizeof frame_background);
5975 frame_background.red = RED_FROM_ULONG (color);
5976 frame_background.green = GREEN_FROM_ULONG (color);
5977 frame_background.blue = BLUE_FROM_ULONG (color);
5978 #endif /* MAC_OS */
5980 fn_png_set_background (png_ptr, &frame_background,
5981 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5985 /* Update info structure. */
5986 fn_png_read_update_info (png_ptr, info_ptr);
5988 /* Get number of channels. Valid values are 1 for grayscale images
5989 and images with a palette, 2 for grayscale images with transparency
5990 information (alpha channel), 3 for RGB images, and 4 for RGB
5991 images with alpha channel, i.e. RGBA. If conversions above were
5992 sufficient we should only have 3 or 4 channels here. */
5993 channels = fn_png_get_channels (png_ptr, info_ptr);
5994 xassert (channels == 3 || channels == 4);
5996 /* Number of bytes needed for one row of the image. */
5997 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
5999 /* Allocate memory for the image. */
6000 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
6001 rows = (png_byte **) xmalloc (height * sizeof *rows);
6002 for (i = 0; i < height; ++i)
6003 rows[i] = pixels + i * row_bytes;
6005 /* Read the entire image. */
6006 fn_png_read_image (png_ptr, rows);
6007 fn_png_read_end (png_ptr, info_ptr);
6008 if (fp)
6010 fclose (fp);
6011 fp = NULL;
6014 /* Create the X image and pixmap. */
6015 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
6016 &img->pixmap))
6017 goto error;
6019 /* Create an image and pixmap serving as mask if the PNG image
6020 contains an alpha channel. */
6021 if (channels == 4
6022 && !transparent_p
6023 && !x_create_x_image_and_pixmap (f, width, height, 1,
6024 &mask_img, &img->mask))
6026 x_destroy_x_image (ximg);
6027 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
6028 img->pixmap = NO_PIXMAP;
6029 goto error;
6032 /* Fill the X image and mask from PNG data. */
6033 init_color_table ();
6035 for (y = 0; y < height; ++y)
6037 png_byte *p = rows[y];
6039 for (x = 0; x < width; ++x)
6041 unsigned r, g, b;
6043 r = *p++ << 8;
6044 g = *p++ << 8;
6045 b = *p++ << 8;
6046 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6047 /* An alpha channel, aka mask channel, associates variable
6048 transparency with an image. Where other image formats
6049 support binary transparency---fully transparent or fully
6050 opaque---PNG allows up to 254 levels of partial transparency.
6051 The PNG library implements partial transparency by combining
6052 the image with a specified background color.
6054 I'm not sure how to handle this here nicely: because the
6055 background on which the image is displayed may change, for
6056 real alpha channel support, it would be necessary to create
6057 a new image for each possible background.
6059 What I'm doing now is that a mask is created if we have
6060 boolean transparency information. Otherwise I'm using
6061 the frame's background color to combine the image with. */
6063 if (channels == 4)
6065 if (mask_img)
6066 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
6067 ++p;
6072 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6073 /* Set IMG's background color from the PNG image, unless the user
6074 overrode it. */
6076 png_color_16 *bg;
6077 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
6079 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
6080 img->background_valid = 1;
6084 #ifdef COLOR_TABLE_SUPPORT
6085 /* Remember colors allocated for this image. */
6086 img->colors = colors_in_color_table (&img->ncolors);
6087 free_color_table ();
6088 #endif /* COLOR_TABLE_SUPPORT */
6090 /* Clean up. */
6091 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6092 xfree (rows);
6093 xfree (pixels);
6095 img->width = width;
6096 img->height = height;
6098 /* Maybe fill in the background field while we have ximg handy. */
6099 IMAGE_BACKGROUND (img, f, ximg);
6101 /* Put the image into the pixmap, then free the X image and its buffer. */
6102 x_put_x_image (f, ximg, img->pixmap, width, height);
6103 x_destroy_x_image (ximg);
6105 /* Same for the mask. */
6106 if (mask_img)
6108 /* Fill in the background_transparent field while we have the mask
6109 handy. */
6110 image_background_transparent (img, f, mask_img);
6112 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6113 x_destroy_x_image (mask_img);
6116 UNGCPRO;
6117 return 1;
6120 #else /* HAVE_PNG */
6122 #ifdef MAC_OS
6123 static int
6124 png_load (f, img)
6125 struct frame *f;
6126 struct image *img;
6128 #ifdef MAC_OSX
6129 if (MyCGImageCreateWithPNGDataProvider)
6130 return image_load_quartz2d (f, img, 1);
6131 else
6132 #endif
6133 return image_load_quicktime (f, img, kQTFileTypePNG);
6135 #endif /* MAC_OS */
6137 #endif /* !HAVE_PNG */
6141 /***********************************************************************
6142 JPEG
6143 ***********************************************************************/
6145 #if defined (HAVE_JPEG) || defined (MAC_OS)
6147 static int jpeg_image_p P_ ((Lisp_Object object));
6148 static int jpeg_load P_ ((struct frame *f, struct image *img));
6150 /* The symbol `jpeg' identifying images of this type. */
6152 Lisp_Object Qjpeg;
6154 /* Indices of image specification fields in gs_format, below. */
6156 enum jpeg_keyword_index
6158 JPEG_TYPE,
6159 JPEG_DATA,
6160 JPEG_FILE,
6161 JPEG_ASCENT,
6162 JPEG_MARGIN,
6163 JPEG_RELIEF,
6164 JPEG_ALGORITHM,
6165 JPEG_HEURISTIC_MASK,
6166 JPEG_MASK,
6167 JPEG_BACKGROUND,
6168 JPEG_LAST
6171 /* Vector of image_keyword structures describing the format
6172 of valid user-defined image specifications. */
6174 static struct image_keyword jpeg_format[JPEG_LAST] =
6176 {":type", IMAGE_SYMBOL_VALUE, 1},
6177 {":data", IMAGE_STRING_VALUE, 0},
6178 {":file", IMAGE_STRING_VALUE, 0},
6179 {":ascent", IMAGE_ASCENT_VALUE, 0},
6180 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6181 {":relief", IMAGE_INTEGER_VALUE, 0},
6182 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6183 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6184 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6185 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6188 /* Structure describing the image type `jpeg'. */
6190 static struct image_type jpeg_type =
6192 &Qjpeg,
6193 jpeg_image_p,
6194 jpeg_load,
6195 x_clear_image,
6196 NULL
6199 /* Return non-zero if OBJECT is a valid JPEG image specification. */
6201 static int
6202 jpeg_image_p (object)
6203 Lisp_Object object;
6205 struct image_keyword fmt[JPEG_LAST];
6207 bcopy (jpeg_format, fmt, sizeof fmt);
6209 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6210 return 0;
6212 /* Must specify either the :data or :file keyword. */
6213 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
6216 #endif /* HAVE_JPEG || MAC_OS */
6218 #ifdef HAVE_JPEG
6220 /* Work around a warning about HAVE_STDLIB_H being redefined in
6221 jconfig.h. */
6222 #ifdef HAVE_STDLIB_H
6223 #define HAVE_STDLIB_H_1
6224 #undef HAVE_STDLIB_H
6225 #endif /* HAVE_STLIB_H */
6227 #include <jpeglib.h>
6228 #include <jerror.h>
6229 #include <setjmp.h>
6231 #ifdef HAVE_STLIB_H_1
6232 #define HAVE_STDLIB_H 1
6233 #endif
6235 #ifdef HAVE_NTGUI
6237 /* JPEG library details. */
6238 DEF_IMGLIB_FN (jpeg_CreateDecompress);
6239 DEF_IMGLIB_FN (jpeg_start_decompress);
6240 DEF_IMGLIB_FN (jpeg_finish_decompress);
6241 DEF_IMGLIB_FN (jpeg_destroy_decompress);
6242 DEF_IMGLIB_FN (jpeg_read_header);
6243 DEF_IMGLIB_FN (jpeg_read_scanlines);
6244 DEF_IMGLIB_FN (jpeg_stdio_src);
6245 DEF_IMGLIB_FN (jpeg_std_error);
6246 DEF_IMGLIB_FN (jpeg_resync_to_restart);
6248 static int
6249 init_jpeg_functions (void)
6251 HMODULE library;
6253 if (!(library = LoadLibrary ("libjpeg.dll"))
6254 && !(library = LoadLibrary ("jpeg-62.dll"))
6255 && !(library = LoadLibrary ("jpeg.dll")))
6256 return 0;
6258 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
6259 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
6260 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
6261 LOAD_IMGLIB_FN (library, jpeg_read_header);
6262 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
6263 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
6264 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
6265 LOAD_IMGLIB_FN (library, jpeg_std_error);
6266 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
6267 return 1;
6270 /* Wrapper since we can't directly assign the function pointer
6271 to another function pointer that was declared more completely easily. */
6272 static boolean
6273 jpeg_resync_to_restart_wrapper(cinfo, desired)
6274 j_decompress_ptr cinfo;
6275 int desired;
6277 return fn_jpeg_resync_to_restart (cinfo, desired);
6280 #else
6282 #define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
6283 #define fn_jpeg_start_decompress jpeg_start_decompress
6284 #define fn_jpeg_finish_decompress jpeg_finish_decompress
6285 #define fn_jpeg_destroy_decompress jpeg_destroy_decompress
6286 #define fn_jpeg_read_header jpeg_read_header
6287 #define fn_jpeg_read_scanlines jpeg_read_scanlines
6288 #define fn_jpeg_stdio_src jpeg_stdio_src
6289 #define fn_jpeg_std_error jpeg_std_error
6290 #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
6292 #endif /* HAVE_NTGUI */
6294 struct my_jpeg_error_mgr
6296 struct jpeg_error_mgr pub;
6297 jmp_buf setjmp_buffer;
6301 static void
6302 my_error_exit (cinfo)
6303 j_common_ptr cinfo;
6305 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
6306 longjmp (mgr->setjmp_buffer, 1);
6310 /* Init source method for JPEG data source manager. Called by
6311 jpeg_read_header() before any data is actually read. See
6312 libjpeg.doc from the JPEG lib distribution. */
6314 static void
6315 our_init_source (cinfo)
6316 j_decompress_ptr cinfo;
6321 /* Fill input buffer method for JPEG data source manager. Called
6322 whenever more data is needed. We read the whole image in one step,
6323 so this only adds a fake end of input marker at the end. */
6325 static boolean
6326 our_fill_input_buffer (cinfo)
6327 j_decompress_ptr cinfo;
6329 /* Insert a fake EOI marker. */
6330 struct jpeg_source_mgr *src = cinfo->src;
6331 static JOCTET buffer[2];
6333 buffer[0] = (JOCTET) 0xFF;
6334 buffer[1] = (JOCTET) JPEG_EOI;
6336 src->next_input_byte = buffer;
6337 src->bytes_in_buffer = 2;
6338 return TRUE;
6342 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6343 is the JPEG data source manager. */
6345 static void
6346 our_skip_input_data (cinfo, num_bytes)
6347 j_decompress_ptr cinfo;
6348 long num_bytes;
6350 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
6352 if (src)
6354 if (num_bytes > src->bytes_in_buffer)
6355 ERREXIT (cinfo, JERR_INPUT_EOF);
6357 src->bytes_in_buffer -= num_bytes;
6358 src->next_input_byte += num_bytes;
6363 /* Method to terminate data source. Called by
6364 jpeg_finish_decompress() after all data has been processed. */
6366 static void
6367 our_term_source (cinfo)
6368 j_decompress_ptr cinfo;
6373 /* Set up the JPEG lib for reading an image from DATA which contains
6374 LEN bytes. CINFO is the decompression info structure created for
6375 reading the image. */
6377 static void
6378 jpeg_memory_src (cinfo, data, len)
6379 j_decompress_ptr cinfo;
6380 JOCTET *data;
6381 unsigned int len;
6383 struct jpeg_source_mgr *src;
6385 if (cinfo->src == NULL)
6387 /* First time for this JPEG object? */
6388 cinfo->src = (struct jpeg_source_mgr *)
6389 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6390 sizeof (struct jpeg_source_mgr));
6391 src = (struct jpeg_source_mgr *) cinfo->src;
6392 src->next_input_byte = data;
6395 src = (struct jpeg_source_mgr *) cinfo->src;
6396 src->init_source = our_init_source;
6397 src->fill_input_buffer = our_fill_input_buffer;
6398 src->skip_input_data = our_skip_input_data;
6399 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6400 src->term_source = our_term_source;
6401 src->bytes_in_buffer = len;
6402 src->next_input_byte = data;
6406 /* Load image IMG for use on frame F. Patterned after example.c
6407 from the JPEG lib. */
6409 static int
6410 jpeg_load (f, img)
6411 struct frame *f;
6412 struct image *img;
6414 struct jpeg_decompress_struct cinfo;
6415 struct my_jpeg_error_mgr mgr;
6416 Lisp_Object file, specified_file;
6417 Lisp_Object specified_data;
6418 FILE * volatile fp = NULL;
6419 JSAMPARRAY buffer;
6420 int row_stride, x, y;
6421 XImagePtr ximg = NULL;
6422 int rc;
6423 unsigned long *colors;
6424 int width, height;
6425 struct gcpro gcpro1;
6427 /* Open the JPEG file. */
6428 specified_file = image_spec_value (img->spec, QCfile, NULL);
6429 specified_data = image_spec_value (img->spec, QCdata, NULL);
6430 file = Qnil;
6431 GCPRO1 (file);
6433 if (NILP (specified_data))
6435 file = x_find_image_file (specified_file);
6436 if (!STRINGP (file))
6438 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6439 UNGCPRO;
6440 return 0;
6443 fp = fopen (SDATA (file), "rb");
6444 if (fp == NULL)
6446 image_error ("Cannot open `%s'", file, Qnil);
6447 UNGCPRO;
6448 return 0;
6452 /* Customize libjpeg's error handling to call my_error_exit when an
6453 error is detected. This function will perform a longjmp. */
6454 cinfo.err = fn_jpeg_std_error (&mgr.pub);
6455 mgr.pub.error_exit = my_error_exit;
6457 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
6459 if (rc == 1)
6461 /* Called from my_error_exit. Display a JPEG error. */
6462 char buffer[JMSG_LENGTH_MAX];
6463 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
6464 image_error ("Error reading JPEG image `%s': %s", img->spec,
6465 build_string (buffer));
6468 /* Close the input file and destroy the JPEG object. */
6469 if (fp)
6470 fclose ((FILE *) fp);
6471 fn_jpeg_destroy_decompress (&cinfo);
6473 /* If we already have an XImage, free that. */
6474 x_destroy_x_image (ximg);
6476 /* Free pixmap and colors. */
6477 x_clear_image (f, img);
6479 UNGCPRO;
6480 return 0;
6483 /* Create the JPEG decompression object. Let it read from fp.
6484 Read the JPEG image header. */
6485 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6487 if (NILP (specified_data))
6488 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
6489 else
6490 jpeg_memory_src (&cinfo, SDATA (specified_data),
6491 SBYTES (specified_data));
6493 fn_jpeg_read_header (&cinfo, TRUE);
6495 /* Customize decompression so that color quantization will be used.
6496 Start decompression. */
6497 cinfo.quantize_colors = TRUE;
6498 fn_jpeg_start_decompress (&cinfo);
6499 width = img->width = cinfo.output_width;
6500 height = img->height = cinfo.output_height;
6502 /* Create X image and pixmap. */
6503 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6504 longjmp (mgr.setjmp_buffer, 2);
6506 /* Allocate colors. When color quantization is used,
6507 cinfo.actual_number_of_colors has been set with the number of
6508 colors generated, and cinfo.colormap is a two-dimensional array
6509 of color indices in the range 0..cinfo.actual_number_of_colors.
6510 No more than 255 colors will be generated. */
6512 int i, ir, ig, ib;
6514 if (cinfo.out_color_components > 2)
6515 ir = 0, ig = 1, ib = 2;
6516 else if (cinfo.out_color_components > 1)
6517 ir = 0, ig = 1, ib = 0;
6518 else
6519 ir = 0, ig = 0, ib = 0;
6521 /* Use the color table mechanism because it handles colors that
6522 cannot be allocated nicely. Such colors will be replaced with
6523 a default color, and we don't have to care about which colors
6524 can be freed safely, and which can't. */
6525 init_color_table ();
6526 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6527 * sizeof *colors);
6529 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6531 /* Multiply RGB values with 255 because X expects RGB values
6532 in the range 0..0xffff. */
6533 int r = cinfo.colormap[ir][i] << 8;
6534 int g = cinfo.colormap[ig][i] << 8;
6535 int b = cinfo.colormap[ib][i] << 8;
6536 colors[i] = lookup_rgb_color (f, r, g, b);
6539 #ifdef COLOR_TABLE_SUPPORT
6540 /* Remember those colors actually allocated. */
6541 img->colors = colors_in_color_table (&img->ncolors);
6542 free_color_table ();
6543 #endif /* COLOR_TABLE_SUPPORT */
6546 /* Read pixels. */
6547 row_stride = width * cinfo.output_components;
6548 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6549 row_stride, 1);
6550 for (y = 0; y < height; ++y)
6552 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6553 for (x = 0; x < cinfo.output_width; ++x)
6554 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6557 /* Clean up. */
6558 fn_jpeg_finish_decompress (&cinfo);
6559 fn_jpeg_destroy_decompress (&cinfo);
6560 if (fp)
6561 fclose ((FILE *) fp);
6563 /* Maybe fill in the background field while we have ximg handy. */
6564 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6565 IMAGE_BACKGROUND (img, f, ximg);
6567 /* Put the image into the pixmap. */
6568 x_put_x_image (f, ximg, img->pixmap, width, height);
6569 x_destroy_x_image (ximg);
6570 UNGCPRO;
6571 return 1;
6574 #else /* HAVE_JPEG */
6576 #ifdef MAC_OS
6577 static int
6578 jpeg_load (f, img)
6579 struct frame *f;
6580 struct image *img;
6582 #ifdef MAC_OSX
6583 return image_load_quartz2d (f, img, 0);
6584 #else
6585 return image_load_quicktime (f, img, kQTFileTypeJPEG);
6586 #endif
6588 #endif /* MAC_OS */
6590 #endif /* !HAVE_JPEG */
6594 /***********************************************************************
6595 TIFF
6596 ***********************************************************************/
6598 #if defined (HAVE_TIFF) || defined (MAC_OS)
6600 static int tiff_image_p P_ ((Lisp_Object object));
6601 static int tiff_load P_ ((struct frame *f, struct image *img));
6603 /* The symbol `tiff' identifying images of this type. */
6605 Lisp_Object Qtiff;
6607 /* Indices of image specification fields in tiff_format, below. */
6609 enum tiff_keyword_index
6611 TIFF_TYPE,
6612 TIFF_DATA,
6613 TIFF_FILE,
6614 TIFF_ASCENT,
6615 TIFF_MARGIN,
6616 TIFF_RELIEF,
6617 TIFF_ALGORITHM,
6618 TIFF_HEURISTIC_MASK,
6619 TIFF_MASK,
6620 TIFF_BACKGROUND,
6621 TIFF_LAST
6624 /* Vector of image_keyword structures describing the format
6625 of valid user-defined image specifications. */
6627 static struct image_keyword tiff_format[TIFF_LAST] =
6629 {":type", IMAGE_SYMBOL_VALUE, 1},
6630 {":data", IMAGE_STRING_VALUE, 0},
6631 {":file", IMAGE_STRING_VALUE, 0},
6632 {":ascent", IMAGE_ASCENT_VALUE, 0},
6633 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6634 {":relief", IMAGE_INTEGER_VALUE, 0},
6635 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6636 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6637 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6638 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6641 /* Structure describing the image type `tiff'. */
6643 static struct image_type tiff_type =
6645 &Qtiff,
6646 tiff_image_p,
6647 tiff_load,
6648 x_clear_image,
6649 NULL
6652 /* Return non-zero if OBJECT is a valid TIFF image specification. */
6654 static int
6655 tiff_image_p (object)
6656 Lisp_Object object;
6658 struct image_keyword fmt[TIFF_LAST];
6659 bcopy (tiff_format, fmt, sizeof fmt);
6661 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6662 return 0;
6664 /* Must specify either the :data or :file keyword. */
6665 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6668 #endif /* HAVE_TIFF || MAC_OS */
6670 #ifdef HAVE_TIFF
6672 #include <tiffio.h>
6674 #ifdef HAVE_NTGUI
6676 /* TIFF library details. */
6677 DEF_IMGLIB_FN (TIFFSetErrorHandler);
6678 DEF_IMGLIB_FN (TIFFSetWarningHandler);
6679 DEF_IMGLIB_FN (TIFFOpen);
6680 DEF_IMGLIB_FN (TIFFClientOpen);
6681 DEF_IMGLIB_FN (TIFFGetField);
6682 DEF_IMGLIB_FN (TIFFReadRGBAImage);
6683 DEF_IMGLIB_FN (TIFFClose);
6685 static int
6686 init_tiff_functions (void)
6688 HMODULE library;
6690 if (!(library = LoadLibrary ("libtiff.dll")))
6691 return 0;
6693 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6694 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6695 LOAD_IMGLIB_FN (library, TIFFOpen);
6696 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6697 LOAD_IMGLIB_FN (library, TIFFGetField);
6698 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
6699 LOAD_IMGLIB_FN (library, TIFFClose);
6700 return 1;
6703 #else
6705 #define fn_TIFFSetErrorHandler TIFFSetErrorHandler
6706 #define fn_TIFFSetWarningHandler TIFFSetWarningHandler
6707 #define fn_TIFFOpen TIFFOpen
6708 #define fn_TIFFClientOpen TIFFClientOpen
6709 #define fn_TIFFGetField TIFFGetField
6710 #define fn_TIFFReadRGBAImage TIFFReadRGBAImage
6711 #define fn_TIFFClose TIFFClose
6713 #endif /* HAVE_NTGUI */
6716 /* Reading from a memory buffer for TIFF images Based on the PNG
6717 memory source, but we have to provide a lot of extra functions.
6718 Blah.
6720 We really only need to implement read and seek, but I am not
6721 convinced that the TIFF library is smart enough not to destroy
6722 itself if we only hand it the function pointers we need to
6723 override. */
6725 typedef struct
6727 unsigned char *bytes;
6728 size_t len;
6729 int index;
6731 tiff_memory_source;
6733 static size_t
6734 tiff_read_from_memory (data, buf, size)
6735 thandle_t data;
6736 tdata_t buf;
6737 tsize_t size;
6739 tiff_memory_source *src = (tiff_memory_source *) data;
6741 if (size > src->len - src->index)
6742 return (size_t) -1;
6743 bcopy (src->bytes + src->index, buf, size);
6744 src->index += size;
6745 return size;
6748 static size_t
6749 tiff_write_from_memory (data, buf, size)
6750 thandle_t data;
6751 tdata_t buf;
6752 tsize_t size;
6754 return (size_t) -1;
6757 static toff_t
6758 tiff_seek_in_memory (data, off, whence)
6759 thandle_t data;
6760 toff_t off;
6761 int whence;
6763 tiff_memory_source *src = (tiff_memory_source *) data;
6764 int idx;
6766 switch (whence)
6768 case SEEK_SET: /* Go from beginning of source. */
6769 idx = off;
6770 break;
6772 case SEEK_END: /* Go from end of source. */
6773 idx = src->len + off;
6774 break;
6776 case SEEK_CUR: /* Go from current position. */
6777 idx = src->index + off;
6778 break;
6780 default: /* Invalid `whence'. */
6781 return -1;
6784 if (idx > src->len || idx < 0)
6785 return -1;
6787 src->index = idx;
6788 return src->index;
6791 static int
6792 tiff_close_memory (data)
6793 thandle_t data;
6795 /* NOOP */
6796 return 0;
6799 static int
6800 tiff_mmap_memory (data, pbase, psize)
6801 thandle_t data;
6802 tdata_t *pbase;
6803 toff_t *psize;
6805 /* It is already _IN_ memory. */
6806 return 0;
6809 static void
6810 tiff_unmap_memory (data, base, size)
6811 thandle_t data;
6812 tdata_t base;
6813 toff_t size;
6815 /* We don't need to do this. */
6818 static toff_t
6819 tiff_size_of_memory (data)
6820 thandle_t data;
6822 return ((tiff_memory_source *) data)->len;
6826 static void
6827 tiff_error_handler (title, format, ap)
6828 const char *title, *format;
6829 va_list ap;
6831 char buf[512];
6832 int len;
6834 len = sprintf (buf, "TIFF error: %s ", title);
6835 vsprintf (buf + len, format, ap);
6836 add_to_log (buf, Qnil, Qnil);
6840 static void
6841 tiff_warning_handler (title, format, ap)
6842 const char *title, *format;
6843 va_list ap;
6845 char buf[512];
6846 int len;
6848 len = sprintf (buf, "TIFF warning: %s ", title);
6849 vsprintf (buf + len, format, ap);
6850 add_to_log (buf, Qnil, Qnil);
6854 /* Load TIFF image IMG for use on frame F. Value is non-zero if
6855 successful. */
6857 static int
6858 tiff_load (f, img)
6859 struct frame *f;
6860 struct image *img;
6862 Lisp_Object file, specified_file;
6863 Lisp_Object specified_data;
6864 TIFF *tiff;
6865 int width, height, x, y;
6866 uint32 *buf;
6867 int rc;
6868 XImagePtr ximg;
6869 struct gcpro gcpro1;
6870 tiff_memory_source memsrc;
6872 specified_file = image_spec_value (img->spec, QCfile, NULL);
6873 specified_data = image_spec_value (img->spec, QCdata, NULL);
6874 file = Qnil;
6875 GCPRO1 (file);
6877 fn_TIFFSetErrorHandler (tiff_error_handler);
6878 fn_TIFFSetWarningHandler (tiff_warning_handler);
6880 if (NILP (specified_data))
6882 /* Read from a file */
6883 file = x_find_image_file (specified_file);
6884 if (!STRINGP (file))
6886 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6887 UNGCPRO;
6888 return 0;
6891 /* Try to open the image file. */
6892 tiff = fn_TIFFOpen (SDATA (file), "r");
6893 if (tiff == NULL)
6895 image_error ("Cannot open `%s'", file, Qnil);
6896 UNGCPRO;
6897 return 0;
6900 else
6902 /* Memory source! */
6903 memsrc.bytes = SDATA (specified_data);
6904 memsrc.len = SBYTES (specified_data);
6905 memsrc.index = 0;
6907 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
6908 (TIFFReadWriteProc) tiff_read_from_memory,
6909 (TIFFReadWriteProc) tiff_write_from_memory,
6910 tiff_seek_in_memory,
6911 tiff_close_memory,
6912 tiff_size_of_memory,
6913 tiff_mmap_memory,
6914 tiff_unmap_memory);
6916 if (!tiff)
6918 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
6919 UNGCPRO;
6920 return 0;
6924 /* Get width and height of the image, and allocate a raster buffer
6925 of width x height 32-bit values. */
6926 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
6927 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6928 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
6930 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
6931 fn_TIFFClose (tiff);
6932 if (!rc)
6934 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
6935 xfree (buf);
6936 UNGCPRO;
6937 return 0;
6940 /* Create the X image and pixmap. */
6941 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6943 xfree (buf);
6944 UNGCPRO;
6945 return 0;
6948 /* Initialize the color table. */
6949 init_color_table ();
6951 /* Process the pixel raster. Origin is in the lower-left corner. */
6952 for (y = 0; y < height; ++y)
6954 uint32 *row = buf + y * width;
6956 for (x = 0; x < width; ++x)
6958 uint32 abgr = row[x];
6959 int r = TIFFGetR (abgr) << 8;
6960 int g = TIFFGetG (abgr) << 8;
6961 int b = TIFFGetB (abgr) << 8;
6962 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
6966 #ifdef COLOR_TABLE_SUPPORT
6967 /* Remember the colors allocated for the image. Free the color table. */
6968 img->colors = colors_in_color_table (&img->ncolors);
6969 free_color_table ();
6970 #endif /* COLOR_TABLE_SUPPORT */
6972 img->width = width;
6973 img->height = height;
6975 /* Maybe fill in the background field while we have ximg handy. */
6976 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6977 IMAGE_BACKGROUND (img, f, ximg);
6979 /* Put the image into the pixmap, then free the X image and its buffer. */
6980 x_put_x_image (f, ximg, img->pixmap, width, height);
6981 x_destroy_x_image (ximg);
6982 xfree (buf);
6984 UNGCPRO;
6985 return 1;
6988 #else /* HAVE_TIFF */
6990 #ifdef MAC_OS
6991 static int
6992 tiff_load (f, img)
6993 struct frame *f;
6994 struct image *img;
6996 return image_load_quicktime (f, img, kQTFileTypeTIFF);
6998 #endif /* MAC_OS */
7000 #endif /* !HAVE_TIFF */
7004 /***********************************************************************
7006 ***********************************************************************/
7008 #if defined (HAVE_GIF) || defined (MAC_OS)
7010 static int gif_image_p P_ ((Lisp_Object object));
7011 static int gif_load P_ ((struct frame *f, struct image *img));
7013 /* The symbol `gif' identifying images of this type. */
7015 Lisp_Object Qgif;
7017 /* Indices of image specification fields in gif_format, below. */
7019 enum gif_keyword_index
7021 GIF_TYPE,
7022 GIF_DATA,
7023 GIF_FILE,
7024 GIF_ASCENT,
7025 GIF_MARGIN,
7026 GIF_RELIEF,
7027 GIF_ALGORITHM,
7028 GIF_HEURISTIC_MASK,
7029 GIF_MASK,
7030 GIF_IMAGE,
7031 GIF_BACKGROUND,
7032 GIF_LAST
7035 /* Vector of image_keyword structures describing the format
7036 of valid user-defined image specifications. */
7038 static struct image_keyword gif_format[GIF_LAST] =
7040 {":type", IMAGE_SYMBOL_VALUE, 1},
7041 {":data", IMAGE_STRING_VALUE, 0},
7042 {":file", IMAGE_STRING_VALUE, 0},
7043 {":ascent", IMAGE_ASCENT_VALUE, 0},
7044 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7045 {":relief", IMAGE_INTEGER_VALUE, 0},
7046 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7047 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7048 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7049 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7050 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7053 /* Structure describing the image type `gif'. */
7055 static struct image_type gif_type =
7057 &Qgif,
7058 gif_image_p,
7059 gif_load,
7060 x_clear_image,
7061 NULL
7064 /* Return non-zero if OBJECT is a valid GIF image specification. */
7066 static int
7067 gif_image_p (object)
7068 Lisp_Object object;
7070 struct image_keyword fmt[GIF_LAST];
7071 bcopy (gif_format, fmt, sizeof fmt);
7073 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
7074 return 0;
7076 /* Must specify either the :data or :file keyword. */
7077 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7080 #endif /* HAVE_GIF || MAC_OS */
7082 #ifdef HAVE_GIF
7084 #if defined (HAVE_NTGUI) || defined (MAC_OS)
7085 /* avoid conflict with QuickdrawText.h */
7086 #define DrawText gif_DrawText
7087 #include <gif_lib.h>
7088 #undef DrawText
7090 #else /* HAVE_NTGUI || MAC_OS */
7092 #include <gif_lib.h>
7094 #endif /* HAVE_NTGUI || MAC_OS */
7097 #ifdef HAVE_NTGUI
7099 /* GIF library details. */
7100 DEF_IMGLIB_FN (DGifCloseFile);
7101 DEF_IMGLIB_FN (DGifSlurp);
7102 DEF_IMGLIB_FN (DGifOpen);
7103 DEF_IMGLIB_FN (DGifOpenFileName);
7105 static int
7106 init_gif_functions (void)
7108 HMODULE library;
7110 if (!(library = LoadLibrary ("libungif.dll")))
7111 return 0;
7113 LOAD_IMGLIB_FN (library, DGifCloseFile);
7114 LOAD_IMGLIB_FN (library, DGifSlurp);
7115 LOAD_IMGLIB_FN (library, DGifOpen);
7116 LOAD_IMGLIB_FN (library, DGifOpenFileName);
7117 return 1;
7120 #else
7122 #define fn_DGifCloseFile DGifCloseFile
7123 #define fn_DGifSlurp DGifSlurp
7124 #define fn_DGifOpen DGifOpen
7125 #define fn_DGifOpenFileName DGifOpenFileName
7127 #endif /* HAVE_NTGUI */
7129 /* Reading a GIF image from memory
7130 Based on the PNG memory stuff to a certain extent. */
7132 typedef struct
7134 unsigned char *bytes;
7135 size_t len;
7136 int index;
7138 gif_memory_source;
7140 /* Make the current memory source available to gif_read_from_memory.
7141 It's done this way because not all versions of libungif support
7142 a UserData field in the GifFileType structure. */
7143 static gif_memory_source *current_gif_memory_src;
7145 static int
7146 gif_read_from_memory (file, buf, len)
7147 GifFileType *file;
7148 GifByteType *buf;
7149 int len;
7151 gif_memory_source *src = current_gif_memory_src;
7153 if (len > src->len - src->index)
7154 return -1;
7156 bcopy (src->bytes + src->index, buf, len);
7157 src->index += len;
7158 return len;
7162 /* Load GIF image IMG for use on frame F. Value is non-zero if
7163 successful. */
7165 static int
7166 gif_load (f, img)
7167 struct frame *f;
7168 struct image *img;
7170 Lisp_Object file, specified_file;
7171 Lisp_Object specified_data;
7172 int rc, width, height, x, y, i;
7173 XImagePtr ximg;
7174 ColorMapObject *gif_color_map;
7175 unsigned long pixel_colors[256];
7176 GifFileType *gif;
7177 struct gcpro gcpro1;
7178 Lisp_Object image;
7179 int ino, image_left, image_top, image_width, image_height;
7180 gif_memory_source memsrc;
7181 unsigned char *raster;
7183 specified_file = image_spec_value (img->spec, QCfile, NULL);
7184 specified_data = image_spec_value (img->spec, QCdata, NULL);
7185 file = Qnil;
7186 GCPRO1 (file);
7188 if (NILP (specified_data))
7190 file = x_find_image_file (specified_file);
7191 if (!STRINGP (file))
7193 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7194 UNGCPRO;
7195 return 0;
7198 /* Open the GIF file. */
7199 gif = fn_DGifOpenFileName (SDATA (file));
7200 if (gif == NULL)
7202 image_error ("Cannot open `%s'", file, Qnil);
7203 UNGCPRO;
7204 return 0;
7207 else
7209 /* Read from memory! */
7210 current_gif_memory_src = &memsrc;
7211 memsrc.bytes = SDATA (specified_data);
7212 memsrc.len = SBYTES (specified_data);
7213 memsrc.index = 0;
7215 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
7216 if (!gif)
7218 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
7219 UNGCPRO;
7220 return 0;
7224 /* Read entire contents. */
7225 rc = fn_DGifSlurp (gif);
7226 if (rc == GIF_ERROR)
7228 image_error ("Error reading `%s'", img->spec, Qnil);
7229 fn_DGifCloseFile (gif);
7230 UNGCPRO;
7231 return 0;
7234 image = image_spec_value (img->spec, QCindex, NULL);
7235 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7236 if (ino >= gif->ImageCount)
7238 image_error ("Invalid image number `%s' in image `%s'",
7239 image, img->spec);
7240 fn_DGifCloseFile (gif);
7241 UNGCPRO;
7242 return 0;
7245 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
7246 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
7248 /* Create the X image and pixmap. */
7249 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7251 fn_DGifCloseFile (gif);
7252 UNGCPRO;
7253 return 0;
7256 /* Allocate colors. */
7257 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
7258 if (!gif_color_map)
7259 gif_color_map = gif->SColorMap;
7260 init_color_table ();
7261 bzero (pixel_colors, sizeof pixel_colors);
7263 for (i = 0; i < gif_color_map->ColorCount; ++i)
7265 int r = gif_color_map->Colors[i].Red << 8;
7266 int g = gif_color_map->Colors[i].Green << 8;
7267 int b = gif_color_map->Colors[i].Blue << 8;
7268 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7271 #ifdef COLOR_TABLE_SUPPORT
7272 img->colors = colors_in_color_table (&img->ncolors);
7273 free_color_table ();
7274 #endif /* COLOR_TABLE_SUPPORT */
7276 /* Clear the part of the screen image that are not covered by
7277 the image from the GIF file. Full animated GIF support
7278 requires more than can be done here (see the gif89 spec,
7279 disposal methods). Let's simply assume that the part
7280 not covered by a sub-image is in the frame's background color. */
7281 image_top = gif->SavedImages[ino].ImageDesc.Top;
7282 image_left = gif->SavedImages[ino].ImageDesc.Left;
7283 image_width = gif->SavedImages[ino].ImageDesc.Width;
7284 image_height = gif->SavedImages[ino].ImageDesc.Height;
7286 for (y = 0; y < image_top; ++y)
7287 for (x = 0; x < width; ++x)
7288 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7290 for (y = image_top + image_height; y < height; ++y)
7291 for (x = 0; x < width; ++x)
7292 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7294 for (y = image_top; y < image_top + image_height; ++y)
7296 for (x = 0; x < image_left; ++x)
7297 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7298 for (x = image_left + image_width; x < width; ++x)
7299 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7302 /* Read the GIF image into the X image. We use a local variable
7303 `raster' here because RasterBits below is a char *, and invites
7304 problems with bytes >= 0x80. */
7305 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7307 if (gif->SavedImages[ino].ImageDesc.Interlace)
7309 static int interlace_start[] = {0, 4, 2, 1};
7310 static int interlace_increment[] = {8, 8, 4, 2};
7311 int pass;
7312 int row = interlace_start[0];
7314 pass = 0;
7316 for (y = 0; y < image_height; y++)
7318 if (row >= image_height)
7320 row = interlace_start[++pass];
7321 while (row >= image_height)
7322 row = interlace_start[++pass];
7325 for (x = 0; x < image_width; x++)
7327 int i = raster[(y * image_width) + x];
7328 XPutPixel (ximg, x + image_left, row + image_top,
7329 pixel_colors[i]);
7332 row += interlace_increment[pass];
7335 else
7337 for (y = 0; y < image_height; ++y)
7338 for (x = 0; x < image_width; ++x)
7340 int i = raster[y * image_width + x];
7341 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
7345 fn_DGifCloseFile (gif);
7347 /* Maybe fill in the background field while we have ximg handy. */
7348 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7349 IMAGE_BACKGROUND (img, f, ximg);
7351 /* Put the image into the pixmap, then free the X image and its buffer. */
7352 x_put_x_image (f, ximg, img->pixmap, width, height);
7353 x_destroy_x_image (ximg);
7355 UNGCPRO;
7356 return 1;
7359 #else
7361 #ifdef MAC_OS
7362 static int
7363 gif_load (f, img)
7364 struct frame *f;
7365 struct image *img;
7367 Lisp_Object specified_file, file;
7368 Lisp_Object specified_data;
7369 OSErr err;
7370 Boolean graphic_p, movie_p, prefer_graphic_p;
7371 Handle dh = NULL;
7372 Movie movie = NULL;
7373 Lisp_Object image;
7374 Track track = NULL;
7375 Media media = NULL;
7376 long nsamples;
7377 Rect rect;
7378 Lisp_Object specified_bg;
7379 XColor color;
7380 RGBColor bg_color;
7381 int width, height;
7382 XImagePtr ximg;
7383 TimeValue time;
7384 struct gcpro gcpro1;
7385 int ino;
7386 CGrafPtr old_port;
7387 GDHandle old_gdh;
7389 specified_file = image_spec_value (img->spec, QCfile, NULL);
7390 specified_data = image_spec_value (img->spec, QCdata, NULL);
7392 if (NILP (specified_data))
7394 /* Read from a file */
7395 FSSpec fss;
7396 short refnum;
7398 err = find_image_fsspec (specified_file, &file, &fss);
7399 if (err != noErr)
7401 if (err == fnfErr)
7402 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7403 else
7404 goto open_error;
7407 err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0,
7408 &graphic_p, &movie_p, &prefer_graphic_p, 0);
7409 if (err != noErr)
7410 goto open_error;
7412 if (!graphic_p && !movie_p)
7413 goto open_error;
7414 if (prefer_graphic_p)
7415 return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL);
7416 err = OpenMovieFile (&fss, &refnum, fsRdPerm);
7417 if (err != noErr)
7418 goto open_error;
7419 err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL);
7420 CloseMovieFile (refnum);
7421 if (err != noErr)
7423 image_error ("Error reading `%s'", file, Qnil);
7424 return 0;
7427 else
7429 /* Memory source! */
7430 Handle dref = NULL;
7431 long file_type_atom[3];
7433 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
7434 if (err != noErr)
7436 image_error ("Cannot allocate data handle for `%s'",
7437 img->spec, Qnil);
7438 goto error;
7441 file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3);
7442 file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
7443 file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF);
7444 err = PtrToHand (&dh, &dref, sizeof (Handle));
7445 if (err == noErr)
7446 /* no file name */
7447 err = PtrAndHand ("\p", dref, 1);
7448 if (err == noErr)
7449 err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3);
7450 if (err != noErr)
7452 image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil);
7453 goto error;
7455 err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p,
7456 &movie_p, &prefer_graphic_p, 0);
7457 if (err != noErr)
7458 goto open_error;
7460 if (!graphic_p && !movie_p)
7461 goto open_error;
7462 if (prefer_graphic_p)
7464 int success_p;
7466 DisposeHandle (dref);
7467 success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh);
7468 DisposeHandle (dh);
7469 return success_p;
7471 err = NewMovieFromDataRef (&movie, 0, NULL, dref,
7472 HandleDataHandlerSubType);
7473 DisposeHandle (dref);
7474 if (err != noErr)
7475 goto open_error;
7478 image = image_spec_value (img->spec, QCindex, NULL);
7479 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7480 track = GetMovieIndTrack (movie, 1);
7481 media = GetTrackMedia (track);
7482 nsamples = GetMediaSampleCount (media);
7483 if (ino >= nsamples)
7485 image_error ("Invalid image number `%s' in image `%s'",
7486 image, img->spec);
7487 goto error;
7490 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
7491 if (!STRINGP (specified_bg) ||
7492 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
7494 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7495 color.red = RED16_FROM_ULONG (color.pixel);
7496 color.green = GREEN16_FROM_ULONG (color.pixel);
7497 color.blue = BLUE16_FROM_ULONG (color.pixel);
7499 GetMovieBox (movie, &rect);
7500 width = img->width = rect.right - rect.left;
7501 height = img->height = rect.bottom - rect.top;
7502 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7503 goto error;
7505 GetGWorld (&old_port, &old_gdh);
7506 SetGWorld (ximg, NULL);
7507 bg_color.red = color.red;
7508 bg_color.green = color.green;
7509 bg_color.blue = color.blue;
7510 RGBBackColor (&bg_color);
7511 SetGWorld (old_port, old_gdh);
7512 SetMovieActive (movie, TRUE);
7513 SetMovieGWorld (movie, ximg, NULL);
7514 SampleNumToMediaTime (media, ino + 1, &time, NULL);
7515 SetMovieTimeValue (movie, time);
7516 MoviesTask (movie, 0L);
7517 DisposeTrackMedia (media);
7518 DisposeMovieTrack (track);
7519 DisposeMovie (movie);
7520 if (dh)
7521 DisposeHandle (dh);
7522 /* Maybe fill in the background field while we have ximg handy. */
7523 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7524 IMAGE_BACKGROUND (img, f, ximg);
7526 /* Put the image into the pixmap. */
7527 x_put_x_image (f, ximg, img->pixmap, width, height);
7528 x_destroy_x_image (ximg);
7529 return 1;
7531 open_error:
7532 image_error ("Cannot open `%s'", file, Qnil);
7533 error:
7534 if (media)
7535 DisposeTrackMedia (media);
7536 if (track)
7537 DisposeMovieTrack (track);
7538 if (movie)
7539 DisposeMovie (movie);
7540 if (dh)
7541 DisposeHandle (dh);
7542 return 0;
7544 #endif /* MAC_OS */
7546 #endif /* HAVE_GIF */
7550 /***********************************************************************
7551 Ghostscript
7552 ***********************************************************************/
7554 #ifdef HAVE_X_WINDOWS
7555 #define HAVE_GHOSTSCRIPT 1
7556 #endif /* HAVE_X_WINDOWS */
7558 /* The symbol `postscript' identifying images of this type. */
7560 Lisp_Object Qpostscript;
7562 #ifdef HAVE_GHOSTSCRIPT
7564 static int gs_image_p P_ ((Lisp_Object object));
7565 static int gs_load P_ ((struct frame *f, struct image *img));
7566 static void gs_clear_image P_ ((struct frame *f, struct image *img));
7568 /* Keyword symbols. */
7570 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
7572 /* Indices of image specification fields in gs_format, below. */
7574 enum gs_keyword_index
7576 GS_TYPE,
7577 GS_PT_WIDTH,
7578 GS_PT_HEIGHT,
7579 GS_FILE,
7580 GS_LOADER,
7581 GS_BOUNDING_BOX,
7582 GS_ASCENT,
7583 GS_MARGIN,
7584 GS_RELIEF,
7585 GS_ALGORITHM,
7586 GS_HEURISTIC_MASK,
7587 GS_MASK,
7588 GS_BACKGROUND,
7589 GS_LAST
7592 /* Vector of image_keyword structures describing the format
7593 of valid user-defined image specifications. */
7595 static struct image_keyword gs_format[GS_LAST] =
7597 {":type", IMAGE_SYMBOL_VALUE, 1},
7598 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7599 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7600 {":file", IMAGE_STRING_VALUE, 1},
7601 {":loader", IMAGE_FUNCTION_VALUE, 0},
7602 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7603 {":ascent", IMAGE_ASCENT_VALUE, 0},
7604 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7605 {":relief", IMAGE_INTEGER_VALUE, 0},
7606 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7607 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7608 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7609 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7612 /* Structure describing the image type `ghostscript'. */
7614 static struct image_type gs_type =
7616 &Qpostscript,
7617 gs_image_p,
7618 gs_load,
7619 gs_clear_image,
7620 NULL
7624 /* Free X resources of Ghostscript image IMG which is used on frame F. */
7626 static void
7627 gs_clear_image (f, img)
7628 struct frame *f;
7629 struct image *img;
7631 /* IMG->data.ptr_val may contain a recorded colormap. */
7632 xfree (img->data.ptr_val);
7633 x_clear_image (f, img);
7637 /* Return non-zero if OBJECT is a valid Ghostscript image
7638 specification. */
7640 static int
7641 gs_image_p (object)
7642 Lisp_Object object;
7644 struct image_keyword fmt[GS_LAST];
7645 Lisp_Object tem;
7646 int i;
7648 bcopy (gs_format, fmt, sizeof fmt);
7650 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
7651 return 0;
7653 /* Bounding box must be a list or vector containing 4 integers. */
7654 tem = fmt[GS_BOUNDING_BOX].value;
7655 if (CONSP (tem))
7657 for (i = 0; i < 4; ++i, tem = XCDR (tem))
7658 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
7659 return 0;
7660 if (!NILP (tem))
7661 return 0;
7663 else if (VECTORP (tem))
7665 if (XVECTOR (tem)->size != 4)
7666 return 0;
7667 for (i = 0; i < 4; ++i)
7668 if (!INTEGERP (XVECTOR (tem)->contents[i]))
7669 return 0;
7671 else
7672 return 0;
7674 return 1;
7678 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
7679 if successful. */
7681 static int
7682 gs_load (f, img)
7683 struct frame *f;
7684 struct image *img;
7686 char buffer[100];
7687 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
7688 struct gcpro gcpro1, gcpro2;
7689 Lisp_Object frame;
7690 double in_width, in_height;
7691 Lisp_Object pixel_colors = Qnil;
7693 /* Compute pixel size of pixmap needed from the given size in the
7694 image specification. Sizes in the specification are in pt. 1 pt
7695 = 1/72 in, xdpi and ydpi are stored in the frame's X display
7696 info. */
7697 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
7698 in_width = XFASTINT (pt_width) / 72.0;
7699 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
7700 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
7701 in_height = XFASTINT (pt_height) / 72.0;
7702 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
7704 /* Create the pixmap. */
7705 xassert (img->pixmap == NO_PIXMAP);
7707 /* Only W32 version did BLOCK_INPUT here. ++kfs */
7708 BLOCK_INPUT;
7709 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7710 img->width, img->height,
7711 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
7712 UNBLOCK_INPUT;
7714 if (!img->pixmap)
7716 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
7717 return 0;
7720 /* Call the loader to fill the pixmap. It returns a process object
7721 if successful. We do not record_unwind_protect here because
7722 other places in redisplay like calling window scroll functions
7723 don't either. Let the Lisp loader use `unwind-protect' instead. */
7724 GCPRO2 (window_and_pixmap_id, pixel_colors);
7726 sprintf (buffer, "%lu %lu",
7727 (unsigned long) FRAME_X_WINDOW (f),
7728 (unsigned long) img->pixmap);
7729 window_and_pixmap_id = build_string (buffer);
7731 sprintf (buffer, "%lu %lu",
7732 FRAME_FOREGROUND_PIXEL (f),
7733 FRAME_BACKGROUND_PIXEL (f));
7734 pixel_colors = build_string (buffer);
7736 XSETFRAME (frame, f);
7737 loader = image_spec_value (img->spec, QCloader, NULL);
7738 if (NILP (loader))
7739 loader = intern ("gs-load-image");
7741 img->data.lisp_val = call6 (loader, frame, img->spec,
7742 make_number (img->width),
7743 make_number (img->height),
7744 window_and_pixmap_id,
7745 pixel_colors);
7746 UNGCPRO;
7747 return PROCESSP (img->data.lisp_val);
7751 /* Kill the Ghostscript process that was started to fill PIXMAP on
7752 frame F. Called from XTread_socket when receiving an event
7753 telling Emacs that Ghostscript has finished drawing. */
7755 void
7756 x_kill_gs_process (pixmap, f)
7757 Pixmap pixmap;
7758 struct frame *f;
7760 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7761 int class, i;
7762 struct image *img;
7764 /* Find the image containing PIXMAP. */
7765 for (i = 0; i < c->used; ++i)
7766 if (c->images[i]->pixmap == pixmap)
7767 break;
7769 /* Should someone in between have cleared the image cache, for
7770 instance, give up. */
7771 if (i == c->used)
7772 return;
7774 /* Kill the GS process. We should have found PIXMAP in the image
7775 cache and its image should contain a process object. */
7776 img = c->images[i];
7777 xassert (PROCESSP (img->data.lisp_val));
7778 Fkill_process (img->data.lisp_val, Qnil);
7779 img->data.lisp_val = Qnil;
7781 #if defined (HAVE_X_WINDOWS)
7783 /* On displays with a mutable colormap, figure out the colors
7784 allocated for the image by looking at the pixels of an XImage for
7785 img->pixmap. */
7786 class = FRAME_X_VISUAL (f)->class;
7787 if (class != StaticColor && class != StaticGray && class != TrueColor)
7789 XImagePtr ximg;
7791 BLOCK_INPUT;
7793 /* Try to get an XImage for img->pixmep. */
7794 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7795 0, 0, img->width, img->height, ~0, ZPixmap);
7796 if (ximg)
7798 int x, y;
7800 /* Initialize the color table. */
7801 init_color_table ();
7803 /* For each pixel of the image, look its color up in the
7804 color table. After having done so, the color table will
7805 contain an entry for each color used by the image. */
7806 for (y = 0; y < img->height; ++y)
7807 for (x = 0; x < img->width; ++x)
7809 unsigned long pixel = XGetPixel (ximg, x, y);
7810 lookup_pixel_color (f, pixel);
7813 /* Record colors in the image. Free color table and XImage. */
7814 #ifdef COLOR_TABLE_SUPPORT
7815 img->colors = colors_in_color_table (&img->ncolors);
7816 free_color_table ();
7817 #endif
7818 XDestroyImage (ximg);
7820 #if 0 /* This doesn't seem to be the case. If we free the colors
7821 here, we get a BadAccess later in x_clear_image when
7822 freeing the colors. */
7823 /* We have allocated colors once, but Ghostscript has also
7824 allocated colors on behalf of us. So, to get the
7825 reference counts right, free them once. */
7826 if (img->ncolors)
7827 x_free_colors (f, img->colors, img->ncolors);
7828 #endif
7830 else
7831 image_error ("Cannot get X image of `%s'; colors will not be freed",
7832 img->spec, Qnil);
7834 UNBLOCK_INPUT;
7836 #endif /* HAVE_X_WINDOWS */
7838 /* Now that we have the pixmap, compute mask and transform the
7839 image if requested. */
7840 BLOCK_INPUT;
7841 postprocess_image (f, img);
7842 UNBLOCK_INPUT;
7845 #endif /* HAVE_GHOSTSCRIPT */
7848 /***********************************************************************
7849 Tests
7850 ***********************************************************************/
7852 #if GLYPH_DEBUG
7854 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
7855 doc: /* Value is non-nil if SPEC is a valid image specification. */)
7856 (spec)
7857 Lisp_Object spec;
7859 return valid_image_p (spec) ? Qt : Qnil;
7863 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
7864 (spec)
7865 Lisp_Object spec;
7867 int id = -1;
7869 if (valid_image_p (spec))
7870 id = lookup_image (SELECTED_FRAME (), spec);
7872 debug_print (spec);
7873 return make_number (id);
7876 #endif /* GLYPH_DEBUG != 0 */
7879 /***********************************************************************
7880 Initialization
7881 ***********************************************************************/
7883 void
7884 syms_of_image ()
7886 QCascent = intern (":ascent");
7887 staticpro (&QCascent);
7888 QCmargin = intern (":margin");
7889 staticpro (&QCmargin);
7890 QCrelief = intern (":relief");
7891 staticpro (&QCrelief);
7892 QCconversion = intern (":conversion");
7893 staticpro (&QCconversion);
7894 QCcolor_symbols = intern (":color-symbols");
7895 staticpro (&QCcolor_symbols);
7896 QCheuristic_mask = intern (":heuristic-mask");
7897 staticpro (&QCheuristic_mask);
7898 QCindex = intern (":index");
7899 staticpro (&QCindex);
7900 QCmatrix = intern (":matrix");
7901 staticpro (&QCmatrix);
7902 QCcolor_adjustment = intern (":color-adjustment");
7903 staticpro (&QCcolor_adjustment);
7904 QCmask = intern (":mask");
7905 staticpro (&QCmask);
7907 Qlaplace = intern ("laplace");
7908 staticpro (&Qlaplace);
7909 Qemboss = intern ("emboss");
7910 staticpro (&Qemboss);
7911 Qedge_detection = intern ("edge-detection");
7912 staticpro (&Qedge_detection);
7913 Qheuristic = intern ("heuristic");
7914 staticpro (&Qheuristic);
7916 Qpostscript = intern ("postscript");
7917 staticpro (&Qpostscript);
7918 #ifdef HAVE_GHOSTSCRIPT
7919 QCloader = intern (":loader");
7920 staticpro (&QCloader);
7921 QCbounding_box = intern (":bounding-box");
7922 staticpro (&QCbounding_box);
7923 QCpt_width = intern (":pt-width");
7924 staticpro (&QCpt_width);
7925 QCpt_height = intern (":pt-height");
7926 staticpro (&QCpt_height);
7927 #endif /* HAVE_GHOSTSCRIPT */
7929 Qpbm = intern ("pbm");
7930 staticpro (&Qpbm);
7932 Qxbm = intern ("xbm");
7933 staticpro (&Qxbm);
7935 #if defined (HAVE_XPM) || defined (MAC_OS)
7936 Qxpm = intern ("xpm");
7937 staticpro (&Qxpm);
7938 #endif
7940 #if defined (HAVE_JPEG) || defined (MAC_OS)
7941 Qjpeg = intern ("jpeg");
7942 staticpro (&Qjpeg);
7943 #endif
7945 #if defined (HAVE_TIFF) || defined (MAC_OS)
7946 Qtiff = intern ("tiff");
7947 staticpro (&Qtiff);
7948 #endif
7950 #if defined (HAVE_GIF) || defined (MAC_OS)
7951 Qgif = intern ("gif");
7952 staticpro (&Qgif);
7953 #endif
7955 #if defined (HAVE_PNG) || defined (MAC_OS)
7956 Qpng = intern ("png");
7957 staticpro (&Qpng);
7958 #endif
7960 defsubr (&Sclear_image_cache);
7961 defsubr (&Simage_size);
7962 defsubr (&Simage_mask_p);
7964 #if GLYPH_DEBUG
7965 defsubr (&Simagep);
7966 defsubr (&Slookup_image);
7967 #endif
7969 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
7970 doc: /* Non-nil means always draw a cross over disabled images.
7971 Disabled images are those having an `:conversion disabled' property.
7972 A cross is always drawn on black & white displays. */);
7973 cross_disabled_images = 0;
7975 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
7976 doc: /* List of directories to search for window system bitmap files. */);
7977 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
7979 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
7980 doc: /* Time after which cached images are removed from the cache.
7981 When an image has not been displayed this many seconds, remove it
7982 from the image cache. Value must be an integer or nil with nil
7983 meaning don't clear the cache. */);
7984 Vimage_cache_eviction_delay = make_number (30 * 60);
7988 #ifdef HAVE_NTGUI
7989 /* Image types that rely on external libraries are loaded dynamically
7990 if the library is available. */
7991 #define IF_LIB_AVAILABLE(init_lib_fn) if (init_lib_fn())
7992 #else
7993 #define IF_LIB_AVAILABLE(init_func) /* Load unconditionally */
7994 #endif /* HAVE_NTGUI */
7996 void
7997 init_image ()
7999 image_types = NULL;
8000 Vimage_types = Qnil;
8002 define_image_type (&xbm_type);
8003 define_image_type (&pbm_type);
8005 #if defined (HAVE_XPM) || defined (MAC_OS)
8006 IF_LIB_AVAILABLE(init_xpm_functions)
8007 define_image_type (&xpm_type);
8008 #endif
8010 #if defined (HAVE_JPEG) || defined (MAC_OS)
8011 IF_LIB_AVAILABLE(init_jpeg_functions)
8012 define_image_type (&jpeg_type);
8013 #endif
8015 #if defined (HAVE_TIFF) || defined (MAC_OS)
8016 IF_LIB_AVAILABLE(init_tiff_functions)
8017 define_image_type (&tiff_type);
8018 #endif
8020 #if defined (HAVE_GIF) || defined (MAC_OS)
8021 IF_LIB_AVAILABLE(init_gif_functions)
8022 define_image_type (&gif_type);
8023 #endif
8025 #if defined (HAVE_PNG) || defined (MAC_OS)
8026 IF_LIB_AVAILABLE(init_png_functions)
8027 define_image_type (&png_type);
8028 #endif
8030 #ifdef HAVE_GHOSTSCRIPT
8031 define_image_type (&gs_type);
8032 #endif
8034 #ifdef MAC_OS
8035 /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */
8036 EnterMovies ();
8037 #ifdef MAC_OSX
8038 init_image_func_pointer ();
8039 #endif
8040 #endif
8043 /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
8044 (do not change this comment) */