emacs-diffs
[Top][All Lists]
Advanced

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

master 519a93e: Don't smooth images when scaling up (bug#38394)


From: Alan Third
Subject: master 519a93e: Don't smooth images when scaling up (bug#38394)
Date: Tue, 4 Aug 2020 15:50:12 -0400 (EDT)

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

    Don't smooth images when scaling up (bug#38394)
    
    * src/image.c (image_set_transform [HAVE_XRENDER]): Use different filter
    when scaling up vs scaling down.
    * src/nsimage.m (ns_image_set_smoothing):
    ([EmacsImage setSmoothing:]): New functions.
    * src/nsterm.h: Add definitions.
    * src/nsterm.m (ns_dumpglyphs_image): Disable smoothing if requested.
---
 src/image.c   | 20 +++++++++++++++++---
 src/nsimage.m | 12 ++++++++++++
 src/nsterm.h  |  3 +++
 src/nsterm.m  | 12 ++++++++++++
 4 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/src/image.c b/src/image.c
index e7e0a93..e236b38 100644
--- a/src/image.c
+++ b/src/image.c
@@ -259,6 +259,8 @@ cr_put_image_to_cr_data (struct image *img)
          cairo_matrix_t matrix;
          cairo_pattern_get_matrix (img->cr_data, &matrix);
          cairo_pattern_set_matrix (pattern, &matrix);
+          cairo_pattern_set_filter
+            (pattern, cairo_pattern_get_filter (img->cr_data));
          cairo_pattern_destroy (img->cr_data);
        }
       cairo_surface_destroy (surface);
@@ -2114,6 +2116,15 @@ image_set_transform (struct frame *f, struct image *img)
   double rotation = 0.0;
   compute_image_rotation (img, &rotation);
 
+# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS
+  /* We want scale up operations to use a nearest neighbour filter to
+     show real pixels instead of munging them, but scale down
+     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);
+# endif
+
   /* Perform scale transformation.  */
 
   matrix3x3 matrix
@@ -2225,11 +2236,14 @@ 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);
 # 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_FILTER_BEST : CAIRO_FILTER_NEAREST);
   /* Dummy solid color pattern just to record pattern matrix.  */
   img->cr_data = pattern;
 # elif defined (HAVE_XRENDER)
@@ -2246,14 +2260,14 @@ image_set_transform (struct frame *f, struct image *img)
              XDoubleToFixed (matrix[1][2]),
              XDoubleToFixed (matrix[2][2])}}};
 
-      XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
-                              0, 0);
+      XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture,
+                               scale_down ? FilterBest : FilterNearest, 0, 0);
       XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
 
       if (img->mask_picture)
         {
           XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture,
-                                   FilterBest, 0, 0);
+                                   scale_down ? FilterBest : FilterNearest, 0, 
0);
           XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture,
                                       &tmat);
         }
diff --git a/src/nsimage.m b/src/nsimage.m
index 07750de..966e704 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -199,6 +199,12 @@ ns_image_set_transform (void *img, double m[3][3])
   [(EmacsImage *)img setTransform:m];
 }
 
+void
+ns_image_set_smoothing (void *img, bool smooth)
+{
+  [(EmacsImage *)img setSmoothing:smooth];
+}
+
 unsigned long
 ns_get_pixel (void *img, int x, int y)
 {
@@ -591,4 +597,10 @@ ns_set_alpha (void *img, int x, int y, unsigned char a)
   [transform setTransformStruct:tm];
 }
 
+- (void)setSmoothing: (BOOL) s
+{
+  smoothing = s;
+}
+
+
 @end
diff --git a/src/nsterm.h b/src/nsterm.h
index 8d5371c..a511fef 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -640,6 +640,7 @@ typedef id instancetype;
   unsigned long xbm_fg;
 @public
   NSAffineTransform *transform;
+  BOOL smoothing;
 }
 + (instancetype)allocInitFromFile: (Lisp_Object)file;
 - (void)dealloc;
@@ -658,6 +659,7 @@ typedef id instancetype;
 - (Lisp_Object)getMetadata;
 - (BOOL)setFrame: (unsigned int) index;
 - (void)setTransform: (double[3][3]) m;
+- (void)setSmoothing: (BOOL)s;
 @end
 
 
@@ -1200,6 +1202,7 @@ extern int ns_image_width (void *img);
 extern int ns_image_height (void *img);
 extern void ns_image_set_size (void *img, int width, int height);
 extern void ns_image_set_transform (void *img, double m[3][3]);
+extern void ns_image_set_smoothing (void *img, bool smooth);
 extern unsigned long ns_get_pixel (void *img, int x, int y);
 extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
 extern void ns_set_alpha (void *img, int x, int y, unsigned char a);
diff --git a/src/nsterm.m b/src/nsterm.m
index df7f716..572b859 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -4043,10 +4043,22 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
 
       [doTransform concat];
 
+      /* Smoothing is the default, so if we don't want smoothing we
+         have to turn it off.  */
+      if (! img->smoothing)
+        [[NSGraphicsContext currentContext]
+          setImageInterpolation:NSImageInterpolationNone];
+
       [img drawInRect:ir fromRect:ir
             operation:NSCompositingOperationSourceOver
              fraction:1.0 respectFlipped:YES hints:nil];
 
+      /* Apparently image interpolation is not reset with
+         restoreGraphicsState, so we have to manually reset it.  */
+      if (! img->smoothing)
+        [[NSGraphicsContext currentContext]
+          setImageInterpolation:NSImageInterpolationDefault];
+
       [[NSGraphicsContext currentContext] restoreGraphicsState];
     }
 



reply via email to

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