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