From 845c69b2e780e1646f68ee99beda10768a1971e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 6 Nov 2009 16:09:16 +0100 Subject: Fixed loading of 8-bit grayscale TIFF files. The PHOTOMETRIC_MINISBLACK and PHOTOMETRIC_MINISWHITE settings also apply to 8-bit grayscale, so we need to check the bit depth of the image as well. For convenience we also try to write the images using PHOTOMETRIC_MINISBLACK and PHOTOMETRIC_MINISWHITE as opposed to PHOTOMETRIC_PALETTE when we detect that the color table is grayscale. Task-number: QTBUG-5459 Reviewed-by: Benjamin Poulain --- src/plugins/imageformats/tiff/qtiffhandler.cpp | 155 ++++++++++++++--------- tests/auto/qimagereader/images/grayscale-ref.tif | Bin 0 -> 256182 bytes tests/auto/qimagereader/images/grayscale.tif | Bin 0 -> 64162 bytes tests/auto/qimagereader/tst_qimagereader.cpp | 9 ++ tests/auto/qimagewriter/tst_qimagewriter.cpp | 17 ++- 5 files changed, 118 insertions(+), 63 deletions(-) create mode 100644 tests/auto/qimagereader/images/grayscale-ref.tif create mode 100644 tests/auto/qimagereader/images/grayscale.tif diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 3669be7..9538745 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -192,7 +192,14 @@ bool QTiffHandler::read(QImage *image) return false; } - if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) { + uint16 bitPerSample; + if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { + TIFFClose(tiff); + return false; + } + + bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE; + if (grayscale && bitPerSample == 1) { if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono) *image = QImage(width, height, QImage::Format_Mono); QVector colortable(2); @@ -208,42 +215,43 @@ bool QTiffHandler::read(QImage *image) if (!image->isNull()) { for (uint32 y=0; yscanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; + TIFFClose(tiff); + return false; } } } } else { - uint16 bitPerSample; - if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { - TIFFClose(tiff); - return false; - } - if (photometric == PHOTOMETRIC_PALETTE && bitPerSample == 8) { + if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) { if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8) *image = QImage(width, height, QImage::Format_Indexed8); if (!image->isNull()) { - // create the color table const uint16 tableSize = 256; - uint16 *redTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { - TIFFClose(tiff); - return false; - } - QVector qtColorTable(tableSize); - for (int i = 0; i(qMalloc(tableSize * sizeof(uint16))); + uint16 *greenTable = static_cast(qMalloc(tableSize * sizeof(uint16))); + uint16 *blueTable = static_cast(qMalloc(tableSize * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + TIFFClose(tiff); + return false; + } + for (int i = 0; isetColorTable(qtColorTable); @@ -371,6 +379,20 @@ bool QTiffHandler::read(QImage *image) return true; } +static bool checkGrayscale(const QVector &colorTable) +{ + if (colorTable.size() != 256) + return false; + + const bool increasing = (colorTable.at(0) == 0xff000000); + for (int i = 0; i < 256; ++i) { + if (increasing && colorTable.at(i) != qRgb(i, i, i) + || !increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i)) + return false; + } + return true; +} + bool QTiffHandler::write(const QImage &image) { if (!device()->isWritable()) @@ -425,7 +447,8 @@ bool QTiffHandler::write(const QImage &image) if (image.colorTable().at(0) == 0xffffffff) photometric = PHOTOMETRIC_MINISWHITE; if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)) { + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) { TIFFClose(tiff); return false; } @@ -450,43 +473,55 @@ bool QTiffHandler::write(const QImage &image) } TIFFClose(tiff); } else if (format == QImage::Format_Indexed8) { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - //// write the color table - // allocate the color tables - uint16 *redTable = static_cast(qMalloc(256 * sizeof(uint16))); - uint16 *greenTable = static_cast(qMalloc(256 * sizeof(uint16))); - uint16 *blueTable = static_cast(qMalloc(256 * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - - // set the color table const QVector colorTable = image.colorTable(); + bool isGrayscale = checkGrayscale(colorTable); + if (isGrayscale) { + uint16 photometric = PHOTOMETRIC_MINISBLACK; + if (image.colorTable().at(0) == 0xffffffff) + photometric = PHOTOMETRIC_MINISWHITE; + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + } else { + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + //// write the color table + // allocate the color tables + uint16 *redTable = static_cast(qMalloc(256 * sizeof(uint16))); + uint16 *greenTable = static_cast(qMalloc(256 * sizeof(uint16))); + uint16 *blueTable = static_cast(qMalloc(256 * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } - const int tableSize = colorTable.size(); - Q_ASSERT(tableSize <= 256); - for (int i = 0; i("format"); QTest::addColumn("expectedFormat"); - QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono; - QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8; - QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32; + QTest::addColumn("grayscale"); + QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false; + QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false; + QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32 << false; + QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true; } void tst_QImageWriter::readWriteNonDestructive() { QFETCH(QImage::Format, format); QFETCH(QImage::Format, expectedFormat); + QFETCH(bool, grayscale); QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format); + + if (grayscale) { + QVector colors; + for (int i = 0; i < 256; ++i) + colors << qRgb(i, i, i); + image.setColorTable(colors); + } + QVERIFY(image.save(prefix + "gen-readWriteNonDestructive.tiff")); QImage image2 = QImage(prefix + "gen-readWriteNonDestructive.tiff"); -- cgit v0.12