summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/imageformats/doc/qtimageformats.qdocconf1
-rw-r--r--src/plugins/imageformats/icns/qicnshandler.cpp50
-rw-r--r--src/plugins/imageformats/icns/qicnshandler_p.h10
-rw-r--r--src/plugins/imageformats/tiff/qtiffhandler.cpp45
-rw-r--r--tests/auto/icns/tst_qicns.cpp1
-rw-r--r--tests/auto/tiff/tst_qtiff.cpp3
-rw-r--r--tests/shared/images/icns.qrc1
-rw-r--r--tests/shared/images/icns/test-variants.icnsbin0 -> 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
new file mode 100644
index 0000000..e623279
--- /dev/null
+++ b/tests/shared/images/icns/test-variants.icns
Binary files differ