// exivsimple.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include "exivsimple.h" #include "exif.hpp" #include "iptc.hpp" #include struct ExivImage { Exiv2::IptcData iptcData; Exiv2::ExifData exifData; std::string fileName; }; // Returns 0 if failed. EXIVSIMPLE_API HIMAGE OpenImage(const char *file) { assert(file); ExivImage *image = new ExivImage; image->fileName = file; // rc of 3 just means no iptc or exif data (not a real error) int rc = image->iptcData.read( file ); if (rc==0 || rc==3) rc = image->exifData.read( file ); if (rc!=0 && rc!=3) { delete image; image = 0; } return (HIMAGE)image; } EXIVSIMPLE_API void FreeImage(HIMAGE img) { if (img) { ExivImage *image = (ExivImage*)img; delete image; } } EXIVSIMPLE_API int SaveImage(HIMAGE img) { assert(img); ExivImage *image = (ExivImage*)img; int rc = image->iptcData.write(image->fileName); if (rc==0) rc = image->exifData.write(image->fileName); return rc; } // This is weird because iptc and exif have not been "unified". Once // the API is turned inside out, 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 full 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. 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; ExivImage *image = (ExivImage*)img; int rc = 2; try { Exiv2::IptcKey iptcKey(key); rc = 1; Exiv2::IptcData::const_iterator iter = image->iptcData.findKey(iptcKey); if (iter != image->iptcData.end()) { strncpy(buff, iter->value().toString().c_str(), buffsize); buff[buffsize-1] = 0; rc = 0; } } catch(const Exiv2::Error&) { } if (rc) { // No iptc value, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; Exiv2::ExifData::const_iterator iter = image->exifData.findKey(exifKey); if (iter != image->exifData.end()) { strncpy(buff, iter->value().toString().c_str(), buffsize); buff[buffsize-1] = 0; rc = 0; } } catch(const Exiv2::Error&) { } } return rc; } // 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. 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; ExivImage *image = (ExivImage*)img; int rc = 2; 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 = image->iptcData.findKey(iptcKey); if (iter != image->iptcData.end()) { iter->setValue(value.get()); rc = 0; } else { rc = image->iptcData.add(iptcKey, value.get()); } } catch(const Exiv2::Error&) { } if (rc) { // Failed with iptc, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; // No way to get value type for exif... alwayst string?? if (type == invalidTypeId) type = asciiString; Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); Exiv2::ExifData::iterator iter = image->exifData.findKey(exifKey); if (iter != image->exifData.end()) { iter->setValue(value.get()); rc = 0; } else { image->exifData.add(exifKey, value.get()); rc = 0; } } catch(const Exiv2::Error&) { } } return rc; } // Always creates a new metadata entry. // Passing invalidTypeId causes the type to be guessed. // Guessing types is accurate for IPTC but not for EXIF. 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; ExivImage *image = (ExivImage*)img; int rc = 2; 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); rc = image->iptcData.add(iptcKey, value.get()); } catch(const Exiv2::Error&) { } if (rc) { // Failed with iptc, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; // No way to get value type for exif... alwayst string?? if (type == invalidTypeId) type = asciiString; Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); image->exifData.add(exifKey, value.get()); rc = 0; } catch(const Exiv2::Error&) { } } return rc; } // If multiple entires exist, this only remove the first one // found. Call multiple times to remove many. EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key) { assert(img && key); if (img==0 || key==0) return -1; ExivImage *image = (ExivImage*)img; int rc = 2; try { Exiv2::IptcKey iptcKey(key); rc = 1; Exiv2::IptcData::iterator iter = image->iptcData.findKey(iptcKey); if (iter != image->iptcData.end()) { image->iptcData.erase(iter); rc = 0; } } catch(const Exiv2::Error&) { } if (rc) { // No iptc value, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; Exiv2::ExifData::iterator iter = image->exifData.findKey(exifKey); if (iter != image->exifData.end()) { image->exifData.erase(iter); rc = 0; } } catch(const Exiv2::Error&) { } } return rc; } EXIVSIMPLE_API int EnumMeta(HIMAGE img, METAENUMPROC proc, void *user) { assert(img && proc); if (img==0 || proc==0) return -1; ExivImage *image = (ExivImage*)img; bool more = true; Exiv2::IptcData::const_iterator iend = image->iptcData.end(); for (Exiv2::IptcData::const_iterator i = image->iptcData.begin(); i != iend && more; ++i) { more = proc(i->key().c_str(), i->value().toString().c_str(), user); } Exiv2::ExifData::const_iterator eend = image->exifData.end(); for (Exiv2::ExifData::const_iterator e = image->exifData.begin(); e != eend && more; ++e) { more = proc(e->key().c_str(), e->value().toString().c_str(), user); } return 0; } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }