summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qbmphandler.cpp
diff options
context:
space:
mode:
authoraavit <eirik.aavitsland@digia.com>2013-12-10 14:39:09 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-08 09:40:50 +0100
commit6f1b82fccdaf202856dcc6510c16b0531680fe23 (patch)
tree8c64215e7e358c2a84c5a4343b4f6932ecb99b36 /src/gui/image/qbmphandler.cpp
parentcd44f363ffd71f402265a03e7168f9774033a664 (diff)
Fixes: 32 bit and alpha bmp format image reading
The bmp handler would ignore the high byte of a 32bit bmp. It would also ignore any alpha channel. The actual change is really simple; it just adds the alpha_* members and the reading of the 4th byte in 32bit depth. However, detection of alpha channel required switching the order of two independent blocks of code, hence the size of this patch. [ChangeLog][QtGui] Support reading bmp images with alpha channel Task-number: QTBUG-35220 Change-Id: Ib133c3644c03c5cfc728f5fa2c837219804e69ae Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/gui/image/qbmphandler.cpp')
-rw-r--r--src/gui/image/qbmphandler.cpp107
1 files changed, 61 insertions, 46 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index c03d9b8e5d..bb79a139b3 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -210,54 +210,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
uint red_mask = 0;
uint green_mask = 0;
uint blue_mask = 0;
+ uint alpha_mask = 0;
int red_shift = 0;
int green_shift = 0;
int blue_shift = 0;
+ int alpha_shift = 0;
int red_scale = 0;
int green_scale = 0;
int blue_scale = 0;
-
- int ncols = 0;
- int depth = 0;
- QImage::Format format;
- switch (nbits) {
- case 32:
- case 24:
- case 16:
- depth = 32;
- format = QImage::Format_RGB32;
- break;
- case 8:
- case 4:
- depth = 8;
- format = QImage::Format_Indexed8;
- break;
- default:
- depth = 1;
- format = QImage::Format_Mono;
- }
-
- if (bi.biHeight < 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;
- }
-
- if (depth != 32) {
- ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
- if (ncols > 256) // sanity check - don't run out of mem if color table is broken
- return false;
- image.setColorCount(ncols);
- }
-
- image.setDotsPerMeterX(bi.biXPelsPerMeter);
- image.setDotsPerMeterY(bi.biYPelsPerMeter);
-
- if (!d->isSequential())
- d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
+ int alpha_scale = 0;
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
@@ -269,7 +230,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
// Read BMP v4+ header
if (bi.biSize >= BMP_WIN4) {
- int alpha_mask = 0;
int CSType = 0;
int gamma_red = 0;
int gamma_green = 0;
@@ -307,6 +267,49 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
}
}
+ bool transp = (comp == BMP_BITFIELDS) && alpha_mask;
+ int ncols = 0;
+ int depth = 0;
+ QImage::Format format;
+ switch (nbits) {
+ case 32:
+ case 24:
+ case 16:
+ depth = 32;
+ format = transp ? QImage::Format_ARGB32 : QImage::Format_RGB32;
+ break;
+ case 8:
+ case 4:
+ depth = 8;
+ format = QImage::Format_Indexed8;
+ break;
+ default:
+ depth = 1;
+ format = QImage::Format_Mono;
+ }
+
+ if (bi.biHeight < 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;
+ }
+
+ if (depth != 32) {
+ ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
+ if (ncols > 256) // sanity check - don't run out of mem if color table is broken
+ return false;
+ image.setColorCount(ncols);
+ }
+
+ image.setDotsPerMeterX(bi.biXPelsPerMeter);
+ image.setDotsPerMeterY(bi.biYPelsPerMeter);
+
+ if (!d->isSequential())
+ d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
+
if (ncols > 0) { // read color table
uchar rgb[4];
int rgb_len = t == BMP_OLD ? 3 : 4;
@@ -324,6 +327,8 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
green_scale = 256 / ((green_mask >> green_shift) + 1);
blue_shift = calc_shift(blue_mask);
blue_scale = 256 / ((blue_mask >> blue_shift) + 1);
+ alpha_shift = calc_shift(alpha_mask);
+ alpha_scale = 256 / ((alpha_mask >> alpha_shift) + 1);
} else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) {
blue_mask = 0x000000ff;
green_mask = 0x0000ff00;
@@ -344,6 +349,13 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
blue_scale = 8;
}
+#if 0
+ qDebug("Rmask: %08x Rshift: %08x Rscale:%08x", red_mask, red_shift, red_scale);
+ qDebug("Gmask: %08x Gshift: %08x Gscale:%08x", green_mask, green_shift, green_scale);
+ qDebug("Bmask: %08x Bshift: %08x Bscale:%08x", blue_mask, blue_shift, blue_scale);
+ 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 (!d->isSequential())
@@ -535,11 +547,14 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
b = buf24;
while (p < end) {
c = *(uchar*)b | (*(uchar*)(b+1)<<8);
- if (nbits != 16)
+ if (nbits > 16)
c |= *(uchar*)(b+2)<<16;
- *p++ = qRgb(((c & red_mask) >> red_shift) * red_scale,
+ if (nbits > 24)
+ c |= *(uchar*)(b+3)<<24;
+ *p++ = qRgba(((c & red_mask) >> red_shift) * red_scale,
((c & green_mask) >> green_shift) * green_scale,
- ((c & blue_mask) >> blue_shift) * blue_scale);
+ ((c & blue_mask) >> blue_shift) * blue_scale,
+ transp ? ((c & alpha_mask) >> alpha_shift) * alpha_scale : 0xff);
b += nbits/8;
}
}