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

#include <kis_exif_io.h>

+ Inheritance diagram for KisExifIO:

Public Member Functions

bool canSaveAllEntries (KisMetaData::Store *store) const override
 
QString id () const override
 
 KisExifIO ()
 
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
 
 ~KisExifIO () override
 

Additional Inherited Members

Detailed Description

Definition at line 17 of file kis_exif_io.h.

Constructor & Destructor Documentation

◆ KisExifIO()

KisExifIO::KisExifIO ( )

Definition at line 409 of file kis_exif_io.cpp.

◆ ~KisExifIO()

KisExifIO::~KisExifIO ( )
override

Definition at line 414 of file kis_exif_io.cpp.

415{
416}

Member Function Documentation

◆ canSaveAllEntries()

bool KisExifIO::canSaveAllEntries ( KisMetaData::Store * store) const
overridevirtual
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 554 of file kis_exif_io.cpp.

555{
556 return false; // It's a known fact that exif can't save all information, but TODO: write the check
557}

◆ id()

QString KisExifIO::id ( ) const
inlineoverridevirtual

Implements KisMetaData::IOBackend.

Definition at line 22 of file kis_exif_io.h.

23 {
24 return "exif";
25 }

◆ loadFrom()

bool KisExifIO::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 559 of file kis_exif_io.cpp.

560{
561 if (!ioDevice->open(QIODevice::ReadOnly)) {
562 return false;
563 }
564 QByteArray arr(ioDevice->readAll());
565 Exiv2::ExifData exifData;
566 Exiv2::ByteOrder byteOrder;
567#if !EXIV2_TEST_VERSION(0, 18, 0)
568 exifData.load((const Exiv2::byte *)arr.data(), arr.size());
569 byteOrder = exifData.byteOrder();
570#else
571 try {
572 byteOrder =
573 Exiv2::ExifParser::decode(exifData, (const Exiv2::byte *)arr.data(), static_cast<uint32_t>(arr.size()));
574 } catch (const std::exception &ex) {
575 warnKrita << "Received exception trying to parse exiv data" << ex.what();
576 return false;
577 } catch (...) {
578 dbgKrita << "Received unknown exception trying to parse exiv data";
579 return false;
580 }
581#endif
582 dbgMetaData << "Byte order = " << byteOrder << ppVar(Exiv2::bigEndian) << ppVar(Exiv2::littleEndian);
583 dbgMetaData << "There are" << exifData.count() << " entries in the exif section";
584 const KisMetaData::Schema *tiffSchema =
586 Q_ASSERT(tiffSchema);
587 const KisMetaData::Schema *exifSchema =
589 Q_ASSERT(exifSchema);
590 const KisMetaData::Schema *dcSchema =
592 Q_ASSERT(dcSchema);
593 const KisMetaData::Schema *xmpSchema =
595 Q_ASSERT(xmpSchema);
596 const KisMetaData::Schema *makerNoteSchema =
598 Q_ASSERT(makerNoteSchema);
599
600 for (const Exiv2::Exifdatum &it : exifData) {
601 const uint16_t tag = it.tag();
602
605 || it.tagName() == "0x0000") {
606 dbgMetaData << it.key().c_str() << " is ignored";
607 } else if (tag == Exif::Photo::MakerNote) {
608 store->addEntry({makerNoteSchema, "RawData", exivValueToKMDValue(it.getValue(), false)});
609 } else if (tag == Exif::Image::DateTime) { // load as xmp:ModifyDate
610 store->addEntry({xmpSchema, "ModifyDate", exivValueToKMDValue(it.getValue(), false)});
611 } else if (tag == Exif::Image::ImageDescription) { // load as "dc:description"
612 store->addEntry({dcSchema, "description", exivValueToKMDValue(it.getValue(), false)});
613 } else if (tag == Exif::Image::Software) { // load as "xmp:CreatorTool"
614 store->addEntry({xmpSchema, "CreatorTool", exivValueToKMDValue(it.getValue(), false)});
615 } else if (tag == Exif::Image::Artist) { // load as dc:creator
616 QList<KisMetaData::Value> creators = {exivValueToKMDValue(it.getValue(), false)};
617 store->addEntry({dcSchema, "creator", {creators, KisMetaData::Value::OrderedArray}});
618 } else if (tag == Exif::Image::Copyright) { // load as dc:rights
619 store->addEntry({dcSchema, "rights", exivValueToKMDValue(it.getValue(), false)});
620 } else if (it.groupName() == "Image") {
621 // Tiff tags
622 const QString fixedTN(it.tagName().c_str());
623 if (tag == Exif::Image::ExifTag || tag == Exif::Image::GPSTag) {
624 dbgMetaData << "Ignoring " << it.key().c_str();
625 } else if (KisMetaData::Entry::isValidName(fixedTN)) {
626 store->addEntry({tiffSchema, fixedTN, exivValueToKMDValue(it.getValue(), false)});
627 } else {
628 dbgMetaData << "Invalid tag name: " << fixedTN;
629 }
630 } else if (it.groupName() == "Photo") {
631 // Exif tags
632 KisMetaData::Value metaDataValue;
634 metaDataValue = exifVersionToKMDValue(it.getValue());
635 } else if (tag == Exif::Photo::FileSource) {
636 metaDataValue = KisMetaData::Value(3);
637 } else if (tag == Exif::Photo::SceneType) {
638 metaDataValue = KisMetaData::Value(1);
639 } else if (tag == Exif::Photo::ComponentsConfiguration) {
640 metaDataValue = exifArrayToKMDIntOrderedArray(it.getValue());
641 } else if (tag == Exif::Photo::OECF) {
642 metaDataValue = exifOECFToKMDOECFStructure(it.getValue(), byteOrder);
644 metaDataValue = exivValueToKMDValue(it.getValue(), false);
645 } else if (tag == Exif::Photo::DeviceSettingDescription) {
646 metaDataValue = deviceSettingDescriptionExifToKMD(it.getValue());
647 } else if (tag == Exif::Photo::CFAPattern) {
648 metaDataValue = cfaPatternExifToKMD(it.getValue(), byteOrder);
649 } else if (tag == Exif::Photo::Flash) {
650 metaDataValue = flashExifToKMD(it.getValue());
651 } else if (tag == Exif::Photo::UserComment) {
652 if (it.getValue()->typeId() != Exiv2::undefined) {
653 KisMetaData::Value vUC = exivValueToKMDValue(it.getValue(), false);
654 Q_ASSERT(vUC.type() == KisMetaData::Value::Variant);
655 QVariant commentVar = vUC.asVariant();
656 QString comment;
657 if (commentVar.type() == QVariant::String) {
658 comment = commentVar.toString();
659 } else if (commentVar.type() == QVariant::ByteArray) {
660 const QByteArray commentString = commentVar.toByteArray();
661 comment = QString::fromLatin1(commentString.constData(), commentString.size());
662 } else {
663 warnKrita << "KisExifIO: Unhandled UserComment value type.";
664 }
665 KisMetaData::Value vcomment(comment);
666 vcomment.addPropertyQualifier("xml:lang", KisMetaData::Value("x-default"));
668 alt.append(vcomment);
670 }
671 } else {
672 bool forceSeq = false;
674 if (tag == Exif::Photo::ISOSpeedRatings) {
675 forceSeq = true;
677 }
678 metaDataValue = exivValueToKMDValue(it.getValue(), forceSeq, arrayType);
679 }
680 if (tag == Exif::Photo::InteroperabilityTag || tag == 0xea1d
681 || metaDataValue.type() == KisMetaData::Value::Invalid) { // InteroperabilityTag isn't useful for XMP,
682 // 0xea1d isn't a valid Exif tag
683 warnMetaData << "Ignoring " << it.key().c_str();
684
685 } else {
686 store->addEntry({exifSchema, it.tagName().c_str(), metaDataValue});
687 }
688 } else if (it.groupName() == "Thumbnail") {
689 dbgMetaData << "Ignoring thumbnail tag :" << it.key().c_str();
690 } else if (it.groupName() == "GPSInfo") {
691 store->addEntry({exifSchema, it.tagName().c_str(), exivValueToKMDValue(it.getValue(), false)});
692 } else {
693 dbgMetaData << "Unknown exif tag, cannot load:" << it.key().c_str();
694 }
695 }
696 ioDevice->close();
697 return true;
698}
static bool isValidName(const QString &_name)
static KisMetaData::SchemaRegistry * instance()
const Schema * schemaFromUri(const QString &uri) const
static const QString TIFFSchemaUri
static const QString DublinCoreSchemaUri
static const QString EXIFSchemaUri
static const QString XMPSchemaUri
static const QString MakerNoteSchemaUri
bool addEntry(const Entry &entry)
QVariant asVariant() const
ValueType
Define the possible value type.
ValueType type() const
#define dbgKrita
Definition kis_debug.h:45
#define warnMetaData
Definition kis_debug.h:103
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
#define dbgMetaData
Definition kis_debug.h:61
KisMetaData::Value deviceSettingDescriptionExifToKMD(const Exiv2::Value::AutoPtr value)
KisMetaData::Value exifOECFToKMDOECFStructure(const Exiv2::Value::AutoPtr value, Exiv2::ByteOrder order)
KisMetaData::Value exifArrayToKMDIntOrderedArray(const Exiv2::Value::AutoPtr value)
KisMetaData::Value cfaPatternExifToKMD(const Exiv2::Value::AutoPtr value, Exiv2::ByteOrder order)
KisMetaData::Value flashExifToKMD(const Exiv2::Value::AutoPtr value)
KisMetaData::Value exifVersionToKMDValue(const Exiv2::Value::AutoPtr value)
KisMetaData::Value exivValueToKMDValue(const Exiv2::Value::AutoPtr &value, bool forceSeq, KisMetaData::Value::ValueType arrayType=KisMetaData::Value::UnorderedArray)
const uint16_t DateTime
const uint16_t StripByteCounts
const uint16_t RowsPerStrip
const uint16_t StripOffsets
const uint16_t JPEGInterchangeFormat
const uint16_t ImageDescription
const uint16_t GPSTag
const uint16_t ExifTag
const uint16_t JPEGInterchangeFormatLength
const uint16_t Copyright
const uint16_t Artist
const uint16_t Software
const uint16_t DateTimeDigitized
const uint16_t UserComment
const uint16_t DeviceSettingDescription
const uint16_t ComponentsConfiguration
const uint16_t FileSource
const uint16_t FlashpixVersion
const uint16_t SceneType
const uint16_t Flash
const uint16_t CFAPattern
const uint16_t ISOSpeedRatings
const uint16_t InteroperabilityTag
const uint16_t ExifVersion
const uint16_t MakerNote
const uint16_t DateTimeOriginal
const uint16_t OECF

References KisMetaData::Store::addEntry(), KisMetaData::Value::addPropertyQualifier(), Exif::Image::Artist, KisMetaData::Value::asVariant(), Exif::Photo::CFAPattern, cfaPatternExifToKMD(), Exif::Photo::ComponentsConfiguration, Exif::Image::Copyright, Exif::Image::DateTime, Exif::Photo::DateTimeDigitized, Exif::Photo::DateTimeOriginal, dbgKrita, dbgMetaData, Exif::Photo::DeviceSettingDescription, deviceSettingDescriptionExifToKMD(), KisMetaData::Schema::DublinCoreSchemaUri, exifArrayToKMDIntOrderedArray(), exifOECFToKMDOECFStructure(), KisMetaData::Schema::EXIFSchemaUri, Exif::Image::ExifTag, Exif::Photo::ExifVersion, exifVersionToKMDValue(), exivValueToKMDValue(), Exif::Photo::FileSource, Exif::Photo::Flash, flashExifToKMD(), Exif::Photo::FlashpixVersion, Exif::Image::GPSTag, Exif::Image::ImageDescription, KisMetaData::SchemaRegistry::instance(), Exif::Photo::InteroperabilityTag, KisMetaData::Value::Invalid, Exif::Photo::ISOSpeedRatings, KisMetaData::Entry::isValidName(), Exif::Image::JPEGInterchangeFormat, Exif::Image::JPEGInterchangeFormatLength, KisMetaData::Value::LangArray, Exif::Photo::MakerNote, KisMetaData::Schema::MakerNoteSchemaUri, Exif::Photo::OECF, KisMetaData::Value::OrderedArray, ppVar, Exif::Image::RowsPerStrip, Exif::Photo::SceneType, KisMetaData::SchemaRegistry::schemaFromUri(), Exif::Image::Software, Exif::Image::StripByteCounts, Exif::Image::StripOffsets, KisMetaData::Schema::TIFFSchemaUri, KisMetaData::Value::type(), KisMetaData::Value::UnorderedArray, Exif::Photo::UserComment, KisMetaData::Value::Variant, warnKrita, warnMetaData, and KisMetaData::Schema::XMPSchemaUri.

◆ name()

QString KisExifIO::name ( ) const
inlineoverridevirtual

Implements KisMetaData::IOBackend.

Definition at line 26 of file kis_exif_io.h.

27 {
28 return i18n("Exif");
29 }

◆ saveTo()

bool KisExifIO::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 418 of file kis_exif_io.cpp.

419{
420 ioDevice->open(QIODevice::WriteOnly);
421 Exiv2::ExifData exifData;
422 if (headerType == KisMetaData::IOBackend::JpegHeader) {
423 QByteArray header(6, 0);
424 header[0] = 0x45;
425 header[1] = 0x78;
426 header[2] = 0x69;
427 header[3] = 0x66;
428 header[4] = 0x00;
429 header[5] = 0x00;
430 ioDevice->write(header);
431 }
432
433 for (const KisMetaData::Entry &entry : *store) {
434 try {
435 dbgMetaData << "Trying to save: " << entry.name() << " of " << entry.schema()->prefix() << ":"
436 << entry.schema()->uri();
437 QString exivKey;
438 if (entry.schema()->uri() == KisMetaData::Schema::TIFFSchemaUri) {
439 exivKey = "Exif.Image." + entry.name();
440 } else if (entry.schema()->uri()
441 == KisMetaData::Schema::EXIFSchemaUri) { // Distinguish between exif and gps
442 if (entry.name().left(3) == "GPS") {
443 exivKey = "Exif.GPSInfo." + entry.name();
444 } else {
445 exivKey = "Exif.Photo." + entry.name();
446 }
447 } else if (entry.schema()->uri() == KisMetaData::Schema::DublinCoreSchemaUri) {
448 if (entry.name() == "description") {
449 exivKey = "Exif.Image.ImageDescription";
450 } else if (entry.name() == "creator") {
451 exivKey = "Exif.Image.Artist";
452 } else if (entry.name() == "rights") {
453 exivKey = "Exif.Image.Copyright";
454 }
455 } else if (entry.schema()->uri() == KisMetaData::Schema::XMPSchemaUri) {
456 if (entry.name() == "ModifyDate") {
457 exivKey = "Exif.Image.DateTime";
458 } else if (entry.name() == "CreatorTool") {
459 exivKey = "Exif.Image.Software";
460 }
461 } else if (entry.schema()->uri() == KisMetaData::Schema::MakerNoteSchemaUri) {
462 if (entry.name() == "RawData") {
463 exivKey = "Exif.Photo.MakerNote";
464 }
465 }
466 dbgMetaData << "Saving " << entry.name() << " to " << exivKey;
467 if (exivKey.isEmpty()) {
468 dbgMetaData << entry.qualifiedName() << " is unsavable to EXIF";
469 } else {
470 Exiv2::ExifKey exifKey(qPrintable(exivKey));
471 Exiv2::Value *v = 0;
472 if (exivKey == "Exif.Photo.ExifVersion" || exivKey == "Exif.Photo.FlashpixVersion") {
473 v = kmdValueToExifVersion(entry.value());
474 } else if (exivKey == "Exif.Photo.FileSource") {
475 char s[] = {0x03};
476 v = new Exiv2::DataValue((const Exiv2::byte *)s, 1);
477 } else if (exivKey == "Exif.Photo.SceneType") {
478 char s[] = {0x01};
479 v = new Exiv2::DataValue((const Exiv2::byte *)s, 1);
480 } else if (exivKey == "Exif.Photo.ComponentsConfiguration") {
481 v = kmdIntOrderedArrayToExifArray(entry.value());
482 } else if (exivKey == "Exif.Image.Artist") { // load as dc:creator
483 KisMetaData::Value creator = entry.value();
484 if (entry.value().asArray().size() > 0) {
485 creator = entry.value().asArray()[0];
486 }
487#if !EXIV2_TEST_VERSION(0, 21, 0)
488 v = kmdValueToExivValue(creator, Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
489#else
490 v = kmdValueToExivValue(creator, exifKey.defaultTypeId());
491#endif
492 } else if (exivKey == "Exif.Photo.OECF") {
493 v = kmdOECFStructureToExifOECF(entry.value());
494 } else if (exivKey == "Exif.Photo.DeviceSettingDescription") {
495 v = deviceSettingDescriptionKMDToExif(entry.value());
496 } else if (exivKey == "Exif.Photo.CFAPattern") {
497 v = cfaPatternKMDToExif(entry.value());
498 } else if (exivKey == "Exif.Photo.Flash") {
499 v = flashKMDToExif(entry.value());
500 } else if (exivKey == "Exif.Photo.UserComment") {
501 Q_ASSERT(entry.value().type() == KisMetaData::Value::LangArray);
502 QMap<QString, KisMetaData::Value> langArr = entry.value().asLangArray();
503 if (langArr.contains("x-default")) {
504#if !EXIV2_TEST_VERSION(0, 21, 0)
505 v = kmdValueToExivValue(langArr.value("x-default"),
506 Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
507#else
508 v = kmdValueToExivValue(langArr.value("x-default"), exifKey.defaultTypeId());
509#endif
510 } else if (langArr.size() > 0) {
511#if !EXIV2_TEST_VERSION(0, 21, 0)
512 v = kmdValueToExivValue(langArr.begin().value(),
513 Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
514#else
515 v = kmdValueToExivValue(langArr.begin().value(), exifKey.defaultTypeId());
516#endif
517 }
518 } else {
519 dbgMetaData << exifKey.tag();
520#if !EXIV2_TEST_VERSION(0, 21, 0)
521 v = kmdValueToExivValue(entry.value(), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
522#else
523 v = kmdValueToExivValue(entry.value(), exifKey.defaultTypeId());
524#endif
525 }
526 if (v && v->typeId() != Exiv2::invalidTypeId) {
527 dbgMetaData << "Saving key" << exivKey << " of KMD value" << entry.value();
528 exifData.add(exifKey, v);
529 } else {
530 dbgMetaData << "No exif value was created for" << entry.qualifiedName() << " as"
531 << exivKey; // << " of KMD value" << entry.value();
532 }
533 }
534#if EXIV2_TEST_VERSION(0,28,0)
535 } catch (Exiv2::Error &e) {
536#else
537 } catch (Exiv2::AnyError &e) {
538#endif
539 dbgMetaData << "exiv error " << e.what();
540 }
541 }
542#if !EXIV2_TEST_VERSION(0, 18, 0)
543 Exiv2::DataBuf rawData = exifData.copy();
544 ioDevice->write((const char *)rawData.pData_, rawData.size_);
545#else
546 Exiv2::Blob rawData;
547 Exiv2::ExifParser::encode(rawData, Exiv2::littleEndian, exifData);
548 ioDevice->write((const char *)&*rawData.begin(), static_cast<int>(rawData.size()));
549#endif
550 ioDevice->close();
551 return true;
552}
qreal v
@ JpegHeader
Append Jpeg-style header.
QList< KisMetaData::Value > asArray() const
Exiv2::Value * deviceSettingDescriptionKMDToExif(const KisMetaData::Value &value)
Exiv2::Value * kmdIntOrderedArrayToExifArray(const KisMetaData::Value &value)
Exiv2::Value * cfaPatternKMDToExif(const KisMetaData::Value &value)
Exiv2::Value * flashKMDToExif(const KisMetaData::Value &value)
Exiv2::Value * kmdOECFStructureToExifOECF(const KisMetaData::Value &value)
Exiv2::Value * kmdValueToExifVersion(const KisMetaData::Value &value)
Exiv2::Value * kmdValueToExivValue(const KisMetaData::Value &value, Exiv2::TypeId type)
Convert a KisMetaData to an Exiv value.

References KisMetaData::Value::asArray(), cfaPatternKMDToExif(), dbgMetaData, deviceSettingDescriptionKMDToExif(), KisMetaData::Schema::DublinCoreSchemaUri, KisMetaData::Schema::EXIFSchemaUri, flashKMDToExif(), KisMetaData::IOBackend::JpegHeader, kmdIntOrderedArrayToExifArray(), kmdOECFStructureToExifOECF(), kmdValueToExifVersion(), kmdValueToExivValue(), KisMetaData::Value::LangArray, KisMetaData::Schema::MakerNoteSchemaUri, KisMetaData::Schema::TIFFSchemaUri, v, and KisMetaData::Schema::XMPSchemaUri.

◆ supportLoading()

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

Implements KisMetaData::IOBackend.

Definition at line 40 of file kis_exif_io.h.

41 {
42 return true;
43 }

◆ supportSaving()

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

Implements KisMetaData::IOBackend.

Definition at line 34 of file kis_exif_io.h.

35 {
36 return true;
37 }

◆ type()

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

Implements KisMetaData::IOBackend.

Definition at line 30 of file kis_exif_io.h.

References KisMetaData::IOBackend::Binary.


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