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 230 of file kis_xmp_io.cpp.

231{
232 ioDevice->open(QIODevice::ReadOnly);
233 dbgMetaData << "Load XMP Data";
234 std::string xmpPacket_;
235 QByteArray arr = ioDevice->readAll();
236 xmpPacket_.assign(arr.data(), arr.length());
237 dbgMetaData << xmpPacket_.length();
238 // dbgMetaData << xmpPacket_.c_str();
239 Exiv2::XmpData xmpData_;
240 if (Exiv2::XmpParser::decode(xmpData_, xmpPacket_) != 0) {
241 warnMetaData << "Failed to decode as XMP";
242 return false;
243 }
244 QMap<const KisMetaData::Schema *, QMap<QString, QMap<QString, KisMetaData::Value>>> structures;
245 QMap<const KisMetaData::Schema *, QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>> arraysOfStructures;
246 for (Exiv2::XmpData::iterator it = xmpData_.begin(); it != xmpData_.end(); ++it) {
247 dbgMetaData << "Start iteration" << it->key().c_str();
248
249 Exiv2::XmpKey key(it->key());
250 dbgMetaData << key.groupName().c_str() << " " << key.tagName().c_str() << " " << key.ns().c_str();
251 if ((key.groupName() == "exif" || key.groupName() == "tiff")
252 && key.tagName() == "NativeDigest") { // TODO: someone who has time to lose can look in adding support for
253 // NativeDigest, it's undocumented use by the XMP SDK to check if exif
254 // data has been changed while XMP hasn't been updated
255 dbgMetaData << "dropped";
256 } else {
257 const KisMetaData::Schema *schema =
259 if (!schema) {
260 schema = KisMetaData::SchemaRegistry::instance()->schemaFromUri(key.ns().c_str());
261 if (!schema) {
262 schema = KisMetaData::SchemaRegistry::instance()->create(key.ns().c_str(), key.groupName().c_str());
263 Q_ASSERT(schema);
264 }
265 }
266#if EXIV2_TEST_VERSION(0,28,0)
267 const Exiv2::Value::UniquePtr value = it->getValue();
268#else
269 const Exiv2::Value::AutoPtr value = it->getValue();
270#endif
271 QString structName;
272 int arrayIndex = -1;
273 QString tagName;
274 const KisMetaData::TypeInfo *typeInfo = 0;
275
276 if (!parseTagName(key.tagName().c_str(), structName, arrayIndex, tagName, &typeInfo, schema))
277 continue;
278
279 bool isStructureEntry = !structName.isEmpty() && arrayIndex == -1;
280 bool isStructureInArrayEntry = !structName.isEmpty() && arrayIndex != -1;
281 Q_ASSERT(isStructureEntry != isStructureInArrayEntry || !isStructureEntry);
282
284 bool ignoreValue = false;
285 // Compute the value
286 if (value->typeId() == Exiv2::xmpBag || value->typeId() == Exiv2::xmpSeq
287 || value->typeId() == Exiv2::xmpAlt) {
288 const KisMetaData::TypeInfo *embeddedTypeInfo = 0;
289 if (typeInfo) {
290 embeddedTypeInfo = typeInfo->embeddedPropertyType();
291 }
292 const KisMetaData::Parser *parser = 0;
293 if (embeddedTypeInfo) {
294 parser = embeddedTypeInfo->parser();
295 }
296 const Exiv2::XmpArrayValue *xav = dynamic_cast<const Exiv2::XmpArrayValue *>(value.get());
297 Q_ASSERT(xav);
299#if EXIV2_TEST_VERSION(0,28,0)
300 for (size_t i = 0; i < xav->count(); ++i) {
301#else
302 for (int i = 0; i < xav->count(); ++i) {
303#endif
304 QString value = QString::fromStdString(xav->toString(i));
305 if (parser) {
306 array.push_back(parser->parse(value));
307 } else {
308 dbgImage << "No parser " << tagName;
309 array.push_back(KisMetaData::Value(value));
310 }
311 }
313 switch (xav->xmpArrayType()) {
314 case Exiv2::XmpValue::xaNone:
315 warnKrita << "KisXMPIO: Unsupported array";
316 break;
317 case Exiv2::XmpValue::xaAlt:
319 break;
320 case Exiv2::XmpValue::xaBag:
322 break;
323 case Exiv2::XmpValue::xaSeq:
325 break;
326 }
327 v = KisMetaData::Value(array, vt);
328 } else if (value->typeId() == Exiv2::langAlt) {
329 const Exiv2::LangAltValue *xav = dynamic_cast<const Exiv2::LangAltValue *>(value.get());
330 KIS_ASSERT(xav);
331
333 for (std::map<std::string, std::string>::const_iterator it = xav->value_.begin();
334 it != xav->value_.end();
335 ++it) {
336 KisMetaData::Value valt(it->second.c_str());
337 valt.addPropertyQualifier("xml:lang", KisMetaData::Value(it->first.c_str()));
338 alt.push_back(valt);
339 }
341 } else {
342 QString valTxt = value->toString().c_str();
343 if (typeInfo && typeInfo->parser()) {
344 v = typeInfo->parser()->parse(valTxt);
345 } else {
346 dbgMetaData << "No parser " << tagName;
347 v = KisMetaData::Value(valTxt);
348 }
349 if (valTxt == "type=\"Struct\"") {
350 if (!typeInfo || typeInfo->propertyType() == KisMetaData::TypeInfo::StructureType) {
351 ignoreValue = true;
352 }
353 }
354 }
355
356 // set the value
357 if (isStructureEntry) {
358 structures[schema][structName][tagName] = v;
359 } else if (isStructureInArrayEntry) {
360 if (arraysOfStructures[schema][structName].size() <= arrayIndex) {
361 arraysOfStructures[schema][structName].resize(arrayIndex + 1);
362 }
363
364 if (!arraysOfStructures[schema][structName][arrayIndex].contains(tagName)) {
365 arraysOfStructures[schema][structName][arrayIndex][tagName] = v;
366 } else {
367 warnKrita << "WARNING: trying to overwrite tag" << tagName << "in" << structName << arrayIndex;
368 }
369 } else {
370 if (!ignoreValue) {
371 store->addEntry(KisMetaData::Entry(schema, tagName, v));
372 } else {
373 dbgMetaData << "Ignoring value for " << tagName << " " << v;
374 }
375 }
376 }
377 }
378
379 for (QMap<const KisMetaData::Schema *, QMap<QString, QMap<QString, KisMetaData::Value>>>::iterator it =
380 structures.begin();
381 it != structures.end();
382 ++it) {
383 const KisMetaData::Schema *schema = it.key();
384 for (QMap<QString, QMap<QString, KisMetaData::Value>>::iterator it2 = it.value().begin();
385 it2 != it.value().end();
386 ++it2) {
387 store->addEntry(KisMetaData::Entry(schema, it2.key(), KisMetaData::Value(it2.value())));
388 }
389 }
390 for (QMap<const KisMetaData::Schema *, QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>>::iterator it =
391 arraysOfStructures.begin();
392 it != arraysOfStructures.end();
393 ++it) {
394 const KisMetaData::Schema *schema = it.key();
395 for (QMap<QString, QVector<QMap<QString, KisMetaData::Value>>>::iterator it2 = it.value().begin();
396 it2 != it.value().end();
397 ++it2) {
399 QString entryName = it2.key();
400 if (schema->propertyType(entryName)) {
401 switch (schema->propertyType(entryName)->propertyType()) {
404 break;
407 break;
410 break;
411 default:
413 break;
414 }
415 } else if (store->containsEntry(schema, entryName)) {
416 KisMetaData::Value value = store->getEntry(schema, entryName).value();
417 if (value.isArray()) {
418 type = value.type();
419 }
420 }
421 store->removeEntry(schema, entryName);
424 for (int i = 0; i < it2.value().size(); ++i) {
425 valueList.append(it2.value()[i]);
426 }
427 store->addEntry(KisMetaData::Entry(schema, entryName, KisMetaData::Value(valueList, type)));
428 }
429 }
430 }
431
432 return true;
433}
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: