JXL: Resolution and metadata support via EXIF

- Added a class to read and write minimal exif metadata.
- JXL plugin uses EXIF metadata to load/save the resolution of the image (like GIMP).
- JXL plugin uses EXIF metadata to set/store text metadata and date/time.
- Enable info display in Dolphin (JXL File -> Properties -> Details on a JXL file, see image below).
- Enabled read test to check also image metadata and resolution.

![_52C044E4-1BA9-4D84-AC0A-B834CDAF72D8_](/uploads/f1649c2b506bf61a5f5488da0d4a4534/_52C044E4-1BA9-4D84-AC0A-B834CDAF72D8_.png){width=401 height=357}
This commit is contained in:
Mirco Miranda
2025-01-15 06:12:07 +00:00
parent f39ca9dc9b
commit ae00c110f2
11 changed files with 1821 additions and 79 deletions

View File

@ -12,6 +12,49 @@
#include <QJsonObject>
#include <QVersionNumber>
static QJsonObject searchObject(const QFileInfo& file)
{
auto fi = QFileInfo(QStringLiteral("%1.json").arg(file.filePath()));
if (!fi.exists()) {
return {};
}
QFile f(fi.filePath());
if (!f.open(QFile::ReadOnly)) {
return {};
}
QJsonParseError err;
auto doc = QJsonDocument::fromJson(f.readAll(), &err);
if (err.error != QJsonParseError::NoError || !doc.isArray()) {
return {};
}
auto currentQt = QVersionNumber::fromString(qVersion());
auto arr = doc.array();
for (auto val : arr) {
if (!val.isObject())
continue;
auto obj = val.toObject();
auto minQt = QVersionNumber::fromString(obj.value("minQtVersion").toString());
auto maxQt = QVersionNumber::fromString(obj.value("maxQtVersion").toString());
auto name = obj.value("fileName").toString();
auto unsupportedFormat = obj.value("unsupportedFormat").toBool();
// filter
if (name.isEmpty() && !unsupportedFormat)
continue;
if (!minQt.isNull() && currentQt < minQt)
continue;
if (!maxQt.isNull() && currentQt > maxQt)
continue;
return obj;
}
return {};
}
TemplateImage::TemplateImage(const QFileInfo &fi) :
m_fi(fi)
{
@ -45,6 +88,43 @@ QFileInfo TemplateImage::compareImage(TestFlags &flags, QString& comment) const
return legacyImage();
}
bool TemplateImage::checkOptionaInfo(const QImage& image, QString& error) const
{
auto obj = searchObject(m_fi);
if (obj.isEmpty()) {
return true;
}
// Test resolution
auto res = obj.value("resolution").toObject();
if (!res.isEmpty()) {
auto resx = res.value("dotsPerMeterX").toInt();
auto resy = res.value("dotsPerMeterY").toInt();
if (resx != image.dotsPerMeterX()) {
error = QStringLiteral("X resolution mismatch (current: %1, expected: %2)!").arg(image.dotsPerMeterX()).arg(resx);
return false;
}
if (resy != image.dotsPerMeterY()) {
error = QStringLiteral("Y resolution mismatch (current: %1, expected: %2)!").arg(image.dotsPerMeterY()).arg(resy);
return false;
}
}
// Test metadata
auto meta = obj.value("metadata").toArray();
for (auto jv : meta) {
auto obj = jv.toObject();
auto key = obj.value("Key").toString();
auto val = obj.value("Value").toString();
auto cur = image.text(key);
if (cur != val) {
error = QStringLiteral("Metadata '%1' mismatch (current: '%2', expected:'%3')!").arg(key, cur, val);
return false;
}
}
return true;
}
QStringList TemplateImage::suffixes()
{
@ -66,51 +146,25 @@ QFileInfo TemplateImage::legacyImage() const
QFileInfo TemplateImage::jsonImage(TestFlags &flags, QString& comment) const
{
flags = TestFlag::None;
auto fi = QFileInfo(QStringLiteral("%1.json").arg(m_fi.filePath()));
if (!fi.exists()) {
auto obj = searchObject(m_fi);
if (obj.isEmpty()) {
return {};
}
QFile f(fi.filePath());
if (!f.open(QFile::ReadOnly)) {
auto name = obj.value("fileName").toString();
auto unsupportedFormat = obj.value("unsupportedFormat").toBool();
comment = obj.value("comment").toString();
if(obj.value("disableAutoTransform").toBool()) {
flags |= TestFlag::DisableAutotransform;
}
if (unsupportedFormat) {
flags |= TestFlag::SkipTest;
return {};
}
QJsonParseError err;
auto doc = QJsonDocument::fromJson(f.readAll(), &err);
if (err.error != QJsonParseError::NoError || !doc.isArray()) {
return {};
}
auto currentQt = QVersionNumber::fromString(qVersion());
auto arr = doc.array();
for (auto val : arr) {
if (!val.isObject())
continue;
auto obj = val.toObject();
auto minQt = QVersionNumber::fromString(obj.value("minQtVersion").toString());
auto maxQt = QVersionNumber::fromString(obj.value("maxQtVersion").toString());
auto name = obj.value("fileName").toString();
auto unsupportedFormat = obj.value("unsupportedFormat").toBool();
comment = obj.value("comment").toString();
if(obj.value("disableAutoTransform").toBool())
flags |= TestFlag::DisableAutotransform;
// filter
if (name.isEmpty() && !unsupportedFormat)
continue;
if (!minQt.isNull() && currentQt < minQt)
continue;
if (!maxQt.isNull() && currentQt > maxQt)
continue;
if (unsupportedFormat) {
flags |= TestFlag::SkipTest;
break;
}
return QFileInfo(QStringLiteral("%1/%2").arg(fi.path(), name));
}
return {};
return QFileInfo(QStringLiteral("%1/%2").arg(m_fi.path(), name));
}