mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-08-26 08:26:59 -04:00
KRA/ORA: merged in a single plugin and added metadata support
- ORA/KRA: merged in a single plugin (KRA) - ORA: removed standalone plugin - KRA: use of logging category - KRA: add metadata support by processing the embedded `documentinfo.xml` - Improved signature lookup (see MR !17) and added test case
This commit is contained in:
+81
-13
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2013 Boudewijn Rempt <[email protected]>
|
||||
SPDX-FileCopyrightText: 2026 Mirco Miranda <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
@@ -8,16 +9,23 @@
|
||||
on public domain. See: http://tulrich.com/geekstuff/
|
||||
*/
|
||||
|
||||
#include "kra.h"
|
||||
#include "kra_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <kzip.h>
|
||||
|
||||
#include <QByteArrayView>
|
||||
#include <QFile>
|
||||
#include <QIODevice>
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
static constexpr char s_magic[] = "application/x-krita";
|
||||
static constexpr int s_magic_size = sizeof(s_magic) - 1; // -1 to remove the last \0
|
||||
Q_DECLARE_LOGGING_CATEGORY(LOG_KRAPLUGIN)
|
||||
Q_LOGGING_CATEGORY(LOG_KRAPLUGIN, "kf.imageformats.plugins.kra", QtWarningMsg)
|
||||
|
||||
#define ORA_MAGIC QByteArrayView("image/openraster")
|
||||
#define KRA_MAGIC QByteArrayView("application/x-krita")
|
||||
|
||||
KraHandler::KraHandler()
|
||||
{
|
||||
@@ -32,6 +40,55 @@ bool KraHandler::canRead() const
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool addMetadata(QImage *image, const QByteArray& rawXml)
|
||||
{
|
||||
if (image == nullptr) {
|
||||
return false;
|
||||
}
|
||||
QXmlStreamReader xml(rawXml);
|
||||
for(QString key; !xml.atEnd();) {
|
||||
auto tt = xml.readNext();
|
||||
if (tt == QXmlStreamReader::StartElement) {
|
||||
key = xml.name().toString().toLower();
|
||||
}
|
||||
else if (tt == QXmlStreamReader::EndElement) {
|
||||
key.clear();
|
||||
}
|
||||
else if (tt == QXmlStreamReader::Characters) {
|
||||
auto text = xml.text().toString().trimmed();
|
||||
if (text.isEmpty() || key.isEmpty())
|
||||
continue;
|
||||
if (key == QStringLiteral("title")) {
|
||||
image->setText(QStringLiteral(META_KEY_TITLE), text);
|
||||
}
|
||||
else if (key == QStringLiteral("abstract")) {
|
||||
image->setText(QStringLiteral(META_KEY_DESCRIPTION), text);
|
||||
}
|
||||
else if (key == QStringLiteral("full-name")) {
|
||||
image->setText(QStringLiteral(META_KEY_AUTHOR), text);
|
||||
}
|
||||
else if (key == QStringLiteral("date")) {
|
||||
if (QDateTime::fromString(text, Qt::ISODate).isValid())
|
||||
image->setText(QStringLiteral(META_KEY_MODIFICATIONDATE), text);
|
||||
}
|
||||
else if (key == QStringLiteral("creation-date")) {
|
||||
if (QDateTime::fromString(text, Qt::ISODate).isValid())
|
||||
image->setText(QStringLiteral(META_KEY_CREATIONDATE), text);
|
||||
}
|
||||
else if (key == QStringLiteral("keyword")) {
|
||||
image->setText(QStringLiteral(META_KEY_KEYWORDS), text);
|
||||
}
|
||||
else if (key == QStringLiteral("license")) {
|
||||
image->setText(QStringLiteral(META_KEY_COPYRIGHT), text);
|
||||
}
|
||||
else {
|
||||
qCDebug(LOG_KRAPLUGIN) << "Unmanaged metadata:" << key << text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !xml.hasError();
|
||||
}
|
||||
|
||||
bool KraHandler::read(QImage *image)
|
||||
{
|
||||
KZip zip(device());
|
||||
@@ -39,14 +96,26 @@ bool KraHandler::read(QImage *image)
|
||||
return false;
|
||||
}
|
||||
|
||||
// reading the image
|
||||
const KArchiveEntry *entry = zip.directory()->entry(QStringLiteral("mergedimage.png"));
|
||||
if (!entry || !entry->isFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const KZipFileEntry *fileZipEntry = static_cast<const KZipFileEntry *>(entry);
|
||||
if (!image->loadFromData(fileZipEntry->data(), "PNG")) {
|
||||
qCCritical(LOG_KRAPLUGIN) << "Invalid image.";
|
||||
return false;
|
||||
}
|
||||
|
||||
image->loadFromData(fileZipEntry->data(), "PNG");
|
||||
// reading metadata
|
||||
const KArchiveEntry *metaEntry = zip.directory()->entry(QStringLiteral("documentinfo.xml"));
|
||||
if (!metaEntry || !metaEntry->isFile()) {
|
||||
return true; // the image is still valid
|
||||
}
|
||||
const KZipFileEntry *metaZipEntry = static_cast<const KZipFileEntry *>(metaEntry);
|
||||
if (!addMetadata(image, metaZipEntry->data())) {
|
||||
qCWarning(LOG_KRAPLUGIN) << "XML metadat seems invalid.";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -54,24 +123,23 @@ bool KraHandler::read(QImage *image)
|
||||
bool KraHandler::canRead(QIODevice *device)
|
||||
{
|
||||
if (!device) {
|
||||
qWarning("KraHandler::canRead() called with no device");
|
||||
qCWarning(LOG_KRAPLUGIN) << "KraHandler::canRead() called with no device";
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buff[57];
|
||||
if (device->peek(buff, sizeof(buff)) == sizeof(buff)) {
|
||||
return memcmp(buff + 0x26, s_magic, s_magic_size) == 0;
|
||||
auto head = device->peek(100);
|
||||
if (!head.startsWith(QByteArrayView("PK"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return head.contains(KRA_MAGIC) || head.contains(ORA_MAGIC);
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities KraPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "kra" || format == "KRA") {
|
||||
if (format == "kra" || format == "ora") {
|
||||
return Capabilities(CanRead);
|
||||
}
|
||||
if (!format.isEmpty()) {
|
||||
@@ -96,4 +164,4 @@ QImageIOHandler *KraPlugin::create(QIODevice *device, const QByteArray &format)
|
||||
return handler;
|
||||
}
|
||||
|
||||
#include "moc_kra.cpp"
|
||||
#include "moc_kra_p.cpp"
|
||||
|
||||
Reference in New Issue
Block a user