summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/image/qbmphandler.cpp30
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp140
2 files changed, 43 insertions, 127 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index 74df9820e4..6d265ded67 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -147,6 +147,26 @@ static QDataStream &operator<<(QDataStream &s, const BMP_INFOHDR &bi)
s << bi.biSizeImage;
s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
s << bi.biClrUsed << bi.biClrImportant;
+
+ if (bi.biSize >= BMP_WIN4) {
+ s << bi.biRedMask << bi.biGreenMask << bi.biBlueMask << bi.biAlphaMask;
+ s << bi.biCSType;
+
+ for (int i = 0; i < 9; i++)
+ s << bi.biEndpoints[i];
+
+ s << bi.biGammaRed;
+ s << bi.biGammaGreen;
+ s << bi.biGammaBlue;
+ }
+
+ if (bi.biSize >= BMP_WIN5) {
+ s << bi.biIntent;
+ s << bi.biProfileData;
+ s << bi.biProfileSize;
+ s << bi.biReserved;
+ }
+
return s;
}
@@ -248,7 +268,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
return false;
}
- bool transp = (comp == BMP_BITFIELDS) && alpha_mask;
+ bool transp = comp == BMP_BITFIELDS || (comp == BMP_RGB && nbits == 32 && alpha_mask == 0xff000000);
+ transp = transp && alpha_mask;
+
int ncols = 0;
int depth = 0;
QImage::Format format;
@@ -320,6 +342,12 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
green_shift = 8;
red_shift = 16;
blue_scale = green_scale = red_scale = 1;
+ if (transp) {
+ alpha_shift = calc_shift(alpha_mask);
+ if (((alpha_mask >> alpha_shift) + 1) == 0)
+ return false;
+ alpha_scale = 256 / ((alpha_mask >> alpha_shift) + 1);
+ }
} else if (comp == BMP_RGB && nbits == 16) {
blue_mask = 0x001f;
green_mask = 0x03e0;
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 95c9a890ef..3321845411 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -114,16 +114,15 @@ static inline QByteArray msgConversionError(const char *func, const char *format
return msg;
}
-static inline QImage readDib(QByteArray data)
+static inline bool readDib(QBuffer &buffer, QImage &img)
{
- QBuffer buffer(&data);
- buffer.open(QIODevice::ReadOnly);
QImageReader reader(&buffer, dibFormatC);
if (!reader.canRead()) {
- qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
- return QImage();
+ qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
+ return false;
}
- return reader.read();
+ img = reader.read();
+ return true;
}
static QByteArray writeDib(const QImage &img)
@@ -213,94 +212,6 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
return true;
}
-static int calc_shift(int mask)
-{
- int result = 0;
- while (!(mask & 1)) {
- result++;
- mask >>= 1;
- }
- return result;
-}
-
-//Supports only 32 bit DIBV5
-static bool qt_read_dibv5(QDataStream &s, QImage &image)
-{
- BMP_BITMAPV5HEADER bi;
- QIODevice* d = s.device();
- if (d->atEnd())
- return false;
-
- d->read(reinterpret_cast<char *>(&bi), sizeof(bi)); // read BITMAPV5HEADER header
- if (s.status() != QDataStream::Ok)
- return false;
-
- const int nbits = bi.bV5BitCount;
- if (nbits != 32 || bi.bV5Planes != 1 || bi.bV5Compression != BMP_BITFIELDS)
- return false; //Unsupported DIBV5 format
-
- const int w = bi.bV5Width;
- int h = bi.bV5Height;
- const int red_mask = int(bi.bV5RedMask);
- const int green_mask = int(bi.bV5GreenMask);
- const int blue_mask = int(bi.bV5BlueMask);
- const int alpha_mask = int(bi.bV5AlphaMask);
-
- const QImage::Format format = QImage::Format_ARGB32;
-
- if (bi.bV5Height < 0)
- h = -h; // support images with negative height
- if (image.size() != QSize(w, h) || image.format() != format) {
- image = QImage(w, h, format);
- if (image.isNull()) // could not create image
- return false;
- }
- image.setDotsPerMeterX(bi.bV5XPelsPerMeter);
- image.setDotsPerMeterY(bi.bV5YPelsPerMeter);
-
- const int red_shift = calc_shift(red_mask);
- const int green_shift = calc_shift(green_mask);
- const int blue_shift = calc_shift(blue_mask);
- const int alpha_shift = alpha_mask ? calc_shift(alpha_mask) : 0u;
-
- const qsizetype bpl = image.bytesPerLine();
- uchar *data = image.bits();
-
- auto *buf24 = new uchar[bpl];
- const qsizetype bpl24 = ((qsizetype(w) * nbits + 31) / 32) * 4;
-
- while (--h >= 0) {
- QRgb *p = reinterpret_cast<QRgb *>(data + h * bpl);
- QRgb *end = p + w;
- if (d->read(reinterpret_cast<char *>(buf24), bpl24) != bpl24)
- break;
- const uchar *b = buf24;
- while (p < end) {
- const int c = *b | (*(b + 1)) << 8 | (*(b + 2)) << 16 | (*(b + 3)) << 24;
- *p++ = qRgba(((c & red_mask) >> red_shift) ,
- ((c & green_mask) >> green_shift),
- ((c & blue_mask) >> blue_shift),
- ((c & alpha_mask) >> alpha_shift));
- b += 4;
- }
- }
- delete[] buf24;
-
- if (bi.bV5Height < 0) {
- // Flip the image
- auto *buf = new uchar[bpl];
- h = -bi.bV5Height;
- for (int y = 0; y < h/2; ++y) {
- memcpy(buf, data + y * bpl, size_t(bpl));
- memcpy(data + y*bpl, data + (h - y -1) * bpl, size_t(bpl));
- memcpy(data + (h - y -1 ) * bpl, buf, size_t(bpl));
- }
- delete [] buf;
- }
-
- return true;
-}
-
// helpers for using global memory
static int getCf(const FORMATETC &formatetc)
@@ -1018,7 +929,6 @@ 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;
};
@@ -1100,44 +1010,20 @@ 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 a format which has more data
- //DIBV5, use only if its is not synthesized
- if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) {
+ //Try to convert from DIBV5 as it is the most
+ //widespread format that support transparency
+ if (canGetData(CF_DIBV5, pDataObj)) {
QImage img;
QByteArray data = getData(CF_DIBV5, pDataObj);
- QDataStream s(&data, QIODevice::ReadOnly);
- s.setByteOrder(QDataStream::LittleEndian);
- if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5
+ QBuffer buffer(&data);
+ if (readDib(buffer, img))
return img;
- }
}
//PNG, MS Office place this (undocumented)
if (canGetData(CF_PNG, pDataObj)) {
@@ -1149,8 +1035,10 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
}
//Fallback to DIB
if (canGetData(CF_DIB, pDataObj)) {
- const QImage img = readDib(getData(CF_DIB, pDataObj));
- if (!img.isNull())
+ QImage img;
+ QByteArray data = getData(CF_DIBV5, pDataObj);
+ QBuffer buffer(&data);
+ if (readDib(buffer, img))
return img;
}
// Failed