From: Cecilio Pardo <cpardo@imayhem.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 71909@debbugs.gnu.org
Subject: bug#71909: 30.0.60;
Date: Sat, 2 Nov 2024 21:30:38 +0100 [thread overview]
Message-ID: <d3e17e4d-1f25-4a72-84aa-03ff1e9566ce@imayhem.com> (raw)
In-Reply-To: <86plndygyx.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 944 bytes --]
On 02/11/2024 13:09, Eli Zaretskii wrote:
>> Date: Sat, 2 Nov 2024 12:24:58 +0100
>> Cc: 71909@debbugs.gnu.org
>> From: Cecilio Pardo <cpardo@imayhem.com>
>>
>>>
>>>> +Elements in FORMATS are symbols naming a format, such a image/png, or
>>>> +image/jpeg. They don't need to be MIME types, any format available can
>>>> +be retrieved. For compatibility with X systems, some conventional
>>>> +format names are translated to equivalent MIME types.
>>>
>>> Should this mention 'w32--selection-target-translations'?
>>>
>>> And I don't understand what you mean by the second sentence above.
>>> Surely, "any format" can be retrieved only if there's a handler for
>>> it?
>>
>> Someone may use this function outside of yank-media to get data from the
>> clipboard, and handle it herself.
>
> Then maybe this sentence should be removed? What useful information
> does it provide?
I did that. New patch attached with all corrections.
Thank you.
[-- Attachment #2: 0001-Add-support-for-yank-media-on-MS-Windows.patch --]
[-- Type: text/plain, Size: 28317 bytes --]
From 4f4bc35f64c8b4e25574a2e396066e2e5fa7b307 Mon Sep 17 00:00:00 2001
From: Cecilio Pardo <cpardo@imayhem.com>
Date: Mon, 28 Oct 2024 22:18:13 +0100
Subject: [PATCH] Add support for yank-media on MS-Windows
Adds the capacity to handle types different from strings to the
clipboard management functions on MS-Windows, and some logic
required to convert media types names and content to be what
yank-media and the modes that use it expect (bug#71909).
* lisp/term/w32-win.el (w32--selection-target-translations): New
variable that holds the name translations for media types.
(w32--translate-selection-target): New function, translate the
name of a media type.
(w32--translate-reverse-selection-target): New function, reverse
translation.
(w32--get-selection): Modified to translate target names when
asked for targets, and retrieve media types when asked for them.
(w32--mime-type-textual-p): New function, checks if a MIME type
is textual.
* lisp/textmodes/sgml-mode.el (html-mode--image-yank-handler):
Fixed the image save mechanism, that added line feed characters
on MS-Windows, breaking binary formats.
* src/w32image.c (gdiplus_init): Modified to fetch more
functions fromm gdiplus.
(get_encoder_clsid): Renamed to w32_gdip_get_encoder_clsid and
made nonstatic.
(gdiplus_startup): Renamed to w32_gdiplus_startup and
made nonstatic.
* src/w32select.c (stdfmt_name): Made global, was static
function.
(convert_dibv5_to_png): New function to convert DIBV5 clipboard
format to PNG.
(get_clipboard_format_name): New function get the name of a
format given its index.
(Fw32__get_clipboard_data_media): New function, retrieves and
converts media content.
(syms_of_w32select): Export new lisp functions.
* src/w32gdiplus.h: New file, for definitions in w32image.c
* doc/lispref/frames.texi: Updated with MS-Windows support.
* etc/NEWS: Added entry about new feature.
---
doc/lispref/frames.texi | 16 +--
etc/NEWS | 6 ++
lisp/term/w32-win.el | 71 ++++++++++++-
lisp/textmodes/sgml-mode.el | 7 +-
src/w32gdiplus.h | 112 +++++++++++++++++++++
src/w32gui.h | 2 +
src/w32image.c | 104 ++++---------------
src/w32select.c | 194 +++++++++++++++++++++++++++++++-----
8 files changed, 389 insertions(+), 123 deletions(-)
create mode 100644 src/w32gdiplus.h
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index edeba3288fc..a3538c8ac4b 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -4758,14 +4758,14 @@ Other Selections
@node Yanking Media
@section Yanking Media
- Data saved within window system selections is not restricted to
-plain text. It is possible for selection data to encompass images or
-other binary data of the like, as well as rich text content instanced
-by HTML, and also PostScript. Since the selection data types incident
-to this data are at variance with those for plain text, the insertion
-of such data is facilitated by a set of functions dubbed
-@dfn{yank-media handlers}, which are registered by each major mode
-undertaking its insertion and called where warranted upon the
+ Data saved within window system selections and the MS-Windows
+clipboard is not restricted to plain text. It is possible for selection
+data to encompass images or other binary data of the like, as well as
+rich text content instanced by HTML, and also PostScript. Since the
+selection data types incident to this data are at variance with those
+for plain text, the insertion of such data is facilitated by a set of
+functions dubbed @dfn{yank-media handlers}, which are registered by each
+major mode undertaking its insertion and called where warranted upon the
execution of the @code{yank-media} command.
@defun yank-media-handler types handler
diff --git a/etc/NEWS b/etc/NEWS
index 4aba4b17055..900073bf80e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -815,6 +815,12 @@ DirectWrite rendering parameters.
To show color Emoji in Emacs, customize the default fontset to use a
color Emoji font installed on your system for the 'emoji' script.
++++
+** Emacs on MS-Windows now supports 'yank-media'.
+This command inserts clipboard data of different formats into the
+current buffer, if the major mode supports it.
+
+
\f
----------------------------------------------------------------------
This file is part of GNU Emacs.
diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 75f8530010c..b5c909f4a4e 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -442,15 +442,82 @@ w32--set-selection
(w32-set-clipboard-data (string-replace "\0" "\\0" value))
(put 'x-selections (or type 'PRIMARY) value)))
-(defun w32--get-selection (&optional type data-type)
+(defvar w32--selection-target-translations
+ '((PNG . image/png)
+ (DIBV5 . image/png)
+ (HTML\ Format . text/html)))
+
+(defun w32--translate-selection-target (target)
+ (let ((xlat (assoc target w32--selection-target-translations)))
+ (if xlat
+ (cdr xlat)
+ target)))
+
+(defun w32--translate-reverse-selection-target (target)
+ (append
+ (mapcar #'car
+ (seq-filter
+ (lambda (x)
+ (eq target
+ (w32--translate-selection-target (car x))))
+ w32--selection-target-translations))
+ (list target)))
+
+(defvar w32--textual-mime-types
+ '("application/xml"
+ "application/json"
+ "application/yaml"
+ "application/json-seq"
+ "\\`text/"
+ "+xml\\'"
+ "+json\\'"
+ "+yaml\\'"
+ "+json-seq\\'"))
+
+(defun w32--mime-type-textual-p (mime-type)
+ "Returns t if MIME-TYPE, a symbol, names a textual MIME type.
+
+This function is intended to classify clipboard data. All MIME subtypes
+of text/ are considered textual. Also those with suffixes +xml, +json,
++yaml, +json-seq. And application/xml, application/json,
+application/yaml, application/json-seq.
+
+This classification is not exhaustive. Some MIME types not listed may
+also be textual."
+ (string-match-p
+ (mapconcat #'identity w32--textual-mime-types "\\|")
+ (symbol-name mime-type)))
+
+(defun w32--get-selection (&optional type data-type)
(cond ((and (eq type 'CLIPBOARD)
(eq data-type 'STRING))
(with-demoted-errors "w32-get-clipboard-data:%S"
(w32-get-clipboard-data)))
((eq data-type 'TARGETS)
(if (eq type 'CLIPBOARD)
- (w32-selection-targets type)
+ (vconcat
+ (delete-dups
+ (seq-map #'w32--translate-selection-target
+ (w32-selection-targets type))))
(if (get 'x-selections (or type 'PRIMARY)) '[STRING])))
+ ((eq type 'CLIPBOARD)
+ (let ((tmp-file (make-temp-file "emacs-clipboard"))
+ (is-textual (w32--mime-type-textual-p data-type)))
+ (unwind-protect
+ (let* ((data-types (w32--translate-reverse-selection-target data-type))
+ (data (w32--get-clipboard-data-media data-types tmp-file is-textual)))
+ (cond
+ ;; data is in the file
+ ((eq data t)
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert-file-contents-literally tmp-file)
+ (buffer-string)))
+ ;; data is in data var
+ ((stringp data) data)
+ ;; No data
+ (t nil)))
+ (delete-file tmp-file))))
(t (get 'x-selections (or type 'PRIMARY)))))
(defun w32--selection-owner-p (selection)
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index cc86294df09..fad7008adc0 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -2476,10 +2476,9 @@ html-mode--image-yank-handler
(when (and (file-exists-p file)
(not (yes-or-no-p (format "%s exists; overwrite?" file))))
(user-error "%s exists" file))
- (with-temp-buffer
- (set-buffer-multibyte nil)
- (insert image)
- (write-region (point-min) (point-max) file))
+ (let ((coding-system-for-write 'emacs-internal))
+ (with-temp-file file
+ (insert image)))
(insert (format "<img src=%S>\n" (file-relative-name file)))
(insert-image
(create-image file (mailcap-mime-type-to-extension type) nil
diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h
new file mode 100644
index 00000000000..9d05ae6c190
--- /dev/null
+++ b/src/w32gdiplus.h
@@ -0,0 +1,112 @@
+#ifdef WINDOWSNT
+typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
+ (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
+typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
+typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
+ (GpImage *, PROPID, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
+ (GpImage *, PROPID, UINT, PropertyItem *);
+typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
+ (GpImage *, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
+ (GpImage *, GUID *, UINT);
+typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
+ (GpImage *, GDIPCONST GUID *, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
+ (GpImage*, GDIPCONST GUID *, UINT);
+typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
+ (WCHAR *, GpBitmap **);
+typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
+ (IStream *, GpBitmap **);
+typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc)
+ (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**);
+typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
+typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
+ (GpBitmap *, HBITMAP *, ARGB);
+typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
+typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
+typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
+ (UINT, UINT, ImageCodecInfo *);
+typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
+ (GDIPCONST WCHAR *,GpImage **);
+typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
+ (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
+typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
+ (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
+ GDIPCONST EncoderParameters *);
+typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc)
+ (GpImage *image, RotateFlipType rfType);
+
+extern GdiplusStartup_Proc fn_GdiplusStartup;
+extern GdiplusShutdown_Proc fn_GdiplusShutdown;
+extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
+extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem;
+extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount;
+extern GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList;
+extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
+extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
+extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
+extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
+extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
+extern SHCreateMemStream_Proc fn_SHCreateMemStream;
+extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
+extern GdipDisposeImage_Proc fn_GdipDisposeImage;
+extern GdipGetImageHeight_Proc fn_GdipGetImageHeight;
+extern GdipGetImageWidth_Proc fn_GdipGetImageWidth;
+extern GdipGetImageEncodersSize_Proc fn_GdipGetImageEncodersSize;
+extern GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
+extern GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
+extern GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
+extern GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
+extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
+
+# undef GdiplusStartup
+# undef GdiplusShutdown
+# undef GdipGetPropertyItemSize
+# undef GdipGetPropertyItem
+# undef GdipImageGetFrameDimensionsCount
+# undef GdipImageGetFrameDimensionsList
+# undef GdipImageGetFrameCount
+# undef GdipImageSelectActiveFrame
+# undef GdipCreateBitmapFromFile
+# undef GdipCreateBitmapFromStream
+# undef GdipCreateBitmapFromScan0
+# undef SHCreateMemStream
+# undef GdipCreateHBITMAPFromBitmap
+# undef GdipDisposeImage
+# undef GdipGetImageHeight
+# undef GdipGetImageWidth
+# undef GdipGetImageEncodersSize
+# undef GdipGetImageEncoders
+# undef GdipLoadImageFromFile
+# undef GdipGetImageThumbnail
+# undef GdipSaveImageToFile
+# undef GdipSaveImageRotateFlip
+
+# define GdiplusStartup fn_GdiplusStartup
+# define GdiplusShutdown fn_GdiplusShutdown
+# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
+# define GdipGetPropertyItem fn_GdipGetPropertyItem
+# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
+# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
+# define GdipImageGetFrameCount fn_GdipImageGetFrameCount
+# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
+# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
+# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
+# define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0
+# define SHCreateMemStream fn_SHCreateMemStream
+# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
+# define GdipDisposeImage fn_GdipDisposeImage
+# define GdipGetImageHeight fn_GdipGetImageHeight
+# define GdipGetImageWidth fn_GdipGetImageWidth
+# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize
+# define GdipGetImageEncoders fn_GdipGetImageEncoders
+# define GdipLoadImageFromFile fn_GdipLoadImageFromFile
+# define GdipGetImageThumbnail fn_GdipGetImageThumbnail
+# define GdipSaveImageToFile fn_GdipSaveImageToFile
+# define GdipImageRotateFlip fn_GdipImageRotateFlip
+#endif
+
+int w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid);
diff --git a/src/w32gui.h b/src/w32gui.h
index 739a790911e..26565dcae6b 100644
--- a/src/w32gui.h
+++ b/src/w32gui.h
@@ -45,7 +45,9 @@ #define local_free(p) (HeapFree (local_heap, 0, ((LPVOID) (p))))
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 bool w32_gdiplus_startup (void);
extern void w32_gdiplus_shutdown (void);
+
extern size_t w32_image_size (Emacs_Pixmap);
#define FACE_DEFAULT (~0)
diff --git a/src/w32image.c b/src/w32image.c
index 359a4fa3a72..44eed087528 100644
--- a/src/w32image.c
+++ b/src/w32image.c
@@ -38,44 +38,8 @@ #define COBJMACROS
#include "frame.h"
#include "coding.h"
+#include "w32gdiplus.h"
#ifdef WINDOWSNT
-
-typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
- (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
-typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
-typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
- (GpImage *, PROPID, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
- (GpImage *, PROPID, UINT, PropertyItem *);
-typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
- (GpImage *, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
- (GpImage *, GUID *, UINT);
-typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
- (GpImage *, GDIPCONST GUID *, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
- (GpImage*, GDIPCONST GUID *, UINT);
-typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
- (WCHAR *, GpBitmap **);
-typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
- (IStream *, GpBitmap **);
-typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
-typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
- (GpBitmap *, HBITMAP *, ARGB);
-typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
-typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
-typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
- (UINT, UINT, ImageCodecInfo *);
-typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
- (GDIPCONST WCHAR *,GpImage **);
-typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
- (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
-typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
- (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
- GDIPCONST EncoderParameters *);
-
GdiplusStartup_Proc fn_GdiplusStartup;
GdiplusShutdown_Proc fn_GdiplusShutdown;
GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
@@ -86,6 +50,7 @@ #define COBJMACROS
GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
+GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
SHCreateMemStream_Proc fn_SHCreateMemStream;
GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
GdipDisposeImage_Proc fn_GdipDisposeImage;
@@ -96,6 +61,7 @@ #define COBJMACROS
GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
+GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
static bool
gdiplus_init (void)
@@ -146,6 +112,10 @@ gdiplus_init (void)
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream");
if (!fn_GdipCreateBitmapFromStream)
return false;
+ fn_GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0_Proc)
+ get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromScan0");
+ if (!fn_GdipCreateBitmapFromScan0)
+ return false;
fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc)
get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap");
if (!fn_GdipCreateHBITMAPFromBitmap)
@@ -196,52 +166,14 @@ gdiplus_init (void)
get_proc_addr (gdiplus_lib, "GdipSaveImageToFile");
if (!fn_GdipSaveImageToFile)
return false;
+ fn_GdipImageRotateFlip = (GdipImageRotateFlip_Proc)
+ get_proc_addr (gdiplus_lib, "GdipImageRotateFlip");
+ if (!fn_GdipImageRotateFlip)
+ 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
-# undef GdipGetImageEncodersSize
-# undef GdipGetImageEncoders
-# undef GdipLoadImageFromFile
-# undef GdipGetImageThumbnail
-# undef GdipSaveImageToFile
-
-# define GdiplusStartup fn_GdiplusStartup
-# define GdiplusShutdown fn_GdiplusShutdown
-# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
-# define GdipGetPropertyItem fn_GdipGetPropertyItem
-# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
-# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
-# define GdipImageGetFrameCount fn_GdipImageGetFrameCount
-# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
-# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
-# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
-# define SHCreateMemStream fn_SHCreateMemStream
-# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
-# define GdipDisposeImage fn_GdipDisposeImage
-# define GdipGetImageHeight fn_GdipGetImageHeight
-# define GdipGetImageWidth fn_GdipGetImageWidth
-# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize
-# define GdipGetImageEncoders fn_GdipGetImageEncoders
-# define GdipLoadImageFromFile fn_GdipLoadImageFromFile
-# define GdipGetImageThumbnail fn_GdipGetImageThumbnail
-# define GdipSaveImageToFile fn_GdipSaveImageToFile
-
#endif /* WINDOWSNT */
static int gdip_initialized;
@@ -252,8 +184,8 @@ gdiplus_init (void)
/* Initialize GDI+, return true if successful. */
-static bool
-gdiplus_startup (void)
+bool
+w32_gdiplus_startup (void)
{
GpStatus status;
@@ -305,7 +237,7 @@ w32_can_use_native_image_api (Lisp_Object type)
But we don't yet support these in image.c. */
return false;
}
- return gdiplus_startup ();
+ return w32_gdiplus_startup ();
}
enum PropertyItem_type {
@@ -549,8 +481,8 @@ w32_load_image (struct frame *f, struct image *img,
};
-static int
-get_encoder_clsid (const char *type, CLSID *clsid)
+int
+w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid)
{
/* A simple cache based on the assumptions that many thumbnails will
be generated using the same TYPE. */
@@ -625,7 +557,7 @@ DEFUN ("w32image-create-thumbnail", Fw32image_create_thumbnail,
if (!gdiplus_started)
{
- if (!gdiplus_startup ())
+ if (!w32_gdiplus_startup ())
return Qnil;
}
@@ -649,7 +581,7 @@ DEFUN ("w32image-create-thumbnail", Fw32image_create_thumbnail,
CLSID thumb_clsid;
if (status == Ok
/* Get the GUID of the TYPE's encoder. */
- && get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0)
+ && w32_gdip_get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0)
{
/* Save the thumbnail image to a file of specified TYPE. */
wchar_t thumb_file_w[MAX_PATH];
diff --git a/src/w32select.c b/src/w32select.c
index 006bf408b47..7e8dc3f0702 100644
--- a/src/w32select.c
+++ b/src/w32select.c
@@ -73,12 +73,22 @@ Copyright (C) 1993-1994, 2001-2024 Free Software Foundation, Inc.
*/
#include <config.h>
+#include <windows.h>
+#include <wingdi.h>
+#include <wtypes.h>
+#include <gdiplus.h>
+#ifndef CF_DIBV5
+# define CF_DIBV5 17
+# undef CF_MAX
+# define CF_MAX 18
+#endif
#include "lisp.h"
#include "w32common.h" /* os_subtype */
#include "w32term.h" /* for all of the w32 includes */
#include "w32select.h"
#include "blockinput.h"
#include "coding.h"
+#include "w32gdiplus.h"
#ifdef CYGWIN
#include <string.h>
@@ -787,6 +797,166 @@ DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data,
return (ok ? string : Qnil);
}
+/* Xlib-like names for standard Windows clipboard data formats.
+ They are in upper-case to mimic xselect.c. A couple of the names
+ were changed to be more like their X counterparts. */
+static const char *stdfmt_name[] = {
+ "UNDEFINED",
+ "STRING",
+ "BITMAP",
+ "METAFILE",
+ "SYMLINK",
+ "DIF",
+ "TIFF",
+ "OEM_STRING",
+ "DIB",
+ "PALETTE",
+ "PENDATA",
+ "RIFF",
+ "WAVE",
+ "UTF8_STRING",
+ "ENHMETAFILE",
+ "FILE_NAMES", /* DND */
+ "LOCALE", /* not used */
+ "DIBV5"
+};
+
+/* Must be called with block_input() active. */
+static bool
+convert_dibv5_to_png (char *data, int size, char *temp_file)
+{
+ CLSID clsid_png;
+
+ if (!w32_gdiplus_startup ()
+ || !w32_gdip_get_encoder_clsid ("png", &clsid_png))
+ return false;
+
+ BITMAPV5HEADER *bmi = (void *) data;
+ int stride = bmi->bV5SizeImage / bmi->bV5Height;
+ long offset = bmi->bV5Size + bmi->bV5ClrUsed * sizeof (RGBQUAD);
+ if (bmi->bV5Compression == BI_BITFIELDS)
+ offset += 12;
+ BYTE *scan0 = data + offset;
+
+ GpBitmap *bitmap = NULL;
+
+ GpStatus status
+ = GdipCreateBitmapFromScan0 (bmi->bV5Width, bmi->bV5Height, stride,
+ PixelFormat32bppARGB, scan0, &bitmap);
+
+ if (status != Ok)
+ return false;
+
+ /* The bitmap comes upside down. */
+ GdipImageRotateFlip (bitmap, RotateNoneFlipY);
+
+ WCHAR wide_filename[MAX_PATH];
+ filename_to_utf16 (temp_file, wide_filename);
+
+ status = GdipSaveImageToFile (bitmap, wide_filename, &clsid_png, NULL);
+ GdipDisposeImage (bitmap);
+ if (status != Ok)
+ return false;
+ return true;
+}
+
+static int
+get_clipboard_format_name (int format_index, char *name)
+{
+ *name = 0;
+ format_index = EnumClipboardFormats (format_index);
+ if (format_index == 0)
+ return 0;
+ if (format_index < CF_MAX)
+ strcpy (name, stdfmt_name[format_index]);
+ GetClipboardFormatName (format_index, name, 256);
+ return format_index;
+}
+
+DEFUN ("w32--get-clipboard-data-media", Fw32__get_clipboard_data_media,
+ Sw32__get_clipboard_data_media, 3, 3, 0,
+ doc: /* Gets media (not plain text) clipboard data in one of the given formats.
+
+FORMATS is a list of formats.
+TEMP-FILE-IN is the name of the file to store the data.
+
+Elements in FORMATS are symbols naming a format, such a image/png, or
+image/jpeg. For compatibility with X systems, some conventional
+format names are translated to equivalent MIME types, as configured with
+the variable 'w32--selection-target-translations'.
+
+The file named in TEMP-FILE-IN must be created by the caller, and also
+deleted if required.
+
+Returns nil it there is no such format, or something failed.
+If it returns t, then the caller should read the file to get the data.
+If it returns a string, then that is the data and the file is not used.
+
+When returning a string, it will be unibyte if IS-TEXTUAL is nil (the
+content is binary data). */)
+ (Lisp_Object formats, Lisp_Object temp_file_in, Lisp_Object is_textual)
+{
+ CHECK_LIST (formats);
+ CHECK_STRING (temp_file_in);
+
+ temp_file_in = Fexpand_file_name (temp_file_in, Qnil);
+ char *temp_file = SSDATA (ENCODE_FILE (temp_file_in));
+
+ Lisp_Object result = Qnil;
+
+ block_input();
+ if (!OpenClipboard (NULL))
+ {
+ unblock_input();
+ return Qnil;
+ }
+
+ for (int format_index = 0;;)
+ {
+ static char name[256];
+ format_index = get_clipboard_format_name (format_index, name);
+ if (format_index == 0)
+ break;
+
+ /* If name doesn't match any of the formats, try the next format. */
+ bool match = false;
+ for (Lisp_Object tail = formats; CONSP (tail); tail = XCDR (tail))
+ if (strcmp (name, SSDATA (SYMBOL_NAME (XCAR (tail)))) == 0)
+ match = true;
+ if (!match)
+ continue;
+
+ /* Of the standard formats, only DIBV5 is supported. */
+ if (format_index < CF_MAX && format_index != CF_DIBV5)
+ continue;
+
+ /* Found the format. */
+ HANDLE d = GetClipboardData (format_index);
+ if (!d)
+ break;
+ int size = GlobalSize (d);
+ char *data = GlobalLock (d);
+ if (!data)
+ break;
+ if (strcmp (name, "DIBV5") == 0)
+ {
+ if (convert_dibv5_to_png (data, size, temp_file))
+ result = Qt;
+ }
+ else
+ {
+ if (NILP (is_textual))
+ result = make_unibyte_string (data, size);
+ else
+ result = make_string (data, size);
+ }
+ GlobalUnlock (d);
+ break;
+ }
+ CloseClipboard ();
+ unblock_input ();
+ return result;
+}
DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data,
Sw32_get_clipboard_data, 0, 1, 0,
@@ -1069,29 +1239,6 @@ DEFUN ("w32-selection-targets", Fw32_selection_targets, Sw32_selection_targets,
representing a data format that is currently available in the clipboard. */)
(Lisp_Object selection, Lisp_Object terminal)
{
- /* Xlib-like names for standard Windows clipboard data formats.
- They are in upper-case to mimic xselect.c. A couple of the names
- were changed to be more like their X counterparts. */
- static const char *stdfmt_name[] = {
- "UNDEFINED",
- "STRING",
- "BITMAP",
- "METAFILE",
- "SYMLINK",
- "DIF",
- "TIFF",
- "OEM_STRING",
- "DIB",
- "PALETTE",
- "PENDATA",
- "RIFF",
- "WAVE",
- "UTF8_STRING",
- "ENHMETAFILE",
- "FILE_NAMES", /* DND */
- "LOCALE", /* not used */
- "DIBV5"
- };
CHECK_SYMBOL (selection);
/* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
@@ -1166,6 +1313,7 @@ syms_of_w32select (void)
{
defsubr (&Sw32_set_clipboard_data);
defsubr (&Sw32_get_clipboard_data);
+ defsubr (&Sw32__get_clipboard_data_media);
defsubr (&Sw32_selection_exists_p);
defsubr (&Sw32_selection_targets);
--
2.35.1.windows.2
next prev parent reply other threads:[~2024-11-02 20:30 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <865xtnhyn6.fsf@foxmail.com>
2024-10-05 12:28 ` bug#71909: 30.0.60; Cecilio Pardo
2024-10-05 12:33 ` Eli Zaretskii
2024-10-05 12:42 ` Eli Zaretskii
2024-10-05 17:14 ` Cecilio Pardo
2024-10-05 19:31 ` Eli Zaretskii
2024-10-05 21:24 ` Cecilio Pardo
2024-10-06 5:59 ` Eli Zaretskii
[not found] ` <87ldz1h5s4.fsf@gmail.com>
2024-10-06 11:50 ` Eli Zaretskii
2024-10-06 12:15 ` Visuwesh
2024-10-20 13:09 ` Ihor Radchenko
2024-10-20 13:51 ` Eli Zaretskii
2024-10-20 13:59 ` Ihor Radchenko
2024-10-20 14:22 ` Eli Zaretskii
2024-10-20 15:02 ` Ihor Radchenko
2024-10-20 15:34 ` Eli Zaretskii
2024-10-20 15:57 ` Ihor Radchenko
2024-10-20 17:50 ` Visuwesh
2024-10-20 17:59 ` Eli Zaretskii
2024-10-20 17:16 ` Cecilio Pardo
2024-10-20 17:58 ` Eli Zaretskii
2024-10-07 10:24 ` Cecilio Pardo
2024-10-07 11:58 ` Eli Zaretskii
2024-10-09 12:52 ` Cecilio Pardo
2024-10-09 13:40 ` Eli Zaretskii
2024-10-23 23:13 ` bug#71909: 30.0.60; yank-media on MS-Windows Cecilio Pardo
2024-10-24 7:18 ` Eli Zaretskii
2024-10-24 8:39 ` Cecilio Pardo
2024-10-24 9:38 ` Eli Zaretskii
2024-10-24 10:43 ` Cecilio Pardo
2024-10-10 10:04 ` bug#71909: 30.0.60; Cecilio Pardo
2024-10-10 10:49 ` Eli Zaretskii
2024-10-28 21:46 ` Cecilio Pardo
2024-10-29 14:25 ` Eli Zaretskii
2024-10-29 14:55 ` Eli Zaretskii
2024-10-30 9:05 ` Cecilio Pardo
2024-10-30 15:35 ` Eli Zaretskii
2024-10-30 15:49 ` Cecilio Pardo
2024-11-02 0:23 ` Cecilio Pardo
2024-11-02 10:44 ` Eli Zaretskii
2024-11-02 11:24 ` Cecilio Pardo
2024-11-02 12:09 ` Eli Zaretskii
2024-11-02 20:30 ` Cecilio Pardo [this message]
2024-11-03 13:14 ` Eli Zaretskii
2024-11-04 22:19 ` Cecilio Pardo
2024-11-05 12:30 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d3e17e4d-1f25-4a72-84aa-03ff1e9566ce@imayhem.com \
--to=cpardo@imayhem.com \
--cc=71909@debbugs.gnu.org \
--cc=eliz@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).