diff options
| author | Alan Third | 2020-08-02 20:43:56 +0100 |
|---|---|---|
| committer | Alan Third | 2020-08-04 20:50:01 +0100 |
| commit | 519a93e067f459ceddb57573261a52118086b73d (patch) | |
| tree | 5d3411e476eb7bb4082bfcba925de00d6cbc0659 /src | |
| parent | 6e70b3793b9cb7730ab8a7132aa6e99f1ca13f98 (diff) | |
| download | emacs-519a93e067f459ceddb57573261a52118086b73d.tar.gz emacs-519a93e067f459ceddb57573261a52118086b73d.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/image.c | 20 | ||||
| -rw-r--r-- | src/nsimage.m | 12 | ||||
| -rw-r--r-- | src/nsterm.h | 3 | ||||
| -rw-r--r-- | src/nsterm.m | 12 |
4 files changed, 44 insertions, 3 deletions
diff --git a/src/image.c b/src/image.c index e7e0a93313b..e236b389210 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -259,6 +259,8 @@ cr_put_image_to_cr_data (struct image *img) | |||
| 259 | cairo_matrix_t matrix; | 259 | cairo_matrix_t matrix; |
| 260 | cairo_pattern_get_matrix (img->cr_data, &matrix); | 260 | cairo_pattern_get_matrix (img->cr_data, &matrix); |
| 261 | cairo_pattern_set_matrix (pattern, &matrix); | 261 | cairo_pattern_set_matrix (pattern, &matrix); |
| 262 | cairo_pattern_set_filter | ||
| 263 | (pattern, cairo_pattern_get_filter (img->cr_data)); | ||
| 262 | cairo_pattern_destroy (img->cr_data); | 264 | cairo_pattern_destroy (img->cr_data); |
| 263 | } | 265 | } |
| 264 | cairo_surface_destroy (surface); | 266 | cairo_surface_destroy (surface); |
| @@ -2114,6 +2116,15 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 2114 | double rotation = 0.0; | 2116 | double rotation = 0.0; |
| 2115 | compute_image_rotation (img, &rotation); | 2117 | compute_image_rotation (img, &rotation); |
| 2116 | 2118 | ||
| 2119 | # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS | ||
| 2120 | /* We want scale up operations to use a nearest neighbour filter to | ||
| 2121 | show real pixels instead of munging them, but scale down | ||
| 2122 | operations to use a blended filter, to avoid aliasing and the like. | ||
| 2123 | |||
| 2124 | TODO: implement for Windows. */ | ||
| 2125 | bool scale_down = (width < img->width) || (height < img->height); | ||
| 2126 | # endif | ||
| 2127 | |||
| 2117 | /* Perform scale transformation. */ | 2128 | /* Perform scale transformation. */ |
| 2118 | 2129 | ||
| 2119 | matrix3x3 matrix | 2130 | matrix3x3 matrix |
| @@ -2225,11 +2236,14 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 2225 | /* Under NS the transform is applied to the drawing surface at | 2236 | /* Under NS the transform is applied to the drawing surface at |
| 2226 | drawing time, so store it for later. */ | 2237 | drawing time, so store it for later. */ |
| 2227 | ns_image_set_transform (img->pixmap, matrix); | 2238 | ns_image_set_transform (img->pixmap, matrix); |
| 2239 | ns_image_set_smoothing (img->pixmap, scale_down); | ||
| 2228 | # elif defined USE_CAIRO | 2240 | # elif defined USE_CAIRO |
| 2229 | cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0], | 2241 | cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0], |
| 2230 | matrix[1][1], matrix[2][0], matrix[2][1]}; | 2242 | matrix[1][1], matrix[2][0], matrix[2][1]}; |
| 2231 | cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); | 2243 | cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); |
| 2232 | cairo_pattern_set_matrix (pattern, &cr_matrix); | 2244 | cairo_pattern_set_matrix (pattern, &cr_matrix); |
| 2245 | cairo_pattern_set_filter (pattern, scale_down | ||
| 2246 | ? CAIRO_FILTER_BEST : CAIRO_FILTER_NEAREST); | ||
| 2233 | /* Dummy solid color pattern just to record pattern matrix. */ | 2247 | /* Dummy solid color pattern just to record pattern matrix. */ |
| 2234 | img->cr_data = pattern; | 2248 | img->cr_data = pattern; |
| 2235 | # elif defined (HAVE_XRENDER) | 2249 | # elif defined (HAVE_XRENDER) |
| @@ -2246,14 +2260,14 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 2246 | XDoubleToFixed (matrix[1][2]), | 2260 | XDoubleToFixed (matrix[1][2]), |
| 2247 | XDoubleToFixed (matrix[2][2])}}}; | 2261 | XDoubleToFixed (matrix[2][2])}}}; |
| 2248 | 2262 | ||
| 2249 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, | 2263 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, |
| 2250 | 0, 0); | 2264 | scale_down ? FilterBest : FilterNearest, 0, 0); |
| 2251 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); | 2265 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); |
| 2252 | 2266 | ||
| 2253 | if (img->mask_picture) | 2267 | if (img->mask_picture) |
| 2254 | { | 2268 | { |
| 2255 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture, | 2269 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture, |
| 2256 | FilterBest, 0, 0); | 2270 | scale_down ? FilterBest : FilterNearest, 0, 0); |
| 2257 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture, | 2271 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture, |
| 2258 | &tmat); | 2272 | &tmat); |
| 2259 | } | 2273 | } |
diff --git a/src/nsimage.m b/src/nsimage.m index 07750de95fe..966e7044f12 100644 --- a/src/nsimage.m +++ b/src/nsimage.m | |||
| @@ -199,6 +199,12 @@ ns_image_set_transform (void *img, double m[3][3]) | |||
| 199 | [(EmacsImage *)img setTransform:m]; | 199 | [(EmacsImage *)img setTransform:m]; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | void | ||
| 203 | ns_image_set_smoothing (void *img, bool smooth) | ||
| 204 | { | ||
| 205 | [(EmacsImage *)img setSmoothing:smooth]; | ||
| 206 | } | ||
| 207 | |||
| 202 | unsigned long | 208 | unsigned long |
| 203 | ns_get_pixel (void *img, int x, int y) | 209 | ns_get_pixel (void *img, int x, int y) |
| 204 | { | 210 | { |
| @@ -591,4 +597,10 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) | |||
| 591 | [transform setTransformStruct:tm]; | 597 | [transform setTransformStruct:tm]; |
| 592 | } | 598 | } |
| 593 | 599 | ||
| 600 | - (void)setSmoothing: (BOOL) s | ||
| 601 | { | ||
| 602 | smoothing = s; | ||
| 603 | } | ||
| 604 | |||
| 605 | |||
| 594 | @end | 606 | @end |
diff --git a/src/nsterm.h b/src/nsterm.h index 8d5371c8f24..a511fef5b98 100644 --- a/src/nsterm.h +++ b/src/nsterm.h | |||
| @@ -640,6 +640,7 @@ typedef id instancetype; | |||
| 640 | unsigned long xbm_fg; | 640 | unsigned long xbm_fg; |
| 641 | @public | 641 | @public |
| 642 | NSAffineTransform *transform; | 642 | NSAffineTransform *transform; |
| 643 | BOOL smoothing; | ||
| 643 | } | 644 | } |
| 644 | + (instancetype)allocInitFromFile: (Lisp_Object)file; | 645 | + (instancetype)allocInitFromFile: (Lisp_Object)file; |
| 645 | - (void)dealloc; | 646 | - (void)dealloc; |
| @@ -658,6 +659,7 @@ typedef id instancetype; | |||
| 658 | - (Lisp_Object)getMetadata; | 659 | - (Lisp_Object)getMetadata; |
| 659 | - (BOOL)setFrame: (unsigned int) index; | 660 | - (BOOL)setFrame: (unsigned int) index; |
| 660 | - (void)setTransform: (double[3][3]) m; | 661 | - (void)setTransform: (double[3][3]) m; |
| 662 | - (void)setSmoothing: (BOOL)s; | ||
| 661 | @end | 663 | @end |
| 662 | 664 | ||
| 663 | 665 | ||
| @@ -1200,6 +1202,7 @@ extern int ns_image_width (void *img); | |||
| 1200 | extern int ns_image_height (void *img); | 1202 | extern int ns_image_height (void *img); |
| 1201 | extern void ns_image_set_size (void *img, int width, int height); | 1203 | extern void ns_image_set_size (void *img, int width, int height); |
| 1202 | extern void ns_image_set_transform (void *img, double m[3][3]); | 1204 | extern void ns_image_set_transform (void *img, double m[3][3]); |
| 1205 | extern void ns_image_set_smoothing (void *img, bool smooth); | ||
| 1203 | extern unsigned long ns_get_pixel (void *img, int x, int y); | 1206 | extern unsigned long ns_get_pixel (void *img, int x, int y); |
| 1204 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); | 1207 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); |
| 1205 | extern void ns_set_alpha (void *img, int x, int y, unsigned char a); | 1208 | 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 df7f716f51e..572b859a982 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -4043,10 +4043,22 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r) | |||
| 4043 | 4043 | ||
| 4044 | [doTransform concat]; | 4044 | [doTransform concat]; |
| 4045 | 4045 | ||
| 4046 | /* Smoothing is the default, so if we don't want smoothing we | ||
| 4047 | have to turn it off. */ | ||
| 4048 | if (! img->smoothing) | ||
| 4049 | [[NSGraphicsContext currentContext] | ||
| 4050 | setImageInterpolation:NSImageInterpolationNone]; | ||
| 4051 | |||
| 4046 | [img drawInRect:ir fromRect:ir | 4052 | [img drawInRect:ir fromRect:ir |
| 4047 | operation:NSCompositingOperationSourceOver | 4053 | operation:NSCompositingOperationSourceOver |
| 4048 | fraction:1.0 respectFlipped:YES hints:nil]; | 4054 | fraction:1.0 respectFlipped:YES hints:nil]; |
| 4049 | 4055 | ||
| 4056 | /* Apparently image interpolation is not reset with | ||
| 4057 | restoreGraphicsState, so we have to manually reset it. */ | ||
| 4058 | if (! img->smoothing) | ||
| 4059 | [[NSGraphicsContext currentContext] | ||
| 4060 | setImageInterpolation:NSImageInterpolationDefault]; | ||
| 4061 | |||
| 4050 | [[NSGraphicsContext currentContext] restoreGraphicsState]; | 4062 | [[NSGraphicsContext currentContext] restoreGraphicsState]; |
| 4051 | } | 4063 | } |
| 4052 | 4064 | ||