}
}
- fd->exif = exif_read(fd->path, sidecar_path);
+ fd->exif = exif_read(fd->path, sidecar_path, fd->modified_xmp);
return fd->exif;
}
+gint exif_write_fd(FileData *fd)
+{
+ gint success;
+ ExifData *exif;
+
+ /* exif_read_fd can either use cached metadata which have fd->modified_xmp already applied
+ or read metadata from file and apply fd->modified_xmp
+ metadata are read also if the file was modified meanwhile */
+ exif = exif_read_fd(fd);
+ if (!exif) return FALSE;
+ success = exif_write(exif); /* write modified metadata */
+ exif_free_fd(fd, exif);
+ g_hash_table_destroy(fd->modified_xmp);
+ fd->modified_xmp = NULL;
+ return success;
+}
+
void exif_free_fd(FileData *fd, ExifData *exif)
{
if (!fd) return;
g_free(exif);
}
-ExifData *exif_read(gchar *path, gchar *sidecar_path)
+ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
{
ExifData *exif;
gpointer f;
return 0;
}
-ExifItem *exif_add_item(ExifData *exif, const gchar *key)
-{
- return NULL;
-}
-
-gint exif_item_delete(ExifData *exif, ExifItem *item)
-{
- return 0;
-}
-gint exif_item_set_string(ExifItem *item, const gchar *str)
+gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values)
{
return 0;
}
-
typedef struct _UnmapData UnmapData;
struct _UnmapData
{
*-----------------------------------------------------------------------------
*/
-ExifData *exif_read(gchar *path, gchar *sidecar_path);
+ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp);
ExifData *exif_read_fd(FileData *fd);
void exif_free_fd(FileData *fd, ExifData *exif);
+gint exif_write_fd(FileData *fd);
/* exif_read returns processed data (merged from image and sidecar, etc.)
this function gives access to the original data from the image.
ExifRational *exif_get_rational(ExifData *exif, const gchar *key, gint *sign);
ExifItem *exif_get_item(ExifData *exif, const gchar *key);
-ExifItem *exif_add_item(ExifData *exif, const gchar *key);
ExifItem *exif_get_first_item(ExifData *exif);
ExifItem *exif_get_next_item(ExifData *exif);
gchar *exif_get_formatted_by_key(ExifData *exif, const gchar *key, gint *key_valid);
-gint exif_item_delete(ExifData *exif, ExifItem *item);
-gint exif_item_set_string(ExifItem *item, const gchar *str);
+gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values);
guchar *exif_get_color_profile(ExifData *exif, guint *data_len);
}
};
+extern "C" {
+static void _ExifDataProcessed_update_xmp(gpointer key, gpointer value, gpointer data);
+}
+
// This allows read-write access to the metadata
struct _ExifDataProcessed : public _ExifData
{
#endif
public:
- _ExifDataProcessed(gchar *path, gchar *sidecar_path)
+ _ExifDataProcessed(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
{
imageData_ = new _ExifDataOriginal(path);
sidecarData_ = NULL;
#if EXIV2_TEST_VERSION(0,17,0)
syncExifWithXmp(exifData_, xmpData_);
#endif
+ if (modified_xmp)
+ {
+ g_hash_table_foreach(modified_xmp, _ExifDataProcessed_update_xmp, this);
+ }
}
virtual ~_ExifDataProcessed()
extern "C" {
-ExifData *exif_read(gchar *path, gchar *sidecar_path)
+static void _ExifDataProcessed_update_xmp(gpointer key, gpointer value, gpointer data)
+{
+ exif_update_metadata((ExifData *)data, (gchar *)key, (GList *)value);
+}
+
+ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
{
DEBUG_1("exif read %s, sidecar: %s", path, sidecar_path ? sidecar_path : "-");
try {
- return new _ExifDataProcessed(path, sidecar_path);
+ return new _ExifDataProcessed(path, sidecar_path, modified_xmp);
}
catch (Exiv2::AnyError& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
}
}
-int exif_item_set_string(ExifItem *item, const char *str)
+gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values)
{
try {
- if (!item) return 0;
- ((Exiv2::Metadatum *)item)->setValue(std::string(str));
- return 1;
- }
- catch (Exiv2::AnyError& e) {
- return 0;
- }
-}
+ const GList *work = values;
-int exif_item_delete(ExifData *exif, ExifItem *item)
-{
- try {
- if (!item) return 0;
- for (Exiv2::ExifData::iterator i = exif->exifData().begin(); i != exif->exifData().end(); ++i) {
- if (((Exiv2::Metadatum *)item) == &*i) {
- i = exif->exifData().erase(i);
- return 1;
- }
+ Exiv2::Metadatum *item = NULL;
+ try {
+ Exiv2::ExifKey ekey(key);
+
+ Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey);
+ while (pos != exif->exifData().end())
+ {
+ exif->exifData().erase(pos);
+ pos = exif->exifData().findKey(ekey);
+ }
+
+ while (work)
+ {
+ exif->exifData()[key] = (gchar *)work->data;
+ work = work->next;
+ }
}
- for (Exiv2::IptcData::iterator i = exif->iptcData().begin(); i != exif->iptcData().end(); ++i) {
- if (((Exiv2::Metadatum *)item) == &*i) {
- i = exif->iptcData().erase(i);
- return 1;
+ catch (Exiv2::AnyError& e) {
+ try {
+ Exiv2::IptcKey ekey(key);
+ Exiv2::IptcData::iterator pos = exif->iptcData().findKey(ekey);
+ while (pos != exif->iptcData().end())
+ {
+ exif->iptcData().erase(pos);
+ pos = exif->iptcData().findKey(ekey);
+ }
+
+ while (work)
+ {
+ exif->iptcData()[key] = (gchar *)work->data;
+ work = work->next;
+ }
}
- }
+ catch (Exiv2::AnyError& e) {
#if EXIV2_TEST_VERSION(0,16,0)
- for (Exiv2::XmpData::iterator i = exif->xmpData().begin(); i != exif->xmpData().end(); ++i) {
- if (((Exiv2::Metadatum *)item) == &*i) {
- i = exif->xmpData().erase(i);
- return 1;
+ Exiv2::XmpKey ekey(key);
+ Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey);
+ while (pos != exif->xmpData().end())
+ {
+ exif->xmpData().erase(pos);
+ pos = exif->xmpData().findKey(ekey);
+ }
+
+ while (work)
+ {
+ exif->xmpData()[key] = (gchar *)work->data;
+ work = work->next;
+ }
+#endif
}
}
-#endif
- return 0;
+ return 1;
}
catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
return 0;
}
}
+
void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
{
exif->add_jpeg_color_profile(cp_data, cp_length);
} MetadataKey;
+gint metadata_write_list(FileData *fd, const gchar *key, GList *values)
+{
+ if (!fd->modified_xmp)
+ {
+ fd->modified_xmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)string_list_free);
+ }
+ g_hash_table_insert(fd->modified_xmp, g_strdup(key), values);
+ if (fd->exif)
+ {
+ exif_update_metadata(fd->exif, key, values);
+ }
+ return TRUE;
+}
+
+gint metadata_write_string(FileData *fd, const gchar *key, const char *value)
+{
+ return metadata_write_list(fd, key, g_list_append(NULL, g_strdup(value)));
+}
+
+
/*
*-------------------------------------------------------------------
* keyword / comment read/write
static gint metadata_xmp_write(FileData *fd, GList *keywords, const gchar *comment)
{
- gint success;
+ gint success = TRUE;
gint write_comment = (comment && comment[0]);
- ExifData *exif;
- ExifItem *item;
-
- exif = exif_read_fd(fd);
- if (!exif) return FALSE;
- item = exif_get_item(exif, COMMENT_KEY);
- if (item && !write_comment)
- {
- exif_item_delete(exif, item);
- item = NULL;
- }
-
- if (!item && write_comment) item = exif_add_item(exif, COMMENT_KEY);
- if (item) exif_item_set_string(item, comment);
-
- while ((item = exif_get_item(exif, KEYWORD_KEY)))
- {
- exif_item_delete(exif, item);
- }
-
- if (keywords)
- {
- GList *work;
-
- item = exif_add_item(exif, KEYWORD_KEY);
-
- work = keywords;
- while (work)
- {
- exif_item_set_string(item, (gchar *) work->data);
- work = work->next;
- }
- }
+ if (write_comment) success = success && metadata_write_string(fd, COMMENT_KEY, comment);
+
+ if (keywords) success = success && metadata_write_list(fd, KEYWORD_KEY, string_list_copy(keywords));
- success = exif_write(exif);
- exif_free_fd(fd, exif);
+/* FIXME - actual writting should be triggered in metadata_write_list and should be delayed */
+ success = exif_write_fd(fd);
return success;
}
gint exif_orientation;
ExifData *exif;
+ GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values
};
struct _LayoutWindow