]> git.eshelyaron.com Git - emacs.git/commitdiff
Enable selectable image smoothing (bug#38394)
authorAlan Third <alan@idiocy.org>
Tue, 9 Mar 2021 18:05:10 +0000 (18:05 +0000)
committerAlan Third <alan@idiocy.org>
Wed, 10 Mar 2021 21:40:42 +0000 (21:40 +0000)
* lisp/doc-view.el (doc-view-insert-image): Always use smoothing in
docview.
* lisp/image-mode.el (image-transform-smoothing): New variable.
(image-mode-map): Add smoothing binding.
(image-transform-properties): Apply smoothing when requested.
(image-transform-set-smoothing): New function.
(image-transform-reset): Reset smoothing.
* src/image.c (image_set_transform): Use new :transform-smoothing
attribute.
(syms_of_image): Add :transform-smoothing attribute.
* doc/lispref/display.texi (Image Descriptors): Document new
:transform-smoothing property.

doc/lispref/display.texi
etc/NEWS
lisp/doc-view.el
lisp/image-mode.el
src/image.c

index 131ad2d9c87f6b259e5759edc9c60ac6ffdde7f9..3d91ed27642fac5a2286b0e6bcbb2c2669ad8bb5 100644 (file)
@@ -5392,6 +5392,17 @@ are supported, unless the image type is @code{imagemagick}.  Positive
 values rotate clockwise, negative values counter-clockwise.  Rotation
 is performed after scaling and cropping.
 
+@item :transform-smoothing @var{smooth}
+When @code{t} any image transform will have smoothing applied, and if
+@code{nil} no smoothing will be applied.  The exact algorithm used
+will be platform dependent, but should be equivalent to bilinear
+filtering.  Disabling smoothing will use a nearest neighbour
+algorithm.
+
+The default, if this property is not specified, will be for
+down-scaling to apply smoothing, and up-scaling to not apply
+smoothing.
+
 @item :index @var{frame}
 @xref{Multi-Frame Images}.
 
index b48f7c361676ae61b17276912380d346940ca8c6..ac092675b4db43f418dd4f32d2815d43d0073821 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1473,6 +1473,16 @@ To load images with the default frame colors use the ':foreground' and
 This change only affects image types that support foreground and
 background colors or transparency, such as xbm, pbm, svg, png and gif.
 
++++
+*** Image smoothing can now be explicitly enabled or disabled.
+Smoothing applies a bilinear filter while scaling or rotating an image
+to prevent aliasing and other unwanted effects.  The new image
+property ':transform-smoothing' can be set to t to enable smoothing
+and nil to disable smoothing.
+
+The default behaviour of smoothing on down-scaling and not smoothing
+on up-scaling remains unchanged.
+
 ** EWW
 
 +++
index f6fcfae453eb3ac0d484fca506037638eae856eb..cef09009d95f9fd684d1c5f349ca99a527409947 100644 (file)
@@ -1439,6 +1439,8 @@ ARGS is a list of image descriptors."
                            (apply #'create-image file doc-view--image-type nil args)
                          (unless (member :width args)
                            (setq args `(,@args :width ,doc-view-image-width)))
+                          (unless (member :transform-smoothing args)
+                            (setq args `(,@args :transform-smoothing t)))
                          (apply #'create-image file doc-view--image-type nil args))))
             (slice (doc-view-current-slice))
             (img-width (and image (car (image-size image))))
index 7384abf3b239b48ad10aa5804fe9c68b19652f1a..8b61aa7e73fa50da23afc0ec097f074af233c3d5 100644 (file)
@@ -95,6 +95,9 @@ Its value should be one of the following:
 (defvar-local image-transform-rotation 0.0
   "Rotation angle for the image in the current Image mode buffer.")
 
+(defvar-local image-transform-smoothing nil
+  "Whether to use transform smoothing.")
+
 (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
@@ -457,6 +460,7 @@ call."
     (define-key map "sb" 'image-transform-fit-both)
     (define-key map "ss" 'image-transform-set-scale)
     (define-key map "sr" 'image-transform-set-rotation)
+    (define-key map "sm" 'image-transform-set-smoothing)
     (define-key map "so" 'image-transform-original)
     (define-key map "s0" 'image-transform-reset)
 
@@ -523,6 +527,8 @@ call."
         :help "Rotate the image"]
        ["Set Rotation..." image-transform-set-rotation
         :help "Set rotation angle of the image"]
+        ["Set Smoothing..." image-transform-set-smoothing
+        :help "Toggle smoothing"]
        ["Original Size" image-transform-original
         :help "Reset image to actual size"]
        ["Reset to Default Size" image-transform-reset
@@ -1474,7 +1480,10 @@ return value is suitable for appending to an image spec."
        ,@(when (cdr resized)
            (list :height (cdr resized)))
        ,@(unless (= 0.0 image-transform-rotation)
-           (list :rotation image-transform-rotation))))))
+           (list :rotation image-transform-rotation))
+        ,@(when image-transform-smoothing
+            (list :transform-smoothing
+                  (string= image-transform-smoothing "smooth")))))))
 
 (defun image-transform-set-scale (scale)
   "Prompt for a number, and resize the current image by that amount."
@@ -1507,6 +1516,12 @@ ROTATION should be in degrees."
   (setq image-transform-rotation (float (mod rotation 360)))
   (image-toggle-display-image))
 
+(defun image-transform-set-smoothing (smoothing)
+  (interactive (list (completing-read "Smoothing: "
+                                      '("none" "smooth") nil t)))
+  (setq image-transform-smoothing smoothing)
+  (image-toggle-display-image))
+
 (defun image-transform-original ()
   "Display the current image with the original (actual) size and rotation."
   (interactive)
@@ -1519,7 +1534,8 @@ ROTATION should be in degrees."
   (interactive)
   (setq image-transform-resize image-auto-resize
        image-transform-rotation 0.0
-       image-transform-scale 1)
+       image-transform-scale 1
+        image-transform-smoothing nil)
   (image-toggle-display-image))
 
 (provide 'image-mode)
index 8137dbea8d7ec725a8ff1e7a0e19b9564b1c8a9f..95ae573354d080dc18f8740009ec404864e02715 100644 (file)
@@ -2230,7 +2230,12 @@ image_set_transform (struct frame *f, struct image *img)
      operations to use a blended filter, to avoid aliasing and the like.
 
      TODO: implement for Windows.  */
-  bool scale_down = (width < img->width) || (height < img->height);
+  bool smoothing;
+  Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL);
+  if (!s)
+    smoothing = (width < img->width) || (height < img->height);
+  else
+    smoothing = !NILP (s);
 # endif
 
   /* Perform scale transformation.  */
@@ -2344,13 +2349,13 @@ image_set_transform (struct frame *f, struct image *img)
   /* Under NS the transform is applied to the drawing surface at
      drawing time, so store it for later.  */
   ns_image_set_transform (img->pixmap, matrix);
-  ns_image_set_smoothing (img->pixmap, scale_down);
+  ns_image_set_smoothing (img->pixmap, smoothing);
 # elif defined USE_CAIRO
   cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0],
                              matrix[1][1], matrix[2][0], matrix[2][1]};
   cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
   cairo_pattern_set_matrix (pattern, &cr_matrix);
-  cairo_pattern_set_filter (pattern, scale_down
+  cairo_pattern_set_filter (pattern, smoothing
                             ? CAIRO_FILTER_BEST : CAIRO_FILTER_NEAREST);
   /* Dummy solid color pattern just to record pattern matrix.  */
   img->cr_data = pattern;
@@ -2369,13 +2374,13 @@ image_set_transform (struct frame *f, struct image *img)
              XDoubleToFixed (matrix[2][2])}}};
 
       XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture,
-                               scale_down ? FilterBest : FilterNearest, 0, 0);
+                               smoothing ? FilterBest : FilterNearest, 0, 0);
       XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
 
       if (img->mask_picture)
         {
           XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture,
-                                   scale_down ? FilterBest : FilterNearest, 0, 0);
+                                   smoothing ? FilterBest : FilterNearest, 0, 0);
           XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture,
                                       &tmat);
         }
@@ -10693,6 +10698,7 @@ non-numeric, there is no explicit limit on the size of images.  */);
   DEFSYM (QCrotation, ":rotation");
   DEFSYM (QCmatrix, ":matrix");
   DEFSYM (QCscale, ":scale");
+  DEFSYM (QCtransform_smoothing, ":transform-smoothing");
   DEFSYM (QCcolor_adjustment, ":color-adjustment");
   DEFSYM (QCmask, ":mask");