diff options
| author | Lars Magne Ingebrigtsen | 2013-08-16 16:54:46 +0200 |
|---|---|---|
| committer | Lars Magne Ingebrigtsen | 2013-08-16 16:54:46 +0200 |
| commit | 274ff63f7f7d19c3eb0c365ed7f8347131b9f62e (patch) | |
| tree | 544f622625ad3724d2e26b0ecaa25d16140337cf /src | |
| parent | e4043ba039b64f2fd91cc3ec950b3d23031a87ce (diff) | |
| download | emacs-274ff63f7f7d19c3eb0c365ed7f8347131b9f62e.tar.gz emacs-274ff63f7f7d19c3eb0c365ed7f8347131b9f62e.zip | |
* image.c: Implement an ImageMagick per-image cache.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 4 | ||||
| -rw-r--r-- | src/image.c | 108 |
2 files changed, 101 insertions, 11 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index ab21a65a805..d5c97748d1a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-08-16 Lars Magne Ingebrigtsen <larsi@gnus.org> | ||
| 2 | |||
| 3 | * image.c: Implement an ImageMagick per-image cache. | ||
| 4 | |||
| 1 | 2013-08-16 Xue Fuqiao <xfq.free@gmail.com> | 5 | 2013-08-16 Xue Fuqiao <xfq.free@gmail.com> |
| 2 | 6 | ||
| 3 | * editfns.c (insert_before_markers): Mention overlay in the doc string. | 7 | * editfns.c (insert_before_markers): Mention overlay in the doc string. |
diff --git a/src/image.c b/src/image.c index 6dc997aa4d0..082cc6a762a 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -7869,10 +7869,91 @@ imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent]) | |||
| 7869 | follow. If following images have non-transparent colors, these are | 7869 | follow. If following images have non-transparent colors, these are |
| 7870 | composed "on top" of the master image. So, in general, one has to | 7870 | composed "on top" of the master image. So, in general, one has to |
| 7871 | compute ann the preceding images to be able to display a particular | 7871 | compute ann the preceding images to be able to display a particular |
| 7872 | sub-image. */ | 7872 | sub-image. |
| 7873 | 7873 | ||
| 7874 | static MagickWand *animation_cache = NULL; | 7874 | Computing all the preceding images is too slow, so we maintain a |
| 7875 | static int animation_index = 0; | 7875 | cache of previously computed images. We have to maintain a cache |
| 7876 | separate from the image cache, because the images may be scaled | ||
| 7877 | before display. */ | ||
| 7878 | |||
| 7879 | struct animation_cache | ||
| 7880 | { | ||
| 7881 | char *signature; | ||
| 7882 | MagickWand *wand; | ||
| 7883 | int index; | ||
| 7884 | EMACS_TIME update_time; | ||
| 7885 | struct animation_cache *next; | ||
| 7886 | }; | ||
| 7887 | |||
| 7888 | static struct animation_cache *animation_cache = NULL; | ||
| 7889 | |||
| 7890 | struct animation_cache * | ||
| 7891 | imagemagick_create_cache (char *signature) | ||
| 7892 | { | ||
| 7893 | struct animation_cache *cache = xzalloc (sizeof (struct animation_cache)); | ||
| 7894 | cache->signature = signature; | ||
| 7895 | cache->update_time = current_emacs_time (); | ||
| 7896 | return cache; | ||
| 7897 | } | ||
| 7898 | |||
| 7899 | /* Discard cached images that haven't been used for a minute. */ | ||
| 7900 | void | ||
| 7901 | imagemagick_prune_animation_cache () | ||
| 7902 | { | ||
| 7903 | struct animation_cache *cache = animation_cache; | ||
| 7904 | struct animation_cache *prev; | ||
| 7905 | EMACS_TIME old = sub_emacs_time (current_emacs_time (), | ||
| 7906 | EMACS_TIME_FROM_DOUBLE (60)); | ||
| 7907 | |||
| 7908 | while (cache) | ||
| 7909 | { | ||
| 7910 | if (EMACS_TIME_LT (cache->update_time, old)) | ||
| 7911 | { | ||
| 7912 | struct animation_cache *this_cache = cache; | ||
| 7913 | free (cache->signature); | ||
| 7914 | if (cache->wand) | ||
| 7915 | DestroyMagickWand (cache->wand); | ||
| 7916 | if (prev) | ||
| 7917 | prev->next = cache->next; | ||
| 7918 | else | ||
| 7919 | animation_cache = cache->next; | ||
| 7920 | cache = cache->next; | ||
| 7921 | free (this_cache); | ||
| 7922 | } | ||
| 7923 | else { | ||
| 7924 | prev = cache; | ||
| 7925 | cache = cache->next; | ||
| 7926 | } | ||
| 7927 | } | ||
| 7928 | } | ||
| 7929 | |||
| 7930 | struct animation_cache * | ||
| 7931 | imagemagick_get_animation_cache (MagickWand *wand) | ||
| 7932 | { | ||
| 7933 | char *signature = MagickGetImageSignature (wand); | ||
| 7934 | struct animation_cache *cache = animation_cache; | ||
| 7935 | |||
| 7936 | imagemagick_prune_animation_cache (); | ||
| 7937 | |||
| 7938 | if (! cache) | ||
| 7939 | { | ||
| 7940 | animation_cache = imagemagick_create_cache (signature); | ||
| 7941 | return animation_cache; | ||
| 7942 | } | ||
| 7943 | |||
| 7944 | while (strcmp(signature, cache->signature) && | ||
| 7945 | cache->next) | ||
| 7946 | cache = cache->next; | ||
| 7947 | |||
| 7948 | if (strcmp(signature, cache->signature)) | ||
| 7949 | { | ||
| 7950 | cache->next = imagemagick_create_cache (signature); | ||
| 7951 | return cache->next; | ||
| 7952 | } | ||
| 7953 | |||
| 7954 | cache->update_time = current_emacs_time (); | ||
| 7955 | return cache; | ||
| 7956 | } | ||
| 7876 | 7957 | ||
| 7877 | static MagickWand * | 7958 | static MagickWand * |
| 7878 | imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | 7959 | imagemagick_compute_animated_image (MagickWand *super_wand, int ino) |
| @@ -7880,18 +7961,23 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | |||
| 7880 | int i; | 7961 | int i; |
| 7881 | MagickWand *composite_wand; | 7962 | MagickWand *composite_wand; |
| 7882 | size_t dest_width, dest_height; | 7963 | size_t dest_width, dest_height; |
| 7964 | struct animation_cache *cache = imagemagick_get_animation_cache (super_wand); | ||
| 7883 | 7965 | ||
| 7884 | MagickSetIteratorIndex (super_wand, 0); | 7966 | MagickSetIteratorIndex (super_wand, 0); |
| 7885 | 7967 | ||
| 7886 | if (ino == 0 || animation_cache == NULL) | 7968 | if (ino == 0 || cache->wand == NULL || cache->index > ino) |
| 7887 | composite_wand = MagickGetImage (super_wand); | 7969 | { |
| 7970 | composite_wand = MagickGetImage (super_wand); | ||
| 7971 | if (cache->wand) | ||
| 7972 | DestroyMagickWand (cache->wand); | ||
| 7973 | } | ||
| 7888 | else | 7974 | else |
| 7889 | composite_wand = animation_cache; | 7975 | composite_wand = cache->wand; |
| 7890 | 7976 | ||
| 7891 | dest_width = MagickGetImageWidth (composite_wand); | 7977 | dest_width = MagickGetImageWidth (composite_wand); |
| 7892 | dest_height = MagickGetImageHeight (composite_wand); | 7978 | dest_height = MagickGetImageHeight (composite_wand); |
| 7893 | 7979 | ||
| 7894 | for (i = max (1, animation_index + 1); i <= ino; i++) | 7980 | for (i = max (1, cache->index + 1); i <= ino; i++) |
| 7895 | { | 7981 | { |
| 7896 | MagickWand *sub_wand; | 7982 | MagickWand *sub_wand; |
| 7897 | PixelIterator *source_iterator, *dest_iterator; | 7983 | PixelIterator *source_iterator, *dest_iterator; |
| @@ -7916,7 +8002,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | |||
| 7916 | { | 8002 | { |
| 7917 | DestroyMagickWand (composite_wand); | 8003 | DestroyMagickWand (composite_wand); |
| 7918 | DestroyMagickWand (sub_wand); | 8004 | DestroyMagickWand (sub_wand); |
| 7919 | animation_cache = NULL; | 8005 | cache->wand = NULL; |
| 7920 | image_error ("Imagemagick pixel iterator creation failed", | 8006 | image_error ("Imagemagick pixel iterator creation failed", |
| 7921 | Qnil, Qnil); | 8007 | Qnil, Qnil); |
| 7922 | return NULL; | 8008 | return NULL; |
| @@ -7928,7 +8014,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | |||
| 7928 | DestroyMagickWand (composite_wand); | 8014 | DestroyMagickWand (composite_wand); |
| 7929 | DestroyMagickWand (sub_wand); | 8015 | DestroyMagickWand (sub_wand); |
| 7930 | DestroyPixelIterator (source_iterator); | 8016 | DestroyPixelIterator (source_iterator); |
| 7931 | animation_cache = NULL; | 8017 | cache->wand = NULL; |
| 7932 | image_error ("Imagemagick pixel iterator creation failed", | 8018 | image_error ("Imagemagick pixel iterator creation failed", |
| 7933 | Qnil, Qnil); | 8019 | Qnil, Qnil); |
| 7934 | return NULL; | 8020 | return NULL; |
| @@ -7979,8 +8065,8 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino) | |||
| 7979 | 8065 | ||
| 7980 | /* Cache a copy for the next iteration. The current wand will be | 8066 | /* Cache a copy for the next iteration. The current wand will be |
| 7981 | destroyed by the caller. */ | 8067 | destroyed by the caller. */ |
| 7982 | animation_cache = CloneMagickWand (composite_wand); | 8068 | cache->wand = CloneMagickWand (composite_wand); |
| 7983 | animation_index = ino; | 8069 | cache->index = ino; |
| 7984 | 8070 | ||
| 7985 | return composite_wand; | 8071 | return composite_wand; |
| 7986 | } | 8072 | } |