// Always creates a new metadata entry. // Passing invalidTypeId causes the type to be guessed. // Guessing types is accurate for IPTC, but not for EXIF. // Returns 0 on success EXIVSIMPLE_API int AddMeta(HIMAGE img, const char *key, const char *val, DllTypeId type) { assert(img && key && val); if (img==0 || key==0 || val==0) return -1; ImageWrapper *imgWrap = (ImageWrapper*)img; int rc = 2; Exiv2::IptcData &iptcData = imgWrap->image->iptcData(); Exiv2::ExifData &exifData = imgWrap->image->exifData(); std::string data(val); { size_t dataLen = data.length(); // if data starts and ends with quotes, remove them if (dataLen > 1 && *(data.begin()) == '\"' && *(data.rbegin()) == '\"') { data = data.substr(1, dataLen-2); } } try { Exiv2::IptcKey iptcKey(key); rc = 1; if (type == invalidTypeId) type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); rc = iptcData.add(iptcKey, value.get()); } catch(const Exiv2::AnyError&) { } if (rc) { // Failed with iptc, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; // No way to get value type for exif... string is the most common if (type == invalidTypeId) type = asciiString; Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); exifData.add(exifKey, value.get()); rc = 0; } catch(const Exiv2::AnyError&) { } } return rc; }
// This is weird because iptc and exif have not been "unified". Once // they are unified, this DLL should not have to know // about either... just generic images, keys, values, etc. // // buffsize should be the total size of *buff (including space for null) // Note that if there is more than one entry (for some IPTC datasets) this // returns the first one found. Currently no way to get the others. // Returns 0 on success EXIVSIMPLE_API int ReadMeta(HIMAGE img, const char *key, char *buff, int buffsize) { assert(img && key && buff); if (img==0 || key==0 || buff==0 || buffsize==0) return -1; ImageWrapper *imgWrap = (ImageWrapper*)img; int rc = 2; Exiv2::IptcData &iptcData = imgWrap->image->iptcData(); Exiv2::ExifData &exifData = imgWrap->image->exifData(); try { // First try iptc Exiv2::IptcKey iptcKey(key); rc = 1; Exiv2::IptcData::const_iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { strncpy(buff, iter->value().toString().c_str(), buffsize); buff[buffsize-1] = 0; rc = 0; } } catch(const Exiv2::AnyError&) { } if (rc) { // No iptc value, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; Exiv2::ExifData::const_iterator iter = exifData.findKey(exifKey); if (iter != exifData.end()) { strncpy(buff, iter->value().toString().c_str(), buffsize); buff[buffsize-1] = 0; rc = 0; } } catch(const Exiv2::AnyError&) { } } return rc; }
// If multiple entires exist, this only remove the first one // found. Call multiple times to remove many. // Returns 0 on success EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key) { assert(img && key); if (img==0 || key==0) return -1; ImageWrapper *imgWrap = (ImageWrapper*)img; int rc = 2; Exiv2::IptcData &iptcData = imgWrap->image->iptcData(); Exiv2::ExifData &exifData = imgWrap->image->exifData(); try { Exiv2::IptcKey iptcKey(key); rc = 1; Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { iptcData.erase(iter); rc = 0; } } catch(const Exiv2::AnyError&) { } if (rc) { // No iptc value, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; Exiv2::ExifData::iterator iter = exifData.findKey(exifKey); if (iter != exifData.end()) { exifData.erase(iter); rc = 0; } } catch(const Exiv2::AnyError&) { } } return rc; }
bool ExtendedPhoto::findExifKey(const std::string& key, String& value) const { const Exiv2::ExifData& exifData = pImage->exifData(); try { Exiv2::ExifKey exifKey(key); Exiv2::ExifData::const_iterator citer = exifData.findKey(exifKey); if (citer != exifData.end()) { value = citer->value().toString(); value.trim(); return true; } return false; } catch (...) { return false; } }
// Overwrites existing value if found, otherwise creates a new one. // Passing invalidTypeId causes the type to be guessed. // Guessing types is accurate for IPTC, but not for EXIF. // Returns 0 on success EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type) { assert(img && key && val); if (img==0 || key==0 || val==0) return -1; ImageWrapper *imgWrap = (ImageWrapper*)img; int rc = 2; Exiv2::IptcData &iptcData = imgWrap->image->iptcData(); Exiv2::ExifData &exifData = imgWrap->image->exifData(); std::string data(val); // if data starts and ends with quotes, remove them if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') { data = data.substr(1, data.size()-2); } try { Exiv2::IptcKey iptcKey(key); rc = 1; if (type == invalidTypeId) type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { iter->setValue(value.get()); rc = 0; } else { rc = iptcData.add(iptcKey, value.get()); } } catch(const Exiv2::AnyError&) { } if (rc) { // Failed with iptc, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; // No way to get value type for exif... string is the most common if (type == invalidTypeId) type = asciiString; Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); Exiv2::ExifData::iterator iter = exifData.findKey(exifKey); if (iter != exifData.end()) { iter->setValue(value.get()); rc = 0; } else { exifData.add(exifKey, value.get()); rc = 0; } } catch(const Exiv2::AnyError&) { } } return rc; }
bool KisExifIO::saveTo(KisMetaData::Store* store, QIODevice* ioDevice, HeaderType headerType) const { ioDevice->open(QIODevice::WriteOnly); Exiv2::ExifData exifData; if (headerType == KisMetaData::IOBackend::JpegHeader) { QByteArray header(6, 0); header[0] = 0x45; header[1] = 0x78; header[2] = 0x69; header[3] = 0x66; header[4] = 0x00; header[5] = 0x00; ioDevice->write(header); } for (QHash<QString, KisMetaData::Entry>::const_iterator it = store->begin(); it != store->end(); ++it) { try { const KisMetaData::Entry& entry = *it; dbgFile << "Trying to save: " << entry.name() << " of " << entry.schema()->prefix() << ":" << entry.schema()->uri(); QString exivKey; if (entry.schema()->uri() == KisMetaData::Schema::TIFFSchemaUri) { exivKey = "Exif.Image." + entry.name(); } else if (entry.schema()->uri() == KisMetaData::Schema::EXIFSchemaUri) { // Distinguish between exif and gps if (entry.name().left(3) == "GPS") { exivKey = "Exif.GPS." + entry.name(); } else { exivKey = "Exif.Photo." + entry.name(); } } else if (entry.schema()->uri() == KisMetaData::Schema::DublinCoreSchemaUri) { if (entry.name() == "description") { exivKey = "Exif.Image.ImageDescription"; } else if (entry.name() == "creator") { exivKey = "Exif.Image.Artist"; } else if (entry.name() == "rights") { exivKey = "Exif.Image.Copyright"; } } else if (entry.schema()->uri() == KisMetaData::Schema::XMPSchemaUri) { if (entry.name() == "ModifyDate") { exivKey = "Exif.Image.DateTime"; } else if (entry.name() == "CreatorTool") { exivKey = "Exif.Image.Software"; } } else if (entry.schema()->uri() == KisMetaData::Schema::MakerNoteSchemaUri) { if (entry.name() == "RawData") { exivKey = "Exif.Photo.MakerNote"; } } dbgFile << "Saving " << entry.name() << " to " << exivKey; if (exivKey.isEmpty()) { dbgFile << entry.qualifiedName() << " is unsavable to EXIF"; } else { Exiv2::ExifKey exifKey(qPrintable(exivKey)); Exiv2::Value* v = 0; if (exivKey == "Exif.Photo.ExifVersion" || exivKey == "Exif.Photo.FlashpixVersion") { v = kmdValueToExifVersion(entry.value()); } else if (exivKey == "Exif.Photo.FileSource") { char s[] = { 0x03 }; v = new Exiv2::DataValue((const Exiv2::byte*)s, 1); } else if (exivKey == "Exif.Photo.SceneType") { char s[] = { 0x01 }; v = new Exiv2::DataValue((const Exiv2::byte*)s, 1); } else if (exivKey == "Exif.Photo.ComponentsConfiguration") { v = kmdIntOrderedArrayToExifArray(entry.value()); } else if (exivKey == "Exif.Image.Artist") { // load as dc:creator KisMetaData::Value creator = entry.value().asArray()[0]; #if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20 v = kmdValueToExivValue(creator, Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId())); #else v = kmdValueToExivValue(creator, exifKey.defaultTypeId()); #endif } else if (exivKey == "Exif.Photo.OECF") { v = kmdOECFStructureToExifOECF(entry.value()); } else if (exivKey == "Exif.Photo.DeviceSettingDescription") { v = deviceSettingDescriptionKMDToExif(entry.value()); } else if (exivKey == "Exif.Photo.CFAPattern") { v = cfaPatternKMDToExif(entry.value()); } else if (exivKey == "Exif.Photo.Flash") { v = flashKMDToExif(entry.value()); } else if (exivKey == "Exif.Photo.UserComment") { Q_ASSERT(entry.value().type() == KisMetaData::Value::LangArray); QMap<QString, KisMetaData::Value> langArr = entry.value().asLangArray(); if (langArr.contains("x-default")) { #if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20 v = kmdValueToExivValue(langArr.value("x-default"), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId())); #else v = kmdValueToExivValue(langArr.value("x-default"), exifKey.defaultTypeId()); #endif } else if (langArr.size() > 0) { #if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20 v = kmdValueToExivValue(langArr.begin().value(), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId())); #else v = kmdValueToExivValue(langArr.begin().value(), exifKey.defaultTypeId()); #endif } } else { dbgFile << exifKey.tag(); #if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20 v = kmdValueToExivValue(entry.value(), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId())); #else v = kmdValueToExivValue(entry.value(), exifKey.defaultTypeId()); #endif } if (v && v->typeId() != Exiv2::invalidTypeId) { dbgFile << "Saving key" << exivKey << " of KMD value" << entry.value(); exifData.add(exifKey, v); } else { dbgFile << "No exif value was created for" << entry.qualifiedName() << " as" << exivKey;// << " of KMD value" << entry.value(); } } } catch (Exiv2::AnyError& e) { dbgFile << "exiv error " << e.what(); } } #if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 17 Exiv2::DataBuf rawData = exifData.copy(); ioDevice->write((const char*) rawData.pData_, rawData.size_); #else Exiv2::Blob rawData; Exiv2::ExifParser::encode(rawData, Exiv2::littleEndian, exifData); ioDevice->write((const char*) &*rawData.begin(), rawData.size()); #endif ioDevice->close(); return true; }