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 <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2023-02-14 15:34:56 +02:00
parent cabf16c521
commit 74e6e5e1b7
10 changed files with 156 additions and 12 deletions

View File

@@ -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
)

View File

@@ -7,6 +7,7 @@
#include <theme.h>
#include <utils/hdrimage.h>
#include <utils/ktximage.h>
#include <utils/stylehelper.h>
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<QPixmap, qint64> 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

View File

@@ -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;

View File

@@ -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<QToolButton *> AssetsLibraryWidget::createToolBarWidgets()

View File

@@ -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;

View File

@@ -35,6 +35,7 @@ public:
bool isVideo() const;
bool isTexture3D() const;
bool isHdrFile() const;
bool isKtxFile() const;
bool isEffect() const;
bool isSupported() const;

View File

@@ -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);

View File

@@ -3,6 +3,8 @@
#include "imageutils.h"
#include "ktximage.h"
#include <QFile>
#include <QFileInfo>
#include <QImageReader>
@@ -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();

View File

@@ -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 <QFile>
#include <QFileInfo>
#include <QDebug>
#include <cmath>
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<const quint32 *>(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<const quint32 *>(convBuf.data());
};
w = convertEndianness(36);
h = convertEndianness(40);
} else {
w = *reinterpret_cast<const quint32 *>(buf.data() + 36);
h = *reinterpret_cast<const quint32 *>(buf.data() + 40);
}
m_dim = QSize(w, h);
}
} // namespace QmlDesigner

View File

@@ -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 <QImage>
#include <QPixmap>
#include <QSize>
#include <QString>
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