]> code.delx.au - gnu-emacs/blobdiff - lisp/image-mode.el
Merge from origin/emacs-24
[gnu-emacs] / lisp / image-mode.el
index 30dfd045b466e7105164b8544b42774154e900cb..b94162d413a2d1d27baa4e69028b27337fc6ee59 100644 (file)
@@ -1,6 +1,6 @@
 ;;; image-mode.el --- support for visiting image files  -*- lexical-binding: t -*-
 ;;
-;; Copyright (C) 2005-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2005-2014 Free Software Foundation, Inc.
 ;;
 ;; Author: Richard Stallman <rms@gnu.org>
 ;; Keywords: multimedia
   "Special hook run when image data is requested in a new window.
 It is called with one argument, the initial WINPROPS.")
 
+;; FIXME this doesn't seem mature yet. Document in manual when it is.
+(defvar image-transform-resize nil
+  "The image resize operation.
+Its value should be one of the following:
+ - nil, meaning no resizing.
+ - `fit-height', meaning to fit the image to the window height.
+ - `fit-width', meaning to fit the image to the window width.
+ - A number, which is a scale factor (the default size is 1).")
+
+(defvar image-transform-scale 1.0
+  "The scale factor of the image being displayed.")
+
+(defvar image-transform-rotation 0.0
+  "Rotation angle for the image in the current Image mode buffer.")
+
+(defvar image-transform-right-angle-fudge 0.0001
+  "Snap distance to a multiple of a right angle.
+There's no deep theory behind the default value, it should just
+be somewhat larger than ImageMagick's MagickEpsilon.")
+
 (defun image-mode-winprops (&optional window cleanup)
   "Return winprops of WINDOW.
 A winprops object has the shape (WINDOW . ALIST).
@@ -90,6 +110,8 @@ otherwise it defaults to t, used for times when the buffer is not displayed."
 
 (defun image-mode-window-put (prop val &optional winprops)
   (unless (consp winprops) (setq winprops (image-mode-winprops winprops)))
+  (unless (eq t (car winprops))
+    (image-mode-window-put prop val t))
   (setcdr winprops (cons (cons prop val)
                          (delq (assq prop (cdr winprops)) (cdr winprops)))))
 
@@ -354,6 +376,10 @@ call."
     (define-key map "b" 'image-previous-frame)
     (define-key map "n" 'image-next-file)
     (define-key map "p" 'image-previous-file)
+    (define-key map "a+" 'image-increase-speed)
+    (define-key map "a-" 'image-decrease-speed)
+    (define-key map "a0" 'image-reset-speed)
+    (define-key map "ar" 'image-reverse-speed)
     (define-key map [remap forward-char] 'image-forward-hscroll)
     (define-key map [remap backward-char] 'image-backward-hscroll)
     (define-key map [remap right-char] 'image-forward-hscroll)
@@ -373,8 +399,6 @@ call."
        ["Show as Text" image-toggle-display :active t
         :help "Show image as text"]
        "--"
-       ["Fit Frame to Image" image-mode-fit-frame :active t
-        :help "Resize frame to match image"]
        ["Fit to Window Height" image-transform-fit-to-height
         :visible (eq image-type 'imagemagick)
         :help "Resize image to match the window height"]
@@ -384,6 +408,9 @@ call."
        ["Rotate Image..." image-transform-set-rotation
         :visible (eq image-type 'imagemagick)
         :help "Rotate the image"]
+       ["Reset Transformations" image-transform-reset
+        :visible (eq image-type 'imagemagick)
+        :help "Reset all image transformations"]
        "--"
        ["Show Thumbnails"
         (lambda ()
@@ -396,6 +423,9 @@ call."
        ["Previous Image" image-previous-file :active buffer-file-name
          :help "Move to previous image in this directory"]
        "--"
+       ["Fit Frame to Image" image-mode-fit-frame :active t
+        :help "Resize frame to match image"]
+       "--"
        ["Animate Image" image-toggle-animation :style toggle
         :selected (let ((image (image-get-display-property)))
                     (and image (image-animate-timer image)))
@@ -412,7 +442,23 @@ call."
             (image-toggle-animation)))
         :style toggle :selected image-animate-loop
         :active image-multi-frame
-         :help "Animate images once, or forever?"]
+        :help "Animate images once, or forever?"]
+       ["Reverse Animation" image-reverse-speed
+        :style toggle :selected (let ((image (image-get-display-property)))
+                                  (and image (<
+                                              (image-animate-get-speed image)
+                                              0)))
+        :active image-multi-frame
+        :help "Reverse direction of this image's animation?"]
+       ["Speed Up Animation" image-increase-speed
+        :active image-multi-frame
+        :help "Speed up this image's animation"]
+       ["Slow Down Animation" image-decrease-speed
+        :active image-multi-frame
+        :help "Slow down this image's animation"]
+       ["Reset Animation Speed" image-reset-speed
+        :active image-multi-frame
+        :help "Reset the speed of this image's animation"]
        ["Next Frame" image-next-frame :active image-multi-frame
         :help "Show the next frame of this image"]
        ["Previous Frame" image-previous-frame :active image-multi-frame
@@ -437,7 +483,10 @@ call."
 (defun image-mode ()
   "Major mode for image files.
 You can use \\<image-mode-map>\\[image-toggle-display]
-to toggle between display as an image and display as text."
+to toggle between display as an image and display as text.
+
+Key bindings:
+\\{image-mode-map}"
   (interactive)
   (condition-case err
       (progn
@@ -613,8 +662,19 @@ was inserted."
                           (string-make-unibyte
                            (buffer-substring-no-properties (point-min) (point-max)))
                         filename))
-        (type (image-type file-or-data nil data-p))
-        (image (create-image file-or-data type data-p))
+        ;; If we have a `fit-width' or a `fit-height', don't limit
+        ;; the size of the image to the window size.
+        (edges (and (null image-transform-resize)
+                    (window-inside-pixel-edges
+                     (get-buffer-window (current-buffer)))))
+        (type (if (fboundp 'imagemagick-types)
+                  'imagemagick
+                (image-type file-or-data nil data-p)))
+        (image (if (not edges)
+                   (create-image file-or-data type data-p)
+                 (create-image file-or-data type data-p
+                               :max-width (- (nth 2 edges) (nth 0 edges))
+                               :max-height (- (nth 3 edges) (nth 1 edges)))))
         (inhibit-read-only t)
         (buffer-undo-list t)
         (modified (buffer-modified-p))
@@ -703,6 +763,48 @@ Otherwise it plays once, then stops."
            (image-animate image index
                           (if image-animate-loop t)))))))))
 
+(defun image--set-speed (speed &optional multiply)
+  "Set speed of an animated image to SPEED.
+If MULTIPLY is non-nil, treat SPEED as a multiplication factor.
+If SPEED is `reset', reset the magnitude of the speed to 1."
+  (let ((image (image-get-display-property)))
+    (cond
+     ((null image)
+      (error "No image is present"))
+     ((null image-multi-frame)
+      (message "No image animation."))
+     (t
+      (if (eq speed 'reset)
+         (setq speed (if (< (image-animate-get-speed image) 0)
+                         -1 1)
+               multiply nil))
+      (image-animate-set-speed image speed multiply)
+      ;; FIXME Hack to refresh an active image.
+      (when (image-animate-timer image)
+       (image-toggle-animation)
+       (image-toggle-animation))
+      (message "Image speed is now %s" (image-animate-get-speed image))))))
+
+(defun image-increase-speed ()
+  "Increase the speed of current animated image by a factor of 2."
+  (interactive)
+  (image--set-speed 2 t))
+
+(defun image-decrease-speed ()
+  "Decrease the speed of current animated image by a factor of 2."
+  (interactive)
+  (image--set-speed 0.5 t))
+
+(defun image-reverse-speed ()
+  "Reverse the animation of the current image."
+  (interactive)
+  (image--set-speed -1 t))
+
+(defun image-reset-speed ()
+  "Reset the animation speed of the current image."
+  (interactive)
+  (image--set-speed 'reset))
+
 (defun image-goto-frame (n &optional relative)
   "Show frame N of a multi-frame image.
 Optional argument OFFSET non-nil means interpret N as relative to the
@@ -823,26 +925,6 @@ replacing the current Image mode buffer."
 ;;   nil "image-transform" image-transform-minor-mode-map)
 
 
-;; FIXME this doesn't seem mature yet. Document in manual when it is.
-(defvar image-transform-resize nil
-  "The image resize operation.
-Its value should be one of the following:
- - nil, meaning no resizing.
- - `fit-height', meaning to fit the image to the window height.
- - `fit-width', meaning to fit the image to the window width.
- - A number, which is a scale factor (the default size is 1).")
-
-(defvar image-transform-scale 1.0
-  "The scale factor of the image being displayed.")
-
-(defvar image-transform-rotation 0.0
-  "Rotation angle for the image in the current Image mode buffer.")
-
-(defvar image-transform-right-angle-fudge 0.0001
-  "Snap distance to a multiple of a right angle.
-There's no deep theory behind the default value, it should just
-be somewhat larger than ImageMagick's MagickEpsilon.")
-
 (defsubst image-transform-width (width height)
   "Return the bounding box width of a rotated WIDTH x HEIGHT rectangle.
 The rotation angle is the value of `image-transform-rotation' in degrees."
@@ -1024,6 +1106,16 @@ Emacs is compiled with ImageMagick support."
   (setq image-transform-rotation (float (mod rotation 360)))
   (image-toggle-display-image))
 
+(defun image-transform-reset ()
+  "Display the current image with the default size and rotation.
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (setq image-transform-resize nil
+       image-transform-rotation 0.0
+       image-transform-scale 1)
+  (image-toggle-display-image))
+
 (provide 'image-mode)
 
 ;;; image-mode.el ends here