From 74e6e5e1b731a4a6e0670781942330bedaff4220 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 14 Feb 2023 15:34:56 +0200 Subject: QmlDesigner: Show ktx texture dimensions in tooltips Tooltips in assets and material browser views now show correct dimensions for ktx files. Dimensions are read from ktx file header. Task-number: QDS-8851 Change-Id: Ia9ce195eba43e7a8d4fc9e4a980c3c56e75108b4 Reviewed-by: Mahmoud Badri --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../assetslibrary/assetslibraryiconprovider.cpp | 17 ++-- .../assetslibrary/assetslibraryiconprovider.h | 1 - .../assetslibrary/assetslibrarywidget.cpp | 3 +- src/plugins/qmldesigner/utils/asset.cpp | 5 ++ src/plugins/qmldesigner/utils/asset.h | 1 + src/plugins/qmldesigner/utils/hdrimage.cpp | 2 +- src/plugins/qmldesigner/utils/imageutils.cpp | 9 +- src/plugins/qmldesigner/utils/ktximage.cpp | 100 +++++++++++++++++++++ src/plugins/qmldesigner/utils/ktximage.h | 29 ++++++ 10 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 src/plugins/qmldesigner/utils/ktximage.cpp create mode 100644 src/plugins/qmldesigner/utils/ktximage.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index f8c1efe40e..7ba17b7786 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -23,6 +23,7 @@ add_qtc_library(QmlDesignerUtils STATIC filedownloader.cpp filedownloader.h fileextractor.cpp fileextractor.h hdrimage.cpp hdrimage.h + ktximage.cpp ktximage.h imageutils.cpp imageutils.h qmldesignerutils_global.h ) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index 0dc73120f1..d3a0d0a72b 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace QmlDesigner { @@ -43,13 +44,16 @@ Thumbnail AssetsLibraryIconProvider::createThumbnail(const QString &id, const QS { auto [pixmap, fileSize] = fetchPixmap(id, requestedSize); QSize originalSize = pixmap.size(); - Asset::Type assetType = Asset(id).type(); + Asset asset(id); + Asset::Type assetType = asset.type(); if (pixmap.isNull()) { pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (assetType == Asset::Image) assetType = Asset::MissingImage; + else if (asset.isKtxFile()) + originalSize = KtxImage(id).dimensions(); } if (requestedSize.isValid()) @@ -86,6 +90,10 @@ QPair AssetsLibraryIconProvider::fetchPixmap(const QString &id, qint64 size = QFileInfo(id).size(); QPixmap pixmap = HdrImage{id}.toPixmap(); return {pixmap, size}; + } else if (asset.isKtxFile()) { + qint64 size = QFileInfo(id).size(); + // TODO: Return ktx specific default image once available (QDS-9140) + return {{}, size}; } else { QString type; if (asset.isShader()) @@ -129,12 +137,5 @@ qint64 AssetsLibraryIconProvider::fileSize(const QString &id) return m_thumbnails.contains(id) ? m_thumbnails[id].fileSize : 0; } -bool AssetsLibraryIconProvider::assetIsImage(const QString &id) -{ - return m_thumbnails.contains(id) - ? (m_thumbnails[id].assetType == Asset::Type::Image || Asset(id).isHdrFile()) - : false; -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h index b089af4c89..b3530f3edb 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h @@ -29,7 +29,6 @@ public: void invalidateThumbnail(const QString &id); QSize imageSize(const QString &id); qint64 fileSize(const QString &id); - bool assetIsImage(const QString &id); private: QPixmap generateFontIcons(const QString &filePath, const QSize &requestedSize) const; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7fa8f6c58f..bf82e08aae 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -251,7 +251,8 @@ QString AssetsLibraryWidget::assetFileSize(const QString &id) bool AssetsLibraryWidget::assetIsImage(const QString &id) { - return m_assetsIconProvider->assetIsImage(id); + Asset asset(id); + return asset.isImage() || asset.isTexture3D(); } QList AssetsLibraryWidget::createToolBarWidgets() diff --git a/src/plugins/qmldesigner/utils/asset.cpp b/src/plugins/qmldesigner/utils/asset.cpp index 31bce298b5..7e8931d9cb 100644 --- a/src/plugins/qmldesigner/utils/asset.cpp +++ b/src/plugins/qmldesigner/utils/asset.cpp @@ -161,6 +161,11 @@ bool Asset::isHdrFile() const return m_suffix == "*.hdr"; } +bool Asset::isKtxFile() const +{ + return m_suffix == "*.ktx"; +} + bool Asset::isEffect() const { return type() == Asset::Type::Effect; diff --git a/src/plugins/qmldesigner/utils/asset.h b/src/plugins/qmldesigner/utils/asset.h index e673f10238..9218cac3b8 100644 --- a/src/plugins/qmldesigner/utils/asset.h +++ b/src/plugins/qmldesigner/utils/asset.h @@ -35,6 +35,7 @@ public: bool isVideo() const; bool isTexture3D() const; bool isHdrFile() const; + bool isKtxFile() const; bool isEffect() const; bool isSupported() const; diff --git a/src/plugins/qmldesigner/utils/hdrimage.cpp b/src/plugins/qmldesigner/utils/hdrimage.cpp index 291784efd0..8f44fef0ec 100644 --- a/src/plugins/qmldesigner/utils/hdrimage.cpp +++ b/src/plugins/qmldesigner/utils/hdrimage.cpp @@ -21,7 +21,7 @@ typedef unsigned char RGBE[4]; constexpr float GAMMA = 1.f / 2.2f; -QByteArray fileToByteArray(QString const &filename) +static QByteArray fileToByteArray(QString const &filename) { QFile file(filename); QFileInfo info(file); diff --git a/src/plugins/qmldesigner/utils/imageutils.cpp b/src/plugins/qmldesigner/utils/imageutils.cpp index c1e3b8f495..ccfa5bfe42 100644 --- a/src/plugins/qmldesigner/utils/imageutils.cpp +++ b/src/plugins/qmldesigner/utils/imageutils.cpp @@ -3,6 +3,8 @@ #include "imageutils.h" +#include "ktximage.h" + #include #include #include @@ -17,7 +19,8 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path) int width = 0; int height = 0; - if (info.suffix() == "hdr") { + const QString suffix = info.suffix(); + if (suffix == "hdr") { QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return {}; @@ -27,6 +30,10 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path) if (sscanf(line.constData(), "-Y %d +X %d", &height, &width)) break; } + } else if (suffix == "ktx") { + KtxImage ktx(path); + width = ktx.dimensions().width(); + height = ktx.dimensions().height(); } else { QSize size = QImageReader(path).size(); width = size.width(); diff --git a/src/plugins/qmldesigner/utils/ktximage.cpp b/src/plugins/qmldesigner/utils/ktximage.cpp new file mode 100644 index 0000000000..1bb607403f --- /dev/null +++ b/src/plugins/qmldesigner/utils/ktximage.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "ktximage.h" + +#include +#include +#include + +#include + +namespace QmlDesigner { + +// Ktx images currently support only image metadata + +static QByteArray fileToByteArray(QString const &filename) +{ + QFile file(filename); + QFileInfo info(file); + + if (info.exists() && file.open(QFile::ReadOnly)) { + // Read data until we have what we need + // Content is: + // Byte[12] identifier + // UInt32 endianness + // UInt32 + // UInt32 + // UInt32 + // Uint32 + // Uint32 + // UInt32 pixelWidth + // UInt32 pixelHeight + // ... + return file.read(44); + } + + return {}; +} + +KtxImage::KtxImage(const QString &fileName) + : m_fileName(fileName) +{ + loadKtx(); +} + +QSize KtxImage::dimensions() const +{ + return m_dim; +} + +void KtxImage::loadKtx() +{ + QByteArray buf(fileToByteArray(m_fileName)); + + auto handleError = [this](const QString &error) { + qWarning() << QStringLiteral("Failed to load KTX image '%1': %2.").arg(m_fileName, error).toUtf8(); + }; + + if (buf.isEmpty()) { + handleError("File open failed"); + return; + } + + constexpr char ktxIdentifier[12] = { + '\xAB', 'K', 'T', 'X', ' ', '1', + '1', '\xBB', '\r', '\n', '\x1A', '\n' + }; + + if (!buf.startsWith(ktxIdentifier)) { + handleError("Non-KTX file"); + return; + } + + if (buf.size() < 44) { + handleError("Missing metadata"); + return; + } + + quint32 w = 0; + quint32 h = 0; + + if (*reinterpret_cast(buf.data() + 12) == 0x01020304) { + // File endianness is different from our endianness + QByteArray convBuf(4, 0); + auto convertEndianness = [&convBuf, &buf](int idx) -> quint32 { + for (int i = 0; i < 4; ++i) + convBuf[i] = buf[idx + 3 - i]; + return *reinterpret_cast(convBuf.data()); + }; + w = convertEndianness(36); + h = convertEndianness(40); + } else { + w = *reinterpret_cast(buf.data() + 36); + h = *reinterpret_cast(buf.data() + 40); + } + + m_dim = QSize(w, h); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/utils/ktximage.h b/src/plugins/qmldesigner/utils/ktximage.h new file mode 100644 index 0000000000..19b8132d27 --- /dev/null +++ b/src/plugins/qmldesigner/utils/ktximage.h @@ -0,0 +1,29 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +#pragma once + +#include "qmldesignerutils_global.h" + +#include +#include +#include +#include + +namespace QmlDesigner { + +class QMLDESIGNERUTILS_EXPORT KtxImage +{ +public: + KtxImage(const QString &fileName); + + QString fileName() const { return m_fileName; } + QSize dimensions() const; + +private: + void loadKtx(); + + QString m_fileName; + QSize m_dim; +}; + +} // namespace QmlDesigner -- cgit v1.2.1