* 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 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 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
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).