Make use of MS-Windows native image API be selectable at run time

* configure.ac: Minor cleanup in how w32image.o is added to the
build when native image APIs are requested.

* src/w32gui.h (w32_load_image, w32_can_use_native_image_api)
(w32_gdiplus_shutdown): Move prototypes from w32term.h here, since
w32.c doesn't include w32term.h.
* src/image.c (struct image_type): No need to pass TYPE to the
'valid_p' method.  All callers changed.
(initialize_image_type) [HAVE_NATIVE_IMAGE_API]: Call
'image_can_use_native_api' before trying image-specific methods.
(image_can_use_native_api): New function.
(image_types): Remove the native_image_type parts.
(syms_of_image): New symbol 'native-image'.
(parse_image_spec): Accept native-image "type" for any image type.
* src/w32term.c (syms_of_w32term): New variable
'w32-use-native-image-API'.
* src/w32image.c: (w32_can_use_native_image_api): New function.
(gdiplus_init): Rename from w32_gdiplus_startup. Simplify code.
Move the call to GdiplusStartup to a separate function.  Use
ordinal number for SHCreateMemStream if cannot load it by name.
(w32_load_image): Ignore Win32Error status from
w32_select_active_frame.
Move DEFSYMs from here...
* src/image.c (syms_of_image) [HAVE_NATIVE_IMAGE_API]: ...to here.

* etc/NEWS: Update the entry about native image API use.
This commit is contained in:
Eli Zaretskii 2020-04-14 18:10:41 +03:00
parent df254a7445
commit e94206aaf6
8 changed files with 259 additions and 153 deletions

View file

@ -433,7 +433,7 @@ OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support])
OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing])
OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support])
OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support])
OPTION_DEFAULT_OFF([native-image-api], [use native API's (GDI+ on Windows) for JPEG/TIFF/GIFF/PNG])
OPTION_DEFAULT_ON([native-image-api], [use native image APIs (GDI+ on Windows)])
OPTION_DEFAULT_ON([json], [don't compile with native JSON support])
OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts])
@ -2127,7 +2127,7 @@ LIB_WSOCK32=
NTLIB=
CM_OBJ="cm.o"
XARGS_LIMIT=
HAVE_NATIVE_IMAGE_API=no
NATIVE_IMAGE_API=no
if test "${HAVE_W32}" = "yes"; then
AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.])
if test "$with_toolkit_scroll_bars" = "no"; then
@ -2156,12 +2156,14 @@ if test "${HAVE_W32}" = "yes"; then
# the rc file), not a linker script.
W32_RES_LINK="-Wl,emacs.res"
else
W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o"
dnl FIXME: This should probably be supported for Cygwin/w32 as
dnl well, but the Cygwin build needs to link against -lgdiplus
if test "${with_native_image_api}" = yes; then
AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use MS Windows GDI+ for images.])
HAVE_NATIVE_IMAGE_API=yes
W32_NATIVE_IMAGE_API="w32image.o"
AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for images.])
NATIVE_IMAGE_API="yes (w32)"
W32_OBJ="$W32_OBJ w32image.o"
fi
W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o $W32_NATIVE_IMAGE_API"
W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32"
W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32"
W32_RES_LINK="\$(EMACSRES)"
@ -5710,7 +5712,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D
Does Emacs use cairo? ${HAVE_CAIRO}
Does Emacs use -llcms2? ${HAVE_LCMS2}
Does Emacs use imagemagick? ${HAVE_IMAGEMAGICK}
Does Emacs use native API for images? ${HAVE_NATIVE_IMAGE_API}
Does Emacs use native APIs for images? ${NATIVE_IMAGE_API}
Does Emacs support sound? ${HAVE_SOUND}
Does Emacs use -lgpm? ${HAVE_GPM}
Does Emacs use -ldbus? ${HAVE_DBUS}

View file

@ -393,6 +393,11 @@ images in JPEG, PNG, GIF and TIFF formats. This support is enabled
with --with-native-image-api, which automatically disables the use of
optional third party libraries for those formats.
This feature is experimental, and needs to be turned on to be used.
To turn this on, set the variable 'w32-use-native-image-API' to a
non-nil value. Please report any bugs you find while using the native
image API via "M-x report-emacs-bug".
----------------------------------------------------------------------
This file is part of GNU Emacs.

View file

@ -751,7 +751,7 @@ struct image_type
/* Check that SPEC is a valid image specification for the given
image type. Value is true if SPEC is valid. */
bool (*valid_p) (Lisp_Object spec, Lisp_Object type);
bool (*valid_p) (Lisp_Object spec);
/* Load IMG which is used on frame F from information contained in
IMG->spec. Value is true if successful. */
@ -807,7 +807,7 @@ valid_image_p (Lisp_Object object)
{
struct image_type const *type = lookup_image_type (XCAR (tail));
if (type)
return type->valid_p (object, builtin_lisp_symbol (type->type));
return type->valid_p (object);
}
break;
}
@ -816,7 +816,6 @@ valid_image_p (Lisp_Object object)
return false;
}
/* Log error message with format string FORMAT and trailing arguments.
Signaling an error, e.g. when an image cannot be loaded, is not a
good idea because this would interrupt redisplay, and the error
@ -1004,7 +1003,8 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
break;
}
if (EQ (key, QCtype) && !EQ (type, value))
if (EQ (key, QCtype)
&& !(EQ (type, value) || EQ (type, Qnative_image)))
return false;
}
@ -3144,12 +3144,12 @@ enum xbm_token
displayed is used. */
static bool
xbm_image_p (Lisp_Object object, Lisp_Object type)
xbm_image_p (Lisp_Object object)
{
struct image_keyword kw[XBM_LAST];
memcpy (kw, xbm_format, sizeof kw);
if (!parse_image_spec (object, kw, XBM_LAST, type))
if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
return 0;
eassert (EQ (kw[XBM_TYPE].value, Qxbm));
@ -3697,7 +3697,7 @@ xbm_load (struct frame *f, struct image *img)
bool success_p = 0;
Lisp_Object file_name;
eassert (xbm_image_p (img->spec, Qxbm));
eassert (xbm_image_p (img->spec));
/* If IMG->spec specifies a file name, create a non-file spec from it. */
file_name = image_spec_value (img->spec, QCfile, NULL);
@ -4155,11 +4155,11 @@ xpm_valid_color_symbols_p (Lisp_Object color_symbols)
/* Value is true if OBJECT is a valid XPM image specification. */
static bool
xpm_image_p (Lisp_Object object, Lisp_Object type)
xpm_image_p (Lisp_Object object)
{
struct image_keyword fmt[XPM_LAST];
memcpy (fmt, xpm_format, sizeof fmt);
return (parse_image_spec (object, fmt, XPM_LAST, type)
return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
/* Either `:file' or `:data' must be present. */
&& fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
/* Either no `:color-symbols' or it's a list of conses
@ -5883,13 +5883,13 @@ static const struct image_keyword pbm_format[PBM_LAST] =
/* Return true if OBJECT is a valid PBM image specification. */
static bool
pbm_image_p (Lisp_Object object, Lisp_Object type)
pbm_image_p (Lisp_Object object)
{
struct image_keyword fmt[PBM_LAST];
memcpy (fmt, pbm_format, sizeof fmt);
if (!parse_image_spec (object, fmt, PBM_LAST, type))
if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
return 0;
/* Must specify either :data or :file. */
@ -6235,21 +6235,30 @@ pbm_load (struct frame *f, struct image *img)
/***********************************************************************
NATIVE IMAGE HANDLING
***********************************************************************/
#if defined(HAVE_NATIVE_IMAGE_API) && defined(HAVE_NTGUI)
static bool
image_can_use_native_api (Lisp_Object type)
{
#if HAVE_NATIVE_IMAGE_API
# ifdef HAVE_NTGUI
return w32_can_use_native_image_api (type);
# else
return false;
# endif
#else
return false;
#endif
}
#if HAVE_NATIVE_IMAGE_API
/*
* These functions are actually defined in the OS-native implementation
* file. Currently, for Windows GDI+ interface, w32image.c, but other
* operating systems can follow suit.
*/
static bool
init_native_image_functions (void)
{
return w32_gdiplus_startup ();
}
/* Indices of image specification fields in native format, below. */
enum native_image_keyword_index
{
NATIVE_IMAGE_TYPE,
@ -6268,7 +6277,6 @@ enum native_image_keyword_index
/* Vector of image_keyword structures describing the format
of valid user-defined image specifications. */
static const struct image_keyword native_image_format[] =
{
{":type", IMAGE_SYMBOL_VALUE, 1},
@ -6287,12 +6295,12 @@ static const struct image_keyword native_image_format[] =
/* Return true if OBJECT is a valid native API image specification. */
static bool
native_image_p (Lisp_Object object, Lisp_Object type)
native_image_p (Lisp_Object object)
{
struct image_keyword fmt[NATIVE_IMAGE_LAST];
memcpy (fmt, native_image_format, sizeof fmt);
if (!parse_image_spec (object, fmt, 10, type))
if (!parse_image_spec (object, fmt, 10, Qnative_image))
return 0;
/* Must specify either the :data or :file keyword. */
@ -6302,11 +6310,17 @@ native_image_p (Lisp_Object object, Lisp_Object type)
static bool
native_image_load (struct frame *f, struct image *img)
{
# ifdef HAVE_NTGUI
return w32_load_image (f, img,
image_spec_value (img->spec, QCfile, NULL),
image_spec_value (img->spec, QCdata, NULL));
# else
return 0;
# endif
}
#endif
#endif /* HAVE_NATIVE_IMAGE_API */
/***********************************************************************
@ -6352,12 +6366,12 @@ static const struct image_keyword png_format[PNG_LAST] =
/* Return true if OBJECT is a valid PNG image specification. */
static bool
png_image_p (Lisp_Object object, Lisp_Object type)
png_image_p (Lisp_Object object)
{
struct image_keyword fmt[PNG_LAST];
memcpy (fmt, png_format, sizeof fmt);
if (!parse_image_spec (object, fmt, PNG_LAST, type))
if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
return 0;
/* Must specify either the :data or :file keyword. */
@ -7014,13 +7028,13 @@ static const struct image_keyword jpeg_format[JPEG_LAST] =
/* Return true if OBJECT is a valid JPEG image specification. */
static bool
jpeg_image_p (Lisp_Object object, Lisp_Object type)
jpeg_image_p (Lisp_Object object)
{
struct image_keyword fmt[JPEG_LAST];
memcpy (fmt, jpeg_format, sizeof fmt);
if (!parse_image_spec (object, fmt, JPEG_LAST, type))
if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
return 0;
/* Must specify either the :data or :file keyword. */
@ -7590,12 +7604,12 @@ static const struct image_keyword tiff_format[TIFF_LAST] =
/* Return true if OBJECT is a valid TIFF image specification. */
static bool
tiff_image_p (Lisp_Object object, Lisp_Object type)
tiff_image_p (Lisp_Object object)
{
struct image_keyword fmt[TIFF_LAST];
memcpy (fmt, tiff_format, sizeof fmt);
if (!parse_image_spec (object, fmt, TIFF_LAST, type))
if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
return 0;
/* Must specify either the :data or :file keyword. */
@ -8038,12 +8052,12 @@ gif_clear_image (struct frame *f, struct image *img)
/* Return true if OBJECT is a valid GIF image specification. */
static bool
gif_image_p (Lisp_Object object, Lisp_Object type)
gif_image_p (Lisp_Object object)
{
struct image_keyword fmt[GIF_LAST];
memcpy (fmt, gif_format, sizeof fmt);
if (!parse_image_spec (object, fmt, GIF_LAST, type))
if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
return 0;
/* Must specify either the :data or :file keyword. */
@ -8650,12 +8664,12 @@ imagemagick_clear_image (struct frame *f,
identify the IMAGEMAGICK format. */
static bool
imagemagick_image_p (Lisp_Object object, Lisp_Object type)
imagemagick_image_p (Lisp_Object object)
{
struct image_keyword fmt[IMAGEMAGICK_LAST];
memcpy (fmt, imagemagick_format, sizeof fmt);
if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, type))
if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick))
return 0;
/* Must specify either the :data or :file keyword. */
@ -9445,12 +9459,12 @@ static const struct image_keyword svg_format[SVG_LAST] =
identify the SVG format. */
static bool
svg_image_p (Lisp_Object object, Lisp_Object type)
svg_image_p (Lisp_Object object)
{
struct image_keyword fmt[SVG_LAST];
memcpy (fmt, svg_format, sizeof fmt);
if (!parse_image_spec (object, fmt, SVG_LAST, type))
if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
return 0;
/* Must specify either the :data or :file keyword. */
@ -9913,7 +9927,7 @@ static const struct image_keyword gs_format[GS_LAST] =
specification. */
static bool
gs_image_p (Lisp_Object object, Lisp_Object type)
gs_image_p (Lisp_Object object)
{
struct image_keyword fmt[GS_LAST];
Lisp_Object tem;
@ -9921,7 +9935,7 @@ gs_image_p (Lisp_Object object, Lisp_Object type)
memcpy (fmt, gs_format, sizeof fmt);
if (!parse_image_spec (object, fmt, GS_LAST, type))
if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
return 0;
/* Bounding box must be a list or vector containing 4 integers. */
@ -10208,20 +10222,19 @@ static bool
initialize_image_type (struct image_type const *type)
{
#ifdef WINDOWSNT
Lisp_Object typesym, tested;
bool (*init) (void) = type->init;
Lisp_Object typesym = builtin_lisp_symbol (type->type);
#ifdef HAVE_NATIVE_IMAGE_API
if (init == init_native_image_functions)
return init();
if (image_can_use_native_api (typesym))
return true;
#endif
typesym = builtin_lisp_symbol (type->type);
tested = Fassq (typesym, Vlibrary_cache);
Lisp_Object tested = Fassq (typesym, Vlibrary_cache);
/* If we failed to load the library before, don't try again. */
if (CONSP (tested))
return !NILP (XCDR (tested)) ? true : false;
bool (*init) (void) = type->init;
if (init)
{
bool type_valid = init ();
@ -10248,16 +10261,6 @@ static struct image_type const image_types[] =
{ SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image,
IMAGE_TYPE_INIT (init_svg_functions) },
#endif
#if defined HAVE_NATIVE_IMAGE_API
{ SYMBOL_INDEX (Qjpeg), native_image_p, native_image_load, image_clear_image,
IMAGE_TYPE_INIT (init_native_image_functions) },
{ SYMBOL_INDEX (Qpng), native_image_p, native_image_load, image_clear_image,
IMAGE_TYPE_INIT (init_native_image_functions) },
{ SYMBOL_INDEX (Qgif), native_image_p, native_image_load, image_clear_image,
IMAGE_TYPE_INIT (init_native_image_functions) },
{ SYMBOL_INDEX (Qtiff), native_image_p, native_image_load, image_clear_image,
IMAGE_TYPE_INIT (init_native_image_functions) },
#endif
#if defined HAVE_PNG || defined HAVE_NS
{ SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image,
IMAGE_TYPE_INIT (init_png_functions) },
@ -10282,23 +10285,28 @@ static struct image_type const image_types[] =
{ SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
};
#ifdef HAVE_NATIVE_IMAGE_API
struct image_type native_image_type =
{ SYMBOL_INDEX (Qnative_image), native_image_p, native_image_load,
image_clear_image };
#endif
/* Look up image type TYPE, and return a pointer to its image_type
structure. Return 0 if TYPE is not a known image type. */
static struct image_type const *
lookup_image_type (Lisp_Object type)
{
#ifdef HAVE_NATIVE_IMAGE_API
if (image_can_use_native_api (type))
return &native_image_type;
#endif
for (int i = 0; i < ARRAYELTS (image_types); i++)
{
struct image_type const *r = &image_types[i];
if (EQ (type, builtin_lisp_symbol (r->type)))
#ifdef HAVE_NATIVE_IMAGE_API
/* We can have more than one backend for one image type. */
if (initialize_image_type (r))
return r;
#else
return initialize_image_type (r) ? r : NULL;
#endif
}
return NULL;
}
@ -10454,6 +10462,14 @@ non-numeric, there is no explicit limit on the size of images. */);
#endif /* HAVE_NTGUI */
#endif /* HAVE_RSVG */
#if HAVE_NATIVE_IMAGE_API
DEFSYM (Qnative_image, "native-image");
# ifdef HAVE_NTGUI
DEFSYM (Qgdiplus, "gdiplus");
DEFSYM (Qshlwapi, "shlwapi");
# endif
#endif
defsubr (&Sinit_image_library);
#ifdef HAVE_IMAGEMAGICK
defsubr (&Simagemagick_types);

View file

@ -10226,7 +10226,7 @@ term_ntproc (int ignored)
term_w32select ();
#ifdef HAVE_GDIPLUS
#if HAVE_NATIVE_IMAGE_API
w32_gdiplus_shutdown ();
#endif
}

View file

@ -41,6 +41,12 @@ typedef struct _XImage
/* Optional RGBQUAD array for palette follows (see BITMAPINFO docs). */
} XImage;
struct image;
extern int w32_load_image (struct frame *f, struct image *img,
Lisp_Object spec_file, Lisp_Object spec_data);
extern bool w32_can_use_native_image_api (Lisp_Object);
extern void w32_gdiplus_shutdown (void);
#define FACE_DEFAULT (~0)
extern HINSTANCE hinst;

View file

@ -23,7 +23,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "lisp.h"
#include "dispextern.h"
#define COBJMACROS
#ifdef MINGW_W64
/* FIXME: Do we need to include objidl.h? */
#include <objidl.h>
#endif
#include <wtypes.h>
#include <gdiplus.h>
#include <shlwapi.h>
@ -32,53 +35,39 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "frame.h"
#include "coding.h"
/*#define LINK_GDIPLUS_STATICALLY 1*/
#ifdef WINDOWSNT
#ifndef LINK_GDIPLUS_STATICALLY
DEF_DLL_FN (GpStatus, GdiplusStartup, (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *));
DEF_DLL_FN (GpStatus, GdiplusStartup,
(ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *));
DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR));
DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, (GpImage *, PROPID, UINT *));
DEF_DLL_FN (GpStatus, GdipGetPropertyItem, (GpImage *, PROPID, UINT, PropertyItem *));
DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize,
(GpImage *, PROPID, UINT *));
DEF_DLL_FN (GpStatus, GdipGetPropertyItem,
(GpImage *, PROPID, UINT, PropertyItem *));
DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *));
DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, (GpImage *, GUID *, UINT));
DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, (GpImage *, GDIPCONST GUID *, UINT *));
DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, (GpImage*, GDIPCONST GUID *, UINT));
DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList,
(GpImage *, GUID *, UINT));
DEF_DLL_FN (GpStatus, GdipImageGetFrameCount,
(GpImage *, GDIPCONST GUID *, UINT *));
DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame,
(GpImage*, GDIPCONST GUID *, UINT));
DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **));
DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **));
DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit));
DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, (GpBitmap *, HBITMAP *, ARGB));
DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap,
(GpBitmap *, HBITMAP *, ARGB));
DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *));
DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *));
DEF_DLL_FN (GpStatus, GdipGetImageWidth, (GpImage *, UINT *));
#endif
static int gdip_initialized = 0;
static ULONG_PTR token;
static GdiplusStartupInput input;
static GdiplusStartupOutput output;
bool
w32_gdiplus_startup (void)
static bool
gdiplus_init (void)
{
HANDLE gdiplus_lib, shlwapi_lib;
GpStatus status;
if (gdip_initialized < 0)
return 0;
else if (gdip_initialized)
return 1;
#ifndef LINK_GDIPLUS_STATICALLY
DEFSYM (Qgdiplus, "gdiplus");
DEFSYM (Qshlwapi, "shlwapi");
if (!(gdiplus_lib = w32_delayed_load (Qgdiplus))) {
gdip_initialized = -1;
return 0;
}
if (!(shlwapi_lib = w32_delayed_load (Qshlwapi))) {
gdip_initialized = -1;
return 0;
}
if (!((gdiplus_lib = w32_delayed_load (Qgdiplus))
&& (shlwapi_lib = w32_delayed_load (Qshlwapi))))
return false;
LOAD_DLL_FN (gdiplus_lib, GdiplusStartup);
LOAD_DLL_FN (gdiplus_lib, GdiplusShutdown);
@ -94,7 +83,41 @@ w32_gdiplus_startup (void)
LOAD_DLL_FN (gdiplus_lib, GdipDisposeImage);
LOAD_DLL_FN (gdiplus_lib, GdipGetImageHeight);
LOAD_DLL_FN (gdiplus_lib, GdipGetImageWidth);
LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream);
/* LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream); */
/* The following terrible kludge is required to use native image API
on Windows before Vista, because SHCreateMemStream was not
exported by name in those versions, only by ordinal number. */
fn_SHCreateMemStream =
(W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib,
"SHCreateMemStream");
if (!fn_SHCreateMemStream)
{
fn_SHCreateMemStream =
(W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib,
MAKEINTRESOURCEA (12));
if (!fn_SHCreateMemStream)
return false;
}
return true;
}
# undef GdiplusStartup
# undef GdiplusShutdown
# undef GdipGetPropertyItemSize
# undef GdipGetPropertyItem
# undef GdipImageGetFrameDimensionsCount
# undef GdipImageGetFrameDimensionsList
# undef GdipImageGetFrameCount
# undef GdipImageSelectActiveFrame
# undef GdipCreateBitmapFromFile
# undef GdipCreateBitmapFromStream
# undef SHCreateMemStream
# undef GdipCreateHBITMAPFromBitmap
# undef GdipDisposeImage
# undef GdipGetImageHeight
# undef GdipGetImageWidth
# define GdiplusStartup fn_GdiplusStartup
# define GdiplusShutdown fn_GdiplusShutdown
@ -111,32 +134,71 @@ w32_gdiplus_startup (void)
# define GdipDisposeImage fn_GdipDisposeImage
# define GdipGetImageHeight fn_GdipGetImageHeight
# define GdipGetImageWidth fn_GdipGetImageWidth
#endif /* WINDOWSNT */
static int gdip_initialized;
static bool gdiplus_started;
static ULONG_PTR token;
static GdiplusStartupInput input;
static GdiplusStartupOutput output;
/* Initialize GDI+, return true if successful. */
static bool
gdiplus_startup (void)
{
GpStatus status;
if (gdiplus_started)
return true;
#ifdef WINDOWSNT
if (!gdip_initialized)
gdip_initialized = gdiplus_init () ? 1 : -1;
#else
gdip_initialized = 1;
#endif
input.GdiplusVersion = 1;
input.DebugEventCallback = NULL;
input.SuppressBackgroundThread = FALSE;
input.SuppressExternalCodecs = FALSE;
status = GdiplusStartup (&token, &input, &output);
if (status == Ok)
if (gdip_initialized > 0)
{
gdip_initialized = 1;
return 1;
}
else
{
gdip_initialized = -1;
return 0;
input.GdiplusVersion = 1;
input.DebugEventCallback = NULL;
input.SuppressBackgroundThread = FALSE;
input.SuppressExternalCodecs = FALSE;
status = GdiplusStartup (&token, &input, &output);
if (status == Ok)
gdiplus_started = true;
return (status == Ok);
}
return false;
}
/* This is called from term_ntproc. */
void
w32_gdiplus_shutdown (void)
{
GdiplusShutdown (token);
if (gdiplus_started)
GdiplusShutdown (token);
gdiplus_started = false;
}
bool
w32_can_use_native_image_api (Lisp_Object type)
{
if (!w32_use_native_image_api)
return false;
if (!(EQ (type, Qjpeg)
|| EQ (type, Qpng)
|| EQ (type, Qgif)
|| EQ (type, Qtiff)
|| EQ (type, Qnative_image)))
{
/* GDI+ can also display BMP, Exif, ICON, WMF, and EMF images.
But we don't yet support these in image.c. */
return false;
}
return gdiplus_startup ();
}
static double
w32_frame_delay (GpBitmap *pBitmap, int frame)
@ -150,25 +212,26 @@ w32_frame_delay (GpBitmap *pBitmap, int frame)
GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay, &size);
/* Allocate a buffer to receive the property item. */
propertyItem = (PropertyItem*)malloc (size);
propertyItem = malloc (size);
if (propertyItem != NULL)
{
/* Get the property item. */
GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size, propertyItem);
delay = ((double)propertyItem[frame].length) / 100;
delay = propertyItem[frame].length / 100.0;
if (delay == 0)
{
/* In GIF files, unfortunately, delay is only specified for the first
frame. */
delay = ((double)propertyItem[0].length) / 100;
delay = propertyItem[0].length / 100.0;
}
free (propertyItem);
}
return delay;
}
static UINT
w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *delay)
static GpStatus
w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes,
double *delay)
{
UINT count, frameCount;
GUID pDimensionIDs[1];
@ -181,15 +244,14 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del
{
status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1);
status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount);
if ((status == Ok) && (frameCount > 1))
if (status == Ok && frameCount > 1)
{
if (frame < 0 || frame >= frameCount)
{
status = GenericError;
}
status = GenericError;
else
{
status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], frame);
status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0],
frame);
*delay = w32_frame_delay (pBitmap, frame);
*nframes = frameCount;
}
@ -201,9 +263,7 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del
static ARGB
w32_image_bg_color (struct frame *f, struct image *img)
{
/* png_color_16 *image_bg; */
Lisp_Object specified_bg
= Fplist_get (XCDR (img->spec), QCbackground);
Lisp_Object specified_bg = Fplist_get (XCDR (img->spec), QCbackground);
Emacs_Color color;
/* If the user specified a color, try to use it; if not, use the
@ -212,38 +272,34 @@ w32_image_bg_color (struct frame *f, struct image *img)
if (STRINGP (specified_bg)
? w32_defined_color (f, SSDATA (specified_bg), &color, false, false)
: (w32_query_frame_background_color (f, &color), true))
/* The user specified `:background', use that. */
/* The user specified ':background', use that. */
{
DWORD red = (((DWORD) color.red) & 0xff00) << 8;
DWORD green = ((DWORD) color.green) & 0xff00;
DWORD blue = ((DWORD) color.blue) >> 8;
return red | green | blue;
return (ARGB) (red | green | blue);
}
return ((DWORD) 0xff000000);
return (ARGB) 0xff000000;
}
int
w32_load_image (struct frame *f, struct image *img,
Lisp_Object spec_file, Lisp_Object spec_data)
{
Emacs_Pixmap pixmap;
GpStatus status = GenericError;
GpBitmap *pBitmap;
wchar_t filename[MAX_PATH];
ARGB bg_color;
Lisp_Object lisp_index, metadata;
unsigned int index, nframes;
double delay;
Lisp_Object metadata;
eassert (valid_image_p (img->spec));
/* This function only gets called if init_w32_gdiplus () was invoked. We have
a valid token and GDI+ is active. */
/* This function only gets called if w32_gdiplus_startup was invoked
and succeeded. We have a valid token and GDI+ is active. */
if (STRINGP (spec_file))
{
if (w32_unicode_filenames)
{
filename_to_utf16 (SSDATA (spec_file) , filename);
wchar_t filename[MAX_PATH];
filename_to_utf16 (SSDATA (spec_file), filename);
status = GdipCreateBitmapFromFile (filename, &pBitmap);
}
else
@ -254,7 +310,7 @@ w32_load_image (struct frame *f, struct image *img,
}
else if (STRINGP (spec_data))
{
IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data),
IStream *pStream = SHCreateMemStream ((BYTE *) SDATA (spec_data),
SBYTES (spec_data));
if (pStream != NULL)
{
@ -266,22 +322,28 @@ w32_load_image (struct frame *f, struct image *img,
metadata = Qnil;
if (status == Ok)
{
/* In multiframe pictures, select the first one */
lisp_index = Fplist_get (XCDR (img->spec), QCindex);
index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0;
/* In multiframe pictures, select the first frame. */
Lisp_Object lisp_index = Fplist_get (XCDR (img->spec), QCindex);
int index = FIXNATP (lisp_index) ? XFIXNAT (lisp_index) : 0;
int nframes;
double delay;
status = w32_select_active_frame (pBitmap, index, &nframes, &delay);
if ((status == Ok))
if (status == Ok)
{
if (nframes > 1)
metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata));
if (delay)
metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata));
}
else if (status == Win32Error) /* FIXME! */
status = Ok;
}
if (status == Ok)
{
bg_color = w32_image_bg_color (f, img);
ARGB bg_color = w32_image_bg_color (f, img);
Emacs_Pixmap pixmap;
status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color);
if (status == Ok)
{

View file

@ -7658,6 +7658,25 @@ Windows 8. It is set to nil on Windows 9X. */);
else
w32_unicode_filenames = 1;
DEFVAR_BOOL ("w32-use-native-image-API",
w32_use_native_image_api,
doc: /* Non-nil means use the native MS-Windows image API to display images.
A value of nil means displaying images other than PBM and XBM requires
optional supporting libraries to be installed.
The native image API library used is GDI+ via GDIPLUS.DLL. This
library is available only since W2K, therefore this variable is
unconditionally set to nil on older systems. */);
/* For now, disabled by default, since this is an experimental feature. */
#if 0 && HAVE_NATIVE_IMAGE_API
if (os_subtype == OS_9X)
w32_use_native_image_api = 0;
else
w32_use_native_image_api = 1;
#else
w32_use_native_image_api = 0;
#endif
/* FIXME: The following variable will be (hopefully) removed
before Emacs 25.1 gets released. */

View file

@ -75,10 +75,6 @@ struct w32_palette_entry {
extern void w32_regenerate_palette (struct frame *f);
extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal,
RECT *rect);
extern int w32_load_image (struct frame *f, struct image *img,
Lisp_Object spec_file, Lisp_Object spec_data);
extern bool w32_gdiplus_startup (void);
extern void w32_gdiplus_shutdown (void);
/* For each display (currently only one on w32), we have a structure that
records information about it. */