From 218c48b5c3eeebafef0e4475493e11e466b9fcd9 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen <allan.jensen@digia.com> Date: Mon, 3 Feb 2014 12:30:38 +0100 Subject: [PATCH] Save opaque images as opaque TIFF files We currently save all non-indexed images as RGBA TIFF files. We should save them without an alpha channel, to save space and maintain the information that they are opaque. Task-number: QTBUG-18475 Change-Id: Id656f4078ea0a1b88235fb04add99a4680422354 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com> --- .../imageformats/tiff/qtiffhandler.cpp | 45 ++++++++++++++++--- tests/auto/tiff/tst_qtiff.cpp | 3 +- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index e2177857..445f0c4b 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -267,8 +267,12 @@ bool QTiffHandler::read(QImage *image) // free redTable, greenTable and greenTable done by libtiff } } else { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) - *image = QImage(width, height, QImage::Format_ARGB32); + QImage::Format format = QImage::Format_ARGB32; + if (samplesPerPixel < 4 && image->format() != QImage::Format_ARGB32) + format = QImage::Format_RGB32; + + if (image->size() != QSize(width, height) || image->format() != format) + *image = QImage(width, height, format); if (!image->isNull()) { const int stopOnError = 1; if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) { @@ -315,7 +319,7 @@ bool QTiffHandler::read(QImage *image) // rotate the image if the orientation is defined in the file uint16 orientationTag; if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) { - if (image->format() == QImage::Format_ARGB32) { + if (image->format() == QImage::Format_ARGB32 || image->format() == QImage::Format_RGB32) { // TIFFReadRGBAImageOriented() flip the image but does not rotate them switch (orientationTag) { case 5: @@ -552,6 +556,33 @@ bool QTiffHandler::write(const QImage &image) } TIFFClose(tiff); + } else if (!image.hasAlphaChannel()) { + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) + || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + // try to do the RGB888 conversion in chunks no greater than 16 MB + const int chunks = (width * height * 3 / (1024 * 1024 * 16)) + 1; + const int chunkHeight = qMax(height / chunks, 1); + + int y = 0; + while (y < height) { + const QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_RGB888); + + int chunkStart = y; + int chunkEnd = y + chunk.height(); + while (y < chunkEnd) { + if (TIFFWriteScanline(tiff, (void*)chunk.scanLine(y - chunkStart), y) != 1) { + TIFFClose(tiff); + return false; + } + ++y; + } + } + TIFFClose(tiff); } else { if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) @@ -561,17 +592,17 @@ bool QTiffHandler::write(const QImage &image) return false; } // try to do the RGBA8888 conversion in chunks no greater than 16 MB - int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); + const int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1; + const int chunkHeight = qMax(height / chunks, 1); int y = 0; while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_RGBA8888); + const QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_RGBA8888); int chunkStart = y; int chunkEnd = y + chunk.height(); while (y < chunkEnd) { - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { + if (TIFFWriteScanline(tiff, (void*)chunk.scanLine(y - chunkStart), y) != 1) { TIFFClose(tiff); return false; } diff --git a/tests/auto/tiff/tst_qtiff.cpp b/tests/auto/tiff/tst_qtiff.cpp index 6548d23a..b838a5d8 100644 --- a/tests/auto/tiff/tst_qtiff.cpp +++ b/tests/auto/tiff/tst_qtiff.cpp @@ -374,7 +374,8 @@ void tst_qtiff::readWriteNonDestructive_data() QTest::addColumn<bool>("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 argb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32 << false; + QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << false; QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true; } -- GitLab