diff options
author | Eirik Aavitsland <eirik.aavitsland@qt.io> | 2017-02-23 09:39:07 +0100 |
---|---|---|
committer | Eirik Aavitsland <eirik.aavitsland@qt.io> | 2017-03-02 07:59:50 +0000 |
commit | c4c8886a864d1058c3441a96556aa8b124b4f17f (patch) | |
tree | 8d1ba0d2c4bd8c8169325afc681cfc99a271bed0 /src/gui | |
parent | 593a707ba35c22c0a1061dce745deceed8837f80 (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')
-rw-r--r-- | src/gui/image/qppmhandler.cpp | 59 |
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; } } |