KFileMetaData

kritaextractor.cpp
1/*
2 SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7
8#include "kritaextractor.h"
9#include "kfilemetadata_debug.h"
10
11#include <KZip>
12#include <QXmlStreamReader>
13
14using namespace KFileMetaData;
15
16KritaExtractor::KritaExtractor(QObject* parent)
17 : ExtractorPlugin(parent)
18{
19}
20
21QStringList KritaExtractor::mimetypes() const
22{
23 return {QStringLiteral("application/x-krita")};
24}
25
26void KritaExtractor::extract(ExtractionResult* result)
27{
28 // Krita files are secretly zip files
29 KZip zip(result->inputUrl());
30 if (!zip.open(QIODevice::ReadOnly)) {
31 return;
32 }
33
34 result->addType(Type::Image);
35
36 if (!result->inputFlags().testFlag(ExtractionResult::ExtractMetaData)) {
37 return;
38 }
39
40 // Read main image information, e.g width and height
41 {
42 const KArchiveFile *entry = zip.directory()->file(QLatin1String("maindoc.xml"));
43 if (!entry) {
44 return;
45 }
46
47 std::unique_ptr<QIODevice> fileDevice{entry->createDevice()};
48
49 // There is only one element of the maindoc we care about: the IMAGE element.
50 // The document width and height are stored as attributes.
51 QXmlStreamReader xml{fileDevice.get()};
52 while (xml.readNextStartElement()) {
53 if (xml.name() == QLatin1String("IMAGE")) {
54 bool ok = false;
55 const int width = xml.attributes().value(QLatin1String("width")).toInt(&ok);
56 if (ok && width != 0) {
57 result->add(Property::Width, width);
58 }
59
60 const int height = xml.attributes().value(QLatin1String("height")).toInt(&ok);
61 if (ok && height != 0) {
62 result->add(Property::Height, height);
63 }
64
65 break;
66 }
67 }
68 }
69
70 // Read extra metadata entered by the author, e.g. title and description
71 {
72 const KArchiveFile *entry = zip.directory()->file(QLatin1String("documentinfo.xml"));
73 if (!entry) {
74 return;
75 }
76
77 std::unique_ptr<QIODevice> fileDevice{entry->createDevice()};
78
79 // The documentinfo xml schema is very simple, every field in the GUI is exposed
80 // as an element of the same name. The one exception is "description" which seems
81 // to be stored under <abstract>.
82 static const QHash<QStringView, Property::Property> propertyMapping {{
83 {QStringLiteral("title"), Property::Title},
84 {QStringLiteral("license"), Property::License},
85 {QStringLiteral("keyword"), Property::Keywords},
86 {QStringLiteral("abstract"), Property::Description},
87 }};
88
89 QXmlStreamReader xml{fileDevice.get()};
90 if (!xml.readNextStartElement() || xml.name() != QStringLiteral("document-info")) {
91 return;
92 }
93
94 while (xml.readNextStartElement()) {
95 const QStringView elementName = xml.name();
96
97 if (elementName == QStringLiteral("about")) {
98 while (xml.readNextStartElement()) {
99 const QStringView childElementName = xml.name();
100
101 const Property::Property property = propertyMapping.value(childElementName);
102 if (property != Property::Empty) {
103 const QString value = xml.readElementText();
104 result->add(property, value);
105 } else if (childElementName == QStringLiteral("creation-date")) {
106 const QString value = xml.readElementText();
107
108 const QDateTime creationDate = QDateTime::fromString(value, Qt::ISODate);
109 if (creationDate.isValid()) {
110 result->add(Property::CreationDate, creationDate);
111 }
112 } else {
113 xml.skipCurrentElement();
114 }
115 }
116 } else if (elementName == QStringLiteral("author")) {
117 while (xml.readNextStartElement()) {
118 const QStringView childElementName = xml.name();
119
120 if (childElementName == QStringLiteral("full-name")) {
121 const QString value = xml.readElementText();
122 if (!value.isEmpty()) {
123 result->add(Property::Author, value);
124 }
125 } else {
126 xml.skipCurrentElement();
127 }
128 }
129 } else {
130 xml.skipCurrentElement();
131 }
132 }
133 }
134}
135
136#include "moc_kritaextractor.cpp"
virtual QIODevice * createDevice() const
The ExtractionResult class is where all the data extracted by the indexer is saved.
QString inputUrl() const
The input URL which the plugins will use to locate the file.
virtual void addType(Type::Type type)=0
This function is called by the plugins.
virtual void add(Property::Property property, const QVariant &value)=0
This function is called by the plugins when they wish to add a key value pair which should be indexed...
Flags inputFlags() const
The flags which the extraction plugin should considering following when extracting metadata from the ...
The ExtractorPlugin is the base class for all file metadata extractors.
Property
The Property enum contains all files property types that KFileMetaData manipulates.
Definition properties.h:26
@ Width
Represents the width of the Media in pixels.
Definition properties.h:189
@ Title
Refers to the Title of the content of the file.
Definition properties.h:121
@ Author
The Author field indicated the primary creator of a document.
Definition properties.h:114
@ Height
Represents the height of the Media in pixels.
Definition properties.h:195
@ Description
Represents the description stored in the file.
Definition properties.h:351
@ CreationDate
The date the content of the file was created.
Definition properties.h:177
@ License
Contains the license information of the file.
Definition properties.h:318
@ Keywords
The keywords used to represent the document.
Definition properties.h:183
@ Image
Any Image file.
Definition types.h:56
The KFileMetaData namespace.
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
bool isValid() const const
bool testFlag(Enum flag) const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:48:41 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.