emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master c93447e: Enable selectable image smoothing (bug#38394)


From: Alan Third
Subject: master c93447e: Enable selectable image smoothing (bug#38394)
Date: Wed, 10 Mar 2021 16:44:14 -0500 (EST)

branch: master
commit c93447eac6f801d7ff97ed6dad368dc49d55cc46
Author: Alan Third <alan@idiocy.org>
Commit: Alan Third <alan@idiocy.org>

    Enable selectable image smoothing (bug#38394)
    
    * 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 | 11 +++++++++++
 etc/NEWS                 | 10 ++++++++++
 lisp/doc-view.el         |  2 ++
 lisp/image-mode.el       | 20 ++++++++++++++++++--
 src/image.c              | 16 +++++++++++-----
 5 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 131ad2d..3d91ed2 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -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}.
 
diff --git a/etc/NEWS b/etc/NEWS
index b48f7c3..ac09267 100644
--- 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
 
 +++
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index f6fcfae..cef0900 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -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))))
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 7384abf..8b61aa7 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -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)
diff --git a/src/image.c b/src/image.c
index 8137dbe..95ae573 100644
--- a/src/image.c
+++ b/src/image.c
@@ -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");
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]