summaryrefslogtreecommitdiffstats
path: root/src/gui/image
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2017-02-23 09:39:07 +0100
committerEirik Aavitsland <eirik.aavitsland@qt.io>2017-03-02 07:59:50 +0000
commitc4c8886a864d1058c3441a96556aa8b124b4f17f (patch)
tree8d1ba0d2c4bd8c8169325afc681cfc99a271bed0 /src/gui/image
parent593a707ba35c22c0a1061dce745deceed8837f80 (diff)
ppm/pgm image formats: fix reading 16bit and limited range
The color values of ppm and pgm images can be either 8 or 16 bits. They can also be scaled to a smaller max value, and they can be expressed either binary or ascii. For some of these permutations, Qt's image handler lacked implementation or would decode the wrong color value. This commit fixes that. Task-number: QTBUG-18262 Task-number: QTBUG-35990 Change-Id: I7cf11c2366244f3a9b31c1a565a81e2658bc6a51 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/gui/image')
-rw-r--r--src/gui/image/qppmhandler.cpp59
1 files changed, 45 insertions, 14 deletions
diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp
index 42d3684aea..e9f5a905f0 100644
--- a/src/gui/image/qppmhandler.cpp
+++ b/src/gui/image/qppmhandler.cpp
@@ -45,6 +45,7 @@
#include <qvariant.h>
#include <qvector.h>
#include <ctype.h>
+#include <qrgba64.h>
QT_BEGIN_NAMESPACE
@@ -120,6 +121,11 @@ static bool read_pbm_header(QIODevice *device, char& type, int& w, int& h, int&
return true;
}
+static inline QRgb scale_pbm_color(quint16 mx, quint16 rv, quint16 gv, quint16 bv)
+{
+ return QRgba64::fromRgba64((rv * 0xffff) / mx, (gv * 0xffff) / mx, (bv * 0xffff) / mx, 0xffff).toArgb32();
+}
+
static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, QImage *outImage)
{
int nbits, y;
@@ -148,9 +154,6 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
}
raw = type >= '4';
- int maxc = mcc;
- if (maxc > 255)
- maxc = 255;
if (outImage->size() != QSize(w, h) || outImage->format() != format) {
*outImage = QImage(w, h, format);
if (outImage->isNull())
@@ -175,22 +178,50 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
b = buf24;
while (p < end) {
if (mcc < 256) {
- *p++ = qRgb(b[0],b[1],b[2]);
+ if (mcc == 255)
+ *p++ = qRgb(b[0],b[1],b[2]);
+ else
+ *p++ = scale_pbm_color(mcc, b[0], b[1], b[2]);
b += 3;
} else {
- *p++ = qRgb(((int(b[0]) * 256 + int(b[1]) + 1) * 256) / (mcc + 1) - 1,
- ((int(b[2]) * 256 + int(b[3]) + 1) * 256) / (mcc + 1) - 1,
- ((int(b[4]) * 256 + int(b[5]) + 1) * 256) / (mcc + 1) - 1);
+ quint16 rv = b[0] << 8 | b[1];
+ quint16 gv = b[2] << 8 | b[3];
+ quint16 bv = b[4] << 8 | b[5];
+ if (mcc == 0xffff)
+ *p++ = QRgba64::fromRgba64(rv, gv, bv, 0xffff).toArgb32();
+ else
+ *p++ = scale_pbm_color(mcc, rv, gv, bv);
b += 6;
}
}
}
delete[] buf24;
+ } else if (nbits == 8 && mcc > 255) { // type 5 16bit
+ pbm_bpl = 2*w;
+ uchar *buf16 = new uchar[pbm_bpl];
+ for (y=0; y<h; y++) {
+ if (device->read((char *)buf16, pbm_bpl) != pbm_bpl) {
+ delete[] buf16;
+ return false;
+ }
+ uchar *p = outImage->scanLine(y);
+ uchar *end = p + w;
+ uchar *b = buf16;
+ while (p < end) {
+ *p++ = (b[0] << 8 | b[1]) * 255 / mcc;
+ b += 2;
+ }
+ }
+ delete[] buf16;
} else { // type 4,5
for (y=0; y<h; y++) {
- if (device->read((char *)outImage->scanLine(y), pbm_bpl)
- != pbm_bpl)
+ uchar *p = outImage->scanLine(y);
+ if (device->read((char *)p, pbm_bpl) != pbm_bpl)
return false;
+ if (nbits == 8 && mcc < 255) {
+ for (int i = 0; i < pbm_bpl; i++)
+ p[i] = (p[i] * 255) / mcc;
+ }
}
}
} else { // read ascii data
@@ -227,7 +258,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
} else { // 32 bits
n /= 4;
int r, g, b;
- if (mcc == maxc) {
+ if (mcc == 255) {
while (n--) {
r = read_pbm_int(device);
g = read_pbm_int(device);
@@ -237,10 +268,10 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
}
} else {
while (n--) {
- r = read_pbm_int(device) * maxc / mcc;
- g = read_pbm_int(device) * maxc / mcc;
- b = read_pbm_int(device) * maxc / mcc;
- *((QRgb*)p) = qRgb(r, g, b);
+ r = read_pbm_int(device);
+ g = read_pbm_int(device);
+ b = read_pbm_int(device);
+ *((QRgb*)p) = scale_pbm_color(mcc, r, g, b);
p += 4;
}
}