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