Mercurial > geeqie
changeset 1238:947e603a52c6
simplified metadata interface, dropped metadata_read,
fixes for older exiv2 versions
author | nadvornik |
---|---|
date | Sat, 10 Jan 2009 20:40:37 +0000 |
parents | 824a1e1775b8 |
children | 254b09942e68 |
files | src/bar_info.c src/exif.c src/exif.h src/exiv2.cc src/image-overlay.c src/metadata.c src/metadata.h src/search.c src/ui_fileops.c src/ui_fileops.h src/view_file_icon.c src/view_file_list.c |
diffstat | 12 files changed, 291 insertions(+), 218 deletions(-) [+] |
line wrap: on
line diff
--- a/src/bar_info.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/bar_info.c Sat Jan 10 20:40:37 2009 +0000 @@ -509,25 +509,16 @@ gtk_label_set_text(GTK_LABEL(bd->label_file_time), (bd->fd) ? text_from_time(bd->fd->date) : ""); } - if (metadata_read(bd->fd, &keywords, &comment)) - { - keyword_list_push(bd->keyword_view, keywords); - gtk_text_buffer_set_text(comment_buffer, - (comment) ? comment : "", -1); - - bar_keyword_list_sync(bd, keywords); - - string_list_free(keywords); - g_free(comment); - } - else - { - gtk_text_buffer_set_text(keyword_buffer, "", -1); - gtk_text_buffer_set_text(comment_buffer, "", -1); - - bar_keyword_list_sync(bd, NULL); - } - + comment = metadata_read_string(bd->fd, COMMENT_KEY); + gtk_text_buffer_set_text(comment_buffer, + (comment) ? comment : "", -1); + g_free(comment); + + keywords = metadata_read_list(bd->fd, KEYWORD_KEY); + keyword_list_push(bd->keyword_view, keywords); + bar_keyword_list_sync(bd, keywords); + string_list_free(keywords); + g_signal_handlers_unblock_by_func(keyword_buffer, bar_info_changed, bd); g_signal_handlers_unblock_by_func(comment_buffer, bar_info_changed, bd); @@ -667,7 +658,16 @@ FileData *fd = work->data; work = work->next; - metadata_set(fd, keywords, comment, append); + if (append) + { + if (comment) metadata_append_string(fd, COMMENT_KEY, comment); + if (keywords) metadata_append_list(fd, KEYWORD_KEY, keywords); + } + else + { + if (comment) metadata_write_string(fd, COMMENT_KEY, comment); + if (keywords) metadata_write_list(fd, KEYWORD_KEY, keywords); + } } filelist_free(list);
--- a/src/exif.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/exif.c Sat Jan 10 20:40:37 2009 +0000 @@ -1367,7 +1367,7 @@ } break; case EXIF_FORMAT_STRING: - string = g_string_append(string, (gchar *)(item->data)); + if (item->data) string = g_string_append(string, (gchar *)(item->data)); break; case EXIF_FORMAT_SHORT_UNSIGNED: if (ne == 1 && marker->list) @@ -1596,6 +1596,19 @@ return 0; } +GList *exif_get_metadata(ExifData *exif, const gchar *key) +{ + gchar *str; + ExifItem *item = exif_get_item(exif, key); + if (!item) return NULL; + + str = exif_item_get_string(item, 0); + + if (!str) return NULL; + + return g_list_append(NULL, str); +} + typedef struct _UnmapData UnmapData; struct _UnmapData {
--- a/src/exif.h Sun Jan 04 17:14:34 2009 +0000 +++ b/src/exif.h Sat Jan 10 20:40:37 2009 +0000 @@ -151,6 +151,7 @@ gchar *exif_get_formatted_by_key(ExifData *exif, const gchar *key, gint *key_valid); gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values); +GList *exif_get_metadata(ExifData *exif, const gchar *key); guchar *exif_get_color_profile(ExifData *exif, guint *data_len);
--- a/src/exiv2.cc Sun Jan 04 17:14:34 2009 +0000 +++ b/src/exiv2.cc Sat Jan 10 20:40:37 2009 +0000 @@ -53,7 +53,6 @@ #include <exiv2/xmpsidecar.hpp> #endif - extern "C" { #include <glib.h> @@ -62,8 +61,28 @@ #include "filefilter.h" #include "ui_fileops.h" + +#include "misc.h" } +typedef struct _AltKey AltKey; + +struct _AltKey +{ + const gchar *xmp_key; + const gchar *exif_key; + const gchar *iptc_key; +}; + +/* this is a list of keys that should be converted, even with the older Exiv2 which does not support it directly */ +static const AltKey alt_keys[] = { + {"Xmp.tiff.Orientation", "Exif.Image.Orientation", NULL}, + {"Xmp.dc.subject", NULL, "Iptc.Application2.Keywords"}, + {"Xmp.dc.description", NULL, "Iptc.Application2.Caption"}, + {NULL, NULL, NULL} + }; + + struct _ExifData { Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */ @@ -259,13 +278,15 @@ virtual void writeMetadata(gchar *path = NULL) { -#if EXIV2_TEST_VERSION(0,17,0) - syncExifWithXmp(exifData_, xmpData_); -#endif if (!path) { #if EXIV2_TEST_VERSION(0,17,0) - if (options->metadata.save_legacy_IPTC) copyXmpToIptc(xmpData_, iptcData_); + if (options->metadata.save_legacy_IPTC) + copyXmpToIptc(xmpData_, iptcData_); + else + iptcData_.clear(); + + copyXmpToExif(xmpData_, exifData_); #endif imageData_->image()->setExifData(exifData_); imageData_->image()->setIptcData(iptcData_); @@ -749,7 +770,19 @@ } } -gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values) +static const AltKey *find_alt_key(const gchar *xmp_key) +{ + gint i = 0; + + while (alt_keys[i].xmp_key) + { + if (strcmp(xmp_key, alt_keys[i].xmp_key) == 0) return &alt_keys[i]; + i++; + } + return NULL; +} + +static gint exif_update_metadata_simple(ExifData *exif, const gchar *key, const GList *values) { try { const GList *work = values; @@ -801,6 +834,8 @@ exif->xmpData()[key] = (gchar *)work->data; work = work->next; } +#else + throw e; #endif } } @@ -812,6 +847,127 @@ } } +gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values) +{ + gint ret = exif_update_metadata_simple(exif, key, values); + + if ( +#if !EXIV2_TEST_VERSION(0,17,0) + TRUE || /* no conversion support */ +#endif + !values || /* deleting item */ + !ret /* writing to the explicitely given xmp tag failed */ + ) + { + /* deleted xmp metadatum can't be converted, we have to delete also the corresponding legacy tag */ + /* if we can't write xmp, update at least the legacy tag */ + const AltKey *alt_key = find_alt_key(key); + if (alt_key && alt_key->iptc_key) + ret = exif_update_metadata_simple(exif, alt_key->iptc_key, values); + + if (alt_key && alt_key->exif_key) + ret = exif_update_metadata_simple(exif, alt_key->exif_key, values); + } + return ret; +} + + +static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item) +{ + Exiv2::TypeId id = item.typeId(); + if (id == Exiv2::asciiString || + id == Exiv2::undefined || + id == Exiv2::string || + id == Exiv2::date || + id == Exiv2::time || +#if EXIV2_TEST_VERSION(0,16,0) + id == Exiv2::xmpText || + id == Exiv2::langAlt || +#endif + id == Exiv2::comment + ) + { + /* read as a single entry */ + std::string str = item.toString(); + if (str.length() > 5 && str.substr(0, 5) == "lang=") + { + std::string::size_type pos = str.find_first_of(' '); + if (pos != std::string::npos) str = str.substr(pos+1); + } + list = g_list_append(list, utf8_validate_or_convert(str.c_str())); + } + else + { + /* read as a list */ + gint i; + for (i = 0; i < item.count(); i++) + list = g_list_append(list, utf8_validate_or_convert(item.toString(i).c_str())); + } + return list; +} + +static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key) +{ + GList *list = NULL; + try { + try { + Exiv2::ExifKey ekey(key); + + Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey); + if (pos != exif->exifData().end()) + list = exif_add_value_to_glist(list, *pos); + + } + catch (Exiv2::AnyError& e) { + try { + Exiv2::IptcKey ekey(key); + Exiv2::IptcData::iterator pos = exif->iptcData().begin(); + while (pos != exif->iptcData().end()) + { + if (pos->key() == key) + list = exif_add_value_to_glist(list, *pos); + ++pos; + } + + } + catch (Exiv2::AnyError& e) { +#if EXIV2_TEST_VERSION(0,16,0) + Exiv2::XmpKey ekey(key); + Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey); + if (pos != exif->xmpData().end()) + list = exif_add_value_to_glist(list, *pos); +#endif + } + } + } + catch (Exiv2::AnyError& e) { + std::cout << "Caught Exiv2 exception '" << e << "'\n"; + } + return list; +} + +GList *exif_get_metadata(ExifData *exif, const gchar *key) +{ + GList *list = NULL; + + list = exif_get_metadata_simple(exif, key); + + /* the following code can be ifdefed out as soon as Exiv2 supports it */ + if (!list) + { + const AltKey *alt_key = find_alt_key(key); + if (alt_key && alt_key->iptc_key) + list = exif_get_metadata_simple(exif, alt_key->iptc_key); + +#if !EXIV2_TEST_VERSION(0,17,0) + /* with older Exiv2 versions exif is not synced */ + if (!list && alt_key && alt_key->exif_key) + list = exif_get_metadata_simple(exif, alt_key->exif_key); +#endif + } + return list; +} + void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length) {
--- a/src/image-overlay.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/image-overlay.c Sat Jan 10 20:40:37 2009 +0000 @@ -178,7 +178,9 @@ g_assert(fd); - if (metadata_read(fd, &keywords, NULL)) + keywords = metadata_read_list(fd, KEYWORD_KEY); + + if (keywords) { GList *work = keywords; @@ -195,6 +197,7 @@ g_string_append(kwstr, kw); } + string_list_free(keywords); } if (kwstr) @@ -275,7 +278,7 @@ } else if (strcmp(name, "comment") == 0) { - metadata_read(imd->image_fd, NULL, &data); + data = metadata_read_string(imd->image_fd, COMMENT_KEY); } else {
--- a/src/metadata.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/metadata.c Sat Jan 10 20:40:37 2009 +0000 @@ -325,7 +325,15 @@ fclose(f); - *keywords = g_list_reverse(list); + if (keywords) + { + *keywords = g_list_reverse(list); + } + else + { + string_list_free(list); + } + if (comment_build) { if (comment) @@ -420,209 +428,93 @@ return g_list_reverse(newlist); } - -static gint metadata_xmp_read(FileData *fd, GList **keywords, gchar **comment) +GList *metadata_read_list(FileData *fd, const gchar *key) { ExifData *exif; + GList *list = NULL; + if (!fd) return NULL; - exif = exif_read_fd(fd); - if (!exif) return FALSE; - - if (comment) + /* unwritten data overide everything */ + if (fd->modified_xmp) { - gchar *text; - ExifItem *item = exif_get_item(exif, COMMENT_KEY); - - text = exif_item_get_string(item, 0); - *comment = utf8_validate_or_convert(text); - g_free(text); + list = g_hash_table_lookup(fd->modified_xmp, key); + if (list) return string_list_copy(list); } - if (keywords) + /* + Legacy metadata file is the primary source if it exists. + Merging the lists does not make much sense, because the existence of + legacy metadata file indicates that the other metadata sources are not + writable and thus it would not be possible to delete the keywords + that comes from the image file. + */ + if (strcmp(key, KEYWORD_KEY) == 0) { - ExifItem *item; - guint i; - - *keywords = NULL; - item = exif_get_item(exif, KEYWORD_KEY); - for (i = 0; i < exif_item_get_elements(item); i++) - { - gchar *kw = exif_item_get_string(item, i); - gchar *utf8_kw; - - if (!kw) break; - - utf8_kw = utf8_validate_or_convert(kw); - *keywords = g_list_append(*keywords, (gpointer) utf8_kw); - g_free(kw); - } + if (metadata_legacy_read(fd, &list, NULL)) return list; + } - /* FIXME: - * Exiv2 handles Iptc keywords as multiple entries with the - * same key, thus exif_get_item returns only the first keyword - * and the only way to get all keywords is to iterate through - * the item list. - */ - /* Read IPTC keywords only if there are no XMP keywords - * IPTC does not have standard charset, thus the encoding may differ - * from XMP and keyword merging is not reliable. - */ - if (!*keywords) - { - for (item = exif_get_first_item(exif); - item; - item = exif_get_next_item(exif)) - { - guint tag; - - tag = exif_item_get_tag_id(item); - if (tag == 0x0019) - { - gchar *tag_name = exif_item_get_tag_name(item); - - if (strcmp(tag_name, "Iptc.Application2.Keywords") == 0) - { - gchar *kw; - gchar *utf8_kw; - - kw = exif_item_get_data_as_text(item); - if (!kw) continue; - - utf8_kw = utf8_validate_or_convert(kw); - *keywords = g_list_append(*keywords, (gpointer) utf8_kw); - g_free(kw); - } - g_free(tag_name); - } - } - } - } - + if (strcmp(key, COMMENT_KEY) == 0) + { + gchar *comment = NULL; + if (metadata_legacy_read(fd, NULL, &comment)) return g_list_append(NULL, comment); + } + + exif = exif_read_fd(fd); /* this is cached, thus inexpensive */ + if (!exif) return NULL; + list = exif_get_metadata(exif, key); exif_free_fd(fd, exif); - - return (comment && *comment) || (keywords && *keywords); + return list; } -gint metadata_read(FileData *fd, GList **keywords, gchar **comment) +gchar *metadata_read_string(FileData *fd, const gchar *key) { - GList *keywords_xmp = NULL; - GList *keywords_legacy = NULL; - gchar *comment_xmp = NULL; - gchar *comment_legacy = NULL; - gint result_xmp, result_legacy; - - if (!fd) return FALSE; - - result_xmp = metadata_xmp_read(fd, &keywords_xmp, &comment_xmp); - result_legacy = metadata_legacy_read(fd, &keywords_legacy, &comment_legacy); - - if (!result_xmp && !result_legacy) + GList *string_list = metadata_read_list(fd, key); + if (string_list) { - return FALSE; + gchar *str = string_list->data; + string_list->data = NULL; + string_list_free(string_list); + return str; } - - if (keywords) + return NULL; +} + +gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value) +{ + gchar *str = metadata_read_string(fd, key); + + if (!str) { - if (result_xmp && result_legacy) - *keywords = g_list_concat(keywords_xmp, keywords_legacy); - else - *keywords = result_xmp ? keywords_xmp : keywords_legacy; - - *keywords = remove_duplicate_strings_from_list(*keywords); + return metadata_write_string(fd, key, value); } else { - if (result_xmp) string_list_free(keywords_xmp); - if (result_legacy) string_list_free(keywords_legacy); - } - - - if (comment) - { - if (result_xmp && result_legacy && comment_xmp && comment_legacy && *comment_xmp && *comment_legacy) - *comment = g_strdup_printf("%s\n%s", comment_xmp, comment_legacy); - else - *comment = result_xmp ? comment_xmp : comment_legacy; + gchar *new_string = g_strconcat(str, value, NULL); + gboolean ret = metadata_write_string(fd, key, new_string); + g_free(str); + g_free(new_string); + return ret; } - - if (result_xmp && (!comment || *comment != comment_xmp)) g_free(comment_xmp); - if (result_legacy && (!comment || *comment != comment_legacy)) g_free(comment_legacy); - - // return FALSE in the following cases: - // - only looking for a comment and didn't find one - // - only looking for keywords and didn't find any - // - looking for either a comment or keywords, but found nothing - if ((!keywords && comment && !*comment) || - (!comment && keywords && !*keywords) || - ( comment && !*comment && keywords && !*keywords)) - return FALSE; - - return TRUE; } -void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append) +gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values) { - gchar *comment = NULL; - GList *keywords = NULL; - GList *keywords_list = NULL; - - metadata_read(fd, &keywords, &comment); + GList *list = metadata_read_list(fd, key); - if (new_comment) - { - if (append && comment && *comment) - { - gchar *tmp = comment; - - comment = g_strconcat(tmp, new_comment, NULL); - g_free(tmp); - } - else - { - g_free(comment); - comment = g_strdup(new_comment); - } - } - - if (new_keywords) + if (!list) { - if (append && keywords && g_list_length(keywords) > 0) - { - GList *work; - - work = new_keywords; - while (work) - { - gchar *key; - GList *p; - - key = work->data; - work = work->next; - - p = keywords; - while (p && key) - { - gchar *needle = p->data; - p = p->next; - - if (strcmp(needle, key) == 0) key = NULL; - } - - if (key) keywords = g_list_append(keywords, g_strdup(key)); - } - keywords_list = keywords; - } - else - { - keywords_list = new_keywords; - } + return metadata_write_list(fd, key, values); } - - metadata_write_string(fd, COMMENT_KEY, comment); - metadata_write_list(fd, KEYWORD_KEY, keywords); - - string_list_free(keywords); - g_free(comment); + else + { + gboolean ret; + list = g_list_concat(list, string_list_copy(values)); + list = remove_duplicate_strings_from_list(list); + + ret = metadata_write_list(fd, key, list); + string_list_free(list); + return ret; + } } gboolean find_string_in_list(GList *list, const gchar *string) @@ -687,7 +579,8 @@ { GList *keywords; gboolean found = FALSE; - if (metadata_read(fd, &keywords, NULL)) + keywords = metadata_read_list(fd, KEYWORD_KEY); + if (keywords) { GList *work = keywords; @@ -713,7 +606,7 @@ gboolean found = FALSE; gboolean changed = FALSE; GList *work; - metadata_read(fd, &keywords, NULL); + keywords = metadata_read_list(fd, KEYWORD_KEY); work = keywords;
--- a/src/metadata.h Sun Jan 04 17:14:34 2009 +0000 +++ b/src/metadata.h Sat Jan 10 20:40:37 2009 +0000 @@ -27,9 +27,12 @@ gboolean metadata_write_list(FileData *fd, const gchar *key, const GList *values); gboolean metadata_write_string(FileData *fd, const gchar *key, const char *value); -gint metadata_read(FileData *fd, GList **keywords, gchar **comment); +GList *metadata_read_list(FileData *fd, const gchar *key); +gchar *metadata_read_string(FileData *fd, const gchar *key); -void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append); +gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value); +gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values); + gboolean find_string_in_list(GList *list, const gchar *keyword); GList *string_to_keywords_list(const gchar *text);
--- a/src/search.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/search.c Sat Jan 10 20:40:37 2009 +0000 @@ -1804,7 +1804,9 @@ tested = TRUE; match = FALSE; - if (metadata_read(fd, &list, NULL)) + list = metadata_read_list(fd, KEYWORD_KEY); + + if (list) { GList *needle; GList *haystack; @@ -1882,7 +1884,9 @@ tested = TRUE; match = FALSE; - if (metadata_read(fd, NULL, &comment)) + comment = metadata_read_string(fd, COMMENT_KEY); + + if (comment) { if (! sd->search_comment_match_case) {
--- a/src/ui_fileops.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/ui_fileops.c Sat Jan 10 20:40:37 2009 +0000 @@ -656,7 +656,7 @@ g_list_free(list); } -GList *string_list_copy(GList *list) +GList *string_list_copy(const GList *list) { GList *new_list = NULL; GList *work;
--- a/src/ui_fileops.h Sun Jan 04 17:14:34 2009 +0000 +++ b/src/ui_fileops.h Sat Jan 10 20:40:37 2009 +0000 @@ -69,7 +69,7 @@ * the lists with string_list_free() */ void string_list_free(GList *list); -GList *string_list_copy(GList *list); +GList *string_list_copy(const GList *list); gchar *unique_filename(const gchar *path, const gchar *ext, const gchar *divider, gint pad); gchar *unique_filename_simple(const gchar *path);
--- a/src/view_file_icon.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/view_file_icon.c Sat Jan 10 20:40:37 2009 +0000 @@ -568,7 +568,7 @@ gchar *str = g_strndup(selection->data, selection->length); GList *kw_list = string_to_keywords_list(str); - metadata_set(fd, kw_list, NULL, TRUE); + metadata_append_list(fd, KEYWORD_KEY, kw_list); string_list_free(kw_list); g_free(str); if (vf->layout && vf->layout->bar_info) {
--- a/src/view_file_list.c Sun Jan 04 17:14:34 2009 +0000 +++ b/src/view_file_list.c Sat Jan 10 20:40:37 2009 +0000 @@ -323,7 +323,7 @@ gchar *str = g_strndup(selection->data, selection->length); GList *kw_list = string_to_keywords_list(str); - metadata_set(fd, kw_list, NULL, TRUE); + metadata_append_list(fd, KEYWORD_KEY, kw_list); string_list_free(kw_list); g_free(str); if (vf->layout && vf->layout->bar_info) {