| Summary: | Pasting (previous) images from Windows clipboard impossible into LO | ||
|---|---|---|---|
| Product: | LibreOffice | Reporter: | Senna-sport <gbcharlot-questionning12345> |
| Component: | LibreOffice | Assignee: | Not Assigned <libreoffice-bugs> |
| Status: | NEW --- | ||
| Severity: | normal | CC: | sokol |
| Priority: | medium | ||
| Version: | 7.4.4.2 release | ||
| Hardware: | All | ||
| OS: | All | ||
| Whiteboard: | |||
| Crash report or crash signature: | Regression By: | ||
|
Description
Senna-sport
2023-06-15 13:51:17 UTC
Repro. Version: 7.4.2.3 (x64) / LibreOffice Community Build ID: 382eef1f22670f7f4118c8c2dd222ec7ad009daf CPU threads: 6; OS: Windows 10.0 Build 19044; UI render: default; VCL: win Locale: ru-RU (ru_RU); UI: ru-RU Calc: CL When pasting an older using Windows' Clipboard history manager (WinLogo+V), the clipboard contents is replaced with the following three item types (seen with NirSoft' InsideClipboard): name size CF_BITMAP (id=2) 0 ExcludeClipboardContentFromMonitorProcessing 90 ClipboardHistoryItemId 76 The second is likely internal, to avoid capturing it second time, so uninteresting. OTOH, [Print Screen] button puts these to the clipboard: name size CF_BITMAP (id=2) 0 CF_DIB 8 294 452 CF_DIBV5 8 294 452 The interesting work happens in CDOTransferable::getClipboardData, which is called to obtain a bitmap, and requests a CF_DIB. We could consider a fallback to also request CF_BITMAP when DIB fails, but - read below. Also, it tries to obtain the data from the IDataObject. It needs a proper tymed; and in this specific case, the tymed that works is TYMED_GDI, so we could try to fallback to it, but - read below. Now for funny things. Even when implementing these ideas, the paste would fail, because WinBITMAPToOOBMP (that is called eventually for CF_BITMAP) would fail in a call to GetDIBits (after a "succeeded" call to GetBitmapDimensionEx, which gave [0, 0] size). OK, we can replace GetBitmapDimensionEx with GetObjectW(aHBMP, sizeof(BITMAP), &aBITMAP), giving the correct info ... but GetDIBits will fail anyway with GetLastInfo() giving 87 (the parameter is incorrect). But the best thing here is the Microsoft documentation for "Clipboard Formats" [1]. It tells in Synthesized Clipboard Formats: > The system implicitly converts data between certain clipboard formats: if a > window requests data in a format that is not on the clipboard, the system > converts an available format to the requested format. > ... > Clipboard Format Conversion Format > CF_BITMAP CF_DIB > ... > When copying bitmaps, it is best to place the CF_DIB or CF_DIBV5 format on the > clipboard. This is because the colors in a device-dependent bitmap (CF_BITMAP) > are relative to the system palette, which may change before the bitmap is pasted. > ... > If you place the CF_BITMAP format on the clipboard (and not CF_DIB), the system > renders the CF_DIB or CF_DIBV5 clipboard format as soon as the clipboard is > closed. This ensures that the correct palette is used to generate the DIB. So many things *not* happening as documented, when using the MS tool named "Clipboard history"! They do not put CF_DIB to the clipboard (even though the original clipboard content included that); the system does not create a CF_DIB at the time they put the CF_BITMAP to the clipboard; and they do not create it even when asked for this format explicitly. And finally, they refuse to create a DIB from the HBITMAP, using the API. If someone intends to work on this, the proper way seems to be like what is used in WinSalBitmap::ImplCopyDIBOrDDB - use the HBITMAP to draw to our buffer, and then maybe output the bitmap to DIB using WriteDIBBitmapEx (vcl/dibtools.hxx)? [1] https://learn.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats#synthesized-clipboard-formats |