Krita Source Code Documentation
Loading...
Searching...
No Matches
KisXMPIO Class Reference

#include <kis_xmp_io.h>

+ Inheritance diagram for KisXMPIO:

Public Member Functions

bool canSaveAllEntries (KisMetaData::Store *) const override
 
QString id () const override
 
 KisXMPIO ()
 
bool loadFrom (KisMetaData::Store *store, QIODevice *ioDevice) const override
 
QString name () const override
 
bool saveTo (const KisMetaData::Store *store, QIODevice *ioDevice, HeaderType headerType=NoHeader) const override
 
bool supportLoading () const override
 
bool supportSaving () const override
 
BackendType type () const override
 
 ~KisXMPIO () override
 

Additional Inherited Members

Detailed Description

Definition at line 15 of file kis_xmp_io.h.

Constructor & Destructor Documentation

◆ KisXMPIO()

KisXMPIO::KisXMPIO ( )

◆ ~KisXMPIO()

KisXMPIO::~KisXMPIO ( )
override

Definition at line 31 of file kis_xmp_io.cpp.

32{
33}

Member Function Documentation

◆ canSaveAllEntries()

bool KisXMPIO::canSaveAllEntries ( KisMetaData::Store * store) const
inlineoverridevirtual
Parameters
storethe list of metadata
Returns
true if this backend is capable of saving all the metadata of the store

Implements KisMetaData::IOBackend.

Definition at line 37 of file kis_xmp_io.h.

38 {
39 return true;
40 }

◆ id()

QString KisXMPIO::id ( ) const
inlineoverridevirtual

Implements KisMetaData::IOBackend.

Definition at line 20 of file kis_xmp_io.h.

21 {
22 return "xmp";
23 }

◆ loadFrom()

bool KisXMPIO::loadFrom ( KisMetaData::Store * store,
QIODevice * ioDevice ) const
overridevirtual
Parameters
storethe list of metadata to load
ioDevicethe device from where the metadata will be loaded
Returns
true if the load was successful

Implements KisMetaData::IOBackend.

Definition at line 220 of file kis_xmp_io.cpp.

221{
222 ioDevice->open(QIODevice::ReadOnly);
223 dbgMetaData << "Load XMP Data";
224 std::string xmpPacket_;
225 QByteArray arr = ioDevice->readAll();
226 xmpPacket_.assign(arr.data(), arr.length());
227 dbgMetaData << xmpPacket_.length();
228 // dbgMetaData << xmpPacket_.c_str();
229 Exiv2::XmpData xmpData_;
230 if (Exiv2::XmpParser::decode(xmpData_, xmpPacket_) != 0) {
231 warnMetaData << "Failed to decode as XMP";
232 return false;
233 }
234 QMap<const KisMetaData::Schema *, QMap<QString, QMap<QString, KisMetaData::Value>>> structures;
235 QMap<const KisMetaData::Schema *, QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>> arraysOfStructures;
236 for (Exiv2::XmpData::iterator it = xmpData_.begin(); it != xmpData_.end(); ++it) {
237 dbgMetaData << "Start iteration" << it->key().c_str();
238
239 Exiv2::XmpKey key(it->key());
240 dbgMetaData << key.groupName().c_str() << " " << key.tagName().c_str() << " " << key.ns().c_str();
241 if ((key.groupName() == "exif" || key.groupName() == "tiff")
242 && key.tagName() == "NativeDigest") { // TODO: someone who has time to lose can look in adding support for
243 // NativeDigest, it's undocumented use by the XMP SDK to check if exif
244 // data has been changed while XMP hasn't been updated
245 dbgMetaData << "dropped";
246 } else {
247 const KisMetaData::Schema *schema =
249 if (!schema) {
250 schema = KisMetaData::SchemaRegistry::instance()->schemaFromUri(key.ns().c_str());
251 if (!schema) {
252 schema = KisMetaData::SchemaRegistry::instance()->create(key.ns().c_str(), key.groupName().c_str());
253 Q_ASSERT(schema);
254 }
255 }
256#if EXIV2_TEST_VERSION(0,28,0)
257 const Exiv2::Value::UniquePtr value = it->getValue();
258#else
259 const Exiv2::Value::AutoPtr value = it->getValue();
260#endif
261 QString structName;
262 int arrayIndex = -1;
263 QString tagName;
264 const KisMetaData::TypeInfo *typeInfo = 0;
265
266 if (!parseTagName(key.tagName().c_str(), structName, arrayIndex, tagName, &typeInfo, schema))
267 continue;
268
269 bool isStructureEntry = !structName.isEmpty() && arrayIndex == -1;
270 bool isStructureInArrayEntry = !structName.isEmpty() && arrayIndex != -1;
271 Q_ASSERT(isStructureEntry != isStructureInArrayEntry || !isStructureEntry);
272
274 bool ignoreValue = false;
275 // Compute the value
276 if (value->typeId() == Exiv2::xmpBag || value->typeId() == Exiv2::xmpSeq
277 || value->typeId() == Exiv2::xmpAlt) {
278 const KisMetaData::TypeInfo *embeddedTypeInfo = 0;
279 if (typeInfo) {
280 embeddedTypeInfo = typeInfo->embeddedPropertyType();
281 }
282 const KisMetaData::Parser *parser = 0;
283 if (embeddedTypeInfo) {
284 parser = embeddedTypeInfo->parser();
285 }
286 const Exiv2::XmpArrayValue *xav = dynamic_cast<const Exiv2::XmpArrayValue *>(value.get());
287 Q_ASSERT(xav);
289#if EXIV2_TEST_VERSION(0,28,0)
290 for (size_t i = 0; i < xav->count(); ++i) {
291#else
292 for (int i = 0; i < xav->count(); ++i) {
293#endif
294 QString value = QString::fromStdString(xav->toString(i));
295 if (parser) {
296 array.push_back(parser->parse(value));
297 } else {
298 dbgImage << "No parser " << tagName;
299 array.push_back(KisMetaData::Value(value));
300 }
301 }
303 switch (xav->xmpArrayType()) {
304 case Exiv2::XmpValue::xaNone:
305 warnKrita << "KisXMPIO: Unsupported array";
306 break;
307 case Exiv2::XmpValue::xaAlt:
309 break;
310 case Exiv2::XmpValue::xaBag:
312 break;
313 case Exiv2::XmpValue::xaSeq:
315 break;
316 }
317 v = KisMetaData::Value(array, vt);
318 } else if (value->typeId() == Exiv2::langAlt) {
319 const Exiv2::LangAltValue *xav = dynamic_cast<const Exiv2::LangAltValue *>(value.get());
320 KIS_ASSERT(xav);
321
323 for (std::map<std::string, std::string>::const_iterator it = xav->value_.begin();
324 it != xav->value_.end();
325 ++it) {
326 KisMetaData::Value valt(it->second.c_str());
327 valt.addPropertyQualifier("xml:lang", KisMetaData::Value(it->first.c_str()));
328 alt.push_back(valt);
329 }
331 } else {
332 QString valTxt = value->toString().c_str();
333 if (typeInfo && typeInfo->parser()) {
334 v = typeInfo->parser()->parse(valTxt);
335 } else {
336 dbgMetaData << "No parser " << tagName;
337 v = KisMetaData::Value(valTxt);
338 }
339 if (valTxt == "type=\"Struct\"") {
340 if (!typeInfo || typeInfo->propertyType() == KisMetaData::TypeInfo::StructureType) {
341 ignoreValue = true;
342 }
343 }
344 }
345
346 // set the value
347 if (isStructureEntry) {
348 structures[schema][structName][tagName] = v;
349 } else if (isStructureInArrayEntry) {
350 if (arraysOfStructures[schema][structName].size() <= arrayIndex) {
351 arraysOfStructures[schema][structName].resize(arrayIndex + 1);
352 }
353
354 if (!arraysOfStructures[schema][structName][arrayIndex].contains(tagName)) {
355 arraysOfStructures[schema][structName][arrayIndex][tagName] = v;
356 } else {
357 warnKrita << "WARNING: trying to overwrite tag" << tagName << "in" << structName << arrayIndex;
358 }
359 } else {
360 if (!ignoreValue) {
361 store->addEntry(KisMetaData::Entry(schema, tagName, v));
362 } else {
363 dbgMetaData << "Ignoring value for " << tagName << " " << v;
364 }
365 }
366 }
367 }
368
369 for (QMap<const KisMetaData::Schema *, QMap<QString, QMap<QString, KisMetaData::Value>>>::iterator it =
370 structures.begin();
371 it != structures.end();
372 ++it) {
373 const KisMetaData::Schema *schema = it.key();
374 for (QMap<QString, QMap<QString, KisMetaData::Value>>::iterator it2 = it.value().begin();
375 it2 != it.value().end();
376 ++it2) {
377 store->addEntry(KisMetaData::Entry(schema, it2.key(), KisMetaData::Value(it2.value())));
378 }
379 }
380 for (QMap<const KisMetaData::Schema *, QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>>::iterator it =
381 arraysOfStructures.begin();
382 it != arraysOfStructures.end();
383 ++it) {
384 const KisMetaData::Schema *schema = it.key();
385 for (QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>::iterator it2 = it.value().begin();
386 it2 != it.value().end();
387 ++it2) {
389 QString entryName = it2.key();
390 if (schema->propertyType(entryName)) {
391 switch (schema->propertyType(entryName)->propertyType()) {
394 break;
397 break;
400 break;
401 default:
403 break;
404 }
405 } else if (store->containsEntry(schema, entryName)) {
406 KisMetaData::Value value = store->getEntry(schema, entryName).value();
407 if (value.isArray()) {
408 type = value.type();
409 }
410 }
411 store->removeEntry(schema, entryName);
414 for (int i = 0; i < it2.value().size(); ++i) {
415 valueList.append(it2.value()[i]);
416 }
417 store->addEntry(KisMetaData::Entry(schema, entryName, KisMetaData::Value(valueList, type)));
418 }
419 }
420 }
421
422 return true;
423}
float value(const T *src, size_t ch)
qreal v
const KisMetaData::Value & value() const
virtual Value parse(const QString &) const =0
static KisMetaData::SchemaRegistry * instance()
const Schema * schemaFromPrefix(const QString &prefix) const
const Schema * schemaFromUri(const QString &uri) const
const KisMetaData::Schema * create(const QString &uri, const QString &prefix)
const TypeInfo * propertyType(const QString &_propertyName) const
void removeEntry(const QString &entryKey)
bool addEntry(const Entry &entry)
bool containsEntry(const QString &entryKey) const
Entry & getEntry(const QString &entryKey)
PropertyType propertyType() const
const Parser * parser() const
const TypeInfo * embeddedPropertyType() const
ValueType
Define the possible value type.
ValueType type() const
BackendType type() const override
Definition kis_xmp_io.h:28
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define warnMetaData
Definition kis_debug.h:103
#define warnKrita
Definition kis_debug.h:87
#define dbgMetaData
Definition kis_debug.h:61
#define dbgImage
Definition kis_debug.h:46
bool parseTagName(const QString &tagString, QString &structName, int &arrayIndex, QString &tagName, const KisMetaData::TypeInfo **typeInfo, const KisMetaData::Schema *schema)
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References KisMetaData::Store::addEntry(), KisMetaData::Value::addPropertyQualifier(), KisMetaData::Value::AlternativeArray, KisMetaData::TypeInfo::AlternativeArrayType, KisMetaData::Store::containsEntry(), KisMetaData::SchemaRegistry::create(), dbgImage, dbgMetaData, KisMetaData::TypeInfo::embeddedPropertyType(), KisMetaData::Store::getEntry(), KisMetaData::SchemaRegistry::instance(), KisMetaData::Value::Invalid, KIS_ASSERT, KisMetaData::Value::LangArray, KisMetaData::Value::OrderedArray, KisMetaData::TypeInfo::OrderedArrayType, KisMetaData::Parser::parse(), KisMetaData::TypeInfo::parser(), parseTagName(), KisMetaData::TypeInfo::propertyType(), KisMetaData::Schema::propertyType(), KisMetaData::Store::removeEntry(), KisMetaData::SchemaRegistry::schemaFromPrefix(), KisMetaData::SchemaRegistry::schemaFromUri(), KisMetaData::TypeInfo::StructureType, KisMetaData::Value::type(), type(), KisMetaData::Value::UnorderedArray, KisMetaData::TypeInfo::UnorderedArrayType, v, KisMetaData::Entry::value(), value(), warnKrita, and warnMetaData.

◆ name()

QString KisXMPIO::name ( ) const
inlineoverridevirtual

Implements KisMetaData::IOBackend.

Definition at line 24 of file kis_xmp_io.h.

25 {
26 return i18n("XMP");
27 }

◆ saveTo()

bool KisXMPIO::saveTo ( const KisMetaData::Store * store,
QIODevice * ioDevice,
HeaderType headerType = NoHeader ) const
overridevirtual
Parameters
storethe list of metadata to save
ioDevicethe device to where the metadata will be saved
headerTypedetermine if an header must be prepend to the binary header, and if it does, which type of header
Returns
true if the save was successful (XXX: actually, all backends always return true...)

Implements KisMetaData::IOBackend.

Definition at line 69 of file kis_xmp_io.cpp.

70{
71 dbgMetaData << "Save XMP Data";
72 Exiv2::XmpData xmpData_;
73
74 for (const KisMetaData::Entry &entry : *store) {
75 // Check whether the prefix and namespace are know to exiv2
76 std::string prefix = exiv2Prefix(entry.schema());
77 dbgMetaData << "Saving " << entry.name();
78
79 const KisMetaData::Value &value = entry.value();
80
81 const KisMetaData::TypeInfo *typeInfo = entry.schema()->propertyType(entry.name());
83 QMap<QString, KisMetaData::Value> structure = value.asStructure();
84 const KisMetaData::Schema *structureSchema = 0;
85 if (typeInfo) {
86 structureSchema = typeInfo->structureSchema();
87 }
88 if (!structureSchema) {
89 dbgMetaData << "Unknown schema for " << entry.name();
90 structureSchema = entry.schema();
91 }
92 Q_ASSERT(structureSchema);
93 saveStructure(xmpData_, entry.name(), prefix, structure, structureSchema);
94 } else {
95 Exiv2::XmpKey key(prefix, entry.name().toLatin1().constData());
96 if (typeInfo
101 // Here is the bad part, again we need to do it by hand
102 Exiv2::XmpTextValue tv;
103 switch (typeInfo->propertyType()) {
105 tv.setXmpArrayType(Exiv2::XmpValue::xaSeq);
106 break;
108 tv.setXmpArrayType(Exiv2::XmpValue::xaBag);
109 break;
111 tv.setXmpArrayType(Exiv2::XmpValue::xaAlt);
112 break;
113 default:
114 // Cannot happen
115 ;
116 }
117 xmpData_.add(key, &tv); // set the array type
118 const KisMetaData::TypeInfo *structureTypeInfo = typeInfo->embeddedPropertyType();
119 const KisMetaData::Schema *structureSchema = 0;
120 if (structureTypeInfo) {
121 structureSchema = structureTypeInfo->structureSchema();
122 }
123 if (!structureSchema) {
124 dbgMetaData << "Unknown schema for " << entry.name();
125 structureSchema = entry.schema();
126 }
127 Q_ASSERT(structureSchema);
128 QList<KisMetaData::Value> array = value.asArray();
129 for (int idx = 0; idx < array.size(); ++idx) {
130 saveStructure(xmpData_,
131 QString("%1[%2]").arg(entry.name()).arg(idx + 1),
132 prefix,
133 array[idx].asStructure(),
134 structureSchema);
135 }
136 } else {
137 dbgMetaData << ppVar(key.key().c_str());
138 Exiv2::Value *v = kmdValueToExivXmpValue(value);
139 if (v) {
140 xmpData_.add(key, v);
141 }
142 }
143 }
144 // TODO property qualifier
145 }
146 // Serialize data
147 std::string xmpPacket_;
148 try {
149 Exiv2::XmpParser::encode(xmpPacket_, xmpData_);
150 } catch (std::exception &e) {
151 warnMetaData << "Couldn't encode the data, error =" << e.what();
152 return false;
153 }
154 // Save data into the IO device
155 ioDevice->open(QIODevice::WriteOnly);
156 if (headerType == KisMetaData::IOBackend::JpegHeader) {
157 xmpPacket_ = "http://ns.adobe.com/xap/1.0/\0" + xmpPacket_;
158 }
159 ioDevice->write(xmpPacket_.c_str(), xmpPacket_.length());
160 return true;
161}
@ JpegHeader
Append Jpeg-style header.
#define ppVar(var)
Definition kis_debug.h:155
Exiv2::Value * kmdValueToExivXmpValue(const KisMetaData::Value &value)
std::string exiv2Prefix(const KisMetaData::Schema *_schema)

References KisMetaData::TypeInfo::AlternativeArrayType, dbgMetaData, KisMetaData::TypeInfo::embeddedPropertyType(), exiv2Prefix(), KisMetaData::IOBackend::JpegHeader, kmdValueToExivXmpValue(), KisMetaData::TypeInfo::OrderedArrayType, ppVar, KisMetaData::TypeInfo::propertyType(), KisMetaData::Value::Structure, KisMetaData::TypeInfo::structureSchema(), KisMetaData::TypeInfo::StructureType, KisMetaData::TypeInfo::UnorderedArrayType, v, value(), and warnMetaData.

◆ supportLoading()

bool KisXMPIO::supportLoading ( ) const
inlineoverridevirtual
Returns
true if this backend support loading

Implements KisMetaData::IOBackend.

Definition at line 41 of file kis_xmp_io.h.

42 {
43 return true;
44 }

◆ supportSaving()

bool KisXMPIO::supportSaving ( ) const
inlineoverridevirtual
Returns
tell if this backend support saving

Implements KisMetaData::IOBackend.

Definition at line 32 of file kis_xmp_io.h.

33 {
34 return true;
35 }

◆ type()

BackendType KisXMPIO::type ( ) const
inlineoverridevirtual
Returns
the type of the backend

Implements KisMetaData::IOBackend.

Definition at line 28 of file kis_xmp_io.h.

29 {
30 return Text;
31 }

References KisMetaData::IOBackend::Text.


The documentation for this class was generated from the following files: