summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gui/image/qbmphandler.cpp60
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp12
2 files changed, 50 insertions, 22 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index 6d265ded67..639c1dc6a7 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -104,6 +104,7 @@ const int BMP_RGB = 0; // no compression
const int BMP_RLE8 = 1; // run-length encoded, 8 bits
const int BMP_RLE4 = 2; // run-length encoded, 4 bits
const int BMP_BITFIELDS = 3; // RGB values encoded in data as bit-fields
+const int BMP_ALPHABITFIELDS = 4; // RGBA values encoded in data as bit-fields
static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi)
@@ -216,13 +217,13 @@ static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
return true;
}
-static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset, qint64 startpos, QImage &image)
+static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 datapos, qint64 startpos, QImage &image)
{
QIODevice* d = s.device();
if (d->atEnd()) // end of stream/file
return false;
#if 0
- qDebug("offset...........%lld", offset);
+ qDebug("offset...........%lld", datapos);
qDebug("startpos.........%lld", startpos);
qDebug("biSize...........%d", bi.biSize);
qDebug("biWidth..........%d", bi.biWidth);
@@ -250,25 +251,28 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
int green_scale = 0;
int blue_scale = 0;
int alpha_scale = 0;
+ bool bitfields = comp == BMP_BITFIELDS || comp == BMP_ALPHABITFIELDS;
if (!d->isSequential())
- d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap or masks
+ d->seek(startpos + bi.biSize); // goto start of colormap or masks
if (bi.biSize >= BMP_WIN4) {
red_mask = bi.biRedMask;
green_mask = bi.biGreenMask;
blue_mask = bi.biBlueMask;
alpha_mask = bi.biAlphaMask;
- } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
+ } else if (bitfields && (nbits == 16 || nbits == 32)) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
return false;
if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
return false;
+ if (comp == BMP_ALPHABITFIELDS && d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask))
+ return false;
}
- bool transp = comp == BMP_BITFIELDS || (comp == BMP_RGB && nbits == 32 && alpha_mask == 0xff000000);
+ bool transp = bitfields || (comp == BMP_RGB && nbits == 32 && alpha_mask == 0xff000000);
transp = transp && alpha_mask;
int ncols = 0;
@@ -317,7 +321,7 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
if (d->atEnd()) // truncated file
return false;
}
- } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
+ } else if (bitfields && (nbits == 16 || nbits == 32)) {
red_shift = calc_shift(red_mask);
if (((red_mask >> red_shift) + 1) == 0)
return false;
@@ -370,10 +374,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
qDebug("Amask: %08x Ashift: %08x Ascale:%08x", alpha_mask, alpha_shift, alpha_scale);
#endif
- // offset can be bogus, be careful
- if (offset>=0 && startpos + offset > d->pos()) {
+ if (datapos >= 0 && datapos > d->pos()) {
if (!d->isSequential())
- d->seek(startpos + offset); // start of image data
+ d->seek(datapos); // start of image data
}
int bpl = image.bytesPerLine();
@@ -591,7 +594,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
return true;
}
-// this is also used in qmime_win.cpp
bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int nbits)
{
QIODevice* d = s.device();
@@ -678,15 +680,6 @@ bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int
return true;
}
-// this is also used in qmime_win.cpp
-bool qt_read_dib(QDataStream &s, QImage &image)
-{
- BMP_INFOHDR bi;
- if (!read_dib_infoheader(s, bi))
- return false;
- return read_dib_body(s, bi, -1, -BMP_FILEHDR_SIZE, image);
-}
-
QBmpHandler::QBmpHandler(InternalFormat fmt) :
m_format(fmt), state(Ready)
{
@@ -769,9 +762,32 @@ bool QBmpHandler::read(QImage *image)
s.setByteOrder(QDataStream::LittleEndian);
// read image
+ qint64 datapos = startpos;
+ if (m_format == BmpFormat) {
+ datapos += fileHeader.bfOffBits;
+ } else {
+ // QTBUG-100351: We have no file header when reading dib format so we have to depend on the size of the
+ // buffer and the biSizeImage value to find where the pixel data starts since there's sometimes optional
+ // color mask values after biSize, like for example when pasting from the windows snipping tool.
+ if (infoHeader.biSizeImage > 0 && infoHeader.biSizeImage < d->size()) {
+ datapos = d->size() - infoHeader.biSizeImage;
+ } else {
+ // And sometimes biSizeImage is not filled in like when pasting from Microsoft Edge, so then we just
+ // have to assume the optional color mask values are there.
+ datapos += infoHeader.biSize;
+
+ if (infoHeader.biBitCount == 16 || infoHeader.biBitCount == 32) {
+ if (infoHeader.biCompression == BMP_BITFIELDS) {
+ datapos += 12;
+ } else if (infoHeader.biCompression == BMP_ALPHABITFIELDS) {
+ datapos += 16;
+ }
+ }
+ }
+ }
const bool readSuccess = m_format == BmpFormat ?
- read_dib_body(s, infoHeader, fileHeader.bfOffBits, startpos, *image) :
- read_dib_body(s, infoHeader, -1, startpos - BMP_FILEHDR_SIZE, *image);
+ read_dib_body(s, infoHeader, datapos, startpos + BMP_FILEHDR_SIZE, *image) :
+ read_dib_body(s, infoHeader, datapos, startpos, *image);
if (!readSuccess)
return false;
@@ -875,7 +891,7 @@ QVariant QBmpHandler::option(ImageOption option) const
case 32:
case 24:
case 16:
- if (infoHeader.biCompression == BMP_BITFIELDS && infoHeader.biSize >= BMP_WIN4 && infoHeader.biAlphaMask)
+ if ((infoHeader.biCompression == BMP_BITFIELDS || infoHeader.biCompression == BMP_ALPHABITFIELDS) && infoHeader.biSize >= BMP_WIN4 && infoHeader.biAlphaMask)
format = QImage::Format_ARGB32;
else
format = QImage::Format_RGB32;
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 555c3f11b7..a2e35687d7 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -177,6 +177,18 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
if (s.status() != QDataStream::Ok)
return false;
+ d->write(reinterpret_cast<const char *>(&bi.bV5RedMask), sizeof(bi.bV5RedMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ d->write(reinterpret_cast<const char *>(&bi.bV5GreenMask), sizeof(bi.bV5GreenMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ d->write(reinterpret_cast<const char *>(&bi.bV5BlueMask), sizeof(bi.bV5BlueMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
if (image.format() != QImage::Format_ARGB32)
image = image.convertToFormat(QImage::Format_ARGB32);