summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2022-08-31 10:29:25 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-09-02 19:22:44 +0000
commit8edb27d7df69e643667e2fb301702a65c1364473 (patch)
tree61dee2eca61243207f7f6167561691c794da1642
parent134abb7eef2683b13b8d8c0be029795791e0233e (diff)
Windows: avoid losing transparency when pasting images into Qt apps
Before Qt6, we would only request a DIBV5 format image from the clipboard if that format was available without synthesizing. Then, in commit 8fa91c75ad that check was believed to be needless, and removed. However, it turns out that it is needed to avoid loosing transparency information, so we revert that part and bring back the check against synthesized DIBV5. The logic is that some widely used apps will provide images in both PNG and DIB on the clipboard, and only the former can have an alpha channel. When we request a synthesized DIBV5 rather than a PNG, it seems we only get the (opaque) DIB image repackaged as a DIBV5. On Windows 11, there even seems to be an issue (possibly a Windows bug) where, after asking for a synthesized DIBV5, the clipboard contents is somehow changed in a way so that pasting again into other (non-Qt) apps later will yield a corrupted (pixel-shifted) image. (It looks like they get a DIBV5 when they expect a DIB). So avoiding requests for synthesized DIBV5 also avoids triggering that issue. Also add some logging outout to help future debugging. Fixes: QTBUG-104872 Fixes: QTBUG-105338 Change-Id: I33ffa2b50870b887a083e9bbb1b2234604e4d8ab Reviewed-by: André de la Rocha <andre.rocha@qt.io> (cherry picked from commit 8cb78647e3d210e73a6dd4f0ca744b2887c482b7) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp35
1 files changed, 32 insertions, 3 deletions
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 8233e82d8e..829dc99b5b 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -906,6 +906,7 @@ public:
QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
+ bool hasOriginalDIBV5(IDataObject *pDataObj) const;
UINT CF_PNG;
};
@@ -987,15 +988,41 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD
return false;
}
+bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
+{
+ bool isSynthesized = true;
+ IEnumFORMATETC *pEnum = nullptr;
+ HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
+ if (res == S_OK && pEnum) {
+ FORMATETC fc;
+ while ((res = pEnum->Next(1, &fc, nullptr)) == S_OK) {
+ if (fc.ptd)
+ CoTaskMemFree(fc.ptd);
+ if (fc.cfFormat == CF_DIB)
+ break;
+ if (fc.cfFormat == CF_DIBV5) {
+ isSynthesized = false;
+ break;
+ }
+ }
+ pEnum->Release();
+ }
+ return !isSynthesized;
+}
+
QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
{
Q_UNUSED(preferredType);
QVariant result;
if (mimeType != u"application/x-qt-image")
return result;
- //Try to convert from DIBV5 as it is the most
- //widespread format that support transparency
- if (canGetData(CF_DIBV5, pDataObj)) {
+ // Try to convert from DIBV5 as it is the most widespread format that supports transparency,
+ // but avoid synthesizing it, as that typically loses transparency, e.g. from Office
+ const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj);
+ const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) : false;
+ qCDebug(lcQpaMime) << "canGetDibV5:" << canGetDibV5 << "hasOrigDibV5:" << hasOrigDibV5;
+ if (hasOrigDibV5) {
+ qCDebug(lcQpaMime) << "Decoding DIBV5";
QImage img;
QByteArray data = getData(CF_DIBV5, pDataObj);
QBuffer buffer(&data);
@@ -1004,6 +1031,7 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
}
//PNG, MS Office place this (undocumented)
if (canGetData(CF_PNG, pDataObj)) {
+ qCDebug(lcQpaMime) << "Decoding PNG";
QImage img;
QByteArray data = getData(CF_PNG, pDataObj);
if (img.loadFromData(data, "PNG")) {
@@ -1012,6 +1040,7 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
}
//Fallback to DIB
if (canGetData(CF_DIB, pDataObj)) {
+ qCDebug(lcQpaMime) << "Decoding DIB";
QImage img;
QByteArray data = getData(CF_DIBV5, pDataObj);
QBuffer buffer(&data);