From b908ceb6bbb78a4edde47710e6291fa8eebb1717 Mon Sep 17 00:00:00 2001 From: Vladimir Nadvornik Date: Mon, 15 Dec 2008 22:47:31 +0000 Subject: [PATCH] prepared infrastructure for delayed metadata writting - refreshing metadata immediately before writting is now possible modified metadata are stored in fd->modified_xmp --- src/exif-common.c | 19 ++++++++- src/exif.c | 14 +------ src/exif.h | 7 ++-- src/exiv2.cc | 99 ++++++++++++++++++++++++++++++++--------------- src/metadata.c | 62 +++++++++++++---------------- src/typedefs.h | 1 + 6 files changed, 117 insertions(+), 85 deletions(-) diff --git a/src/exif-common.c b/src/exif-common.c index 1aba8ba2..81c7d06f 100644 --- a/src/exif-common.c +++ b/src/exif-common.c @@ -627,10 +627,27 @@ ExifData *exif_read_fd(FileData *fd) } } - 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; diff --git a/src/exif.c b/src/exif.c index 29230853..35781b0c 100644 --- a/src/exif.c +++ b/src/exif.c @@ -1209,7 +1209,7 @@ void exif_free(ExifData *exif) 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; @@ -1584,22 +1584,12 @@ gint exif_write(ExifData *exif) 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 { diff --git a/src/exif.h b/src/exif.h index 5ed08a9f..e9c3c5aa 100644 --- a/src/exif.h +++ b/src/exif.h @@ -107,10 +107,11 @@ struct _ExifFormattedText *----------------------------------------------------------------------------- */ -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. @@ -125,7 +126,6 @@ gint exif_get_integer(ExifData *exif, const gchar *key, gint *value); 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); @@ -148,8 +148,7 @@ gchar *exif_get_tag_description_by_key(const gchar *key); 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); diff --git a/src/exiv2.cc b/src/exiv2.cc index 31bf976a..ea05e30e 100644 --- a/src/exiv2.cc +++ b/src/exiv2.cc @@ -201,6 +201,10 @@ public: } }; +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 { @@ -215,7 +219,7 @@ protected: #endif public: - _ExifDataProcessed(gchar *path, gchar *sidecar_path) + _ExifDataProcessed(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp) { imageData_ = new _ExifDataOriginal(path); sidecarData_ = NULL; @@ -233,6 +237,10 @@ public: #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() @@ -326,11 +334,16 @@ public: 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"; @@ -731,49 +744,71 @@ gchar *exif_get_tag_description_by_key(const gchar *key) } } -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); diff --git a/src/metadata.c b/src/metadata.c index 29378b19..1c0949ce 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -30,6 +30,26 @@ typedef enum { } 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 @@ -341,46 +361,16 @@ static gint metadata_xmp_read(FileData *fd, GList **keywords, gchar **comment) 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; } diff --git a/src/typedefs.h b/src/typedefs.h index 2b5533e8..9a43c9f1 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -440,6 +440,7 @@ struct _FileData { gint exif_orientation; ExifData *exif; + GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values }; struct _LayoutWindow -- 2.20.1