diff options
-rw-r--r-- | src/gui/image/qbmphandler.cpp | 60 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowsmime.cpp | 12 |
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); |