summaryrefslogtreecommitdiff
path: root/lisp/image.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/image.el')
-rw-r--r--lisp/image.el80
1 files changed, 66 insertions, 14 deletions
diff --git a/lisp/image.el b/lisp/image.el
index 6955a90de77..494c26a8a33 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -141,6 +141,18 @@ based on the font pixel size."
(const :tag "Automatically compute" auto))
:version "26.1")
+(defcustom image-transform-smoothing #'image--default-smoothing
+ "Whether to do smoothing when applying transforms to images.
+Common transforms are rescaling and rotation.
+
+Valid values are nil (no smoothing), t (smoothing) or a predicate
+function that is called with the image specification and should return
+either nil or non-nil."
+ :type '(choice (const :tag "Do smoothing" t)
+ (const :tag "No smoothing" nil)
+ function)
+ :version "28.1")
+
(defcustom image-use-external-converter nil
"If non-nil, `create-image' will use external converters for exotic formats.
Emacs handles most of the common image formats (SVG, JPEG, PNG, GIF
@@ -485,11 +497,40 @@ Image file names that are not absolute are searched for in the
type 'png
data-p t)))
(when (image-type-available-p type)
- (append (list 'image :type type (if data-p :data :file) file-or-data)
- (and (not (plist-get props :scale))
- (list :scale
- (image-compute-scaling-factor image-scaling-factor)))
- props)))
+ (let ((image
+ (append (list 'image :type type (if data-p :data :file)
+ file-or-data)
+ (and (not (plist-get props :scale))
+ ;; Add default scaling.
+ (list :scale
+ (image-compute-scaling-factor
+ image-scaling-factor)))
+ props)))
+ ;; Add default smoothing.
+ (unless (plist-member props :transform-smoothing)
+ (setq image (nconc image
+ (list :transform-smoothing
+ (pcase image-transform-smoothing
+ ('t t)
+ ('nil nil)
+ (func (funcall func image)))))))
+ image)))
+
+(defun image--default-smoothing (image)
+ "Say whether IMAGE should be smoothed when transformed."
+ (let* ((props (nthcdr 5 image))
+ (scaling (plist-get props :scale))
+ (rotation (plist-get props :rotation)))
+ (cond
+ ;; We always smooth when scaling down and small upwards scaling.
+ ((and scaling (< scaling 2))
+ t)
+ ;; Smooth when doing non-90-degree rotation
+ ((and rotation
+ (or (not (zerop (mod rotation 1)))
+ (not (zerop (% (truncate rotation) 90)))))
+ t)
+ (t nil))))
(defun image--set-property (image property value)
"Set PROPERTY in IMAGE to VALUE.
@@ -562,12 +603,16 @@ means display it in the right marginal area."
(defun insert-image (image &optional string area slice)
"Insert IMAGE into current buffer at point.
IMAGE is displayed by inserting STRING into the current buffer
-with a `display' property whose value is the image. STRING
-defaults to a single space if you omit it.
+with a `display' property whose value is the image.
+
+STRING defaults to a single space if you omit it, which means
+that the inserted image will behave as whitespace syntactically.
+
AREA is where to display the image. AREA nil or omitted means
display it in the text area, a value of `left-margin' means
display it in the left marginal area, a value of `right-margin'
means display it in the right marginal area.
+
SLICE specifies slice of IMAGE to insert. SLICE nil or omitted
means insert whole image. SLICE is a list (X Y WIDTH HEIGHT)
specifying the X and Y positions and WIDTH and HEIGHT of image area
@@ -794,6 +839,9 @@ number, play until that number of seconds has elapsed."
(cancel-timer timer))
(plist-put (cdr image) :animate-buffer (current-buffer))
(plist-put (cdr image) :animate-tardiness 0)
+ ;; Stash the data about the animation here so that we don't
+ ;; trigger image recomputation unnecessarily later.
+ (plist-put (cdr image) :animate-multi-frame-data animation)
(run-with-timer 0.2 nil #'image-animate-timeout
image (or index 0) (car animation)
0 limit (+ (float-time) 0.2)))))
@@ -824,9 +872,10 @@ Frames are indexed from 0. Optional argument NOCHECK non-nil means
do not check N is within the range of frames present in the image."
(unless nocheck
(if (< n 0) (setq n 0)
- (setq n (min n (1- (car (image-multi-frame-p image)))))))
+ (setq n (min n (1- (car (plist-get (cdr image)
+ :animate-multi-frame-data)))))))
(plist-put (cdr image) :index n)
- (force-window-update))
+ (force-window-update (plist-get (cdr image) :animate-buffer)))
(defun image-animate-get-speed (image)
"Return the speed factor for animating IMAGE."
@@ -872,11 +921,11 @@ for the animation speed. A negative value means to animate in reverse."
(image-show-frame image n t)
(let* ((speed (image-animate-get-speed image))
(time (current-time))
- (animation (image-multi-frame-p image))
(time-to-load-image (time-since time))
- (stated-delay-time (/ (or (cdr animation)
- image-default-frame-delay)
- (float (abs speed))))
+ (stated-delay-time
+ (/ (or (cdr (plist-get (cdr image) :animate-multi-frame-data))
+ image-default-frame-delay)
+ (float (abs speed))))
;; Subtract off the time we took to load the image from the
;; stated delay time.
(delay (max (float-time (time-subtract stated-delay-time
@@ -1089,6 +1138,7 @@ default is 20%."
image))
(defun image--get-imagemagick-and-warn (&optional position)
+ (declare-function image-transforms-p "image.c" (&optional frame))
(unless (or (fboundp 'imagemagick-types) (image-transforms-p))
(error "Cannot rescale images on this terminal"))
(let ((image (image--get-image position)))
@@ -1141,7 +1191,9 @@ rotations by only multiples of 90 degrees."
360)))))
(defun image-save ()
- "Save the image under point."
+ "Save the image under point.
+This writes the original image data to a file. Rotating or
+changing the displayed image size does not affect the saved image."
(interactive)
(let ((image (image--get-image)))
(with-temp-buffer