Reading from Windows clipboard:

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Reading from Windows clipboard:

Post by GeeMack »

Using Windows 10 with IM 6.9.9-33 and 7.0.7-25.

I have a few little scripts where I copy some image data from another program to the Windows clipboard, then read it into an ImageMagick command using "clipboard:". If I try to read "clipboard:" more than once in a command, everything after the first read is just a black image.

Here's an example...

Code: Select all

magick logo: clipboard:

magick clipboard: test1.png

magick clipboard: clipboard: test2-%d.png
The first command starts with the built-in "logo:" and writes it to the Windows clipboard. The second command reads the Windows clipboard and writes it back out to "test1.png". So far so good.

The third command reads the Windows clipboard twice, then writes two output images, "test2-0.png" and "test2-1.png". The first is the image stored in the Windows clipboard as expected. The second image is the correct dimensions, but is just an all black image.

Is this a bug, feature, oversight?
Jason S
Posts: 103
Joined: 2010-12-14T19:42:12-07:00
Authentication code: 8675308

Re: Reading from Windows clipboard:

Post by Jason S »

I can reproduce this, and it seems like a bug to me. A process should be able to read the same clipboard data multiple times. Looking at the source code, this looks suspicious:

Code: Select all

coders/clipboard.c:

  OpenClipboard(NULL);
  bitmapH=(HBITMAP) GetClipboardData(CF_BITMAP);
  hPal=(HPALETTE) GetClipboardData(CF_PALETTE);
  CloseClipboard();
  ...
  hOldBitmap=(HBITMAP) SelectObject(hMemDC,bitmapH);
  ...
The documentation for GetClipboardData() says "The application must not use the handle [that the GetClipboardData function returns] after the EmptyClipboard or CloseClipboard function is called...".

Side note: Back when this code was written, maybe there was a reason to retrieve the image in CF_BITMAP format. But I'd bet that that's no longer the case, and using CF_DIB (or CF_DIBV5) would be better in every way. Windows will convert it automatically.
User avatar
dlemstra
Posts: 1570
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Reading from Windows clipboard:

Post by dlemstra »

This does look like a bug and we probably can do a clean up and use CF_DIB instead. Would you be willing to send us a PR for this Jason, or would you prefer us to handle this ourselves?

p.s. I wonder if we can free the bitmap that we created. I suspect that makes the second image black.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate
Jason S
Posts: 103
Joined: 2010-12-14T19:42:12-07:00
Authentication code: 8675308

Re: Reading from Windows clipboard:

Post by Jason S »

Sorry, but I don't think I want to try to make a pull request for this. Even just figuring out the minimal changes to fix the bug would take some time.

As for refactoring the whole thing to use CF_DIB, one issue is that ideally I'd want clipboard.c and bmp.c to share a lot of code, and I don't even know how to do that, and be compliant with your coding standards.

I suggest essentially the following steps for pasting an image from the clipboard:

Code: Select all

OpenClipboard(NULL)
[Optional: EnumClipboardFormats(), see below]
cliphandle = GetClipboardData(CF_DIB)
clipmem_size = GlobalSize(cliphandle)
clipmem = GlobalLock(cliphandle)
[Make a copy of the bytes in clipmem.]
GlobalUnlock(cliphandle)
CloseClipboard();
You now have a copy of clipmem, in DIB format (a BMP file, but without the 14-byte FILEHEADER).

If you want to try to support transparency, the best I can figure out is that you can use EnumClipboardFormats to get a list of available formats. If CF_DIBV5 appears in the list before CF_DIB or CF_BITMAP, then request the data in CF_DIBV5 format instead of CF_DIB format.

Copying an image to the clipboard would be something like this (this is not too different from the current code):

Code: Select all

cliphandle = GlobalAlloc(GMEM_MOVEABLE, clipmem_size)
clipmem = GlobalLock(cliphandle)
[Encode or copy the image in DIB format to clipmem.]
GlobalUnlock(cliphandle)
OpenClipboard(NULL)
EmptyClipboard()
SetClipboardData(CF_DIB [or CIF_DIBV5], cliphandle)
CloseClipboard()
User avatar
dlemstra
Posts: 1570
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Reading from Windows clipboard:

Post by dlemstra »

I just pushed some patches to resolve the issues. I also decided to read and write with the BMP delegate. We will try to publish a new release today/tomorrow. Can you give it another try after the next release?
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Reading from Windows clipboard:

Post by GeeMack »

dlemstra wrote: 2018-03-25T13:00:54-07:00Can you give it another try after the next release?
I'll give it a test and report my results here. As always, thanks for your attention to this issue!
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Reading from Windows clipboard:

Post by GeeMack »

dlemstra wrote: 2018-03-25T13:00:54-07:00Can you give it another try after the next release?
This issue appears to be resolved with both IM 7.0.7-28 Q16 x64 HDRI and IM 6.9.9-40 Q16 x64 HDRI. Thanks again.
Post Reply