*** empty log message ***
[emacs.git] / src / image.c
blob9c2f6962b6eaa9df2a81a6a9e21c13e0b6a32b52
1 /* Functions for image support on window system.
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04
3 Free Software Foundation.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <ctype.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
32 /* This makes the fields of a Display accessible, in Xlib header files. */
34 #define XLIB_ILLEGAL_ACCESS
36 #include "lisp.h"
37 #include "frame.h"
38 #include "window.h"
39 #include "dispextern.h"
40 #include "blockinput.h"
41 #include "systime.h"
42 #include <epaths.h>
45 #ifdef HAVE_X_WINDOWS
46 #include "xterm.h"
47 #include <sys/types.h>
48 #include <sys/stat.h>
50 #define COLOR_TABLE_SUPPORT 1
52 typedef struct x_bitmap_record Bitmap_Record;
53 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
54 #define NO_PIXMAP None
56 #define RGB_PIXEL_COLOR unsigned long
58 #define PIX_MASK_RETAIN(f) 0
59 #define PIX_MASK_DRAW(f) 1
60 #endif /* HAVE_X_WINDOWS */
63 #ifdef HAVE_NTGUI
64 #include "w32term.h"
66 /* W32_TODO : Color tables on W32. */
67 #undef COLOR_TABLE_SUPPORT
69 typedef struct w32_bitmap_record Bitmap_Record;
70 #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
71 #define NO_PIXMAP 0
73 #define RGB_PIXEL_COLOR COLORREF
75 #define PIX_MASK_RETAIN(f) 0
76 #define PIX_MASK_DRAW(f) 1
78 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
79 #define x_defined_color w32_defined_color
80 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
81 #endif /* HAVE_NTGUI */
84 #ifdef MAC_OS
85 #include "macterm.h"
86 #include <sys/stat.h>
87 #ifndef MAC_OSX
88 #include <alloca.h>
89 #include <sys/param.h>
90 #endif
91 #ifdef MAC_OSX
92 #include <QuickTime/QuickTime.h>
93 #else /* not MAC_OSX */
94 #include <Windows.h>
95 #include <Gestalt.h>
96 #include <TextUtils.h>
97 #include <ImageCompression.h>
98 #include <QuickTimeComponents.h>
99 #endif /* not MAC_OSX */
101 /* MAC_TODO : Color tables on Mac. */
102 #undef COLOR_TABLE_SUPPORT
104 #define ZPixmap 0 /* arbitrary */
105 typedef struct mac_bitmap_record Bitmap_Record;
107 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
108 #define NO_PIXMAP 0
110 #define RGB_PIXEL_COLOR unsigned long
112 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
113 #define x_defined_color mac_defined_color
114 #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
115 #define XDrawLine(display, w, gc, x1, y1, x2, y2) \
116 mac_draw_line_to_pixmap(display, w, gc, x1, y1, x2, y2)
118 #endif /* MAC_OS */
121 /* Search path for bitmap files. */
123 Lisp_Object Vx_bitmap_file_path;
126 static void x_disable_image P_ ((struct frame *, struct image *));
127 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
128 Lisp_Object));
130 static void init_color_table P_ ((void));
131 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
132 #ifdef COLOR_TABLE_SUPPORT
133 static void free_color_table P_ ((void));
134 static unsigned long *colors_in_color_table P_ ((int *n));
135 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
136 #endif
138 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
139 id, which is just an int that this section returns. Bitmaps are
140 reference counted so they can be shared among frames.
142 Bitmap indices are guaranteed to be > 0, so a negative number can
143 be used to indicate no bitmap.
145 If you use x_create_bitmap_from_data, then you must keep track of
146 the bitmaps yourself. That is, creating a bitmap from the same
147 data more than once will not be caught. */
149 #ifdef MAC_OS
151 static XImagePtr
152 XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
153 Display *display; /* not used */
154 Pixmap pixmap;
155 int x, y; /* not used */
156 unsigned int width, height; /* not used */
157 unsigned long plane_mask; /* not used */
158 int format; /* not used */
160 #if GLYPH_DEBUG
161 xassert (x == 0 && y == 0);
163 Rect ri, rp;
164 SetRect (&ri, 0, 0, width, height);
165 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
167 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
168 #endif
170 LockPixels (GetGWorldPixMap (pixmap));
172 return pixmap;
175 static void
176 XPutPixel (ximage, x, y, pixel)
177 XImagePtr ximage;
178 int x, y;
179 unsigned long pixel;
181 CGrafPtr old_port;
182 GDHandle old_gdh;
183 RGBColor color;
185 GetGWorld (&old_port, &old_gdh);
186 SetGWorld (ximage, NULL);
188 color.red = RED16_FROM_ULONG (pixel);
189 color.green = GREEN16_FROM_ULONG (pixel);
190 color.blue = BLUE16_FROM_ULONG (pixel);
191 SetCPixel (x, y, &color);
193 SetGWorld (old_port, old_gdh);
196 static unsigned long
197 XGetPixel (ximage, x, y)
198 XImagePtr ximage;
199 int x, y;
201 CGrafPtr old_port;
202 GDHandle old_gdh;
203 RGBColor color;
205 GetGWorld (&old_port, &old_gdh);
206 SetGWorld (ximage, NULL);
208 GetCPixel (x, y, &color);
210 SetGWorld (old_port, old_gdh);
211 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
214 static void
215 XDestroyImage (ximg)
216 XImagePtr ximg;
218 UnlockPixels (GetGWorldPixMap (ximg));
220 #endif /* MAC_OS */
223 /* Functions to access the contents of a bitmap, given an id. */
226 x_bitmap_height (f, id)
227 FRAME_PTR f;
228 int id;
230 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
234 x_bitmap_width (f, id)
235 FRAME_PTR f;
236 int id;
238 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
241 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
243 x_bitmap_pixmap (f, id)
244 FRAME_PTR f;
245 int id;
247 return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
249 #endif
251 #ifdef HAVE_X_WINDOWS
253 x_bitmap_mask (f, id)
254 FRAME_PTR f;
255 int id;
257 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
259 #endif
261 /* Allocate a new bitmap record. Returns index of new record. */
263 static int
264 x_allocate_bitmap_record (f)
265 FRAME_PTR f;
267 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
268 int i;
270 if (dpyinfo->bitmaps == NULL)
272 dpyinfo->bitmaps_size = 10;
273 dpyinfo->bitmaps
274 = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
275 dpyinfo->bitmaps_last = 1;
276 return 1;
279 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
280 return ++dpyinfo->bitmaps_last;
282 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
283 if (dpyinfo->bitmaps[i].refcount == 0)
284 return i + 1;
286 dpyinfo->bitmaps_size *= 2;
287 dpyinfo->bitmaps
288 = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
289 dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
290 return ++dpyinfo->bitmaps_last;
293 /* Add one reference to the reference count of the bitmap with id ID. */
295 void
296 x_reference_bitmap (f, id)
297 FRAME_PTR f;
298 int id;
300 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
303 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
306 x_create_bitmap_from_data (f, bits, width, height)
307 struct frame *f;
308 char *bits;
309 unsigned int width, height;
311 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
312 int id;
314 #ifdef HAVE_X_WINDOWS
315 Pixmap bitmap;
316 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
317 bits, width, height);
318 if (! bitmap)
319 return -1;
320 #endif /* HAVE_X_WINDOWS */
322 #ifdef HAVE_NTGUI
323 Pixmap bitmap;
324 bitmap = CreateBitmap (width, height,
325 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
326 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
327 bits);
328 if (! bitmap)
329 return -1;
330 #endif /* HAVE_NTGUI */
332 #ifdef MAC_OS
333 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
334 if (width % 16 != 0)
335 return -1;
336 #endif
338 id = x_allocate_bitmap_record (f);
339 #ifdef MAC_OS
340 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
341 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
342 return -1;
343 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
344 #endif /* MAC_OS */
346 dpyinfo->bitmaps[id - 1].file = NULL;
347 dpyinfo->bitmaps[id - 1].height = height;
348 dpyinfo->bitmaps[id - 1].width = width;
349 dpyinfo->bitmaps[id - 1].refcount = 1;
351 #ifdef HAVE_X_WINDOWS
352 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
353 dpyinfo->bitmaps[id - 1].have_mask = 0;
354 dpyinfo->bitmaps[id - 1].depth = 1;
355 #endif /* HAVE_X_WINDOWS */
357 #ifdef HAVE_NTGUI
358 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
359 dpyinfo->bitmaps[id - 1].hinst = NULL;
360 dpyinfo->bitmaps[id - 1].depth = 1;
361 #endif /* HAVE_NTGUI */
363 return id;
366 /* Create bitmap from file FILE for frame F. */
369 x_create_bitmap_from_file (f, file)
370 struct frame *f;
371 Lisp_Object file;
373 #ifdef MAC_OS
374 return -1; /* MAC_TODO : bitmap support */
375 #endif /* MAC_OS */
377 #ifdef HAVE_NTGUI
378 return -1; /* W32_TODO : bitmap support */
379 #endif /* HAVE_NTGUI */
381 #ifdef HAVE_X_WINDOWS
382 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
383 unsigned int width, height;
384 Pixmap bitmap;
385 int xhot, yhot, result, id;
386 Lisp_Object found;
387 int fd;
388 char *filename;
390 /* Look for an existing bitmap with the same name. */
391 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
393 if (dpyinfo->bitmaps[id].refcount
394 && dpyinfo->bitmaps[id].file
395 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
397 ++dpyinfo->bitmaps[id].refcount;
398 return id + 1;
402 /* Search bitmap-file-path for the file, if appropriate. */
403 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
404 if (fd < 0)
405 return -1;
406 emacs_close (fd);
408 filename = (char *) SDATA (found);
410 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
411 filename, &width, &height, &bitmap, &xhot, &yhot);
412 if (result != BitmapSuccess)
413 return -1;
415 id = x_allocate_bitmap_record (f);
416 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
417 dpyinfo->bitmaps[id - 1].have_mask = 0;
418 dpyinfo->bitmaps[id - 1].refcount = 1;
419 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
420 dpyinfo->bitmaps[id - 1].depth = 1;
421 dpyinfo->bitmaps[id - 1].height = height;
422 dpyinfo->bitmaps[id - 1].width = width;
423 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
425 return id;
426 #endif /* HAVE_X_WINDOWS */
429 /* Free bitmap B. */
431 static void
432 Free_Bitmap_Record (dpyinfo, bm)
433 Display_Info *dpyinfo;
434 Bitmap_Record *bm;
436 #ifdef HAVE_X_WINDOWS
437 XFreePixmap (dpyinfo->display, bm->pixmap);
438 if (bm->have_mask)
439 XFreePixmap (dpyinfo->display, bm->mask);
440 #endif /* HAVE_X_WINDOWS */
442 #ifdef HAVE_NTGUI
443 DeleteObject (bm->pixmap);
444 #endif /* HAVE_NTGUI */
446 #ifdef MAC_OS
447 xfree (bm->bitmap_data); /* Added ++kfs */
448 bm->bitmap_data = NULL;
449 #endif /* MAC_OS */
451 if (bm->file)
453 xfree (bm->file);
454 bm->file = NULL;
458 /* Remove reference to bitmap with id number ID. */
460 void
461 x_destroy_bitmap (f, id)
462 FRAME_PTR f;
463 int id;
465 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
467 if (id > 0)
469 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
471 if (--bm->refcount == 0)
473 BLOCK_INPUT;
474 Free_Bitmap_Record (dpyinfo, bm);
475 UNBLOCK_INPUT;
480 /* Free all the bitmaps for the display specified by DPYINFO. */
482 void
483 x_destroy_all_bitmaps (dpyinfo)
484 Display_Info *dpyinfo;
486 int i;
487 Bitmap_Record *bm = dpyinfo->bitmaps;
489 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
490 if (bm->refcount > 0)
491 Free_Bitmap_Record (dpyinfo, bm);
493 dpyinfo->bitmaps_last = 0;
497 #ifdef HAVE_X_WINDOWS
499 /* Useful functions defined in the section
500 `Image type independent image structures' below. */
502 static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
503 unsigned long height));
505 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
506 int depth, XImagePtr *ximg,
507 Pixmap *pixmap));
509 static void x_destroy_x_image P_ ((XImagePtr ximg));
512 /* Create a mask of a bitmap. Note is this not a perfect mask.
513 It's nicer with some borders in this context */
516 x_create_bitmap_mask (f, id)
517 struct frame *f;
518 int id;
520 Pixmap pixmap, mask;
521 XImagePtr ximg, mask_img;
522 unsigned long width, height;
523 int result;
524 unsigned long bg;
525 unsigned long x, y, xp, xm, yp, ym;
526 GC gc;
528 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
530 if (!(id > 0))
531 return -1;
533 pixmap = x_bitmap_pixmap (f, id);
534 width = x_bitmap_width (f, id);
535 height = x_bitmap_height (f, id);
537 BLOCK_INPUT;
538 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
539 ~0, ZPixmap);
541 if (!ximg)
543 UNBLOCK_INPUT;
544 return -1;
547 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
549 UNBLOCK_INPUT;
550 if (!result)
552 XDestroyImage (ximg);
553 return -1;
556 bg = four_corners_best (ximg, width, height);
558 for (y = 0; y < ximg->height; ++y)
560 for (x = 0; x < ximg->width; ++x)
562 xp = x != ximg->width - 1 ? x + 1 : 0;
563 xm = x != 0 ? x - 1 : ximg->width - 1;
564 yp = y != ximg->height - 1 ? y + 1 : 0;
565 ym = y != 0 ? y - 1 : ximg->height - 1;
566 if (XGetPixel (ximg, x, y) == bg
567 && XGetPixel (ximg, x, yp) == bg
568 && XGetPixel (ximg, x, ym) == bg
569 && XGetPixel (ximg, xp, y) == bg
570 && XGetPixel (ximg, xp, yp) == bg
571 && XGetPixel (ximg, xp, ym) == bg
572 && XGetPixel (ximg, xm, y) == bg
573 && XGetPixel (ximg, xm, yp) == bg
574 && XGetPixel (ximg, xm, ym) == bg)
575 XPutPixel (mask_img, x, y, 0);
576 else
577 XPutPixel (mask_img, x, y, 1);
581 xassert (interrupt_input_blocked);
582 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
583 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
584 width, height);
585 XFreeGC (FRAME_X_DISPLAY (f), gc);
587 dpyinfo->bitmaps[id - 1].have_mask = 1;
588 dpyinfo->bitmaps[id - 1].mask = mask;
590 XDestroyImage (ximg);
591 x_destroy_x_image (mask_img);
593 return 0;
596 #endif /* HAVE_X_WINDOWS */
599 /***********************************************************************
600 Image types
601 ***********************************************************************/
603 /* Value is the number of elements of vector VECTOR. */
605 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
607 /* List of supported image types. Use define_image_type to add new
608 types. Use lookup_image_type to find a type for a given symbol. */
610 static struct image_type *image_types;
612 /* A list of symbols, one for each supported image type. */
614 Lisp_Object Vimage_types;
616 /* Cache for delayed-loading image types. */
618 static Lisp_Object Vimage_type_cache;
620 /* The symbol `xbm' which is used as the type symbol for XBM images. */
622 Lisp_Object Qxbm;
624 /* Keywords. */
626 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
627 extern Lisp_Object QCdata, QCtype;
628 extern Lisp_Object Qcenter;
629 Lisp_Object QCascent, QCmargin, QCrelief;
630 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
631 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
633 /* Other symbols. */
635 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
637 /* Time in seconds after which images should be removed from the cache
638 if not displayed. */
640 Lisp_Object Vimage_cache_eviction_delay;
642 /* Function prototypes. */
644 static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
645 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
646 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
647 static void x_laplace P_ ((struct frame *, struct image *));
648 static void x_emboss P_ ((struct frame *, struct image *));
649 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
650 Lisp_Object));
652 #define CACHE_IMAGE_TYPE(type, status) \
653 do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
655 #define ADD_IMAGE_TYPE(type) \
656 do { Vimage_types = Fcons (type, Vimage_types); } while (0)
658 /* Define a new image type from TYPE. This adds a copy of TYPE to
659 image_types and caches the loading status of TYPE. */
661 static Lisp_Object
662 define_image_type (type, loaded)
663 struct image_type *type;
664 int loaded;
666 Lisp_Object success;
668 if (!loaded)
669 success = Qnil;
670 else
672 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
673 The initialized data segment is read-only. */
674 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
675 bcopy (type, p, sizeof *p);
676 p->next = image_types;
677 image_types = p;
678 success = Qt;
681 CACHE_IMAGE_TYPE (*type->type, success);
682 return success;
686 /* Look up image type SYMBOL, and return a pointer to its image_type
687 structure. Value is null if SYMBOL is not a known image type. */
689 static INLINE struct image_type *
690 lookup_image_type (symbol)
691 Lisp_Object symbol;
693 struct image_type *type;
695 /* We must initialize the image-type if it hasn't been already. */
696 if (NILP (Finit_image_library (symbol, Qnil)))
697 return 0; /* unimplemented */
699 for (type = image_types; type; type = type->next)
700 if (EQ (symbol, *type->type))
701 break;
703 return type;
707 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
708 valid image specification is a list whose car is the symbol
709 `image', and whose rest is a property list. The property list must
710 contain a value for key `:type'. That value must be the name of a
711 supported image type. The rest of the property list depends on the
712 image type. */
715 valid_image_p (object)
716 Lisp_Object object;
718 int valid_p = 0;
720 if (IMAGEP (object))
722 Lisp_Object tem;
724 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
725 if (EQ (XCAR (tem), QCtype))
727 tem = XCDR (tem);
728 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
730 struct image_type *type;
731 type = lookup_image_type (XCAR (tem));
732 if (type)
733 valid_p = type->valid_p (object);
736 break;
740 return valid_p;
744 /* Log error message with format string FORMAT and argument ARG.
745 Signaling an error, e.g. when an image cannot be loaded, is not a
746 good idea because this would interrupt redisplay, and the error
747 message display would lead to another redisplay. This function
748 therefore simply displays a message. */
750 static void
751 image_error (format, arg1, arg2)
752 char *format;
753 Lisp_Object arg1, arg2;
755 add_to_log (format, arg1, arg2);
760 /***********************************************************************
761 Image specifications
762 ***********************************************************************/
764 enum image_value_type
766 IMAGE_DONT_CHECK_VALUE_TYPE,
767 IMAGE_STRING_VALUE,
768 IMAGE_STRING_OR_NIL_VALUE,
769 IMAGE_SYMBOL_VALUE,
770 IMAGE_POSITIVE_INTEGER_VALUE,
771 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
772 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
773 IMAGE_ASCENT_VALUE,
774 IMAGE_INTEGER_VALUE,
775 IMAGE_FUNCTION_VALUE,
776 IMAGE_NUMBER_VALUE,
777 IMAGE_BOOL_VALUE
780 /* Structure used when parsing image specifications. */
782 struct image_keyword
784 /* Name of keyword. */
785 char *name;
787 /* The type of value allowed. */
788 enum image_value_type type;
790 /* Non-zero means key must be present. */
791 int mandatory_p;
793 /* Used to recognize duplicate keywords in a property list. */
794 int count;
796 /* The value that was found. */
797 Lisp_Object value;
801 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
802 int, Lisp_Object));
803 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
806 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
807 has the format (image KEYWORD VALUE ...). One of the keyword/
808 value pairs must be `:type TYPE'. KEYWORDS is a vector of
809 image_keywords structures of size NKEYWORDS describing other
810 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
812 static int
813 parse_image_spec (spec, keywords, nkeywords, type)
814 Lisp_Object spec;
815 struct image_keyword *keywords;
816 int nkeywords;
817 Lisp_Object type;
819 int i;
820 Lisp_Object plist;
822 if (!IMAGEP (spec))
823 return 0;
825 plist = XCDR (spec);
826 while (CONSP (plist))
828 Lisp_Object key, value;
830 /* First element of a pair must be a symbol. */
831 key = XCAR (plist);
832 plist = XCDR (plist);
833 if (!SYMBOLP (key))
834 return 0;
836 /* There must follow a value. */
837 if (!CONSP (plist))
838 return 0;
839 value = XCAR (plist);
840 plist = XCDR (plist);
842 /* Find key in KEYWORDS. Error if not found. */
843 for (i = 0; i < nkeywords; ++i)
844 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
845 break;
847 if (i == nkeywords)
848 continue;
850 /* Record that we recognized the keyword. If a keywords
851 was found more than once, it's an error. */
852 keywords[i].value = value;
853 ++keywords[i].count;
855 if (keywords[i].count > 1)
856 return 0;
858 /* Check type of value against allowed type. */
859 switch (keywords[i].type)
861 case IMAGE_STRING_VALUE:
862 if (!STRINGP (value))
863 return 0;
864 break;
866 case IMAGE_STRING_OR_NIL_VALUE:
867 if (!STRINGP (value) && !NILP (value))
868 return 0;
869 break;
871 case IMAGE_SYMBOL_VALUE:
872 if (!SYMBOLP (value))
873 return 0;
874 break;
876 case IMAGE_POSITIVE_INTEGER_VALUE:
877 if (!INTEGERP (value) || XINT (value) <= 0)
878 return 0;
879 break;
881 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
882 if (INTEGERP (value) && XINT (value) >= 0)
883 break;
884 if (CONSP (value)
885 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
886 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
887 break;
888 return 0;
890 case IMAGE_ASCENT_VALUE:
891 if (SYMBOLP (value) && EQ (value, Qcenter))
892 break;
893 else if (INTEGERP (value)
894 && XINT (value) >= 0
895 && XINT (value) <= 100)
896 break;
897 return 0;
899 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
900 if (!INTEGERP (value) || XINT (value) < 0)
901 return 0;
902 break;
904 case IMAGE_DONT_CHECK_VALUE_TYPE:
905 break;
907 case IMAGE_FUNCTION_VALUE:
908 value = indirect_function (value);
909 if (SUBRP (value)
910 || COMPILEDP (value)
911 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
912 break;
913 return 0;
915 case IMAGE_NUMBER_VALUE:
916 if (!INTEGERP (value) && !FLOATP (value))
917 return 0;
918 break;
920 case IMAGE_INTEGER_VALUE:
921 if (!INTEGERP (value))
922 return 0;
923 break;
925 case IMAGE_BOOL_VALUE:
926 if (!NILP (value) && !EQ (value, Qt))
927 return 0;
928 break;
930 default:
931 abort ();
932 break;
935 if (EQ (key, QCtype) && !EQ (type, value))
936 return 0;
939 /* Check that all mandatory fields are present. */
940 for (i = 0; i < nkeywords; ++i)
941 if (keywords[i].mandatory_p && keywords[i].count == 0)
942 return 0;
944 return NILP (plist);
948 /* Return the value of KEY in image specification SPEC. Value is nil
949 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
950 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
952 static Lisp_Object
953 image_spec_value (spec, key, found)
954 Lisp_Object spec, key;
955 int *found;
957 Lisp_Object tail;
959 xassert (valid_image_p (spec));
961 for (tail = XCDR (spec);
962 CONSP (tail) && CONSP (XCDR (tail));
963 tail = XCDR (XCDR (tail)))
965 if (EQ (XCAR (tail), key))
967 if (found)
968 *found = 1;
969 return XCAR (XCDR (tail));
973 if (found)
974 *found = 0;
975 return Qnil;
979 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
980 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
981 PIXELS non-nil means return the size in pixels, otherwise return the
982 size in canonical character units.
983 FRAME is the frame on which the image will be displayed. FRAME nil
984 or omitted means use the selected frame. */)
985 (spec, pixels, frame)
986 Lisp_Object spec, pixels, frame;
988 Lisp_Object size;
990 size = Qnil;
991 if (valid_image_p (spec))
993 struct frame *f = check_x_frame (frame);
994 int id = lookup_image (f, spec);
995 struct image *img = IMAGE_FROM_ID (f, id);
996 int width = img->width + 2 * img->hmargin;
997 int height = img->height + 2 * img->vmargin;
999 if (NILP (pixels))
1000 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
1001 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
1002 else
1003 size = Fcons (make_number (width), make_number (height));
1005 else
1006 error ("Invalid image specification");
1008 return size;
1012 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
1013 doc: /* Return t if image SPEC has a mask bitmap.
1014 FRAME is the frame on which the image will be displayed. FRAME nil
1015 or omitted means use the selected frame. */)
1016 (spec, frame)
1017 Lisp_Object spec, frame;
1019 Lisp_Object mask;
1021 mask = Qnil;
1022 if (valid_image_p (spec))
1024 struct frame *f = check_x_frame (frame);
1025 int id = lookup_image (f, spec);
1026 struct image *img = IMAGE_FROM_ID (f, id);
1027 if (img->mask)
1028 mask = Qt;
1030 else
1031 error ("Invalid image specification");
1033 return mask;
1037 /***********************************************************************
1038 Image type independent image structures
1039 ***********************************************************************/
1041 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
1042 static void free_image P_ ((struct frame *f, struct image *img));
1045 /* Allocate and return a new image structure for image specification
1046 SPEC. SPEC has a hash value of HASH. */
1048 static struct image *
1049 make_image (spec, hash)
1050 Lisp_Object spec;
1051 unsigned hash;
1053 struct image *img = (struct image *) xmalloc (sizeof *img);
1055 xassert (valid_image_p (spec));
1056 bzero (img, sizeof *img);
1057 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1058 xassert (img->type != NULL);
1059 img->spec = spec;
1060 img->data.lisp_val = Qnil;
1061 img->ascent = DEFAULT_IMAGE_ASCENT;
1062 img->hash = hash;
1063 return img;
1067 /* Free image IMG which was used on frame F, including its resources. */
1069 static void
1070 free_image (f, img)
1071 struct frame *f;
1072 struct image *img;
1074 if (img)
1076 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1078 /* Remove IMG from the hash table of its cache. */
1079 if (img->prev)
1080 img->prev->next = img->next;
1081 else
1082 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1084 if (img->next)
1085 img->next->prev = img->prev;
1087 c->images[img->id] = NULL;
1089 /* Free resources, then free IMG. */
1090 img->type->free (f, img);
1091 xfree (img);
1096 /* Prepare image IMG for display on frame F. Must be called before
1097 drawing an image. */
1099 void
1100 prepare_image_for_display (f, img)
1101 struct frame *f;
1102 struct image *img;
1104 EMACS_TIME t;
1106 /* We're about to display IMG, so set its timestamp to `now'. */
1107 EMACS_GET_TIME (t);
1108 img->timestamp = EMACS_SECS (t);
1110 /* If IMG doesn't have a pixmap yet, load it now, using the image
1111 type dependent loader function. */
1112 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1113 img->load_failed_p = img->type->load (f, img) == 0;
1117 /* Value is the number of pixels for the ascent of image IMG when
1118 drawn in face FACE. */
1121 image_ascent (img, face, slice)
1122 struct image *img;
1123 struct face *face;
1124 struct glyph_slice *slice;
1126 int height;
1127 int ascent;
1129 if (slice->height == img->height)
1130 height = img->height + img->vmargin;
1131 else if (slice->y == 0)
1132 height = slice->height + img->vmargin;
1133 else
1134 height = slice->height;
1136 if (img->ascent == CENTERED_IMAGE_ASCENT)
1138 if (face->font)
1140 #ifdef HAVE_NTGUI
1141 /* W32 specific version. Why?. ++kfs */
1142 ascent = height / 2 - (FONT_DESCENT(face->font)
1143 - FONT_BASE(face->font)) / 2;
1144 #else
1145 /* This expression is arranged so that if the image can't be
1146 exactly centered, it will be moved slightly up. This is
1147 because a typical font is `top-heavy' (due to the presence
1148 uppercase letters), so the image placement should err towards
1149 being top-heavy too. It also just generally looks better. */
1150 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
1151 #endif /* HAVE_NTGUI */
1153 else
1154 ascent = height / 2;
1156 else
1157 ascent = (int) (height * img->ascent / 100.0);
1159 return ascent;
1163 /* Image background colors. */
1165 /* Find the "best" corner color of a bitmap.
1166 On W32, XIMG is assumed to a device context with the bitmap selected. */
1168 static RGB_PIXEL_COLOR
1169 four_corners_best (ximg, width, height)
1170 XImagePtr_or_DC ximg;
1171 unsigned long width, height;
1173 RGB_PIXEL_COLOR corners[4], best;
1174 int i, best_count;
1176 /* Get the colors at the corners of ximg. */
1177 corners[0] = GET_PIXEL (ximg, 0, 0);
1178 corners[1] = GET_PIXEL (ximg, width - 1, 0);
1179 corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
1180 corners[3] = GET_PIXEL (ximg, 0, height - 1);
1182 /* Choose the most frequently found color as background. */
1183 for (i = best_count = 0; i < 4; ++i)
1185 int j, n;
1187 for (j = n = 0; j < 4; ++j)
1188 if (corners[i] == corners[j])
1189 ++n;
1191 if (n > best_count)
1192 best = corners[i], best_count = n;
1195 return best;
1198 /* Portability macros */
1200 #ifdef HAVE_NTGUI
1202 #define Destroy_Image(img_dc, prev) \
1203 do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
1205 #define Free_Pixmap(display, pixmap) \
1206 DeleteObject (pixmap)
1208 #else
1210 #define Destroy_Image(ximg, dummy) \
1211 XDestroyImage (ximg)
1213 #define Free_Pixmap(display, pixmap) \
1214 XFreePixmap (display, pixmap)
1216 #endif /* HAVE_NTGUI */
1219 /* Return the `background' field of IMG. If IMG doesn't have one yet,
1220 it is guessed heuristically. If non-zero, XIMG is an existing
1221 XImage object (or device context with the image selected on W32) to
1222 use for the heuristic. */
1224 RGB_PIXEL_COLOR
1225 image_background (img, f, ximg)
1226 struct image *img;
1227 struct frame *f;
1228 XImagePtr_or_DC ximg;
1230 if (! img->background_valid)
1231 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1233 int free_ximg = !ximg;
1234 #ifdef HAVE_NTGUI
1235 HGDIOBJ prev;
1236 #endif /* HAVE_NTGUI */
1238 if (free_ximg)
1240 #ifndef HAVE_NTGUI
1241 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
1242 0, 0, img->width, img->height, ~0, ZPixmap);
1243 #else
1244 HDC frame_dc = get_frame_dc (f);
1245 ximg = CreateCompatibleDC (frame_dc);
1246 release_frame_dc (f, frame_dc);
1247 prev = SelectObject (ximg, img->pixmap);
1248 #endif /* !HAVE_NTGUI */
1251 img->background = four_corners_best (ximg, img->width, img->height);
1253 if (free_ximg)
1254 Destroy_Image (ximg, prev);
1256 img->background_valid = 1;
1259 return img->background;
1262 /* Return the `background_transparent' field of IMG. If IMG doesn't
1263 have one yet, it is guessed heuristically. If non-zero, MASK is an
1264 existing XImage object to use for the heuristic. */
1267 image_background_transparent (img, f, mask)
1268 struct image *img;
1269 struct frame *f;
1270 XImagePtr_or_DC mask;
1272 if (! img->background_transparent_valid)
1273 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1275 if (img->mask)
1277 int free_mask = !mask;
1278 #ifdef HAVE_NTGUI
1279 HGDIOBJ prev;
1280 #endif /* HAVE_NTGUI */
1282 if (free_mask)
1284 #ifndef HAVE_NTGUI
1285 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
1286 0, 0, img->width, img->height, ~0, ZPixmap);
1287 #else
1288 HDC frame_dc = get_frame_dc (f);
1289 mask = CreateCompatibleDC (frame_dc);
1290 release_frame_dc (f, frame_dc);
1291 prev = SelectObject (mask, img->mask);
1292 #endif /* HAVE_NTGUI */
1295 img->background_transparent
1296 = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
1298 if (free_mask)
1299 Destroy_Image (mask, prev);
1301 else
1302 img->background_transparent = 0;
1304 img->background_transparent_valid = 1;
1307 return img->background_transparent;
1311 /***********************************************************************
1312 Helper functions for X image types
1313 ***********************************************************************/
1315 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
1316 int, int));
1317 static void x_clear_image P_ ((struct frame *f, struct image *img));
1318 static unsigned long x_alloc_image_color P_ ((struct frame *f,
1319 struct image *img,
1320 Lisp_Object color_name,
1321 unsigned long dflt));
1324 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
1325 free the pixmap if any. MASK_P non-zero means clear the mask
1326 pixmap if any. COLORS_P non-zero means free colors allocated for
1327 the image, if any. */
1329 static void
1330 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
1331 struct frame *f;
1332 struct image *img;
1333 int pixmap_p, mask_p, colors_p;
1335 if (pixmap_p && img->pixmap)
1337 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
1338 img->pixmap = NO_PIXMAP;
1339 img->background_valid = 0;
1342 if (mask_p && img->mask)
1344 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1345 img->mask = NO_PIXMAP;
1346 img->background_transparent_valid = 0;
1349 if (colors_p && img->ncolors)
1351 /* MAC_TODO: color table support. */
1352 /* W32_TODO: color table support. */
1353 #ifdef HAVE_X_WINDOWS
1354 x_free_colors (f, img->colors, img->ncolors);
1355 #endif /* HAVE_X_WINDOWS */
1356 xfree (img->colors);
1357 img->colors = NULL;
1358 img->ncolors = 0;
1362 /* Free X resources of image IMG which is used on frame F. */
1364 static void
1365 x_clear_image (f, img)
1366 struct frame *f;
1367 struct image *img;
1369 BLOCK_INPUT;
1370 x_clear_image_1 (f, img, 1, 1, 1);
1371 UNBLOCK_INPUT;
1375 /* Allocate color COLOR_NAME for image IMG on frame F. If color
1376 cannot be allocated, use DFLT. Add a newly allocated color to
1377 IMG->colors, so that it can be freed again. Value is the pixel
1378 color. */
1380 static unsigned long
1381 x_alloc_image_color (f, img, color_name, dflt)
1382 struct frame *f;
1383 struct image *img;
1384 Lisp_Object color_name;
1385 unsigned long dflt;
1387 XColor color;
1388 unsigned long result;
1390 xassert (STRINGP (color_name));
1392 if (x_defined_color (f, SDATA (color_name), &color, 1))
1394 /* This isn't called frequently so we get away with simply
1395 reallocating the color vector to the needed size, here. */
1396 ++img->ncolors;
1397 img->colors =
1398 (unsigned long *) xrealloc (img->colors,
1399 img->ncolors * sizeof *img->colors);
1400 img->colors[img->ncolors - 1] = color.pixel;
1401 result = color.pixel;
1403 else
1404 result = dflt;
1406 return result;
1411 /***********************************************************************
1412 Image Cache
1413 ***********************************************************************/
1415 static void cache_image P_ ((struct frame *f, struct image *img));
1416 static void postprocess_image P_ ((struct frame *, struct image *));
1418 /* Return a new, initialized image cache that is allocated from the
1419 heap. Call free_image_cache to free an image cache. */
1421 struct image_cache *
1422 make_image_cache ()
1424 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
1425 int size;
1427 bzero (c, sizeof *c);
1428 c->size = 50;
1429 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
1430 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
1431 c->buckets = (struct image **) xmalloc (size);
1432 bzero (c->buckets, size);
1433 return c;
1437 /* Free image cache of frame F. Be aware that X frames share images
1438 caches. */
1440 void
1441 free_image_cache (f)
1442 struct frame *f;
1444 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1445 if (c)
1447 int i;
1449 /* Cache should not be referenced by any frame when freed. */
1450 xassert (c->refcount == 0);
1452 for (i = 0; i < c->used; ++i)
1453 free_image (f, c->images[i]);
1454 xfree (c->images);
1455 xfree (c->buckets);
1456 xfree (c);
1457 FRAME_X_IMAGE_CACHE (f) = NULL;
1462 /* Clear image cache of frame F. FORCE_P non-zero means free all
1463 images. FORCE_P zero means clear only images that haven't been
1464 displayed for some time. Should be called from time to time to
1465 reduce the number of loaded images. If image-eviction-seconds is
1466 non-nil, this frees images in the cache which weren't displayed for
1467 at least that many seconds. */
1469 void
1470 clear_image_cache (f, force_p)
1471 struct frame *f;
1472 int force_p;
1474 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1476 if (c && INTEGERP (Vimage_cache_eviction_delay))
1478 EMACS_TIME t;
1479 unsigned long old;
1480 int i, nfreed;
1482 EMACS_GET_TIME (t);
1483 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
1485 /* Block input so that we won't be interrupted by a SIGIO
1486 while being in an inconsistent state. */
1487 BLOCK_INPUT;
1489 for (i = nfreed = 0; i < c->used; ++i)
1491 struct image *img = c->images[i];
1492 if (img != NULL
1493 && (force_p || img->timestamp < old))
1495 free_image (f, img);
1496 ++nfreed;
1500 /* We may be clearing the image cache because, for example,
1501 Emacs was iconified for a longer period of time. In that
1502 case, current matrices may still contain references to
1503 images freed above. So, clear these matrices. */
1504 if (nfreed)
1506 Lisp_Object tail, frame;
1508 FOR_EACH_FRAME (tail, frame)
1510 struct frame *f = XFRAME (frame);
1511 if (FRAME_WINDOW_P (f)
1512 && FRAME_X_IMAGE_CACHE (f) == c)
1513 clear_current_matrices (f);
1516 ++windows_or_buffers_changed;
1519 UNBLOCK_INPUT;
1524 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
1525 0, 1, 0,
1526 doc: /* Clear the image cache of FRAME.
1527 FRAME nil or omitted means use the selected frame.
1528 FRAME t means clear the image caches of all frames. */)
1529 (frame)
1530 Lisp_Object frame;
1532 if (EQ (frame, Qt))
1534 Lisp_Object tail;
1536 FOR_EACH_FRAME (tail, frame)
1537 if (FRAME_WINDOW_P (XFRAME (frame)))
1538 clear_image_cache (XFRAME (frame), 1);
1540 else
1541 clear_image_cache (check_x_frame (frame), 1);
1543 return Qnil;
1547 /* Compute masks and transform image IMG on frame F, as specified
1548 by the image's specification, */
1550 static void
1551 postprocess_image (f, img)
1552 struct frame *f;
1553 struct image *img;
1555 /* Manipulation of the image's mask. */
1556 if (img->pixmap)
1558 Lisp_Object conversion, spec;
1559 Lisp_Object mask;
1561 spec = img->spec;
1563 /* `:heuristic-mask t'
1564 `:mask heuristic'
1565 means build a mask heuristically.
1566 `:heuristic-mask (R G B)'
1567 `:mask (heuristic (R G B))'
1568 means build a mask from color (R G B) in the
1569 image.
1570 `:mask nil'
1571 means remove a mask, if any. */
1573 mask = image_spec_value (spec, QCheuristic_mask, NULL);
1574 if (!NILP (mask))
1575 x_build_heuristic_mask (f, img, mask);
1576 else
1578 int found_p;
1580 mask = image_spec_value (spec, QCmask, &found_p);
1582 if (EQ (mask, Qheuristic))
1583 x_build_heuristic_mask (f, img, Qt);
1584 else if (CONSP (mask)
1585 && EQ (XCAR (mask), Qheuristic))
1587 if (CONSP (XCDR (mask)))
1588 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
1589 else
1590 x_build_heuristic_mask (f, img, XCDR (mask));
1592 else if (NILP (mask) && found_p && img->mask)
1594 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1595 img->mask = NO_PIXMAP;
1600 /* Should we apply an image transformation algorithm? */
1601 conversion = image_spec_value (spec, QCconversion, NULL);
1602 if (EQ (conversion, Qdisabled))
1603 x_disable_image (f, img);
1604 else if (EQ (conversion, Qlaplace))
1605 x_laplace (f, img);
1606 else if (EQ (conversion, Qemboss))
1607 x_emboss (f, img);
1608 else if (CONSP (conversion)
1609 && EQ (XCAR (conversion), Qedge_detection))
1611 Lisp_Object tem;
1612 tem = XCDR (conversion);
1613 if (CONSP (tem))
1614 x_edge_detection (f, img,
1615 Fplist_get (tem, QCmatrix),
1616 Fplist_get (tem, QCcolor_adjustment));
1622 /* Return the id of image with Lisp specification SPEC on frame F.
1623 SPEC must be a valid Lisp image specification (see valid_image_p). */
1626 lookup_image (f, spec)
1627 struct frame *f;
1628 Lisp_Object spec;
1630 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1631 #ifdef _MSC_VER
1632 /* Work around a problem with MinGW builds of graphics libraries
1633 not honoring calling conventions. */
1634 static
1635 #endif
1636 struct image *img;
1637 int i;
1638 unsigned hash;
1639 struct gcpro gcpro1;
1640 EMACS_TIME now;
1642 /* F must be a window-system frame, and SPEC must be a valid image
1643 specification. */
1644 xassert (FRAME_WINDOW_P (f));
1645 xassert (valid_image_p (spec));
1647 GCPRO1 (spec);
1649 /* Look up SPEC in the hash table of the image cache. */
1650 hash = sxhash (spec, 0);
1651 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1653 for (img = c->buckets[i]; img; img = img->next)
1654 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
1655 break;
1657 /* If not found, create a new image and cache it. */
1658 if (img == NULL)
1660 extern Lisp_Object Qpostscript;
1662 BLOCK_INPUT;
1663 img = make_image (spec, hash);
1664 cache_image (f, img);
1665 img->load_failed_p = img->type->load (f, img) == 0;
1667 /* If we can't load the image, and we don't have a width and
1668 height, use some arbitrary width and height so that we can
1669 draw a rectangle for it. */
1670 if (img->load_failed_p)
1672 Lisp_Object value;
1674 value = image_spec_value (spec, QCwidth, NULL);
1675 img->width = (INTEGERP (value)
1676 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
1677 value = image_spec_value (spec, QCheight, NULL);
1678 img->height = (INTEGERP (value)
1679 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
1681 else
1683 /* Handle image type independent image attributes
1684 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
1685 `:background COLOR'. */
1686 Lisp_Object ascent, margin, relief, bg;
1688 ascent = image_spec_value (spec, QCascent, NULL);
1689 if (INTEGERP (ascent))
1690 img->ascent = XFASTINT (ascent);
1691 else if (EQ (ascent, Qcenter))
1692 img->ascent = CENTERED_IMAGE_ASCENT;
1694 margin = image_spec_value (spec, QCmargin, NULL);
1695 if (INTEGERP (margin) && XINT (margin) >= 0)
1696 img->vmargin = img->hmargin = XFASTINT (margin);
1697 else if (CONSP (margin) && INTEGERP (XCAR (margin))
1698 && INTEGERP (XCDR (margin)))
1700 if (XINT (XCAR (margin)) > 0)
1701 img->hmargin = XFASTINT (XCAR (margin));
1702 if (XINT (XCDR (margin)) > 0)
1703 img->vmargin = XFASTINT (XCDR (margin));
1706 relief = image_spec_value (spec, QCrelief, NULL);
1707 if (INTEGERP (relief))
1709 img->relief = XINT (relief);
1710 img->hmargin += abs (img->relief);
1711 img->vmargin += abs (img->relief);
1714 if (! img->background_valid)
1716 bg = image_spec_value (img->spec, QCbackground, NULL);
1717 if (!NILP (bg))
1719 img->background
1720 = x_alloc_image_color (f, img, bg,
1721 FRAME_BACKGROUND_PIXEL (f));
1722 img->background_valid = 1;
1726 /* Do image transformations and compute masks, unless we
1727 don't have the image yet. */
1728 if (!EQ (*img->type->type, Qpostscript))
1729 postprocess_image (f, img);
1732 UNBLOCK_INPUT;
1735 /* We're using IMG, so set its timestamp to `now'. */
1736 EMACS_GET_TIME (now);
1737 img->timestamp = EMACS_SECS (now);
1739 UNGCPRO;
1741 /* Value is the image id. */
1742 return img->id;
1746 /* Cache image IMG in the image cache of frame F. */
1748 static void
1749 cache_image (f, img)
1750 struct frame *f;
1751 struct image *img;
1753 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1754 int i;
1756 /* Find a free slot in c->images. */
1757 for (i = 0; i < c->used; ++i)
1758 if (c->images[i] == NULL)
1759 break;
1761 /* If no free slot found, maybe enlarge c->images. */
1762 if (i == c->used && c->used == c->size)
1764 c->size *= 2;
1765 c->images = (struct image **) xrealloc (c->images,
1766 c->size * sizeof *c->images);
1769 /* Add IMG to c->images, and assign IMG an id. */
1770 c->images[i] = img;
1771 img->id = i;
1772 if (i == c->used)
1773 ++c->used;
1775 /* Add IMG to the cache's hash table. */
1776 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
1777 img->next = c->buckets[i];
1778 if (img->next)
1779 img->next->prev = img;
1780 img->prev = NULL;
1781 c->buckets[i] = img;
1785 /* Call FN on every image in the image cache of frame F. Used to mark
1786 Lisp Objects in the image cache. */
1788 void
1789 forall_images_in_image_cache (f, fn)
1790 struct frame *f;
1791 void (*fn) P_ ((struct image *img));
1793 if (FRAME_LIVE_P (f) && FRAME_WINDOW_P (f))
1795 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
1796 if (c)
1798 int i;
1799 for (i = 0; i < c->used; ++i)
1800 if (c->images[i])
1801 fn (c->images[i]);
1808 /***********************************************************************
1809 X / MAC / W32 support code
1810 ***********************************************************************/
1812 #ifdef HAVE_NTGUI
1814 /* Macro for defining functions that will be loaded from image DLLs. */
1815 #define DEF_IMGLIB_FN(func) FARPROC fn_##func
1817 /* Macro for loading those image functions from the library. */
1818 #define LOAD_IMGLIB_FN(lib,func) { \
1819 fn_##func = (void *) GetProcAddress (lib, #func); \
1820 if (!fn_##func) return 0; \
1823 /* Load a DLL implementing an image type.
1824 The `image-library-alist' variable associates a symbol,
1825 identifying an image type, to a list of possible filenames.
1826 The function returns NULL if no library could be loaded for
1827 the given image type, or if the library was previously loaded;
1828 else the handle of the DLL. */
1829 static HMODULE
1830 w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
1832 HMODULE library = NULL;
1834 if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
1836 Lisp_Object dlls = Fassq (type, libraries);
1838 if (CONSP (dlls))
1839 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
1841 CHECK_STRING_CAR (dlls);
1842 if (library = LoadLibrary (SDATA (XCAR (dlls))))
1843 break;
1847 return library;
1850 #endif /* HAVE_NTGUI */
1852 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
1853 XImagePtr *, Pixmap *));
1854 static void x_destroy_x_image P_ ((XImagePtr));
1855 static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
1858 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
1859 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
1860 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
1861 via xmalloc. Print error messages via image_error if an error
1862 occurs. Value is non-zero if successful.
1864 On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
1865 should indicate the bit depth of the image. */
1867 static int
1868 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
1869 struct frame *f;
1870 int width, height, depth;
1871 XImagePtr *ximg;
1872 Pixmap *pixmap;
1874 #ifdef HAVE_X_WINDOWS
1875 Display *display = FRAME_X_DISPLAY (f);
1876 Window window = FRAME_X_WINDOW (f);
1877 Screen *screen = FRAME_X_SCREEN (f);
1879 xassert (interrupt_input_blocked);
1881 if (depth <= 0)
1882 depth = DefaultDepthOfScreen (screen);
1883 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
1884 depth, ZPixmap, 0, NULL, width, height,
1885 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
1886 if (*ximg == NULL)
1888 image_error ("Unable to allocate X image", Qnil, Qnil);
1889 return 0;
1892 /* Allocate image raster. */
1893 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
1895 /* Allocate a pixmap of the same size. */
1896 *pixmap = XCreatePixmap (display, window, width, height, depth);
1897 if (*pixmap == NO_PIXMAP)
1899 x_destroy_x_image (*ximg);
1900 *ximg = NULL;
1901 image_error ("Unable to create X pixmap", Qnil, Qnil);
1902 return 0;
1905 return 1;
1906 #endif /* HAVE_X_WINDOWS */
1908 #ifdef HAVE_NTGUI
1910 BITMAPINFOHEADER *header;
1911 HDC hdc;
1912 int scanline_width_bits;
1913 int remainder;
1914 int palette_colors = 0;
1916 if (depth == 0)
1917 depth = 24;
1919 if (depth != 1 && depth != 4 && depth != 8
1920 && depth != 16 && depth != 24 && depth != 32)
1922 image_error ("Invalid image bit depth specified", Qnil, Qnil);
1923 return 0;
1926 scanline_width_bits = width * depth;
1927 remainder = scanline_width_bits % 32;
1929 if (remainder)
1930 scanline_width_bits += 32 - remainder;
1932 /* Bitmaps with a depth less than 16 need a palette. */
1933 /* BITMAPINFO structure already contains the first RGBQUAD. */
1934 if (depth < 16)
1935 palette_colors = 1 << depth - 1;
1937 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
1938 if (*ximg == NULL)
1940 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
1941 return 0;
1944 header = &((*ximg)->info.bmiHeader);
1945 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
1946 header->biSize = sizeof (*header);
1947 header->biWidth = width;
1948 header->biHeight = -height; /* negative indicates a top-down bitmap. */
1949 header->biPlanes = 1;
1950 header->biBitCount = depth;
1951 header->biCompression = BI_RGB;
1952 header->biClrUsed = palette_colors;
1954 /* TODO: fill in palette. */
1955 if (depth == 1)
1957 (*ximg)->info.bmiColors[0].rgbBlue = 0;
1958 (*ximg)->info.bmiColors[0].rgbGreen = 0;
1959 (*ximg)->info.bmiColors[0].rgbRed = 0;
1960 (*ximg)->info.bmiColors[0].rgbReserved = 0;
1961 (*ximg)->info.bmiColors[1].rgbBlue = 255;
1962 (*ximg)->info.bmiColors[1].rgbGreen = 255;
1963 (*ximg)->info.bmiColors[1].rgbRed = 255;
1964 (*ximg)->info.bmiColors[1].rgbReserved = 0;
1967 hdc = get_frame_dc (f);
1969 /* Create a DIBSection and raster array for the bitmap,
1970 and store its handle in *pixmap. */
1971 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
1972 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
1973 &((*ximg)->data), NULL, 0);
1975 /* Realize display palette and garbage all frames. */
1976 release_frame_dc (f, hdc);
1978 if (*pixmap == NULL)
1980 DWORD err = GetLastError();
1981 Lisp_Object errcode;
1982 /* All system errors are < 10000, so the following is safe. */
1983 XSETINT (errcode, (int) err);
1984 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
1985 x_destroy_x_image (*ximg);
1986 return 0;
1989 return 1;
1991 #endif /* HAVE_NTGUI */
1993 #ifdef MAC_OS
1994 Display *display = FRAME_X_DISPLAY (f);
1995 Window window = FRAME_X_WINDOW (f);
1997 xassert (interrupt_input_blocked);
1999 /* Allocate a pixmap of the same size. */
2000 *pixmap = XCreatePixmap (display, window, width, height, depth);
2001 if (*pixmap == NO_PIXMAP)
2003 x_destroy_x_image (*ximg);
2004 *ximg = NULL;
2005 image_error ("Unable to create X pixmap", Qnil, Qnil);
2006 return 0;
2009 LockPixels (GetGWorldPixMap (*pixmap));
2010 *ximg = *pixmap;
2011 return 1;
2013 #endif /* MAC_OS */
2017 /* Destroy XImage XIMG. Free XIMG->data. */
2019 static void
2020 x_destroy_x_image (ximg)
2021 XImagePtr ximg;
2023 xassert (interrupt_input_blocked);
2024 if (ximg)
2026 #ifdef HAVE_X_WINDOWS
2027 xfree (ximg->data);
2028 ximg->data = NULL;
2029 XDestroyImage (ximg);
2030 #endif /* HAVE_X_WINDOWS */
2031 #ifdef HAVE_NTGUI
2032 /* Data will be freed by DestroyObject. */
2033 ximg->data = NULL;
2034 xfree (ximg);
2035 #endif /* HAVE_NTGUI */
2036 #ifdef MAC_OS
2037 XDestroyImage (ximg);
2038 #endif /* MAC_OS */
2043 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
2044 are width and height of both the image and pixmap. */
2046 static void
2047 x_put_x_image (f, ximg, pixmap, width, height)
2048 struct frame *f;
2049 XImagePtr ximg;
2050 Pixmap pixmap;
2051 int width, height;
2053 #ifdef HAVE_X_WINDOWS
2054 GC gc;
2056 xassert (interrupt_input_blocked);
2057 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
2058 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
2059 XFreeGC (FRAME_X_DISPLAY (f), gc);
2060 #endif /* HAVE_X_WINDOWS */
2062 #ifdef HAVE_NTGUI
2063 #if 0 /* I don't think this is necessary looking at where it is used. */
2064 HDC hdc = get_frame_dc (f);
2065 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
2066 release_frame_dc (f, hdc);
2067 #endif
2068 #endif /* HAVE_NTGUI */
2070 #ifdef MAC_OS
2071 xassert (ximg == pixmap);
2072 #endif /* MAC_OS */
2076 /***********************************************************************
2077 File Handling
2078 ***********************************************************************/
2080 static unsigned char *slurp_file P_ ((char *, int *));
2083 /* Find image file FILE. Look in data-directory, then
2084 x-bitmap-file-path. Value is the full name of the file found, or
2085 nil if not found. */
2087 Lisp_Object
2088 x_find_image_file (file)
2089 Lisp_Object file;
2091 Lisp_Object file_found, search_path;
2092 struct gcpro gcpro1, gcpro2;
2093 int fd;
2095 file_found = Qnil;
2096 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
2097 GCPRO2 (file_found, search_path);
2099 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
2100 fd = openp (search_path, file, Qnil, &file_found, Qnil);
2102 if (fd == -1)
2103 file_found = Qnil;
2104 else
2105 close (fd);
2107 UNGCPRO;
2108 return file_found;
2112 /* Read FILE into memory. Value is a pointer to a buffer allocated
2113 with xmalloc holding FILE's contents. Value is null if an error
2114 occurred. *SIZE is set to the size of the file. */
2116 static unsigned char *
2117 slurp_file (file, size)
2118 char *file;
2119 int *size;
2121 FILE *fp = NULL;
2122 unsigned char *buf = NULL;
2123 struct stat st;
2125 if (stat (file, &st) == 0
2126 && (fp = fopen (file, "rb")) != NULL
2127 && (buf = (char *) xmalloc (st.st_size),
2128 fread (buf, 1, st.st_size, fp) == st.st_size))
2130 *size = st.st_size;
2131 fclose (fp);
2133 else
2135 if (fp)
2136 fclose (fp);
2137 if (buf)
2139 xfree (buf);
2140 buf = NULL;
2144 return buf;
2149 #ifdef MAC_OS
2151 /***********************************************************************
2152 MAC Image Load Functions
2153 ***********************************************************************/
2155 static int image_load_quicktime P_ ((struct frame *, struct image *img,
2156 OSType));
2157 #ifdef MAC_OSX
2158 static int image_load_quartz2d P_ ((struct frame *, struct image *img, int));
2159 #endif
2161 static OSErr
2162 find_image_fsspec (specified_file, file, fss)
2163 Lisp_Object specified_file, *file;
2164 FSSpec *fss;
2166 #if TARGET_API_MAC_CARBON
2167 FSRef fsr;
2168 #else
2169 Str255 mac_pathname;
2170 #endif
2171 OSErr err;
2173 *file = x_find_image_file (specified_file);
2174 if (!STRINGP (*file))
2175 return fnfErr; /* file or directory not found;
2176 incomplete pathname */
2177 /* Try to open the image file. */
2178 #if TARGET_API_MAC_CARBON
2179 err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
2180 if (err == noErr)
2181 err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
2182 #else
2183 if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
2184 return fnfErr;
2185 c2pstr (mac_pathname);
2186 err = FSMakeFSSpec (0, 0, mac_pathname, fss);
2187 #endif
2188 return err;
2191 static int
2192 image_load_qt_1 (f, img, type, fss, dh)
2193 struct frame *f;
2194 struct image *img;
2195 OSType type;
2196 FSSpec *fss;
2197 Handle dh;
2199 OSErr err;
2200 GraphicsImportComponent gi;
2201 Rect rect;
2202 int width, height;
2203 short draw_all_pixels;
2204 Lisp_Object specified_bg;
2205 XColor color;
2206 XImagePtr ximg;
2207 RGBColor bg_color;
2209 err = OpenADefaultComponent (GraphicsImporterComponentType,
2210 type, &gi);
2211 if (err != noErr)
2213 image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
2214 return 0;
2216 if (dh == NULL)
2218 /* read from file system spec */
2219 err = GraphicsImportSetDataFile (gi, fss);
2220 if (err != noErr)
2222 image_error ("Cannot set fsspec to graphics importer for '%s'",
2223 img->spec, Qnil);
2224 goto error;
2227 else
2229 /* read from data handle */
2230 err = GraphicsImportSetDataHandle (gi, dh);
2231 if (err != noErr)
2233 image_error ("Cannot set data handle to graphics importer for `%s'",
2234 img->spec, Qnil);
2235 goto error;
2238 err = GraphicsImportGetNaturalBounds (gi, &rect);
2239 if (err != noErr)
2241 image_error ("Error reading `%s'", img->spec, Qnil);
2242 goto error;
2244 width = img->width = rect.right - rect.left;
2245 height = img->height = rect.bottom - rect.top;
2246 err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
2247 #if 0
2248 /* Don't check the error code here. It may have an undocumented
2249 value -32766. */
2250 if (err != noErr)
2252 image_error ("Error reading `%s'", img->spec, Qnil);
2253 goto error;
2255 #endif
2256 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2258 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2259 if (!STRINGP (specified_bg) ||
2260 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2262 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2263 color.red = RED16_FROM_ULONG (color.pixel);
2264 color.green = GREEN16_FROM_ULONG (color.pixel);
2265 color.blue = BLUE16_FROM_ULONG (color.pixel);
2269 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2270 goto error;
2271 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
2273 CGrafPtr old_port;
2274 GDHandle old_gdh;
2276 GetGWorld (&old_port, &old_gdh);
2277 SetGWorld (ximg, NULL);
2278 bg_color.red = color.red;
2279 bg_color.green = color.green;
2280 bg_color.blue = color.blue;
2281 RGBBackColor (&bg_color);
2282 #if TARGET_API_MAC_CARBON
2283 GetPortBounds (ximg, &rect);
2284 EraseRect (&rect);
2285 #else
2286 EraseRect (&(ximg->portRect));
2287 #endif
2288 SetGWorld (old_port, old_gdh);
2290 GraphicsImportSetGWorld (gi, ximg, NULL);
2291 GraphicsImportDraw (gi);
2292 CloseComponent (gi);
2294 /* Maybe fill in the background field while we have ximg handy. */
2295 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2296 IMAGE_BACKGROUND (img, f, ximg);
2298 /* Put the image into the pixmap. */
2299 x_put_x_image (f, ximg, img->pixmap, width, height);
2300 x_destroy_x_image (ximg);
2301 return 1;
2303 error:
2304 CloseComponent (gi);
2305 return 0;
2309 /* Load an image using the QuickTime Graphics Importer.
2310 Note: The alpha channel does not work for PNG images. */
2311 static int
2312 image_load_quicktime (f, img, type)
2313 struct frame *f;
2314 struct image *img;
2315 OSType type;
2317 Lisp_Object specified_file;
2318 Lisp_Object specified_data;
2319 OSErr err;
2321 specified_file = image_spec_value (img->spec, QCfile, NULL);
2322 specified_data = image_spec_value (img->spec, QCdata, NULL);
2324 if (NILP (specified_data))
2326 /* Read from a file */
2327 Lisp_Object file;
2328 FSSpec fss;
2330 err = find_image_fsspec (specified_file, &file, &fss);
2331 if (err != noErr)
2333 if (err == fnfErr)
2334 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2335 else
2336 image_error ("Cannot open `%s'", file, Qnil);
2337 return 0;
2339 return image_load_qt_1 (f, img, type, &fss, NULL);
2341 else
2343 /* Memory source! */
2344 int success_p;
2345 Handle dh;
2347 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
2348 if (err != noErr)
2350 image_error ("Cannot allocate data handle for `%s'",
2351 img->spec, Qnil);
2352 return 0;
2354 success_p = image_load_qt_1 (f, img, type, NULL, dh);
2355 DisposeHandle (dh);
2356 return success_p;
2361 #ifdef MAC_OSX
2362 /* Load a PNG/JPEG image using Quartz 2D decoding routines.
2363 CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2.
2364 So don't use this function directly but determine at runtime
2365 whether it exists. */
2366 typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType)
2367 (CGDataProviderRef, const float [], bool, CGColorRenderingIntent);
2368 static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider;
2371 static void
2372 init_image_func_pointer ()
2374 if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider"))
2376 MyCGImageCreateWithPNGDataProvider
2377 = (CGImageCreateWithPNGDataProviderProcType)
2378 NSAddressOfSymbol (NSLookupAndBindSymbol
2379 ("_CGImageCreateWithPNGDataProvider"));
2381 else
2382 MyCGImageCreateWithPNGDataProvider = NULL;
2386 static int
2387 image_load_quartz2d (f, img, png_p)
2388 struct frame *f;
2389 struct image *img;
2390 int png_p;
2392 Lisp_Object file, specified_file;
2393 Lisp_Object specified_data, specified_bg;
2394 struct gcpro gcpro1;
2395 CGDataProviderRef source;
2396 CGImageRef image;
2397 int width, height;
2398 XColor color;
2399 XImagePtr ximg = NULL;
2400 CGContextRef context;
2401 CGRect rectangle;
2403 /* Open the file. */
2404 specified_file = image_spec_value (img->spec, QCfile, NULL);
2405 specified_data = image_spec_value (img->spec, QCdata, NULL);
2407 file = Qnil;
2408 GCPRO1 (file);
2410 if (NILP (specified_data))
2412 CFStringRef path;
2413 CFURLRef url;
2415 file = x_find_image_file (specified_file);
2416 if (!STRINGP (file))
2418 image_error ("Cannot find image file `%s'", specified_file, Qnil);
2419 UNGCPRO;
2420 return 0;
2422 path = cfstring_create_with_utf8_cstring (SDATA (file));
2423 url = CFURLCreateWithFileSystemPath (NULL, path,
2424 kCFURLPOSIXPathStyle, 0);
2425 CFRelease (path);
2426 source = CGDataProviderCreateWithURL (url);
2427 CFRelease (url);
2429 else
2430 source = CGDataProviderCreateWithData (NULL, SDATA (specified_data),
2431 SBYTES (specified_data), NULL);
2433 if (png_p)
2434 image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE,
2435 kCGRenderingIntentDefault);
2436 else
2437 image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE,
2438 kCGRenderingIntentDefault);
2440 CGDataProviderRelease (source);
2441 if (image == NULL)
2443 UNGCPRO;
2444 image_error ("Error reading image `%s'", img->spec, Qnil);
2445 return 0;
2448 if (png_p)
2450 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
2451 if (!STRINGP (specified_bg) ||
2452 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
2454 color.pixel = FRAME_BACKGROUND_PIXEL (f);
2455 color.red = RED16_FROM_ULONG (color.pixel);
2456 color.green = GREEN16_FROM_ULONG (color.pixel);
2457 color.blue = BLUE16_FROM_ULONG (color.pixel);
2460 width = img->width = CGImageGetWidth (image);
2461 height = img->height = CGImageGetHeight (image);
2462 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
2464 CGImageRelease (image);
2465 UNGCPRO;
2466 return 0;
2468 rectangle = CGRectMake (0, 0, width, height);
2469 QDBeginCGContext (ximg, &context);
2470 if (png_p)
2472 CGContextSetRGBFillColor (context, color.red / 65535.0,
2473 color.green / 65535.0,
2474 color.blue / 65535.0, 1.0);
2475 CGContextFillRect (context, rectangle);
2477 CGContextDrawImage (context, rectangle, image);
2478 QDEndCGContext (ximg, &context);
2479 CGImageRelease (image);
2481 /* Maybe fill in the background field while we have ximg handy. */
2482 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2483 IMAGE_BACKGROUND (img, f, ximg);
2485 /* Put the image into the pixmap. */
2486 x_put_x_image (f, ximg, img->pixmap, width, height);
2487 x_destroy_x_image (ximg);
2488 UNGCPRO;
2489 return 1;
2491 #endif
2493 #endif /* MAC_OS */
2496 /***********************************************************************
2497 XBM images
2498 ***********************************************************************/
2500 static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
2501 static int xbm_load P_ ((struct frame *f, struct image *img));
2502 static int xbm_load_image P_ ((struct frame *f, struct image *img,
2503 unsigned char *, unsigned char *));
2504 static int xbm_image_p P_ ((Lisp_Object object));
2505 static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
2506 int *, int *, unsigned char **));
2507 static int xbm_file_p P_ ((Lisp_Object));
2510 /* Indices of image specification fields in xbm_format, below. */
2512 enum xbm_keyword_index
2514 XBM_TYPE,
2515 XBM_FILE,
2516 XBM_WIDTH,
2517 XBM_HEIGHT,
2518 XBM_DATA,
2519 XBM_FOREGROUND,
2520 XBM_BACKGROUND,
2521 XBM_ASCENT,
2522 XBM_MARGIN,
2523 XBM_RELIEF,
2524 XBM_ALGORITHM,
2525 XBM_HEURISTIC_MASK,
2526 XBM_MASK,
2527 XBM_LAST
2530 /* Vector of image_keyword structures describing the format
2531 of valid XBM image specifications. */
2533 static struct image_keyword xbm_format[XBM_LAST] =
2535 {":type", IMAGE_SYMBOL_VALUE, 1},
2536 {":file", IMAGE_STRING_VALUE, 0},
2537 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2538 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2539 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2540 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
2541 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
2542 {":ascent", IMAGE_ASCENT_VALUE, 0},
2543 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
2544 {":relief", IMAGE_INTEGER_VALUE, 0},
2545 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2546 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2547 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
2550 /* Structure describing the image type XBM. */
2552 static struct image_type xbm_type =
2554 &Qxbm,
2555 xbm_image_p,
2556 xbm_load,
2557 x_clear_image,
2558 NULL
2561 /* Tokens returned from xbm_scan. */
2563 enum xbm_token
2565 XBM_TK_IDENT = 256,
2566 XBM_TK_NUMBER
2570 /* Return non-zero if OBJECT is a valid XBM-type image specification.
2571 A valid specification is a list starting with the symbol `image'
2572 The rest of the list is a property list which must contain an
2573 entry `:type xbm..
2575 If the specification specifies a file to load, it must contain
2576 an entry `:file FILENAME' where FILENAME is a string.
2578 If the specification is for a bitmap loaded from memory it must
2579 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
2580 WIDTH and HEIGHT are integers > 0. DATA may be:
2582 1. a string large enough to hold the bitmap data, i.e. it must
2583 have a size >= (WIDTH + 7) / 8 * HEIGHT
2585 2. a bool-vector of size >= WIDTH * HEIGHT
2587 3. a vector of strings or bool-vectors, one for each line of the
2588 bitmap.
2590 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
2591 may not be specified in this case because they are defined in the
2592 XBM file.
2594 Both the file and data forms may contain the additional entries
2595 `:background COLOR' and `:foreground COLOR'. If not present,
2596 foreground and background of the frame on which the image is
2597 displayed is used. */
2599 static int
2600 xbm_image_p (object)
2601 Lisp_Object object;
2603 struct image_keyword kw[XBM_LAST];
2605 bcopy (xbm_format, kw, sizeof kw);
2606 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
2607 return 0;
2609 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
2611 if (kw[XBM_FILE].count)
2613 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
2614 return 0;
2616 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
2618 /* In-memory XBM file. */
2619 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
2620 return 0;
2622 else
2624 Lisp_Object data;
2625 int width, height;
2627 /* Entries for `:width', `:height' and `:data' must be present. */
2628 if (!kw[XBM_WIDTH].count
2629 || !kw[XBM_HEIGHT].count
2630 || !kw[XBM_DATA].count)
2631 return 0;
2633 data = kw[XBM_DATA].value;
2634 width = XFASTINT (kw[XBM_WIDTH].value);
2635 height = XFASTINT (kw[XBM_HEIGHT].value);
2637 /* Check type of data, and width and height against contents of
2638 data. */
2639 if (VECTORP (data))
2641 int i;
2643 /* Number of elements of the vector must be >= height. */
2644 if (XVECTOR (data)->size < height)
2645 return 0;
2647 /* Each string or bool-vector in data must be large enough
2648 for one line of the image. */
2649 for (i = 0; i < height; ++i)
2651 Lisp_Object elt = XVECTOR (data)->contents[i];
2653 if (STRINGP (elt))
2655 if (SCHARS (elt)
2656 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
2657 return 0;
2659 else if (BOOL_VECTOR_P (elt))
2661 if (XBOOL_VECTOR (elt)->size < width)
2662 return 0;
2664 else
2665 return 0;
2668 else if (STRINGP (data))
2670 if (SCHARS (data)
2671 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
2672 return 0;
2674 else if (BOOL_VECTOR_P (data))
2676 if (XBOOL_VECTOR (data)->size < width * height)
2677 return 0;
2679 else
2680 return 0;
2683 return 1;
2687 /* Scan a bitmap file. FP is the stream to read from. Value is
2688 either an enumerator from enum xbm_token, or a character for a
2689 single-character token, or 0 at end of file. If scanning an
2690 identifier, store the lexeme of the identifier in SVAL. If
2691 scanning a number, store its value in *IVAL. */
2693 static int
2694 xbm_scan (s, end, sval, ival)
2695 unsigned char **s, *end;
2696 char *sval;
2697 int *ival;
2699 unsigned int c;
2701 loop:
2703 /* Skip white space. */
2704 while (*s < end && (c = *(*s)++, isspace (c)))
2707 if (*s >= end)
2708 c = 0;
2709 else if (isdigit (c))
2711 int value = 0, digit;
2713 if (c == '0' && *s < end)
2715 c = *(*s)++;
2716 if (c == 'x' || c == 'X')
2718 while (*s < end)
2720 c = *(*s)++;
2721 if (isdigit (c))
2722 digit = c - '0';
2723 else if (c >= 'a' && c <= 'f')
2724 digit = c - 'a' + 10;
2725 else if (c >= 'A' && c <= 'F')
2726 digit = c - 'A' + 10;
2727 else
2728 break;
2729 value = 16 * value + digit;
2732 else if (isdigit (c))
2734 value = c - '0';
2735 while (*s < end
2736 && (c = *(*s)++, isdigit (c)))
2737 value = 8 * value + c - '0';
2740 else
2742 value = c - '0';
2743 while (*s < end
2744 && (c = *(*s)++, isdigit (c)))
2745 value = 10 * value + c - '0';
2748 if (*s < end)
2749 *s = *s - 1;
2750 *ival = value;
2751 c = XBM_TK_NUMBER;
2753 else if (isalpha (c) || c == '_')
2755 *sval++ = c;
2756 while (*s < end
2757 && (c = *(*s)++, (isalnum (c) || c == '_')))
2758 *sval++ = c;
2759 *sval = 0;
2760 if (*s < end)
2761 *s = *s - 1;
2762 c = XBM_TK_IDENT;
2764 else if (c == '/' && **s == '*')
2766 /* C-style comment. */
2767 ++*s;
2768 while (**s && (**s != '*' || *(*s + 1) != '/'))
2769 ++*s;
2770 if (**s)
2772 *s += 2;
2773 goto loop;
2777 return c;
2780 #ifdef HAVE_NTGUI
2782 /* Create a Windows bitmap from X bitmap data. */
2783 static HBITMAP
2784 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
2786 static unsigned char swap_nibble[16]
2787 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
2788 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
2789 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
2790 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
2791 int i, j, w1, w2;
2792 unsigned char *bits, *p;
2793 HBITMAP bmp;
2795 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
2796 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
2797 bits = (unsigned char *) alloca (height * w2);
2798 bzero (bits, height * w2);
2799 for (i = 0; i < height; i++)
2801 p = bits + i*w2;
2802 for (j = 0; j < w1; j++)
2804 /* Bitswap XBM bytes to match how Windows does things. */
2805 unsigned char c = *data++;
2806 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
2807 | (swap_nibble[(c>>4) & 0xf]));
2810 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
2812 return bmp;
2815 static void convert_mono_to_color_image (f, img, foreground, background)
2816 struct frame *f;
2817 struct image *img;
2818 COLORREF foreground, background;
2820 HDC hdc, old_img_dc, new_img_dc;
2821 HGDIOBJ old_prev, new_prev;
2822 HBITMAP new_pixmap;
2824 hdc = get_frame_dc (f);
2825 old_img_dc = CreateCompatibleDC (hdc);
2826 new_img_dc = CreateCompatibleDC (hdc);
2827 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
2828 release_frame_dc (f, hdc);
2829 old_prev = SelectObject (old_img_dc, img->pixmap);
2830 new_prev = SelectObject (new_img_dc, new_pixmap);
2831 SetTextColor (new_img_dc, foreground);
2832 SetBkColor (new_img_dc, background);
2834 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
2835 0, 0, SRCCOPY);
2837 SelectObject (old_img_dc, old_prev);
2838 SelectObject (new_img_dc, new_prev);
2839 DeleteDC (old_img_dc);
2840 DeleteDC (new_img_dc);
2841 DeleteObject (img->pixmap);
2842 if (new_pixmap == 0)
2843 fprintf (stderr, "Failed to convert image to color.\n");
2844 else
2845 img->pixmap = new_pixmap;
2848 #define XBM_BIT_SHUFFLE(b) (~(b))
2850 #else
2852 #define XBM_BIT_SHUFFLE(b) (b)
2854 #endif /* HAVE_NTGUI */
2857 static void
2858 Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
2859 struct frame *f;
2860 struct image *img;
2861 char *data;
2862 RGB_PIXEL_COLOR fg, bg;
2863 int non_default_colors;
2865 #ifdef HAVE_NTGUI
2866 img->pixmap
2867 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
2869 /* If colors were specified, transfer the bitmap to a color one. */
2870 if (non_default_colors)
2871 convert_mono_to_color_image (f, img, fg, bg);
2872 #else
2873 img->pixmap
2874 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
2875 FRAME_X_WINDOW (f),
2876 data,
2877 img->width, img->height,
2878 fg, bg,
2879 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
2880 #endif /* HAVE_NTGUI */
2885 /* Replacement for XReadBitmapFileData which isn't available under old
2886 X versions. CONTENTS is a pointer to a buffer to parse; END is the
2887 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
2888 the image. Return in *DATA the bitmap data allocated with xmalloc.
2889 Value is non-zero if successful. DATA null means just test if
2890 CONTENTS looks like an in-memory XBM file. */
2892 static int
2893 xbm_read_bitmap_data (contents, end, width, height, data)
2894 unsigned char *contents, *end;
2895 int *width, *height;
2896 unsigned char **data;
2898 unsigned char *s = contents;
2899 char buffer[BUFSIZ];
2900 int padding_p = 0;
2901 int v10 = 0;
2902 int bytes_per_line, i, nbytes;
2903 unsigned char *p;
2904 int value;
2905 int LA1;
2907 #define match() \
2908 LA1 = xbm_scan (&s, end, buffer, &value)
2910 #define expect(TOKEN) \
2911 if (LA1 != (TOKEN)) \
2912 goto failure; \
2913 else \
2914 match ()
2916 #define expect_ident(IDENT) \
2917 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2918 match (); \
2919 else \
2920 goto failure
2922 *width = *height = -1;
2923 if (data)
2924 *data = NULL;
2925 LA1 = xbm_scan (&s, end, buffer, &value);
2927 /* Parse defines for width, height and hot-spots. */
2928 while (LA1 == '#')
2930 match ();
2931 expect_ident ("define");
2932 expect (XBM_TK_IDENT);
2934 if (LA1 == XBM_TK_NUMBER);
2936 char *p = strrchr (buffer, '_');
2937 p = p ? p + 1 : buffer;
2938 if (strcmp (p, "width") == 0)
2939 *width = value;
2940 else if (strcmp (p, "height") == 0)
2941 *height = value;
2943 expect (XBM_TK_NUMBER);
2946 if (*width < 0 || *height < 0)
2947 goto failure;
2948 else if (data == NULL)
2949 goto success;
2951 /* Parse bits. Must start with `static'. */
2952 expect_ident ("static");
2953 if (LA1 == XBM_TK_IDENT)
2955 if (strcmp (buffer, "unsigned") == 0)
2957 match ();
2958 expect_ident ("char");
2960 else if (strcmp (buffer, "short") == 0)
2962 match ();
2963 v10 = 1;
2964 if (*width % 16 && *width % 16 < 9)
2965 padding_p = 1;
2967 else if (strcmp (buffer, "char") == 0)
2968 match ();
2969 else
2970 goto failure;
2972 else
2973 goto failure;
2975 expect (XBM_TK_IDENT);
2976 expect ('[');
2977 expect (']');
2978 expect ('=');
2979 expect ('{');
2981 bytes_per_line = (*width + 7) / 8 + padding_p;
2982 nbytes = bytes_per_line * *height;
2983 p = *data = (char *) xmalloc (nbytes);
2985 if (v10)
2987 for (i = 0; i < nbytes; i += 2)
2989 int val = value;
2990 expect (XBM_TK_NUMBER);
2992 *p++ = XBM_BIT_SHUFFLE (val);
2993 if (!padding_p || ((i + 2) % bytes_per_line))
2994 *p++ = XBM_BIT_SHUFFLE (value >> 8);
2996 if (LA1 == ',' || LA1 == '}')
2997 match ();
2998 else
2999 goto failure;
3002 else
3004 for (i = 0; i < nbytes; ++i)
3006 int val = value;
3007 expect (XBM_TK_NUMBER);
3009 *p++ = XBM_BIT_SHUFFLE (val);
3011 if (LA1 == ',' || LA1 == '}')
3012 match ();
3013 else
3014 goto failure;
3018 success:
3019 return 1;
3021 failure:
3023 if (data && *data)
3025 xfree (*data);
3026 *data = NULL;
3028 return 0;
3030 #undef match
3031 #undef expect
3032 #undef expect_ident
3036 /* Load XBM image IMG which will be displayed on frame F from buffer
3037 CONTENTS. END is the end of the buffer. Value is non-zero if
3038 successful. */
3040 static int
3041 xbm_load_image (f, img, contents, end)
3042 struct frame *f;
3043 struct image *img;
3044 unsigned char *contents, *end;
3046 int rc;
3047 unsigned char *data;
3048 int success_p = 0;
3050 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
3051 if (rc)
3053 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3054 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3055 int non_default_colors = 0;
3056 Lisp_Object value;
3058 xassert (img->width > 0 && img->height > 0);
3060 /* Get foreground and background colors, maybe allocate colors. */
3061 value = image_spec_value (img->spec, QCforeground, NULL);
3062 if (!NILP (value))
3064 foreground = x_alloc_image_color (f, img, value, foreground);
3065 non_default_colors = 1;
3067 value = image_spec_value (img->spec, QCbackground, NULL);
3068 if (!NILP (value))
3070 background = x_alloc_image_color (f, img, value, background);
3071 img->background = background;
3072 img->background_valid = 1;
3073 non_default_colors = 1;
3076 Create_Pixmap_From_Bitmap_Data (f, img, data,
3077 foreground, background,
3078 non_default_colors);
3079 xfree (data);
3081 if (img->pixmap == NO_PIXMAP)
3083 x_clear_image (f, img);
3084 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3086 else
3087 success_p = 1;
3089 else
3090 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3092 return success_p;
3096 /* Value is non-zero if DATA looks like an in-memory XBM file. */
3098 static int
3099 xbm_file_p (data)
3100 Lisp_Object data;
3102 int w, h;
3103 return (STRINGP (data)
3104 && xbm_read_bitmap_data (SDATA (data),
3105 (SDATA (data)
3106 + SBYTES (data)),
3107 &w, &h, NULL));
3111 /* Fill image IMG which is used on frame F with pixmap data. Value is
3112 non-zero if successful. */
3114 static int
3115 xbm_load (f, img)
3116 struct frame *f;
3117 struct image *img;
3119 int success_p = 0;
3120 Lisp_Object file_name;
3122 xassert (xbm_image_p (img->spec));
3124 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3125 file_name = image_spec_value (img->spec, QCfile, NULL);
3126 if (STRINGP (file_name))
3128 Lisp_Object file;
3129 unsigned char *contents;
3130 int size;
3131 struct gcpro gcpro1;
3133 file = x_find_image_file (file_name);
3134 GCPRO1 (file);
3135 if (!STRINGP (file))
3137 image_error ("Cannot find image file `%s'", file_name, Qnil);
3138 UNGCPRO;
3139 return 0;
3142 contents = slurp_file (SDATA (file), &size);
3143 if (contents == NULL)
3145 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3146 UNGCPRO;
3147 return 0;
3150 success_p = xbm_load_image (f, img, contents, contents + size);
3151 UNGCPRO;
3153 else
3155 struct image_keyword fmt[XBM_LAST];
3156 Lisp_Object data;
3157 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3158 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3159 int non_default_colors = 0;
3160 char *bits;
3161 int parsed_p;
3162 int in_memory_file_p = 0;
3164 /* See if data looks like an in-memory XBM file. */
3165 data = image_spec_value (img->spec, QCdata, NULL);
3166 in_memory_file_p = xbm_file_p (data);
3168 /* Parse the image specification. */
3169 bcopy (xbm_format, fmt, sizeof fmt);
3170 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3171 xassert (parsed_p);
3173 /* Get specified width, and height. */
3174 if (!in_memory_file_p)
3176 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3177 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3178 xassert (img->width > 0 && img->height > 0);
3181 /* Get foreground and background colors, maybe allocate colors. */
3182 if (fmt[XBM_FOREGROUND].count
3183 && STRINGP (fmt[XBM_FOREGROUND].value))
3185 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3186 foreground);
3187 non_default_colors = 1;
3190 if (fmt[XBM_BACKGROUND].count
3191 && STRINGP (fmt[XBM_BACKGROUND].value))
3193 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3194 background);
3195 non_default_colors = 1;
3198 if (in_memory_file_p)
3199 success_p = xbm_load_image (f, img, SDATA (data),
3200 (SDATA (data)
3201 + SBYTES (data)));
3202 else
3204 if (VECTORP (data))
3206 int i;
3207 char *p;
3208 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3210 p = bits = (char *) alloca (nbytes * img->height);
3211 for (i = 0; i < img->height; ++i, p += nbytes)
3213 Lisp_Object line = XVECTOR (data)->contents[i];
3214 if (STRINGP (line))
3215 bcopy (SDATA (line), p, nbytes);
3216 else
3217 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3220 else if (STRINGP (data))
3221 bits = SDATA (data);
3222 else
3223 bits = XBOOL_VECTOR (data)->data;
3225 /* Create the pixmap. */
3227 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3228 foreground, background,
3229 non_default_colors);
3230 if (img->pixmap)
3231 success_p = 1;
3232 else
3234 image_error ("Unable to create pixmap for XBM image `%s'",
3235 img->spec, Qnil);
3236 x_clear_image (f, img);
3241 return success_p;
3246 /***********************************************************************
3247 XPM images
3248 ***********************************************************************/
3250 #if defined (HAVE_XPM) || defined (MAC_OS)
3252 static int xpm_image_p P_ ((Lisp_Object object));
3253 static int xpm_load P_ ((struct frame *f, struct image *img));
3254 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3256 #endif /* HAVE_XPM || MAC_OS */
3258 #ifdef HAVE_XPM
3259 #ifdef HAVE_NTGUI
3260 /* Indicate to xpm.h that we don't have Xlib. */
3261 #define FOR_MSW
3262 /* simx.h in xpm defines XColor and XImage differently than Emacs. */
3263 /* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
3264 #define XColor xpm_XColor
3265 #define XImage xpm_XImage
3266 #define Display xpm_Display
3267 #define PIXEL_ALREADY_TYPEDEFED
3268 #include "X11/xpm.h"
3269 #undef FOR_MSW
3270 #undef XColor
3271 #undef XImage
3272 #undef Display
3273 #undef PIXEL_ALREADY_TYPEDEFED
3274 #else
3275 #include "X11/xpm.h"
3276 #endif /* HAVE_NTGUI */
3277 #endif /* HAVE_XPM */
3279 #if defined (HAVE_XPM) || defined (MAC_OS)
3280 /* The symbol `xpm' identifying XPM-format images. */
3282 Lisp_Object Qxpm;
3284 /* Indices of image specification fields in xpm_format, below. */
3286 enum xpm_keyword_index
3288 XPM_TYPE,
3289 XPM_FILE,
3290 XPM_DATA,
3291 XPM_ASCENT,
3292 XPM_MARGIN,
3293 XPM_RELIEF,
3294 XPM_ALGORITHM,
3295 XPM_HEURISTIC_MASK,
3296 XPM_MASK,
3297 XPM_COLOR_SYMBOLS,
3298 XPM_BACKGROUND,
3299 XPM_LAST
3302 /* Vector of image_keyword structures describing the format
3303 of valid XPM image specifications. */
3305 static struct image_keyword xpm_format[XPM_LAST] =
3307 {":type", IMAGE_SYMBOL_VALUE, 1},
3308 {":file", IMAGE_STRING_VALUE, 0},
3309 {":data", IMAGE_STRING_VALUE, 0},
3310 {":ascent", IMAGE_ASCENT_VALUE, 0},
3311 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3312 {":relief", IMAGE_INTEGER_VALUE, 0},
3313 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3314 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3315 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3316 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3317 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3320 /* Structure describing the image type XPM. */
3322 static struct image_type xpm_type =
3324 &Qxpm,
3325 xpm_image_p,
3326 xpm_load,
3327 x_clear_image,
3328 NULL
3331 #ifdef HAVE_X_WINDOWS
3333 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3334 functions for allocating image colors. Our own functions handle
3335 color allocation failures more gracefully than the ones on the XPM
3336 lib. */
3338 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3339 #define ALLOC_XPM_COLORS
3340 #endif
3341 #endif /* HAVE_X_WINDOWS */
3343 #ifdef ALLOC_XPM_COLORS
3345 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3346 static void xpm_free_color_cache P_ ((void));
3347 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3348 static int xpm_color_bucket P_ ((char *));
3349 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3350 XColor *, int));
3352 /* An entry in a hash table used to cache color definitions of named
3353 colors. This cache is necessary to speed up XPM image loading in
3354 case we do color allocations ourselves. Without it, we would need
3355 a call to XParseColor per pixel in the image. */
3357 struct xpm_cached_color
3359 /* Next in collision chain. */
3360 struct xpm_cached_color *next;
3362 /* Color definition (RGB and pixel color). */
3363 XColor color;
3365 /* Color name. */
3366 char name[1];
3369 /* The hash table used for the color cache, and its bucket vector
3370 size. */
3372 #define XPM_COLOR_CACHE_BUCKETS 1001
3373 struct xpm_cached_color **xpm_color_cache;
3375 /* Initialize the color cache. */
3377 static void
3378 xpm_init_color_cache (f, attrs)
3379 struct frame *f;
3380 XpmAttributes *attrs;
3382 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3383 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3384 memset (xpm_color_cache, 0, nbytes);
3385 init_color_table ();
3387 if (attrs->valuemask & XpmColorSymbols)
3389 int i;
3390 XColor color;
3392 for (i = 0; i < attrs->numsymbols; ++i)
3393 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3394 attrs->colorsymbols[i].value, &color))
3396 color.pixel = lookup_rgb_color (f, color.red, color.green,
3397 color.blue);
3398 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3403 /* Free the color cache. */
3405 static void
3406 xpm_free_color_cache ()
3408 struct xpm_cached_color *p, *next;
3409 int i;
3411 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3412 for (p = xpm_color_cache[i]; p; p = next)
3414 next = p->next;
3415 xfree (p);
3418 xfree (xpm_color_cache);
3419 xpm_color_cache = NULL;
3420 free_color_table ();
3423 /* Return the bucket index for color named COLOR_NAME in the color
3424 cache. */
3426 static int
3427 xpm_color_bucket (color_name)
3428 char *color_name;
3430 unsigned h = 0;
3431 char *s;
3433 for (s = color_name; *s; ++s)
3434 h = (h << 2) ^ *s;
3435 return h %= XPM_COLOR_CACHE_BUCKETS;
3439 /* On frame F, cache values COLOR for color with name COLOR_NAME.
3440 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3441 entry added. */
3443 static struct xpm_cached_color *
3444 xpm_cache_color (f, color_name, color, bucket)
3445 struct frame *f;
3446 char *color_name;
3447 XColor *color;
3448 int bucket;
3450 size_t nbytes;
3451 struct xpm_cached_color *p;
3453 if (bucket < 0)
3454 bucket = xpm_color_bucket (color_name);
3456 nbytes = sizeof *p + strlen (color_name);
3457 p = (struct xpm_cached_color *) xmalloc (nbytes);
3458 strcpy (p->name, color_name);
3459 p->color = *color;
3460 p->next = xpm_color_cache[bucket];
3461 xpm_color_cache[bucket] = p;
3462 return p;
3465 /* Look up color COLOR_NAME for frame F in the color cache. If found,
3466 return the cached definition in *COLOR. Otherwise, make a new
3467 entry in the cache and allocate the color. Value is zero if color
3468 allocation failed. */
3470 static int
3471 xpm_lookup_color (f, color_name, color)
3472 struct frame *f;
3473 char *color_name;
3474 XColor *color;
3476 struct xpm_cached_color *p;
3477 int h = xpm_color_bucket (color_name);
3479 for (p = xpm_color_cache[h]; p; p = p->next)
3480 if (strcmp (p->name, color_name) == 0)
3481 break;
3483 if (p != NULL)
3484 *color = p->color;
3485 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3486 color_name, color))
3488 color->pixel = lookup_rgb_color (f, color->red, color->green,
3489 color->blue);
3490 p = xpm_cache_color (f, color_name, color, h);
3492 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3493 with transparency, and it's useful. */
3494 else if (strcmp ("opaque", color_name) == 0)
3496 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3497 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3498 p = xpm_cache_color (f, color_name, color, h);
3501 return p != NULL;
3505 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3506 CLOSURE is a pointer to the frame on which we allocate the
3507 color. Return in *COLOR the allocated color. Value is non-zero
3508 if successful. */
3510 static int
3511 xpm_alloc_color (dpy, cmap, color_name, color, closure)
3512 Display *dpy;
3513 Colormap cmap;
3514 char *color_name;
3515 XColor *color;
3516 void *closure;
3518 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3522 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3523 is a pointer to the frame on which we allocate the color. Value is
3524 non-zero if successful. */
3526 static int
3527 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3528 Display *dpy;
3529 Colormap cmap;
3530 Pixel *pixels;
3531 int npixels;
3532 void *closure;
3534 return 1;
3537 #endif /* ALLOC_XPM_COLORS */
3540 #ifdef HAVE_NTGUI
3542 /* XPM library details. */
3544 DEF_IMGLIB_FN (XpmFreeAttributes);
3545 DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3546 DEF_IMGLIB_FN (XpmReadFileToImage);
3547 DEF_IMGLIB_FN (XImageFree);
3549 static int
3550 init_xpm_functions (Lisp_Object libraries)
3552 HMODULE library;
3554 if (!(library = w32_delayed_load (libraries, Qxpm)))
3555 return 0;
3557 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3558 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3559 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3560 LOAD_IMGLIB_FN (library, XImageFree);
3561 return 1;
3564 #endif /* HAVE_NTGUI */
3567 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3568 for XPM images. Such a list must consist of conses whose car and
3569 cdr are strings. */
3571 static int
3572 xpm_valid_color_symbols_p (color_symbols)
3573 Lisp_Object color_symbols;
3575 while (CONSP (color_symbols))
3577 Lisp_Object sym = XCAR (color_symbols);
3578 if (!CONSP (sym)
3579 || !STRINGP (XCAR (sym))
3580 || !STRINGP (XCDR (sym)))
3581 break;
3582 color_symbols = XCDR (color_symbols);
3585 return NILP (color_symbols);
3589 /* Value is non-zero if OBJECT is a valid XPM image specification. */
3591 static int
3592 xpm_image_p (object)
3593 Lisp_Object object;
3595 struct image_keyword fmt[XPM_LAST];
3596 bcopy (xpm_format, fmt, sizeof fmt);
3597 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3598 /* Either `:file' or `:data' must be present. */
3599 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3600 /* Either no `:color-symbols' or it's a list of conses
3601 whose car and cdr are strings. */
3602 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3603 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3606 #endif /* HAVE_XPM || MAC_OS */
3608 /* Load image IMG which will be displayed on frame F. Value is
3609 non-zero if successful. */
3611 #ifdef HAVE_XPM
3613 static int
3614 xpm_load (f, img)
3615 struct frame *f;
3616 struct image *img;
3618 int rc;
3619 XpmAttributes attrs;
3620 Lisp_Object specified_file, color_symbols;
3621 #ifdef HAVE_NTGUI
3622 HDC hdc;
3623 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3624 #endif /* HAVE_NTGUI */
3626 /* Configure the XPM lib. Use the visual of frame F. Allocate
3627 close colors. Return colors allocated. */
3628 bzero (&attrs, sizeof attrs);
3630 #ifndef HAVE_NTGUI
3631 attrs.visual = FRAME_X_VISUAL (f);
3632 attrs.colormap = FRAME_X_COLORMAP (f);
3633 attrs.valuemask |= XpmVisual;
3634 attrs.valuemask |= XpmColormap;
3635 #endif /* HAVE_NTGUI */
3637 #ifdef ALLOC_XPM_COLORS
3638 /* Allocate colors with our own functions which handle
3639 failing color allocation more gracefully. */
3640 attrs.color_closure = f;
3641 attrs.alloc_color = xpm_alloc_color;
3642 attrs.free_colors = xpm_free_colors;
3643 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3644 #else /* not ALLOC_XPM_COLORS */
3645 /* Let the XPM lib allocate colors. */
3646 attrs.valuemask |= XpmReturnAllocPixels;
3647 #ifdef XpmAllocCloseColors
3648 attrs.alloc_close_colors = 1;
3649 attrs.valuemask |= XpmAllocCloseColors;
3650 #else /* not XpmAllocCloseColors */
3651 attrs.closeness = 600;
3652 attrs.valuemask |= XpmCloseness;
3653 #endif /* not XpmAllocCloseColors */
3654 #endif /* ALLOC_XPM_COLORS */
3656 /* If image specification contains symbolic color definitions, add
3657 these to `attrs'. */
3658 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3659 if (CONSP (color_symbols))
3661 Lisp_Object tail;
3662 XpmColorSymbol *xpm_syms;
3663 int i, size;
3665 attrs.valuemask |= XpmColorSymbols;
3667 /* Count number of symbols. */
3668 attrs.numsymbols = 0;
3669 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3670 ++attrs.numsymbols;
3672 /* Allocate an XpmColorSymbol array. */
3673 size = attrs.numsymbols * sizeof *xpm_syms;
3674 xpm_syms = (XpmColorSymbol *) alloca (size);
3675 bzero (xpm_syms, size);
3676 attrs.colorsymbols = xpm_syms;
3678 /* Fill the color symbol array. */
3679 for (tail = color_symbols, i = 0;
3680 CONSP (tail);
3681 ++i, tail = XCDR (tail))
3683 Lisp_Object name = XCAR (XCAR (tail));
3684 Lisp_Object color = XCDR (XCAR (tail));
3685 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3686 strcpy (xpm_syms[i].name, SDATA (name));
3687 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3688 strcpy (xpm_syms[i].value, SDATA (color));
3692 /* Create a pixmap for the image, either from a file, or from a
3693 string buffer containing data in the same format as an XPM file. */
3694 #ifdef ALLOC_XPM_COLORS
3695 xpm_init_color_cache (f, &attrs);
3696 #endif
3698 specified_file = image_spec_value (img->spec, QCfile, NULL);
3700 #ifdef HAVE_NTGUI
3702 HDC frame_dc = get_frame_dc (f);
3703 hdc = CreateCompatibleDC (frame_dc);
3704 release_frame_dc (f, frame_dc);
3706 #endif /* HAVE_NTGUI */
3708 if (STRINGP (specified_file))
3710 Lisp_Object file = x_find_image_file (specified_file);
3711 if (!STRINGP (file))
3713 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3714 return 0;
3717 #ifdef HAVE_NTGUI
3718 /* XpmReadFileToPixmap is not available in the Windows port of
3719 libxpm. But XpmReadFileToImage almost does what we want. */
3720 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3721 &xpm_image, &xpm_mask,
3722 &attrs);
3723 #else
3724 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3725 SDATA (file), &img->pixmap, &img->mask,
3726 &attrs);
3727 #endif /* HAVE_NTGUI */
3729 else
3731 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3732 #ifdef HAVE_NTGUI
3733 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3734 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3735 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3736 &xpm_image, &xpm_mask,
3737 &attrs);
3738 #else
3739 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3740 SDATA (buffer),
3741 &img->pixmap, &img->mask,
3742 &attrs);
3743 #endif /* HAVE_NTGUI */
3746 if (rc == XpmSuccess)
3748 #if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3749 img->colors = colors_in_color_table (&img->ncolors);
3750 #else /* not ALLOC_XPM_COLORS */
3751 int i;
3753 #ifdef HAVE_NTGUI
3754 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3755 plus some duplicate attributes. */
3756 if (xpm_image && xpm_image->bitmap)
3758 img->pixmap = xpm_image->bitmap;
3759 /* XImageFree in libXpm frees XImage struct without destroying
3760 the bitmap, which is what we want. */
3761 fn_XImageFree (xpm_image);
3763 if (xpm_mask && xpm_mask->bitmap)
3765 /* The mask appears to be inverted compared with what we expect.
3766 TODO: invert our expectations. See other places where we
3767 have to invert bits because our idea of masks is backwards. */
3768 HGDIOBJ old_obj;
3769 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3771 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3772 SelectObject (hdc, old_obj);
3774 img->mask = xpm_mask->bitmap;
3775 fn_XImageFree (xpm_mask);
3776 DeleteDC (hdc);
3779 DeleteDC (hdc);
3780 #endif /* HAVE_NTGUI */
3782 /* Remember allocated colors. */
3783 img->ncolors = attrs.nalloc_pixels;
3784 img->colors = (unsigned long *) xmalloc (img->ncolors
3785 * sizeof *img->colors);
3786 for (i = 0; i < attrs.nalloc_pixels; ++i)
3788 img->colors[i] = attrs.alloc_pixels[i];
3789 #ifdef DEBUG_X_COLORS
3790 register_color (img->colors[i]);
3791 #endif
3793 #endif /* not ALLOC_XPM_COLORS */
3795 img->width = attrs.width;
3796 img->height = attrs.height;
3797 xassert (img->width > 0 && img->height > 0);
3799 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3800 #ifdef HAVE_NTGUI
3801 fn_XpmFreeAttributes (&attrs);
3802 #else
3803 XpmFreeAttributes (&attrs);
3804 #endif /* HAVE_NTGUI */
3806 else
3808 #ifdef HAVE_NTGUI
3809 DeleteDC (hdc);
3810 #endif /* HAVE_NTGUI */
3812 switch (rc)
3814 case XpmOpenFailed:
3815 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3816 break;
3818 case XpmFileInvalid:
3819 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3820 break;
3822 case XpmNoMemory:
3823 image_error ("Out of memory (%s)", img->spec, Qnil);
3824 break;
3826 case XpmColorFailed:
3827 image_error ("Color allocation error (%s)", img->spec, Qnil);
3828 break;
3830 default:
3831 image_error ("Unknown error (%s)", img->spec, Qnil);
3832 break;
3836 #ifdef ALLOC_XPM_COLORS
3837 xpm_free_color_cache ();
3838 #endif
3839 return rc == XpmSuccess;
3842 #endif /* HAVE_XPM */
3844 #ifdef MAC_OS
3846 /* XPM support functions for Mac OS where libxpm is not available.
3847 Only XPM version 3 (without any extensions) is supported. */
3849 static int xpm_scan P_ ((unsigned char **, unsigned char *,
3850 unsigned char **, int *));
3851 static Lisp_Object xpm_make_color_table_v
3852 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3853 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3854 static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *,
3855 int, Lisp_Object));
3856 static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
3857 unsigned char *, int));
3858 static Lisp_Object xpm_make_color_table_h
3859 P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
3860 Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
3861 static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *,
3862 int, Lisp_Object));
3863 static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
3864 unsigned char *, int));
3865 static int xpm_str_to_color_key P_ ((char *));
3866 static int xpm_load_image P_ ((struct frame *, struct image *,
3867 unsigned char *, unsigned char *));
3869 /* Tokens returned from xpm_scan. */
3871 enum xpm_token
3873 XPM_TK_IDENT = 256,
3874 XPM_TK_STRING,
3875 XPM_TK_EOF
3878 /* Scan an XPM data and return a character (< 256) or a token defined
3879 by enum xpm_token above. *S and END are the start (inclusive) and
3880 the end (exclusive) addresses of the data, respectively. Advance
3881 *S while scanning. If token is either XPM_TK_IDENT or
3882 XPM_TK_STRING, *BEG and *LEN are set to the start address and the
3883 length of the corresponding token, respectively. */
3885 static int
3886 xpm_scan (s, end, beg, len)
3887 unsigned char **s, *end, **beg;
3888 int *len;
3890 int c;
3892 while (*s < end)
3894 /* Skip white-space. */
3895 while (*s < end && (c = *(*s)++, isspace (c)))
3898 /* gnus-pointer.xpm uses '-' in its identifier.
3899 sb-dir-plus.xpm uses '+' in its identifier. */
3900 if (isalpha (c) || c == '_' || c == '-' || c == '+')
3902 *beg = *s - 1;
3903 while (*s < end &&
3904 (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
3905 ++*s;
3906 *len = *s - *beg;
3907 return XPM_TK_IDENT;
3909 else if (c == '"')
3911 *beg = *s;
3912 while (*s < end && **s != '"')
3913 ++*s;
3914 *len = *s - *beg;
3915 if (*s < end)
3916 ++*s;
3917 return XPM_TK_STRING;
3919 else if (c == '/')
3921 if (*s < end && **s == '*')
3923 /* C-style comment. */
3924 ++*s;
3927 while (*s < end && *(*s)++ != '*')
3930 while (*s < end && **s != '/');
3931 if (*s < end)
3932 ++*s;
3934 else
3935 return c;
3937 else
3938 return c;
3941 return XPM_TK_EOF;
3944 /* Functions for color table lookup in XPM data. A Key is a string
3945 specifying the color of each pixel in XPM data. A value is either
3946 an integer that specifies a pixel color, Qt that specifies
3947 transparency, or Qnil for the unspecified color. If the length of
3948 the key string is one, a vector is used as a table. Otherwise, a
3949 hash table is used. */
3951 static Lisp_Object
3952 xpm_make_color_table_v (put_func, get_func)
3953 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3954 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3956 *put_func = xpm_put_color_table_v;
3957 *get_func = xpm_get_color_table_v;
3958 return Fmake_vector (make_number (256), Qnil);
3961 static void
3962 xpm_put_color_table_v (color_table, chars_start, chars_len, color)
3963 Lisp_Object color_table;
3964 unsigned char *chars_start;
3965 int chars_len;
3966 Lisp_Object color;
3968 XVECTOR (color_table)->contents[*chars_start] = color;
3971 static Lisp_Object
3972 xpm_get_color_table_v (color_table, chars_start, chars_len)
3973 Lisp_Object color_table;
3974 unsigned char *chars_start;
3975 int chars_len;
3977 return XVECTOR (color_table)->contents[*chars_start];
3980 static Lisp_Object
3981 xpm_make_color_table_h (put_func, get_func)
3982 void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
3983 Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
3985 *put_func = xpm_put_color_table_h;
3986 *get_func = xpm_get_color_table_h;
3987 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
3988 make_float (DEFAULT_REHASH_SIZE),
3989 make_float (DEFAULT_REHASH_THRESHOLD),
3990 Qnil, Qnil, Qnil);
3993 static void
3994 xpm_put_color_table_h (color_table, chars_start, chars_len, color)
3995 Lisp_Object color_table;
3996 unsigned char *chars_start;
3997 int chars_len;
3998 Lisp_Object color;
4000 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4001 unsigned hash_code;
4002 Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
4004 hash_lookup (table, chars, &hash_code);
4005 hash_put (table, chars, color, hash_code);
4008 static Lisp_Object
4009 xpm_get_color_table_h (color_table, chars_start, chars_len)
4010 Lisp_Object color_table;
4011 unsigned char *chars_start;
4012 int chars_len;
4014 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4015 int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
4016 NULL);
4018 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
4021 enum xpm_color_key {
4022 XPM_COLOR_KEY_S,
4023 XPM_COLOR_KEY_M,
4024 XPM_COLOR_KEY_G4,
4025 XPM_COLOR_KEY_G,
4026 XPM_COLOR_KEY_C
4029 static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
4031 static int
4032 xpm_str_to_color_key (s)
4033 char *s;
4035 int i;
4037 for (i = 0;
4038 i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
4039 i++)
4040 if (strcmp (xpm_color_key_strings[i], s) == 0)
4041 return i;
4042 return -1;
4045 static int
4046 xpm_load_image (f, img, contents, end)
4047 struct frame *f;
4048 struct image *img;
4049 unsigned char *contents, *end;
4051 unsigned char *s = contents, *beg, *str;
4052 unsigned char buffer[BUFSIZ];
4053 int width, height, x, y;
4054 int num_colors, chars_per_pixel;
4055 int len, LA1;
4056 void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object);
4057 Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int);
4058 Lisp_Object frame, color_symbols, color_table;
4059 int best_key, have_mask = 0;
4060 XImagePtr ximg = NULL, mask_img = NULL;
4062 #define match() \
4063 LA1 = xpm_scan (&s, end, &beg, &len)
4065 #define expect(TOKEN) \
4066 if (LA1 != (TOKEN)) \
4067 goto failure; \
4068 else \
4069 match ()
4071 #define expect_ident(IDENT) \
4072 if (LA1 == XPM_TK_IDENT \
4073 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
4074 match (); \
4075 else \
4076 goto failure
4078 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
4079 goto failure;
4080 s += 9;
4081 match();
4082 expect_ident ("static");
4083 expect_ident ("char");
4084 expect ('*');
4085 expect (XPM_TK_IDENT);
4086 expect ('[');
4087 expect (']');
4088 expect ('=');
4089 expect ('{');
4090 expect (XPM_TK_STRING);
4091 if (len >= BUFSIZ)
4092 goto failure;
4093 memcpy (buffer, beg, len);
4094 buffer[len] = '\0';
4095 if (sscanf (buffer, "%d %d %d %d", &width, &height,
4096 &num_colors, &chars_per_pixel) != 4
4097 || width <= 0 || height <= 0
4098 || num_colors <= 0 || chars_per_pixel <= 0)
4099 goto failure;
4100 expect (',');
4102 XSETFRAME (frame, f);
4103 if (!NILP (Fxw_display_color_p (frame)))
4104 best_key = XPM_COLOR_KEY_C;
4105 else if (!NILP (Fx_display_grayscale_p (frame)))
4106 best_key = (XFASTINT (Fx_display_planes (frame)) > 2
4107 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
4108 else
4109 best_key = XPM_COLOR_KEY_M;
4111 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
4112 if (chars_per_pixel == 1)
4113 color_table = xpm_make_color_table_v (&put_color_table,
4114 &get_color_table);
4115 else
4116 color_table = xpm_make_color_table_h (&put_color_table,
4117 &get_color_table);
4119 while (num_colors-- > 0)
4121 unsigned char *color, *max_color;
4122 int key, next_key, max_key = 0;
4123 Lisp_Object symbol_color = Qnil, color_val;
4124 XColor cdef;
4126 expect (XPM_TK_STRING);
4127 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
4128 goto failure;
4129 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
4130 buffer[len - chars_per_pixel] = '\0';
4132 str = strtok (buffer, " \t");
4133 if (str == NULL)
4134 goto failure;
4135 key = xpm_str_to_color_key (str);
4136 if (key < 0)
4137 goto failure;
4140 color = strtok (NULL, " \t");
4141 if (color == NULL)
4142 goto failure;
4144 while (str = strtok (NULL, " \t"))
4146 next_key = xpm_str_to_color_key (str);
4147 if (next_key >= 0)
4148 break;
4149 color[strlen (color)] = ' ';
4152 if (key == XPM_COLOR_KEY_S)
4154 if (NILP (symbol_color))
4155 symbol_color = build_string (color);
4157 else if (max_key < key && key <= best_key)
4159 max_key = key;
4160 max_color = color;
4162 key = next_key;
4164 while (str);
4166 color_val = Qnil;
4167 if (!NILP (color_symbols) && !NILP (symbol_color))
4169 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
4171 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
4172 if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0)
4173 color_val = Qt;
4174 else if (x_defined_color (f, SDATA (XCDR (specified_color)),
4175 &cdef, 0))
4176 color_val = make_number (cdef.pixel);
4178 if (NILP (color_val) && max_key > 0)
4179 if (xstricmp (max_color, "None") == 0)
4180 color_val = Qt;
4181 else if (x_defined_color (f, max_color, &cdef, 0))
4182 color_val = make_number (cdef.pixel);
4183 if (!NILP (color_val))
4184 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
4186 expect (',');
4189 if (!x_create_x_image_and_pixmap (f, width, height, 0,
4190 &ximg, &img->pixmap)
4191 || !x_create_x_image_and_pixmap (f, width, height, 1,
4192 &mask_img, &img->mask))
4194 image_error ("Out of memory (%s)", img->spec, Qnil);
4195 goto error;
4198 for (y = 0; y < height; y++)
4200 expect (XPM_TK_STRING);
4201 str = beg;
4202 if (len < width * chars_per_pixel)
4203 goto failure;
4204 for (x = 0; x < width; x++, str += chars_per_pixel)
4206 Lisp_Object color_val =
4207 (*get_color_table) (color_table, str, chars_per_pixel);
4209 XPutPixel (ximg, x, y,
4210 (INTEGERP (color_val) ? XINT (color_val)
4211 : FRAME_FOREGROUND_PIXEL (f)));
4212 XPutPixel (mask_img, x, y,
4213 (!EQ (color_val, Qt) ? PIX_MASK_DRAW (f)
4214 : (have_mask = 1, PIX_MASK_RETAIN (f))));
4216 if (y + 1 < height)
4217 expect (',');
4220 img->width = width;
4221 img->height = height;
4223 x_put_x_image (f, ximg, img->pixmap, width, height);
4224 x_destroy_x_image (ximg);
4225 if (have_mask)
4227 x_put_x_image (f, mask_img, img->mask, width, height);
4228 x_destroy_x_image (mask_img);
4230 else
4232 x_destroy_x_image (mask_img);
4233 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4234 img->mask = NO_PIXMAP;
4237 return 1;
4239 failure:
4240 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
4241 error:
4242 x_destroy_x_image (ximg);
4243 x_destroy_x_image (mask_img);
4244 x_clear_image (f, img);
4245 return 0;
4247 #undef match
4248 #undef expect
4249 #undef expect_ident
4252 static int
4253 xpm_load (f, img)
4254 struct frame *f;
4255 struct image *img;
4257 int success_p = 0;
4258 Lisp_Object file_name;
4260 /* If IMG->spec specifies a file name, create a non-file spec from it. */
4261 file_name = image_spec_value (img->spec, QCfile, NULL);
4262 if (STRINGP (file_name))
4264 Lisp_Object file;
4265 unsigned char *contents;
4266 int size;
4267 struct gcpro gcpro1;
4269 file = x_find_image_file (file_name);
4270 GCPRO1 (file);
4271 if (!STRINGP (file))
4273 image_error ("Cannot find image file `%s'", file_name, Qnil);
4274 UNGCPRO;
4275 return 0;
4278 contents = slurp_file (SDATA (file), &size);
4279 if (contents == NULL)
4281 image_error ("Error loading XPM image `%s'", img->spec, Qnil);
4282 UNGCPRO;
4283 return 0;
4286 success_p = xpm_load_image (f, img, contents, contents + size);
4287 xfree (contents);
4288 UNGCPRO;
4290 else
4292 Lisp_Object data;
4294 data = image_spec_value (img->spec, QCdata, NULL);
4295 success_p = xpm_load_image (f, img, SDATA (data),
4296 SDATA (data) + SBYTES (data));
4299 return success_p;
4302 #endif /* MAC_OS */
4306 /***********************************************************************
4307 Color table
4308 ***********************************************************************/
4310 #ifdef COLOR_TABLE_SUPPORT
4312 /* An entry in the color table mapping an RGB color to a pixel color. */
4314 struct ct_color
4316 int r, g, b;
4317 unsigned long pixel;
4319 /* Next in color table collision list. */
4320 struct ct_color *next;
4323 /* The bucket vector size to use. Must be prime. */
4325 #define CT_SIZE 101
4327 /* Value is a hash of the RGB color given by R, G, and B. */
4329 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
4331 /* The color hash table. */
4333 struct ct_color **ct_table;
4335 /* Number of entries in the color table. */
4337 int ct_colors_allocated;
4339 /* Initialize the color table. */
4341 static void
4342 init_color_table ()
4344 int size = CT_SIZE * sizeof (*ct_table);
4345 ct_table = (struct ct_color **) xmalloc (size);
4346 bzero (ct_table, size);
4347 ct_colors_allocated = 0;
4351 /* Free memory associated with the color table. */
4353 static void
4354 free_color_table ()
4356 int i;
4357 struct ct_color *p, *next;
4359 for (i = 0; i < CT_SIZE; ++i)
4360 for (p = ct_table[i]; p; p = next)
4362 next = p->next;
4363 xfree (p);
4366 xfree (ct_table);
4367 ct_table = NULL;
4371 /* Value is a pixel color for RGB color R, G, B on frame F. If an
4372 entry for that color already is in the color table, return the
4373 pixel color of that entry. Otherwise, allocate a new color for R,
4374 G, B, and make an entry in the color table. */
4376 static unsigned long
4377 lookup_rgb_color (f, r, g, b)
4378 struct frame *f;
4379 int r, g, b;
4381 unsigned hash = CT_HASH_RGB (r, g, b);
4382 int i = hash % CT_SIZE;
4383 struct ct_color *p;
4384 Display_Info *dpyinfo;
4386 /* Handle TrueColor visuals specially, which improves performance by
4387 two orders of magnitude. Freeing colors on TrueColor visuals is
4388 a nop, and pixel colors specify RGB values directly. See also
4389 the Xlib spec, chapter 3.1. */
4390 dpyinfo = FRAME_X_DISPLAY_INFO (f);
4391 if (dpyinfo->red_bits > 0)
4393 unsigned long pr, pg, pb;
4395 /* Apply gamma-correction like normal color allocation does. */
4396 if (f->gamma)
4398 XColor color;
4399 color.red = r, color.green = g, color.blue = b;
4400 gamma_correct (f, &color);
4401 r = color.red, g = color.green, b = color.blue;
4404 /* Scale down RGB values to the visual's bits per RGB, and shift
4405 them to the right position in the pixel color. Note that the
4406 original RGB values are 16-bit values, as usual in X. */
4407 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
4408 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
4409 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
4411 /* Assemble the pixel color. */
4412 return pr | pg | pb;
4415 for (p = ct_table[i]; p; p = p->next)
4416 if (p->r == r && p->g == g && p->b == b)
4417 break;
4419 if (p == NULL)
4422 #ifdef HAVE_X_WINDOWS
4423 XColor color;
4424 Colormap cmap;
4425 int rc;
4427 color.red = r;
4428 color.green = g;
4429 color.blue = b;
4431 cmap = FRAME_X_COLORMAP (f);
4432 rc = x_alloc_nearest_color (f, cmap, &color);
4433 if (rc)
4435 ++ct_colors_allocated;
4436 p = (struct ct_color *) xmalloc (sizeof *p);
4437 p->r = r;
4438 p->g = g;
4439 p->b = b;
4440 p->pixel = color.pixel;
4441 p->next = ct_table[i];
4442 ct_table[i] = p;
4444 else
4445 return FRAME_FOREGROUND_PIXEL (f);
4447 #else
4448 COLORREF color;
4449 #ifdef HAVE_NTGUI
4450 color = PALETTERGB (r, g, b);
4451 #else
4452 color = RGB_TO_ULONG (r, g, b);
4453 #endif /* HAVE_NTGUI */
4454 ++ct_colors_allocated;
4455 p = (struct ct_color *) xmalloc (sizeof *p);
4456 p->r = r;
4457 p->g = g;
4458 p->b = b;
4459 p->pixel = color;
4460 p->next = ct_table[i];
4461 ct_table[i] = p;
4462 #endif /* HAVE_X_WINDOWS */
4466 return p->pixel;
4470 /* Look up pixel color PIXEL which is used on frame F in the color
4471 table. If not already present, allocate it. Value is PIXEL. */
4473 static unsigned long
4474 lookup_pixel_color (f, pixel)
4475 struct frame *f;
4476 unsigned long pixel;
4478 int i = pixel % CT_SIZE;
4479 struct ct_color *p;
4481 for (p = ct_table[i]; p; p = p->next)
4482 if (p->pixel == pixel)
4483 break;
4485 if (p == NULL)
4487 XColor color;
4488 Colormap cmap;
4489 int rc;
4491 #ifdef HAVE_X_WINDOWS
4492 cmap = FRAME_X_COLORMAP (f);
4493 color.pixel = pixel;
4494 x_query_color (f, &color);
4495 rc = x_alloc_nearest_color (f, cmap, &color);
4496 #else
4497 BLOCK_INPUT;
4498 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
4499 color.pixel = pixel;
4500 XQueryColor (NULL, cmap, &color);
4501 rc = x_alloc_nearest_color (f, cmap, &color);
4502 UNBLOCK_INPUT;
4503 #endif /* HAVE_X_WINDOWS */
4505 if (rc)
4507 ++ct_colors_allocated;
4509 p = (struct ct_color *) xmalloc (sizeof *p);
4510 p->r = color.red;
4511 p->g = color.green;
4512 p->b = color.blue;
4513 p->pixel = pixel;
4514 p->next = ct_table[i];
4515 ct_table[i] = p;
4517 else
4518 return FRAME_FOREGROUND_PIXEL (f);
4520 return p->pixel;
4524 /* Value is a vector of all pixel colors contained in the color table,
4525 allocated via xmalloc. Set *N to the number of colors. */
4527 static unsigned long *
4528 colors_in_color_table (n)
4529 int *n;
4531 int i, j;
4532 struct ct_color *p;
4533 unsigned long *colors;
4535 if (ct_colors_allocated == 0)
4537 *n = 0;
4538 colors = NULL;
4540 else
4542 colors = (unsigned long *) xmalloc (ct_colors_allocated
4543 * sizeof *colors);
4544 *n = ct_colors_allocated;
4546 for (i = j = 0; i < CT_SIZE; ++i)
4547 for (p = ct_table[i]; p; p = p->next)
4548 colors[j++] = p->pixel;
4551 return colors;
4554 #else /* COLOR_TABLE_SUPPORT */
4556 static unsigned long
4557 lookup_rgb_color (f, r, g, b)
4558 struct frame *f;
4559 int r, g, b;
4561 unsigned long pixel;
4563 #ifdef MAC_OS
4564 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4565 gamma_correct (f, &pixel);
4566 #endif /* MAC_OS */
4568 #ifdef HAVE_NTGUI
4569 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4570 #endif /* HAVE_NTGUI */
4572 return pixel;
4575 static void
4576 init_color_table ()
4579 #endif /* COLOR_TABLE_SUPPORT */
4582 /***********************************************************************
4583 Algorithms
4584 ***********************************************************************/
4586 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4587 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4588 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4590 #ifdef HAVE_NTGUI
4591 static void XPutPixel (XImagePtr , int, int, COLORREF);
4592 #endif /* HAVE_NTGUI */
4594 /* Non-zero means draw a cross on images having `:conversion
4595 disabled'. */
4597 int cross_disabled_images;
4599 /* Edge detection matrices for different edge-detection
4600 strategies. */
4602 static int emboss_matrix[9] = {
4603 /* x - 1 x x + 1 */
4604 2, -1, 0, /* y - 1 */
4605 -1, 0, 1, /* y */
4606 0, 1, -2 /* y + 1 */
4609 static int laplace_matrix[9] = {
4610 /* x - 1 x x + 1 */
4611 1, 0, 0, /* y - 1 */
4612 0, 0, 0, /* y */
4613 0, 0, -1 /* y + 1 */
4616 /* Value is the intensity of the color whose red/green/blue values
4617 are R, G, and B. */
4619 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4622 /* On frame F, return an array of XColor structures describing image
4623 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4624 non-zero means also fill the red/green/blue members of the XColor
4625 structures. Value is a pointer to the array of XColors structures,
4626 allocated with xmalloc; it must be freed by the caller. */
4628 static XColor *
4629 x_to_xcolors (f, img, rgb_p)
4630 struct frame *f;
4631 struct image *img;
4632 int rgb_p;
4634 int x, y;
4635 XColor *colors, *p;
4636 XImagePtr_or_DC ximg;
4637 #ifdef HAVE_NTGUI
4638 HDC hdc;
4639 HGDIOBJ prev;
4640 #endif /* HAVE_NTGUI */
4642 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4644 #ifndef HAVE_NTGUI
4645 /* Get the X image IMG->pixmap. */
4646 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4647 0, 0, img->width, img->height, ~0, ZPixmap);
4648 #else
4649 /* Load the image into a memory device context. */
4650 hdc = get_frame_dc (f);
4651 ximg = CreateCompatibleDC (hdc);
4652 release_frame_dc (f, hdc);
4653 prev = SelectObject (ximg, img->pixmap);
4654 #endif /* HAVE_NTGUI */
4656 /* Fill the `pixel' members of the XColor array. I wished there
4657 were an easy and portable way to circumvent XGetPixel. */
4658 p = colors;
4659 for (y = 0; y < img->height; ++y)
4661 XColor *row = p;
4663 #ifdef HAVE_X_WINDOWS
4664 for (x = 0; x < img->width; ++x, ++p)
4665 p->pixel = XGetPixel (ximg, x, y);
4666 if (rgb_p)
4667 x_query_colors (f, row, img->width);
4669 #else
4671 for (x = 0; x < img->width; ++x, ++p)
4673 /* W32_TODO: palette support needed here? */
4674 p->pixel = GET_PIXEL (ximg, x, y);
4675 if (rgb_p)
4677 #ifdef MAC_OS
4678 p->red = RED16_FROM_ULONG (p->pixel);
4679 p->green = GREEN16_FROM_ULONG (p->pixel);
4680 p->blue = BLUE16_FROM_ULONG (p->pixel);
4681 #endif /* MAC_OS */
4682 #ifdef HAVE_NTGUI
4683 p->red = 256 * GetRValue (p->pixel);
4684 p->green = 256 * GetGValue (p->pixel);
4685 p->blue = 256 * GetBValue (p->pixel);
4686 #endif /* HAVE_NTGUI */
4689 #endif /* HAVE_X_WINDOWS */
4692 Destroy_Image (ximg, prev);
4694 return colors;
4697 #ifdef HAVE_NTGUI
4699 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4700 created with CreateDIBSection, with the pointer to the bit values
4701 stored in ximg->data. */
4703 static void XPutPixel (ximg, x, y, color)
4704 XImagePtr ximg;
4705 int x, y;
4706 COLORREF color;
4708 int width = ximg->info.bmiHeader.biWidth;
4709 int height = ximg->info.bmiHeader.biHeight;
4710 unsigned char * pixel;
4712 /* True color images. */
4713 if (ximg->info.bmiHeader.biBitCount == 24)
4715 int rowbytes = width * 3;
4716 /* Ensure scanlines are aligned on 4 byte boundaries. */
4717 if (rowbytes % 4)
4718 rowbytes += 4 - (rowbytes % 4);
4720 pixel = ximg->data + y * rowbytes + x * 3;
4721 /* Windows bitmaps are in BGR order. */
4722 *pixel = GetBValue (color);
4723 *(pixel + 1) = GetGValue (color);
4724 *(pixel + 2) = GetRValue (color);
4726 /* Monochrome images. */
4727 else if (ximg->info.bmiHeader.biBitCount == 1)
4729 int rowbytes = width / 8;
4730 /* Ensure scanlines are aligned on 4 byte boundaries. */
4731 if (rowbytes % 4)
4732 rowbytes += 4 - (rowbytes % 4);
4733 pixel = ximg->data + y * rowbytes + x / 8;
4734 /* Filter out palette info. */
4735 if (color & 0x00ffffff)
4736 *pixel = *pixel | (1 << x % 8);
4737 else
4738 *pixel = *pixel & ~(1 << x % 8);
4740 else
4741 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4744 #endif /* HAVE_NTGUI */
4746 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
4747 RGB members are set. F is the frame on which this all happens.
4748 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4750 static void
4751 x_from_xcolors (f, img, colors)
4752 struct frame *f;
4753 struct image *img;
4754 XColor *colors;
4756 int x, y;
4757 XImagePtr oimg;
4758 Pixmap pixmap;
4759 XColor *p;
4761 init_color_table ();
4763 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4764 &oimg, &pixmap);
4765 p = colors;
4766 for (y = 0; y < img->height; ++y)
4767 for (x = 0; x < img->width; ++x, ++p)
4769 unsigned long pixel;
4770 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4771 XPutPixel (oimg, x, y, pixel);
4774 xfree (colors);
4775 x_clear_image_1 (f, img, 1, 0, 1);
4777 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4778 x_destroy_x_image (oimg);
4779 img->pixmap = pixmap;
4780 #ifdef COLOR_TABLE_SUPPORT
4781 img->colors = colors_in_color_table (&img->ncolors);
4782 free_color_table ();
4783 #endif /* COLOR_TABLE_SUPPORT */
4787 /* On frame F, perform edge-detection on image IMG.
4789 MATRIX is a nine-element array specifying the transformation
4790 matrix. See emboss_matrix for an example.
4792 COLOR_ADJUST is a color adjustment added to each pixel of the
4793 outgoing image. */
4795 static void
4796 x_detect_edges (f, img, matrix, color_adjust)
4797 struct frame *f;
4798 struct image *img;
4799 int matrix[9], color_adjust;
4801 XColor *colors = x_to_xcolors (f, img, 1);
4802 XColor *new, *p;
4803 int x, y, i, sum;
4805 for (i = sum = 0; i < 9; ++i)
4806 sum += abs (matrix[i]);
4808 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4810 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4812 for (y = 0; y < img->height; ++y)
4814 p = COLOR (new, 0, y);
4815 p->red = p->green = p->blue = 0xffff/2;
4816 p = COLOR (new, img->width - 1, y);
4817 p->red = p->green = p->blue = 0xffff/2;
4820 for (x = 1; x < img->width - 1; ++x)
4822 p = COLOR (new, x, 0);
4823 p->red = p->green = p->blue = 0xffff/2;
4824 p = COLOR (new, x, img->height - 1);
4825 p->red = p->green = p->blue = 0xffff/2;
4828 for (y = 1; y < img->height - 1; ++y)
4830 p = COLOR (new, 1, y);
4832 for (x = 1; x < img->width - 1; ++x, ++p)
4834 int r, g, b, y1, x1;
4836 r = g = b = i = 0;
4837 for (y1 = y - 1; y1 < y + 2; ++y1)
4838 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4839 if (matrix[i])
4841 XColor *t = COLOR (colors, x1, y1);
4842 r += matrix[i] * t->red;
4843 g += matrix[i] * t->green;
4844 b += matrix[i] * t->blue;
4847 r = (r / sum + color_adjust) & 0xffff;
4848 g = (g / sum + color_adjust) & 0xffff;
4849 b = (b / sum + color_adjust) & 0xffff;
4850 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4854 xfree (colors);
4855 x_from_xcolors (f, img, new);
4857 #undef COLOR
4861 /* Perform the pre-defined `emboss' edge-detection on image IMG
4862 on frame F. */
4864 static void
4865 x_emboss (f, img)
4866 struct frame *f;
4867 struct image *img;
4869 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4873 /* Transform image IMG which is used on frame F with a Laplace
4874 edge-detection algorithm. The result is an image that can be used
4875 to draw disabled buttons, for example. */
4877 static void
4878 x_laplace (f, img)
4879 struct frame *f;
4880 struct image *img;
4882 x_detect_edges (f, img, laplace_matrix, 45000);
4886 /* Perform edge-detection on image IMG on frame F, with specified
4887 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
4889 MATRIX must be either
4891 - a list of at least 9 numbers in row-major form
4892 - a vector of at least 9 numbers
4894 COLOR_ADJUST nil means use a default; otherwise it must be a
4895 number. */
4897 static void
4898 x_edge_detection (f, img, matrix, color_adjust)
4899 struct frame *f;
4900 struct image *img;
4901 Lisp_Object matrix, color_adjust;
4903 int i = 0;
4904 int trans[9];
4906 if (CONSP (matrix))
4908 for (i = 0;
4909 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
4910 ++i, matrix = XCDR (matrix))
4911 trans[i] = XFLOATINT (XCAR (matrix));
4913 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
4915 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
4916 trans[i] = XFLOATINT (AREF (matrix, i));
4919 if (NILP (color_adjust))
4920 color_adjust = make_number (0xffff / 2);
4922 if (i == 9 && NUMBERP (color_adjust))
4923 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
4927 /* Transform image IMG on frame F so that it looks disabled. */
4929 static void
4930 x_disable_image (f, img)
4931 struct frame *f;
4932 struct image *img;
4934 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4935 #ifdef HAVE_NTGUI
4936 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
4937 #else
4938 int n_planes = dpyinfo->n_planes;
4939 #endif /* HAVE_NTGUI */
4941 if (n_planes >= 2)
4943 /* Color (or grayscale). Convert to gray, and equalize. Just
4944 drawing such images with a stipple can look very odd, so
4945 we're using this method instead. */
4946 XColor *colors = x_to_xcolors (f, img, 1);
4947 XColor *p, *end;
4948 const int h = 15000;
4949 const int l = 30000;
4951 for (p = colors, end = colors + img->width * img->height;
4952 p < end;
4953 ++p)
4955 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
4956 int i2 = (0xffff - h - l) * i / 0xffff + l;
4957 p->red = p->green = p->blue = i2;
4960 x_from_xcolors (f, img, colors);
4963 /* Draw a cross over the disabled image, if we must or if we
4964 should. */
4965 if (n_planes < 2 || cross_disabled_images)
4967 #ifndef HAVE_NTGUI
4968 Display *dpy = FRAME_X_DISPLAY (f);
4969 GC gc;
4971 #ifdef MAC_OS
4972 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
4973 #define MaskForeground(f) PIX_MASK_DRAW (f)
4974 #else
4975 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
4976 #define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4977 #endif
4979 gc = XCreateGC_pixmap (dpy, img->pixmap);
4980 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
4981 XDrawLine (dpy, img->pixmap, gc, 0, 0,
4982 img->width - 1, img->height - 1);
4983 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
4984 img->width - 1, 0);
4985 XFreeGC (dpy, gc);
4987 if (img->mask)
4989 gc = XCreateGC_pixmap (dpy, img->mask);
4990 XSetForeground (dpy, gc, MaskForeground (f));
4991 XDrawLine (dpy, img->mask, gc, 0, 0,
4992 img->width - 1, img->height - 1);
4993 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
4994 img->width - 1, 0);
4995 XFreeGC (dpy, gc);
4997 #else
4998 HDC hdc, bmpdc;
4999 HGDIOBJ prev;
5001 hdc = get_frame_dc (f);
5002 bmpdc = CreateCompatibleDC (hdc);
5003 release_frame_dc (f, hdc);
5005 prev = SelectObject (bmpdc, img->pixmap);
5007 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
5008 MoveToEx (bmpdc, 0, 0, NULL);
5009 LineTo (bmpdc, img->width - 1, img->height - 1);
5010 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5011 LineTo (bmpdc, img->width - 1, 0);
5013 if (img->mask)
5015 SelectObject (bmpdc, img->mask);
5016 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
5017 MoveToEx (bmpdc, 0, 0, NULL);
5018 LineTo (bmpdc, img->width - 1, img->height - 1);
5019 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5020 LineTo (bmpdc, img->width - 1, 0);
5022 SelectObject (bmpdc, prev);
5023 DeleteDC (bmpdc);
5024 #endif /* HAVE_NTGUI */
5029 /* Build a mask for image IMG which is used on frame F. FILE is the
5030 name of an image file, for error messages. HOW determines how to
5031 determine the background color of IMG. If it is a list '(R G B)',
5032 with R, G, and B being integers >= 0, take that as the color of the
5033 background. Otherwise, determine the background color of IMG
5034 heuristically. Value is non-zero if successful. */
5036 static int
5037 x_build_heuristic_mask (f, img, how)
5038 struct frame *f;
5039 struct image *img;
5040 Lisp_Object how;
5042 XImagePtr_or_DC ximg;
5043 #ifndef HAVE_NTGUI
5044 XImagePtr mask_img;
5045 #else
5046 HDC frame_dc;
5047 HGDIOBJ prev;
5048 char *mask_img;
5049 int row_width;
5050 #endif /* HAVE_NTGUI */
5051 int x, y, rc, use_img_background;
5052 unsigned long bg = 0;
5054 if (img->mask)
5056 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
5057 img->mask = NO_PIXMAP;
5058 img->background_transparent_valid = 0;
5061 #ifndef HAVE_NTGUI
5062 /* Create an image and pixmap serving as mask. */
5063 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
5064 &mask_img, &img->mask);
5065 if (!rc)
5066 return 0;
5068 /* Get the X image of IMG->pixmap. */
5069 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
5070 img->width, img->height,
5071 ~0, ZPixmap);
5072 #else
5073 /* Create the bit array serving as mask. */
5074 row_width = (img->width + 7) / 8;
5075 mask_img = xmalloc (row_width * img->height);
5076 bzero (mask_img, row_width * img->height);
5078 /* Create a memory device context for IMG->pixmap. */
5079 frame_dc = get_frame_dc (f);
5080 ximg = CreateCompatibleDC (frame_dc);
5081 release_frame_dc (f, frame_dc);
5082 prev = SelectObject (ximg, img->pixmap);
5083 #endif /* HAVE_NTGUI */
5085 /* Determine the background color of ximg. If HOW is `(R G B)'
5086 take that as color. Otherwise, use the image's background color. */
5087 use_img_background = 1;
5089 if (CONSP (how))
5091 int rgb[3], i;
5093 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
5095 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
5096 how = XCDR (how);
5099 if (i == 3 && NILP (how))
5101 char color_name[30];
5102 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
5103 bg = (
5104 #ifdef HAVE_NTGUI
5105 0x00ffffff & /* Filter out palette info. */
5106 #endif /* HAVE_NTGUI */
5107 x_alloc_image_color (f, img, build_string (color_name), 0));
5108 use_img_background = 0;
5112 if (use_img_background)
5113 bg = four_corners_best (ximg, img->width, img->height);
5115 /* Set all bits in mask_img to 1 whose color in ximg is different
5116 from the background color bg. */
5117 #ifndef HAVE_NTGUI
5118 for (y = 0; y < img->height; ++y)
5119 for (x = 0; x < img->width; ++x)
5120 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
5121 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
5123 /* Fill in the background_transparent field while we have the mask handy. */
5124 image_background_transparent (img, f, mask_img);
5126 /* Put mask_img into img->mask. */
5127 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5128 x_destroy_x_image (mask_img);
5130 #else
5131 for (y = 0; y < img->height; ++y)
5132 for (x = 0; x < img->width; ++x)
5134 COLORREF p = GetPixel (ximg, x, y);
5135 if (p != bg)
5136 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
5139 /* Create the mask image. */
5140 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
5141 mask_img);
5142 /* Fill in the background_transparent field while we have the mask handy. */
5143 SelectObject (ximg, img->mask);
5144 image_background_transparent (img, f, ximg);
5146 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
5147 xfree (mask_img);
5148 #endif /* HAVE_NTGUI */
5150 Destroy_Image (ximg, prev);
5152 return 1;
5156 /***********************************************************************
5157 PBM (mono, gray, color)
5158 ***********************************************************************/
5160 static int pbm_image_p P_ ((Lisp_Object object));
5161 static int pbm_load P_ ((struct frame *f, struct image *img));
5162 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
5164 /* The symbol `pbm' identifying images of this type. */
5166 Lisp_Object Qpbm;
5168 /* Indices of image specification fields in gs_format, below. */
5170 enum pbm_keyword_index
5172 PBM_TYPE,
5173 PBM_FILE,
5174 PBM_DATA,
5175 PBM_ASCENT,
5176 PBM_MARGIN,
5177 PBM_RELIEF,
5178 PBM_ALGORITHM,
5179 PBM_HEURISTIC_MASK,
5180 PBM_MASK,
5181 PBM_FOREGROUND,
5182 PBM_BACKGROUND,
5183 PBM_LAST
5186 /* Vector of image_keyword structures describing the format
5187 of valid user-defined image specifications. */
5189 static struct image_keyword pbm_format[PBM_LAST] =
5191 {":type", IMAGE_SYMBOL_VALUE, 1},
5192 {":file", IMAGE_STRING_VALUE, 0},
5193 {":data", IMAGE_STRING_VALUE, 0},
5194 {":ascent", IMAGE_ASCENT_VALUE, 0},
5195 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5196 {":relief", IMAGE_INTEGER_VALUE, 0},
5197 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5198 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5199 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5200 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5201 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5204 /* Structure describing the image type `pbm'. */
5206 static struct image_type pbm_type =
5208 &Qpbm,
5209 pbm_image_p,
5210 pbm_load,
5211 x_clear_image,
5212 NULL
5216 /* Return non-zero if OBJECT is a valid PBM image specification. */
5218 static int
5219 pbm_image_p (object)
5220 Lisp_Object object;
5222 struct image_keyword fmt[PBM_LAST];
5224 bcopy (pbm_format, fmt, sizeof fmt);
5226 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
5227 return 0;
5229 /* Must specify either :data or :file. */
5230 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
5234 /* Scan a decimal number from *S and return it. Advance *S while
5235 reading the number. END is the end of the string. Value is -1 at
5236 end of input. */
5238 static int
5239 pbm_scan_number (s, end)
5240 unsigned char **s, *end;
5242 int c = 0, val = -1;
5244 while (*s < end)
5246 /* Skip white-space. */
5247 while (*s < end && (c = *(*s)++, isspace (c)))
5250 if (c == '#')
5252 /* Skip comment to end of line. */
5253 while (*s < end && (c = *(*s)++, c != '\n'))
5256 else if (isdigit (c))
5258 /* Read decimal number. */
5259 val = c - '0';
5260 while (*s < end && (c = *(*s)++, isdigit (c)))
5261 val = 10 * val + c - '0';
5262 break;
5264 else
5265 break;
5268 return val;
5272 #ifdef HAVE_NTGUI
5273 #if 0 /* Unused. ++kfs */
5275 /* Read FILE into memory. Value is a pointer to a buffer allocated
5276 with xmalloc holding FILE's contents. Value is null if an error
5277 occurred. *SIZE is set to the size of the file. */
5279 static char *
5280 pbm_read_file (file, size)
5281 Lisp_Object file;
5282 int *size;
5284 FILE *fp = NULL;
5285 char *buf = NULL;
5286 struct stat st;
5288 if (stat (SDATA (file), &st) == 0
5289 && (fp = fopen (SDATA (file), "rb")) != NULL
5290 && (buf = (char *) xmalloc (st.st_size),
5291 fread (buf, 1, st.st_size, fp) == st.st_size))
5293 *size = st.st_size;
5294 fclose (fp);
5296 else
5298 if (fp)
5299 fclose (fp);
5300 if (buf)
5302 xfree (buf);
5303 buf = NULL;
5307 return buf;
5309 #endif
5310 #endif /* HAVE_NTGUI */
5312 /* Load PBM image IMG for use on frame F. */
5314 static int
5315 pbm_load (f, img)
5316 struct frame *f;
5317 struct image *img;
5319 int raw_p, x, y;
5320 int width, height, max_color_idx = 0;
5321 XImagePtr ximg;
5322 Lisp_Object file, specified_file;
5323 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
5324 struct gcpro gcpro1;
5325 unsigned char *contents = NULL;
5326 unsigned char *end, *p;
5327 int size;
5329 specified_file = image_spec_value (img->spec, QCfile, NULL);
5330 file = Qnil;
5331 GCPRO1 (file);
5333 if (STRINGP (specified_file))
5335 file = x_find_image_file (specified_file);
5336 if (!STRINGP (file))
5338 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5339 UNGCPRO;
5340 return 0;
5343 contents = slurp_file (SDATA (file), &size);
5344 if (contents == NULL)
5346 image_error ("Error reading `%s'", file, Qnil);
5347 UNGCPRO;
5348 return 0;
5351 p = contents;
5352 end = contents + size;
5354 else
5356 Lisp_Object data;
5357 data = image_spec_value (img->spec, QCdata, NULL);
5358 p = SDATA (data);
5359 end = p + SBYTES (data);
5362 /* Check magic number. */
5363 if (end - p < 2 || *p++ != 'P')
5365 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5366 error:
5367 xfree (contents);
5368 UNGCPRO;
5369 return 0;
5372 switch (*p++)
5374 case '1':
5375 raw_p = 0, type = PBM_MONO;
5376 break;
5378 case '2':
5379 raw_p = 0, type = PBM_GRAY;
5380 break;
5382 case '3':
5383 raw_p = 0, type = PBM_COLOR;
5384 break;
5386 case '4':
5387 raw_p = 1, type = PBM_MONO;
5388 break;
5390 case '5':
5391 raw_p = 1, type = PBM_GRAY;
5392 break;
5394 case '6':
5395 raw_p = 1, type = PBM_COLOR;
5396 break;
5398 default:
5399 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5400 goto error;
5403 /* Read width, height, maximum color-component. Characters
5404 starting with `#' up to the end of a line are ignored. */
5405 width = pbm_scan_number (&p, end);
5406 height = pbm_scan_number (&p, end);
5408 if (type != PBM_MONO)
5410 max_color_idx = pbm_scan_number (&p, end);
5411 if (raw_p && max_color_idx > 255)
5412 max_color_idx = 255;
5415 if (width < 0
5416 || height < 0
5417 || (type != PBM_MONO && max_color_idx < 0))
5418 goto error;
5420 if (!x_create_x_image_and_pixmap (f, width, height, 0,
5421 &ximg, &img->pixmap))
5422 goto error;
5424 /* Initialize the color hash table. */
5425 init_color_table ();
5427 if (type == PBM_MONO)
5429 int c = 0, g;
5430 struct image_keyword fmt[PBM_LAST];
5431 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
5432 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
5434 /* Parse the image specification. */
5435 bcopy (pbm_format, fmt, sizeof fmt);
5436 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
5438 /* Get foreground and background colors, maybe allocate colors. */
5439 if (fmt[PBM_FOREGROUND].count
5440 && STRINGP (fmt[PBM_FOREGROUND].value))
5441 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
5442 if (fmt[PBM_BACKGROUND].count
5443 && STRINGP (fmt[PBM_BACKGROUND].value))
5445 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
5446 img->background = bg;
5447 img->background_valid = 1;
5450 for (y = 0; y < height; ++y)
5451 for (x = 0; x < width; ++x)
5453 if (raw_p)
5455 if ((x & 7) == 0)
5456 c = *p++;
5457 g = c & 0x80;
5458 c <<= 1;
5460 else
5461 g = pbm_scan_number (&p, end);
5463 XPutPixel (ximg, x, y, g ? fg : bg);
5466 else
5468 for (y = 0; y < height; ++y)
5469 for (x = 0; x < width; ++x)
5471 int r, g, b;
5473 if (type == PBM_GRAY)
5474 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
5475 else if (raw_p)
5477 r = *p++;
5478 g = *p++;
5479 b = *p++;
5481 else
5483 r = pbm_scan_number (&p, end);
5484 g = pbm_scan_number (&p, end);
5485 b = pbm_scan_number (&p, end);
5488 if (r < 0 || g < 0 || b < 0)
5490 x_destroy_x_image (ximg);
5491 image_error ("Invalid pixel value in image `%s'",
5492 img->spec, Qnil);
5493 goto error;
5496 /* RGB values are now in the range 0..max_color_idx.
5497 Scale this to the range 0..0xffff supported by X. */
5498 r = (double) r * 65535 / max_color_idx;
5499 g = (double) g * 65535 / max_color_idx;
5500 b = (double) b * 65535 / max_color_idx;
5501 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5505 #ifdef COLOR_TABLE_SUPPORT
5506 /* Store in IMG->colors the colors allocated for the image, and
5507 free the color table. */
5508 img->colors = colors_in_color_table (&img->ncolors);
5509 free_color_table ();
5510 #endif /* COLOR_TABLE_SUPPORT */
5512 img->width = width;
5513 img->height = height;
5515 /* Maybe fill in the background field while we have ximg handy. */
5517 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5518 IMAGE_BACKGROUND (img, f, ximg);
5520 /* Put the image into a pixmap. */
5521 x_put_x_image (f, ximg, img->pixmap, width, height);
5522 x_destroy_x_image (ximg);
5524 /* X and W32 versions did it here, MAC version above. ++kfs
5525 img->width = width;
5526 img->height = height; */
5528 UNGCPRO;
5529 xfree (contents);
5530 return 1;
5534 /***********************************************************************
5536 ***********************************************************************/
5538 #if defined (HAVE_PNG) || defined (MAC_OS)
5540 /* Function prototypes. */
5542 static int png_image_p P_ ((Lisp_Object object));
5543 static int png_load P_ ((struct frame *f, struct image *img));
5545 /* The symbol `png' identifying images of this type. */
5547 Lisp_Object Qpng;
5549 /* Indices of image specification fields in png_format, below. */
5551 enum png_keyword_index
5553 PNG_TYPE,
5554 PNG_DATA,
5555 PNG_FILE,
5556 PNG_ASCENT,
5557 PNG_MARGIN,
5558 PNG_RELIEF,
5559 PNG_ALGORITHM,
5560 PNG_HEURISTIC_MASK,
5561 PNG_MASK,
5562 PNG_BACKGROUND,
5563 PNG_LAST
5566 /* Vector of image_keyword structures describing the format
5567 of valid user-defined image specifications. */
5569 static struct image_keyword png_format[PNG_LAST] =
5571 {":type", IMAGE_SYMBOL_VALUE, 1},
5572 {":data", IMAGE_STRING_VALUE, 0},
5573 {":file", IMAGE_STRING_VALUE, 0},
5574 {":ascent", IMAGE_ASCENT_VALUE, 0},
5575 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5576 {":relief", IMAGE_INTEGER_VALUE, 0},
5577 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5578 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5579 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5580 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5583 /* Structure describing the image type `png'. */
5585 static struct image_type png_type =
5587 &Qpng,
5588 png_image_p,
5589 png_load,
5590 x_clear_image,
5591 NULL
5594 /* Return non-zero if OBJECT is a valid PNG image specification. */
5596 static int
5597 png_image_p (object)
5598 Lisp_Object object;
5600 struct image_keyword fmt[PNG_LAST];
5601 bcopy (png_format, fmt, sizeof fmt);
5603 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5604 return 0;
5606 /* Must specify either the :data or :file keyword. */
5607 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5610 #endif /* HAVE_PNG || MAC_OS */
5613 #ifdef HAVE_PNG
5615 #if defined HAVE_LIBPNG_PNG_H
5616 # include <libpng/png.h>
5617 #else
5618 # include <png.h>
5619 #endif
5621 #ifdef HAVE_NTGUI
5622 /* PNG library details. */
5624 DEF_IMGLIB_FN (png_get_io_ptr);
5625 DEF_IMGLIB_FN (png_check_sig);
5626 DEF_IMGLIB_FN (png_create_read_struct);
5627 DEF_IMGLIB_FN (png_create_info_struct);
5628 DEF_IMGLIB_FN (png_destroy_read_struct);
5629 DEF_IMGLIB_FN (png_set_read_fn);
5630 DEF_IMGLIB_FN (png_init_io);
5631 DEF_IMGLIB_FN (png_set_sig_bytes);
5632 DEF_IMGLIB_FN (png_read_info);
5633 DEF_IMGLIB_FN (png_get_IHDR);
5634 DEF_IMGLIB_FN (png_get_valid);
5635 DEF_IMGLIB_FN (png_set_strip_16);
5636 DEF_IMGLIB_FN (png_set_expand);
5637 DEF_IMGLIB_FN (png_set_gray_to_rgb);
5638 DEF_IMGLIB_FN (png_set_background);
5639 DEF_IMGLIB_FN (png_get_bKGD);
5640 DEF_IMGLIB_FN (png_read_update_info);
5641 DEF_IMGLIB_FN (png_get_channels);
5642 DEF_IMGLIB_FN (png_get_rowbytes);
5643 DEF_IMGLIB_FN (png_read_image);
5644 DEF_IMGLIB_FN (png_read_end);
5645 DEF_IMGLIB_FN (png_error);
5647 static int
5648 init_png_functions (Lisp_Object libraries)
5650 HMODULE library;
5652 /* Try loading libpng under probable names. */
5653 if (!(library = w32_delayed_load (libraries, Qpng)))
5654 return 0;
5656 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5657 LOAD_IMGLIB_FN (library, png_check_sig);
5658 LOAD_IMGLIB_FN (library, png_create_read_struct);
5659 LOAD_IMGLIB_FN (library, png_create_info_struct);
5660 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5661 LOAD_IMGLIB_FN (library, png_set_read_fn);
5662 LOAD_IMGLIB_FN (library, png_init_io);
5663 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5664 LOAD_IMGLIB_FN (library, png_read_info);
5665 LOAD_IMGLIB_FN (library, png_get_IHDR);
5666 LOAD_IMGLIB_FN (library, png_get_valid);
5667 LOAD_IMGLIB_FN (library, png_set_strip_16);
5668 LOAD_IMGLIB_FN (library, png_set_expand);
5669 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5670 LOAD_IMGLIB_FN (library, png_set_background);
5671 LOAD_IMGLIB_FN (library, png_get_bKGD);
5672 LOAD_IMGLIB_FN (library, png_read_update_info);
5673 LOAD_IMGLIB_FN (library, png_get_channels);
5674 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5675 LOAD_IMGLIB_FN (library, png_read_image);
5676 LOAD_IMGLIB_FN (library, png_read_end);
5677 LOAD_IMGLIB_FN (library, png_error);
5678 return 1;
5680 #else
5682 #define fn_png_get_io_ptr png_get_io_ptr
5683 #define fn_png_check_sig png_check_sig
5684 #define fn_png_create_read_struct png_create_read_struct
5685 #define fn_png_create_info_struct png_create_info_struct
5686 #define fn_png_destroy_read_struct png_destroy_read_struct
5687 #define fn_png_set_read_fn png_set_read_fn
5688 #define fn_png_init_io png_init_io
5689 #define fn_png_set_sig_bytes png_set_sig_bytes
5690 #define fn_png_read_info png_read_info
5691 #define fn_png_get_IHDR png_get_IHDR
5692 #define fn_png_get_valid png_get_valid
5693 #define fn_png_set_strip_16 png_set_strip_16
5694 #define fn_png_set_expand png_set_expand
5695 #define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5696 #define fn_png_set_background png_set_background
5697 #define fn_png_get_bKGD png_get_bKGD
5698 #define fn_png_read_update_info png_read_update_info
5699 #define fn_png_get_channels png_get_channels
5700 #define fn_png_get_rowbytes png_get_rowbytes
5701 #define fn_png_read_image png_read_image
5702 #define fn_png_read_end png_read_end
5703 #define fn_png_error png_error
5705 #endif /* HAVE_NTGUI */
5707 /* Error and warning handlers installed when the PNG library
5708 is initialized. */
5710 static void
5711 my_png_error (png_ptr, msg)
5712 png_struct *png_ptr;
5713 char *msg;
5715 xassert (png_ptr != NULL);
5716 image_error ("PNG error: %s", build_string (msg), Qnil);
5717 longjmp (png_ptr->jmpbuf, 1);
5721 static void
5722 my_png_warning (png_ptr, msg)
5723 png_struct *png_ptr;
5724 char *msg;
5726 xassert (png_ptr != NULL);
5727 image_error ("PNG warning: %s", build_string (msg), Qnil);
5730 /* Memory source for PNG decoding. */
5732 struct png_memory_storage
5734 unsigned char *bytes; /* The data */
5735 size_t len; /* How big is it? */
5736 int index; /* Where are we? */
5740 /* Function set as reader function when reading PNG image from memory.
5741 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5742 bytes from the input to DATA. */
5744 #ifdef _MSC_VER
5745 /* Work around a problem with MinGW builds of graphics libraries
5746 not honoring calling conventions. */
5747 #pragma optimize("g", off)
5748 #endif
5750 static void
5751 png_read_from_memory (png_ptr, data, length)
5752 png_structp png_ptr;
5753 png_bytep data;
5754 png_size_t length;
5756 struct png_memory_storage *tbr
5757 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5759 if (length > tbr->len - tbr->index)
5760 fn_png_error (png_ptr, "Read error");
5762 bcopy (tbr->bytes + tbr->index, data, length);
5763 tbr->index = tbr->index + length;
5766 #ifdef _MSC_VER
5767 /* Restore normal optimization, as specified on the command line. */
5768 #pragma optimize("", on)
5769 #endif
5771 /* Load PNG image IMG for use on frame F. Value is non-zero if
5772 successful. */
5774 static int
5775 png_load (f, img)
5776 struct frame *f;
5777 struct image *img;
5779 Lisp_Object file, specified_file;
5780 Lisp_Object specified_data;
5781 int x, y, i;
5782 XImagePtr ximg, mask_img = NULL;
5783 struct gcpro gcpro1;
5784 png_struct *png_ptr = NULL;
5785 png_info *info_ptr = NULL, *end_info = NULL;
5786 FILE *volatile fp = NULL;
5787 png_byte sig[8];
5788 png_byte * volatile pixels = NULL;
5789 png_byte ** volatile rows = NULL;
5790 png_uint_32 width, height;
5791 int bit_depth, color_type, interlace_type;
5792 png_byte channels;
5793 png_uint_32 row_bytes;
5794 int transparent_p;
5795 double screen_gamma;
5796 struct png_memory_storage tbr; /* Data to be read */
5798 /* Find out what file to load. */
5799 specified_file = image_spec_value (img->spec, QCfile, NULL);
5800 specified_data = image_spec_value (img->spec, QCdata, NULL);
5801 file = Qnil;
5802 GCPRO1 (file);
5804 if (NILP (specified_data))
5806 file = x_find_image_file (specified_file);
5807 if (!STRINGP (file))
5809 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5810 UNGCPRO;
5811 return 0;
5814 /* Open the image file. */
5815 fp = fopen (SDATA (file), "rb");
5816 if (!fp)
5818 image_error ("Cannot open image file `%s'", file, Qnil);
5819 UNGCPRO;
5820 fclose (fp);
5821 return 0;
5824 /* Check PNG signature. */
5825 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
5826 || !fn_png_check_sig (sig, sizeof sig))
5828 image_error ("Not a PNG file: `%s'", file, Qnil);
5829 UNGCPRO;
5830 fclose (fp);
5831 return 0;
5834 else
5836 /* Read from memory. */
5837 tbr.bytes = SDATA (specified_data);
5838 tbr.len = SBYTES (specified_data);
5839 tbr.index = 0;
5841 /* Check PNG signature. */
5842 if (tbr.len < sizeof sig
5843 || !fn_png_check_sig (tbr.bytes, sizeof sig))
5845 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5846 UNGCPRO;
5847 return 0;
5850 /* Need to skip past the signature. */
5851 tbr.bytes += sizeof (sig);
5854 /* Initialize read and info structs for PNG lib. */
5855 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
5856 my_png_error, my_png_warning);
5857 if (!png_ptr)
5859 if (fp) fclose (fp);
5860 UNGCPRO;
5861 return 0;
5864 info_ptr = fn_png_create_info_struct (png_ptr);
5865 if (!info_ptr)
5867 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
5868 if (fp) fclose (fp);
5869 UNGCPRO;
5870 return 0;
5873 end_info = fn_png_create_info_struct (png_ptr);
5874 if (!end_info)
5876 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
5877 if (fp) fclose (fp);
5878 UNGCPRO;
5879 return 0;
5882 /* Set error jump-back. We come back here when the PNG library
5883 detects an error. */
5884 if (setjmp (png_ptr->jmpbuf))
5886 error:
5887 if (png_ptr)
5888 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
5889 xfree (pixels);
5890 xfree (rows);
5891 if (fp) fclose (fp);
5892 UNGCPRO;
5893 return 0;
5896 /* Read image info. */
5897 if (!NILP (specified_data))
5898 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
5899 else
5900 fn_png_init_io (png_ptr, fp);
5902 fn_png_set_sig_bytes (png_ptr, sizeof sig);
5903 fn_png_read_info (png_ptr, info_ptr);
5904 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
5905 &interlace_type, NULL, NULL);
5907 /* If image contains simply transparency data, we prefer to
5908 construct a clipping mask. */
5909 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
5910 transparent_p = 1;
5911 else
5912 transparent_p = 0;
5914 /* This function is easier to write if we only have to handle
5915 one data format: RGB or RGBA with 8 bits per channel. Let's
5916 transform other formats into that format. */
5918 /* Strip more than 8 bits per channel. */
5919 if (bit_depth == 16)
5920 fn_png_set_strip_16 (png_ptr);
5922 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
5923 if available. */
5924 fn_png_set_expand (png_ptr);
5926 /* Convert grayscale images to RGB. */
5927 if (color_type == PNG_COLOR_TYPE_GRAY
5928 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
5929 fn_png_set_gray_to_rgb (png_ptr);
5931 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
5933 #if 0 /* Avoid double gamma correction for PNG images. */
5934 { /* Tell the PNG lib to handle gamma correction for us. */
5935 int intent;
5936 double image_gamma;
5937 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
5938 if (png_get_sRGB (png_ptr, info_ptr, &intent))
5939 /* The libpng documentation says this is right in this case. */
5940 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5941 else
5942 #endif
5943 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
5944 /* Image contains gamma information. */
5945 png_set_gamma (png_ptr, screen_gamma, image_gamma);
5946 else
5947 /* Use the standard default for the image gamma. */
5948 png_set_gamma (png_ptr, screen_gamma, 0.45455);
5950 #endif /* if 0 */
5952 /* Handle alpha channel by combining the image with a background
5953 color. Do this only if a real alpha channel is supplied. For
5954 simple transparency, we prefer a clipping mask. */
5955 if (!transparent_p)
5957 png_color_16 *image_bg;
5958 Lisp_Object specified_bg
5959 = image_spec_value (img->spec, QCbackground, NULL);
5961 if (STRINGP (specified_bg))
5962 /* The user specified `:background', use that. */
5964 /* W32 version incorrectly used COLORREF here!! ++kfs */
5965 XColor color;
5966 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
5968 png_color_16 user_bg;
5970 bzero (&user_bg, sizeof user_bg);
5971 user_bg.red = color.red >> 8;
5972 user_bg.green = color.green >> 8;
5973 user_bg.blue = color.blue >> 8;
5975 fn_png_set_background (png_ptr, &user_bg,
5976 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
5979 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
5980 /* Image contains a background color with which to
5981 combine the image. */
5982 fn_png_set_background (png_ptr, image_bg,
5983 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
5984 else
5986 /* Image does not contain a background color with which
5987 to combine the image data via an alpha channel. Use
5988 the frame's background instead. */
5989 #ifdef HAVE_X_WINDOWS
5990 XColor color;
5991 png_color_16 frame_background;
5993 color.pixel = FRAME_BACKGROUND_PIXEL (f);
5994 x_query_color (f, &color);
5996 bzero (&frame_background, sizeof frame_background);
5997 frame_background.red = color.red >> 8;
5998 frame_background.green = color.green >> 8;
5999 frame_background.blue = color.blue >> 8;
6000 #endif /* HAVE_X_WINDOWS */
6002 #ifdef HAVE_NTGUI
6003 COLORREF color;
6004 png_color_16 frame_background;
6005 color = FRAME_BACKGROUND_PIXEL (f);
6006 #if 0 /* W32 TODO : Colormap support. */
6007 x_query_color (f, &color);
6008 #endif
6009 bzero (&frame_background, sizeof frame_background);
6010 frame_background.red = GetRValue (color);
6011 frame_background.green = GetGValue (color);
6012 frame_background.blue = GetBValue (color);
6013 #endif /* HAVE_NTGUI */
6015 #ifdef MAC_OS
6016 unsigned long color;
6017 png_color_16 frame_background;
6018 color = FRAME_BACKGROUND_PIXEL (f);
6019 #if 0 /* MAC/W32 TODO : Colormap support. */
6020 x_query_color (f, &color);
6021 #endif
6022 bzero (&frame_background, sizeof frame_background);
6023 frame_background.red = RED_FROM_ULONG (color);
6024 frame_background.green = GREEN_FROM_ULONG (color);
6025 frame_background.blue = BLUE_FROM_ULONG (color);
6026 #endif /* MAC_OS */
6028 fn_png_set_background (png_ptr, &frame_background,
6029 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6033 /* Update info structure. */
6034 fn_png_read_update_info (png_ptr, info_ptr);
6036 /* Get number of channels. Valid values are 1 for grayscale images
6037 and images with a palette, 2 for grayscale images with transparency
6038 information (alpha channel), 3 for RGB images, and 4 for RGB
6039 images with alpha channel, i.e. RGBA. If conversions above were
6040 sufficient we should only have 3 or 4 channels here. */
6041 channels = fn_png_get_channels (png_ptr, info_ptr);
6042 xassert (channels == 3 || channels == 4);
6044 /* Number of bytes needed for one row of the image. */
6045 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6047 /* Allocate memory for the image. */
6048 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
6049 rows = (png_byte **) xmalloc (height * sizeof *rows);
6050 for (i = 0; i < height; ++i)
6051 rows[i] = pixels + i * row_bytes;
6053 /* Read the entire image. */
6054 fn_png_read_image (png_ptr, rows);
6055 fn_png_read_end (png_ptr, info_ptr);
6056 if (fp)
6058 fclose (fp);
6059 fp = NULL;
6062 /* Create the X image and pixmap. */
6063 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
6064 &img->pixmap))
6065 goto error;
6067 /* Create an image and pixmap serving as mask if the PNG image
6068 contains an alpha channel. */
6069 if (channels == 4
6070 && !transparent_p
6071 && !x_create_x_image_and_pixmap (f, width, height, 1,
6072 &mask_img, &img->mask))
6074 x_destroy_x_image (ximg);
6075 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
6076 img->pixmap = NO_PIXMAP;
6077 goto error;
6080 /* Fill the X image and mask from PNG data. */
6081 init_color_table ();
6083 for (y = 0; y < height; ++y)
6085 png_byte *p = rows[y];
6087 for (x = 0; x < width; ++x)
6089 unsigned r, g, b;
6091 r = *p++ << 8;
6092 g = *p++ << 8;
6093 b = *p++ << 8;
6094 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6095 /* An alpha channel, aka mask channel, associates variable
6096 transparency with an image. Where other image formats
6097 support binary transparency---fully transparent or fully
6098 opaque---PNG allows up to 254 levels of partial transparency.
6099 The PNG library implements partial transparency by combining
6100 the image with a specified background color.
6102 I'm not sure how to handle this here nicely: because the
6103 background on which the image is displayed may change, for
6104 real alpha channel support, it would be necessary to create
6105 a new image for each possible background.
6107 What I'm doing now is that a mask is created if we have
6108 boolean transparency information. Otherwise I'm using
6109 the frame's background color to combine the image with. */
6111 if (channels == 4)
6113 if (mask_img)
6114 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
6115 ++p;
6120 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6121 /* Set IMG's background color from the PNG image, unless the user
6122 overrode it. */
6124 png_color_16 *bg;
6125 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
6127 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
6128 img->background_valid = 1;
6132 #ifdef COLOR_TABLE_SUPPORT
6133 /* Remember colors allocated for this image. */
6134 img->colors = colors_in_color_table (&img->ncolors);
6135 free_color_table ();
6136 #endif /* COLOR_TABLE_SUPPORT */
6138 /* Clean up. */
6139 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6140 xfree (rows);
6141 xfree (pixels);
6143 img->width = width;
6144 img->height = height;
6146 /* Maybe fill in the background field while we have ximg handy. */
6147 IMAGE_BACKGROUND (img, f, ximg);
6149 /* Put the image into the pixmap, then free the X image and its buffer. */
6150 x_put_x_image (f, ximg, img->pixmap, width, height);
6151 x_destroy_x_image (ximg);
6153 /* Same for the mask. */
6154 if (mask_img)
6156 /* Fill in the background_transparent field while we have the mask
6157 handy. */
6158 image_background_transparent (img, f, mask_img);
6160 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6161 x_destroy_x_image (mask_img);
6164 UNGCPRO;
6165 return 1;
6168 #else /* HAVE_PNG */
6170 #ifdef MAC_OS
6171 static int
6172 png_load (f, img)
6173 struct frame *f;
6174 struct image *img;
6176 #ifdef MAC_OSX
6177 if (MyCGImageCreateWithPNGDataProvider)
6178 return image_load_quartz2d (f, img, 1);
6179 else
6180 #endif
6181 return image_load_quicktime (f, img, kQTFileTypePNG);
6183 #endif /* MAC_OS */
6185 #endif /* !HAVE_PNG */
6189 /***********************************************************************
6190 JPEG
6191 ***********************************************************************/
6193 #if defined (HAVE_JPEG) || defined (MAC_OS)
6195 static int jpeg_image_p P_ ((Lisp_Object object));
6196 static int jpeg_load P_ ((struct frame *f, struct image *img));
6198 /* The symbol `jpeg' identifying images of this type. */
6200 Lisp_Object Qjpeg;
6202 /* Indices of image specification fields in gs_format, below. */
6204 enum jpeg_keyword_index
6206 JPEG_TYPE,
6207 JPEG_DATA,
6208 JPEG_FILE,
6209 JPEG_ASCENT,
6210 JPEG_MARGIN,
6211 JPEG_RELIEF,
6212 JPEG_ALGORITHM,
6213 JPEG_HEURISTIC_MASK,
6214 JPEG_MASK,
6215 JPEG_BACKGROUND,
6216 JPEG_LAST
6219 /* Vector of image_keyword structures describing the format
6220 of valid user-defined image specifications. */
6222 static struct image_keyword jpeg_format[JPEG_LAST] =
6224 {":type", IMAGE_SYMBOL_VALUE, 1},
6225 {":data", IMAGE_STRING_VALUE, 0},
6226 {":file", IMAGE_STRING_VALUE, 0},
6227 {":ascent", IMAGE_ASCENT_VALUE, 0},
6228 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6229 {":relief", IMAGE_INTEGER_VALUE, 0},
6230 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6231 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6232 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6233 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6236 /* Structure describing the image type `jpeg'. */
6238 static struct image_type jpeg_type =
6240 &Qjpeg,
6241 jpeg_image_p,
6242 jpeg_load,
6243 x_clear_image,
6244 NULL
6247 /* Return non-zero if OBJECT is a valid JPEG image specification. */
6249 static int
6250 jpeg_image_p (object)
6251 Lisp_Object object;
6253 struct image_keyword fmt[JPEG_LAST];
6255 bcopy (jpeg_format, fmt, sizeof fmt);
6257 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6258 return 0;
6260 /* Must specify either the :data or :file keyword. */
6261 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
6264 #endif /* HAVE_JPEG || MAC_OS */
6266 #ifdef HAVE_JPEG
6268 /* Work around a warning about HAVE_STDLIB_H being redefined in
6269 jconfig.h. */
6270 #ifdef HAVE_STDLIB_H
6271 #define HAVE_STDLIB_H_1
6272 #undef HAVE_STDLIB_H
6273 #endif /* HAVE_STLIB_H */
6275 #if defined (HAVE_NTGUI) && !defined (__WIN32__)
6276 /* jpeglib.h will define boolean differently depending on __WIN32__,
6277 so make sure it is defined. */
6278 #define __WIN32__ 1
6279 #endif
6281 #include <jpeglib.h>
6282 #include <jerror.h>
6283 #include <setjmp.h>
6285 #ifdef HAVE_STLIB_H_1
6286 #define HAVE_STDLIB_H 1
6287 #endif
6289 #ifdef HAVE_NTGUI
6291 /* JPEG library details. */
6292 DEF_IMGLIB_FN (jpeg_CreateDecompress);
6293 DEF_IMGLIB_FN (jpeg_start_decompress);
6294 DEF_IMGLIB_FN (jpeg_finish_decompress);
6295 DEF_IMGLIB_FN (jpeg_destroy_decompress);
6296 DEF_IMGLIB_FN (jpeg_read_header);
6297 DEF_IMGLIB_FN (jpeg_read_scanlines);
6298 DEF_IMGLIB_FN (jpeg_stdio_src);
6299 DEF_IMGLIB_FN (jpeg_std_error);
6300 DEF_IMGLIB_FN (jpeg_resync_to_restart);
6302 static int
6303 init_jpeg_functions (Lisp_Object libraries)
6305 HMODULE library;
6307 if (!(library = w32_delayed_load (libraries, Qjpeg)))
6308 return 0;
6310 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
6311 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
6312 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
6313 LOAD_IMGLIB_FN (library, jpeg_read_header);
6314 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
6315 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
6316 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
6317 LOAD_IMGLIB_FN (library, jpeg_std_error);
6318 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
6319 return 1;
6322 /* Wrapper since we can't directly assign the function pointer
6323 to another function pointer that was declared more completely easily. */
6324 static boolean
6325 jpeg_resync_to_restart_wrapper(cinfo, desired)
6326 j_decompress_ptr cinfo;
6327 int desired;
6329 return fn_jpeg_resync_to_restart (cinfo, desired);
6332 #else
6334 #define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
6335 #define fn_jpeg_start_decompress jpeg_start_decompress
6336 #define fn_jpeg_finish_decompress jpeg_finish_decompress
6337 #define fn_jpeg_destroy_decompress jpeg_destroy_decompress
6338 #define fn_jpeg_read_header jpeg_read_header
6339 #define fn_jpeg_read_scanlines jpeg_read_scanlines
6340 #define fn_jpeg_stdio_src jpeg_stdio_src
6341 #define fn_jpeg_std_error jpeg_std_error
6342 #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
6344 #endif /* HAVE_NTGUI */
6346 struct my_jpeg_error_mgr
6348 struct jpeg_error_mgr pub;
6349 jmp_buf setjmp_buffer;
6353 static void
6354 my_error_exit (cinfo)
6355 j_common_ptr cinfo;
6357 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
6358 longjmp (mgr->setjmp_buffer, 1);
6362 /* Init source method for JPEG data source manager. Called by
6363 jpeg_read_header() before any data is actually read. See
6364 libjpeg.doc from the JPEG lib distribution. */
6366 static void
6367 our_init_source (cinfo)
6368 j_decompress_ptr cinfo;
6373 /* Fill input buffer method for JPEG data source manager. Called
6374 whenever more data is needed. We read the whole image in one step,
6375 so this only adds a fake end of input marker at the end. */
6377 static boolean
6378 our_fill_input_buffer (cinfo)
6379 j_decompress_ptr cinfo;
6381 /* Insert a fake EOI marker. */
6382 struct jpeg_source_mgr *src = cinfo->src;
6383 static JOCTET buffer[2];
6385 buffer[0] = (JOCTET) 0xFF;
6386 buffer[1] = (JOCTET) JPEG_EOI;
6388 src->next_input_byte = buffer;
6389 src->bytes_in_buffer = 2;
6390 return 1;
6394 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6395 is the JPEG data source manager. */
6397 static void
6398 our_skip_input_data (cinfo, num_bytes)
6399 j_decompress_ptr cinfo;
6400 long num_bytes;
6402 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
6404 if (src)
6406 if (num_bytes > src->bytes_in_buffer)
6407 ERREXIT (cinfo, JERR_INPUT_EOF);
6409 src->bytes_in_buffer -= num_bytes;
6410 src->next_input_byte += num_bytes;
6415 /* Method to terminate data source. Called by
6416 jpeg_finish_decompress() after all data has been processed. */
6418 static void
6419 our_term_source (cinfo)
6420 j_decompress_ptr cinfo;
6425 /* Set up the JPEG lib for reading an image from DATA which contains
6426 LEN bytes. CINFO is the decompression info structure created for
6427 reading the image. */
6429 static void
6430 jpeg_memory_src (cinfo, data, len)
6431 j_decompress_ptr cinfo;
6432 JOCTET *data;
6433 unsigned int len;
6435 struct jpeg_source_mgr *src;
6437 if (cinfo->src == NULL)
6439 /* First time for this JPEG object? */
6440 cinfo->src = (struct jpeg_source_mgr *)
6441 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6442 sizeof (struct jpeg_source_mgr));
6443 src = (struct jpeg_source_mgr *) cinfo->src;
6444 src->next_input_byte = data;
6447 src = (struct jpeg_source_mgr *) cinfo->src;
6448 src->init_source = our_init_source;
6449 src->fill_input_buffer = our_fill_input_buffer;
6450 src->skip_input_data = our_skip_input_data;
6451 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6452 src->term_source = our_term_source;
6453 src->bytes_in_buffer = len;
6454 src->next_input_byte = data;
6458 /* Load image IMG for use on frame F. Patterned after example.c
6459 from the JPEG lib. */
6461 static int
6462 jpeg_load (f, img)
6463 struct frame *f;
6464 struct image *img;
6466 struct jpeg_decompress_struct cinfo;
6467 struct my_jpeg_error_mgr mgr;
6468 Lisp_Object file, specified_file;
6469 Lisp_Object specified_data;
6470 FILE * volatile fp = NULL;
6471 JSAMPARRAY buffer;
6472 int row_stride, x, y;
6473 XImagePtr ximg = NULL;
6474 int rc;
6475 unsigned long *colors;
6476 int width, height;
6477 struct gcpro gcpro1;
6479 /* Open the JPEG file. */
6480 specified_file = image_spec_value (img->spec, QCfile, NULL);
6481 specified_data = image_spec_value (img->spec, QCdata, NULL);
6482 file = Qnil;
6483 GCPRO1 (file);
6485 if (NILP (specified_data))
6487 file = x_find_image_file (specified_file);
6488 if (!STRINGP (file))
6490 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6491 UNGCPRO;
6492 return 0;
6495 fp = fopen (SDATA (file), "rb");
6496 if (fp == NULL)
6498 image_error ("Cannot open `%s'", file, Qnil);
6499 UNGCPRO;
6500 return 0;
6504 /* Customize libjpeg's error handling to call my_error_exit when an
6505 error is detected. This function will perform a longjmp. */
6506 cinfo.err = fn_jpeg_std_error (&mgr.pub);
6507 mgr.pub.error_exit = my_error_exit;
6509 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
6511 if (rc == 1)
6513 /* Called from my_error_exit. Display a JPEG error. */
6514 char buffer[JMSG_LENGTH_MAX];
6515 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
6516 image_error ("Error reading JPEG image `%s': %s", img->spec,
6517 build_string (buffer));
6520 /* Close the input file and destroy the JPEG object. */
6521 if (fp)
6522 fclose ((FILE *) fp);
6523 fn_jpeg_destroy_decompress (&cinfo);
6525 /* If we already have an XImage, free that. */
6526 x_destroy_x_image (ximg);
6528 /* Free pixmap and colors. */
6529 x_clear_image (f, img);
6531 UNGCPRO;
6532 return 0;
6535 /* Create the JPEG decompression object. Let it read from fp.
6536 Read the JPEG image header. */
6537 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6539 if (NILP (specified_data))
6540 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
6541 else
6542 jpeg_memory_src (&cinfo, SDATA (specified_data),
6543 SBYTES (specified_data));
6545 fn_jpeg_read_header (&cinfo, 1);
6547 /* Customize decompression so that color quantization will be used.
6548 Start decompression. */
6549 cinfo.quantize_colors = 1;
6550 fn_jpeg_start_decompress (&cinfo);
6551 width = img->width = cinfo.output_width;
6552 height = img->height = cinfo.output_height;
6554 /* Create X image and pixmap. */
6555 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6556 longjmp (mgr.setjmp_buffer, 2);
6558 /* Allocate colors. When color quantization is used,
6559 cinfo.actual_number_of_colors has been set with the number of
6560 colors generated, and cinfo.colormap is a two-dimensional array
6561 of color indices in the range 0..cinfo.actual_number_of_colors.
6562 No more than 255 colors will be generated. */
6564 int i, ir, ig, ib;
6566 if (cinfo.out_color_components > 2)
6567 ir = 0, ig = 1, ib = 2;
6568 else if (cinfo.out_color_components > 1)
6569 ir = 0, ig = 1, ib = 0;
6570 else
6571 ir = 0, ig = 0, ib = 0;
6573 /* Use the color table mechanism because it handles colors that
6574 cannot be allocated nicely. Such colors will be replaced with
6575 a default color, and we don't have to care about which colors
6576 can be freed safely, and which can't. */
6577 init_color_table ();
6578 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6579 * sizeof *colors);
6581 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6583 /* Multiply RGB values with 255 because X expects RGB values
6584 in the range 0..0xffff. */
6585 int r = cinfo.colormap[ir][i] << 8;
6586 int g = cinfo.colormap[ig][i] << 8;
6587 int b = cinfo.colormap[ib][i] << 8;
6588 colors[i] = lookup_rgb_color (f, r, g, b);
6591 #ifdef COLOR_TABLE_SUPPORT
6592 /* Remember those colors actually allocated. */
6593 img->colors = colors_in_color_table (&img->ncolors);
6594 free_color_table ();
6595 #endif /* COLOR_TABLE_SUPPORT */
6598 /* Read pixels. */
6599 row_stride = width * cinfo.output_components;
6600 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6601 row_stride, 1);
6602 for (y = 0; y < height; ++y)
6604 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6605 for (x = 0; x < cinfo.output_width; ++x)
6606 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6609 /* Clean up. */
6610 fn_jpeg_finish_decompress (&cinfo);
6611 fn_jpeg_destroy_decompress (&cinfo);
6612 if (fp)
6613 fclose ((FILE *) fp);
6615 /* Maybe fill in the background field while we have ximg handy. */
6616 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6617 IMAGE_BACKGROUND (img, f, ximg);
6619 /* Put the image into the pixmap. */
6620 x_put_x_image (f, ximg, img->pixmap, width, height);
6621 x_destroy_x_image (ximg);
6622 UNGCPRO;
6623 return 1;
6626 #else /* HAVE_JPEG */
6628 #ifdef MAC_OS
6629 static int
6630 jpeg_load (f, img)
6631 struct frame *f;
6632 struct image *img;
6634 #ifdef MAC_OSX
6635 return image_load_quartz2d (f, img, 0);
6636 #else
6637 return image_load_quicktime (f, img, kQTFileTypeJPEG);
6638 #endif
6640 #endif /* MAC_OS */
6642 #endif /* !HAVE_JPEG */
6646 /***********************************************************************
6647 TIFF
6648 ***********************************************************************/
6650 #if defined (HAVE_TIFF) || defined (MAC_OS)
6652 static int tiff_image_p P_ ((Lisp_Object object));
6653 static int tiff_load P_ ((struct frame *f, struct image *img));
6655 /* The symbol `tiff' identifying images of this type. */
6657 Lisp_Object Qtiff;
6659 /* Indices of image specification fields in tiff_format, below. */
6661 enum tiff_keyword_index
6663 TIFF_TYPE,
6664 TIFF_DATA,
6665 TIFF_FILE,
6666 TIFF_ASCENT,
6667 TIFF_MARGIN,
6668 TIFF_RELIEF,
6669 TIFF_ALGORITHM,
6670 TIFF_HEURISTIC_MASK,
6671 TIFF_MASK,
6672 TIFF_BACKGROUND,
6673 TIFF_LAST
6676 /* Vector of image_keyword structures describing the format
6677 of valid user-defined image specifications. */
6679 static struct image_keyword tiff_format[TIFF_LAST] =
6681 {":type", IMAGE_SYMBOL_VALUE, 1},
6682 {":data", IMAGE_STRING_VALUE, 0},
6683 {":file", IMAGE_STRING_VALUE, 0},
6684 {":ascent", IMAGE_ASCENT_VALUE, 0},
6685 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6686 {":relief", IMAGE_INTEGER_VALUE, 0},
6687 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6688 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6689 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6690 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6693 /* Structure describing the image type `tiff'. */
6695 static struct image_type tiff_type =
6697 &Qtiff,
6698 tiff_image_p,
6699 tiff_load,
6700 x_clear_image,
6701 NULL
6704 /* Return non-zero if OBJECT is a valid TIFF image specification. */
6706 static int
6707 tiff_image_p (object)
6708 Lisp_Object object;
6710 struct image_keyword fmt[TIFF_LAST];
6711 bcopy (tiff_format, fmt, sizeof fmt);
6713 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6714 return 0;
6716 /* Must specify either the :data or :file keyword. */
6717 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6720 #endif /* HAVE_TIFF || MAC_OS */
6722 #ifdef HAVE_TIFF
6724 #include <tiffio.h>
6726 #ifdef HAVE_NTGUI
6728 /* TIFF library details. */
6729 DEF_IMGLIB_FN (TIFFSetErrorHandler);
6730 DEF_IMGLIB_FN (TIFFSetWarningHandler);
6731 DEF_IMGLIB_FN (TIFFOpen);
6732 DEF_IMGLIB_FN (TIFFClientOpen);
6733 DEF_IMGLIB_FN (TIFFGetField);
6734 DEF_IMGLIB_FN (TIFFReadRGBAImage);
6735 DEF_IMGLIB_FN (TIFFClose);
6737 static int
6738 init_tiff_functions (Lisp_Object libraries)
6740 HMODULE library;
6742 if (!(library = w32_delayed_load (libraries, Qtiff)))
6743 return 0;
6745 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6746 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6747 LOAD_IMGLIB_FN (library, TIFFOpen);
6748 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6749 LOAD_IMGLIB_FN (library, TIFFGetField);
6750 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
6751 LOAD_IMGLIB_FN (library, TIFFClose);
6752 return 1;
6755 #else
6757 #define fn_TIFFSetErrorHandler TIFFSetErrorHandler
6758 #define fn_TIFFSetWarningHandler TIFFSetWarningHandler
6759 #define fn_TIFFOpen TIFFOpen
6760 #define fn_TIFFClientOpen TIFFClientOpen
6761 #define fn_TIFFGetField TIFFGetField
6762 #define fn_TIFFReadRGBAImage TIFFReadRGBAImage
6763 #define fn_TIFFClose TIFFClose
6765 #endif /* HAVE_NTGUI */
6768 /* Reading from a memory buffer for TIFF images Based on the PNG
6769 memory source, but we have to provide a lot of extra functions.
6770 Blah.
6772 We really only need to implement read and seek, but I am not
6773 convinced that the TIFF library is smart enough not to destroy
6774 itself if we only hand it the function pointers we need to
6775 override. */
6777 typedef struct
6779 unsigned char *bytes;
6780 size_t len;
6781 int index;
6783 tiff_memory_source;
6785 static size_t
6786 tiff_read_from_memory (data, buf, size)
6787 thandle_t data;
6788 tdata_t buf;
6789 tsize_t size;
6791 tiff_memory_source *src = (tiff_memory_source *) data;
6793 if (size > src->len - src->index)
6794 return (size_t) -1;
6795 bcopy (src->bytes + src->index, buf, size);
6796 src->index += size;
6797 return size;
6800 static size_t
6801 tiff_write_from_memory (data, buf, size)
6802 thandle_t data;
6803 tdata_t buf;
6804 tsize_t size;
6806 return (size_t) -1;
6809 static toff_t
6810 tiff_seek_in_memory (data, off, whence)
6811 thandle_t data;
6812 toff_t off;
6813 int whence;
6815 tiff_memory_source *src = (tiff_memory_source *) data;
6816 int idx;
6818 switch (whence)
6820 case SEEK_SET: /* Go from beginning of source. */
6821 idx = off;
6822 break;
6824 case SEEK_END: /* Go from end of source. */
6825 idx = src->len + off;
6826 break;
6828 case SEEK_CUR: /* Go from current position. */
6829 idx = src->index + off;
6830 break;
6832 default: /* Invalid `whence'. */
6833 return -1;
6836 if (idx > src->len || idx < 0)
6837 return -1;
6839 src->index = idx;
6840 return src->index;
6843 static int
6844 tiff_close_memory (data)
6845 thandle_t data;
6847 /* NOOP */
6848 return 0;
6851 static int
6852 tiff_mmap_memory (data, pbase, psize)
6853 thandle_t data;
6854 tdata_t *pbase;
6855 toff_t *psize;
6857 /* It is already _IN_ memory. */
6858 return 0;
6861 static void
6862 tiff_unmap_memory (data, base, size)
6863 thandle_t data;
6864 tdata_t base;
6865 toff_t size;
6867 /* We don't need to do this. */
6870 static toff_t
6871 tiff_size_of_memory (data)
6872 thandle_t data;
6874 return ((tiff_memory_source *) data)->len;
6878 static void
6879 tiff_error_handler (title, format, ap)
6880 const char *title, *format;
6881 va_list ap;
6883 char buf[512];
6884 int len;
6886 len = sprintf (buf, "TIFF error: %s ", title);
6887 vsprintf (buf + len, format, ap);
6888 add_to_log (buf, Qnil, Qnil);
6892 static void
6893 tiff_warning_handler (title, format, ap)
6894 const char *title, *format;
6895 va_list ap;
6897 char buf[512];
6898 int len;
6900 len = sprintf (buf, "TIFF warning: %s ", title);
6901 vsprintf (buf + len, format, ap);
6902 add_to_log (buf, Qnil, Qnil);
6906 /* Load TIFF image IMG for use on frame F. Value is non-zero if
6907 successful. */
6909 static int
6910 tiff_load (f, img)
6911 struct frame *f;
6912 struct image *img;
6914 Lisp_Object file, specified_file;
6915 Lisp_Object specified_data;
6916 TIFF *tiff;
6917 int width, height, x, y;
6918 uint32 *buf;
6919 int rc;
6920 XImagePtr ximg;
6921 struct gcpro gcpro1;
6922 tiff_memory_source memsrc;
6924 specified_file = image_spec_value (img->spec, QCfile, NULL);
6925 specified_data = image_spec_value (img->spec, QCdata, NULL);
6926 file = Qnil;
6927 GCPRO1 (file);
6929 fn_TIFFSetErrorHandler (tiff_error_handler);
6930 fn_TIFFSetWarningHandler (tiff_warning_handler);
6932 if (NILP (specified_data))
6934 /* Read from a file */
6935 file = x_find_image_file (specified_file);
6936 if (!STRINGP (file))
6938 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6939 UNGCPRO;
6940 return 0;
6943 /* Try to open the image file. */
6944 tiff = fn_TIFFOpen (SDATA (file), "r");
6945 if (tiff == NULL)
6947 image_error ("Cannot open `%s'", file, Qnil);
6948 UNGCPRO;
6949 return 0;
6952 else
6954 /* Memory source! */
6955 memsrc.bytes = SDATA (specified_data);
6956 memsrc.len = SBYTES (specified_data);
6957 memsrc.index = 0;
6959 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
6960 (TIFFReadWriteProc) tiff_read_from_memory,
6961 (TIFFReadWriteProc) tiff_write_from_memory,
6962 tiff_seek_in_memory,
6963 tiff_close_memory,
6964 tiff_size_of_memory,
6965 tiff_mmap_memory,
6966 tiff_unmap_memory);
6968 if (!tiff)
6970 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
6971 UNGCPRO;
6972 return 0;
6976 /* Get width and height of the image, and allocate a raster buffer
6977 of width x height 32-bit values. */
6978 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
6979 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6980 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
6982 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
6983 fn_TIFFClose (tiff);
6984 if (!rc)
6986 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
6987 xfree (buf);
6988 UNGCPRO;
6989 return 0;
6992 /* Create the X image and pixmap. */
6993 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6995 xfree (buf);
6996 UNGCPRO;
6997 return 0;
7000 /* Initialize the color table. */
7001 init_color_table ();
7003 /* Process the pixel raster. Origin is in the lower-left corner. */
7004 for (y = 0; y < height; ++y)
7006 uint32 *row = buf + y * width;
7008 for (x = 0; x < width; ++x)
7010 uint32 abgr = row[x];
7011 int r = TIFFGetR (abgr) << 8;
7012 int g = TIFFGetG (abgr) << 8;
7013 int b = TIFFGetB (abgr) << 8;
7014 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
7018 #ifdef COLOR_TABLE_SUPPORT
7019 /* Remember the colors allocated for the image. Free the color table. */
7020 img->colors = colors_in_color_table (&img->ncolors);
7021 free_color_table ();
7022 #endif /* COLOR_TABLE_SUPPORT */
7024 img->width = width;
7025 img->height = height;
7027 /* Maybe fill in the background field while we have ximg handy. */
7028 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7029 IMAGE_BACKGROUND (img, f, ximg);
7031 /* Put the image into the pixmap, then free the X image and its buffer. */
7032 x_put_x_image (f, ximg, img->pixmap, width, height);
7033 x_destroy_x_image (ximg);
7034 xfree (buf);
7036 UNGCPRO;
7037 return 1;
7040 #else /* HAVE_TIFF */
7042 #ifdef MAC_OS
7043 static int
7044 tiff_load (f, img)
7045 struct frame *f;
7046 struct image *img;
7048 return image_load_quicktime (f, img, kQTFileTypeTIFF);
7050 #endif /* MAC_OS */
7052 #endif /* !HAVE_TIFF */
7056 /***********************************************************************
7058 ***********************************************************************/
7060 #if defined (HAVE_GIF) || defined (MAC_OS)
7062 static int gif_image_p P_ ((Lisp_Object object));
7063 static int gif_load P_ ((struct frame *f, struct image *img));
7065 /* The symbol `gif' identifying images of this type. */
7067 Lisp_Object Qgif;
7069 /* Indices of image specification fields in gif_format, below. */
7071 enum gif_keyword_index
7073 GIF_TYPE,
7074 GIF_DATA,
7075 GIF_FILE,
7076 GIF_ASCENT,
7077 GIF_MARGIN,
7078 GIF_RELIEF,
7079 GIF_ALGORITHM,
7080 GIF_HEURISTIC_MASK,
7081 GIF_MASK,
7082 GIF_IMAGE,
7083 GIF_BACKGROUND,
7084 GIF_LAST
7087 /* Vector of image_keyword structures describing the format
7088 of valid user-defined image specifications. */
7090 static struct image_keyword gif_format[GIF_LAST] =
7092 {":type", IMAGE_SYMBOL_VALUE, 1},
7093 {":data", IMAGE_STRING_VALUE, 0},
7094 {":file", IMAGE_STRING_VALUE, 0},
7095 {":ascent", IMAGE_ASCENT_VALUE, 0},
7096 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7097 {":relief", IMAGE_INTEGER_VALUE, 0},
7098 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7099 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7100 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7101 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7102 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7105 /* Structure describing the image type `gif'. */
7107 static struct image_type gif_type =
7109 &Qgif,
7110 gif_image_p,
7111 gif_load,
7112 x_clear_image,
7113 NULL
7116 /* Return non-zero if OBJECT is a valid GIF image specification. */
7118 static int
7119 gif_image_p (object)
7120 Lisp_Object object;
7122 struct image_keyword fmt[GIF_LAST];
7123 bcopy (gif_format, fmt, sizeof fmt);
7125 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
7126 return 0;
7128 /* Must specify either the :data or :file keyword. */
7129 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7132 #endif /* HAVE_GIF || MAC_OS */
7134 #ifdef HAVE_GIF
7136 #if defined (HAVE_NTGUI) || defined (MAC_OS)
7137 /* avoid conflict with QuickdrawText.h */
7138 #define DrawText gif_DrawText
7139 #include <gif_lib.h>
7140 #undef DrawText
7142 #else /* HAVE_NTGUI || MAC_OS */
7144 #include <gif_lib.h>
7146 #endif /* HAVE_NTGUI || MAC_OS */
7149 #ifdef HAVE_NTGUI
7151 /* GIF library details. */
7152 DEF_IMGLIB_FN (DGifCloseFile);
7153 DEF_IMGLIB_FN (DGifSlurp);
7154 DEF_IMGLIB_FN (DGifOpen);
7155 DEF_IMGLIB_FN (DGifOpenFileName);
7157 static int
7158 init_gif_functions (Lisp_Object libraries)
7160 HMODULE library;
7162 if (!(library = w32_delayed_load (libraries, Qgif)))
7163 return 0;
7165 LOAD_IMGLIB_FN (library, DGifCloseFile);
7166 LOAD_IMGLIB_FN (library, DGifSlurp);
7167 LOAD_IMGLIB_FN (library, DGifOpen);
7168 LOAD_IMGLIB_FN (library, DGifOpenFileName);
7169 return 1;
7172 #else
7174 #define fn_DGifCloseFile DGifCloseFile
7175 #define fn_DGifSlurp DGifSlurp
7176 #define fn_DGifOpen DGifOpen
7177 #define fn_DGifOpenFileName DGifOpenFileName
7179 #endif /* HAVE_NTGUI */
7181 /* Reading a GIF image from memory
7182 Based on the PNG memory stuff to a certain extent. */
7184 typedef struct
7186 unsigned char *bytes;
7187 size_t len;
7188 int index;
7190 gif_memory_source;
7192 /* Make the current memory source available to gif_read_from_memory.
7193 It's done this way because not all versions of libungif support
7194 a UserData field in the GifFileType structure. */
7195 static gif_memory_source *current_gif_memory_src;
7197 static int
7198 gif_read_from_memory (file, buf, len)
7199 GifFileType *file;
7200 GifByteType *buf;
7201 int len;
7203 gif_memory_source *src = current_gif_memory_src;
7205 if (len > src->len - src->index)
7206 return -1;
7208 bcopy (src->bytes + src->index, buf, len);
7209 src->index += len;
7210 return len;
7214 /* Load GIF image IMG for use on frame F. Value is non-zero if
7215 successful. */
7217 static int
7218 gif_load (f, img)
7219 struct frame *f;
7220 struct image *img;
7222 Lisp_Object file, specified_file;
7223 Lisp_Object specified_data;
7224 int rc, width, height, x, y, i;
7225 XImagePtr ximg;
7226 ColorMapObject *gif_color_map;
7227 unsigned long pixel_colors[256];
7228 GifFileType *gif;
7229 struct gcpro gcpro1;
7230 Lisp_Object image;
7231 int ino, image_left, image_top, image_width, image_height;
7232 gif_memory_source memsrc;
7233 unsigned char *raster;
7235 specified_file = image_spec_value (img->spec, QCfile, NULL);
7236 specified_data = image_spec_value (img->spec, QCdata, NULL);
7237 file = Qnil;
7238 GCPRO1 (file);
7240 if (NILP (specified_data))
7242 file = x_find_image_file (specified_file);
7243 if (!STRINGP (file))
7245 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7246 UNGCPRO;
7247 return 0;
7250 /* Open the GIF file. */
7251 gif = fn_DGifOpenFileName (SDATA (file));
7252 if (gif == NULL)
7254 image_error ("Cannot open `%s'", file, Qnil);
7255 UNGCPRO;
7256 return 0;
7259 else
7261 /* Read from memory! */
7262 current_gif_memory_src = &memsrc;
7263 memsrc.bytes = SDATA (specified_data);
7264 memsrc.len = SBYTES (specified_data);
7265 memsrc.index = 0;
7267 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
7268 if (!gif)
7270 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
7271 UNGCPRO;
7272 return 0;
7276 /* Read entire contents. */
7277 rc = fn_DGifSlurp (gif);
7278 if (rc == GIF_ERROR)
7280 image_error ("Error reading `%s'", img->spec, Qnil);
7281 fn_DGifCloseFile (gif);
7282 UNGCPRO;
7283 return 0;
7286 image = image_spec_value (img->spec, QCindex, NULL);
7287 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7288 if (ino >= gif->ImageCount)
7290 image_error ("Invalid image number `%s' in image `%s'",
7291 image, img->spec);
7292 fn_DGifCloseFile (gif);
7293 UNGCPRO;
7294 return 0;
7297 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
7298 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
7300 /* Create the X image and pixmap. */
7301 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7303 fn_DGifCloseFile (gif);
7304 UNGCPRO;
7305 return 0;
7308 /* Allocate colors. */
7309 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
7310 if (!gif_color_map)
7311 gif_color_map = gif->SColorMap;
7312 init_color_table ();
7313 bzero (pixel_colors, sizeof pixel_colors);
7315 for (i = 0; i < gif_color_map->ColorCount; ++i)
7317 int r = gif_color_map->Colors[i].Red << 8;
7318 int g = gif_color_map->Colors[i].Green << 8;
7319 int b = gif_color_map->Colors[i].Blue << 8;
7320 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7323 #ifdef COLOR_TABLE_SUPPORT
7324 img->colors = colors_in_color_table (&img->ncolors);
7325 free_color_table ();
7326 #endif /* COLOR_TABLE_SUPPORT */
7328 /* Clear the part of the screen image that are not covered by
7329 the image from the GIF file. Full animated GIF support
7330 requires more than can be done here (see the gif89 spec,
7331 disposal methods). Let's simply assume that the part
7332 not covered by a sub-image is in the frame's background color. */
7333 image_top = gif->SavedImages[ino].ImageDesc.Top;
7334 image_left = gif->SavedImages[ino].ImageDesc.Left;
7335 image_width = gif->SavedImages[ino].ImageDesc.Width;
7336 image_height = gif->SavedImages[ino].ImageDesc.Height;
7338 for (y = 0; y < image_top; ++y)
7339 for (x = 0; x < width; ++x)
7340 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7342 for (y = image_top + image_height; y < height; ++y)
7343 for (x = 0; x < width; ++x)
7344 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7346 for (y = image_top; y < image_top + image_height; ++y)
7348 for (x = 0; x < image_left; ++x)
7349 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7350 for (x = image_left + image_width; x < width; ++x)
7351 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7354 /* Read the GIF image into the X image. We use a local variable
7355 `raster' here because RasterBits below is a char *, and invites
7356 problems with bytes >= 0x80. */
7357 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7359 if (gif->SavedImages[ino].ImageDesc.Interlace)
7361 static int interlace_start[] = {0, 4, 2, 1};
7362 static int interlace_increment[] = {8, 8, 4, 2};
7363 int pass;
7364 int row = interlace_start[0];
7366 pass = 0;
7368 for (y = 0; y < image_height; y++)
7370 if (row >= image_height)
7372 row = interlace_start[++pass];
7373 while (row >= image_height)
7374 row = interlace_start[++pass];
7377 for (x = 0; x < image_width; x++)
7379 int i = raster[(y * image_width) + x];
7380 XPutPixel (ximg, x + image_left, row + image_top,
7381 pixel_colors[i]);
7384 row += interlace_increment[pass];
7387 else
7389 for (y = 0; y < image_height; ++y)
7390 for (x = 0; x < image_width; ++x)
7392 int i = raster[y * image_width + x];
7393 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
7397 fn_DGifCloseFile (gif);
7399 /* Maybe fill in the background field while we have ximg handy. */
7400 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7401 IMAGE_BACKGROUND (img, f, ximg);
7403 /* Put the image into the pixmap, then free the X image and its buffer. */
7404 x_put_x_image (f, ximg, img->pixmap, width, height);
7405 x_destroy_x_image (ximg);
7407 UNGCPRO;
7408 return 1;
7411 #else
7413 #ifdef MAC_OS
7414 static int
7415 gif_load (f, img)
7416 struct frame *f;
7417 struct image *img;
7419 Lisp_Object specified_file, file;
7420 Lisp_Object specified_data;
7421 OSErr err;
7422 Boolean graphic_p, movie_p, prefer_graphic_p;
7423 Handle dh = NULL;
7424 Movie movie = NULL;
7425 Lisp_Object image;
7426 Track track = NULL;
7427 Media media = NULL;
7428 long nsamples;
7429 Rect rect;
7430 Lisp_Object specified_bg;
7431 XColor color;
7432 RGBColor bg_color;
7433 int width, height;
7434 XImagePtr ximg;
7435 TimeValue time;
7436 struct gcpro gcpro1;
7437 int ino;
7438 CGrafPtr old_port;
7439 GDHandle old_gdh;
7441 specified_file = image_spec_value (img->spec, QCfile, NULL);
7442 specified_data = image_spec_value (img->spec, QCdata, NULL);
7444 if (NILP (specified_data))
7446 /* Read from a file */
7447 FSSpec fss;
7448 short refnum;
7450 err = find_image_fsspec (specified_file, &file, &fss);
7451 if (err != noErr)
7453 if (err == fnfErr)
7454 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7455 else
7456 goto open_error;
7459 err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0,
7460 &graphic_p, &movie_p, &prefer_graphic_p, 0);
7461 if (err != noErr)
7462 goto open_error;
7464 if (!graphic_p && !movie_p)
7465 goto open_error;
7466 if (prefer_graphic_p)
7467 return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL);
7468 err = OpenMovieFile (&fss, &refnum, fsRdPerm);
7469 if (err != noErr)
7470 goto open_error;
7471 err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL);
7472 CloseMovieFile (refnum);
7473 if (err != noErr)
7475 image_error ("Error reading `%s'", file, Qnil);
7476 return 0;
7479 else
7481 /* Memory source! */
7482 Handle dref = NULL;
7483 long file_type_atom[3];
7485 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
7486 if (err != noErr)
7488 image_error ("Cannot allocate data handle for `%s'",
7489 img->spec, Qnil);
7490 goto error;
7493 file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3);
7494 file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
7495 file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF);
7496 err = PtrToHand (&dh, &dref, sizeof (Handle));
7497 if (err == noErr)
7498 /* no file name */
7499 err = PtrAndHand ("\p", dref, 1);
7500 if (err == noErr)
7501 err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3);
7502 if (err != noErr)
7504 image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil);
7505 goto error;
7507 err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p,
7508 &movie_p, &prefer_graphic_p, 0);
7509 if (err != noErr)
7510 goto open_error;
7512 if (!graphic_p && !movie_p)
7513 goto open_error;
7514 if (prefer_graphic_p)
7516 int success_p;
7518 DisposeHandle (dref);
7519 success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh);
7520 DisposeHandle (dh);
7521 return success_p;
7523 err = NewMovieFromDataRef (&movie, 0, NULL, dref,
7524 HandleDataHandlerSubType);
7525 DisposeHandle (dref);
7526 if (err != noErr)
7527 goto open_error;
7530 image = image_spec_value (img->spec, QCindex, NULL);
7531 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7532 track = GetMovieIndTrack (movie, 1);
7533 media = GetTrackMedia (track);
7534 nsamples = GetMediaSampleCount (media);
7535 if (ino >= nsamples)
7537 image_error ("Invalid image number `%s' in image `%s'",
7538 image, img->spec);
7539 goto error;
7542 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
7543 if (!STRINGP (specified_bg) ||
7544 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
7546 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7547 color.red = RED16_FROM_ULONG (color.pixel);
7548 color.green = GREEN16_FROM_ULONG (color.pixel);
7549 color.blue = BLUE16_FROM_ULONG (color.pixel);
7551 GetMovieBox (movie, &rect);
7552 width = img->width = rect.right - rect.left;
7553 height = img->height = rect.bottom - rect.top;
7554 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7555 goto error;
7557 GetGWorld (&old_port, &old_gdh);
7558 SetGWorld (ximg, NULL);
7559 bg_color.red = color.red;
7560 bg_color.green = color.green;
7561 bg_color.blue = color.blue;
7562 RGBBackColor (&bg_color);
7563 SetGWorld (old_port, old_gdh);
7564 SetMovieActive (movie, 1);
7565 SetMovieGWorld (movie, ximg, NULL);
7566 SampleNumToMediaTime (media, ino + 1, &time, NULL);
7567 SetMovieTimeValue (movie, time);
7568 MoviesTask (movie, 0L);
7569 DisposeTrackMedia (media);
7570 DisposeMovieTrack (track);
7571 DisposeMovie (movie);
7572 if (dh)
7573 DisposeHandle (dh);
7574 /* Maybe fill in the background field while we have ximg handy. */
7575 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7576 IMAGE_BACKGROUND (img, f, ximg);
7578 /* Put the image into the pixmap. */
7579 x_put_x_image (f, ximg, img->pixmap, width, height);
7580 x_destroy_x_image (ximg);
7581 return 1;
7583 open_error:
7584 image_error ("Cannot open `%s'", file, Qnil);
7585 error:
7586 if (media)
7587 DisposeTrackMedia (media);
7588 if (track)
7589 DisposeMovieTrack (track);
7590 if (movie)
7591 DisposeMovie (movie);
7592 if (dh)
7593 DisposeHandle (dh);
7594 return 0;
7596 #endif /* MAC_OS */
7598 #endif /* HAVE_GIF */
7602 /***********************************************************************
7603 Ghostscript
7604 ***********************************************************************/
7606 #ifdef HAVE_X_WINDOWS
7607 #define HAVE_GHOSTSCRIPT 1
7608 #endif /* HAVE_X_WINDOWS */
7610 /* The symbol `postscript' identifying images of this type. */
7612 Lisp_Object Qpostscript;
7614 #ifdef HAVE_GHOSTSCRIPT
7616 static int gs_image_p P_ ((Lisp_Object object));
7617 static int gs_load P_ ((struct frame *f, struct image *img));
7618 static void gs_clear_image P_ ((struct frame *f, struct image *img));
7620 /* Keyword symbols. */
7622 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
7624 /* Indices of image specification fields in gs_format, below. */
7626 enum gs_keyword_index
7628 GS_TYPE,
7629 GS_PT_WIDTH,
7630 GS_PT_HEIGHT,
7631 GS_FILE,
7632 GS_LOADER,
7633 GS_BOUNDING_BOX,
7634 GS_ASCENT,
7635 GS_MARGIN,
7636 GS_RELIEF,
7637 GS_ALGORITHM,
7638 GS_HEURISTIC_MASK,
7639 GS_MASK,
7640 GS_BACKGROUND,
7641 GS_LAST
7644 /* Vector of image_keyword structures describing the format
7645 of valid user-defined image specifications. */
7647 static struct image_keyword gs_format[GS_LAST] =
7649 {":type", IMAGE_SYMBOL_VALUE, 1},
7650 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7651 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
7652 {":file", IMAGE_STRING_VALUE, 1},
7653 {":loader", IMAGE_FUNCTION_VALUE, 0},
7654 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7655 {":ascent", IMAGE_ASCENT_VALUE, 0},
7656 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7657 {":relief", IMAGE_INTEGER_VALUE, 0},
7658 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7659 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7660 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7661 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7664 /* Structure describing the image type `ghostscript'. */
7666 static struct image_type gs_type =
7668 &Qpostscript,
7669 gs_image_p,
7670 gs_load,
7671 gs_clear_image,
7672 NULL
7676 /* Free X resources of Ghostscript image IMG which is used on frame F. */
7678 static void
7679 gs_clear_image (f, img)
7680 struct frame *f;
7681 struct image *img;
7683 /* IMG->data.ptr_val may contain a recorded colormap. */
7684 xfree (img->data.ptr_val);
7685 x_clear_image (f, img);
7689 /* Return non-zero if OBJECT is a valid Ghostscript image
7690 specification. */
7692 static int
7693 gs_image_p (object)
7694 Lisp_Object object;
7696 struct image_keyword fmt[GS_LAST];
7697 Lisp_Object tem;
7698 int i;
7700 bcopy (gs_format, fmt, sizeof fmt);
7702 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
7703 return 0;
7705 /* Bounding box must be a list or vector containing 4 integers. */
7706 tem = fmt[GS_BOUNDING_BOX].value;
7707 if (CONSP (tem))
7709 for (i = 0; i < 4; ++i, tem = XCDR (tem))
7710 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
7711 return 0;
7712 if (!NILP (tem))
7713 return 0;
7715 else if (VECTORP (tem))
7717 if (XVECTOR (tem)->size != 4)
7718 return 0;
7719 for (i = 0; i < 4; ++i)
7720 if (!INTEGERP (XVECTOR (tem)->contents[i]))
7721 return 0;
7723 else
7724 return 0;
7726 return 1;
7730 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
7731 if successful. */
7733 static int
7734 gs_load (f, img)
7735 struct frame *f;
7736 struct image *img;
7738 char buffer[100];
7739 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
7740 struct gcpro gcpro1, gcpro2;
7741 Lisp_Object frame;
7742 double in_width, in_height;
7743 Lisp_Object pixel_colors = Qnil;
7745 /* Compute pixel size of pixmap needed from the given size in the
7746 image specification. Sizes in the specification are in pt. 1 pt
7747 = 1/72 in, xdpi and ydpi are stored in the frame's X display
7748 info. */
7749 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
7750 in_width = XFASTINT (pt_width) / 72.0;
7751 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
7752 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
7753 in_height = XFASTINT (pt_height) / 72.0;
7754 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
7756 /* Create the pixmap. */
7757 xassert (img->pixmap == NO_PIXMAP);
7759 /* Only W32 version did BLOCK_INPUT here. ++kfs */
7760 BLOCK_INPUT;
7761 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7762 img->width, img->height,
7763 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
7764 UNBLOCK_INPUT;
7766 if (!img->pixmap)
7768 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
7769 return 0;
7772 /* Call the loader to fill the pixmap. It returns a process object
7773 if successful. We do not record_unwind_protect here because
7774 other places in redisplay like calling window scroll functions
7775 don't either. Let the Lisp loader use `unwind-protect' instead. */
7776 GCPRO2 (window_and_pixmap_id, pixel_colors);
7778 sprintf (buffer, "%lu %lu",
7779 (unsigned long) FRAME_X_WINDOW (f),
7780 (unsigned long) img->pixmap);
7781 window_and_pixmap_id = build_string (buffer);
7783 sprintf (buffer, "%lu %lu",
7784 FRAME_FOREGROUND_PIXEL (f),
7785 FRAME_BACKGROUND_PIXEL (f));
7786 pixel_colors = build_string (buffer);
7788 XSETFRAME (frame, f);
7789 loader = image_spec_value (img->spec, QCloader, NULL);
7790 if (NILP (loader))
7791 loader = intern ("gs-load-image");
7793 img->data.lisp_val = call6 (loader, frame, img->spec,
7794 make_number (img->width),
7795 make_number (img->height),
7796 window_and_pixmap_id,
7797 pixel_colors);
7798 UNGCPRO;
7799 return PROCESSP (img->data.lisp_val);
7803 /* Kill the Ghostscript process that was started to fill PIXMAP on
7804 frame F. Called from XTread_socket when receiving an event
7805 telling Emacs that Ghostscript has finished drawing. */
7807 void
7808 x_kill_gs_process (pixmap, f)
7809 Pixmap pixmap;
7810 struct frame *f;
7812 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7813 int class, i;
7814 struct image *img;
7816 /* Find the image containing PIXMAP. */
7817 for (i = 0; i < c->used; ++i)
7818 if (c->images[i]->pixmap == pixmap)
7819 break;
7821 /* Should someone in between have cleared the image cache, for
7822 instance, give up. */
7823 if (i == c->used)
7824 return;
7826 /* Kill the GS process. We should have found PIXMAP in the image
7827 cache and its image should contain a process object. */
7828 img = c->images[i];
7829 xassert (PROCESSP (img->data.lisp_val));
7830 Fkill_process (img->data.lisp_val, Qnil);
7831 img->data.lisp_val = Qnil;
7833 #if defined (HAVE_X_WINDOWS)
7835 /* On displays with a mutable colormap, figure out the colors
7836 allocated for the image by looking at the pixels of an XImage for
7837 img->pixmap. */
7838 class = FRAME_X_VISUAL (f)->class;
7839 if (class != StaticColor && class != StaticGray && class != TrueColor)
7841 XImagePtr ximg;
7843 BLOCK_INPUT;
7845 /* Try to get an XImage for img->pixmep. */
7846 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7847 0, 0, img->width, img->height, ~0, ZPixmap);
7848 if (ximg)
7850 int x, y;
7852 /* Initialize the color table. */
7853 init_color_table ();
7855 /* For each pixel of the image, look its color up in the
7856 color table. After having done so, the color table will
7857 contain an entry for each color used by the image. */
7858 for (y = 0; y < img->height; ++y)
7859 for (x = 0; x < img->width; ++x)
7861 unsigned long pixel = XGetPixel (ximg, x, y);
7862 lookup_pixel_color (f, pixel);
7865 /* Record colors in the image. Free color table and XImage. */
7866 #ifdef COLOR_TABLE_SUPPORT
7867 img->colors = colors_in_color_table (&img->ncolors);
7868 free_color_table ();
7869 #endif
7870 XDestroyImage (ximg);
7872 #if 0 /* This doesn't seem to be the case. If we free the colors
7873 here, we get a BadAccess later in x_clear_image when
7874 freeing the colors. */
7875 /* We have allocated colors once, but Ghostscript has also
7876 allocated colors on behalf of us. So, to get the
7877 reference counts right, free them once. */
7878 if (img->ncolors)
7879 x_free_colors (f, img->colors, img->ncolors);
7880 #endif
7882 else
7883 image_error ("Cannot get X image of `%s'; colors will not be freed",
7884 img->spec, Qnil);
7886 UNBLOCK_INPUT;
7888 #endif /* HAVE_X_WINDOWS */
7890 /* Now that we have the pixmap, compute mask and transform the
7891 image if requested. */
7892 BLOCK_INPUT;
7893 postprocess_image (f, img);
7894 UNBLOCK_INPUT;
7897 #endif /* HAVE_GHOSTSCRIPT */
7900 /***********************************************************************
7901 Tests
7902 ***********************************************************************/
7904 #if GLYPH_DEBUG
7906 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
7907 doc: /* Value is non-nil if SPEC is a valid image specification. */)
7908 (spec)
7909 Lisp_Object spec;
7911 return valid_image_p (spec) ? Qt : Qnil;
7915 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
7916 (spec)
7917 Lisp_Object spec;
7919 int id = -1;
7921 if (valid_image_p (spec))
7922 id = lookup_image (SELECTED_FRAME (), spec);
7924 debug_print (spec);
7925 return make_number (id);
7928 #endif /* GLYPH_DEBUG != 0 */
7931 /***********************************************************************
7932 Initialization
7933 ***********************************************************************/
7935 #ifdef HAVE_NTGUI
7936 /* Image types that rely on external libraries are loaded dynamically
7937 if the library is available. */
7938 #define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
7939 define_image_type (image_type, init_lib_fn (libraries))
7940 #else
7941 #define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
7942 define_image_type (image_type, 1)
7943 #endif /* HAVE_NTGUI */
7945 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
7946 doc: /* Initialize image library implementing image type TYPE.
7947 Return non-nil if TYPE is a supported image type.
7949 Image types pbm and xbm are prebuilt; other types are loaded here.
7950 Libraries to load are specified in alist LIBRARIES (usually, the value
7951 of `image-library-alist', which see). */)
7952 (type, libraries)
7953 Lisp_Object type, libraries;
7955 Lisp_Object tested;
7957 /* Don't try to reload the library. */
7958 tested = Fassq (type, Vimage_type_cache);
7959 if (CONSP (tested))
7960 return XCDR (tested);
7962 #if defined (HAVE_XPM) || defined (MAC_OS)
7963 if (EQ (type, Qxpm))
7964 return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
7965 #endif
7967 #if defined (HAVE_JPEG) || defined (MAC_OS)
7968 if (EQ (type, Qjpeg))
7969 return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
7970 #endif
7972 #if defined (HAVE_TIFF) || defined (MAC_OS)
7973 if (EQ (type, Qtiff))
7974 return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
7975 #endif
7977 #if defined (HAVE_GIF) || defined (MAC_OS)
7978 if (EQ (type, Qgif))
7979 return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
7980 #endif
7982 #if defined (HAVE_PNG) || defined (MAC_OS)
7983 if (EQ (type, Qpng))
7984 return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
7985 #endif
7987 #ifdef HAVE_GHOSTSCRIPT
7988 if (EQ (type, Qpostscript))
7989 return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
7990 #endif
7992 /* If the type is not recognized, avoid testing it ever again. */
7993 CACHE_IMAGE_TYPE (type, Qnil);
7994 return Qnil;
7997 void
7998 syms_of_image ()
8000 /* Must be defined now becase we're going to update it below, while
8001 defining the supported image types. */
8002 DEFVAR_LISP ("image-types", &Vimage_types,
8003 doc: /* List of potentially supported image types.
8004 Each element of the list is a symbol for a image type, like 'jpeg or 'png.
8005 To check whether it is really supported, use `image-type-available-p'. */);
8006 Vimage_types = Qnil;
8008 Vimage_type_cache = Qnil;
8009 staticpro (&Vimage_type_cache);
8011 QCascent = intern (":ascent");
8012 staticpro (&QCascent);
8013 QCmargin = intern (":margin");
8014 staticpro (&QCmargin);
8015 QCrelief = intern (":relief");
8016 staticpro (&QCrelief);
8017 QCconversion = intern (":conversion");
8018 staticpro (&QCconversion);
8019 QCcolor_symbols = intern (":color-symbols");
8020 staticpro (&QCcolor_symbols);
8021 QCheuristic_mask = intern (":heuristic-mask");
8022 staticpro (&QCheuristic_mask);
8023 QCindex = intern (":index");
8024 staticpro (&QCindex);
8025 QCmatrix = intern (":matrix");
8026 staticpro (&QCmatrix);
8027 QCcolor_adjustment = intern (":color-adjustment");
8028 staticpro (&QCcolor_adjustment);
8029 QCmask = intern (":mask");
8030 staticpro (&QCmask);
8032 Qlaplace = intern ("laplace");
8033 staticpro (&Qlaplace);
8034 Qemboss = intern ("emboss");
8035 staticpro (&Qemboss);
8036 Qedge_detection = intern ("edge-detection");
8037 staticpro (&Qedge_detection);
8038 Qheuristic = intern ("heuristic");
8039 staticpro (&Qheuristic);
8041 Qpostscript = intern ("postscript");
8042 staticpro (&Qpostscript);
8043 #ifdef HAVE_GHOSTSCRIPT
8044 ADD_IMAGE_TYPE(Qpostscript);
8045 QCloader = intern (":loader");
8046 staticpro (&QCloader);
8047 QCbounding_box = intern (":bounding-box");
8048 staticpro (&QCbounding_box);
8049 QCpt_width = intern (":pt-width");
8050 staticpro (&QCpt_width);
8051 QCpt_height = intern (":pt-height");
8052 staticpro (&QCpt_height);
8053 #endif /* HAVE_GHOSTSCRIPT */
8055 Qpbm = intern ("pbm");
8056 staticpro (&Qpbm);
8057 ADD_IMAGE_TYPE(Qpbm);
8059 Qxbm = intern ("xbm");
8060 staticpro (&Qxbm);
8061 ADD_IMAGE_TYPE(Qxbm);
8063 #if defined (HAVE_XPM) || defined (MAC_OS)
8064 Qxpm = intern ("xpm");
8065 staticpro (&Qxpm);
8066 ADD_IMAGE_TYPE(Qxpm);
8067 #endif
8069 #if defined (HAVE_JPEG) || defined (MAC_OS)
8070 Qjpeg = intern ("jpeg");
8071 staticpro (&Qjpeg);
8072 ADD_IMAGE_TYPE(Qjpeg);
8073 #endif
8075 #if defined (HAVE_TIFF) || defined (MAC_OS)
8076 Qtiff = intern ("tiff");
8077 staticpro (&Qtiff);
8078 ADD_IMAGE_TYPE(Qtiff);
8079 #endif
8081 #if defined (HAVE_GIF) || defined (MAC_OS)
8082 Qgif = intern ("gif");
8083 staticpro (&Qgif);
8084 ADD_IMAGE_TYPE(Qgif);
8085 #endif
8087 #if defined (HAVE_PNG) || defined (MAC_OS)
8088 Qpng = intern ("png");
8089 staticpro (&Qpng);
8090 ADD_IMAGE_TYPE(Qpng);
8091 #endif
8093 defsubr (&Sinit_image_library);
8094 defsubr (&Sclear_image_cache);
8095 defsubr (&Simage_size);
8096 defsubr (&Simage_mask_p);
8098 #if GLYPH_DEBUG
8099 defsubr (&Simagep);
8100 defsubr (&Slookup_image);
8101 #endif
8103 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
8104 doc: /* Non-nil means always draw a cross over disabled images.
8105 Disabled images are those having an `:conversion disabled' property.
8106 A cross is always drawn on black & white displays. */);
8107 cross_disabled_images = 0;
8109 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
8110 doc: /* List of directories to search for window system bitmap files. */);
8111 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
8113 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
8114 doc: /* Time after which cached images are removed from the cache.
8115 When an image has not been displayed this many seconds, remove it
8116 from the image cache. Value must be an integer or nil with nil
8117 meaning don't clear the cache. */);
8118 Vimage_cache_eviction_delay = make_number (30 * 60);
8121 void
8122 init_image ()
8124 image_types = NULL;
8126 define_image_type (&xbm_type, 1);
8127 define_image_type (&pbm_type, 1);
8129 #ifdef MAC_OS
8130 /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */
8131 EnterMovies ();
8132 #ifdef MAC_OSX
8133 init_image_func_pointer ();
8134 #endif
8135 #endif
8138 /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
8139 (do not change this comment) */