diff options
Diffstat (limited to 'src/image.c')
| -rw-r--r-- | src/image.c | 399 |
1 files changed, 309 insertions, 90 deletions
diff --git a/src/image.c b/src/image.c index 911ca8e6681..1271376bcab 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -30,13 +30,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| 32 | #include <setjmp.h> | 32 | #include <setjmp.h> |
| 33 | |||
| 34 | #include <c-ctype.h> | 33 | #include <c-ctype.h> |
| 35 | 34 | ||
| 36 | /* This makes the fields of a Display accessible, in Xlib header files. */ | ||
| 37 | |||
| 38 | #define XLIB_ILLEGAL_ACCESS | ||
| 39 | |||
| 40 | #include "lisp.h" | 35 | #include "lisp.h" |
| 41 | #include "frame.h" | 36 | #include "frame.h" |
| 42 | #include "window.h" | 37 | #include "window.h" |
| @@ -145,7 +140,7 @@ static Lisp_Object QCmax_width, QCmax_height; | |||
| 145 | 140 | ||
| 146 | #ifdef HAVE_NS | 141 | #ifdef HAVE_NS |
| 147 | /* Use with images created by ns_image_for_XPM. */ | 142 | /* Use with images created by ns_image_for_XPM. */ |
| 148 | unsigned long | 143 | static unsigned long |
| 149 | XGetPixel (XImagePtr ximage, int x, int y) | 144 | XGetPixel (XImagePtr ximage, int x, int y) |
| 150 | { | 145 | { |
| 151 | return ns_get_pixel (ximage, x, y); | 146 | return ns_get_pixel (ximage, x, y); |
| @@ -153,7 +148,7 @@ XGetPixel (XImagePtr ximage, int x, int y) | |||
| 153 | 148 | ||
| 154 | /* Use with images created by ns_image_for_XPM; alpha set to 1; | 149 | /* Use with images created by ns_image_for_XPM; alpha set to 1; |
| 155 | pixel is assumed to be in RGB form. */ | 150 | pixel is assumed to be in RGB form. */ |
| 156 | void | 151 | static void |
| 157 | XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel) | 152 | XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel) |
| 158 | { | 153 | { |
| 159 | ns_put_pixel (ximage, x, y, pixel); | 154 | ns_put_pixel (ximage, x, y, pixel); |
| @@ -302,11 +297,10 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) | |||
| 302 | id = x_allocate_bitmap_record (f); | 297 | id = x_allocate_bitmap_record (f); |
| 303 | dpyinfo->bitmaps[id - 1].img = bitmap; | 298 | dpyinfo->bitmaps[id - 1].img = bitmap; |
| 304 | dpyinfo->bitmaps[id - 1].refcount = 1; | 299 | dpyinfo->bitmaps[id - 1].refcount = 1; |
| 305 | dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1); | 300 | dpyinfo->bitmaps[id - 1].file = xlispstrdup (file); |
| 306 | dpyinfo->bitmaps[id - 1].depth = 1; | 301 | dpyinfo->bitmaps[id - 1].depth = 1; |
| 307 | dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap); | 302 | dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap); |
| 308 | dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap); | 303 | dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap); |
| 309 | strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file)); | ||
| 310 | return id; | 304 | return id; |
| 311 | #endif | 305 | #endif |
| 312 | 306 | ||
| @@ -345,11 +339,10 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) | |||
| 345 | dpyinfo->bitmaps[id - 1].pixmap = bitmap; | 339 | dpyinfo->bitmaps[id - 1].pixmap = bitmap; |
| 346 | dpyinfo->bitmaps[id - 1].have_mask = 0; | 340 | dpyinfo->bitmaps[id - 1].have_mask = 0; |
| 347 | dpyinfo->bitmaps[id - 1].refcount = 1; | 341 | dpyinfo->bitmaps[id - 1].refcount = 1; |
| 348 | dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1); | 342 | dpyinfo->bitmaps[id - 1].file = xlispstrdup (file); |
| 349 | dpyinfo->bitmaps[id - 1].depth = 1; | 343 | dpyinfo->bitmaps[id - 1].depth = 1; |
| 350 | dpyinfo->bitmaps[id - 1].height = height; | 344 | dpyinfo->bitmaps[id - 1].height = height; |
| 351 | dpyinfo->bitmaps[id - 1].width = width; | 345 | dpyinfo->bitmaps[id - 1].width = width; |
| 352 | strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file)); | ||
| 353 | 346 | ||
| 354 | return id; | 347 | return id; |
| 355 | #endif /* HAVE_X_WINDOWS */ | 348 | #endif /* HAVE_X_WINDOWS */ |
| @@ -565,7 +558,6 @@ static void x_emboss (struct frame *, struct image *); | |||
| 565 | static void x_build_heuristic_mask (struct frame *, struct image *, | 558 | static void x_build_heuristic_mask (struct frame *, struct image *, |
| 566 | Lisp_Object); | 559 | Lisp_Object); |
| 567 | #ifdef WINDOWSNT | 560 | #ifdef WINDOWSNT |
| 568 | extern Lisp_Object Vlibrary_cache; | ||
| 569 | #define CACHE_IMAGE_TYPE(type, status) \ | 561 | #define CACHE_IMAGE_TYPE(type, status) \ |
| 570 | do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0) | 562 | do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0) |
| 571 | #else | 563 | #else |
| @@ -1044,7 +1036,7 @@ void | |||
| 1044 | prepare_image_for_display (struct frame *f, struct image *img) | 1036 | prepare_image_for_display (struct frame *f, struct image *img) |
| 1045 | { | 1037 | { |
| 1046 | /* We're about to display IMG, so set its timestamp to `now'. */ | 1038 | /* We're about to display IMG, so set its timestamp to `now'. */ |
| 1047 | img->timestamp = current_emacs_time (); | 1039 | img->timestamp = current_timespec (); |
| 1048 | 1040 | ||
| 1049 | /* If IMG doesn't have a pixmap yet, load it now, using the image | 1041 | /* If IMG doesn't have a pixmap yet, load it now, using the image |
| 1050 | type dependent loader function. */ | 1042 | type dependent loader function. */ |
| @@ -1362,14 +1354,12 @@ static void cache_image (struct frame *f, struct image *img); | |||
| 1362 | struct image_cache * | 1354 | struct image_cache * |
| 1363 | make_image_cache (void) | 1355 | make_image_cache (void) |
| 1364 | { | 1356 | { |
| 1365 | struct image_cache *c = xzalloc (sizeof *c); | 1357 | struct image_cache *c = xmalloc (sizeof *c); |
| 1366 | int size; | ||
| 1367 | 1358 | ||
| 1368 | size = 50; | 1359 | c->size = 50; |
| 1369 | c->images = xmalloc (size * sizeof *c->images); | 1360 | c->used = c->refcount = 0; |
| 1370 | c->size = size; | 1361 | c->images = xmalloc (c->size * sizeof *c->images); |
| 1371 | size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; | 1362 | c->buckets = xzalloc (IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets); |
| 1372 | c->buckets = xzalloc (size); | ||
| 1373 | return c; | 1363 | return c; |
| 1374 | } | 1364 | } |
| 1375 | 1365 | ||
| @@ -1485,7 +1475,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter) | |||
| 1485 | else if (INTEGERP (Vimage_cache_eviction_delay)) | 1475 | else if (INTEGERP (Vimage_cache_eviction_delay)) |
| 1486 | { | 1476 | { |
| 1487 | /* Free cache based on timestamp. */ | 1477 | /* Free cache based on timestamp. */ |
| 1488 | EMACS_TIME old, t; | 1478 | struct timespec old, t; |
| 1489 | double delay; | 1479 | double delay; |
| 1490 | ptrdiff_t nimages = 0; | 1480 | ptrdiff_t nimages = 0; |
| 1491 | 1481 | ||
| @@ -1500,13 +1490,13 @@ clear_image_cache (struct frame *f, Lisp_Object filter) | |||
| 1500 | delay = 1600 * delay / nimages / nimages; | 1490 | delay = 1600 * delay / nimages / nimages; |
| 1501 | delay = max (delay, 1); | 1491 | delay = max (delay, 1); |
| 1502 | 1492 | ||
| 1503 | t = current_emacs_time (); | 1493 | t = current_timespec (); |
| 1504 | old = sub_emacs_time (t, EMACS_TIME_FROM_DOUBLE (delay)); | 1494 | old = timespec_sub (t, dtotimespec (delay)); |
| 1505 | 1495 | ||
| 1506 | for (i = 0; i < c->used; ++i) | 1496 | for (i = 0; i < c->used; ++i) |
| 1507 | { | 1497 | { |
| 1508 | struct image *img = c->images[i]; | 1498 | struct image *img = c->images[i]; |
| 1509 | if (img && EMACS_TIME_LT (img->timestamp, old)) | 1499 | if (img && timespec_cmp (img->timestamp, old) < 0) |
| 1510 | { | 1500 | { |
| 1511 | free_image (f, img); | 1501 | free_image (f, img); |
| 1512 | ++nfreed; | 1502 | ++nfreed; |
| @@ -1769,7 +1759,7 @@ lookup_image (struct frame *f, Lisp_Object spec) | |||
| 1769 | } | 1759 | } |
| 1770 | 1760 | ||
| 1771 | /* We're using IMG, so set its timestamp to `now'. */ | 1761 | /* We're using IMG, so set its timestamp to `now'. */ |
| 1772 | img->timestamp = current_emacs_time (); | 1762 | img->timestamp = current_timespec (); |
| 1773 | 1763 | ||
| 1774 | /* Value is the image id. */ | 1764 | /* Value is the image id. */ |
| 1775 | return img->id; | 1765 | return img->id; |
| @@ -2717,10 +2707,13 @@ xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *e | |||
| 2717 | LA1 = xbm_scan (&s, end, buffer, &value) | 2707 | LA1 = xbm_scan (&s, end, buffer, &value) |
| 2718 | 2708 | ||
| 2719 | #define expect(TOKEN) \ | 2709 | #define expect(TOKEN) \ |
| 2720 | if (LA1 != (TOKEN)) \ | 2710 | do \ |
| 2721 | goto failure; \ | 2711 | { \ |
| 2722 | else \ | 2712 | if (LA1 != (TOKEN)) \ |
| 2723 | match () | 2713 | goto failure; \ |
| 2714 | match (); \ | ||
| 2715 | } \ | ||
| 2716 | while (0) | ||
| 2724 | 2717 | ||
| 2725 | #define expect_ident(IDENT) \ | 2718 | #define expect_ident(IDENT) \ |
| 2726 | if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ | 2719 | if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ |
| @@ -3332,7 +3325,7 @@ static int | |||
| 3332 | xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color, | 3325 | xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color, |
| 3333 | void *closure) | 3326 | void *closure) |
| 3334 | { | 3327 | { |
| 3335 | return xpm_lookup_color ((struct frame *) closure, color_name, color); | 3328 | return xpm_lookup_color (closure, color_name, color); |
| 3336 | } | 3329 | } |
| 3337 | 3330 | ||
| 3338 | 3331 | ||
| @@ -3980,10 +3973,13 @@ xpm_load_image (struct frame *f, | |||
| 3980 | LA1 = xpm_scan (&s, end, &beg, &len) | 3973 | LA1 = xpm_scan (&s, end, &beg, &len) |
| 3981 | 3974 | ||
| 3982 | #define expect(TOKEN) \ | 3975 | #define expect(TOKEN) \ |
| 3983 | if (LA1 != (TOKEN)) \ | 3976 | do \ |
| 3984 | goto failure; \ | 3977 | { \ |
| 3985 | else \ | 3978 | if (LA1 != (TOKEN)) \ |
| 3986 | match () | 3979 | goto failure; \ |
| 3980 | match (); \ | ||
| 3981 | } \ | ||
| 3982 | while (0) | ||
| 3987 | 3983 | ||
| 3988 | #define expect_ident(IDENT) \ | 3984 | #define expect_ident(IDENT) \ |
| 3989 | if (LA1 == XPM_TK_IDENT \ | 3985 | if (LA1 == XPM_TK_IDENT \ |
| @@ -4936,7 +4932,7 @@ x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how) | |||
| 4936 | int row_width; | 4932 | int row_width; |
| 4937 | #endif /* HAVE_NTGUI */ | 4933 | #endif /* HAVE_NTGUI */ |
| 4938 | int x, y; | 4934 | int x, y; |
| 4939 | bool rc, use_img_background; | 4935 | bool use_img_background; |
| 4940 | unsigned long bg = 0; | 4936 | unsigned long bg = 0; |
| 4941 | 4937 | ||
| 4942 | if (img->mask) | 4938 | if (img->mask) |
| @@ -4945,9 +4941,8 @@ x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how) | |||
| 4945 | #ifndef HAVE_NTGUI | 4941 | #ifndef HAVE_NTGUI |
| 4946 | #ifndef HAVE_NS | 4942 | #ifndef HAVE_NS |
| 4947 | /* Create an image and pixmap serving as mask. */ | 4943 | /* Create an image and pixmap serving as mask. */ |
| 4948 | rc = image_create_x_image_and_pixmap (f, img, img->width, img->height, 1, | 4944 | if (! image_create_x_image_and_pixmap (f, img, img->width, img->height, 1, |
| 4949 | &mask_img, 1); | 4945 | &mask_img, 1)) |
| 4950 | if (!rc) | ||
| 4951 | return; | 4946 | return; |
| 4952 | #endif /* !HAVE_NS */ | 4947 | #endif /* !HAVE_NS */ |
| 4953 | #else | 4948 | #else |
| @@ -5652,8 +5647,7 @@ struct png_memory_storage | |||
| 5652 | static void | 5647 | static void |
| 5653 | png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length) | 5648 | png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length) |
| 5654 | { | 5649 | { |
| 5655 | struct png_memory_storage *tbr | 5650 | struct png_memory_storage *tbr = fn_png_get_io_ptr (png_ptr); |
| 5656 | = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr); | ||
| 5657 | 5651 | ||
| 5658 | if (length > tbr->len - tbr->index) | 5652 | if (length > tbr->len - tbr->index) |
| 5659 | fn_png_error (png_ptr, "Read error"); | 5653 | fn_png_error (png_ptr, "Read error"); |
| @@ -5670,7 +5664,7 @@ png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length) | |||
| 5670 | static void | 5664 | static void |
| 5671 | png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length) | 5665 | png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length) |
| 5672 | { | 5666 | { |
| 5673 | FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr); | 5667 | FILE *fp = fn_png_get_io_ptr (png_ptr); |
| 5674 | 5668 | ||
| 5675 | if (fread (data, 1, length, fp) < length) | 5669 | if (fread (data, 1, length, fp) < length) |
| 5676 | fn_png_error (png_ptr, "Read error"); | 5670 | fn_png_error (png_ptr, "Read error"); |
| @@ -5814,9 +5808,9 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) | |||
| 5814 | 5808 | ||
| 5815 | /* Read image info. */ | 5809 | /* Read image info. */ |
| 5816 | if (!NILP (specified_data)) | 5810 | if (!NILP (specified_data)) |
| 5817 | fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); | 5811 | fn_png_set_read_fn (png_ptr, &tbr, png_read_from_memory); |
| 5818 | else | 5812 | else |
| 5819 | fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file); | 5813 | fn_png_set_read_fn (png_ptr, fp, png_read_from_file); |
| 5820 | 5814 | ||
| 5821 | fn_png_set_sig_bytes (png_ptr, sizeof sig); | 5815 | fn_png_set_sig_bytes (png_ptr, sizeof sig); |
| 5822 | fn_png_read_info (png_ptr, info_ptr); | 5816 | fn_png_read_info (png_ptr, info_ptr); |
| @@ -6306,7 +6300,7 @@ our_memory_fill_input_buffer (j_decompress_ptr cinfo) | |||
| 6306 | static void | 6300 | static void |
| 6307 | our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes) | 6301 | our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes) |
| 6308 | { | 6302 | { |
| 6309 | struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; | 6303 | struct jpeg_source_mgr *src = cinfo->src; |
| 6310 | 6304 | ||
| 6311 | if (src) | 6305 | if (src) |
| 6312 | { | 6306 | { |
| @@ -6326,19 +6320,17 @@ our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes) | |||
| 6326 | static void | 6320 | static void |
| 6327 | jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len) | 6321 | jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len) |
| 6328 | { | 6322 | { |
| 6329 | struct jpeg_source_mgr *src; | 6323 | struct jpeg_source_mgr *src = cinfo->src; |
| 6330 | 6324 | ||
| 6331 | if (cinfo->src == NULL) | 6325 | if (! src) |
| 6332 | { | 6326 | { |
| 6333 | /* First time for this JPEG object? */ | 6327 | /* First time for this JPEG object? */ |
| 6334 | cinfo->src = (struct jpeg_source_mgr *) | 6328 | src = cinfo->mem->alloc_small ((j_common_ptr) cinfo, |
| 6335 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | 6329 | JPOOL_PERMANENT, sizeof *src); |
| 6336 | sizeof (struct jpeg_source_mgr)); | 6330 | cinfo->src = src; |
| 6337 | src = (struct jpeg_source_mgr *) cinfo->src; | ||
| 6338 | src->next_input_byte = data; | 6331 | src->next_input_byte = data; |
| 6339 | } | 6332 | } |
| 6340 | 6333 | ||
| 6341 | src = (struct jpeg_source_mgr *) cinfo->src; | ||
| 6342 | src->init_source = our_common_init_source; | 6334 | src->init_source = our_common_init_source; |
| 6343 | src->fill_input_buffer = our_memory_fill_input_buffer; | 6335 | src->fill_input_buffer = our_memory_fill_input_buffer; |
| 6344 | src->skip_input_data = our_memory_skip_input_data; | 6336 | src->skip_input_data = our_memory_skip_input_data; |
| @@ -6430,20 +6422,17 @@ our_stdio_skip_input_data (j_decompress_ptr cinfo, long int num_bytes) | |||
| 6430 | static void | 6422 | static void |
| 6431 | jpeg_file_src (j_decompress_ptr cinfo, FILE *fp) | 6423 | jpeg_file_src (j_decompress_ptr cinfo, FILE *fp) |
| 6432 | { | 6424 | { |
| 6433 | struct jpeg_stdio_mgr *src; | 6425 | struct jpeg_stdio_mgr *src = (struct jpeg_stdio_mgr *) cinfo->src; |
| 6434 | 6426 | ||
| 6435 | if (cinfo->src != NULL) | 6427 | if (! src) |
| 6436 | src = (struct jpeg_stdio_mgr *) cinfo->src; | ||
| 6437 | else | ||
| 6438 | { | 6428 | { |
| 6439 | /* First time for this JPEG object? */ | 6429 | /* First time for this JPEG object? */ |
| 6440 | cinfo->src = (struct jpeg_source_mgr *) | 6430 | src = cinfo->mem->alloc_small ((j_common_ptr) cinfo, |
| 6441 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | 6431 | JPOOL_PERMANENT, sizeof *src); |
| 6442 | sizeof (struct jpeg_stdio_mgr)); | 6432 | cinfo->src = (struct jpeg_source_mgr *) src; |
| 6443 | src = (struct jpeg_stdio_mgr *) cinfo->src; | 6433 | src->buffer = cinfo->mem->alloc_small ((j_common_ptr) cinfo, |
| 6444 | src->buffer = (JOCTET *) | 6434 | JPOOL_PERMANENT, |
| 6445 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | 6435 | JPEG_STDIO_BUFFER_SIZE); |
| 6446 | JPEG_STDIO_BUFFER_SIZE); | ||
| 6447 | } | 6436 | } |
| 6448 | 6437 | ||
| 6449 | src->file = fp; | 6438 | src->file = fp; |
| @@ -7746,6 +7735,7 @@ enum imagemagick_keyword_index | |||
| 7746 | IMAGEMAGICK_WIDTH, | 7735 | IMAGEMAGICK_WIDTH, |
| 7747 | IMAGEMAGICK_MAX_HEIGHT, | 7736 | IMAGEMAGICK_MAX_HEIGHT, |
| 7748 | IMAGEMAGICK_MAX_WIDTH, | 7737 | IMAGEMAGICK_MAX_WIDTH, |
| 7738 | IMAGEMAGICK_FORMAT, | ||
| 7749 | IMAGEMAGICK_ROTATION, | 7739 | IMAGEMAGICK_ROTATION, |
| 7750 | IMAGEMAGICK_CROP, | 7740 | IMAGEMAGICK_CROP, |
| 7751 | IMAGEMAGICK_LAST | 7741 | IMAGEMAGICK_LAST |
| @@ -7770,6 +7760,7 @@ static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] = | |||
| 7770 | {":width", IMAGE_INTEGER_VALUE, 0}, | 7760 | {":width", IMAGE_INTEGER_VALUE, 0}, |
| 7771 | {":max-height", IMAGE_INTEGER_VALUE, 0}, | 7761 | {":max-height", IMAGE_INTEGER_VALUE, 0}, |
| 7772 | {":max-width", IMAGE_INTEGER_VALUE, 0}, | 7762 | {":max-width", IMAGE_INTEGER_VALUE, 0}, |
| 7763 | {":format", IMAGE_SYMBOL_VALUE, 0}, | ||
| 7773 | {":rotation", IMAGE_NUMBER_VALUE, 0}, | 7764 | {":rotation", IMAGE_NUMBER_VALUE, 0}, |
| 7774 | {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | 7765 | {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0} |
| 7775 | }; | 7766 | }; |
| @@ -7848,6 +7839,233 @@ imagemagick_error (MagickWand *wand) | |||
| 7848 | description = (char *) MagickRelinquishMemory (description); | 7839 | description = (char *) MagickRelinquishMemory (description); |
| 7849 | } | 7840 | } |
| 7850 | 7841 | ||
| 7842 | /* Possibly give ImageMagick some extra help to determine the image | ||
| 7843 | type by supplying a "dummy" filename based on the Content-Type. */ | ||
| 7844 | |||
| 7845 | static char * | ||
| 7846 | imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent]) | ||
| 7847 | { | ||
| 7848 | Lisp_Object symbol = intern ("image-format-suffixes"); | ||
| 7849 | Lisp_Object val = find_symbol_value (symbol); | ||
| 7850 | Lisp_Object format; | ||
| 7851 | |||
| 7852 | if (! CONSP (val)) | ||
| 7853 | return NULL; | ||
| 7854 | |||
| 7855 | format = image_spec_value (spec, intern (":format"), NULL); | ||
| 7856 | val = Fcar_safe (Fcdr_safe (Fassq (format, val))); | ||
| 7857 | if (! STRINGP (val)) | ||
| 7858 | return NULL; | ||
| 7859 | |||
| 7860 | /* It's OK to truncate the hint if it has MaxTextExtent or more bytes, | ||
| 7861 | as ImageMagick would ignore the extra bytes anyway. */ | ||
| 7862 | snprintf (hint_buffer, MaxTextExtent, "/tmp/foo.%s", SSDATA (val)); | ||
| 7863 | return hint_buffer; | ||
| 7864 | } | ||
| 7865 | |||
| 7866 | /* Animated images (e.g., GIF89a) are composed from one "master image" | ||
| 7867 | (which is the first one, and then there's a number of images that | ||
| 7868 | follow. If following images have non-transparent colors, these are | ||
| 7869 | composed "on top" of the master image. So, in general, one has to | ||
| 7870 | compute ann the preceding images to be able to display a particular | ||
| 7871 | sub-image. | ||
| 7872 | |||
| 7873 | Computing all the preceding images is too slow, so we maintain a | ||
| 7874 | cache of previously computed images. We have to maintain a cache | ||
| 7875 | separate from the image cache, because the images may be scaled | ||
| 7876 | before display. */ | ||
| 7877 | |||
| 7878 | struct animation_cache | ||
| 7879 | { | ||
| 7880 | MagickWand *wand; | ||
| 7881 | int index; | ||
| 7882 | struct timespec update_time; | ||
| 7883 | struct animation_cache *next; | ||
| 7884 | char signature[FLEXIBLE_ARRAY_MEMBER]; | ||
| 7885 | }; | ||
| 7886 | |||
| 7887 | static struct animation_cache *animation_cache = NULL; | ||
| 7888 | |||
| 7889 | static struct animation_cache * | ||
| 7890 | imagemagick_create_cache (char *signature) | ||
| 7891 | { | ||
| 7892 | struct animation_cache *cache | ||
| 7893 | = xmalloc (offsetof (struct animation_cache, signature) | ||
| 7894 | + strlen (signature) + 1); | ||
| 7895 | cache->wand = 0; | ||
| 7896 | cache->index = 0; | ||
| 7897 | cache->next = 0; | ||
| 7898 | strcpy (cache->signature, signature); | ||
| 7899 | return cache; | ||
| 7900 | } | ||
| 7901 | |||
| 7902 | /* Discard cached images that haven't been used for a minute. */ | ||
| 7903 | static void | ||
| 7904 | imagemagick_prune_animation_cache (void) | ||
| 7905 | { | ||
| 7906 | struct animation_cache **pcache = &animation_cache; | ||
| 7907 | struct timespec old = timespec_sub (current_timespec (), | ||
| 7908 | make_timespec (60, 0)); | ||
| 7909 | |||
| 7910 | while (*pcache) | ||
| 7911 | { | ||
| 7912 | struct animation_cache *cache = *pcache; | ||
| 7913 | if (timespec_cmp (old, cache->update_time) <= 0) | ||
| 7914 | pcache = &cache->next; | ||
| 7915 | else | ||
| 7916 | { | ||
| 7917 | if (cache->wand) | ||
| 7918 | DestroyMagickWand (cache->wand); | ||
| 7919 | *pcache = cache->next; | ||
| 7920 | xfree (cache); | ||
| 7921 | } | ||
| 7922 | } | ||
| 7923 | } | ||
| 7924 | |||
| 7925 | static struct animation_cache * | ||
| 7926 | imagemagick_get_animation_cache (MagickWand *wand) | ||
| 7927 | { | ||
| 7928 | char *signature = MagickGetImageSignature (wand); | ||
| 7929 | struct animation_cache *cache; | ||
| 7930 | struct animation_cache **pcache = &animation_cache; | ||
| 7931 | |||
| 7932 | imagemagick_prune_animation_cache (); | ||
| 7933 | |||
| 7934 | while (1) | ||
| 7935 | { | ||
| 7936 | cache = *pcache; | ||
| 7937 | if (! cache) | ||
| 7938 | { | ||
| 7939 | *pcache = cache = imagemagick_create_cache (signature); | ||
| 7940 | break; | ||
| 7941 | } | ||
| 7942 | if (strcmp (signature, cache->signature) == 0) | ||
| 7943 | break; | ||
| 7944 | pcache = &cache->next; | ||
| 7945 | } | ||
| 7946 | |||
| 7947 | DestroyString (signature); | ||
| 7948 | cache->update_time = current_timespec (); | ||
| 7949 | return cache; | ||
| 7950 | } | ||
| 7951 | |||
| 7952 | static MagickWand * | ||
| 7953 | imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | ||
| 7954 | { | ||
| 7955 | int i; | ||
| 7956 | MagickWand *composite_wand; | ||
| 7957 | size_t dest_width, dest_height; | ||
| 7958 | struct animation_cache *cache = imagemagick_get_animation_cache (super_wand); | ||
| 7959 | |||
| 7960 | MagickSetIteratorIndex (super_wand, 0); | ||
| 7961 | |||
| 7962 | if (ino == 0 || cache->wand == NULL || cache->index > ino) | ||
| 7963 | { | ||
| 7964 | composite_wand = MagickGetImage (super_wand); | ||
| 7965 | if (cache->wand) | ||
| 7966 | DestroyMagickWand (cache->wand); | ||
| 7967 | } | ||
| 7968 | else | ||
| 7969 | composite_wand = cache->wand; | ||
| 7970 | |||
| 7971 | dest_width = MagickGetImageWidth (composite_wand); | ||
| 7972 | dest_height = MagickGetImageHeight (composite_wand); | ||
| 7973 | |||
| 7974 | for (i = max (1, cache->index + 1); i <= ino; i++) | ||
| 7975 | { | ||
| 7976 | MagickWand *sub_wand; | ||
| 7977 | PixelIterator *source_iterator, *dest_iterator; | ||
| 7978 | PixelWand **source, **dest; | ||
| 7979 | size_t source_width, source_height; | ||
| 7980 | ssize_t source_left, source_top; | ||
| 7981 | MagickPixelPacket pixel; | ||
| 7982 | DisposeType dispose; | ||
| 7983 | ptrdiff_t lines = 0; | ||
| 7984 | |||
| 7985 | MagickSetIteratorIndex (super_wand, i); | ||
| 7986 | sub_wand = MagickGetImage (super_wand); | ||
| 7987 | |||
| 7988 | MagickGetImagePage (sub_wand, &source_width, &source_height, | ||
| 7989 | &source_left, &source_top); | ||
| 7990 | |||
| 7991 | /* This flag says how to handle transparent pixels. */ | ||
| 7992 | dispose = MagickGetImageDispose (sub_wand); | ||
| 7993 | |||
| 7994 | source_iterator = NewPixelIterator (sub_wand); | ||
| 7995 | if (! source_iterator) | ||
| 7996 | { | ||
| 7997 | DestroyMagickWand (composite_wand); | ||
| 7998 | DestroyMagickWand (sub_wand); | ||
| 7999 | cache->wand = NULL; | ||
| 8000 | image_error ("Imagemagick pixel iterator creation failed", | ||
| 8001 | Qnil, Qnil); | ||
| 8002 | return NULL; | ||
| 8003 | } | ||
| 8004 | |||
| 8005 | dest_iterator = NewPixelIterator (composite_wand); | ||
| 8006 | if (! dest_iterator) | ||
| 8007 | { | ||
| 8008 | DestroyMagickWand (composite_wand); | ||
| 8009 | DestroyMagickWand (sub_wand); | ||
| 8010 | DestroyPixelIterator (source_iterator); | ||
| 8011 | cache->wand = NULL; | ||
| 8012 | image_error ("Imagemagick pixel iterator creation failed", | ||
| 8013 | Qnil, Qnil); | ||
| 8014 | return NULL; | ||
| 8015 | } | ||
| 8016 | |||
| 8017 | /* The sub-image may not start at origin, so move the destination | ||
| 8018 | iterator to where the sub-image should start. */ | ||
| 8019 | if (source_top > 0) | ||
| 8020 | { | ||
| 8021 | PixelSetIteratorRow (dest_iterator, source_top); | ||
| 8022 | lines = source_top; | ||
| 8023 | } | ||
| 8024 | |||
| 8025 | while ((source = PixelGetNextIteratorRow (source_iterator, &source_width)) | ||
| 8026 | != NULL) | ||
| 8027 | { | ||
| 8028 | ptrdiff_t x; | ||
| 8029 | |||
| 8030 | /* Sanity check. This shouldn't happen, but apparently | ||
| 8031 | does in some pictures. */ | ||
| 8032 | if (++lines >= dest_height) | ||
| 8033 | break; | ||
| 8034 | |||
| 8035 | dest = PixelGetNextIteratorRow (dest_iterator, &dest_width); | ||
| 8036 | for (x = 0; x < source_width; x++) | ||
| 8037 | { | ||
| 8038 | /* Sanity check. This shouldn't happen, but apparently | ||
| 8039 | also does in some pictures. */ | ||
| 8040 | if (x + source_left > dest_width) | ||
| 8041 | break; | ||
| 8042 | /* Normally we only copy over non-transparent pixels, | ||
| 8043 | but if the disposal method is "Background", then we | ||
| 8044 | copy over all pixels. */ | ||
| 8045 | if (dispose == BackgroundDispose || | ||
| 8046 | PixelGetAlpha (source[x])) | ||
| 8047 | { | ||
| 8048 | PixelGetMagickColor (source[x], &pixel); | ||
| 8049 | PixelSetMagickColor (dest[x + source_left], &pixel); | ||
| 8050 | } | ||
| 8051 | } | ||
| 8052 | PixelSyncIterator (dest_iterator); | ||
| 8053 | } | ||
| 8054 | |||
| 8055 | DestroyPixelIterator (source_iterator); | ||
| 8056 | DestroyPixelIterator (dest_iterator); | ||
| 8057 | DestroyMagickWand (sub_wand); | ||
| 8058 | } | ||
| 8059 | |||
| 8060 | /* Cache a copy for the next iteration. The current wand will be | ||
| 8061 | destroyed by the caller. */ | ||
| 8062 | cache->wand = CloneMagickWand (composite_wand); | ||
| 8063 | cache->index = ino; | ||
| 8064 | |||
| 8065 | return composite_wand; | ||
| 8066 | } | ||
| 8067 | |||
| 8068 | |||
| 7851 | /* Helper function for imagemagick_load, which does the actual loading | 8069 | /* Helper function for imagemagick_load, which does the actual loading |
| 7852 | given contents and size, apart from frame and image structures, | 8070 | given contents and size, apart from frame and image structures, |
| 7853 | passed from imagemagick_load. Uses librimagemagick to do most of | 8071 | passed from imagemagick_load. Uses librimagemagick to do most of |
| @@ -7870,7 +8088,6 @@ imagemagick_load_image (struct frame *f, struct image *img, | |||
| 7870 | XImagePtr ximg; | 8088 | XImagePtr ximg; |
| 7871 | int x, y; | 8089 | int x, y; |
| 7872 | MagickWand *image_wand; | 8090 | MagickWand *image_wand; |
| 7873 | MagickWand *ping_wand; | ||
| 7874 | PixelIterator *iterator; | 8091 | PixelIterator *iterator; |
| 7875 | PixelWand **pixels, *bg_wand = NULL; | 8092 | PixelWand **pixels, *bg_wand = NULL; |
| 7876 | MagickPixelPacket pixel; | 8093 | MagickPixelPacket pixel; |
| @@ -7881,6 +8098,8 @@ imagemagick_load_image (struct frame *f, struct image *img, | |||
| 7881 | int desired_width, desired_height; | 8098 | int desired_width, desired_height; |
| 7882 | double rotation; | 8099 | double rotation; |
| 7883 | int pixelwidth; | 8100 | int pixelwidth; |
| 8101 | char hint_buffer[MaxTextExtent]; | ||
| 8102 | char *filename_hint = NULL; | ||
| 7884 | 8103 | ||
| 7885 | /* Handle image index for image types who can contain more than one image. | 8104 | /* Handle image index for image types who can contain more than one image. |
| 7886 | Interface :index is same as for GIF. First we "ping" the image to see how | 8105 | Interface :index is same as for GIF. First we "ping" the image to see how |
| @@ -7891,48 +8110,48 @@ imagemagick_load_image (struct frame *f, struct image *img, | |||
| 7891 | MagickWandGenesis (); | 8110 | MagickWandGenesis (); |
| 7892 | image = image_spec_value (img->spec, QCindex, NULL); | 8111 | image = image_spec_value (img->spec, QCindex, NULL); |
| 7893 | ino = INTEGERP (image) ? XFASTINT (image) : 0; | 8112 | ino = INTEGERP (image) ? XFASTINT (image) : 0; |
| 7894 | ping_wand = NewMagickWand (); | 8113 | image_wand = NewMagickWand (); |
| 7895 | /* MagickSetResolution (ping_wand, 2, 2); (Bug#10112) */ | ||
| 7896 | 8114 | ||
| 7897 | status = filename | 8115 | if (filename) |
| 7898 | ? MagickPingImage (ping_wand, filename) | 8116 | status = MagickReadImage (image_wand, filename); |
| 7899 | : MagickPingImageBlob (ping_wand, contents, size); | 8117 | else |
| 8118 | { | ||
| 8119 | filename_hint = imagemagick_filename_hint (img->spec, hint_buffer); | ||
| 8120 | MagickSetFilename (image_wand, filename_hint); | ||
| 8121 | status = MagickReadImageBlob (image_wand, contents, size); | ||
| 8122 | } | ||
| 7900 | 8123 | ||
| 7901 | if (status == MagickFalse) | 8124 | if (status == MagickFalse) |
| 7902 | { | 8125 | { |
| 7903 | imagemagick_error (ping_wand); | 8126 | imagemagick_error (image_wand); |
| 7904 | DestroyMagickWand (ping_wand); | 8127 | DestroyMagickWand (image_wand); |
| 7905 | return 0; | 8128 | return 0; |
| 7906 | } | 8129 | } |
| 7907 | 8130 | ||
| 7908 | if (ino < 0 || ino >= MagickGetNumberImages (ping_wand)) | 8131 | if (ino < 0 || ino >= MagickGetNumberImages (image_wand)) |
| 7909 | { | 8132 | { |
| 7910 | image_error ("Invalid image number `%s' in image `%s'", | 8133 | image_error ("Invalid image number `%s' in image `%s'", |
| 7911 | image, img->spec); | 8134 | image, img->spec); |
| 7912 | DestroyMagickWand (ping_wand); | 8135 | DestroyMagickWand (image_wand); |
| 7913 | return 0; | 8136 | return 0; |
| 7914 | } | 8137 | } |
| 7915 | 8138 | ||
| 7916 | if (MagickGetNumberImages (ping_wand) > 1) | 8139 | if (MagickGetNumberImages (image_wand) > 1) |
| 7917 | img->lisp_data = | 8140 | img->lisp_data = |
| 7918 | Fcons (Qcount, | 8141 | Fcons (Qcount, |
| 7919 | Fcons (make_number (MagickGetNumberImages (ping_wand)), | 8142 | Fcons (make_number (MagickGetNumberImages (image_wand)), |
| 7920 | img->lisp_data)); | 8143 | img->lisp_data)); |
| 7921 | 8144 | ||
| 7922 | DestroyMagickWand (ping_wand); | 8145 | /* If we have an animated image, get the new wand based on the |
| 7923 | 8146 | "super-wand". */ | |
| 7924 | /* Now we know how many images are inside the file. If it's not a | 8147 | if (MagickGetNumberImages (image_wand) > 1) |
| 7925 | bundle, the number is one. Load the image data. */ | ||
| 7926 | |||
| 7927 | image_wand = NewMagickWand (); | ||
| 7928 | |||
| 7929 | if ((filename | ||
| 7930 | ? MagickReadImage (image_wand, filename) | ||
| 7931 | : MagickReadImageBlob (image_wand, contents, size)) | ||
| 7932 | == MagickFalse) | ||
| 7933 | { | 8148 | { |
| 7934 | imagemagick_error (image_wand); | 8149 | MagickWand *super_wand = image_wand; |
| 7935 | goto imagemagick_error; | 8150 | image_wand = imagemagick_compute_animated_image (super_wand, ino); |
| 8151 | if (! image_wand) | ||
| 8152 | image_wand = super_wand; | ||
| 8153 | else | ||
| 8154 | DestroyMagickWand (super_wand); | ||
| 7936 | } | 8155 | } |
| 7937 | 8156 | ||
| 7938 | /* Retrieve the frame's background color, for use later. */ | 8157 | /* Retrieve the frame's background color, for use later. */ |
| @@ -8120,7 +8339,7 @@ imagemagick_load_image (struct frame *f, struct image *img, | |||
| 8120 | 8339 | ||
| 8121 | /* Copy pixels from the imagemagick image structure to the x image map. */ | 8340 | /* Copy pixels from the imagemagick image structure to the x image map. */ |
| 8122 | iterator = NewPixelIterator (image_wand); | 8341 | iterator = NewPixelIterator (image_wand); |
| 8123 | if (iterator == (PixelIterator *) NULL) | 8342 | if (! iterator) |
| 8124 | { | 8343 | { |
| 8125 | #ifdef COLOR_TABLE_SUPPORT | 8344 | #ifdef COLOR_TABLE_SUPPORT |
| 8126 | free_color_table (); | 8345 | free_color_table (); |
| @@ -8135,7 +8354,7 @@ imagemagick_load_image (struct frame *f, struct image *img, | |||
| 8135 | for (y = 0; y < image_height; y++) | 8354 | for (y = 0; y < image_height; y++) |
| 8136 | { | 8355 | { |
| 8137 | pixels = PixelGetNextIteratorRow (iterator, &width); | 8356 | pixels = PixelGetNextIteratorRow (iterator, &width); |
| 8138 | if (pixels == (PixelWand **) NULL) | 8357 | if (! pixels) |
| 8139 | break; | 8358 | break; |
| 8140 | for (x = 0; x < (long) width; x++) | 8359 | for (x = 0; x < (long) width; x++) |
| 8141 | { | 8360 | { |
| @@ -9200,7 +9419,7 @@ A cross is always drawn on black & white displays. */); | |||
| 9200 | 9419 | ||
| 9201 | DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path, | 9420 | DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path, |
| 9202 | doc: /* List of directories to search for window system bitmap files. */); | 9421 | doc: /* List of directories to search for window system bitmap files. */); |
| 9203 | Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); | 9422 | Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS); |
| 9204 | 9423 | ||
| 9205 | DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay, | 9424 | DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay, |
| 9206 | doc: /* Maximum time after which images are removed from the cache. | 9425 | doc: /* Maximum time after which images are removed from the cache. |