unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#71909: 30.0.60;
       [not found] <865xtnhyn6.fsf@foxmail.com>
@ 2024-10-05 12:28 ` Cecilio Pardo
  2024-10-05 12:33   ` Eli Zaretskii
  2024-10-28 21:46   ` Cecilio Pardo
  0 siblings, 2 replies; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-05 12:28 UTC (permalink / raw)
  To: 71909


I'll be working on this, if no one else is.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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-10 10:04     ` bug#71909: 30.0.60; Cecilio Pardo
  2024-10-28 21:46   ` Cecilio Pardo
  1 sibling, 2 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-05 12:33 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Sat, 5 Oct 2024 14:28:35 +0200
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> 
> I'll be working on this, if no one else is.

Thanks in advance.

Btw, if you are looking for significant enhancements to Emacs on
Windows, then support for color fonts (which needs to use Direct2D,
AFAIU) will be greatly appreciated.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 12:33   ` Eli Zaretskii
@ 2024-10-05 12:42     ` Eli Zaretskii
  2024-10-05 17:14       ` Cecilio Pardo
  2024-10-10 10:04     ` bug#71909: 30.0.60; Cecilio Pardo
  1 sibling, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-05 12:42 UTC (permalink / raw)
  To: cpardo; +Cc: 71909

> Cc: 71909@debbugs.gnu.org
> Date: Sat, 05 Oct 2024 15:33:39 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> 
> > Date: Sat, 5 Oct 2024 14:28:35 +0200
> > From: Cecilio Pardo <cpardo@imayhem.com>
> > 
> > 
> > I'll be working on this, if no one else is.
> 
> Thanks in advance.

Btw, perhaps we should discuss the implementation ideas you have
first.  I'm guessing you are going to somehow map the clipboard
formats defined by Windows to MIME types, then I wonder what should we
do with the virtually open-ended set of Windows clipboard formats.

Or maybe you have other ideas?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 12:42     ` Eli Zaretskii
@ 2024-10-05 17:14       ` Cecilio Pardo
  2024-10-05 19:31         ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-05 17:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

On 05/10/2024 14:42, Eli Zaretskii wrote:

> Btw, perhaps we should discuss the implementation ideas you have
> first.  I'm guessing you are going to somehow map the clipboard
> formats defined by Windows to MIME types, then I wonder what should we
> do with the virtually open-ended set of Windows clipboard formats.
> 
> Or maybe you have other ideas?

Yes, I was thinking about mapping some of the formats, and ignoring the 
rest. Looking at the lisp files inside emacs, only these formats seem to 
be in use:

image/*
text/html (which is treated as text in sgml-mode)
x/special-\\(?:gnome\\|KDE\\|mate\\)-files

So CF_BITMAP and CF_HDROP, and maybe CF_HTML would cover all. Metafiles 
could be converted to bitmaps.

As for other formats, other than offer them as application/octet-stream, 
I don't know.
















^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 17:14       ` Cecilio Pardo
@ 2024-10-05 19:31         ` Eli Zaretskii
  2024-10-05 21:24           ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-05 19:31 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Sat, 5 Oct 2024 19:14:20 +0200
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> On 05/10/2024 14:42, Eli Zaretskii wrote:
> 
> > Btw, perhaps we should discuss the implementation ideas you have
> > first.  I'm guessing you are going to somehow map the clipboard
> > formats defined by Windows to MIME types, then I wonder what should we
> > do with the virtually open-ended set of Windows clipboard formats.
> > 
> > Or maybe you have other ideas?
> 
> Yes, I was thinking about mapping some of the formats, and ignoring the 
> rest. Looking at the lisp files inside emacs, only these formats seem to 
> be in use:
> 
> image/*
> text/html (which is treated as text in sgml-mode)
> x/special-\\(?:gnome\\|KDE\\|mate\\)-files
> 
> So CF_BITMAP and CF_HDROP, and maybe CF_HTML would cover all. Metafiles 
> could be converted to bitmaps.
> 
> As for other formats, other than offer them as application/octet-stream, 
> I don't know.

If you invoke "M-: (gui-get-selection 'CLIPBOARD 'TARGETS) RET" after
copying something to the clipboard, you will see some very weird
format names there.  For the standard formats, we convert them to
something similar to what X Window system produces (see
w32-selection-targets), but the rest are returned as-is.  For example,
after copying an image from Firefox, I get this as the return value of
the above evaluation:

  [DataObject text/html HTML\ Format text/_moz_htmlinfo text/_moz_htmlcontext application/x-moz-file-promise-url application/x-moz-file-promise-dest-filename FILE_NAMES Preferred\ DropEffect application/x-moz-nativeimage DIB Ole\ Private\ Data BITMAP nil]

There's no image/* here, only DIB and BITMAP (which correspond to
CF_DIB and CF_BITMAP clipboard formats).  There are also a lot of
text/* formats, but they are all non-standard, except, perhaps,
text/html.  Do you have ideas how to select the proper format and how
to yank the data?

What do the x/special-* formats correspond to on Windows?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 19:31         ` Eli Zaretskii
@ 2024-10-05 21:24           ` Cecilio Pardo
  2024-10-06  5:59             ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-05 21:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

On 05/10/2024 21:31, Eli Zaretskii wrote:

> If you invoke "M-: (gui-get-selection 'CLIPBOARD 'TARGETS) RET" after
> copying something to the clipboard, you will see some very weird
> format names there.  For the standard formats, we convert them to
> something similar to what X Window system produces (see
> w32-selection-targets), but the rest are returned as-is.  For example,
> after copying an image from Firefox, I get this as the return value of
> the above evaluation:
> 
>    [DataObject text/html HTML\ Format text/_moz_htmlinfo text/_moz_htmlcontext application/x-moz-file-promise-url application/x-moz-file-promise-dest-filename FILE_NAMES Preferred\ DropEffect application/x-moz-nativeimage DIB Ole\ Private\ Data BITMAP nil]
> 
> There's no image/* here, only DIB and BITMAP (which correspond to
> CF_DIB and CF_BITMAP clipboard formats).  There are also a lot of
> text/* formats, but they are all non-standard, except, perhaps,
> text/html.  Do you have ideas how to select the proper format and how
> to yank the data?

> What do the x/special-* formats correspond to on Windows?

We would convert the BITMAP format to image/png, and FILE_NAMES to
x-special/gnome-copied-files, to be compatible with what org-mode does 
now. The offer to yank-media would then be text/html, image/png, and 
x-special/gnome-copied-files, ignoring the rest of formats.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 21:24           ` Cecilio Pardo
@ 2024-10-06  5:59             ` Eli Zaretskii
       [not found]               ` <87ldz1h5s4.fsf@gmail.com>
  2024-10-07 10:24               ` Cecilio Pardo
  0 siblings, 2 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-06  5:59 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Sat, 5 Oct 2024 23:24:09 +0200
> From: Cecilio Pardo <cpardo@imayhem.com>
> Cc: 71909@debbugs.gnu.org
> 
> On 05/10/2024 21:31, Eli Zaretskii wrote:
> 
> > If you invoke "M-: (gui-get-selection 'CLIPBOARD 'TARGETS) RET" after
> > copying something to the clipboard, you will see some very weird
> > format names there.  For the standard formats, we convert them to
> > something similar to what X Window system produces (see
> > w32-selection-targets), but the rest are returned as-is.  For example,
> > after copying an image from Firefox, I get this as the return value of
> > the above evaluation:
> > 
> >    [DataObject text/html HTML\ Format text/_moz_htmlinfo text/_moz_htmlcontext application/x-moz-file-promise-url application/x-moz-file-promise-dest-filename FILE_NAMES Preferred\ DropEffect application/x-moz-nativeimage DIB Ole\ Private\ Data BITMAP nil]
> > 
> > There's no image/* here, only DIB and BITMAP (which correspond to
> > CF_DIB and CF_BITMAP clipboard formats).  There are also a lot of
> > text/* formats, but they are all non-standard, except, perhaps,
> > text/html.  Do you have ideas how to select the proper format and how
> > to yank the data?
> 
> > What do the x/special-* formats correspond to on Windows?
> 
> We would convert the BITMAP format to image/png

But BITMAP is not PNG, AFAIU.  Moreover, with some images, when I copy
them in a Web browser, I see "PNG" in the targets vector reported by
gui-get-selection.  So I think we need to understand what exactly we
get with each format before we decide on the mapping.

As another data point. text/html seems to be Firefox-specific thing;
the standard Windows name for this is "HTML Format" (with the embedded
space).

> and FILE_NAMES to
> x-special/gnome-copied-files, to be compatible with what org-mode does 
> now. The offer to yank-media would then be text/html, image/png, and 
> x-special/gnome-copied-files, ignoring the rest of formats.

I don't like the Gnome-specific name x-special/gnome-copied-files.
I'd rather we produced a more generic name, and then ask the Org
developers to add support for it.

What about other kinds of media, like audio and video data?  Is that
supported, and if so, can we include that in some way?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
       [not found]               ` <87ldz1h5s4.fsf@gmail.com>
@ 2024-10-06 11:50                 ` Eli Zaretskii
  2024-10-06 12:15                   ` Visuwesh
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-06 11:50 UTC (permalink / raw)
  To: Visuwesh; +Cc: cpardo, 71909

> From: Visuwesh <visuweshm@gmail.com>
> Cc: Cecilio Pardo <cpardo@imayhem.com>,  71909@debbugs.gnu.org
> Date: Sun, 06 Oct 2024 16:12:03 +0530
> 
> What happens when you copy text from, say, MS Office with formatting
> applied to it (bold, italic, whatever)?  The same with MS Office Excel.
> I was thinking of eventually™ writing handlers for LibreOffice when
> copying over table cells for org-mode.

That requires Emacs to know about Rich Text, and to be able to convert
that to Emacs faces.

> When copying rich text from LibreOffice's MS Word equivalent,
> yank-media-types reports:
> 
>     Possible completions are:
>     primary:text/html
>     clipboard:application/x-openoffice-link;windows_formatname="Link"
>     clipboard:application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"
>     clipboard:TIMESTAMP
>     primary:STRING
>     primary:TEXT
>     primary:TIMESTAMP
>     primary:UTF8_STRING
>     primary:application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"
>     primary:application/x-openoffice-objectdescriptor-xml;windows_formatname="Star Object Descriptor (XML)";classname="8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6";typename="LibreOffice 24.2 Text Document";displayname="file:///home/viz/tmp/User_Manual.docx";viewaspect="1";width="17000";height="3000";posx="0";posy="0"
>     primary:text/plain
>     primary:text/plain;charset=utf-16
>     primary:text/plain;charset=utf-8
>     primary:text/richtext
>     primary:text/rtf

It is similar with Word on Windows, but the names of the formats are
different.

Also, if "primary:" means this is available in the PRIMARY selection,
then we are only talking about CLIPBOARD.  Try

  M-: (gui-get-selection 'CLIPBOARD 'TARGETS) RET

instead.

> where text/html is the most useful.

no, the most useful is Rich Text, but Emacs cannot yet yank that.

> When I copy a few table cells from LibreOffice's MS Excel equivalent, it
> reports:
> 
>     Possible completions are:
>     clipboard:application/x-openoffice-link;windows_formatname="Link"
>     clipboard:application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"
>     clipboard:STRING
>     clipboard:TEXT
>     clipboard:TIMESTAMP
>     clipboard:UTF8_STRING
>     clipboard:application/x-libreoffice-tsvc
>     clipboard:application/x-openoffice-bitmap;windows_formatname="Bitmap"
>     clipboard:application/x-openoffice-dif;windows_formatname="DIF"
>     clipboard:application/x-openoffice-emf;windows_formatname="Image EMF"
>     clipboard:application/x-openoffice-gdimetafile;windows_formatname="GDIMetaFile"
>     clipboard:application/x-openoffice-objectdescriptor-xml;windows_formatname="Star Object Descriptor (XML)";classname="47BBB4CB-CE4C-4E80-a591-42d9ae74950f";typename="LibreOffice 24.2 Spreadsheet";displayname="file:///home/viz/doc/uni/pincer/convergence_for_Mn-1.ods";viewaspect="1";width="15846";height="4065";posx="0";posy="0"
>     clipboard:application/x-openoffice-sylk;windows_formatname="Sylk"
>     clipboard:application/x-openoffice-wmf;windows_formatname="Image WMF"
>     clipboard:image/bmp
>     clipboard:image/png
>     clipboard:text/html
>     clipboard:text/plain
>     clipboard:text/plain;charset=utf-16
>     clipboard:text/plain;charset=utf-8
>     clipboard:text/richtext
>     clipboard:text/rtf
>     primary:CLASS
>     primary:COMPOUND_TEXT
>     primary:HOST_NAME
>     primary:LENGTH
>     primary:NAME
>     primary:OWNER_OS
>     primary:STRING
>     primary:TEXT
>     primary:TIMESTAMP
>     primary:USER
>     primary:UTF8_STRING
>     primary:text/plain
>     primary:text/plain;charset=utf-8
> 
> image/png is, well, an image of the copied cells, and text/html has a
> (an?) HTML table.

On Windows, I see CSV, which I think is more useful (maybe tsvc above
is something similar).  You definitely do NOT want an image in this
case.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-06 11:50                 ` Eli Zaretskii
@ 2024-10-06 12:15                   ` Visuwesh
  2024-10-20 13:09                     ` Ihor Radchenko
  0 siblings, 1 reply; 45+ messages in thread
From: Visuwesh @ 2024-10-06 12:15 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpardo, 71909

[ஞாயிறு அக்டோபர் 06, 2024] Eli Zaretskii wrote:

>> From: Visuwesh <visuweshm@gmail.com>
>> Cc: Cecilio Pardo <cpardo@imayhem.com>,  71909@debbugs.gnu.org
>> Date: Sun, 06 Oct 2024 16:12:03 +0530
>> 
>> What happens when you copy text from, say, MS Office with formatting
>> applied to it (bold, italic, whatever)?  The same with MS Office Excel.
>> I was thinking of eventually™ writing handlers for LibreOffice when
>> copying over table cells for org-mode.
>
> That requires Emacs to know about Rich Text, and to be able to convert
> that to Emacs faces.

Which I hope someone will eventually do something about.  When
yank-media was first mentioned among org-mode users, one of the first
question was "Can it paste text copied from the browser in org-mode
format?" (i.e., convert bold text to *bold text*)

>> When copying rich text from LibreOffice's MS Word equivalent,
>> yank-media-types reports:
>> 
>>     Possible completions are:
>>     primary:text/html
>>     clipboard:application/x-openoffice-link;windows_formatname="Link"
>>     clipboard:application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"
>>     clipboard:TIMESTAMP
>>[...]
> It is similar with Word on Windows, but the names of the formats are
> different.
>
> Also, if "primary:" means this is available in the PRIMARY selection,
> then we are only talking about CLIPBOARD.  

Yes, it means the PRIMARY selection.  For some reason, yank-media also
seems to consider the PRIMARY selection?  When I did M-x yank-media RET
in a html-mode buffer, it pasted the above text/html data.

> Try
>
>   M-: (gui-get-selection 'CLIPBOARD 'TARGETS) RET
>
> instead.
>
>> where text/html is the most useful.
>
> no, the most useful is Rich Text, but Emacs cannot yet yank that.

Possibly.  But we could at least "hijack" shr to convert text/html to
string with text properties on it, or make it insert markup elements.
I've done the later as a personal hack and it works fairly well.

>> When I copy a few table cells from LibreOffice's MS Excel equivalent, it
>> reports:
>> 
>>     Possible completions are:
>> [...]
>> image/png is, well, an image of the copied cells, and text/html has a
>> (an?) HTML table.
>
> On Windows, I see CSV, which I think is more useful (maybe tsvc above
> is something similar).  

You are right.  It pasted a TSV formatted text.  I missed it in the long
list of items.

> You definitely do NOT want an image in this case.

Definitely not.  I simply found it amusing that LibreOffice offered it
as a potential candidate.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-06  5:59             ` Eli Zaretskii
       [not found]               ` <87ldz1h5s4.fsf@gmail.com>
@ 2024-10-07 10:24               ` Cecilio Pardo
  2024-10-07 11:58                 ` Eli Zaretskii
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-07 10:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

On 06/10/2024 7:59, Eli Zaretskii wrote:

> But BITMAP is not PNG, AFAIU.  Moreover, with some images, when I copy
> them in a Web browser, I see "PNG" in the targets vector reported by
> gui-get-selection.  So I think we need to understand what exactly we
> get with each format before we decide on the mapping.

The standard bitmap formats for the clipboard (CF_BITMAP, CF_DIB, 
CF_DIBV5) are image data specific to windows, not an image format for 
saving to file.  We need to convert it to an image format, with a 
mime/type.  PNG or any other, even multiple ones.

GIMP on ubuntu for example does this when you copy a section of image:

[TIMESTAMP TARGETS MULTIPLE SAVE_TARGETS image/png image/bmp image/x-bmp 
image/x-MS-bmp image/x-icon image/x-ico image/x-win-bitmap 
image/vnd.microsoft.icon ...]

On windows it does this:

[PNG DIB BITMAP DIBV5]

And the Paint program that comes with Windows 11:

[DataObject Embed\ Source Native OwnerLink Object\ Descriptor METAFILE 
DIB PNG image/png Ole\ Private\ Data ENHMETAFILE BITMAP ...]

I didn't expect the PNG, image/png formats.  I suppose they are the same 
image as the DIB/BITMAP.  It seems programs are already doing the 
conversion.  I don't know the details yet, I'm on it.

So at least for images it seems most times we will have a well-known 
format.  If not (BITMAP,DIV), then we can do the PNG conversion.

> As another data point. text/html seems to be Firefox-specific thing;
> the standard Windows name for this is "HTML Format" (with the embedded
> space).

It may be interesting to handle some of this specific formats, from 
Firefox, or OpenOffice as discussed on another thread.  We will have to 
detect them somehow and decide what to do for each case.

> I don't like the Gnome-specific name x-special/gnome-copied-files.
> I'd rather we produced a more generic name, and then ask the Org
> developers to add support for it.

Of course.

> What about other kinds of media, like audio and video data?  Is that
> supported, and if so, can we include that in some way?

In standard formats there is CF_RIFF and CF_WAVE.  Also programas may 
insert a file format (as they do with PNGS), but I haven't found any 
example yet. In any case, we can do the same as with images.












^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-07 10:24               ` Cecilio Pardo
@ 2024-10-07 11:58                 ` Eli Zaretskii
  2024-10-09 12:52                   ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-07 11:58 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Mon, 7 Oct 2024 12:24:01 +0200
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> On 06/10/2024 7:59, Eli Zaretskii wrote:
> 
> > But BITMAP is not PNG, AFAIU.  Moreover, with some images, when I copy
> > them in a Web browser, I see "PNG" in the targets vector reported by
> > gui-get-selection.  So I think we need to understand what exactly we
> > get with each format before we decide on the mapping.
> 
> The standard bitmap formats for the clipboard (CF_BITMAP, CF_DIB, 
> CF_DIBV5) are image data specific to windows, not an image format for 
> saving to file.  We need to convert it to an image format, with a 
> mime/type.  PNG or any other, even multiple ones.

Isn't CF_BITMAP format indicate the data to which we convert images on
Windows in the w32-specific portions of image.c?  Or maybe it's a BMP
data (which we can already display, see w32image.c)?  If so, then
yanking images into an Emacs buffer could simply use the data instead
of converting to PNG, then back to bitmap.

> GIMP on ubuntu for example does this when you copy a section of image:
> 
> [TIMESTAMP TARGETS MULTIPLE SAVE_TARGETS image/png image/bmp image/x-bmp 
> image/x-MS-bmp image/x-icon image/x-ico image/x-win-bitmap 
> image/vnd.microsoft.icon ...]
> 
> On windows it does this:
> 
> [PNG DIB BITMAP DIBV5]
> 
> And the Paint program that comes with Windows 11:
> 
> [DataObject Embed\ Source Native OwnerLink Object\ Descriptor METAFILE 
> DIB PNG image/png Ole\ Private\ Data ENHMETAFILE BITMAP ...]
> 
> I didn't expect the PNG, image/png formats.  I suppose they are the same 
> image as the DIB/BITMAP.

I'd rather expect them to be in PNG format.

> > What about other kinds of media, like audio and video data?  Is that
> > supported, and if so, can we include that in some way?
> 
> In standard formats there is CF_RIFF and CF_WAVE.  Also programas may 
> insert a file format (as they do with PNGS), but I haven't found any 
> example yet. In any case, we can do the same as with images.

If CF_WAVE are the same data as in *.wav files, then we should be able
to invoke play-sound in some way.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-07 11:58                 ` Eli Zaretskii
@ 2024-10-09 12:52                   ` Cecilio Pardo
  2024-10-09 13:40                     ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-09 12:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

On 07/10/2024 13:58, Eli Zaretskii wrote:

> Isn't CF_BITMAP format indicate the data to which we convert images on
> Windows in the w32-specific portions of image.c?  Or maybe it's a BMP
> data (which we can already display, see w32image.c)?  If so, then
> yanking images into an Emacs buffer could simply use the data instead
> of converting to PNG, then back to bitmap.

But how would lisp programs register for receiving that?
yank-media-handler asks for mime types.

>> I didn't expect the PNG, image/png formats.  I suppose they are the same
>> image as the DIB/BITMAP.
> 
> I'd rather expect them to be in PNG format.

Yes, the same pixels, but in PNG format.

>>> What about other kinds of media, like audio and video data?  Is that
>>> supported, and if so, can we include that in some way?
>>
>> In standard formats there is CF_RIFF and CF_WAVE.  Also programas may
>> insert a file format (as they do with PNGS), but I haven't found any
>> example yet. In any case, we can do the same as with images.
> 
> If CF_WAVE are the same data as in *.wav files, then we should be able
> to invoke play-sound in some way.

But again, lisp programas need to register for a mime type, and then act 
on the data as they require.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-09 13:40 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Wed, 9 Oct 2024 14:52:57 +0200
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> On 07/10/2024 13:58, Eli Zaretskii wrote:
> 
> > Isn't CF_BITMAP format indicate the data to which we convert images on
> > Windows in the w32-specific portions of image.c?  Or maybe it's a BMP
> > data (which we can already display, see w32image.c)?  If so, then
> > yanking images into an Emacs buffer could simply use the data instead
> > of converting to PNG, then back to bitmap.
> 
> But how would lisp programs register for receiving that?
> yank-media-handler asks for mime types.

I believe the MIME type is image/bmp.

> > If CF_WAVE are the same data as in *.wav files, then we should be able
> > to invoke play-sound in some way.
> 
> But again, lisp programas need to register for a mime type, and then act 
> on the data as they require.

That's audio/wav, I believe.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 12:33   ` Eli Zaretskii
  2024-10-05 12:42     ` Eli Zaretskii
@ 2024-10-10 10:04     ` Cecilio Pardo
  2024-10-10 10:49       ` Eli Zaretskii
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-10 10:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

On 05/10/2024 14:33, Eli Zaretskii wrote:
>> Date: Sat, 5 Oct 2024 14:28:35 +0200
>> From: Cecilio Pardo <cpardo@imayhem.com>
>>
>>
>> I'll be working on this, if no one else is.
> 
> Thanks in advance.
> 
> Btw, if you are looking for significant enhancements to Emacs on
> Windows, then support for color fonts (which needs to use Direct2D,
> AFAIU) will be greatly appreciated.

Is there an open bug about this, or should I open a new one?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-10 10:04     ` bug#71909: 30.0.60; Cecilio Pardo
@ 2024-10-10 10:49       ` Eli Zaretskii
  0 siblings, 0 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-10 10:49 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Thu, 10 Oct 2024 12:04:31 +0200
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> On 05/10/2024 14:33, Eli Zaretskii wrote:
> >> Date: Sat, 5 Oct 2024 14:28:35 +0200
> >> From: Cecilio Pardo <cpardo@imayhem.com>
> >>
> > Btw, if you are looking for significant enhancements to Emacs on
> > Windows, then support for color fonts (which needs to use Direct2D,
> > AFAIU) will be greatly appreciated.
> 
> Is there an open bug about this, or should I open a new one?

I don't think we have a bug open for this.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-06 12:15                   ` Visuwesh
@ 2024-10-20 13:09                     ` Ihor Radchenko
  2024-10-20 13:51                       ` Eli Zaretskii
  2024-10-20 17:16                       ` Cecilio Pardo
  0 siblings, 2 replies; 45+ messages in thread
From: Ihor Radchenko @ 2024-10-20 13:09 UTC (permalink / raw)
  To: Visuwesh; +Cc: Eli Zaretskii, 71909, cpardo

Visuwesh <visuweshm@gmail.com> writes:

>>> where text/html is the most useful.
>>
>> no, the most useful is Rich Text, but Emacs cannot yet yank that.
>
> Possibly.  But we could at least "hijack" shr to convert text/html to
> string with text properties on it, or make it insert markup elements.
> I've done the later as a personal hack and it works fairly well.

May we utilize tree-sitter?
Having an AST, it should not be too hard to convert it into something
Emacs can understand.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 13:09                     ` Ihor Radchenko
@ 2024-10-20 13:51                       ` Eli Zaretskii
  2024-10-20 13:59                         ` Ihor Radchenko
  2024-10-20 17:16                       ` Cecilio Pardo
  1 sibling, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-20 13:51 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: cpardo, 71909, visuweshm

> From: Ihor Radchenko <yantar92@posteo.net>
> Cc: Eli Zaretskii <eliz@gnu.org>, cpardo@imayhem.com, 71909@debbugs.gnu.org
> Date: Sun, 20 Oct 2024 13:09:01 +0000
> 
> Visuwesh <visuweshm@gmail.com> writes:
> 
> >>> where text/html is the most useful.
> >>
> >> no, the most useful is Rich Text, but Emacs cannot yet yank that.
> >
> > Possibly.  But we could at least "hijack" shr to convert text/html to
> > string with text properties on it, or make it insert markup elements.
> > I've done the later as a personal hack and it works fairly well.
> 
> May we utilize tree-sitter?
> Having an AST, it should not be too hard to convert it into something
> Emacs can understand.

You mean, someone has written a tree-sitter grammar for Rich Text?

If not, what do you mean by "utilize tree-sitter" in this context?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 13:51                       ` Eli Zaretskii
@ 2024-10-20 13:59                         ` Ihor Radchenko
  2024-10-20 14:22                           ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Ihor Radchenko @ 2024-10-20 13:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpardo, 71909, visuweshm

Eli Zaretskii <eliz@gnu.org> writes:

>> May we utilize tree-sitter?
>> Having an AST, it should not be too hard to convert it into something
>> Emacs can understand.
>
> You mean, someone has written a tree-sitter grammar for Rich Text?

Yes. I did not check in details, but I did quick search before writing
my email and arrived at https://github.com/GoodNotes/tree-sitter-rtf

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 13:59                         ` Ihor Radchenko
@ 2024-10-20 14:22                           ` Eli Zaretskii
  2024-10-20 15:02                             ` Ihor Radchenko
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-20 14:22 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: cpardo, 71909, visuweshm

> From: Ihor Radchenko <yantar92@posteo.net>
> Cc: visuweshm@gmail.com, cpardo@imayhem.com, 71909@debbugs.gnu.org
> Date: Sun, 20 Oct 2024 13:59:47 +0000
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> May we utilize tree-sitter?
> >> Having an AST, it should not be too hard to convert it into something
> >> Emacs can understand.
> >
> > You mean, someone has written a tree-sitter grammar for Rich Text?
> 
> Yes. I did not check in details, but I did quick search before writing
> my email and arrived at https://github.com/GoodNotes/tree-sitter-rtf

Someone will need to generate the parser from that, before people can
compile and use the grammar library.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 14:22                           ` Eli Zaretskii
@ 2024-10-20 15:02                             ` Ihor Radchenko
  2024-10-20 15:34                               ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Ihor Radchenko @ 2024-10-20 15:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpardo, 71909, visuweshm

Eli Zaretskii <eliz@gnu.org> writes:

>> > You mean, someone has written a tree-sitter grammar for Rich Text?
>> 
>> Yes. I did not check in details, but I did quick search before writing
>> my email and arrived at https://github.com/GoodNotes/tree-sitter-rtf
>
> Someone will need to generate the parser from that, before people can
> compile and use the grammar library.

What is the problem generating parser library from source code?
The source code is there. Generating is simply yarn generate.


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 15:02                             ` Ihor Radchenko
@ 2024-10-20 15:34                               ` Eli Zaretskii
  2024-10-20 15:57                                 ` Ihor Radchenko
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-20 15:34 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: cpardo, 71909, visuweshm

> From: Ihor Radchenko <yantar92@posteo.net>
> Cc: visuweshm@gmail.com, cpardo@imayhem.com, 71909@debbugs.gnu.org
> Date: Sun, 20 Oct 2024 15:02:18 +0000
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> > You mean, someone has written a tree-sitter grammar for Rich Text?
> >> 
> >> Yes. I did not check in details, but I did quick search before writing
> >> my email and arrived at https://github.com/GoodNotes/tree-sitter-rtf
> >
> > Someone will need to generate the parser from that, before people can
> > compile and use the grammar library.
> 
> What is the problem generating parser library from source code?
> The source code is there. Generating is simply yarn generate.

We want to assume that everyone has yarn (and Node.js)?
treesit-install-language-grammar assumes the library's Git repository
includes code in C or C++.

All the other grammar libraries include the parser (and scanner, where
needed) in the Git repository, so I wonder why this one doesn't.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 15:34                               ` Eli Zaretskii
@ 2024-10-20 15:57                                 ` Ihor Radchenko
  2024-10-20 17:50                                   ` Visuwesh
  0 siblings, 1 reply; 45+ messages in thread
From: Ihor Radchenko @ 2024-10-20 15:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpardo, 71909, visuweshm

Eli Zaretskii <eliz@gnu.org> writes:

>> What is the problem generating parser library from source code?
>> The source code is there. Generating is simply yarn generate.
>
> We want to assume that everyone has yarn (and Node.js)?
> treesit-install-language-grammar assumes the library's Git repository
> includes code in C or C++.

> All the other grammar libraries include the parser (and scanner, where
> needed) in the Git repository, so I wonder why this one doesn't.

I see. It looks like a small problem. But one can set a CI pipeline to
compile the grammar automatically in a separate repository.

AFAIU, there are no license obstacles for doing this.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 13:09                     ` Ihor Radchenko
  2024-10-20 13:51                       ` Eli Zaretskii
@ 2024-10-20 17:16                       ` Cecilio Pardo
  2024-10-20 17:58                         ` Eli Zaretskii
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-20 17:16 UTC (permalink / raw)
  To: Ihor Radchenko, Visuwesh; +Cc: Eli Zaretskii, 71909

On 20/10/2024 15:09, Ihor Radchenko wrote:
> Visuwesh <visuweshm@gmail.com> writes:
> 
>>>> where text/html is the most useful.
>>>
>>> no, the most useful is Rich Text, but Emacs cannot yet yank that.
>>
>> Possibly.  But we could at least "hijack" shr to convert text/html to
>> string with text properties on it, or make it insert markup elements.
>> I've done the later as a personal hack and it works fairly well.
> 
> May we utilize tree-sitter?
> Having an AST, it should not be too hard to convert it into something
> Emacs can understand.

I had planned to try to use UnRTF for this.

https://www.gnu.org/software/unrtf/

It's a GNU package, and despite being old and (I think) unmaintained, it 
is used by many wrappers for different languages, so it probably works 
well, though I haven't tested it myself yet.

Has it been already tried for emacs?

If not, which approach (tree-sitter, unrtf) would be more promising?









^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 15:57                                 ` Ihor Radchenko
@ 2024-10-20 17:50                                   ` Visuwesh
  2024-10-20 17:59                                     ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Visuwesh @ 2024-10-20 17:50 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Eli Zaretskii, 71909, cpardo

[ஞாயிறு அக்டோபர் 20, 2024] Ihor Radchenko wrote:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> What is the problem generating parser library from source code?
>>> The source code is there. Generating is simply yarn generate.
>>
>> We want to assume that everyone has yarn (and Node.js)?
>> treesit-install-language-grammar assumes the library's Git repository
>> includes code in C or C++.
>
>> All the other grammar libraries include the parser (and scanner, where
>> needed) in the Git repository, so I wonder why this one doesn't.
>
> I see. It looks like a small problem. But one can set a CI pipeline to
> compile the grammar automatically in a separate repository.
>
> AFAIU, there are no license obstacles for doing this.

Can we not ask the author of the library to provide the C/C++ files in
the repo?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 17:16                       ` Cecilio Pardo
@ 2024-10-20 17:58                         ` Eli Zaretskii
  0 siblings, 0 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-20 17:58 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: yantar92, 71909, visuweshm

> Date: Sun, 20 Oct 2024 19:16:03 +0200
> Cc: Eli Zaretskii <eliz@gnu.org>, 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> I had planned to try to use UnRTF for this.
> 
> https://www.gnu.org/software/unrtf/
> 
> It's a GNU package, and despite being old and (I think) unmaintained, it 
> is used by many wrappers for different languages, so it probably works 
> well, though I haven't tested it myself yet.
> 
> Has it been already tried for emacs?

I don't think so.

> If not, which approach (tree-sitter, unrtf) would be more promising?

It depends on which one covers the RTF spec better, I think.  All the
rest being equal, I think tree-sitter is more promising, because it
will definitely be faster.  OTOH, an Emacs-specific downside of using
tree-sitter is that we don't have any experience using TS
structure-related information (sectioning, tables, numbered lists,
etc.) in Emacs, we only use TS for faces and indentation.  UnRTF
converts to HTML, and we already know how to use this stuff when
expressed in HTML.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-20 17:50                                   ` Visuwesh
@ 2024-10-20 17:59                                     ` Eli Zaretskii
  0 siblings, 0 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-20 17:59 UTC (permalink / raw)
  To: Visuwesh; +Cc: yantar92, 71909, cpardo

> From: Visuwesh <visuweshm@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  cpardo@imayhem.com,  71909@debbugs.gnu.org
> Date: Sun, 20 Oct 2024 23:20:50 +0530
> 
> [ஞாயிறு அக்டோபர் 20, 2024] Ihor Radchenko wrote:
> 
> > Eli Zaretskii <eliz@gnu.org> writes:
> >
> >>> What is the problem generating parser library from source code?
> >>> The source code is there. Generating is simply yarn generate.
> >>
> >> We want to assume that everyone has yarn (and Node.js)?
> >> treesit-install-language-grammar assumes the library's Git repository
> >> includes code in C or C++.
> >
> >> All the other grammar libraries include the parser (and scanner, where
> >> needed) in the Git repository, so I wonder why this one doesn't.
> >
> > I see. It looks like a small problem. But one can set a CI pipeline to
> > compile the grammar automatically in a separate repository.
> >
> > AFAIU, there are no license obstacles for doing this.
> 
> Can we not ask the author of the library to provide the C/C++ files in
> the repo?

It cannot hurt.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60; yank-media on MS-Windows
  2024-10-09 13:40                     ` Eli Zaretskii
@ 2024-10-23 23:13                       ` Cecilio Pardo
  2024-10-24  7:18                         ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-23 23:13 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

Getting back to this, I have been checking what some programs (a couple
of nonfree ones) provide on the clipboard for different media types.

GIMP           | Copy pixels           | PNG
LibreOffice    | Copy vectorial object | PNG, GDIMetafile
LibreOffice    | Copy embedded image   | PNG
LibreOffice    | Copy text             | RTF, HTML, ODT
LibreOffice    | Copy equation         | RTF
LibreOffice    | Copy Calc cells       | PNG, RTF, HTML, GDIMetafile
Firefox        | Copy Image            | DIBV5
Firefox        | Copy Text             | HTML, RTF
Krita          | Copy pixels           | PNG
Inkscape       | Copy vector           | SVG, PNG, PDF, Postscript
Windows Paint  | Copy pixels           | PNG
Acrobat Reader | Copy text             | RTF

They offer more formats, but in many cases they are not really there 
(the yank-media code knows about this, and in fact checks every type to 
purge the empty ones from list), or are propietary.

So I think we should stick to these:

- Rename PNG to image/png, so the emacs programs find it. If there are 
other image formats with mime spec, yank-media will let the user choose. 
For example, krita offers a huge amount of formats, as mime.

- If no PNG is offered, but DIBV5 is, like Firefox, convert the pixel 
data to a PNG file, and offer it as image/png. We don't loose anything 
converting the BMP to PNG, and the programs that use yank-media for 
images (message-mode, org-mode) need a file, not an in-memory image 
object. And PNG is a much better format.

- GDIMetafile would be ideally converted to SVG. Offering the metafile 
as it is makes little sense in my opinion. It is not a very used format.

- Text as HTML should be offered as text/html, for the use of html 
editing modes.

- Rtf text should be offered also to org-mode, adding a new yank handler 
to convert rtf format to org format. I am working on that. We could also 
provide it to enriched-mode, but it could use very few properties of the 
text. Anyway, this is not a Windows issue, and it still a little far away.






^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60; yank-media on MS-Windows
  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
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-24  7:18 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Thu, 24 Oct 2024 01:13:49 +0200
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> - Rename PNG to image/png, so the emacs programs find it. If there are 
> other image formats with mime spec, yank-media will let the user choose. 
> For example, krita offers a huge amount of formats, as mime.
> 
> - If no PNG is offered, but DIBV5 is, like Firefox, convert the pixel 
> data to a PNG file, and offer it as image/png. We don't loose anything 
> converting the BMP to PNG, and the programs that use yank-media for 
> images (message-mode, org-mode) need a file, not an in-memory image 
> object. And PNG is a much better format.

I'm not sure I follow: isn't yank-media about yanking the image into
the current buffer?  If so, why is having a file important, let alone
necessary?

> - GDIMetafile would be ideally converted to SVG. Offering the metafile 
> as it is makes little sense in my opinion. It is not a very used format.

Will we support yanking from a spreadsheet?  If so, with what format?

> - Text as HTML should be offered as text/html, for the use of html 
> editing modes.
> 
> - Rtf text should be offered also to org-mode, adding a new yank handler 
> to convert rtf format to org format. I am working on that. We could also 
> provide it to enriched-mode, but it could use very few properties of the 
> text. Anyway, this is not a Windows issue, and it still a little far away.

Where we have both RTF and HTML, should we perhaps use HTML and pass
it through shr, to produce text with faces, rather than raw HTML?
Once RTF handler exists, we could use that instead, but having it
rendered via HTML might be a useful option anyway.

Anyway, all in all, this sounds like a good plan, thanks.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60; yank-media on MS-Windows
  2024-10-24  7:18                         ` Eli Zaretskii
@ 2024-10-24  8:39                           ` Cecilio Pardo
  2024-10-24  9:38                             ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-24  8:39 UTC (permalink / raw)
  To: 71909



On 24/10/2024 9:18, Eli Zaretskii wrote:

>> - If no PNG is offered, but DIBV5 is, like Firefox, convert the pixel
>> data to a PNG file, and offer it as image/png. We don't loose anything
>> converting the BMP to PNG, and the programs that use yank-media for
>> images (message-mode, org-mode) need a file, not an in-memory image
>> object. And PNG is a much better format.
> 
> I'm not sure I follow: isn't yank-media about yanking the image into
> the current buffer?  If so, why is having a file important, let alone
> necessary?

I mean they need data in the format that would go into a file, PNG, BMP, 
etc. Not the kind of data that is a DIB. We could easily convert in to a 
BMP file, but, once we need to manipulate it, better to give a PNG.

org-mode stores the yanked images as attachments, saving files. 
message-mode stores the images in the message like this:

<#part type="image/png" disposition=inline data-encoding=base64 raw=t>
iVBORw0KGgoAA...

That is, not a file in disk, but the data that would go into a PNG file.

>> - GDIMetafile would be ideally converted to SVG. Offering the metafile
>> as it is makes little sense in my opinion. It is not a very used format.
> 
> Will we support yanking from a spreadsheet?  If so, with what format?

Yes, LibreOffice offers them as RTF, with a table. Also in HTML. I'm 
hoping to convert RTF tables to org-mode tables.

> Where we have both RTF and HTML, should we perhaps use HTML and pass
> it through shr, to produce text with faces, rather than raw HTML?
> Once RTF handler exists, we could use that instead, but having it
> rendered via HTML might be a useful option anyway.

What mode could benefit from yanking propertized test?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60; yank-media on MS-Windows
  2024-10-24  8:39                           ` Cecilio Pardo
@ 2024-10-24  9:38                             ` Eli Zaretskii
  2024-10-24 10:43                               ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-24  9:38 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Thu, 24 Oct 2024 10:39:13 +0200
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> On 24/10/2024 9:18, Eli Zaretskii wrote:
> 
> >> - If no PNG is offered, but DIBV5 is, like Firefox, convert the pixel
> >> data to a PNG file, and offer it as image/png. We don't loose anything
> >> converting the BMP to PNG, and the programs that use yank-media for
> >> images (message-mode, org-mode) need a file, not an in-memory image
> >> object. And PNG is a much better format.
> > 
> > I'm not sure I follow: isn't yank-media about yanking the image into
> > the current buffer?  If so, why is having a file important, let alone
> > necessary?
> 
> I mean they need data in the format that would go into a file, PNG, BMP, 
> etc. Not the kind of data that is a DIB. We could easily convert in to a 
> BMP file, but, once we need to manipulate it, better to give a PNG.

Maybe we need an image-save-as function, to save an image's data to a
file, then?  What you describe sounds like a separate requirement.

> org-mode stores the yanked images as attachments, saving files. 
> message-mode stores the images in the message like this:
> 
> <#part type="image/png" disposition=inline data-encoding=base64 raw=t>
> iVBORw0KGgoAA...
> 
> That is, not a file in disk, but the data that would go into a PNG file.

If a file is needed, writing the image data to a file will solve it
(and is a useful feature to have, regardless).

Does yank-media produce image files on GNU/Linux, when it yanks
images?

> > Where we have both RTF and HTML, should we perhaps use HTML and pass
> > it through shr, to produce text with faces, rather than raw HTML?
> > Once RTF handler exists, we could use that instead, but having it
> > rendered via HTML might be a useful option anyway.
> 
> What mode could benefit from yanking propertized test?

Any descendant of Text mode can use propertized text.  It doesn't
_have_ to be so, but it's possible, and I think we should offer that
if we can.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60; yank-media on MS-Windows
  2024-10-24  9:38                             ` Eli Zaretskii
@ 2024-10-24 10:43                               ` Cecilio Pardo
  0 siblings, 0 replies; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-24 10:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909



On 24/10/2024 11:38, Eli Zaretskii wrote:
>> Date: Thu, 24 Oct 2024 10:39:13 +0200
>> From: Cecilio Pardo <cpardo@imayhem.com>
>>
>> On 24/10/2024 9:18, Eli Zaretskii wrote:
>>
>>> I'm not sure I follow: isn't yank-media about yanking the image into
>>> the current buffer?  If so, why is having a file important, let alone
>>> necessary?
>>
>> I mean they need data in the format that would go into a file, PNG, BMP,
>> etc. Not the kind of data that is a DIB. We could easily convert in to a
>> BMP file, but, once we need to manipulate it, better to give a PNG.
> 
> Maybe we need an image-save-as function, to save an image's data to a
> file, then?  What you describe sounds like a separate requirement.
> 
>> org-mode stores the yanked images as attachments, saving files.
>> message-mode stores the images in the message like this:
>>
>> <#part type="image/png" disposition=inline data-encoding=base64 raw=t>
>> iVBORw0KGgoAA...
>>
>> That is, not a file in disk, but the data that would go into a PNG file.
> 
> If a file is needed, writing the image data to a file will solve it
> (and is a useful feature to have, regardless).
> 
> Does yank-media produce image files on GNU/Linux, when it yanks
> images?
> 

No, yank-media calls a handler (lisp function) given by the current mode 
that receives raw data for the clipboard content. The content 
corresponds to some file format. The mode specifies which mime types it 
wants, and specify a handler for each one of them. If after invoking 
yank-media there is more that one format accepted by the mode, the user 
has to choose one.

Org-mode saves the files to disk, message-mode embeds them in the body 
of the message, other modes could do differently.

This behaviour is only for GNU/Linux (and other ports I guess), on 
Windows yank-media does nothing currently.

>>> Where we have both RTF and HTML, should we perhaps use HTML and pass
>>> it through shr, to produce text with faces, rather than raw HTML?
>>> Once RTF handler exists, we could use that instead, but having it
>>> rendered via HTML might be a useful option anyway.
>>
>> What mode could benefit from yanking propertized test?
> 
> Any descendant of Text mode can use propertized text.  It doesn't
> _have_ to be so, but it's possible, and I think we should offer that
> if we can.

Then we can make Text-mode add a media handler for html-text (and 
hopefully tich text later), and convert it into propertized text.






^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-05 12:28 ` bug#71909: 30.0.60; Cecilio Pardo
  2024-10-05 12:33   ` Eli Zaretskii
@ 2024-10-28 21:46   ` Cecilio Pardo
  2024-10-29 14:25     ` Eli Zaretskii
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-28 21:46 UTC (permalink / raw)
  To: 71909

[-- Attachment #1: Type: text/plain, Size: 2307 bytes --]

This patch adds support for yank-media on MS-Windows.  Media is handled
in some different ways:

- Clipboard data that is already named as a mime-type needs no work
   besides returning it. For example, Krita provides copied pixels as
   multiple image/xxxx types, and Firefox provides html as text/html.

- Other programs don't use mime types. We try to recognize some names
   and change then to mime types. For example, GIMP uses the name "PNG"
   for copied pixels. We change it to image/png. LibreOffice also uses
   "PNG" for images. It uses "HTML Format" for rich text and also for
   spreadsheet cells, and we change that to text/html.

- Finally, some programs supply image data in DIBV5 format. We offer
   it as image/png, and convert in on the fly when requested. Firefox
   does this when using "Copy image".

This are the tested media types:

- [X] GIMP copy pixels             -> image/png
- [X] LibreOffice vectorial object -> image/png
- [X] LibreOffice embedded image   -> image/png
- [X] LibreOffice rich text        -> text/html
- [X] LibreOffice Calc cells       -> text/html
- [X] Firefox copy image           -> image/png (also text/html as
                                       embedded image)
- [X] Firefox page text            -> text/html
- [X] Krita pixels                 -> image/png (and others)
- [X] InkScape                     -> image/svg+xml, image/png

Images can be yanked in at least org-mode, message-mode, html-mode.
HTML (text/html) can be yanked in at least html-mode.

SVG will not work until bug #74044 is fixed.

LibreOffice offers vectorial objects as Metafiles, that
could be converted to SVG. I may do that at some point.

This patch does NOT include the planned functionality to yank rich
text as propertized text, or to use RTF format as a source. Those are
not Windows-only.

It also includes a small fix in sgml-mode.el. It was mangling image
files because of Windows new lines.

The image conversion is done using GdiPlus functions, which are
already used on w32image.c, but are static. I have splitted this file
into .c and .h, to be able to reuse those definitions. The image
conversion requires that native image functions are activated.

Now I think this patch may have been splitted into 2 or 3 for review. 
Let me know if that would be better.


[-- Attachment #2: 0001-Add-support-for-yank-media-on-MS-Windows.patch --]
[-- Type: text/plain, Size: 23418 bytes --]

From c6ecb594068db689c0b348be4f7cf53cc41b53e0 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.

* lisp/term/w32-win.el (w32--selection-target-translations): New
variable that holds the name translations for media tytpes.
(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.
* 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.
* src/w32select.c (stdfmt_name): Made global, was function static.
(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 convert
media content.
(syms_of_w32select): Export new lisp functions
* src/w32gdiplus.h: New file, for definitions in w32image.c
---
 lisp/term/w32-win.el        |  47 +++++++++-
 lisp/textmodes/sgml-mode.el |   7 +-
 src/w32gdiplus.h            | 112 +++++++++++++++++++++++
 src/w32image.c              |  96 +++-----------------
 src/w32select.c             | 174 +++++++++++++++++++++++++++++++-----
 5 files changed, 325 insertions(+), 111 deletions(-)
 create mode 100644 src/w32gdiplus.h

diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 75f8530010c..80d0e252839 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -442,15 +442,58 @@ 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)
+  (let ((ret
+         (append
+          (cl-mapcar #'car
+                     (cl-remove-if-not
+                      (lambda (x) (eq target
+                                      (w32--translate-selection-target (car x))))
+                      w32--selection-target-translations))
+          (list target))))
+    ret))
+
+
+(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"))
+                (data-types (w32--translate-reverse-selection-target data-type))
+                (data (w32--get-clipboard-data-media data-types tmp-file))
+                (result (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)
+           result))
         (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/w32image.c b/src/w32image.c
index 359a4fa3a72..2b1c6730e3e 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;
@@ -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.  */
@@ -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..6ee4e3af106 100644
--- a/src/w32select.c
+++ b/src/w32select.c
@@ -73,12 +73,17 @@ 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>
 #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 +792,151 @@ 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_can_use_native_image_api (Qpng)
+      || !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, 2, 2, 0,
+       doc: /* Gets media (not plain text) clipboard data in one of the given formats.
+FORMATS is the list of formats.
+TEMP-FILE-IN is the name of the file to store the data, that must be
+created by the callee, and also deleted if required.
+The passed file may be used or not, as indicated by the return value:
+
+Returns nil it there is no such format, or something failed.
+If it returns a string, then that is the data (not necessarily textual).
+If it returns 't, then the file contains the data.  */)
+  (Lisp_Object formats, Lisp_Object temp_file_in)
+{
+  CHECK_CONS (formats);
+  CHECK_STRING (temp_file_in);
+
+  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
+	result = make_unibyte_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 +1219,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 +1293,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


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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
  0 siblings, 2 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-29 14:25 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Mon, 28 Oct 2024 22:46:36 +0100
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> This patch adds support for yank-media on MS-Windows.  Media is handled
> in some different ways:
> 
> - Clipboard data that is already named as a mime-type needs no work
>    besides returning it. For example, Krita provides copied pixels as
>    multiple image/xxxx types, and Firefox provides html as text/html.
> 
> - Other programs don't use mime types. We try to recognize some names
>    and change then to mime types. For example, GIMP uses the name "PNG"
>    for copied pixels. We change it to image/png. LibreOffice also uses
>    "PNG" for images. It uses "HTML Format" for rich text and also for
>    spreadsheet cells, and we change that to text/html.
> 
> - Finally, some programs supply image data in DIBV5 format. We offer
>    it as image/png, and convert in on the fly when requested. Firefox
>    does this when using "Copy image".
> 
> This are the tested media types:
> 
> - [X] GIMP copy pixels             -> image/png
> - [X] LibreOffice vectorial object -> image/png
> - [X] LibreOffice embedded image   -> image/png
> - [X] LibreOffice rich text        -> text/html
> - [X] LibreOffice Calc cells       -> text/html
> - [X] Firefox copy image           -> image/png (also text/html as
>                                        embedded image)
> - [X] Firefox page text            -> text/html
> - [X] Krita pixels                 -> image/png (and others)
> - [X] InkScape                     -> image/svg+xml, image/png
> 
> Images can be yanked in at least org-mode, message-mode, html-mode.
> HTML (text/html) can be yanked in at least html-mode.
> 
> SVG will not work until bug #74044 is fixed.

Thanks.

> The image conversion is done using GdiPlus functions, which are
> already used on w32image.c, but are static. I have splitted this file
> into .c and .h, to be able to reuse those definitions. The image
> conversion requires that native image functions are activated.

What happens with yank-media if the user disables native image APIs?
Do we signal an error or is there some graceful degradation (like
using another MIME type)?

> Now I think this patch may have been splitted into 2 or 3 for review. 
> Let me know if that would be better.

I personally prefer a single patch.

> * lisp/term/w32-win.el (w32--selection-target-translations): New
> variable that holds the name translations for media tytpes.
> (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.
> * 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.
> * src/w32select.c (stdfmt_name): Made global, was function static.
> (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 convert
> media content.
> (syms_of_w32select): Export new lisp functions
> * src/w32gdiplus.h: New file, for definitions in w32image.c

Some of these lines are too long, please make sure they don't exceed
70 columns, preferably 63.

> +(defun w32--translate-reverse-selection-target(target)
> +  (let ((ret
> +         (append
> +          (cl-mapcar #'car
> +                     (cl-remove-if-not

This will load cl-seq in every w32 session, so let's not call cl-*
functions in preloaded files.

> +        ((eq type 'CLIPBOARD)
> +         (let* ((tmp-file (make-temp-file "emacs-clipboard"))
> +                (data-types (w32--translate-reverse-selection-target data-type))
> +                (data (w32--get-clipboard-data-media data-types tmp-file))
> +                (result (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)
> +           result))

This should use unwind-protect and/or condition-case, to make sure the
temporary file is deleted even if the user presses C-g or some code
signals an error.

> +DEFUN ("w32--get-clipboard-data-media", Fw32__get_clipboard_data_media,
> +       Sw32__get_clipboard_data_media, 2, 2, 0,
> +       doc: /* Gets media (not plain text) clipboard data in one of the given formats.
> +FORMATS is the list of formats.

This should say something about what can be put into FORMATS.

Also, "a list", not "the list".

> +TEMP-FILE-IN is the name of the file to store the data, that must be
> +created by the callee, and also deleted if required.
> +The passed file may be used or not, as indicated by the return value:

Isn't it easier and clearer to say "if the function returns t"?

> +Returns nil it there is no such format, or something failed.
> +If it returns a string, then that is the data (not necessarily textual).
> +If it returns 't, then the file contains the data.  */)
                 ^^
t, not 't

> +  (Lisp_Object formats, Lisp_Object temp_file_in)
> +{
> +  CHECK_CONS (formats);

CHECK_CONS or CHECK_LIST?

> +  char *temp_file = SSDATA (ENCODE_FILE (temp_file_in));

Every file name that we pass to C APIs must be run through
Fexpand_file_name, because each buffer in Emacs can have its own
default-directory.

> +      if (strcmp (name, "DIBV5") == 0)
> +	{
> +	  if (convert_dibv5_to_png (data, size, temp_file))
> +	    result = Qt;
> +	}
> +      else
> +	result = make_unibyte_string (data, size);

Why a unibyte string?  Is this always binary data or something?  If
this could be text (e.g., text/html), then a unibyte string is not the
best choice.

In any case, if the function must return a unibyte string in some
cases, that should be mentioned in the doc string, because callers
will otherwise not expect to get a unibyte string.  Also, where will
this unibyte string be decoded?

Finally, this needs some documentation: a NEWS item and some minimal
updates for the "Yanking Media" section of the ELisp manual (AFAICT,
it only needs to say that media can be yanked from the clipboard as
well as from a selection).





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-29 14:25     ` Eli Zaretskii
@ 2024-10-29 14:55       ` Eli Zaretskii
  2024-10-30  9:05       ` Cecilio Pardo
  1 sibling, 0 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-29 14:55 UTC (permalink / raw)
  To: cpardo; +Cc: 71909

> Cc: 71909@debbugs.gnu.org
> Date: Tue, 29 Oct 2024 16:25:29 +0200
> From: Eli Zaretskii <eliz@gnu.org>
> 
> Finally, this needs some documentation: a NEWS item and some minimal
> updates for the "Yanking Media" section of the ELisp manual (AFAICT,
> it only needs to say that media can be yanked from the clipboard as
> well as from a selection).

And one more issue: I get a compilation error using MinGW because
CF_DIBV5 is only defined since Win2K, and MinGW compilation generally
uses the default value of _WIN32_WINNT, which is set for Windows 9X.
So I suggest the following addition to w32select.c to work around that
(defining a larger value of _WIN32_WINNT doesn't seem justified for
such a minor nit):

#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"





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-30  9:05 UTC (permalink / raw)
  To: 71909

>> The image conversion is done using GdiPlus functions, which are
>> already used on w32image.c, but are static. I have splitted this file
>> into .c and .h, to be able to reuse those definitions. The image
>> conversion requires that native image functions are activated.
> 
> What happens with yank-media if the user disables native image APIs?
> Do we signal an error or is there some graceful degradation (like
> using another MIME type)?

The ability to yank DIBV5 will be lost. If there is no alternative such 
as PNG or image/*, then yank can't be done.

> Why a unibyte string?  Is this always binary data or something?  If
> this could be text (e.g., text/html), then a unibyte string is not the
> best choice.

It can be binary, but not always.  Is unibyte ok for binary cases? I can 
treat text/* differently, and make exceptions for types like image/svg+xml.

> In any case, if the function must return a unibyte string in some
> cases, that should be mentioned in the doc string, because callers
> will otherwise not expect to get a unibyte string.  Also, where will
> this unibyte string be decoded?

In the binary case, is there any decoding to do?








^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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
  0 siblings, 2 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-10-30 15:35 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Wed, 30 Oct 2024 10:05:08 +0100
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> >> The image conversion is done using GdiPlus functions, which are
> >> already used on w32image.c, but are static. I have splitted this file
> >> into .c and .h, to be able to reuse those definitions. The image
> >> conversion requires that native image functions are activated.
> > 
> > What happens with yank-media if the user disables native image APIs?
> > Do we signal an error or is there some graceful degradation (like
> > using another MIME type)?
> 
> The ability to yank DIBV5 will be lost. If there is no alternative such 
> as PNG or image/*, then yank can't be done.

Is this because w32-use-native-image-API set to nil disables loading
of GDI+?  If so, we could load it even if w32-use-native-image-API is
nil, but just return false from w32_can_use_native_image_api.  This
would allow us to use the GDI+ functions needed for yanking, but not
those needed for image display.  Does this make sense?

> > Why a unibyte string?  Is this always binary data or something?  If
> > this could be text (e.g., text/html), then a unibyte string is not the
> > best choice.
> 
> It can be binary, but not always.  Is unibyte ok for binary cases?

Yes.  But we need to document that in the doc string.

> I can 
> treat text/* differently, and make exceptions for types like image/svg+xml.

That'd be much better.

> > In any case, if the function must return a unibyte string in some
> > cases, that should be mentioned in the doc string, because callers
> > will otherwise not expect to get a unibyte string.  Also, where will
> > this unibyte string be decoded?
> 
> In the binary case, is there any decoding to do?

No.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-10-30 15:35         ` Eli Zaretskii
@ 2024-10-30 15:49           ` Cecilio Pardo
  2024-11-02  0:23           ` Cecilio Pardo
  1 sibling, 0 replies; 45+ messages in thread
From: Cecilio Pardo @ 2024-10-30 15:49 UTC (permalink / raw)
  To: 71909

On 30/10/2024 16:35, Eli Zaretskii wrote:
>> The ability to yank DIBV5 will be lost. If there is no alternative such
>> as PNG or image/*, then yank can't be done.
> 
> Is this because w32-use-native-image-API set to nil disables loading
> of GDI+?  If so, we could load it even if w32-use-native-image-API is
> nil, but just return false from w32_can_use_native_image_api.  This
> would allow us to use the GDI+ functions needed for yanking, but not
> those needed for image display.  Does this make sense?

Yes, I'll do that.

>>> Why a unibyte string?  Is this always binary data or something?  If
>>> this could be text (e.g., text/html), then a unibyte string is not the
>>> best choice.
>>
>> It can be binary, but not always.  Is unibyte ok for binary cases?
> 
> Yes.  But we need to document that in the doc string.
> 
>> I can
>> treat text/* differently, and make exceptions for types like image/svg+xml.
> 
> That'd be much better.

Ok.

I'm on it.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  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
  1 sibling, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-11-02  0:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

[-- Attachment #1: Type: text/plain, Size: 399 bytes --]

Here is a new version, with the discussed corrections.

- Now the test for gdiplus is done calling w32_gdiplus_startup.
   Will use it if its available, even if native image functions
   are disabled.
- Don't use cl-seq.
- Use Fexpand_file_name on file name.
- Send unibyte string only for binary data.
- Use unwind-protect to ensure temp file is deleted.
- Fixed docs, changelog, NEWS and manual.


[-- Attachment #2: 0001-Add-support-for-yank-media-on-MS-Windows.patch --]
[-- Type: text/plain, Size: 28306 bytes --]

From a2f9fadc4b951a321b5d03de9344731ef08dded7 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.

* lisp/term/w32-win.el (w32--selection-target-translations): New
variable that holds the name translations for media tytpes.
(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 function
static.
(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.
---
 doc/lispref/frames.texi     |  16 +--
 etc/NEWS                    |   6 ++
 lisp/term/w32-win.el        |  69 ++++++++++++-
 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, 387 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 d1c7303f976..601fcdb218b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -802,6 +802,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 active 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..037b97f4294 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -442,15 +442,80 @@ 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)))
+
+(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."
+
+  (let ((str (symbol-name mime-type)))
+    (or
+     (eq mime-type 'application/xml)
+     (eq mime-type 'application/json)
+     (eq mime-type 'application/yaml)
+     (eq mime-type 'application/json-seq)
+     (string-match-p "\\`text/" str)
+     (string-match-p "+xml\\'" str)
+     (string-match-p "+json\\'" str)
+     (string-match-p "+yaml\\'" str)
+     (string-match-p "+json-seq\\'" str))))
+
+(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..d1ca3848826 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.  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.
+
+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 file contains the data.
+If it returns a string, then that is the data and the file is not used.
+
+When returning a string, it can be unibyte if the format is not known to
+be text.  */)
+  (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


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-02  0:23           ` Cecilio Pardo
@ 2024-11-02 10:44             ` Eli Zaretskii
  2024-11-02 11:24               ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-11-02 10:44 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> Date: Sat, 2 Nov 2024 01:23:11 +0100
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> Here is a new version, with the discussed corrections.
> 
> - Now the test for gdiplus is done calling w32_gdiplus_startup.
>    Will use it if its available, even if native image functions
>    are disabled.
> - Don't use cl-seq.
> - Use Fexpand_file_name on file name.
> - Send unibyte string only for binary data.
> - Use unwind-protect to ensure temp file is deleted.
> - Fixed docs, changelog, NEWS and manual.

Thanks, there are a few minor nits left.

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

Please mention the bug number somwhere in the log message.

> * lisp/term/w32-win.el (w32--selection-target-translations): New
> variable that holds the name translations for media tytpes.
                                                      ^^^^^^
Typo.

> (w32--translate-reverse-selection-target): New function, Reverse
> translation.                                             ^^^^^^^

"reverse", not capitalized.

> * src/w32select.c (stdfmt_name): Made global, was function
> static.                                       ^^^^^^^^^^^^
  ^^^^^^
"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 not mentioned.

> ++++
> +** Emacs on MS-Windows now supports 'yank-media'.
> +This command inserts clipboard data of different formats into the
> +current buffer, if the active mode supports it.
                          ^^^^^^^^^^^
"major mode"

> +(defun w32--translate-selection-target(target)
                                        ^^
We leave one space between the function's name and the opening
parenthesis.  Same issue with other functions you added.

> +  (let ((str (symbol-name mime-type)))
> +    (or
> +     (eq mime-type 'application/xml)
> +     (eq mime-type 'application/json)
> +     (eq mime-type 'application/yaml)
> +     (eq mime-type 'application/json-seq)
> +     (string-match-p "\\`text/" str)
> +     (string-match-p "+xml\\'" str)
> +     (string-match-p "+json\\'" str)
> +     (string-match-p "+yaml\\'" str)
> +     (string-match-p "+json-seq\\'" str))))

This begs for 2 variables and using memq and seq-contains-p.  Or am I
missing something?

> +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?

> +If it returns t, then the file contains the data.

I guess we should add "and the caller should read the file to fetch
the data"?

> +If it returns a string, then that is the data and the file is not used.
> +
> +When returning a string, it can be unibyte if the format is not known to
> +be text.  */)
> +  (Lisp_Object formats, Lisp_Object temp_file_in, Lisp_Object is_textual)

This doc string doesn't say anything about the IS-TEXTUAL argument.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-02 10:44             ` Eli Zaretskii
@ 2024-11-02 11:24               ` Cecilio Pardo
  2024-11-02 12:09                 ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-11-02 11:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

> 
>> +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.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-02 11:24               ` Cecilio Pardo
@ 2024-11-02 12:09                 ` Eli Zaretskii
  2024-11-02 20:30                   ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-11-02 12:09 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909

> 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?





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-02 12:09                 ` Eli Zaretskii
@ 2024-11-02 20:30                   ` Cecilio Pardo
  2024-11-03 13:14                     ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-11-02 20:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71909

[-- 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


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-02 20:30                   ` Cecilio Pardo
@ 2024-11-03 13:14                     ` Eli Zaretskii
  2024-11-04 22:19                       ` Cecilio Pardo
  0 siblings, 1 reply; 45+ messages in thread
From: Eli Zaretskii @ 2024-11-03 13:14 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: 71909-done

> Date: Sat, 2 Nov 2024 21:30:38 +0100
> Cc: 71909@debbugs.gnu.org
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> 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.

Thanks, installed on master, and closing the bug.





^ permalink raw reply	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-03 13:14                     ` Eli Zaretskii
@ 2024-11-04 22:19                       ` Cecilio Pardo
  2024-11-05 12:30                         ` Eli Zaretskii
  0 siblings, 1 reply; 45+ messages in thread
From: Cecilio Pardo @ 2024-11-04 22:19 UTC (permalink / raw)
  To: 71909, eliz, aqua0210

I'm afraid this breaks the build if using --without-native-image-api

We'll need this:



diff --git a/src/w32select.c b/src/w32select.c
index 7e8dc3f0702..9379151f00d 100644
--- a/src/w32select.c
+++ b/src/w32select.c
@@ -825,6 +825,7 @@ DEFUN ("w32-set-clipboard-data", 
Fw32_set_clipboard_data,
  static bool
  convert_dibv5_to_png (char *data, int size, char *temp_file)
  {
+#ifdef HAVE_NATIVE_IMAGE_API
    CLSID clsid_png;

    if (!w32_gdiplus_startup ()
@@ -858,6 +859,10 @@ convert_dibv5_to_png (char *data, int size, char 
*temp_file)
    if (status != Ok)
      return false;
    return true;
+#else
+  return false;
+#endif
+
  }

  static int






^ permalink raw reply related	[flat|nested] 45+ messages in thread

* bug#71909: 30.0.60;
  2024-11-04 22:19                       ` Cecilio Pardo
@ 2024-11-05 12:30                         ` Eli Zaretskii
  0 siblings, 0 replies; 45+ messages in thread
From: Eli Zaretskii @ 2024-11-05 12:30 UTC (permalink / raw)
  To: Cecilio Pardo; +Cc: aqua0210, 71909

> Date: Mon, 4 Nov 2024 23:19:26 +0100
> From: Cecilio Pardo <cpardo@imayhem.com>
> 
> I'm afraid this breaks the build if using --without-native-image-api
> 
> We'll need this:

Thanks, installed (and mentioned in NEWS).





^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2024-11-05 12:30 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [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
2024-11-03 13:14                     ` Eli Zaretskii
2024-11-04 22:19                       ` Cecilio Pardo
2024-11-05 12:30                         ` 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).