From 5a5eb18deb5239863a2cedb6b77f90e9a5be3113 Mon Sep 17 00:00:00 2001
From: Ivan Komissarov <ABBAPOH@gmail.com>
Date: Tue, 7 Jan 2014 16:09:11 +0400
Subject: [PATCH] Add support for SubType and SupportedSubTypes options in DDS
 handler

Change-Id: I2fa563bf023871e9e99ed32829f978577eaf2a68
Reviewed-by: Alex Char <prevedtest@gmail.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
---
 src/plugins/imageformats/dds/qddshandler.cpp | 144 ++++++++++++++++++-
 src/plugins/imageformats/dds/qddshandler.h   |   1 +
 tests/auto/dds/tst_qdds.cpp                  |  11 ++
 3 files changed, 154 insertions(+), 2 deletions(-)

diff --git a/src/plugins/imageformats/dds/qddshandler.cpp b/src/plugins/imageformats/dds/qddshandler.cpp
index d5c8793e..05bf87bd 100644
--- a/src/plugins/imageformats/dds/qddshandler.cpp
+++ b/src/plugins/imageformats/dds/qddshandler.cpp
@@ -166,6 +166,101 @@ static const Format knownFourCCs[] = {
 };
 static const size_t knownFourCCsSize = sizeof(knownFourCCs)/sizeof(Format);
 
+struct FormatName
+{
+    Format format;
+    const char *const name;
+};
+static const FormatName formatNames[] = {
+    { FormatUnknown,  "unknown" },
+
+    { FormatR8G8B8,   "R8G8B8"  },
+    { FormatA8R8G8B8, "A8R8G8B8" },
+    { FormatX8R8G8B8, "X8R8G8B8" },
+    { FormatR5G6B5,   "R5G6B5" },
+    { FormatX1R5G5B5, "X1R5G5B5" },
+    { FormatA1R5G5B5, "A1R5G5B5" },
+    { FormatA4R4G4B4, "A4R4G4B4" },
+    { FormatR3G3B2, "R3G3B2" },
+    { FormatA8, "A8" },
+    { FormatA8R3G3B2, "A8R3G3B2" },
+    { FormatX4R4G4B4, "X4R4G4B4" },
+    { FormatA2B10G10R10, "A2B10G10R10" },
+    { FormatA8B8G8R8, "A8B8G8R8" },
+    { FormatX8B8G8R8, "X8B8G8R8" },
+    { FormatG16R16, "G16R16" },
+    { FormatA2R10G10B10, "A2R10G10B10" },
+    { FormatA16B16G16R16, "A16B16G16R16" },
+
+    { FormatA8P8, "A8P8" },
+    { FormatP8, "P8" },
+
+    { FormatL8, "L8" },
+    { FormatA8L8, "A8L8" },
+    { FormatA4L4, "A4L4" },
+
+    { FormatV8U8, "V8U8" },
+    { FormatL6V5U5, "L6V5U5" },
+    { FormatX8L8V8U8, "X8L8V8U8" },
+    { FormatQ8W8V8U8, "Q8W8V8U8" },
+    { FormatV16U16, "V16U16" },
+    { FormatA2W10V10U10, "A2W10V10U10" },
+
+    { FormatUYVY, "UYVY" },
+    { FormatR8G8B8G8, "R8G8_B8G8" },
+    { FormatYUY2, "YUY2" },
+    { FormatG8R8G8B8, "G8R8_G8B8" },
+    { FormatDXT1, "DXT1" },
+    { FormatDXT2, "DXT2" },
+    { FormatDXT3, "DXT3" },
+    { FormatDXT4, "DXT4" },
+    { FormatDXT5, "DXT5" },
+    { FormatRXGB, "RXGB" },
+    { FormatATI2, "ATI2" },
+
+    { FormatD16Lockable, "D16Lockable" },
+    { FormatD32, "D32" },
+    { FormatD15S1, "D15S1" },
+    { FormatD24S8, "D24S8" },
+    { FormatD24X8, "D24X8" },
+    { FormatD24X4S4, "D24X4S4" },
+    { FormatD16, "D16" },
+
+    { FormatD32FLockable, "D32FLockable" },
+    { FormatD24FS8, "D24FS8" },
+
+    { FormatD32Lockable, "D32Lockable" },
+    { FormatS8Lockable, "S8Lockable" },
+
+    { FormatL16, "L16" },
+
+    { FormatVertexData, "VertexData" },
+    { FormatIndex32, "Index32" },
+    { FormatIndex32, "Index32" },
+
+    { FormatQ16W16V16U16, "Q16W16V16U16" },
+
+    { FormatMulti2ARGB8, "Multi2ARGB8" },
+
+    { FormatR16F, "R16F" },
+    { FormatG16R16F, "G16R16F" },
+    { FormatA16B16G16R16F, "A16B16G16R16F" },
+
+    { FormatR32F, "R32F" },
+    { FormatG32R32F, "G32R32F" },
+    { FormatA32B32G32R32F, "A32B32G32R32F" },
+
+    { FormatCxV8U8, "CxV8U8" },
+
+    { FormatA1, "A1" },
+    { FormatA2B10G10R10_XR_BIAS, "A2B10G10R10_XR_BIAS" },
+    { FormatBinaryBuffer, "BinaryBuffer" },
+
+    { FormatP4, "P4" },
+    { FormatA4P4, "A4P4" }
+};
+static const size_t formatNamesSize = sizeof(formatNames)/sizeof(FormatName);
+
 static inline int maskToShift(quint32 mask)
 {
     if (mask == 0)
@@ -1256,7 +1351,29 @@ static QImage readCubeMap(QDataStream &s, const DDSHeader &dds, const int fmt)
     return image;
 }
 
+static QByteArray formatName(int format)
+{
+    for (size_t i = 0; i < formatNamesSize; ++i) {
+        if (formatNames[i].format == format)
+            return formatNames[i].name;
+    }
+
+    return formatNames[0].name;
+}
+
+static int formatByName(const QByteArray &name)
+{
+    const QByteArray loweredName = name.toLower();
+    for (size_t i = 0; i < formatNamesSize; ++i) {
+        if (QByteArray(formatNames[i].name).toLower() == loweredName)
+            return formatNames[i].format;
+    }
+
+    return FormatUnknown;
+}
+
 QDDSHandler::QDDSHandler() :
+    m_format(FormatA8R8G8B8),
     m_currentImage(0),
     m_scanState(ScanNotScanned)
 {
@@ -1303,6 +1420,11 @@ bool QDDSHandler::read(QImage *outImage)
 
 bool QDDSHandler::write(const QImage &outImage)
 {
+    if (m_format != FormatA8R8G8B8) {
+        qWarning() << "Format" << formatName(m_format) << "is not supported";
+        return false;
+    }
+
     const QImage image = outImage.convertToFormat(QImage::Format_ARGB32);
 
     QDataStream s(device());
@@ -1362,6 +1484,10 @@ QVariant QDDSHandler::option(QImageIOHandler::ImageOption option) const
     switch (option) {
     case QImageIOHandler::Size:
         return QSize(m_header.width, m_header.height);
+    case QImageIOHandler::SubType:
+        return formatName(m_format);
+    case QImageIOHandler::SupportedSubTypes:
+        return QVariant::fromValue(QList<QByteArray>() << formatName(FormatA8R8G8B8));
     default:
         break;
     }
@@ -1369,9 +1495,21 @@ QVariant QDDSHandler::option(QImageIOHandler::ImageOption option) const
     return QVariant();
 }
 
+void QDDSHandler::setOption(QImageIOHandler::ImageOption option, const QVariant &value)
+{
+    if (option == QImageIOHandler::SubType) {
+        const QByteArray subType = value.toByteArray();
+        m_format = formatByName(subType.toUpper());
+        if (m_format == FormatUnknown)
+            qWarning() << "unknown format" << subType;
+    }
+}
+
 bool QDDSHandler::supportsOption(QImageIOHandler::ImageOption option) const
 {
-    return option == QImageIOHandler::Size;
+    return (option == QImageIOHandler::Size)
+            || (option == QImageIOHandler::SubType)
+            || (option == QImageIOHandler::SupportedSubTypes);
 }
 
 int QDDSHandler::imageCount() const
@@ -1411,6 +1549,9 @@ bool QDDSHandler::ensureScanned() const
 
     m_scanState = ScanError;
 
+    QDDSHandler *that = const_cast<QDDSHandler *>(this);
+    that->m_format = FormatUnknown;
+
     if (device()->isSequential()) {
         qWarning() << "Sequential devices are not supported";
         return false;
@@ -1419,7 +1560,6 @@ bool QDDSHandler::ensureScanned() const
     qint64 oldPos = device()->pos();
     device()->seek(0);
 
-    QDDSHandler *that = const_cast<QDDSHandler *>(this);
     QDataStream s(device());
     s.setByteOrder(QDataStream::LittleEndian);
     s >> that->m_header;
diff --git a/src/plugins/imageformats/dds/qddshandler.h b/src/plugins/imageformats/dds/qddshandler.h
index 582a0133..967a35d2 100644
--- a/src/plugins/imageformats/dds/qddshandler.h
+++ b/src/plugins/imageformats/dds/qddshandler.h
@@ -62,6 +62,7 @@ public:
     bool write(const QImage &image);
 
     QVariant option(QImageIOHandler::ImageOption option) const;
+    void setOption(ImageOption option, const QVariant &value);
     bool supportsOption(QImageIOHandler::ImageOption option) const;
 
     int imageCount() const;
diff --git a/tests/auto/dds/tst_qdds.cpp b/tests/auto/dds/tst_qdds.cpp
index 24746641..f3c69f86 100644
--- a/tests/auto/dds/tst_qdds.cpp
+++ b/tests/auto/dds/tst_qdds.cpp
@@ -118,8 +118,12 @@ void tst_qdds::readImage()
     QFETCH(QSize, size);
 
     const QString path = QStringLiteral(":/dds/") + fileName + QStringLiteral(".dds");
+    const QByteArray subType = fileName.left(fileName.lastIndexOf(QLatin1Char('.'))).toLatin1();
     QImageReader reader(path);
     QVERIFY(reader.canRead());
+    QVERIFY(reader.supportsOption(QImageIOHandler::SubType));
+    QCOMPARE(reader.subType(), subType);
+    QVERIFY(reader.supportsOption(QImageIOHandler::SupportedSubTypes));
     QImage image = reader.read();
     QVERIFY2(!image.isNull(), qPrintable(reader.errorString()));
     QCOMPARE(image.size(), size);
@@ -169,6 +173,7 @@ void tst_qdds::testWriteImage()
 
     const QString path = fileName + QStringLiteral(".dds");
     const QString sourcePath = QStringLiteral(":/dds/") + fileName + QStringLiteral(".dds");
+    const QByteArray subType = fileName.left(fileName.lastIndexOf(QLatin1Char('.'))).toLatin1();
 
     QImage image(sourcePath);
     QVERIFY(!image.isNull());
@@ -176,9 +181,15 @@ void tst_qdds::testWriteImage()
 
     QImageWriter writer(path, QByteArrayLiteral("dds"));
     QVERIFY2(writer.canWrite(), qPrintable(writer.errorString()));
+    writer.setSubType(subType);
     QVERIFY2(writer.write(image), qPrintable(writer.errorString()));
 
     QVERIFY(image == QImage(path));
+
+    QImageReader reader(path);
+    QVERIFY(reader.canRead());
+    QCOMPARE(reader.size(), size);
+    QCOMPARE(reader.subType(), subType);
 }
 
 QTEST_MAIN(tst_qdds)
-- 
GitLab