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.
This commit is contained in:
parent
8a7910fb67
commit
4e8bf2977e
6 changed files with 112 additions and 14 deletions
3
etc/NEWS
3
etc/NEWS
|
@ -838,6 +838,9 @@ current buffer, if the major mode supports it. (Support for
|
|||
'yank-media' will be unavailable on MS-Windows if Emacs was configured
|
||||
'--without-native-image-api'.)
|
||||
|
||||
---
|
||||
** Images on MS-Windows now support the :transform-smoothing flag.
|
||||
Bilinear interpolation with GDI+ is used to smooth images.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
|
|
@ -3172,6 +3172,7 @@ struct image
|
|||
#endif /* HAVE_ANDROID */
|
||||
#ifdef HAVE_NTGUI
|
||||
XFORM xform;
|
||||
bool smoothing;
|
||||
#endif
|
||||
#ifdef HAVE_HAIKU
|
||||
/* The affine transformation to apply to this image. */
|
||||
|
|
10
src/image.c
10
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
|
||||
|
|
|
@ -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 @@ typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
|
|||
(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 @@ typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc)
|
|||
|
||||
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 GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
|
|||
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 @@ extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
|
|||
# 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 @@ extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
|
|||
# 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
|
||||
|
|
|
@ -42,6 +42,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#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 @@ GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
|
|||
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)
|
||||
|
|
|
@ -24,6 +24,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#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
|
||||
|
|
Loading…
Add table
Reference in a new issue