changeset 1288:10073464e6aa

use metadata_read_* functions where possible switch exiv2 to utf8 charset support for exiv2 formatting that depends on other tags: http://dev.robotbattle.com/bugs/view.php?id=0000516
author nadvornik
date Sat, 07 Feb 2009 19:01:21 +0000
parents 5fdf258f9c24
children deb0876c29d2
files src/bar_exif.c src/bar_info.c src/cache-loader.c src/exif.c src/exif.h src/exiv2.cc src/image-overlay.c src/image.c src/main.c src/metadata.c src/metadata.h src/pan-view.c src/search.c src/thumb.c src/thumb_standard.c src/typedefs.h
diffstat 16 files changed, 220 insertions(+), 165 deletions(-) [+]
line wrap: on
line diff
--- a/src/bar_exif.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/bar_exif.c	Sat Feb 07 19:01:21 2009 +0000
@@ -15,6 +15,7 @@
 #include "bar_exif.h"
 
 #include "exif.h"
+#include "metadata.h"
 #include "filedata.h"
 #include "history_list.h"
 #include "misc.h"
@@ -180,27 +181,25 @@
 
 static void bar_exif_update(ExifBar *eb)
 {
-	ExifData *exif_processed;
 	ExifData *exif;
 	gint i;
 
-	exif_processed = exif_read_fd(eb->fd);
+	/* do we have any exif at all ? */
+	exif = exif_read_fd(eb->fd);
 
-	if (!exif_processed)
+	if (!exif)
 		{
 		bar_exif_sensitive(eb, FALSE);
 		return;
 		}
-	
-	if (eb->advanced_scrolled)
-		{
-		/* show the original values from the file */
-		exif = exif_get_original(exif_processed);
-		}
 	else
 		{
-		exif = exif_processed;
+		/* we will use high level functions so we can release it for now.
+		   it will stay in the cache */
+		exif_free_fd(eb->fd, exif);
+		exif = NULL;
 		}
+	
 
 	bar_exif_sensitive(eb, TRUE);
 
@@ -210,7 +209,6 @@
 		for (i = 0; ExifUIList[i].key; i++)
 			{
 			gchar *text;
-			gchar *utf8_text;
 
 			if (ExifUIList[i].current == EXIF_UI_OFF)
 				{
@@ -218,21 +216,19 @@
 				gtk_widget_hide(eb->keys[i]);
 				continue;
 				}
-			text = exif_get_data_as_text(exif, ExifUIList[i].key);
-			utf8_text = utf8_validate_or_convert(text);
-			g_free(text);
+			text =  metadata_read_string(eb->fd, ExifUIList[i].key, METADATA_FORMATTED);
 			if (ExifUIList[i].current == EXIF_UI_IFSET
-			    && (!utf8_text || !*utf8_text))
+			    && (!text || !*text))
 				{
 				gtk_widget_hide(eb->labels[i]);
 				gtk_widget_hide(eb->keys[i]);
-				g_free(utf8_text);
+				g_free(text);
 				continue;
 				}
 			gtk_widget_show(eb->labels[i]);
 			gtk_widget_show(eb->keys[i]);
-			gtk_label_set_text(GTK_LABEL(eb->labels[i]), utf8_text);
-			g_free(utf8_text);
+			gtk_label_set_text(GTK_LABEL(eb->labels[i]), text);
+			g_free(text);
 			}
 
 		list = g_list_last(history_list_get_by_key("exif_extras"));
@@ -248,7 +244,6 @@
 		while (list && i < EXIF_BAR_CUSTOM_COUNT)
 			{
 			gchar *text;
-			gchar *utf8_text;
 			gchar *name;
 			gchar *buf;
 			gchar *description;
@@ -256,9 +251,7 @@
 			name = list->data;
 			list = list->prev;
 			
-			text = exif_get_data_as_text(exif, name);
-			utf8_text = utf8_validate_or_convert(text);
-			g_free(text);
+			text =  metadata_read_string(eb->fd, name, METADATA_FORMATTED);
 
 			description = exif_get_tag_description_by_key(name);
 			if (!description || *description == '\0') 
@@ -271,8 +264,8 @@
 			
 			gtk_label_set_text(GTK_LABEL(eb->custom_name[i]), buf);
 			g_free(buf);
-			gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), utf8_text);
-			g_free(utf8_text);
+			gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), text);
+			g_free(text);
 
 			gtk_widget_show(eb->custom_name[i]);
 			gtk_widget_show(eb->custom_value[i]);
@@ -297,12 +290,18 @@
 		{
 		GtkListStore *store;
 		GtkTreeIter iter;
+		ExifData *exif_original;
 		ExifItem *item;
 
+		exif = exif_read_fd(eb->fd);
+		if (!exif) return;
+		
+		exif_original = exif_get_original(exif);
+
 		store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
 		gtk_list_store_clear(store);
 
-		item = exif_get_first_item(exif);
+		item = exif_get_first_item(exif_original);
 		while (item)
 			{
 			gchar *tag;
@@ -341,11 +340,11 @@
 			g_free(elements);
 			g_free(description);
 			g_free(tag_name);
-			item = exif_get_next_item(exif);
+			item = exif_get_next_item(exif_original);
 			}
+		exif_free_fd(eb->fd, exif);
 		}
 
-	exif_free_fd(eb->fd, exif_processed);
 }
 
 static void bar_exif_clear(ExifBar *eb)
--- a/src/bar_info.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/bar_info.c	Sat Feb 07 19:01:21 2009 +0000
@@ -509,12 +509,12 @@
 		gtk_label_set_text(GTK_LABEL(bd->label_file_time), (bd->fd) ? text_from_time(bd->fd->date) : "");
 		}
 
-	comment = metadata_read_string(bd->fd, COMMENT_KEY);
+	comment = metadata_read_string(bd->fd, COMMENT_KEY, METADATA_PLAIN);
 	gtk_text_buffer_set_text(comment_buffer,
 				 (comment) ? comment : "", -1);
 	g_free(comment);
 	
-	keywords = metadata_read_list(bd->fd, KEYWORD_KEY);
+	keywords = metadata_read_list(bd->fd, KEYWORD_KEY, METADATA_PLAIN);
 	keyword_list_push(bd->keyword_view, keywords);
 	bar_keyword_list_sync(bd, keywords);
 	string_list_free(keywords);
--- a/src/cache-loader.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/cache-loader.c	Sat Feb 07 19:01:21 2009 +0000
@@ -16,6 +16,7 @@
 
 #include "filedata.h"
 #include "exif.h"
+#include "metadata.h"
 #include "md5-util.h"
 #include "ui_fileops.h"
 
@@ -125,31 +126,24 @@
 		 !cl->cd->have_date)
 		{
 		time_t date = -1;
-		ExifData *exif;
+		gchar *text;
 
-		exif = exif_read_fd(cl->fd);
-		if (exif)
+		text =  metadata_read_string(cl->fd, "formatted.DateTime", METADATA_FORMATTED);
+		if (text)
 			{
-			gchar *text;
+			struct tm t;
 
-			text = exif_get_data_as_text(exif, "formatted.DateTime");
-			if (text)
-				{
-				struct tm t;
+			memset(&t, 0, sizeof(t));
 
-				memset(&t, 0, sizeof(t));
-
-				if (sscanf(text, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
-					   &t.tm_hour, &t.tm_min, &t.tm_sec) == 6)
-					{
-					t.tm_year -= 1900;
-					t.tm_mon -= 1;
-					t.tm_isdst = -1;
-					date = mktime(&t);
-					}
-				g_free(text);
+			if (sscanf(text, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
+				   &t.tm_hour, &t.tm_min, &t.tm_sec) == 6)
+				{
+				t.tm_year -= 1900;
+				t.tm_mon -= 1;
+				t.tm_isdst = -1;
+				date = mktime(&t);
 				}
-			exif_free_fd(cl->fd, exif);
+			g_free(text);
 			}
 
 		cl->cd->date = date;
--- a/src/exif.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/exif.c	Sat Feb 07 19:01:21 2009 +0000
@@ -1311,13 +1311,8 @@
 
 #define EXIF_DATA_AS_TEXT_MAX_COUNT 16
 
-gchar *exif_item_get_string(ExifItem *item, gint idx)
-{
-	return exif_item_get_data_as_text(item);
-}
 
-
-gchar *exif_item_get_data_as_text(ExifItem *item)
+static gchar *exif_item_get_data_as_text_full(ExifItem *item, MetadataFormat format)
 {
 	const ExifMarker *marker;
 	gpointer data;
@@ -1342,7 +1337,7 @@
 		case EXIF_FORMAT_BYTE_UNSIGNED:
 		case EXIF_FORMAT_BYTE:
 		case EXIF_FORMAT_UNDEFINED:
-			if (ne == 1 && marker->list)
+			if (ne == 1 && marker->list && format == METADATA_FORMATTED)
 				{
 				gchar *result;
 				guchar val;
@@ -1370,7 +1365,7 @@
 			if (item->data) string = g_string_append(string, (gchar *)(item->data));
 			break;
 		case EXIF_FORMAT_SHORT_UNSIGNED:
-			if (ne == 1 && marker->list)
+			if (ne == 1 && marker->list && format == METADATA_FORMATTED)
 				{
 				gchar *result;
 
@@ -1453,6 +1448,16 @@
 	return text;
 }
 
+gchar *exif_item_get_string(ExifItem *item, gint idx)
+{
+	return exif_item_get_data_as_text_full(item, METADATA_PLAIN);
+}
+
+gchar *exif_item_get_data_as_text(ExifItem *item)
+{
+	return exif_item_get_data_as_text_full(item, METADATA_FORMATTED);
+}
+
 gint exif_item_get_integer(ExifItem *item, gint *value)
 {
 	if (!item) return FALSE;
@@ -1596,13 +1601,25 @@
 	return 0;
 }
 
-GList *exif_get_metadata(ExifData *exif, const gchar *key)
+GList *exif_get_metadata(ExifData *exif, const gchar *key, MetadataFormat format)
 {
 	gchar *str;
-	ExifItem *item = exif_get_item(exif, key);
+	ExifItem *item;
+	
+	if (!key) return NULL;
+	
+	if (format == METADATA_FORMATTED)
+		{
+		gchar *text;
+		gint key_valid;
+		text = exif_get_formatted_by_key(exif, key, &key_valid);
+		if (key_valid) return g_list_append(NULL, text);
+		}
+
+	item = exif_get_item(exif, key);
 	if (!item) return NULL;
 	
-	str = exif_item_get_string(item, 0);
+	str = exif_item_get_data_as_text_full(item, format);
 	
 	if (!str) return NULL;
 	
@@ -1692,6 +1709,9 @@
 	g_assert_not_reached();
 }
 
+void exif_init(void)
+{
+}
 
 #endif
 /* not HAVE_EXIV2 */
--- a/src/exif.h	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/exif.h	Sat Feb 07 19:01:21 2009 +0000
@@ -92,7 +92,6 @@
 	EXIF_UNIT_CENTIMETER	= 3
 } ExifUnitType;
 
-
 typedef struct _ExifFormattedText ExifFormattedText;
 struct _ExifFormattedText
 {
@@ -107,6 +106,8 @@
  *-----------------------------------------------------------------------------
  */
 
+void exif_init(void);
+
 ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp);
 
 ExifData *exif_read_fd(FileData *fd);
@@ -151,7 +152,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);
+GList *exif_get_metadata(ExifData *exif, const gchar *key, MetadataFormat format);
 
 guchar *exif_get_color_profile(ExifData *exif, guint *data_len);
 
--- a/src/exiv2.cc	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/exiv2.cc	Sat Feb 07 19:01:21 2009 +0000
@@ -350,6 +350,16 @@
 
 extern "C" {
 
+
+void exif_init(void)
+{
+#ifdef EXV_ENABLE_NLS
+	bind_textdomain_codeset (EXV_PACKAGE, "UTF-8");
+#endif
+}
+
+
+
 static void _ExifDataProcessed_update_xmp(gpointer key, gpointer value, gpointer data)
 {
 	exif_update_metadata((ExifData *)data, (gchar *)key, (GList *)value);
@@ -604,7 +614,7 @@
 {
 	try {
 		if (!item) return NULL;
-		return g_locale_to_utf8(((Exiv2::Metadatum *)item)->tagLabel().c_str(), -1, NULL, NULL, NULL);
+		return utf8_validate_or_convert(((Exiv2::Metadatum *)item)->tagLabel().c_str());
 	}
 	catch (std::exception& e) {
 //		std::cout << "Caught Exiv2 exception '" << e << "'\n";
@@ -678,7 +688,7 @@
 		if (!item) return NULL;
 		Exiv2::Metadatum *metadatum = (Exiv2::Metadatum *)item;
 #if EXIV2_TEST_VERSION(0,17,0)
-		return g_locale_to_utf8(metadatum->print().c_str(), -1, NULL, NULL, NULL);
+		return utf8_validate_or_convert(metadatum->print().c_str());
 #else
 		std::stringstream str;
 		Exiv2::Exifdatum *exifdatum;
@@ -695,7 +705,7 @@
 			str << *xmpdatum;
 #endif
 
-		return g_locale_to_utf8(str.str().c_str(), -1, NULL, NULL, NULL);
+		return utf8_validate_or_convert(str.str().c_str());
 #endif
 	}
 	catch (Exiv2::AnyError& e) {
@@ -720,8 +730,7 @@
 			if (pos != std::string::npos) str = str.substr(pos+1);
 			}
 
-//		return g_locale_to_utf8(str.c_str(), -1, NULL, NULL, NULL); // FIXME
-		return g_strdup(str.c_str());
+		return utf8_validate_or_convert(str.c_str());
 	}
 	catch (Exiv2::AnyError& e) {
 		return NULL;
@@ -764,7 +773,7 @@
 {
 	try {
 		Exiv2::ExifKey ekey(key);
-		return g_locale_to_utf8(Exiv2::ExifTags::tagLabel(ekey.tag(), ekey.ifdId ()), -1, NULL, NULL, NULL);
+		return utf8_validate_or_convert(Exiv2::ExifTags::tagLabel(ekey.tag(), ekey.ifdId ()));
 	}
 	catch (Exiv2::AnyError& e) {
 		std::cout << "Caught Exiv2 exception '" << e << "'\n";
@@ -875,11 +884,12 @@
 }
 
 
-static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item)
+static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item, MetadataFormat format, const Exiv2::ExifData *metadata)
 {
 #if EXIV2_TEST_VERSION(0,16,0)
 	Exiv2::TypeId id = item.typeId();
-	if (id == Exiv2::asciiString ||
+	if (format == METADATA_FORMATTED ||
+	    id == Exiv2::asciiString ||
 	    id == Exiv2::undefined ||
 	    id == Exiv2::string ||
 	    id == Exiv2::date ||
@@ -891,11 +901,48 @@
 		{
 #endif 
 		/* read as a single entry */
-		std::string str = item.toString();
-		if (str.length() > 5 && str.substr(0, 5) == "lang=")
+		std::string str;
+		
+		if (format == METADATA_FORMATTED)
 			{
-			std::string::size_type pos = str.find_first_of(' ');
-			if (pos != std::string::npos) str = str.substr(pos+1);
+#if EXIV2_TEST_VERSION(0,17,0)
+			str = item.print(
+#if EXIV2_TEST_VERSION(0,18,0)
+					metadata
+#endif 
+					);
+#else
+			std::stringstream stream;
+			Exiv2::Exifdatum *exifdatum;
+			Exiv2::Iptcdatum *iptcdatum;
+#if EXIV2_TEST_VERSION(0,16,0)
+			Exiv2::Xmpdatum *xmpdatum;
+#endif
+			if ((exifdatum = dynamic_cast<Exiv2::Exifdatum *>(metadatum)))
+				stream << *exifdatum;
+			else if ((iptcdatum = dynamic_cast<Exiv2::Iptcdatum *>(metadatum)))
+				stream << *iptcdatum;
+#if EXIV2_TEST_VERSION(0,16,0)
+			else if ((xmpdatum = dynamic_cast<Exiv2::Xmpdatum *>(metadatum)))
+				stream << *xmpdatum;
+#endif
+			str = stream.str();
+#endif
+			if (str.length() > 1024)
+				{
+				/* truncate very long strings, they cause problems in gui */
+				str.erase(1024);
+				str.append("...");
+				}
+			}
+		else
+			{
+			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())); 
 #if EXIV2_TEST_VERSION(0,16,0)
@@ -911,16 +958,15 @@
 	return list;
 }
 
-static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key)
+static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key, MetadataFormat format)
 {
 	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);
+				list = exif_add_value_to_glist(list, *pos, format, &exif->exifData());
 
 		}
 		catch (Exiv2::AnyError& e) {
@@ -930,7 +976,7 @@
 				while (pos != exif->iptcData().end())
 					{
 					if (pos->key() == key)
-						list = exif_add_value_to_glist(list, *pos);
+						list = exif_add_value_to_glist(list, *pos, format, NULL);
 					++pos;
 					}
 
@@ -940,7 +986,7 @@
 				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);
+					list = exif_add_value_to_glist(list, *pos, format, NULL);
 #endif
 			}
 		}
@@ -951,23 +997,33 @@
 	return list;
 }
 
-GList *exif_get_metadata(ExifData *exif, const gchar *key)
+GList *exif_get_metadata(ExifData *exif, const gchar *key, MetadataFormat format)
 {
 	GList *list = NULL;
-	
-	list = exif_get_metadata_simple(exif, key);
+
+	if (!key) return NULL;
+
+	if (format == METADATA_FORMATTED)
+		{
+		gchar *text;
+		gint key_valid;
+		text = exif_get_formatted_by_key(exif, key, &key_valid);
+		if (key_valid) return g_list_append(NULL, text);
+		}
+		
+	list = exif_get_metadata_simple(exif, key, format);
 	
 	/* 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);
+			list = exif_get_metadata_simple(exif, alt_key->iptc_key, format);
 
 #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);
+			list = exif_get_metadata_simple(exif, alt_key->exif_key, format);
 #endif
 		}
 	return list;
--- a/src/image-overlay.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/image-overlay.c	Sat Feb 07 19:01:21 2009 +0000
@@ -178,7 +178,7 @@
 
 	g_assert(fd);
 
-	keywords = metadata_read_list(fd, KEYWORD_KEY);
+	keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
 
 	if (keywords)
 		{
@@ -278,24 +278,14 @@
 			}
 		else if (strcmp(name, "comment") == 0)
 			{
-			data = metadata_read_string(imd->image_fd, COMMENT_KEY);
+			data = metadata_read_string(imd->image_fd, COMMENT_KEY, METADATA_PLAIN);
 			}
 		else
 			{
-			/*
-			   keywords and comment can't be read between exif_read_fd and exif_free_fd calls
-			   because fd->exif does not count references
-			   on the other hand, it is OK to call it in the loop because it is cached
-			*/
-			   
-			ExifData *exif;
-			exif = exif_read_fd(imd->image_fd);
-
 			data = g_strdup(g_hash_table_lookup(vars, name));
 			if (data && strcmp(name, "zoom") == 0) imd->overlay_show_zoom = TRUE;
-			if (!data && exif)
-				data = exif_get_data_as_text(exif, name);
-			exif_free_fd(imd->image_fd, exif);
+			if (!data)
+				data = metadata_read_string(imd->image_fd, name, METADATA_FORMATTED);
 			}
 	
 		if (data && *data && limit > 0 && strlen(data) > limit + 3)
--- a/src/image.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/image.c	Sat Feb 07 19:01:21 2009 +0000
@@ -18,6 +18,7 @@
 #include "collect.h"
 #include "color-man.h"
 #include "exif.h"
+#include "metadata.h"
 #include "histogram.h"
 #include "image-load.h"
 #include "image-overlay.h"
@@ -999,31 +1000,20 @@
 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom, gint lazy)
 {
 
-	ExifData *exif = NULL;
-	gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
-	gint read_exif_for_orientation = FALSE;
 
 	/* read_exif and similar functions can actually notice that the file has changed and triger a notification
 	that removes the pixbuf	from cache and unref it. Therefore we must ref it here before it is taken over by the renderer. */
 	if (pixbuf) g_object_ref(pixbuf); 
 	
-	if (imd->image_fd && imd->image_fd->user_orientation)
-		imd->orientation = imd->image_fd->user_orientation;
-	else if (options->image.exif_rotate_enable)
-		read_exif_for_orientation = TRUE;
-
-	if (read_exif_for_color_profile || read_exif_for_orientation)
+	if (imd->image_fd)
 		{
-		gint orientation;
-
-		exif = exif_read_fd(imd->image_fd);
-
-		if (exif && read_exif_for_orientation)
+		if (imd->image_fd->user_orientation)
 			{
-			if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
-				imd->orientation = orientation;
-			else
-				imd->orientation = 1;
+			imd->orientation = imd->image_fd->user_orientation;
+			}
+		else if (options->image.exif_rotate_enable)
+			{
+			imd->orientation = metadata_read_int(imd->image_fd, "Exif.Image.Orientation", EXIF_ORIENTATION_TOP_LEFT);
 			imd->image_fd->exif_orientation = imd->orientation;
 			}
 		}
@@ -1049,15 +1039,18 @@
 
 	if (imd->color_profile_enable)
 		{
+		ExifData *exif = NULL;
+
+		if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
+
 		if (!image_post_process_color(imd, 0, exif, FALSE))
 			{
 			/* fixme: note error to user */
 //			image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
 			}
-		}
+		if (exif) exif_free_fd(imd->image_fd, exif);
 
-	if (read_exif_for_color_profile || read_exif_for_orientation)
-		exif_free_fd(imd->image_fd, exif);
+		}
 
 	if (imd->cm || imd->desaturate)
 		pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
--- a/src/main.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/main.c	Sat Feb 07 19:01:21 2009 +0000
@@ -32,6 +32,7 @@
 #include "thumb.h"
 #include "metadata.h"
 #include "editors.h"
+#include "exif.h"
 
 #include <gdk/gdkkeysyms.h> /* for keyboard values */
 
@@ -728,6 +729,8 @@
 	textdomain(PACKAGE);
 #endif
 
+	exif_init();
+	
 	/* setup random seed for random slideshow */
 	srand(time(NULL));
 
--- a/src/metadata.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/metadata.c	Sat Feb 07 19:01:21 2009 +0000
@@ -447,14 +447,14 @@
 	return g_list_reverse(newlist);
 }
 
-GList *metadata_read_list(FileData *fd, const gchar *key)
+GList *metadata_read_list(FileData *fd, const gchar *key, MetadataFormat format)
 {
 	ExifData *exif;
 	GList *list = NULL;
 	if (!fd) return NULL;
 
 	/* unwritten data overide everything */
-	if (fd->modified_xmp)
+	if (fd->modified_xmp && format == METADATA_PLAIN)
 		{
 	        list = g_hash_table_lookup(fd->modified_xmp, key);
 		if (list) return string_list_copy(list);
@@ -480,14 +480,14 @@
 	
 	exif = exif_read_fd(fd); /* this is cached, thus inexpensive */
 	if (!exif) return NULL;
-	list = exif_get_metadata(exif, key);
+	list = exif_get_metadata(exif, key, format);
 	exif_free_fd(fd, exif);
 	return list;
 }
 
-gchar *metadata_read_string(FileData *fd, const gchar *key)
+gchar *metadata_read_string(FileData *fd, const gchar *key, MetadataFormat format)
 {
-	GList *string_list = metadata_read_list(fd, key);
+	GList *string_list = metadata_read_list(fd, key, format);
 	if (string_list)
 		{
 		gchar *str = string_list->data;
@@ -497,10 +497,23 @@
 		}
 	return NULL;
 }
+
+guint64 metadata_read_int(FileData *fd, const gchar *key, guint64 fallback)
+{
+	guint64 ret;
+	gchar *endptr;
+	gchar *string = metadata_read_string(fd, key, METADATA_PLAIN);
+	if (!string) return fallback;
+	
+	ret = g_ascii_strtoull(string, &endptr, 10);
+	if (string == endptr) ret = fallback;
+	g_free(string);
+	return ret;
+}
 	
 gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value)
 {
-	gchar *str = metadata_read_string(fd, key);
+	gchar *str = metadata_read_string(fd, key, METADATA_PLAIN);
 	
 	if (!str) 
 		{
@@ -518,7 +531,7 @@
 
 gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values)
 {
-	GList *list = metadata_read_list(fd, key);
+	GList *list = metadata_read_list(fd, key, METADATA_PLAIN);
 	
 	if (!list) 
 		{
@@ -598,7 +611,7 @@
 {
 	GList *keywords;
 	gboolean found = FALSE;
-	keywords = metadata_read_list(fd, KEYWORD_KEY);
+	keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
 	if (keywords)
 		{
 		GList *work = keywords;
@@ -625,7 +638,7 @@
 	gboolean found = FALSE;
 	gboolean changed = FALSE;
 	GList *work;
-	keywords = metadata_read_list(fd, KEYWORD_KEY);
+	keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
 
 	work = keywords;
 
--- a/src/metadata.h	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/metadata.h	Sat Feb 07 19:01:21 2009 +0000
@@ -27,8 +27,9 @@
 gboolean metadata_write_list(FileData *fd, const gchar *key, const GList *values);
 gboolean metadata_write_string(FileData *fd, const gchar *key, const char *value);
 
-GList *metadata_read_list(FileData *fd, const gchar *key);
-gchar *metadata_read_string(FileData *fd, const gchar *key);
+GList *metadata_read_list(FileData *fd, const gchar *key, MetadataFormat format);
+gchar *metadata_read_string(FileData *fd, const gchar *key, MetadataFormat format);
+guint64 metadata_read_int(FileData *fd, const gchar *key, guint64 fallback);
 
 gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value);
 gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values);
--- a/src/pan-view.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/pan-view.c	Sat Feb 07 19:01:21 2009 +0000
@@ -18,6 +18,7 @@
 #include "dnd.h"
 #include "editors.h"
 #include "exif.h"
+#include "metadata.h"
 #include "fullscreen.h"
 #include "history_list.h"
 #include "img-view.h"
@@ -1434,13 +1435,10 @@
 
 static void pan_info_add_exif(PanTextAlignment *ta, FileData *fd)
 {
-	ExifData *exif;
 	GList *work;
 	gint i;
 
 	if (!fd) return;
-	exif = exif_read_fd(fd);
-	if (!exif) return;
 
 	pan_text_alignment_add(ta, NULL, NULL);
 
@@ -1449,11 +1447,11 @@
 		gchar *label;
 		gchar *desc;
 		gchar *text;
-		gchar *utf8_text;
 
 		if (ExifUIList[i].current == EXIF_UI_OFF) continue;
 
-		text = exif_get_data_as_text(exif, ExifUIList[i].key);
+		text = metadata_read_string(fd, ExifUIList[i].key, METADATA_FORMATTED);
+		
 		if (ExifUIList[i].current == EXIF_UI_IFSET && (!text || !*text))
 			{
 			g_free(text);
@@ -1463,11 +1461,9 @@
 		desc = exif_get_description_by_key(ExifUIList[i].key);
 		label = g_strdup_printf("%s:", desc);
 		g_free(desc);
-		utf8_text = utf8_validate_or_convert(text);
+		pan_text_alignment_add(ta, label, text);
+		g_free(label);
 		g_free(text);
-		pan_text_alignment_add(ta, label, utf8_text);
-		g_free(label);
-		g_free(utf8_text);
 		}
 
 	work = g_list_last(history_list_get_by_key("exif_extras"));
@@ -1480,20 +1476,15 @@
 		name = work->data;
 		work = work->prev;
 
-		text = exif_get_data_as_text(exif, name);
+		text =  metadata_read_string(fd, name, METADATA_FORMATTED);
 		if (text)
 			{
 			gchar *label = g_strdup_printf("%s:", name);
-			gchar *utf8_text = utf8_validate_or_convert(text);
-
+			pan_text_alignment_add(ta, label, text);
+			g_free(label);
 			g_free(text);
-			pan_text_alignment_add(ta, label, utf8_text);
-			g_free(label);
-			g_free(utf8_text);
 			}
 		}
-
-	exif_free_fd(fd, exif);
 }
 
 static void pan_info_update(PanWindow *pw, PanItem *pi)
--- a/src/search.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/search.c	Sat Feb 07 19:01:21 2009 +0000
@@ -1804,7 +1804,7 @@
 		tested = TRUE;
 		match = FALSE;
 
-		list = metadata_read_list(fd, KEYWORD_KEY);
+		list = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
 
 		if (list)
 			{
@@ -1884,7 +1884,7 @@
 		tested = TRUE;
 		match = FALSE;
 
-		comment = metadata_read_string(fd, COMMENT_KEY);
+		comment = metadata_read_string(fd, COMMENT_KEY, METADATA_PLAIN);
 
 		if (comment)
 			{
--- a/src/thumb.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/thumb.c	Sat Feb 07 19:01:21 2009 +0000
@@ -21,6 +21,7 @@
 #include "thumb_standard.h"
 #include "ui_fileops.h"
 #include "exif.h"
+#include "metadata.h"
 
 #include <utime.h>
 
@@ -141,14 +142,7 @@
 		{
 		if (!tl->fd->exif_orientation)
 			{
-			ExifData *exif = exif_read_fd(tl->fd);
-			gint orientation;
-
-			if (exif && exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
-				tl->fd->exif_orientation = orientation;
-			else
-				tl->fd->exif_orientation = EXIF_ORIENTATION_TOP_LEFT;
-			exif_free_fd(tl->fd, exif);
+			tl->fd->exif_orientation = metadata_read_int(tl->fd, "Exif.Image.Orientation", EXIF_ORIENTATION_TOP_LEFT);
 			}
 		
 		if (tl->fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
--- a/src/thumb_standard.c	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/thumb_standard.c	Sat Feb 07 19:01:21 2009 +0000
@@ -20,6 +20,7 @@
 #include "ui_fileops.h"
 #include "filedata.h"
 #include "exif.h"
+#include "metadata.h"
 
 
 /*
@@ -394,14 +395,7 @@
 		{
 		if (!tl->fd->exif_orientation)
 			{
-			ExifData *exif = exif_read_fd(tl->fd);
-			gint orientation;
-
-			if (exif && exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
-				tl->fd->exif_orientation = orientation;
-			else
-				tl->fd->exif_orientation = EXIF_ORIENTATION_TOP_LEFT;
-			exif_free_fd(tl->fd, exif);
+			tl->fd->exif_orientation = metadata_read_int(tl->fd, "Exif.Image.Orientation", EXIF_ORIENTATION_TOP_LEFT);
 			}
 		
 		if (tl->fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
--- a/src/typedefs.h	Fri Feb 06 23:49:03 2009 +0000
+++ b/src/typedefs.h	Sat Feb 07 19:01:21 2009 +0000
@@ -164,6 +164,12 @@
 	CHANGE_GENERIC_ERROR           = 1 << 16
 } ChangeError;
 
+typedef enum {
+	METADATA_PLAIN		= 0, /* format that can be edited and written back */
+	METADATA_FORMATTED	= 1  /* for display only */
+} MetadataFormat;
+
+
 #define MAX_SPLIT_IMAGES 4
 
 typedef struct _ImageLoader ImageLoader;