summaryrefslogtreecommitdiff
path: root/lisp/image-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/image-mode.el')
-rw-r--r--lisp/image-mode.el132
1 files changed, 94 insertions, 38 deletions
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 1eb7cd58c3d..b2af3f06a27 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -58,16 +58,25 @@ It is called with one argument, the initial WINPROPS.")
"Non-nil to resize the image upon first display.
Its value should be one of the following:
- nil, meaning no resizing.
- - t, meaning to fit the image to the window height and width.
- - `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)."
+ - t, meaning to scale the image down to fit in the window.
+ - `fit-window', meaning to fit the image to the window.
+ - A number, which is a scale factor (the default size is 1).
+
+Resizing will always preserve the aspect ratio of the image."
:type '(choice (const :tag "No resizing" nil)
- (other :tag "Fit height and width" t)
- (const :tag "Fit height" fit-height)
- (const :tag "Fit width" fit-width)
+ (const :tag "Fit to window" fit-window)
+ (other :tag "Scale down to fit window" t)
(number :tag "Scale factor" 1))
- :version "27.1"
+ :version "29.1"
+ :group 'image)
+
+(defcustom image-auto-resize-max-scale-percent nil
+ "Max size (in percent) to scale up to when `image-auto-resize' is `fit-window'.
+Can be either a number larger than 100, or nil, which means no
+max size."
+ :type '(choice (const :tag "No max" nil)
+ natnum)
+ :version "29.1"
:group 'image)
(defcustom image-auto-resize-on-window-resize 1
@@ -82,12 +91,18 @@ resizing according to the value specified in `image-auto-resize'."
(defvar-local image-transform-resize nil
"The image resize operation.
+Non-nil to resize the image upon first display.
Its value should be one of the following:
- nil, meaning no resizing.
- - t, meaning to fit the image to the window height and width.
+ - t, meaning to scale the image down to fit in the window.
+ - `fit-window', meaning to fit the image to the window.
+ - A number, which is a scale factor (the default size is 1).
+
+There is also support for these values, obsolete since Emacs 29.1:
- `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).")
+
+Resizing will always preserve the aspect ratio of the image.")
(defvar-local image-transform-scale 1.0
"The scale factor of the image being displayed.")
@@ -440,6 +455,15 @@ call."
;;; Image Mode setup
+(defcustom image-text-based-formats '(svg xpm)
+ "List of image formats that use a plain text format.
+For such formats, display a message that explains how to edit the
+image as text, when opening such images in `image-mode'."
+ :type '(choice (const :tag "Disable completely" nil)
+ (repeat :tag "List of formats" sexp))
+ :version "29.1"
+ :group 'image)
+
(defvar-local image-type nil
"The image type for the current Image mode buffer.")
@@ -455,8 +479,9 @@ call."
;; Transformation keys
(define-key map "sf" 'image-mode-fit-frame)
+ (define-key map "sw" 'image-transform-fit-to-window)
(define-key map "sh" 'image-transform-fit-to-height)
- (define-key map "sw" 'image-transform-fit-to-width)
+ (define-key map "si" 'image-transform-fit-to-width)
(define-key map "sb" 'image-transform-fit-both)
(define-key map "ss" 'image-transform-set-scale)
(define-key map "sr" 'image-transform-set-rotation)
@@ -511,12 +536,10 @@ call."
"--"
["Fit Frame to Image" image-mode-fit-frame :active t
:help "Resize frame to match image"]
- ["Fit Image to Window (Best Fit)" image-transform-fit-both
- :help "Resize image to match the window height and width"]
- ["Fit to Window Height" image-transform-fit-to-height
- :help "Resize image to match the window height"]
- ["Fit to Window Width" image-transform-fit-to-width
- :help "Resize image to match the window width"]
+ ["Fit Image to Window" image-transform-fit-to-window
+ :help "Resize image to match the window height and width"]
+ ["Fit Image to Window (Scale down only)" image-transform-fit-both
+ :help "Scale image down to match the window height and width"]
["Zoom In" image-increase-size
:help "Enlarge the image"]
["Zoom Out" image-decrease-size
@@ -605,8 +628,9 @@ call."
;;;###autoload
(defun image-mode ()
"Major mode for image files.
-You can use \\<image-mode-map>\\[image-toggle-display] or \\<image-mode-map>\\[image-toggle-hex-display]
-to toggle between display as an image and display as text or hex.
+You can use \\<image-mode-map>\\[image-toggle-display] or \
+\\[image-toggle-hex-display] to toggle between display
+as an image and display as text or hex.
Key bindings:
\\{image-mode-map}"
@@ -680,12 +704,10 @@ Key bindings:
(run-mode-hooks 'image-mode-hook)
(let ((image (image-get-display-property))
- (msg1 (substitute-command-keys
- "Type \\[image-toggle-display] or \\[image-toggle-hex-display] to view the image as "))
- animated)
+ msg animated)
(cond
((null image)
- (message "%s" (concat msg1 "an image.")))
+ (setq msg "an image"))
((setq animated (image-multi-frame-p image))
(setq image-multi-frame t
mode-line-process
@@ -703,10 +725,13 @@ Key bindings:
keymap
(down-mouse-1 . image-next-frame)
(down-mouse-3 . image-previous-frame)))))))
- (message "%s"
- (concat msg1 "text. This image has multiple frames.")))
+ (setq msg "text. This image has multiple frames"))
(t
- (message "%s" (concat msg1 "text or hex."))))))
+ (setq msg "text")))
+ (when (memq (plist-get (cdr image) :type) image-text-based-formats)
+ (message (substitute-command-keys
+ "Type \\[image-toggle-display] to view the image as %s")
+ msg))))
;;;###autoload
(define-minor-mode image-minor-mode
@@ -753,11 +778,11 @@ on these modes."
(image-mode-to-text)
;; Turn on hexl-mode
(hexl-mode)
- (message "%s" (concat
- (substitute-command-keys
- "Type \\[image-toggle-hex-display] or \\[image-toggle-display] to view the image as ")
- (if (image-get-display-property)
- "hex" "an image or text") ".")))
+ (message (substitute-command-keys
+ "Type \\[image-toggle-hex-display] or \
+\\[image-toggle-display] to view the image as %s")
+ (if (image-get-display-property)
+ "hex" "an image or text")))
(defun image-mode-as-text ()
"Set a non-image mode as major mode in combination with image minor mode.
@@ -773,11 +798,10 @@ See commands `image-mode' and `image-minor-mode' for more information
on these modes."
(interactive)
(image-mode-to-text)
- (message "%s" (concat
- (substitute-command-keys
- "Type \\[image-toggle-display] or \\[image-toggle-hex-display] to view the image as ")
- (if (image-get-display-property)
- "text" "an image or hex") ".")))
+ (message (substitute-command-keys
+ "Type \\[image-toggle-display] to view the image as %s")
+ (if (image-get-display-property)
+ "text" "an image")))
(defun image-toggle-display-text ()
"Show the image file as text.
@@ -805,6 +829,21 @@ Remove text properties that display the image."
(defvar tar-superior-buffer)
(declare-function image-flush "image.c" (spec &optional frame))
+(defun image--scale-within-limits-p (image)
+ "Return t if `fit-window' will scale image within the customized limits.
+The limits are given by the user option
+`image-auto-resize-max-scale-percent'."
+ (or (not image-auto-resize-max-scale-percent)
+ (let ((scale (/ image-auto-resize-max-scale-percent 100))
+ (mw (plist-get (cdr image) :max-width))
+ (mh (plist-get (cdr image) :max-height))
+ ;; Note: `image-size' looks up and thus caches the
+ ;; untransformed image. There's no easy way to
+ ;; prevent that.
+ (size (image-size image t)))
+ (or (<= mw (* (car size) scale))
+ (<= mh (* (cdr size) scale))))))
+
(defun image-toggle-display-image ()
"Show the image of the image file.
Turn the image data into a real image, but only if the whole file
@@ -839,7 +878,8 @@ was inserted."
filename))
;; If we have a `fit-width' or a `fit-height', don't limit
;; the size of the image to the window size.
- (edges (when (eq image-transform-resize t)
+ (edges (when (or (eq image-transform-resize t)
+ (eq image-transform-resize 'fit-window))
(window-inside-pixel-edges (get-buffer-window))))
(max-width (when edges
(- (nth 2 edges) (nth 0 edges))))
@@ -886,6 +926,14 @@ was inserted."
;; Type hint.
:format (and filename data-p))))
+ ;; Handle `fit-window'.
+ (when (and (eq image-transform-resize 'fit-window)
+ (image--scale-within-limits-p image))
+ (setq image
+ (cons (car image)
+ (plist-put (cdr image) :width
+ (plist-get (cdr image) :max-width)))))
+
;; Discard any stale image data before looking it up again.
(image-flush image)
(setq image (append image (image-transform-properties image)))
@@ -1496,21 +1544,29 @@ return value is suitable for appending to an image spec."
(defun image-transform-fit-to-height ()
"Fit the current image to the height of the current window."
(interactive)
+ (declare (obsolete nil "29.1"))
(setq image-transform-resize 'fit-height)
(image-toggle-display-image))
(defun image-transform-fit-to-width ()
"Fit the current image to the width of the current window."
+ (declare (obsolete nil "29.1"))
(interactive)
(setq image-transform-resize 'fit-width)
(image-toggle-display-image))
(defun image-transform-fit-both ()
- "Fit the current image both to the height and width of the current window."
+ "Scale the current image down to fit in the current window."
(interactive)
(setq image-transform-resize t)
(image-toggle-display-image))
+(defun image-transform-fit-to-window ()
+ "Fit the current image to the height and width of the current window."
+ (interactive)
+ (setq image-transform-resize 'fit-window)
+ (image-toggle-display-image))
+
(defun image-transform-set-rotation (rotation)
"Prompt for an angle ROTATION, and rotate the image by that amount.
ROTATION should be in degrees."