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