]> git.eshelyaron.com Git - emacs.git/commitdiff
Don't smooth images when scaling up (bug#38394)
authorAlan Third <alan@idiocy.org>
Sun, 2 Aug 2020 19:43:56 +0000 (20:43 +0100)
committerAlan Third <alan@idiocy.org>
Tue, 4 Aug 2020 19:50:01 +0000 (20:50 +0100)
* 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
src/nsimage.m
src/nsterm.h
src/nsterm.m

index e7e0a93313ba928f24fc8d53dbfe8989b93c7dba..e236b389210fba1dfce3b466b577b94fdfa19f25 100644 (file)
@@ -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);
         }
index 07750de95fecc3da44a883e19bc1b1fa67c12155..966e7044f129ac1ce7b58faa780d0e51018a70f3 100644 (file)
@@ -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
index 8d5371c8f24ad16e7fb158514c97b425cbca3b4b..a511fef5b98c9b84803d4aaba05a15ee10c61edd 100644 (file)
@@ -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);
index df7f716f51e1baf80e39d1112dbeff28f3e7caca..572b859a98212dadd8c398436e4691bd6d7647cb 100644 (file)
@@ -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];
     }