diff src/exiv2.cc @ 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 ebfd305d902e
children 13d4501bfa7a
line wrap: on
line diff
--- 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)
 {