diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | src/imageformats/doc/qtimageformats.qdocconf | 1 | ||||
-rw-r--r-- | src/plugins/imageformats/icns/qicnshandler.cpp | 50 | ||||
-rw-r--r-- | src/plugins/imageformats/icns/qicnshandler_p.h | 10 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.cpp | 45 | ||||
-rw-r--r-- | tests/auto/icns/tst_qicns.cpp | 1 | ||||
-rw-r--r-- | tests/auto/tiff/tst_qtiff.cpp | 3 | ||||
-rw-r--r-- | tests/shared/images/icns.qrc | 1 | ||||
-rw-r--r-- | tests/shared/images/icns/test-variants.icns | bin | 0 -> 16360 bytes |
9 files changed, 95 insertions, 18 deletions
diff --git a/.qmake.conf b/.qmake.conf index 3d3f19b..e28797d 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,3 @@ load(qt_build_config) -MODULE_VERSION = 5.3.2 +MODULE_VERSION = 5.4.0 diff --git a/src/imageformats/doc/qtimageformats.qdocconf b/src/imageformats/doc/qtimageformats.qdocconf index 647d561..f37c9d8 100644 --- a/src/imageformats/doc/qtimageformats.qdocconf +++ b/src/imageformats/doc/qtimageformats.qdocconf @@ -3,7 +3,6 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) # Name of the project. project = QtImageFormats description = Qt Image Formats Documentation -url = http://qt-project.org/doc/qt-$QT_VER version = $QT_VERSION # Directories in which to search for files to document. diff --git a/src/plugins/imageformats/icns/qicnshandler.cpp b/src/plugins/imageformats/icns/qicnshandler.cpp index b99c667..5daf29d 100644 --- a/src/plugins/imageformats/icns/qicnshandler.cpp +++ b/src/plugins/imageformats/icns/qicnshandler.cpp @@ -372,7 +372,8 @@ static inline bool isIconCompressed(const ICNSEntry &icon) static inline bool isMaskSuitable(const ICNSEntry &mask, const ICNSEntry &icon, ICNSEntry::Depth target) { - return mask.depth == target && mask.height == icon.height && mask.width == icon.width; + return mask.variant == icon.variant && mask.depth == target + && mask.height == icon.height && mask.width == icon.width; } static inline QByteArray nameFromOSType(quint32 ostype) @@ -664,12 +665,15 @@ bool QICNSHandler::canRead(QIODevice *device) return false; } - if (device->isSequential()) { - qWarning("QICNSHandler::canRead() called on a sequential device"); - return false; + if (device->peek(4) == QByteArrayLiteral("icns")) { + if (device->isSequential()) { + qWarning("QICNSHandler::canRead() called on a sequential device"); + return false; + } + return true; } - return device->peek(4) == QByteArrayLiteral("icns"); + return false; } bool QICNSHandler::canRead() const @@ -813,6 +817,8 @@ QVariant QICNSHandler::option(ImageOption option) const if (option == SubType) { if (imageCount() > 0 && m_currentIconIndex <= imageCount()) { const ICNSEntry &icon = m_icons.at(m_currentIconIndex); + if (icon.variant != 0) + return nameFromOSType(icon.variant) + '-' + nameFromOSType(icon.ostype); return nameFromOSType(icon.ostype); } } @@ -852,11 +858,12 @@ bool QICNSHandler::ensureScanned() const return m_state == ScanSuccess; } -bool QICNSHandler::addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset) +bool QICNSHandler::addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset, quint32 variant) { // Note: This function returns false only when a device positioning error occurred ICNSEntry entry; entry.ostype = header.ostype; + entry.variant = variant; entry.dataOffset = imgDataOffset; entry.dataLength = header.length - ICNSBlockHeaderSize; // Check for known magic numbers: @@ -920,6 +927,37 @@ bool QICNSHandler::scanDevice() // We don't have a good use for these blocks... yet. stream.skipRawData(blockDataLength); break; + case ICNSBlockHeader::TypeTile: + case ICNSBlockHeader::TypeOver: + case ICNSBlockHeader::TypeOpen: + case ICNSBlockHeader::TypeDrop: + case ICNSBlockHeader::TypeOdrp: + // Icns container seems to have an embedded icon variant container + // Let's start a scan for entries + while (device()->pos() < nextBlockOffset) { + ICNSBlockHeader icon; + stream >> icon; + // Check for incorrect variant entry header and stop scan + if (!isBlockHeaderValid(icon, blockDataLength)) + break; + if (!addEntry(icon, device()->pos(), blockHeader.ostype)) + return false; + if (stream.skipRawData(icon.length - ICNSBlockHeaderSize) < 0) + return false; + } + if (device()->pos() != nextBlockOffset) { + // Scan of this container didn't end where we expected. + // Let's generate some output about this incident: + qWarning("Scan of the icon variant container (\"%s\") failed at pos %s.\n" \ + "Reason: Scan didn't reach the end of this container's block, " \ + "delta: %s bytes. This file may be corrupted.", + nameFromOSType(blockHeader.ostype).constData(), + QByteArray::number(device()->pos()).constData(), + QByteArray::number(nextBlockOffset - device()->pos()).constData()); + if (!device()->seek(nextBlockOffset)) + return false; + } + break; case ICNSBlockHeader::TypeToc: { // Quick scan, table of contents if (blockDataOffset != ICNSBlockHeaderSize * 2) { diff --git a/src/plugins/imageformats/icns/qicnshandler_p.h b/src/plugins/imageformats/icns/qicnshandler_p.h index 12c165b..747cb3e 100644 --- a/src/plugins/imageformats/icns/qicnshandler_p.h +++ b/src/plugins/imageformats/icns/qicnshandler_p.h @@ -60,6 +60,11 @@ struct ICNSBlockHeader TypeIcnv = MAKEOSTYPE('i', 'c', 'n', 'V'), // Icon Composer version // Legacy: TypeClut = MAKEOSTYPE('c', 'l', 'u', 't'), // Color look-up table (pre-OS X resources) + TypeTile = MAKEOSTYPE('t', 'i', 'l', 'e'), // Container (icon variants) + TypeOver = MAKEOSTYPE('o', 'v', 'e', 'r'), // Container (icon variants) + TypeOpen = MAKEOSTYPE('o', 'p', 'e', 'n'), // Container (icon variants) + TypeDrop = MAKEOSTYPE('d', 'r', 'o', 'p'), // Container (icon variants) + TypeOdrp = MAKEOSTYPE('o', 'd', 'r', 'p'), // Container (icon variants) }; quint32 ostype; @@ -102,6 +107,7 @@ struct ICNSEntry }; quint32 ostype; // Real OSType + quint32 variant; // Virtual OSType: a parent container, zero if parent is icns root Group group; // ASCII character number quint32 width; // For uncompressed icons only, zero for compressed ones for now quint32 height; // For uncompressed icons only, zero for compressed ones fow now @@ -112,7 +118,7 @@ struct ICNSEntry qint64 dataOffset; // Offset from the initial position of the file/device ICNSEntry() : - ostype(0), group(GroupUnknown), width(0), height(0), depth(DepthUnknown), + ostype(0), variant(0), group(GroupUnknown), width(0), height(0), depth(DepthUnknown), flags(Unknown), dataFormat(FormatUnknown), dataLength(0), dataOffset(0) { } @@ -142,7 +148,7 @@ public: private: bool ensureScanned() const; bool scanDevice(); - bool addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset); + bool addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset, quint32 variant = 0); const ICNSEntry &getIconMask(const ICNSEntry &icon) const; private: diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index e217785..445f0c4 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/icns/tst_qicns.cpp b/tests/auto/icns/tst_qicns.cpp index 261590e..29ca3ee 100644 --- a/tests/auto/icns/tst_qicns.cpp +++ b/tests/auto/icns/tst_qicns.cpp @@ -65,6 +65,7 @@ void tst_qicns::readIcons_data() QTest::newRow("2") << QStringLiteral("test-jp2") << QSize(128, 128) << 7 << QByteArrayLiteral("jp2"); QTest::newRow("3") << QStringLiteral("test-32bit") << QSize(128, 128) << 4 << QByteArray(); QTest::newRow("4") << QStringLiteral("test-legacy") << QSize(48, 48) << 12 << QByteArray(); + QTest::newRow("5") << QStringLiteral("test-variants") << QSize(128, 128) << 5 << QByteArrayLiteral("png"); } void tst_qicns::readIcons() diff --git a/tests/auto/tiff/tst_qtiff.cpp b/tests/auto/tiff/tst_qtiff.cpp index 6548d23..b838a5d 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; } diff --git a/tests/shared/images/icns.qrc b/tests/shared/images/icns.qrc index 072b78c..f87830d 100644 --- a/tests/shared/images/icns.qrc +++ b/tests/shared/images/icns.qrc @@ -4,6 +4,7 @@ <file>icns/test-jp2.icns</file> <file>icns/test-32bit.icns</file> <file>icns/test-legacy.icns</file> + <file>icns/test-variants.icns</file> <file>icns/test-write-16.png</file> <file>icns/test-write-32.png</file> <file>icns/test-write-64.png</file> diff --git a/tests/shared/images/icns/test-variants.icns b/tests/shared/images/icns/test-variants.icns Binary files differnew file mode 100644 index 0000000..e623279 --- /dev/null +++ b/tests/shared/images/icns/test-variants.icns |