diff options
| author | Chong Yidong | 2011-06-07 14:32:12 -0400 |
|---|---|---|
| committer | Chong Yidong | 2011-06-07 14:32:12 -0400 |
| commit | 18af70d0258153a042be9fd71d4eb090f7189a8f (patch) | |
| tree | 81449660fd53df5f0a6e97907e1aeaf631e13879 | |
| parent | 2c631e0e829031852440433ff248149c27ba3fde (diff) | |
| download | emacs-18af70d0258153a042be9fd71d4eb090f7189a8f.tar.gz emacs-18af70d0258153a042be9fd71d4eb090f7189a8f.zip | |
Some changes and re-organization for animated gif support.
* lisp/image.el (image-animate-max-time): Moved to image-mode.el.
(create-animated-image): Remove unnecessary function.
(image-animate): Rename from image-animate-start. New arg.
(image-animate-stop): Removed; just use image-animate-timer.
(image-animate-timer): Use car-safe.
(image-animate-timeout): Rename argument.
* lisp/image-mode.el (image-toggle-animation): New command.
(image-mode-map): Bind it to RET.
(image-mode): Update message.
(image-toggle-display-image): Avoid a spurious cache flush.
(image-transform-rotation): Doc fix.
(image-transform-properties): Return quickly in the normal case.
(image-animate-loop): Rename from image-animate-max-time.
| -rw-r--r-- | etc/NEWS | 22 | ||||
| -rw-r--r-- | lisp/ChangeLog | 17 | ||||
| -rw-r--r-- | lisp/image-mode.el | 112 | ||||
| -rw-r--r-- | lisp/image.el | 127 |
4 files changed, 154 insertions, 124 deletions
| @@ -693,6 +693,14 @@ listing object name completions when being sent text via | |||
| 693 | 693 | ||
| 694 | *** An API for manipulating SQL product definitions has been added. | 694 | *** An API for manipulating SQL product definitions has been added. |
| 695 | 695 | ||
| 696 | ** Image mode | ||
| 697 | |||
| 698 | *** RET (`image-toggle-animation') toggles animation, if the displayed | ||
| 699 | image can be animated. | ||
| 700 | |||
| 701 | *** Option `image-animate-loop', if non-nil, loops the animation. | ||
| 702 | If nil, `image-toggle-animation' plays the animation once. | ||
| 703 | |||
| 696 | ** sregex.el is now obsolete, since rx.el is a strict superset. | 704 | ** sregex.el is now obsolete, since rx.el is a strict superset. |
| 697 | 705 | ||
| 698 | ** s-region.el and pc-select are now declared obsolete, | 706 | ** s-region.el and pc-select are now declared obsolete, |
| @@ -980,12 +988,14 @@ i.e. via menu entries of the form `(menu-item "--")'. | |||
| 980 | 988 | ||
| 981 | ** Image API | 989 | ** Image API |
| 982 | 990 | ||
| 983 | *** When the image type is one of listed in `image-animated-types' | 991 | *** Animated images support (currently animated gifs only). |
| 984 | and the number of sub-images in the image is more than one, then the | 992 | |
| 985 | new function `create-animated-image' creates an animated image where | 993 | **** `image-animated-p' returns non-nil if an image can be animated. |
| 986 | sub-images are displayed successively with the duration defined by | 994 | |
| 987 | `image-animate-max-time' and the delay between sub-images defined | 995 | **** `image-animate' animates a supplied image spec. |
| 988 | by the Graphic Control Extension of the image. | 996 | |
| 997 | **** `image-animate-timer' returns the timer object for an image that | ||
| 998 | is being animated. | ||
| 989 | 999 | ||
| 990 | *** `image-extension-data' is renamed to `image-metadata'. | 1000 | *** `image-extension-data' is renamed to `image-metadata'. |
| 991 | 1001 | ||
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index ab80b59e0be..e5911a35db2 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,20 @@ | |||
| 1 | 2011-06-07 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * image-mode.el (image-toggle-animation): New command. | ||
| 4 | (image-mode-map): Bind it to RET. | ||
| 5 | (image-mode): Update message. | ||
| 6 | (image-toggle-display-image): Avoid a spurious cache flush. | ||
| 7 | (image-transform-rotation): Doc fix. | ||
| 8 | (image-transform-properties): Return quickly in the normal case. | ||
| 9 | (image-animate-loop): Rename from image-animate-max-time. | ||
| 10 | |||
| 11 | * image.el (image-animate-max-time): Moved to image-mode.el. | ||
| 12 | (create-animated-image): Remove unnecessary function. | ||
| 13 | (image-animate): Rename from image-animate-start. New arg. | ||
| 14 | (image-animate-stop): Removed; just use image-animate-timer. | ||
| 15 | (image-animate-timer): Use car-safe. | ||
| 16 | (image-animate-timeout): Rename argument. | ||
| 17 | |||
| 1 | 2011-06-07 Martin Rudalics <rudalics@gmx.at> | 18 | 2011-06-07 Martin Rudalics <rudalics@gmx.at> |
| 2 | 19 | ||
| 3 | * window.el (get-lru-window, get-largest-window): Move here from | 20 | * window.el (get-lru-window, get-largest-window): Move here from |
diff --git a/lisp/image-mode.el b/lisp/image-mode.el index 145a15de246..7082cfc57ad 100644 --- a/lisp/image-mode.el +++ b/lisp/image-mode.el | |||
| @@ -308,6 +308,7 @@ This function assumes the current frame has only one window." | |||
| 308 | (define-key map "\C-c\C-c" 'image-toggle-display) | 308 | (define-key map "\C-c\C-c" 'image-toggle-display) |
| 309 | (define-key map (kbd "SPC") 'image-scroll-up) | 309 | (define-key map (kbd "SPC") 'image-scroll-up) |
| 310 | (define-key map (kbd "DEL") 'image-scroll-down) | 310 | (define-key map (kbd "DEL") 'image-scroll-down) |
| 311 | (define-key map (kbd "RET") 'image-toggle-animation) | ||
| 311 | (define-key map [remap forward-char] 'image-forward-hscroll) | 312 | (define-key map [remap forward-char] 'image-forward-hscroll) |
| 312 | (define-key map [remap backward-char] 'image-backward-hscroll) | 313 | (define-key map [remap backward-char] 'image-backward-hscroll) |
| 313 | (define-key map [remap right-char] 'image-forward-hscroll) | 314 | (define-key map [remap right-char] 'image-forward-hscroll) |
| @@ -373,16 +374,26 @@ to toggle between display as an image and display as text." | |||
| 373 | (add-hook 'change-major-mode-hook 'image-toggle-display-text nil t) | 374 | (add-hook 'change-major-mode-hook 'image-toggle-display-text nil t) |
| 374 | (add-hook 'after-revert-hook 'image-after-revert-hook nil t) | 375 | (add-hook 'after-revert-hook 'image-after-revert-hook nil t) |
| 375 | (run-mode-hooks 'image-mode-hook) | 376 | (run-mode-hooks 'image-mode-hook) |
| 376 | (message "%s" (concat | 377 | (let ((image (image-get-display-property)) |
| 377 | (substitute-command-keys | 378 | (msg1 (substitute-command-keys |
| 378 | "Type \\[image-toggle-display] to view the image as ") | 379 | "Type \\[image-toggle-display] to view the image as "))) |
| 379 | (if (image-get-display-property) | 380 | (cond |
| 380 | "text" "an image") "."))) | 381 | ((null image) |
| 382 | (message "%s" (concat msg1 "an image."))) | ||
| 383 | ((image-animated-p image) | ||
| 384 | (message "%s" | ||
| 385 | (concat msg1 "text, or " | ||
| 386 | (substitute-command-keys | ||
| 387 | "\\[image-toggle-animation] to animate.")))) | ||
| 388 | (t | ||
| 389 | (message "%s" (concat msg1 "text.")))))) | ||
| 390 | |||
| 381 | (error | 391 | (error |
| 382 | (image-mode-as-text) | 392 | (image-mode-as-text) |
| 383 | (funcall | 393 | (funcall |
| 384 | (if (called-interactively-p 'any) 'error 'message) | 394 | (if (called-interactively-p 'any) 'error 'message) |
| 385 | "Cannot display image: %s" (cdr err))))) | 395 | "Cannot display image: %s" (cdr err))))) |
| 396 | |||
| 386 | ;;;###autoload | 397 | ;;;###autoload |
| 387 | (define-minor-mode image-minor-mode | 398 | (define-minor-mode image-minor-mode |
| 388 | "Toggle Image minor mode. | 399 | "Toggle Image minor mode. |
| @@ -484,25 +495,20 @@ was inserted." | |||
| 484 | (buffer-substring-no-properties (point-min) (point-max))) | 495 | (buffer-substring-no-properties (point-min) (point-max))) |
| 485 | filename)) | 496 | filename)) |
| 486 | (type (image-type file-or-data nil data-p)) | 497 | (type (image-type file-or-data nil data-p)) |
| 487 | ;; Don't use create-animated-image here; that would start the | ||
| 488 | ;; timer, which works by altering the spec destructively. | ||
| 489 | ;; But we still need to append the transformation properties, | ||
| 490 | ;; which would make a new list. | ||
| 491 | (image (create-image file-or-data type data-p)) | 498 | (image (create-image file-or-data type data-p)) |
| 492 | (inhibit-read-only t) | 499 | (inhibit-read-only t) |
| 493 | (buffer-undo-list t) | 500 | (buffer-undo-list t) |
| 494 | (modified (buffer-modified-p)) | 501 | (modified (buffer-modified-p)) |
| 495 | props) | 502 | props) |
| 496 | 503 | ||
| 504 | ;; Discard any stale image data before looking it up again. | ||
| 505 | (image-flush image) | ||
| 497 | (setq image (append image (image-transform-properties image))) | 506 | (setq image (append image (image-transform-properties image))) |
| 498 | (setq props | 507 | (setq props |
| 499 | `(display ,image | 508 | `(display ,image |
| 500 | intangible ,image | 509 | intangible ,image |
| 501 | rear-nonsticky (display intangible) | 510 | rear-nonsticky (display intangible) |
| 502 | read-only t front-sticky (read-only))) | 511 | read-only t front-sticky (read-only))) |
| 503 | (image-flush image) | ||
| 504 | ;; Begin the animation, if any. | ||
| 505 | (image-animate-start image) | ||
| 506 | 512 | ||
| 507 | (let ((buffer-file-truename nil)) ; avoid changing dir mtime by lock_file | 513 | (let ((buffer-file-truename nil)) ; avoid changing dir mtime by lock_file |
| 508 | (add-text-properties (point-min) (point-max) props) | 514 | (add-text-properties (point-min) (point-max) props) |
| @@ -545,6 +551,37 @@ the image by calling `image-mode'." | |||
| 545 | (image-toggle-display-image))) | 551 | (image-toggle-display-image))) |
| 546 | 552 | ||
| 547 | 553 | ||
| 554 | ;;; Animated images | ||
| 555 | |||
| 556 | (defcustom image-animate-loop nil | ||
| 557 | "Whether to play animated images on a loop in Image mode." | ||
| 558 | :type 'boolean | ||
| 559 | :version "24.1" | ||
| 560 | :group 'image) | ||
| 561 | |||
| 562 | (defun image-toggle-animation () | ||
| 563 | "Start or stop animating the current image." | ||
| 564 | (interactive) | ||
| 565 | (let ((image (image-get-display-property)) | ||
| 566 | animation) | ||
| 567 | (cond | ||
| 568 | ((null image) | ||
| 569 | (error "No image is present")) | ||
| 570 | ((null (setq animation (image-animated-p image))) | ||
| 571 | (message "No image animation.")) | ||
| 572 | (t | ||
| 573 | (let ((timer (image-animate-timer image))) | ||
| 574 | (if timer | ||
| 575 | (cancel-timer timer) | ||
| 576 | (let ((index (plist-get (cdr image) :index))) | ||
| 577 | ;; If we're at the end, restart. | ||
| 578 | (and index | ||
| 579 | (>= index (1- (car animation))) | ||
| 580 | (setq index nil)) | ||
| 581 | (image-animate image index | ||
| 582 | (if image-animate-loop t))))))))) | ||
| 583 | |||
| 584 | |||
| 548 | ;;; Support for bookmark.el | 585 | ;;; Support for bookmark.el |
| 549 | (declare-function bookmark-make-record-default | 586 | (declare-function bookmark-make-record-default |
| 550 | "bookmark" (&optional no-file no-context posn)) | 587 | "bookmark" (&optional no-file no-context posn)) |
| @@ -589,33 +626,38 @@ Its value should be one of the following: | |||
| 589 | - `fit-width', meaning to fit the image to the window width. | 626 | - `fit-width', meaning to fit the image to the window width. |
| 590 | - A number, which is a scale factor (the default size is 100).") | 627 | - A number, which is a scale factor (the default size is 100).") |
| 591 | 628 | ||
| 592 | (defvar image-transform-rotation 0.0) | 629 | (defvar image-transform-rotation 0.0 |
| 630 | "Rotation angle for the image in the current Image mode buffer.") | ||
| 593 | 631 | ||
| 594 | (defun image-transform-properties (display) | 632 | (defun image-transform-properties (spec) |
| 595 | "Return rescaling/rotation properties for the Image mode buffer. | 633 | "Return rescaling/rotation properties for image SPEC. |
| 596 | These properties are suitable for appending to an image spec; | 634 | These properties are determined by the Image mode variables |
| 597 | they are determined by the variables `image-transform-resize' and | 635 | `image-transform-resize' and `image-transform-rotation'. The |
| 598 | `image-transform-rotation'. | 636 | return value is suitable for appending to an image spec. |
| 599 | 637 | ||
| 600 | Recaling and rotation properties only take effect if Emacs is | 638 | Recaling and rotation properties only take effect if Emacs is |
| 601 | compiled with ImageMagick support." | 639 | compiled with ImageMagick support." |
| 602 | (let* ((size (image-size display t)) | 640 | (when (or image-transform-resize |
| 603 | (height | 641 | (not (equal image-transform-rotation 0.0))) |
| 604 | (cond | 642 | ;; Note: `image-size' looks up and thus caches the untransformed |
| 605 | ((numberp image-transform-resize) | 643 | ;; image. There's no easy way to prevent that. |
| 606 | (unless (= image-transform-resize 100) | 644 | (let* ((size (image-size spec t)) |
| 607 | (* image-transform-resize (cdr size)))) | 645 | (height |
| 608 | ((eq image-transform-resize 'fit-height) | 646 | (cond |
| 609 | (- (nth 3 (window-inside-pixel-edges)) | 647 | ((numberp image-transform-resize) |
| 610 | (nth 1 (window-inside-pixel-edges)))))) | 648 | (unless (= image-transform-resize 100) |
| 611 | (width (if (eq image-transform-resize 'fit-width) | 649 | (* image-transform-resize (cdr size)))) |
| 612 | (- (nth 2 (window-inside-pixel-edges)) | 650 | ((eq image-transform-resize 'fit-height) |
| 613 | (nth 0 (window-inside-pixel-edges)))))) | 651 | (- (nth 3 (window-inside-pixel-edges)) |
| 614 | ;;TODO fit-to-* should consider the rotation angle | 652 | (nth 1 (window-inside-pixel-edges)))))) |
| 615 | `(,@(if height (list :height height)) | 653 | (width (if (eq image-transform-resize 'fit-width) |
| 616 | ,@(if width (list :width width)) | 654 | (- (nth 2 (window-inside-pixel-edges)) |
| 617 | ,@(if (not (equal 0.0 image-transform-rotation)) | 655 | (nth 0 (window-inside-pixel-edges)))))) |
| 618 | (list :rotation image-transform-rotation))))) | 656 | ;;TODO fit-to-* should consider the rotation angle |
| 657 | `(,@(if height (list :height height)) | ||
| 658 | ,@(if width (list :width width)) | ||
| 659 | ,@(if (not (equal 0.0 image-transform-rotation)) | ||
| 660 | (list :rotation image-transform-rotation)))))) | ||
| 619 | 661 | ||
| 620 | (defun image-transform-set-scale (scale) | 662 | (defun image-transform-set-scale (scale) |
| 621 | "Prompt for a number, and resize the current image by that amount. | 663 | "Prompt for a number, and resize the current image by that amount. |
diff --git a/lisp/image.el b/lisp/image.el index b9ed10eacf2..e076c2d09f1 100644 --- a/lisp/image.el +++ b/lisp/image.el | |||
| @@ -590,43 +590,45 @@ Example: | |||
| 590 | 590 | ||
| 591 | ;;; Animated image API | 591 | ;;; Animated image API |
| 592 | 592 | ||
| 593 | (defcustom image-animate-max-time nil | ||
| 594 | "Time in seconds to animate images. | ||
| 595 | If the value is nil, play animations once. | ||
| 596 | If the value is t, loop forever." | ||
| 597 | :type '(choice (const :tag "Play once" nil) | ||
| 598 | (const :tag "Loop forever" t) | ||
| 599 | integer) | ||
| 600 | :version "24.1" | ||
| 601 | :group 'image) | ||
| 602 | |||
| 603 | (defconst image-animated-types '(gif) | 593 | (defconst image-animated-types '(gif) |
| 604 | "List of supported animated image types.") | 594 | "List of supported animated image types.") |
| 605 | 595 | ||
| 606 | ;;;###autoload | 596 | (defun image-animated-p (image) |
| 607 | (defun create-animated-image (file-or-data &optional type data-p &rest props) | 597 | "Return non-nil if image can be animated. |
| 608 | "Create an animated image, and begin animating it. | 598 | Actually, the return value is a cons (NIMAGES . DELAY), where |
| 609 | FILE-OR-DATA is an image file name or image data. | 599 | NIMAGES is the number of sub-images in the animated image and |
| 610 | Optional TYPE is a symbol describing the image type. If TYPE is omitted | 600 | DELAY is the delay in 100ths of a second until the next sub-image |
| 611 | or nil, try to determine the image type from its first few bytes | 601 | shall be displayed." |
| 612 | of image data. If that doesn't work, and FILE-OR-DATA is a file name, | 602 | (cond |
| 613 | use its file extension as image type. | 603 | ((eq (plist-get (cdr image) :type) 'gif) |
| 614 | Optional DATA-P non-nil means FILE-OR-DATA is a string containing image data. | 604 | (let* ((metadata (image-metadata image)) |
| 615 | Optional PROPS are additional image attributes to assign to the image, | 605 | (images (plist-get metadata 'count)) |
| 616 | like, e.g. `:mask MASK'. | 606 | (extdata (plist-get metadata 'extension-data)) |
| 617 | Value is the image created, or nil if images of type TYPE are not supported. | 607 | (anim (plist-get extdata #xF9)) |
| 608 | (tmo (and (integerp images) (> images 1) | ||
| 609 | (stringp anim) (>= (length anim) 4) | ||
| 610 | (+ (aref anim 1) (* (aref anim 2) 256))))) | ||
| 611 | (when tmo | ||
| 612 | (if (eq tmo 0) (setq tmo 10)) | ||
| 613 | (cons images tmo)))))) | ||
| 618 | 614 | ||
| 619 | Images should not be larger than specified by `max-image-size'." | 615 | (defun image-animate (image &optional index limit) |
| 620 | (setq type (image-type file-or-data type data-p)) | 616 | "Start animating IMAGE. |
| 621 | (when (image-type-available-p type) | 617 | Animation occurs by destructively altering the IMAGE spec list. |
| 622 | (let* ((animate (memq type image-animated-types)) | 618 | |
| 623 | (image | 619 | With optional INDEX, begin animating from that animation frame. |
| 624 | (append (list 'image :type type (if data-p :data :file) file-or-data) | 620 | LIMIT specifies how long to animate the image. If omitted or |
| 625 | (if animate '(:index 0)) | 621 | nil, play the animation until the end. If t, loop forever. If a |
| 626 | props))) | 622 | number, play until that number of seconds has elapsed." |
| 627 | (if animate | 623 | (let ((anim (image-animated-p image)) |
| 628 | (image-animate-start image)) | 624 | delay timer) |
| 629 | image))) | 625 | (when anim |
| 626 | (if (setq timer (image-animate-timer image)) | ||
| 627 | (cancel-timer timer)) | ||
| 628 | (setq delay (max (* (cdr anim) 0.01) 0.025)) | ||
| 629 | (run-with-timer 0.2 nil #'image-animate-timeout | ||
| 630 | image (or index 0) (car anim) | ||
| 631 | delay 0 limit)))) | ||
| 630 | 632 | ||
| 631 | (defun image-animate-timer (image) | 633 | (defun image-animate-timer (image) |
| 632 | "Return the animation timer for image IMAGE." | 634 | "Return the animation timer for image IMAGE." |
| @@ -635,78 +637,37 @@ Images should not be larger than specified by `max-image-size'." | |||
| 635 | (while tail | 637 | (while tail |
| 636 | (setq timer (car tail) | 638 | (setq timer (car tail) |
| 637 | tail (cdr tail)) | 639 | tail (cdr tail)) |
| 638 | (if (and (eq (aref timer 5) #'image-animate-timeout) | 640 | (if (and (eq (aref timer 5) 'image-animate-timeout) |
| 639 | (consp (aref timer 6)) | 641 | (eq (car-safe (aref timer 6)) image)) |
| 640 | (eq (car (aref timer 6)) image)) | ||
| 641 | (setq tail nil) | 642 | (setq tail nil) |
| 642 | (setq timer nil))) | 643 | (setq timer nil))) |
| 643 | timer)) | 644 | timer)) |
| 644 | 645 | ||
| 645 | (defun image-animate-start (image) | 646 | (defun image-animate-timeout (image n count delay time-elapsed limit) |
| 646 | "Start animating the image IMAGE. | ||
| 647 | The variable `image-animate-max-time' determines how long to | ||
| 648 | animate for." | ||
| 649 | (let ((anim (image-animated-p image)) | ||
| 650 | delay ; in seconds | ||
| 651 | timer) | ||
| 652 | (when anim | ||
| 653 | (if (setq timer (image-animate-timer image)) | ||
| 654 | (cancel-timer timer)) | ||
| 655 | (setq delay (max (* (cdr anim) 0.01) 0.025)) | ||
| 656 | (run-with-timer 0.2 nil #'image-animate-timeout | ||
| 657 | image 0 (car anim) | ||
| 658 | delay 0 image-animate-max-time)))) | ||
| 659 | |||
| 660 | (defun image-animate-stop (image) | ||
| 661 | "Stop animation of image." | ||
| 662 | (let ((timer (image-animate-timer image))) | ||
| 663 | (when timer | ||
| 664 | (cancel-timer timer)))) | ||
| 665 | |||
| 666 | (defun image-animate-timeout (image n count delay time-elapsed max) | ||
| 667 | "Display animation frame N of IMAGE. | 647 | "Display animation frame N of IMAGE. |
| 668 | N=0 refers to the initial animation frame. | 648 | N=0 refers to the initial animation frame. |
| 669 | COUNT is the total number of frames in the animation. | 649 | COUNT is the total number of frames in the animation. |
| 670 | DELAY is the time between animation frames, in seconds. | 650 | DELAY is the time between animation frames, in seconds. |
| 671 | TIME-ELAPSED is the total time that has elapsed since | 651 | TIME-ELAPSED is the total time that has elapsed since |
| 672 | `image-animate-start' was called. | 652 | `image-animate-start' was called. |
| 673 | MAX determines when to stop. If t, loop forever. If nil, stop | 653 | LIMIT determines when to stop. If t, loop forever. If nil, stop |
| 674 | after displaying the last animation frame. Otherwise, stop | 654 | after displaying the last animation frame. Otherwise, stop |
| 675 | after MAX seconds have elapsed." | 655 | after LIMIT seconds have elapsed." |
| 676 | (let (done) | 656 | (let (done) |
| 677 | (plist-put (cdr image) :index n) | 657 | (plist-put (cdr image) :index n) |
| 678 | (force-window-update) | 658 | (force-window-update) |
| 679 | (setq n (1+ n)) | 659 | (setq n (1+ n)) |
| 680 | (if (>= n count) | 660 | (if (>= n count) |
| 681 | (if max | 661 | (if limit |
| 682 | (setq n 0) | 662 | (setq n 0) |
| 683 | (setq done t))) | 663 | (setq done t))) |
| 684 | (setq time-elapsed (+ delay time-elapsed)) | 664 | (setq time-elapsed (+ delay time-elapsed)) |
| 685 | (if (numberp max) | 665 | (if (numberp limit) |
| 686 | (setq done (>= time-elapsed max))) | 666 | (setq done (>= time-elapsed limit))) |
| 687 | (unless done | 667 | (unless done |
| 688 | (run-with-timer delay nil 'image-animate-timeout | 668 | (run-with-timer delay nil 'image-animate-timeout |
| 689 | image n count delay | 669 | image n count delay |
| 690 | time-elapsed max)))) | 670 | time-elapsed limit)))) |
| 691 | |||
| 692 | (defun image-animated-p (image) | ||
| 693 | "Return non-nil if image is animated. | ||
| 694 | Actually, return value is a cons (IMAGES . DELAY) where IMAGES | ||
| 695 | is the number of sub-images in the animated image, and DELAY | ||
| 696 | is the delay in 100ths of a second until the next sub-image | ||
| 697 | shall be displayed." | ||
| 698 | (cond | ||
| 699 | ((eq (plist-get (cdr image) :type) 'gif) | ||
| 700 | (let* ((metadata (image-metadata image)) | ||
| 701 | (images (plist-get metadata 'count)) | ||
| 702 | (extdata (plist-get metadata 'extension-data)) | ||
| 703 | (anim (plist-get extdata #xF9)) | ||
| 704 | (tmo (and (integerp images) (> images 1) | ||
| 705 | (stringp anim) (>= (length anim) 4) | ||
| 706 | (+ (aref anim 1) (* (aref anim 2) 256))))) | ||
| 707 | (when tmo | ||
| 708 | (if (eq tmo 0) (setq tmo 10)) | ||
| 709 | (cons images tmo)))))) | ||
| 710 | 671 | ||
| 711 | 672 | ||
| 712 | (defcustom imagemagick-types-inhibit | 673 | (defcustom imagemagick-types-inhibit |