diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index e34ea25c70740c46359a1193f44ffadb6647cecb..81ad7e92b9bf57425310e61c1d72a138e118d40b 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -329,125 +329,106 @@ bool QTiffHandler::read(QImage *image) if (image->size() != d->size || image->format() != format) *image = QImage(d->size, format); + if (image->isNull()) { + d->close(); + return false; + } + TIFF *const tiff = d->tiff; const uint32 width = d->size.width(); const uint32 height = d->size.height(); - if (format == QImage::Format_Mono) { - QVector<QRgb> colortable(2); - if (d->photometric == PHOTOMETRIC_MINISBLACK) { - colortable[0] = 0xff000000; - colortable[1] = 0xffffffff; - } else { - colortable[0] = 0xffffffff; - colortable[1] = 0xff000000; - } - image->setColorTable(colortable); - - if (!image->isNull()) { - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { + if (format == QImage::Format_Mono || format == QImage::Format_Indexed8 || format == QImage::Format_Grayscale8) { + if (format == QImage::Format_Mono) { + QVector<QRgb> colortable(2); + if (d->photometric == PHOTOMETRIC_MINISBLACK) { + colortable[0] = 0xff000000; + colortable[1] = 0xffffffff; + } else { + colortable[0] = 0xffffffff; + colortable[1] = 0xff000000; + } + image->setColorTable(colortable); + } else if (format == QImage::Format_Indexed8) { + const uint16 tableSize = 256; + QVector<QRgb> qtColorTable(tableSize); + if (d->grayscale) { + for (int i = 0; i<tableSize; ++i) { + const int c = (d->photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i); + qtColorTable[i] = qRgb(c, c, c); + } + } else { + // create the color table + uint16 *redTable = 0; + uint16 *greenTable = 0; + uint16 *blueTable = 0; + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { d->close(); return false; } - } - } - } else { - if (format == QImage::Format_Indexed8) { - if (!image->isNull()) { - const uint16 tableSize = 256; - QVector<QRgb> qtColorTable(tableSize); - if (d->grayscale) { - for (int i = 0; i<tableSize; ++i) { - const int c = (d->photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i); - qtColorTable[i] = qRgb(c, c, c); - } - } else { - // create the color table - uint16 *redTable = 0; - uint16 *greenTable = 0; - uint16 *blueTable = 0; - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { - d->close(); - return false; - } - if (!redTable || !greenTable || !blueTable) { - d->close(); - return false; - } - - for (int i = 0; i<tableSize ;++i) { - const int red = redTable[i] / 257; - const int green = greenTable[i] / 257; - const int blue = blueTable[i] / 257; - qtColorTable[i] = qRgb(red, green, blue); - } + if (!redTable || !greenTable || !blueTable) { + d->close(); + return false; } - image->setColorTable(qtColorTable); - - if (TIFFIsTiled(tiff)) { - quint32 tileWidth, tileLength; - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength); - uchar *buf = (uchar *)_TIFFmalloc(TIFFTileSize(tiff)); - if (!tileWidth || !tileLength || !buf) { - _TIFFfree(buf); - d->close(); - return false; - } - for (quint32 y = 0; y < height; y += tileLength) { - for (quint32 x = 0; x < width; x += tileWidth) { - if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) { - _TIFFfree(buf); - d->close(); - return false; - } - quint32 linesToCopy = qMin(tileLength, height - y); - quint32 widthToCopy = qMin(tileWidth, width - x); - for (quint32 i = 0; i < linesToCopy; i++) - ::memcpy(image->scanLine(y + i) + x, buf + (i * tileWidth), widthToCopy); - } - } - _TIFFfree(buf); - } else { - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - d->close(); - return false; - } - } + for (int i = 0; i<tableSize ;++i) { + const int red = redTable[i] / 257; + const int green = greenTable[i] / 257; + const int blue = blueTable[i] / 257; + qtColorTable[i] = qRgb(red, green, blue); } + } + image->setColorTable(qtColorTable); + // free redTable, greenTable and greenTable done by libtiff + } - // free redTable, greenTable and greenTable done by libtiff + if (TIFFIsTiled(tiff)) { + quint32 tileWidth, tileLength; + TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth); + TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength); + uchar *buf = (uchar *)_TIFFmalloc(TIFFTileSize(tiff)); + if (!tileWidth || !tileLength || !buf) { + _TIFFfree(buf); + d->close(); + return false; } - } else if (format == QImage::Format_Grayscale8) { - if (!image->isNull()) { - for (uint32 y = 0; y < height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { + quint32 byteWidth = (format == QImage::Format_Mono) ? (width + 7)/8 : width; + quint32 byteTileWidth = (format == QImage::Format_Mono) ? tileWidth/8 : tileWidth; + for (quint32 y = 0; y < height; y += tileLength) { + for (quint32 x = 0; x < width; x += tileWidth) { + if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) { + _TIFFfree(buf); d->close(); return false; } + quint32 linesToCopy = qMin(tileLength, height - y); + quint32 byteOffset = (format == QImage::Format_Mono) ? x/8 : x; + quint32 widthToCopy = qMin(byteTileWidth, byteWidth - byteOffset); + for (quint32 i = 0; i < linesToCopy; i++) { + ::memcpy(image->scanLine(y + i) + byteOffset, buf + (i * byteTileWidth), widthToCopy); + } } } + _TIFFfree(buf); } else { - if (!image->isNull()) { - const int stopOnError = 1; - if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) { - for (uint32 y=0; y<height; ++y) - convert32BitOrder(image->scanLine(y), width); - } else { + for (uint32 y=0; y<height; ++y) { + if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { d->close(); return false; } } } + } else { + const int stopOnError = 1; + if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) { + for (uint32 y=0; y<height; ++y) + convert32BitOrder(image->scanLine(y), width); + } else { + d->close(); + return false; + } } - if (image->isNull()) { - d->close(); - return false; - } float resX = 0; float resY = 0; diff --git a/tests/auto/tiff/tst_qtiff.cpp b/tests/auto/tiff/tst_qtiff.cpp index bec2ca28199052e10172042b172c4775af6ef4b5..1a96ab381c04552aa03729784b809aa0d843033f 100644 --- a/tests/auto/tiff/tst_qtiff.cpp +++ b/tests/auto/tiff/tst_qtiff.cpp @@ -139,6 +139,7 @@ void tst_qtiff::readImage_data() QTest::newRow("mono_orientation_7") << QString("mono_orientation_7.tiff") << QSize(64, 64); QTest::newRow("mono_orientation_8") << QString("mono_orientation_8.tiff") << QSize(64, 64); QTest::newRow("original_indexed") << QString("original_indexed.tiff") << QSize(64, 64); + QTest::newRow("original_grayscale") << QString("original_grayscale.tiff") << QSize(64, 64); QTest::newRow("original_mono") << QString("original_mono.tiff") << QSize(64, 64); QTest::newRow("original_rgb") << QString("original_rgb.tiff") << QSize(64, 64); QTest::newRow("rgba_adobedeflate_littleendian") << QString("rgba_adobedeflate_littleendian.tif") << QSize(200, 200); @@ -156,8 +157,14 @@ void tst_qtiff::readImage_data() QTest::newRow("rgb_orientation_7") << QString("rgb_orientation_7.tiff") << QSize(64, 64); QTest::newRow("rgb_orientation_8") << QString("rgb_orientation_8.tiff") << QSize(64, 64); QTest::newRow("teapot") << QString("teapot.tiff") << QSize(256, 256); - QTest::newRow("indexed_nontiled") << QString("indexed_nontiled.tif") << QSize(512, 384); - QTest::newRow("indexed_tiled") << QString("indexed_tiled.tif") << QSize(512, 384); + QTest::newRow("oddsize_grayscale") << QString("oddsize_grayscale.tiff") << QSize(59, 71); + QTest::newRow("oddsize_mono") << QString("oddsize_mono.tiff") << QSize(59, 71); + QTest::newRow("tiled_rgb") << QString("tiled_rgb.tiff") << QSize(64, 64); + QTest::newRow("tiled_indexed") << QString("tiled_indexed.tiff") << QSize(64, 64); + QTest::newRow("tiled_grayscale") << QString("tiled_grayscale.tiff") << QSize(64, 64); + QTest::newRow("tiled_mono") << QString("tiled_mono.tiff") << QSize(64, 64); + QTest::newRow("tiled_oddsize_grayscale") << QString("tiled_oddsize_grayscale.tiff") << QSize(59, 71); + QTest::newRow("tiled_oddsize_mono") << QString("tiled_oddsize_mono.tiff") << QSize(59, 71); } void tst_qtiff::readImage() @@ -566,7 +573,12 @@ void tst_qtiff::tiled_data() { QTest::addColumn<QString>("expectedFile"); QTest::addColumn<QString>("tiledFile"); - QTest::newRow("Indexed") << "indexed_nontiled.tif" << "indexed_tiled.tif"; + QTest::newRow("RGB") << "original_rgb.tiff" << "tiled_rgb.tiff"; + QTest::newRow("Indexed") << "original_indexed.tiff" << "tiled_indexed.tiff"; + QTest::newRow("Grayscale") << "original_grayscale.tiff" << "tiled_grayscale.tiff"; + QTest::newRow("Mono") << "original_mono.tiff" << "tiled_mono.tiff"; + QTest::newRow("Oddsize (Grayscale)") << "oddsize_grayscale.tiff" << "tiled_oddsize_grayscale.tiff"; + QTest::newRow("Oddsize (Mono)") << "oddsize_mono.tiff" << "tiled_oddsize_mono.tiff"; } void tst_qtiff::tiled() @@ -576,6 +588,7 @@ void tst_qtiff::tiled() QImage expectedImage(prefix + expectedFile); QImage tiledImage(prefix + tiledFile); + QVERIFY(!tiledImage.isNull()); QCOMPARE(expectedImage, tiledImage); } diff --git a/tests/shared/images/tiff.qrc b/tests/shared/images/tiff.qrc index 258acf0ba3286707139bcba61ca89e5a08b22916..19675ba656e49951f3d8f2d42a6cc835a9212d24 100644 --- a/tests/shared/images/tiff.qrc +++ b/tests/shared/images/tiff.qrc @@ -41,7 +41,14 @@ <file>tiff/rgb_orientation_8.tiff</file> <file>tiff/teapot.tiff</file> <file>tiff/colorful.bmp</file> - <file>tiff/indexed_tiled.tif</file> - <file>tiff/indexed_nontiled.tif</file> + <file>tiff/tiled_grayscale.tiff</file> + <file>tiff/tiled_oddsize_grayscale.tiff</file> + <file>tiff/oddsize_grayscale.tiff</file> + <file>tiff/original_grayscale.tiff</file> + <file>tiff/tiled_indexed.tiff</file> + <file>tiff/tiled_mono.tiff</file> + <file>tiff/tiled_oddsize_mono.tiff</file> + <file>tiff/oddsize_mono.tiff</file> + <file>tiff/tiled_rgb.tiff</file> </qresource> </RCC> diff --git a/tests/shared/images/tiff/indexed_nontiled.tif b/tests/shared/images/tiff/indexed_nontiled.tif deleted file mode 100644 index d0b7cef9718969298f11c95f9dc9a20c66201d1e..0000000000000000000000000000000000000000 Binary files a/tests/shared/images/tiff/indexed_nontiled.tif and /dev/null differ diff --git a/tests/shared/images/tiff/indexed_tiled.tif b/tests/shared/images/tiff/indexed_tiled.tif deleted file mode 100644 index 4ed11dd7456c1497bf4450d153d370ff5d891a48..0000000000000000000000000000000000000000 Binary files a/tests/shared/images/tiff/indexed_tiled.tif and /dev/null differ diff --git a/tests/shared/images/tiff/oddsize_grayscale.tiff b/tests/shared/images/tiff/oddsize_grayscale.tiff new file mode 100644 index 0000000000000000000000000000000000000000..d519cd2b9aef6c8d66bfb4f026a783cd43be00f4 Binary files /dev/null and b/tests/shared/images/tiff/oddsize_grayscale.tiff differ diff --git a/tests/shared/images/tiff/oddsize_mono.tiff b/tests/shared/images/tiff/oddsize_mono.tiff new file mode 100644 index 0000000000000000000000000000000000000000..fbac0edca7ea4a38e3d8481702c5dc7e9a337c7b Binary files /dev/null and b/tests/shared/images/tiff/oddsize_mono.tiff differ diff --git a/tests/shared/images/tiff/original_grayscale.tiff b/tests/shared/images/tiff/original_grayscale.tiff new file mode 100644 index 0000000000000000000000000000000000000000..174c2cfe88b3fbf879d28da2b2e07f332e032d99 Binary files /dev/null and b/tests/shared/images/tiff/original_grayscale.tiff differ diff --git a/tests/shared/images/tiff/tiled_grayscale.tiff b/tests/shared/images/tiff/tiled_grayscale.tiff new file mode 100644 index 0000000000000000000000000000000000000000..894ba8b1a0e298e2faefac0aa4d1421cfd787e03 Binary files /dev/null and b/tests/shared/images/tiff/tiled_grayscale.tiff differ diff --git a/tests/shared/images/tiff/tiled_indexed.tiff b/tests/shared/images/tiff/tiled_indexed.tiff new file mode 100644 index 0000000000000000000000000000000000000000..2bd266a1c696ebe0f5db5030e665cd2bd3c87197 Binary files /dev/null and b/tests/shared/images/tiff/tiled_indexed.tiff differ diff --git a/tests/shared/images/tiff/tiled_mono.tiff b/tests/shared/images/tiff/tiled_mono.tiff new file mode 100644 index 0000000000000000000000000000000000000000..cbcda19249aa6b704a91cea9a8f978b52589ab43 Binary files /dev/null and b/tests/shared/images/tiff/tiled_mono.tiff differ diff --git a/tests/shared/images/tiff/tiled_oddsize_grayscale.tiff b/tests/shared/images/tiff/tiled_oddsize_grayscale.tiff new file mode 100644 index 0000000000000000000000000000000000000000..27bc9d45c659ef689744a7427a897ece5c1b4a86 Binary files /dev/null and b/tests/shared/images/tiff/tiled_oddsize_grayscale.tiff differ diff --git a/tests/shared/images/tiff/tiled_oddsize_mono.tiff b/tests/shared/images/tiff/tiled_oddsize_mono.tiff new file mode 100644 index 0000000000000000000000000000000000000000..e858e90400886850aa055bf35117692ec66e1cbe Binary files /dev/null and b/tests/shared/images/tiff/tiled_oddsize_mono.tiff differ diff --git a/tests/shared/images/tiff/tiled_rgb.tiff b/tests/shared/images/tiff/tiled_rgb.tiff new file mode 100644 index 0000000000000000000000000000000000000000..90291b9859c0d9dbddd488f7bd1439ab12eee77c Binary files /dev/null and b/tests/shared/images/tiff/tiled_rgb.tiff differ