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