* bug#57166: 28.1; image :transform-smoothing dose not work @ 2022-08-13 6:06 awrhygty 2022-08-13 6:24 ` Eli Zaretskii 2024-11-04 19:19 ` Cecilio Pardo 0 siblings, 2 replies; 9+ messages in thread From: awrhygty @ 2022-08-13 6:06 UTC (permalink / raw) To: 57166 [-- Attachment #1: Type: text/plain, Size: 406 bytes --] I tried image smoothing, but no intermediate colors are displayed. The attached image is the result of the form below. (let ((xpm "/* XPM */ static char *data[] = { \"4 8 2 1\", \" c #FFFFFF\", \"R c #FF0000\", \" R\", \" R\", \" RR\", \" RR\", \" RRR\", \" RRR\", \"RRRR\", \"RRRR\"}")) (insert-image (create-image xpm 'xpm t :scale 1.5 :transform-smoothing t))) [-- Attachment #2: nosmoothing.png --] [-- Type: image/png, Size: 1586 bytes --] [-- Attachment #3: Type: text/plain, Size: 2928 bytes --] In GNU Emacs 28.1 (build 2, x86_64-w64-mingw32) of 2022-04-22 built on AVALON Windowing system distributor 'Microsoft Corp.', version 10.0.19044 System Description: Microsoft Windows 10 Pro (v10.0.2009.19044.1889) Configured using: 'configure --with-modules --without-dbus --with-native-compilation --without-compress-install CFLAGS=-O2' Configured features: ACL GIF GMP GNUTLS HARFBUZZ JPEG JSON LCMS2 LIBXML2 MODULES NATIVE_COMP NOTIFY W32NOTIFY PDUMPER PNG RSVG SOUND THREADS TIFF TOOLKIT_SCROLL_BARS XPM ZLIB (NATIVE_COMP present but libgccjit not available) Important settings: value of $LANG: JPN locale-coding-system: cp932 Major mode: Fundamental Minor modes in effect: tooltip-mode: t global-eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr emacsbug message rmc puny dired dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config gnus-util rmail rmail-loaddefs auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs password-cache json map text-property-search time-date subr-x mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils term/bobcat find-func noutline outline easy-mmode view thingatpt cl-extra seq byte-opt gv bytecomp byte-compile cconv novice mule-util help-mode cl-loaddefs cl-lib japan-util iso-transl tooltip eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel dos-w32 ls-lisp disp-table term/w32-win w32-win w32-vars term/common-win tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help simple abbrev obarray cl-preloaded nadvice button loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote threads w32notify w32 lcms2 multi-tty make-network-process native-compile emacs) Memory information: ((conses 16 68756 5924) (symbols 48 7113 1) (strings 32 22330 1664) (string-bytes 1 733632) (vectors 16 15734) (vector-slots 8 340218 10640) (floats 8 87 147) (intervals 56 736 46) (buffers 992 13)) ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2022-08-13 6:06 bug#57166: 28.1; image :transform-smoothing dose not work awrhygty @ 2022-08-13 6:24 ` Eli Zaretskii 2024-11-04 19:19 ` Cecilio Pardo 1 sibling, 0 replies; 9+ messages in thread From: Eli Zaretskii @ 2022-08-13 6:24 UTC (permalink / raw) To: awrhygty; +Cc: 57166 tags 57166 wishlist thanks > From: awrhygty@outlook.com > Date: Sat, 13 Aug 2022 15:06:07 +0900 > > I tried image smoothing, but no intermediate colors are displayed. :transform-smoothing is not yet implemented for MS-Windows, so this is not a bug, but a missing feature. Patches welcome. ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2022-08-13 6:06 bug#57166: 28.1; image :transform-smoothing dose not work awrhygty 2022-08-13 6:24 ` Eli Zaretskii @ 2024-11-04 19:19 ` Cecilio Pardo 2024-11-04 19:47 ` Eli Zaretskii 1 sibling, 1 reply; 9+ messages in thread From: Cecilio Pardo @ 2024-11-04 19:19 UTC (permalink / raw) To: 57166 [-- Attachment #1: Type: text/plain, Size: 286 bytes --] This patch adds support for :transform-smoothing on windows using GDI+ (since XP). It converts the HBITMAP to GpBitmap everytime its drawn. We could keep it around for speed, but take more resources. Since this may be used on machines with small memmory, I think its better this way. [-- Attachment #2: 0001-Support-transform-smoothing-on-images-MS-Windows-bug.patch --] [-- Type: text/plain, Size: 11138 bytes --] From 0fae31b5732f666eb12f2bf792208483d2319ff8 Mon Sep 17 00:00:00 2001 From: Cecilio Pardo <cpardo@imayhem.com> Date: Mon, 4 Nov 2024 18:58:40 +0100 Subject: [PATCH] Support :transform-smoothing on images (MS-Windows) (bug#57166) * src/dispextern.h (struct image): Add field 'smoothing' for NTGUI. * src/image.c (image_set_transform): Assign the 'smoothing' field of the image struct. * src/w32gdiplus.h: Add references to more GDI+ functions. * src/w32image.c (gdiplus_init): Add references to more GDI+ functions. * src/w32term.c (w32_draw_image_foreground): If the image is marked for smoothing and GDI+ is available, draw it with GDI+ interpolation. --- src/dispextern.h | 1 + src/image.c | 10 +++++---- src/w32gdiplus.h | 27 ++++++++++++++++++++++ src/w32image.c | 25 +++++++++++++++++++++ src/w32term.c | 58 +++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 107 insertions(+), 14 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index cc248a4472e..004eb82d87a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3172,6 +3172,7 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo) #endif /* HAVE_ANDROID */ #ifdef HAVE_NTGUI XFORM xform; + bool smoothing; #endif #ifdef HAVE_HAIKU /* The affine transformation to apply to this image. */ diff --git a/src/image.c b/src/image.c index 34936977a40..db7f6acd171 100644 --- a/src/image.c +++ b/src/image.c @@ -3049,12 +3049,10 @@ image_set_transform (struct frame *f, struct image *img) flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \ - || defined HAVE_ANDROID + || defined HAVE_ANDROID || defined HAVE_NTGUI /* We want scale up operations to use a nearest neighbor 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. */ + operations to use a blended filter, to avoid aliasing and the like. */ bool smoothing; Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL); if (NILP (s)) @@ -3067,6 +3065,10 @@ image_set_transform (struct frame *f, struct image *img) img->use_bilinear_filtering = smoothing; #endif +#ifdef HAVE_NTGUI + img->smoothing = smoothing; +#endif + /* Perform scale transformation. */ matrix3x3 matrix diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h index 9d05ae6c190..b438b1a64f8 100644 --- a/src/w32gdiplus.h +++ b/src/w32gdiplus.h @@ -2,6 +2,9 @@ typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); +typedef GpStatus (WINGDIPAPI *GdipCreateFromHDC_Proc) + (HDC hdc, GpGraphics **graphics); +typedef GpStatus (WINGDIPAPI *GdipDeleteGraphics_Proc) (GpGraphics *graphics); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) (GpImage *, PROPID, UINT *); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) @@ -20,6 +23,15 @@ (IStream *, GpBitmap **); typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc) (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromHBITMAP_Proc) + (HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap); +typedef GpStatus (WINGDIPAPI *GdipSetInterpolationMode_Proc) + (GpGraphics *graphics, InterpolationMode interpolationMode); +typedef GpStatus (WINGDIPAPI *GdipDrawImageRectRectI_Proc) + (GpGraphics *graphics, GpImage *image, INT dstx, INT dsty, INT dstwidth, + INT dstheight, INT srcx, INT srcy, INT srcwidth, INT srcheight, + GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, + DrawImageAbort callback, VOID * callbackData); typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) (GpBitmap *, HBITMAP *, ARGB); @@ -41,6 +53,8 @@ extern GdiplusStartup_Proc fn_GdiplusStartup; extern GdiplusShutdown_Proc fn_GdiplusShutdown; +extern GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +extern GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -49,6 +63,9 @@ extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; +extern GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +extern GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +extern GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; extern SHCreateMemStream_Proc fn_SHCreateMemStream; extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; @@ -73,6 +90,11 @@ # undef GdipCreateBitmapFromFile # undef GdipCreateBitmapFromStream # undef GdipCreateBitmapFromScan0 +# undef GdipCreateBitmapFromHBITMAP +# undef GdipCreateFromHDC +# undef GdipDrawImageRectRectI +# undef GdipSetInterpolationMode +# undef GdipDeleteGraphics # undef SHCreateMemStream # undef GdipCreateHBITMAPFromBitmap # undef GdipDisposeImage @@ -96,6 +118,11 @@ # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream # define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0 +# define GdipCreateBitmapFromHBITMAP fn_GdipCreateBitmapFromHBITMAP +# define GdipCreateFromHDC fn_GdipCreateFromHDC +# define GdipDrawImageRectRectI fn_GdipDrawImageRectRectI +# define GdipSetInterpolationMode fn_GdipSetInterpolationMode +# define GdipDeleteGraphics fn_GdipDeleteGraphics # define SHCreateMemStream fn_SHCreateMemStream # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap # define GdipDisposeImage fn_GdipDisposeImage diff --git a/src/w32image.c b/src/w32image.c index 44eed087528..da4d6843ba9 100644 --- a/src/w32image.c +++ b/src/w32image.c @@ -42,6 +42,8 @@ #define COBJMACROS #ifdef WINDOWSNT GdiplusStartup_Proc fn_GdiplusStartup; GdiplusShutdown_Proc fn_GdiplusShutdown; +GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -53,6 +55,9 @@ #define COBJMACROS GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; SHCreateMemStream_Proc fn_SHCreateMemStream; GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; +GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; GdipDisposeImage_Proc fn_GdipDisposeImage; GdipGetImageHeight_Proc fn_GdipGetImageHeight; GdipGetImageWidth_Proc fn_GdipGetImageWidth; @@ -80,6 +85,14 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdiplusShutdown"); if (!fn_GdiplusShutdown) return false; + fn_GdipCreateFromHDC = (GdipCreateFromHDC_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateFromHDC"); + if (!fn_GdipCreateFromHDC) + return false; + fn_GdipDeleteGraphics = (GdipDeleteGraphics_Proc) + get_proc_addr (gdiplus_lib, "GdipDeleteGraphics"); + if (!fn_GdipDeleteGraphics) + return false; fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc) get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize"); if (!fn_GdipGetPropertyItemSize) @@ -120,6 +133,18 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); if (!fn_GdipCreateHBITMAPFromBitmap) return false; + fn_GdipCreateBitmapFromHBITMAP = (GdipCreateBitmapFromHBITMAP_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromHBITMAP"); + if (!fn_GdipCreateBitmapFromHBITMAP) + return false; + fn_GdipDrawImageRectRectI = (GdipDrawImageRectRectI_Proc) + get_proc_addr (gdiplus_lib, "GdipDrawImageRectRectI"); + if (!fn_GdipDrawImageRectRectI) + return false; + fn_GdipSetInterpolationMode = (GdipSetInterpolationMode_Proc) + get_proc_addr (gdiplus_lib, "GdipSetInterpolationMode"); + if (!fn_GdipSetInterpolationMode) + return false; fn_GdipDisposeImage = (GdipDisposeImage_Proc) get_proc_addr (gdiplus_lib, "GdipDisposeImage"); if (!fn_GdipDisposeImage) diff --git a/src/w32term.c b/src/w32term.c index 88622700386..d3c3b9f590e 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -24,6 +24,9 @@ Copyright (C) 1989, 1993-2024 Free Software Foundation, Inc. #include "blockinput.h" #include "w32term.h" #include "w32common.h" /* for OS version info */ +#include <wtypes.h> +#include <gdiplus.h> +#include "w32gdiplus.h" #include <ctype.h> #include <errno.h> @@ -2106,16 +2109,51 @@ w32_draw_image_foreground (struct glyph_string *s) compat_hdc, s->slice.x, s->slice.y, SRCCOPY); else { - int pmode = 0; - /* Windows 9X doesn't support HALFTONE. */ - if (os_subtype == OS_SUBTYPE_NT - && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) - SetBrushOrgEx (s->hdc, 0, 0, NULL); - StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, orig_slice_x, orig_slice_y, - orig_slice_width, orig_slice_height, SRCCOPY); - if (pmode) - SetStretchBltMode (s->hdc, pmode); + if (s->img->smoothing && w32_gdiplus_startup ()) + { + GpGraphics *graphics; + if (GdipCreateFromHDC (s->hdc, &graphics) == Ok) + { + GpBitmap *gp_bitmap; + /* Can't create a GpBitmap from a HBITMAP that was + ever selected into a DC, so we need to copy. */ + HBITMAP copy + = CopyImage (GetCurrentObject (compat_hdc, OBJ_BITMAP), + IMAGE_BITMAP, 0, 0, 0); + if (GdipCreateBitmapFromHBITMAP (copy, NULL, + &gp_bitmap) == Ok) + { + GdipSetInterpolationMode (graphics, + InterpolationModeHighQualityBicubic); + GdipDrawImageRectRectI (graphics, + gp_bitmap, x, y, + s->slice.width, + s->slice.height, + orig_slice_x, + orig_slice_y, + orig_slice_width, + orig_slice_height, + UnitPixel, + NULL, NULL, NULL); + GdipDisposeImage (gp_bitmap); + } + DeleteObject (copy); + GdipDeleteGraphics (graphics); + } + } + else + { + int pmode = 0; + /* Windows 9X doesn't support HALFTONE. */ + if (os_subtype == OS_SUBTYPE_NT + && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) + SetBrushOrgEx (s->hdc, 0, 0, NULL); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, orig_slice_x, orig_slice_y, + orig_slice_width, orig_slice_height, SRCCOPY); + if (pmode) + SetStretchBltMode (s->hdc, pmode); + } } /* When the image has a mask, we can expect that at -- 2.35.1.windows.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 19:19 ` Cecilio Pardo @ 2024-11-04 19:47 ` Eli Zaretskii 2024-11-04 20:07 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: Eli Zaretskii @ 2024-11-04 19:47 UTC (permalink / raw) To: Cecilio Pardo; +Cc: 57166 > Date: Mon, 4 Nov 2024 20:19:11 +0100 > From: Cecilio Pardo <cpardo@imayhem.com> > > This patch adds support for :transform-smoothing on windows using GDI+ > (since XP). Thanks, this needs a NEWS entry. > + GdipSetInterpolationMode (graphics, > + InterpolationModeHighQualityBicubic); I wonder why you decided to go with this interpolation mode. AFAIU, other platforms use bilinear filtering. Should the Windows port produce results similar to the other platforms, or should it produce the best possible results? ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 19:47 ` Eli Zaretskii @ 2024-11-04 20:07 ` Eli Zaretskii 2024-11-04 23:04 ` Cecilio Pardo 2024-11-04 23:03 ` Cecilio Pardo 2024-11-04 23:11 ` Cecilio Pardo 2 siblings, 1 reply; 9+ messages in thread From: Eli Zaretskii @ 2024-11-04 20:07 UTC (permalink / raw) To: cpardo; +Cc: 57166 > Cc: 57166@debbugs.gnu.org > Date: Mon, 04 Nov 2024 21:47:19 +0200 > From: Eli Zaretskii <eliz@gnu.org> > > > + GdipSetInterpolationMode (graphics, > > + InterpolationModeHighQualityBicubic); > > I wonder why you decided to go with this interpolation mode. AFAIU, > other platforms use bilinear filtering. Should the Windows port > produce results similar to the other platforms, or should it produce > the best possible results? And another question: does this work even when w32-use-native-image-API is nil? IOW, does smoothing work for images produced by external libraries such as libpng and libjpeg? ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 20:07 ` Eli Zaretskii @ 2024-11-04 23:04 ` Cecilio Pardo 0 siblings, 0 replies; 9+ messages in thread From: Cecilio Pardo @ 2024-11-04 23:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 57166 On 04/11/2024 21:07, Eli Zaretskii wrote: >> Cc: 57166@debbugs.gnu.org > And another question: does this work even when > w32-use-native-image-API is nil? IOW, does smoothing work for images > produced by external libraries such as libpng and libjpeg? Yes, it does. ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 19:47 ` Eli Zaretskii 2024-11-04 20:07 ` Eli Zaretskii @ 2024-11-04 23:03 ` Cecilio Pardo 2024-11-04 23:11 ` Cecilio Pardo 2 siblings, 0 replies; 9+ messages in thread From: Cecilio Pardo @ 2024-11-04 23:03 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 57166 On 04/11/2024 20:47, Eli Zaretskii wrote: >> + GdipSetInterpolationMode (graphics, >> + InterpolationModeHighQualityBicubic); > > I wonder why you decided to go with this interpolation mode. AFAIU, > other platforms use bilinear filtering. Should the Windows port > produce results similar to the other platforms, or should it produce > the best possible results? It should be bilinear. Documentation says it should be equivalent to bilinear. I'm going with HighQualityBilinear, just Bilinear does not look good. ^ permalink raw reply [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 19:47 ` Eli Zaretskii 2024-11-04 20:07 ` Eli Zaretskii 2024-11-04 23:03 ` Cecilio Pardo @ 2024-11-04 23:11 ` Cecilio Pardo 2024-11-05 12:41 ` Eli Zaretskii 2 siblings, 1 reply; 9+ messages in thread From: Cecilio Pardo @ 2024-11-04 23:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 57166 [-- Attachment #1: Type: text/plain, Size: 56 bytes --] New patch with NEWS entry and bilinear interpolation. [-- Attachment #2: 0001-Support-transform-smoothing-on-images-MS-Windows-bug.patch --] [-- Type: text/plain, Size: 11764 bytes --] From bbe02f4218b6ba0ffd5a8356978a35bf920d1727 Mon Sep 17 00:00:00 2001 From: Cecilio Pardo <cpardo@imayhem.com> Date: Mon, 4 Nov 2024 18:58:40 +0100 Subject: [PATCH] Support :transform-smoothing on images (MS-Windows) (bug#57166) * src/dispextern.h (struct image): Add field 'smoothing' for NTGUI. * src/image.c (image_set_transform): Assign the 'smoothing' field of the image struct. * src/w32gdiplus.h: Add references to more GDI+ functions. * src/w32image.c (gdiplus_init): Add references to more GDI+ functions. * src/w32term.c (w32_draw_image_foreground): If the image is marked for smoothing and GDI+ is available, draw it with GDI+ bilinear interpolation. * etc/NEWS: New entry for this change. --- etc/NEWS | 3 +++ src/dispextern.h | 1 + src/image.c | 10 ++++---- src/w32gdiplus.h | 27 ++++++++++++++++++++++ src/w32image.c | 25 ++++++++++++++++++++ src/w32term.c | 60 ++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 112 insertions(+), 14 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 41a76d1cd95..33da804d63e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -830,6 +830,9 @@ color Emoji font installed on your system for the 'emoji' script. This command inserts clipboard data of different formats into the current buffer, if the major mode supports it. +--- +** Images on MS-Windows now support the :transform-smoothing flag. +Bilinear interpolation with GDI+ is used to smooth images. \f ---------------------------------------------------------------------- diff --git a/src/dispextern.h b/src/dispextern.h index cc248a4472e..004eb82d87a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3172,6 +3172,7 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo) #endif /* HAVE_ANDROID */ #ifdef HAVE_NTGUI XFORM xform; + bool smoothing; #endif #ifdef HAVE_HAIKU /* The affine transformation to apply to this image. */ diff --git a/src/image.c b/src/image.c index 34936977a40..db7f6acd171 100644 --- a/src/image.c +++ b/src/image.c @@ -3049,12 +3049,10 @@ image_set_transform (struct frame *f, struct image *img) flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \ - || defined HAVE_ANDROID + || defined HAVE_ANDROID || defined HAVE_NTGUI /* We want scale up operations to use a nearest neighbor 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. */ + operations to use a blended filter, to avoid aliasing and the like. */ bool smoothing; Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL); if (NILP (s)) @@ -3067,6 +3065,10 @@ image_set_transform (struct frame *f, struct image *img) img->use_bilinear_filtering = smoothing; #endif +#ifdef HAVE_NTGUI + img->smoothing = smoothing; +#endif + /* Perform scale transformation. */ matrix3x3 matrix diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h index 9d05ae6c190..b438b1a64f8 100644 --- a/src/w32gdiplus.h +++ b/src/w32gdiplus.h @@ -2,6 +2,9 @@ typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); +typedef GpStatus (WINGDIPAPI *GdipCreateFromHDC_Proc) + (HDC hdc, GpGraphics **graphics); +typedef GpStatus (WINGDIPAPI *GdipDeleteGraphics_Proc) (GpGraphics *graphics); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) (GpImage *, PROPID, UINT *); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) @@ -20,6 +23,15 @@ (IStream *, GpBitmap **); typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc) (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromHBITMAP_Proc) + (HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap); +typedef GpStatus (WINGDIPAPI *GdipSetInterpolationMode_Proc) + (GpGraphics *graphics, InterpolationMode interpolationMode); +typedef GpStatus (WINGDIPAPI *GdipDrawImageRectRectI_Proc) + (GpGraphics *graphics, GpImage *image, INT dstx, INT dsty, INT dstwidth, + INT dstheight, INT srcx, INT srcy, INT srcwidth, INT srcheight, + GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, + DrawImageAbort callback, VOID * callbackData); typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) (GpBitmap *, HBITMAP *, ARGB); @@ -41,6 +53,8 @@ extern GdiplusStartup_Proc fn_GdiplusStartup; extern GdiplusShutdown_Proc fn_GdiplusShutdown; +extern GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +extern GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -49,6 +63,9 @@ extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; +extern GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +extern GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +extern GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; extern SHCreateMemStream_Proc fn_SHCreateMemStream; extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; @@ -73,6 +90,11 @@ # undef GdipCreateBitmapFromFile # undef GdipCreateBitmapFromStream # undef GdipCreateBitmapFromScan0 +# undef GdipCreateBitmapFromHBITMAP +# undef GdipCreateFromHDC +# undef GdipDrawImageRectRectI +# undef GdipSetInterpolationMode +# undef GdipDeleteGraphics # undef SHCreateMemStream # undef GdipCreateHBITMAPFromBitmap # undef GdipDisposeImage @@ -96,6 +118,11 @@ # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream # define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0 +# define GdipCreateBitmapFromHBITMAP fn_GdipCreateBitmapFromHBITMAP +# define GdipCreateFromHDC fn_GdipCreateFromHDC +# define GdipDrawImageRectRectI fn_GdipDrawImageRectRectI +# define GdipSetInterpolationMode fn_GdipSetInterpolationMode +# define GdipDeleteGraphics fn_GdipDeleteGraphics # define SHCreateMemStream fn_SHCreateMemStream # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap # define GdipDisposeImage fn_GdipDisposeImage diff --git a/src/w32image.c b/src/w32image.c index 44eed087528..da4d6843ba9 100644 --- a/src/w32image.c +++ b/src/w32image.c @@ -42,6 +42,8 @@ #define COBJMACROS #ifdef WINDOWSNT GdiplusStartup_Proc fn_GdiplusStartup; GdiplusShutdown_Proc fn_GdiplusShutdown; +GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -53,6 +55,9 @@ #define COBJMACROS GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; SHCreateMemStream_Proc fn_SHCreateMemStream; GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; +GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; GdipDisposeImage_Proc fn_GdipDisposeImage; GdipGetImageHeight_Proc fn_GdipGetImageHeight; GdipGetImageWidth_Proc fn_GdipGetImageWidth; @@ -80,6 +85,14 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdiplusShutdown"); if (!fn_GdiplusShutdown) return false; + fn_GdipCreateFromHDC = (GdipCreateFromHDC_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateFromHDC"); + if (!fn_GdipCreateFromHDC) + return false; + fn_GdipDeleteGraphics = (GdipDeleteGraphics_Proc) + get_proc_addr (gdiplus_lib, "GdipDeleteGraphics"); + if (!fn_GdipDeleteGraphics) + return false; fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc) get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize"); if (!fn_GdipGetPropertyItemSize) @@ -120,6 +133,18 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); if (!fn_GdipCreateHBITMAPFromBitmap) return false; + fn_GdipCreateBitmapFromHBITMAP = (GdipCreateBitmapFromHBITMAP_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromHBITMAP"); + if (!fn_GdipCreateBitmapFromHBITMAP) + return false; + fn_GdipDrawImageRectRectI = (GdipDrawImageRectRectI_Proc) + get_proc_addr (gdiplus_lib, "GdipDrawImageRectRectI"); + if (!fn_GdipDrawImageRectRectI) + return false; + fn_GdipSetInterpolationMode = (GdipSetInterpolationMode_Proc) + get_proc_addr (gdiplus_lib, "GdipSetInterpolationMode"); + if (!fn_GdipSetInterpolationMode) + return false; fn_GdipDisposeImage = (GdipDisposeImage_Proc) get_proc_addr (gdiplus_lib, "GdipDisposeImage"); if (!fn_GdipDisposeImage) diff --git a/src/w32term.c b/src/w32term.c index 88622700386..e18f39dd2a8 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -24,6 +24,9 @@ Copyright (C) 1989, 1993-2024 Free Software Foundation, Inc. #include "blockinput.h" #include "w32term.h" #include "w32common.h" /* for OS version info */ +#include <wtypes.h> +#include <gdiplus.h> +#include "w32gdiplus.h" #include <ctype.h> #include <errno.h> @@ -2106,16 +2109,53 @@ w32_draw_image_foreground (struct glyph_string *s) compat_hdc, s->slice.x, s->slice.y, SRCCOPY); else { - int pmode = 0; - /* Windows 9X doesn't support HALFTONE. */ - if (os_subtype == OS_SUBTYPE_NT - && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) - SetBrushOrgEx (s->hdc, 0, 0, NULL); - StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, orig_slice_x, orig_slice_y, - orig_slice_width, orig_slice_height, SRCCOPY); - if (pmode) - SetStretchBltMode (s->hdc, pmode); +#ifdef HAVE_NATIVE_IMAGE_API + if (s->img->smoothing && w32_gdiplus_startup ()) + { + GpGraphics *graphics; + if (GdipCreateFromHDC (s->hdc, &graphics) == Ok) + { + GpBitmap *gp_bitmap; + /* Can't create a GpBitmap from a HBITMAP that was + ever selected into a DC, so we need to copy. */ + HBITMAP copy + = CopyImage (GetCurrentObject (compat_hdc, OBJ_BITMAP), + IMAGE_BITMAP, 0, 0, 0); + if (GdipCreateBitmapFromHBITMAP (copy, NULL, + &gp_bitmap) == Ok) + { + GdipSetInterpolationMode (graphics, + InterpolationModeHighQualityBilinear); + GdipDrawImageRectRectI (graphics, + gp_bitmap, x, y, + s->slice.width, + s->slice.height, + orig_slice_x, + orig_slice_y, + orig_slice_width, + orig_slice_height, + UnitPixel, + NULL, NULL, NULL); + GdipDisposeImage (gp_bitmap); + } + DeleteObject (copy); + GdipDeleteGraphics (graphics); + } + } + else +#endif + { + int pmode = 0; + /* Windows 9X doesn't support HALFTONE. */ + if (os_subtype == OS_SUBTYPE_NT + && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) + SetBrushOrgEx (s->hdc, 0, 0, NULL); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, orig_slice_x, orig_slice_y, + orig_slice_width, orig_slice_height, SRCCOPY); + if (pmode) + SetStretchBltMode (s->hdc, pmode); + } } /* When the image has a mask, we can expect that at -- 2.35.1.windows.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* bug#57166: 28.1; image :transform-smoothing dose not work 2024-11-04 23:11 ` Cecilio Pardo @ 2024-11-05 12:41 ` Eli Zaretskii 0 siblings, 0 replies; 9+ messages in thread From: Eli Zaretskii @ 2024-11-05 12:41 UTC (permalink / raw) To: Cecilio Pardo; +Cc: 57166-done > Date: Tue, 5 Nov 2024 00:11:52 +0100 > Cc: 57166@debbugs.gnu.org > From: Cecilio Pardo <cpardo@imayhem.com> > > New patch with NEWS entry and bilinear interpolation. Thanks, installed on the master branch, and closing the bug. ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-11-05 12:41 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-08-13 6:06 bug#57166: 28.1; image :transform-smoothing dose not work awrhygty 2022-08-13 6:24 ` Eli Zaretskii 2024-11-04 19:19 ` Cecilio Pardo 2024-11-04 19:47 ` Eli Zaretskii 2024-11-04 20:07 ` Eli Zaretskii 2024-11-04 23:04 ` Cecilio Pardo 2024-11-04 23:03 ` Cecilio Pardo 2024-11-04 23:11 ` Cecilio Pardo 2024-11-05 12:41 ` Eli Zaretskii
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).