#endif
#include <setjmp.h>
-
#include <c-ctype.h>
-/* This makes the fields of a Display accessible, in Xlib header files. */
-
-#define XLIB_ILLEGAL_ACCESS
-
#include "lisp.h"
#include "frame.h"
#include "window.h"
#define x_defined_color w32_defined_color
#define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
-/* Version of libpng that we were compiled with, or -1 if no PNG
- support was compiled in. This is tested by w32-win.el to correctly
- set up the alist used to search for PNG libraries. */
-Lisp_Object Qlibpng_version;
+/* Versions of libpng and libgif that we were compiled with, or -1 if
+ no PNG/GIF support was compiled in. This is tested by w32-win.el
+ to correctly set up the alist used to search for the respective
+ image libraries. */
+Lisp_Object Qlibpng_version, Qlibgif_version;
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
#ifdef HAVE_NS
/* Use with images created by ns_image_for_XPM. */
-unsigned long
+static unsigned long
XGetPixel (XImagePtr ximage, int x, int y)
{
return ns_get_pixel (ximage, x, y);
/* Use with images created by ns_image_for_XPM; alpha set to 1;
pixel is assumed to be in RGB form. */
-void
+static void
XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
{
ns_put_pixel (ximage, x, y, pixel);
/* Functions to access the contents of a bitmap, given an id. */
int
-x_bitmap_height (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_height (struct frame *f, ptrdiff_t id)
{
- return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
+ return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].height;
}
int
-x_bitmap_width (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_width (struct frame *f, ptrdiff_t id)
{
- return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
+ return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].width;
}
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
ptrdiff_t
-x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
{
/* HAVE_NTGUI needs the explicit cast here. */
- return (ptrdiff_t) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
+ return (ptrdiff_t) FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
}
#endif
#ifdef HAVE_X_WINDOWS
int
-x_bitmap_mask (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_mask (struct frame *f, ptrdiff_t id)
{
- return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
+ return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
}
#endif
/* Allocate a new bitmap record. Returns index of new record. */
static ptrdiff_t
-x_allocate_bitmap_record (FRAME_PTR f)
+x_allocate_bitmap_record (struct frame *f)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
ptrdiff_t i;
if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
/* Add one reference to the reference count of the bitmap with id ID. */
void
-x_reference_bitmap (FRAME_PTR f, ptrdiff_t id)
+x_reference_bitmap (struct frame *f, ptrdiff_t id)
{
- ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
+ ++FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
}
/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
ptrdiff_t
x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
ptrdiff_t id;
#ifdef HAVE_X_WINDOWS
#ifdef HAVE_NTGUI
Pixmap bitmap;
bitmap = CreateBitmap (width, height,
- FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
- FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
+ FRAME_DISPLAY_INFO (XFRAME (frame))->n_planes,
+ FRAME_DISPLAY_INFO (XFRAME (frame))->n_cbits,
bits);
if (! bitmap)
return -1;
ptrdiff_t
x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
#ifdef HAVE_NTGUI
return -1; /* W32_TODO : bitmap support */
id = x_allocate_bitmap_record (f);
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].refcount = 1;
- dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
+ dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
- strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
return id;
#endif
dpyinfo->bitmaps[id - 1].pixmap = bitmap;
dpyinfo->bitmaps[id - 1].have_mask = 0;
dpyinfo->bitmaps[id - 1].refcount = 1;
- dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
+ dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = height;
dpyinfo->bitmaps[id - 1].width = width;
- strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
return id;
#endif /* HAVE_X_WINDOWS */
/* Remove reference to bitmap with id number ID. */
void
-x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id)
+x_destroy_bitmap (struct frame *f, ptrdiff_t id)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
if (id > 0)
{
unsigned long x, y, xp, xm, yp, ym;
GC gc;
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
if (!(id > 0))
return;
static void x_build_heuristic_mask (struct frame *, struct image *,
Lisp_Object);
#ifdef WINDOWSNT
-extern Lisp_Object Vlibrary_cache;
#define CACHE_IMAGE_TYPE(type, status) \
do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0)
#else
prepare_image_for_display (struct frame *f, struct image *img)
{
/* We're about to display IMG, so set its timestamp to `now'. */
- img->timestamp = current_emacs_time ();
+ img->timestamp = current_timespec ();
/* If IMG doesn't have a pixmap yet, load it now, using the image
type dependent loader function. */
struct image_cache *
make_image_cache (void)
{
- struct image_cache *c = xzalloc (sizeof *c);
- int size;
+ struct image_cache *c = xmalloc (sizeof *c);
- size = 50;
- c->images = xmalloc (size * sizeof *c->images);
- c->size = size;
- size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
- c->buckets = xzalloc (size);
+ c->size = 50;
+ c->used = c->refcount = 0;
+ c->images = xmalloc (c->size * sizeof *c->images);
+ c->buckets = xzalloc (IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets);
return c;
}
else if (INTEGERP (Vimage_cache_eviction_delay))
{
/* Free cache based on timestamp. */
- EMACS_TIME old, t;
+ struct timespec old, t;
double delay;
ptrdiff_t nimages = 0;
delay = 1600 * delay / nimages / nimages;
delay = max (delay, 1);
- t = current_emacs_time ();
- old = sub_emacs_time (t, EMACS_TIME_FROM_DOUBLE (delay));
+ t = current_timespec ();
+ old = timespec_sub (t, dtotimespec (delay));
for (i = 0; i < c->used; ++i)
{
struct image *img = c->images[i];
- if (img && EMACS_TIME_LT (img->timestamp, old))
+ if (img && timespec_cmp (img->timestamp, old) < 0)
{
free_image (f, img);
++nfreed;
}
/* We're using IMG, so set its timestamp to `now'. */
- img->timestamp = current_emacs_time ();
+ img->timestamp = current_timespec ();
/* Value is the image id. */
return img->id;
LA1 = xbm_scan (&s, end, buffer, &value)
#define expect(TOKEN) \
- if (LA1 != (TOKEN)) \
- goto failure; \
- else \
- match ()
+ do \
+ { \
+ if (LA1 != (TOKEN)) \
+ goto failure; \
+ match (); \
+ } \
+ while (0)
#define expect_ident(IDENT) \
if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color,
void *closure)
{
- return xpm_lookup_color ((struct frame *) closure, color_name, color);
+ return xpm_lookup_color (closure, color_name, color);
}
ptrdiff_t
x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
ptrdiff_t id;
int rc;
XpmAttributes attrs;
LA1 = xpm_scan (&s, end, &beg, &len)
#define expect(TOKEN) \
- if (LA1 != (TOKEN)) \
- goto failure; \
- else \
- match ()
+ do \
+ { \
+ if (LA1 != (TOKEN)) \
+ goto failure; \
+ match (); \
+ } \
+ while (0)
#define expect_ident(IDENT) \
if (LA1 == XPM_TK_IDENT \
two orders of magnitude. Freeing colors on TrueColor visuals is
a nop, and pixel colors specify RGB values directly. See also
the Xlib spec, chapter 3.1. */
- dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ dpyinfo = FRAME_DISPLAY_INFO (f);
if (dpyinfo->red_bits > 0)
{
unsigned long pr, pg, pb;
static void
x_disable_image (struct frame *f, struct image *img)
{
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
#ifdef HAVE_NTGUI
int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
#else
int row_width;
#endif /* HAVE_NTGUI */
int x, y;
- bool rc, use_img_background;
+ bool use_img_background;
unsigned long bg = 0;
if (img->mask)
#ifndef HAVE_NTGUI
#ifndef HAVE_NS
/* Create an image and pixmap serving as mask. */
- rc = image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
- &mask_img, 1);
- if (!rc)
+ if (! image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
+ &mask_img, 1))
return;
#endif /* !HAVE_NS */
#else
static void
png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length)
{
- struct png_memory_storage *tbr
- = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
+ struct png_memory_storage *tbr = fn_png_get_io_ptr (png_ptr);
if (length > tbr->len - tbr->index)
fn_png_error (png_ptr, "Read error");
static void
png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length)
{
- FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
+ FILE *fp = fn_png_get_io_ptr (png_ptr);
if (fread (data, 1, length, fp) < length)
fn_png_error (png_ptr, "Read error");
/* Read image info. */
if (!NILP (specified_data))
- fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
+ fn_png_set_read_fn (png_ptr, &tbr, png_read_from_memory);
else
- fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
+ fn_png_set_read_fn (png_ptr, fp, png_read_from_file);
fn_png_set_sig_bytes (png_ptr, sizeof sig);
fn_png_read_info (png_ptr, info_ptr);
static void
our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
{
- struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
+ struct jpeg_source_mgr *src = cinfo->src;
if (src)
{
static void
jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
{
- struct jpeg_source_mgr *src;
+ struct jpeg_source_mgr *src = cinfo->src;
- if (cinfo->src == NULL)
+ if (! src)
{
/* First time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof (struct jpeg_source_mgr));
- src = (struct jpeg_source_mgr *) cinfo->src;
+ src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT, sizeof *src);
+ cinfo->src = src;
src->next_input_byte = data;
}
- src = (struct jpeg_source_mgr *) cinfo->src;
src->init_source = our_common_init_source;
src->fill_input_buffer = our_memory_fill_input_buffer;
src->skip_input_data = our_memory_skip_input_data;
static void
jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
{
- struct jpeg_stdio_mgr *src;
+ struct jpeg_stdio_mgr *src = (struct jpeg_stdio_mgr *) cinfo->src;
- if (cinfo->src != NULL)
- src = (struct jpeg_stdio_mgr *) cinfo->src;
- else
+ if (! src)
{
/* First time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof (struct jpeg_stdio_mgr));
- src = (struct jpeg_stdio_mgr *) cinfo->src;
- src->buffer = (JOCTET *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- JPEG_STDIO_BUFFER_SIZE);
+ src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT, sizeof *src);
+ cinfo->src = (struct jpeg_source_mgr *) src;
+ src->buffer = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT,
+ JPEG_STDIO_BUFFER_SIZE);
}
src->file = fp;
#ifdef HAVE_GIF
+/* Giflib before 5.0 didn't define these macros. */
+#ifndef GIFLIB_MAJOR
+#define GIFLIB_MAJOR 4
+#endif
+
#if defined (HAVE_NTGUI)
+
+/* Giflib before 5.0 didn't define these macros (used only if HAVE_NTGUI). */
+#ifndef GIFLIB_MINOR
+#define GIFLIB_MINOR 0
+#endif
+#ifndef GIFLIB_RELEASE
+#define GIFLIB_RELEASE 0
+#endif
+
/* winuser.h might define DrawText to DrawTextA or DrawTextW.
Undefine before redefining to avoid a preprocessor warning. */
#ifdef DrawText
#endif /* HAVE_NTGUI */
-
#ifdef WINDOWSNT
/* GIF library details. */
DEF_IMGLIB_FN (int, DGifCloseFile, (GifFileType *));
DEF_IMGLIB_FN (int, DGifSlurp, (GifFileType *));
+#if GIFLIB_MAJOR < 5
DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc));
DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *));
+#else
+DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *));
+DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *, int *));
+DEF_IMGLIB_FN (char *, GifErrorString, (int));
+#endif
static bool
init_gif_functions (void)
LOAD_IMGLIB_FN (library, DGifSlurp);
LOAD_IMGLIB_FN (library, DGifOpen);
LOAD_IMGLIB_FN (library, DGifOpenFileName);
+#if GIFLIB_MAJOR >= 5
+ LOAD_IMGLIB_FN (library, GifErrorString);
+#endif
return 1;
}
#define fn_DGifSlurp DGifSlurp
#define fn_DGifOpen DGifOpen
#define fn_DGifOpenFileName DGifOpenFileName
+#if 5 <= GIFLIB_MAJOR
+# define fn_GifErrorString GifErrorString
+#endif
#endif /* WINDOWSNT */
Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
unsigned long bgcolor = 0;
EMACS_INT idx;
+#if GIFLIB_MAJOR >= 5
+ int gif_err;
+#endif
if (NILP (specified_data))
{
}
/* Open the GIF file. */
+#if GIFLIB_MAJOR < 5
gif = fn_DGifOpenFileName (SSDATA (file));
if (gif == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
return 0;
}
+#else
+ gif = fn_DGifOpenFileName (SSDATA (file), &gif_err);
+ if (gif == NULL)
+ {
+ image_error ("Cannot open `%s': %s",
+ file, build_string (fn_GifErrorString (gif_err)));
+ return 0;
+ }
+#endif
}
else
{
memsrc.len = SBYTES (specified_data);
memsrc.index = 0;
+#if GIFLIB_MAJOR < 5
gif = fn_DGifOpen (&memsrc, gif_read_from_memory);
if (!gif)
{
image_error ("Cannot open memory source `%s'", img->spec, Qnil);
return 0;
}
+#else
+ gif = fn_DGifOpen (&memsrc, gif_read_from_memory, &gif_err);
+ if (!gif)
+ {
+ image_error ("Cannot open memory source `%s': %s",
+ img->spec, build_string (fn_GifErrorString (gif_err)));
+ return 0;
+ }
+#endif
}
/* Before reading entire contents, check the declared image size. */
{
while (subimg_height <= row)
{
- lint_assume (pass < 3);
+ assume (pass < 3);
row = interlace_start[++pass];
}
IMAGEMAGICK_WIDTH,
IMAGEMAGICK_MAX_HEIGHT,
IMAGEMAGICK_MAX_WIDTH,
+ IMAGEMAGICK_FORMAT,
IMAGEMAGICK_ROTATION,
IMAGEMAGICK_CROP,
IMAGEMAGICK_LAST
{":width", IMAGE_INTEGER_VALUE, 0},
{":max-height", IMAGE_INTEGER_VALUE, 0},
{":max-width", IMAGE_INTEGER_VALUE, 0},
+ {":format", IMAGE_SYMBOL_VALUE, 0},
{":rotation", IMAGE_NUMBER_VALUE, 0},
{":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
};
description = (char *) MagickRelinquishMemory (description);
}
+/* Possibly give ImageMagick some extra help to determine the image
+ type by supplying a "dummy" filename based on the Content-Type. */
+
+static char *
+imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent])
+{
+ Lisp_Object symbol = intern ("image-format-suffixes");
+ Lisp_Object val = find_symbol_value (symbol);
+ Lisp_Object format;
+
+ if (! CONSP (val))
+ return NULL;
+
+ format = image_spec_value (spec, intern (":format"), NULL);
+ val = Fcar_safe (Fcdr_safe (Fassq (format, val)));
+ if (! STRINGP (val))
+ return NULL;
+
+ /* It's OK to truncate the hint if it has MaxTextExtent or more bytes,
+ as ImageMagick would ignore the extra bytes anyway. */
+ snprintf (hint_buffer, MaxTextExtent, "/tmp/foo.%s", SSDATA (val));
+ return hint_buffer;
+}
+
+/* Animated images (e.g., GIF89a) are composed from one "master image"
+ (which is the first one, and then there's a number of images that
+ follow. If following images have non-transparent colors, these are
+ composed "on top" of the master image. So, in general, one has to
+ compute ann the preceding images to be able to display a particular
+ sub-image.
+
+ Computing all the preceding images is too slow, so we maintain a
+ cache of previously computed images. We have to maintain a cache
+ separate from the image cache, because the images may be scaled
+ before display. */
+
+struct animation_cache
+{
+ MagickWand *wand;
+ int index;
+ struct timespec update_time;
+ struct animation_cache *next;
+ char signature[FLEXIBLE_ARRAY_MEMBER];
+};
+
+static struct animation_cache *animation_cache = NULL;
+
+static struct animation_cache *
+imagemagick_create_cache (char *signature)
+{
+ struct animation_cache *cache
+ = xmalloc (offsetof (struct animation_cache, signature)
+ + strlen (signature) + 1);
+ cache->wand = 0;
+ cache->index = 0;
+ cache->next = 0;
+ strcpy (cache->signature, signature);
+ return cache;
+}
+
+/* Discard cached images that haven't been used for a minute. */
+static void
+imagemagick_prune_animation_cache (void)
+{
+ struct animation_cache **pcache = &animation_cache;
+ struct timespec old = timespec_sub (current_timespec (),
+ make_timespec (60, 0));
+
+ while (*pcache)
+ {
+ struct animation_cache *cache = *pcache;
+ if (timespec_cmp (old, cache->update_time) <= 0)
+ pcache = &cache->next;
+ else
+ {
+ if (cache->wand)
+ DestroyMagickWand (cache->wand);
+ *pcache = cache->next;
+ xfree (cache);
+ }
+ }
+}
+
+static struct animation_cache *
+imagemagick_get_animation_cache (MagickWand *wand)
+{
+ char *signature = MagickGetImageSignature (wand);
+ struct animation_cache *cache;
+ struct animation_cache **pcache = &animation_cache;
+
+ imagemagick_prune_animation_cache ();
+
+ while (1)
+ {
+ cache = *pcache;
+ if (! cache)
+ {
+ *pcache = cache = imagemagick_create_cache (signature);
+ break;
+ }
+ if (strcmp (signature, cache->signature) == 0)
+ break;
+ pcache = &cache->next;
+ }
+
+ DestroyString (signature);
+ cache->update_time = current_timespec ();
+ return cache;
+}
+
+static MagickWand *
+imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
+{
+ int i;
+ MagickWand *composite_wand;
+ size_t dest_width, dest_height;
+ struct animation_cache *cache = imagemagick_get_animation_cache (super_wand);
+
+ MagickSetIteratorIndex (super_wand, 0);
+
+ if (ino == 0 || cache->wand == NULL || cache->index > ino)
+ {
+ composite_wand = MagickGetImage (super_wand);
+ if (cache->wand)
+ DestroyMagickWand (cache->wand);
+ }
+ else
+ composite_wand = cache->wand;
+
+ dest_width = MagickGetImageWidth (composite_wand);
+ dest_height = MagickGetImageHeight (composite_wand);
+
+ for (i = max (1, cache->index + 1); i <= ino; i++)
+ {
+ MagickWand *sub_wand;
+ PixelIterator *source_iterator, *dest_iterator;
+ PixelWand **source, **dest;
+ size_t source_width, source_height;
+ ssize_t source_left, source_top;
+ MagickPixelPacket pixel;
+ DisposeType dispose;
+ ptrdiff_t lines = 0;
+
+ MagickSetIteratorIndex (super_wand, i);
+ sub_wand = MagickGetImage (super_wand);
+
+ MagickGetImagePage (sub_wand, &source_width, &source_height,
+ &source_left, &source_top);
+
+ /* This flag says how to handle transparent pixels. */
+ dispose = MagickGetImageDispose (sub_wand);
+
+ source_iterator = NewPixelIterator (sub_wand);
+ if (! source_iterator)
+ {
+ DestroyMagickWand (composite_wand);
+ DestroyMagickWand (sub_wand);
+ cache->wand = NULL;
+ image_error ("Imagemagick pixel iterator creation failed",
+ Qnil, Qnil);
+ return NULL;
+ }
+
+ dest_iterator = NewPixelIterator (composite_wand);
+ if (! dest_iterator)
+ {
+ DestroyMagickWand (composite_wand);
+ DestroyMagickWand (sub_wand);
+ DestroyPixelIterator (source_iterator);
+ cache->wand = NULL;
+ image_error ("Imagemagick pixel iterator creation failed",
+ Qnil, Qnil);
+ return NULL;
+ }
+
+ /* The sub-image may not start at origin, so move the destination
+ iterator to where the sub-image should start. */
+ if (source_top > 0)
+ {
+ PixelSetIteratorRow (dest_iterator, source_top);
+ lines = source_top;
+ }
+
+ while ((source = PixelGetNextIteratorRow (source_iterator, &source_width))
+ != NULL)
+ {
+ ptrdiff_t x;
+
+ /* Sanity check. This shouldn't happen, but apparently
+ does in some pictures. */
+ if (++lines >= dest_height)
+ break;
+
+ dest = PixelGetNextIteratorRow (dest_iterator, &dest_width);
+ for (x = 0; x < source_width; x++)
+ {
+ /* Sanity check. This shouldn't happen, but apparently
+ also does in some pictures. */
+ if (x + source_left > dest_width)
+ break;
+ /* Normally we only copy over non-transparent pixels,
+ but if the disposal method is "Background", then we
+ copy over all pixels. */
+ if (dispose == BackgroundDispose ||
+ PixelGetAlpha (source[x]))
+ {
+ PixelGetMagickColor (source[x], &pixel);
+ PixelSetMagickColor (dest[x + source_left], &pixel);
+ }
+ }
+ PixelSyncIterator (dest_iterator);
+ }
+
+ DestroyPixelIterator (source_iterator);
+ DestroyPixelIterator (dest_iterator);
+ DestroyMagickWand (sub_wand);
+ }
+
+ /* Cache a copy for the next iteration. The current wand will be
+ destroyed by the caller. */
+ cache->wand = CloneMagickWand (composite_wand);
+ cache->index = ino;
+
+ return composite_wand;
+}
+
+
/* Helper function for imagemagick_load, which does the actual loading
given contents and size, apart from frame and image structures,
passed from imagemagick_load. Uses librimagemagick to do most of
XImagePtr ximg;
int x, y;
MagickWand *image_wand;
- MagickWand *ping_wand;
PixelIterator *iterator;
PixelWand **pixels, *bg_wand = NULL;
MagickPixelPacket pixel;
int desired_width, desired_height;
double rotation;
int pixelwidth;
+ char hint_buffer[MaxTextExtent];
+ char *filename_hint = NULL;
/* Handle image index for image types who can contain more than one image.
Interface :index is same as for GIF. First we "ping" the image to see how
MagickWandGenesis ();
image = image_spec_value (img->spec, QCindex, NULL);
ino = INTEGERP (image) ? XFASTINT (image) : 0;
- ping_wand = NewMagickWand ();
- /* MagickSetResolution (ping_wand, 2, 2); (Bug#10112) */
+ image_wand = NewMagickWand ();
- status = filename
- ? MagickPingImage (ping_wand, filename)
- : MagickPingImageBlob (ping_wand, contents, size);
+ if (filename)
+ status = MagickReadImage (image_wand, filename);
+ else
+ {
+ filename_hint = imagemagick_filename_hint (img->spec, hint_buffer);
+ MagickSetFilename (image_wand, filename_hint);
+ status = MagickReadImageBlob (image_wand, contents, size);
+ }
if (status == MagickFalse)
{
- imagemagick_error (ping_wand);
- DestroyMagickWand (ping_wand);
+ imagemagick_error (image_wand);
+ DestroyMagickWand (image_wand);
return 0;
}
- if (ino < 0 || ino >= MagickGetNumberImages (ping_wand))
+ if (ino < 0 || ino >= MagickGetNumberImages (image_wand))
{
image_error ("Invalid image number `%s' in image `%s'",
image, img->spec);
- DestroyMagickWand (ping_wand);
+ DestroyMagickWand (image_wand);
return 0;
}
- if (MagickGetNumberImages (ping_wand) > 1)
+ if (MagickGetNumberImages (image_wand) > 1)
img->lisp_data =
Fcons (Qcount,
- Fcons (make_number (MagickGetNumberImages (ping_wand)),
+ Fcons (make_number (MagickGetNumberImages (image_wand)),
img->lisp_data));
- DestroyMagickWand (ping_wand);
-
- /* Now we know how many images are inside the file. If it's not a
- bundle, the number is one. Load the image data. */
-
- image_wand = NewMagickWand ();
-
- if ((filename
- ? MagickReadImage (image_wand, filename)
- : MagickReadImageBlob (image_wand, contents, size))
- == MagickFalse)
+ /* If we have an animated image, get the new wand based on the
+ "super-wand". */
+ if (MagickGetNumberImages (image_wand) > 1)
{
- imagemagick_error (image_wand);
- goto imagemagick_error;
+ MagickWand *super_wand = image_wand;
+ image_wand = imagemagick_compute_animated_image (super_wand, ino);
+ if (! image_wand)
+ image_wand = super_wand;
+ else
+ DestroyMagickWand (super_wand);
}
/* Retrieve the frame's background color, for use later. */
/* Copy pixels from the imagemagick image structure to the x image map. */
iterator = NewPixelIterator (image_wand);
- if (iterator == (PixelIterator *) NULL)
+ if (! iterator)
{
#ifdef COLOR_TABLE_SUPPORT
free_color_table ();
for (y = 0; y < image_height; y++)
{
pixels = PixelGetNextIteratorRow (iterator, &width);
- if (pixels == (PixelWand **) NULL)
+ if (! pixels)
break;
for (x = 0; x < (long) width; x++)
{
DEF_IMGLIB_FN (gboolean, gdk_pixbuf_get_has_alpha, (const GdkPixbuf *));
DEF_IMGLIB_FN (int, gdk_pixbuf_get_bits_per_sample, (const GdkPixbuf *));
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
DEF_IMGLIB_FN (void, g_type_init, (void));
+#endif
DEF_IMGLIB_FN (void, g_object_unref, (gpointer));
DEF_IMGLIB_FN (void, g_error_free, (GError *));
LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_has_alpha);
LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
LOAD_IMGLIB_FN (gobject, g_type_init);
+#endif
LOAD_IMGLIB_FN (gobject, g_object_unref);
LOAD_IMGLIB_FN (glib, g_error_free);
#define fn_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha
#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
#define fn_g_type_init g_type_init
+#endif
#define fn_g_object_unref g_object_unref
#define fn_g_error_free g_error_free
#endif /* !WINDOWSNT */
int x;
int y;
- /* g_type_init is a glib function that must be called prior to using
- gnome type library functions. */
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
+ /* g_type_init is a glib function that must be called prior to
+ using gnome type library functions (obsolete since 2.36.0). */
fn_g_type_init ();
+#endif
+
/* Make a handle to a new rsvg object. */
rsvg_handle = fn_rsvg_handle_new ();
make_number (PNG_LIBPNG_VER)
#else
make_number (-1)
+#endif
+ );
+ DEFSYM (Qlibgif_version, "libgif-version");
+ Fset (Qlibgif_version,
+#ifdef HAVE_GIF
+ make_number (GIFLIB_MAJOR * 10000
+ + GIFLIB_MINOR * 100
+ + GIFLIB_RELEASE)
+#else
+ make_number (-1)
#endif
);
#endif
DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path,
doc: /* List of directories to search for window system bitmap files. */);
- Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
+ Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS);
DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
doc: /* Maximum time after which images are removed from the cache.