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 #include #include +#include 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; yread((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; yread((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; } } diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index bd02dc6255..18649b3de5 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -133,6 +133,9 @@ private slots: void gifImageCount(); void gifLoopCount(); + void ppmMaxval_data(); + void ppmMaxval(); + void readCorruptImage_data(); void readCorruptImage(); void readCorruptBmp(); @@ -956,6 +959,79 @@ void tst_QImageReader::gifLoopCount() } } +void tst_QImageReader::ppmMaxval_data() +{ + QTest::addColumn("hasColor"); + QTest::addColumn("bytes"); + + QTest::newRow("PGM plain 8bit full") << false << QByteArray("P2 3 1 255 255 0 127\n"); + QTest::newRow("PGM plain 8bit lim.") << false << QByteArray("P2 3 1 50 50 0 25\n"); + QTest::newRow("PGM plain 16bit full") << false << QByteArray("P2 3 1 65535 65535 0 32767\n"); + QTest::newRow("PGM plain 16bit lim.") << false << QByteArray("P2 3 1 5000 5000 0 2500\n"); + QTest::newRow("PGM raw 8bit full") << false << QByteArray("P5 3 1 255 \xff\x00\x7f", 13 + 3); + QTest::newRow("PGM raw 8bit lim.") << false << QByteArray("P5 3 1 50 \x32\x00\x19", 13 + 3); + QTest::newRow("PGM raw 16bit full") << false << QByteArray("P5 3 1 65535 \xff\xff\x00\x00\x7f\xff", 13 + 3 * 2); + QTest::newRow("PGM raw 16bit lim.") << false << QByteArray("P5 3 1 5000 \x13\x88\x00\x00\x09\xc4", 13 + 3 * 2); + + QTest::newRow("PPM plain 8bit full") << true << QByteArray("P3 3 2 255 " + "255 255 255 0 0 0 127 127 127 " + "255 0 0 0 255 0 0 0 255\n"); + + QTest::newRow("PPM plain 8bit lim.") << true << QByteArray("P3 3 2 50 " + " 50 50 50 0 0 0 25 25 25 " + " 50 0 0 0 50 0 0 0 50\n"); + + QTest::newRow("PPM plain 16bit full") << true << QByteArray("P3 3 2 65535 " + "65535 65535 65535 0 0 0 32767 32767 32767 " + "65535 0 0 0 65535 0 0 0 65535\n"); + + QTest::newRow("PPM plain 16bit lim.") << true << QByteArray("P3 3 2 5000 " + " 5000 5000 5000 0 0 0 2500 2500 2500 " + " 5000 0 0 0 5000 0 0 0 5000\n"); + + QTest::newRow("PPM raw 8bit full") << true << QByteArray("P6 3 2 255 " + "\xff\xff\xff\x00\x00\x00\x7f\x7f\x7f" + "\xff\x00\x00\x00\xff\x00\x00\x00\xff", 13 + 6 * 3); + + QTest::newRow("PPM raw 8bit lim.") << true << QByteArray("P6 3 2 50 " + "\x32\x32\x32\x00\x00\x00\x19\x19\x19" + "\x32\x00\x00\x00\x32\x00\x00\x00\x32", 13 + 6 * 3); + + QTest::newRow("PPM raw 16bit full") << true << QByteArray("P6 3 2 65535 " + "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x7f\xff\x7f\xff\x7f\xff" + "\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff", 13 + 6 * 3 * 2); + + QTest::newRow("PPM raw 16bit lim.") << true << QByteArray("P6 3 2 5000 " + "\x13\x88\x13\x88\x13\x88\x00\x00\x00\x00\x00\x00\x09\xc4\x09\xc4\x09\xc4" + "\x13\x88\x00\x00\x00\x00\x00\x00\x13\x88\x00\x00\x00\x00\x00\x00\x13\x88", 13 + 6 * 3 * 2); +} + +void tst_QImageReader::ppmMaxval() +{ + SKIP_IF_UNSUPPORTED("ppm"); + + QFETCH(bool, hasColor); + QFETCH(QByteArray, bytes); + + QImage img; + img.loadFromData(bytes); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), 3); + QCOMPARE(img.height(), hasColor ? 2 : 1); + + QCOMPARE(img.pixel(0,0), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(img.pixel(1,0), qRgb(0, 0, 0)); + QRgb gray = img.pixel(2,0); + QVERIFY(qIsGray(gray)); + QVERIFY(qRed(gray) > 0x70 && qRed(gray) < 0x90 ); + + if (hasColor) { + QCOMPARE(img.pixel(0,1), qRgb(0xff, 0, 0)); + QCOMPARE(img.pixel(1,1), qRgb(0, 0xff, 0)); + QCOMPARE(img.pixel(2,1), qRgb(0, 0, 0xff)); + } +} + class Server : public QObject { Q_OBJECT