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