summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Riemann <[email protected]>2013-10-30 19:05:12 +0100
committerraveit65 <[email protected]>2018-07-26 00:45:21 +0200
commit49c5c977f26dfd1d02b493260ca79f43a291ad89 (patch)
tree3ad7764beb337e88bfc5575a23ed40157cdf7f74
parent9593351e473942268e6297011634d75246d4e246 (diff)
downloadeom-49c5c977f26dfd1d02b493260ca79f43a291ad89.tar.bz2
eom-49c5c977f26dfd1d02b493260ca79f43a291ad89.tar.xz
EomExifDetails: Rename to EomMetadataDetails
The widget is not specific to Exif, and is used for XMP as well. https://bugzilla.gnome.org/show_bug.cgi?id=509406 origin commit: https://gitlab.gnome.org/GNOME/eog/commit/2969a58 Plus a clean up, tabs to spaces for eom-metadata-details.c/h
-rw-r--r--doc/reference/Makefile.am2
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/Makefile.am15
-rw-r--r--src/eom-exif-details.c665
-rw-r--r--src/eom-exif-details.h72
-rw-r--r--src/eom-metadata-details.c665
-rw-r--r--src/eom-metadata-details.h72
-rw-r--r--src/eom-properties-dialog.c8
8 files changed, 751 insertions, 750 deletions
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
index 9c5aa63..e6fc457 100644
--- a/doc/reference/Makefile.am
+++ b/doc/reference/Makefile.am
@@ -58,7 +58,7 @@ if !HAVE_EXIF
if !HAVE_EXEMPI
IGNORE_HFILES += \
eom-exif-util.h \
- eom-exif-details.h
+ eom-metadata-details.h
endif
endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7e62f4c..efd637e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -20,7 +20,7 @@ src/eom-file-chooser.c
src/eom-image.c
src/eom-image-jpeg.c
src/eom-error-message-area.c
-src/eom-exif-details.c
+src/eom-metadata-details.c
src/eom-exif-util.c
src/eom-metadata-sidebar.c
src/eom-preferences-dialog.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8f9cab7..912fe1c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -111,23 +111,24 @@ libeom_la_SOURCES = \
if HAVE_EXIF
INST_H_FILES += \
- eom-exif-util.h \
- eom-exif-details.h
+ eom-metadata-details.h \
+ eom-exif-util.h
+
libeom_c_files += \
- eom-exif-util.c \
- eom-exif-details.c
+ eom-metadata-details.c \
+ eom-exif-util.c
endif
if HAVE_EXEMPI
-# We need to make sure eom-exif-details.h
+# We need to make sure eom-metadata-details.h
# is only listed once in INST_H_FILES
# or the build will break with automake-1.11
if !HAVE_EXIF
INST_H_FILES += \
- eom-exif-details.h
+ eom-metadata-details.h
endif !HAVE_EXIF
libeom_la_SOURCES += \
- eom-exif-details.c
+ eom-metadata-details.c
endif HAVE_EXEMPI
libeom_la_CPPFLAGS = \
diff --git a/src/eom-exif-details.c b/src/eom-exif-details.c
deleted file mode 100644
index 2203a60..0000000
--- a/src/eom-exif-details.c
+++ /dev/null
@@ -1,665 +0,0 @@
-/* Eye Of Mate - EOM Image Exif Details
- *
- * Copyright (C) 2006 The Free Software Foundation
- *
- * Author: Lucas Rocha <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "eom-exif-details.h"
-#include "eom-util.h"
-
-#if HAVE_EXIF
-#include <libexif/exif-entry.h>
-#include <libexif/exif-utils.h>
-#endif
-#if HAVE_EXEMPI
-#include <exempi/xmp.h>
-#include <exempi/xmpconsts.h>
-#endif
-
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-
-#include <string.h>
-
-typedef enum {
- EXIF_CATEGORY_CAMERA,
- EXIF_CATEGORY_IMAGE_DATA,
- EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS,
- EXIF_CATEGORY_GPS_DATA,
- EXIF_CATEGORY_MAKER_NOTE,
- EXIF_CATEGORY_OTHER,
-#ifdef HAVE_EXEMPI
- XMP_CATEGORY_EXIF,
- XMP_CATEGORY_IPTC,
- XMP_CATEGORY_RIGHTS,
- XMP_CATEGORY_OTHER
-#endif
-} ExifCategory;
-
-typedef struct {
- char *label;
- char *path;
-} ExifCategoryInfo;
-
-static ExifCategoryInfo exif_categories[] = {
- { N_("Camera"), "0" },
- { N_("Image Data"), "1" },
- { N_("Image Taking Conditions"), "2" },
- { N_("GPS Data"), "3" },
- { N_("Maker Note"), "4" },
- { N_("Other"), "5" },
-#ifdef HAVE_EXEMPI
- { N_("XMP Exif"), "6" },
- { N_("XMP IPTC"), "7" },
- { N_("XMP Rights Management"), "8" },
- { N_("XMP Other"), "9" },
-#endif
- { NULL, NULL }
-};
-
-typedef struct {
- int id;
- ExifCategory category;
-} ExifTagCategory;
-
-#ifdef HAVE_EXIF
-static ExifTagCategory exif_tag_category_map[] = {
- { EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_INTEROPERABILITY_VERSION, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_IMAGE_WIDTH, EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_IMAGE_LENGTH , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_BITS_PER_SAMPLE ,EXIF_CATEGORY_CAMERA },
- { EXIF_TAG_COMPRESSION , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_PHOTOMETRIC_INTERPRETATION , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_FILL_ORDER , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_DOCUMENT_NAME , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_IMAGE_DESCRIPTION , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_MAKE , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_MODEL , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_STRIP_OFFSETS , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_ORIENTATION , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_SAMPLES_PER_PIXEL , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_ROWS_PER_STRIP , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_STRIP_BYTE_COUNTS , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_X_RESOLUTION , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_Y_RESOLUTION , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_PLANAR_CONFIGURATION , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_RESOLUTION_UNIT , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_TRANSFER_FUNCTION , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_SOFTWARE , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_DATE_TIME , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_ARTIST , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_WHITE_POINT , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_TRANSFER_RANGE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_JPEG_PROC , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, },
- { EXIF_TAG_YCBCR_COEFFICIENTS , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_YCBCR_SUB_SAMPLING , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_YCBCR_POSITIONING , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_REFERENCE_BLACK_WHITE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT,EXIF_CATEGORY_OTHER},
- { EXIF_TAG_RELATED_IMAGE_WIDTH , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_RELATED_IMAGE_LENGTH , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_CFA_REPEAT_PATTERN_DIM, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_CFA_PATTERN , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_BATTERY_LEVEL , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_COPYRIGHT , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_EXPOSURE_TIME , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_FNUMBER , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_IPTC_NAA , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_EXIF_IFD_POINTER , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_INTER_COLOR_PROFILE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_EXPOSURE_PROGRAM , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SPECTRAL_SENSITIVITY , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_GPS_INFO_IFD_POINTER , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_ISO_SPEED_RATINGS , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_OECF , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_EXIF_VERSION , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_DATE_TIME_ORIGINAL , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_DATE_TIME_DIGITIZED , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_COMPONENTS_CONFIGURATION , EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_SHUTTER_SPEED_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_BRIGHTNESS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_EXPOSURE_BIAS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_MAX_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SUBJECT_DISTANCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_METERING_MODE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_LIGHT_SOURCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_FLASH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_FOCAL_LENGTH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SUBJECT_AREA , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_MAKER_NOTE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_USER_COMMENT , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_SUBSEC_TIME , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_FLASH_PIX_VERSION , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_COLOR_SPACE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_PIXEL_X_DIMENSION , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_PIXEL_Y_DIMENSION , EXIF_CATEGORY_IMAGE_DATA},
- { EXIF_TAG_RELATED_SOUND_FILE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_FLASH_ENERGY ,EXIF_CATEGORY_OTHER },
- { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_SUBJECT_LOCATION, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_EXPOSURE_INDEX, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SENSING_METHOD, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_FILE_SOURCE , EXIF_CATEGORY_OTHER},
- { EXIF_TAG_SCENE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_NEW_CFA_PATTERN, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_CUSTOM_RENDERED, EXIF_CATEGORY_OTHER},
- { EXIF_TAG_EXPOSURE_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_WHITE_BALANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_SCENE_CAPTURE_TYPE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_GAIN_CONTROL , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_CONTRAST , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SATURATION , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_SHARPNESS , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_DEVICE_SETTING_DESCRIPTION, EXIF_CATEGORY_CAMERA},
- { EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
- { EXIF_TAG_IMAGE_UNIQUE_ID , EXIF_CATEGORY_IMAGE_DATA},
- { -1, -1 }
-};
-#endif
-
-#define MODEL_COLUMN_ATTRIBUTE 0
-#define MODEL_COLUMN_VALUE 1
-
-struct _EomExifDetailsPrivate {
- GtkTreeModel *model;
-
- GHashTable *id_path_hash;
- GHashTable *id_path_hash_mnote;
-};
-
-static char* set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value);
-
-static void eom_exif_details_reset (EomExifDetails *exif_details);
-
-G_DEFINE_TYPE_WITH_PRIVATE (EomExifDetails, eom_exif_details, GTK_TYPE_TREE_VIEW)
-
-static void
-eom_exif_details_dispose (GObject *object)
-{
- EomExifDetailsPrivate *priv;
-
- priv = EOM_EXIF_DETAILS (object)->priv;
-
- if (priv->model) {
- g_object_unref (priv->model);
- priv->model = NULL;
- }
-
- if (priv->id_path_hash) {
- g_hash_table_destroy (priv->id_path_hash);
- priv->id_path_hash = NULL;
- }
-
- if (priv->id_path_hash_mnote) {
- g_hash_table_destroy (priv->id_path_hash_mnote);
- priv->id_path_hash_mnote = NULL;
- }
- G_OBJECT_CLASS (eom_exif_details_parent_class)->dispose (object);
-}
-
-static void
-eom_exif_details_init (EomExifDetails *exif_details)
-{
- EomExifDetailsPrivate *priv;
- GtkTreeViewColumn *column;
- GtkCellRenderer *cell;
-
- exif_details->priv = eom_exif_details_get_instance_private (exif_details);
-
- priv = exif_details->priv;
-
- priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
- priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
- priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
-
- /* Tag name column */
- cell = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell,
- "text", MODEL_COLUMN_ATTRIBUTE,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column);
-
- /* Value column */
- cell = gtk_cell_renderer_text_new ();
- g_object_set (cell,
- "editable", TRUE,
- NULL);
- column = gtk_tree_view_column_new_with_attributes (_("Value"), cell,
- "text", MODEL_COLUMN_VALUE,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column);
-
- eom_exif_details_reset (exif_details);
-
- gtk_tree_view_set_model (GTK_TREE_VIEW (exif_details),
- GTK_TREE_MODEL (priv->model));
-}
-
-static void
-eom_exif_details_class_init (EomExifDetailsClass *klass)
-{
- GObjectClass *object_class = (GObjectClass*) klass;
-
- object_class->dispose = eom_exif_details_dispose;
-}
-
-#ifdef HAVE_EXIF
-static ExifCategory
-get_exif_category (ExifEntry *entry)
-{
- ExifCategory cat = EXIF_CATEGORY_OTHER;
- int i;
-
- /* Some GPS tag IDs overlap with other ones, so check the IFD */
- if (exif_entry_get_ifd (entry) == EXIF_IFD_GPS) {
- return EXIF_CATEGORY_GPS_DATA;
- }
-
- for (i = 0; exif_tag_category_map [i].id != -1; i++) {
- if (exif_tag_category_map[i].id == (int) entry->tag) {
- cat = exif_tag_category_map[i].category;
- break;
- }
- }
-
- return cat;
-}
-#endif
-
-static char*
-set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value)
-{
- GtkTreeIter iter;
- gchar *utf_attribute = NULL;
- gchar *utf_value = NULL;
- gboolean iter_valid = FALSE;
-
- if (!attribute) return NULL;
-
- if (path != NULL) {
- iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path);
- }
-
- if (!iter_valid) {
- GtkTreePath *tree_path;
- GtkTreeIter parent_iter;
- gboolean parent_valid = FALSE;
-
- if (parent != NULL) {
- parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store),
- &parent_iter,
- parent);
- }
-
- gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL);
-
- if (path == NULL) {
- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
-
- if (tree_path != NULL) {
- path = gtk_tree_path_to_string (tree_path);
- gtk_tree_path_free (tree_path);
- }
- }
- }
-
- utf_attribute = eom_util_make_valid_utf8 (attribute);
-
- gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1);
- g_free (utf_attribute);
-
- if (value != NULL) {
- utf_value = eom_util_make_valid_utf8 (value);
- gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1);
- g_free (utf_value);
- }
-
- return path;
-}
-
-#ifdef HAVE_EXIF
-
-static const char *
-eom_exif_entry_get_value (ExifEntry *e,
- char *buf,
- guint n_buf)
-{
- ExifByteOrder bo;
-
- /* For now we only want to reformat some GPS values */
- if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS))
- return exif_entry_get_value (e, buf, n_buf);
-
- bo = exif_data_get_byte_order (e->parent->parent);
-
- /* Cast to number to avoid warnings about values not in enumeration */
- switch ((guint16) e->tag) {
- case EXIF_TAG_GPS_LATITUDE:
- case EXIF_TAG_GPS_LONGITUDE:
- {
- gsize rational_size;
- ExifRational r;
- gfloat h = 0., m = 0.;
-
-
- rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL);
- if (G_UNLIKELY (e->components != 3 ||
- e->format != EXIF_FORMAT_RATIONAL))
- return exif_entry_get_value (e, buf, n_buf);
-
- r = exif_get_rational (e->data, bo);
- if (r.denominator != 0)
- h = (gfloat)r.numerator / r.denominator;
-
- r = exif_get_rational (e->data + rational_size, bo);
- if (r.denominator != 0)
- m = (gfloat)r.numerator / (gfloat)r.denominator;
-
- r = exif_get_rational (e->data + (2 * rational_size),
- bo);
- if (r.numerator != 0 && r.denominator != 0) {
- gfloat s;
-
- s = (gfloat)r.numerator / (gfloat)r.denominator;
- g_snprintf (buf, n_buf,
- "%.0f° %.0f' %.2f\"",
- h, m, s);
- } else {
- g_snprintf (buf, n_buf,
- "%.0f° %.2f'",
- h, m);
- }
-
- break;
- }
- case EXIF_TAG_GPS_LATITUDE_REF:
- case EXIF_TAG_GPS_LONGITUDE_REF:
- {
- if (G_UNLIKELY (e->components != 2 ||
- e->format != EXIF_FORMAT_ASCII))
- return exif_entry_get_value (e, buf, n_buf);
-
- switch (e->data[0]) {
- case 'N':
- g_snprintf (buf, n_buf, "%s", _("North"));
- break;
- case 'E':
- g_snprintf (buf, n_buf, "%s", _("East"));
- break;
- case 'W':
- g_snprintf (buf, n_buf, "%s", _("West"));
- break;
- case 'S':
- g_snprintf (buf, n_buf, "%s", _("South"));
- break;
- default:
- return exif_entry_get_value (e, buf, n_buf);
- break;
- }
- break;
- }
- default:
- return exif_entry_get_value (e, buf, n_buf);
- break;
- }
-
- return buf;
-}
-
-static void
-exif_entry_cb (ExifEntry *entry, gpointer data)
-{
- GtkTreeStore *store;
- EomExifDetails *view;
- EomExifDetailsPrivate *priv;
- ExifCategory cat;
- ExifIfd ifd = exif_entry_get_ifd (entry);
- char *path;
- char b[1024];
- const gint key = ifd << 16 | entry->tag;
-
- /* This should optimize away if comparision is correct */
- g_warn_if_fail (EXIF_IFD_COUNT <= G_MAXUINT16);
-
- view = EOM_EXIF_DETAILS (data);
- priv = view->priv;
-
- store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
-
- /* Take the tag's IFD into account when caching their GtkTreePaths.
- * That should fix key collisions for tags that have the same number
- * but are stored in different IFDs. Exif tag numbers are 16-bit
- * values so we should be able to set the high word to the IFD number.
- */
- path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (key));
-
- if (path != NULL) {
- set_row_data (store,
- path,
- NULL,
- exif_tag_get_name_in_ifd (entry->tag, ifd),
- eom_exif_entry_get_value (entry, b, sizeof(b)));
- } else {
-
- ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ?
- exif_data_get_mnote_data (entry->parent->parent) : NULL);
-
- if (mnote) {
- // Supported MakerNote Found
- unsigned int i, c = exif_mnote_data_count (mnote);
-
- for (i = 0; i < c; i++) {
- path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i));
- if (path != NULL) {
- set_row_data (store, path, NULL,
- exif_mnote_data_get_title (mnote, i),
- exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
- } else {
- path = set_row_data (store,
- NULL,
- exif_categories[EXIF_CATEGORY_MAKER_NOTE].path,
- exif_mnote_data_get_title (mnote, i),
- exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
- g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path);
- }
- }
- } else {
- cat = get_exif_category (entry);
-
- path = set_row_data (store,
- NULL,
- exif_categories[cat].path,
- exif_tag_get_name_in_ifd (entry->tag, ifd),
- eom_exif_entry_get_value (entry, b,
- sizeof(b)));
-
- g_hash_table_insert (priv->id_path_hash,
- GINT_TO_POINTER (key),
- path);
- }
- }
-}
-#endif
-
-#ifdef HAVE_EXIF
-static void
-exif_content_cb (ExifContent *content, gpointer data)
-{
- exif_content_foreach_entry (content, exif_entry_cb, data);
-}
-#endif
-
-GtkWidget *
-eom_exif_details_new (void)
-{
- GObject *object;
-
- object = g_object_new (EOM_TYPE_EXIF_DETAILS, NULL);
-
- return GTK_WIDGET (object);
-}
-
-static void
-eom_exif_details_reset (EomExifDetails *exif_details)
-{
- int i;
- EomExifDetailsPrivate *priv = exif_details->priv;
-
- gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
-
- g_hash_table_remove_all (priv->id_path_hash);
- g_hash_table_remove_all (priv->id_path_hash_mnote);
-
- for (i = 0; exif_categories [i].label != NULL; i++) {
- char *translated_string;
-
- translated_string = gettext (exif_categories[i].label);
-
- set_row_data (GTK_TREE_STORE (priv->model),
- exif_categories[i].path,
- NULL,
- translated_string,
- NULL);
- }
-}
-
-#ifdef HAVE_EXIF
-void
-eom_exif_details_update (EomExifDetails *exif_details, ExifData *data)
-{
- g_return_if_fail (EOM_IS_EXIF_DETAILS (exif_details));
-
- eom_exif_details_reset (exif_details);
- if (data) {
- exif_data_foreach_content (data, exif_content_cb, exif_details);
- }
-}
-#endif /* HAVE_EXIF */
-
-#ifdef HAVE_EXEMPI
-typedef struct {
- const char *id;
- ExifCategory category;
-} XmpNsCategory;
-
-static XmpNsCategory xmp_ns_category_map[] = {
- { NS_EXIF, XMP_CATEGORY_EXIF},
- { NS_TIFF, XMP_CATEGORY_EXIF},
- { NS_XAP, XMP_CATEGORY_EXIF},
- { NS_XAP_RIGHTS, XMP_CATEGORY_RIGHTS},
- { NS_EXIF_AUX, XMP_CATEGORY_EXIF},
- { NS_DC, XMP_CATEGORY_IPTC},
- { NS_IPTC4XMP, XMP_CATEGORY_IPTC},
- { NS_CC, XMP_CATEGORY_RIGHTS},
- { NULL, -1}
-};
-
-static ExifCategory
-get_xmp_category (XmpStringPtr schema)
-{
- ExifCategory cat = XMP_CATEGORY_OTHER;
- const char *s = xmp_string_cstr(schema);
- int i;
-
- for (i = 0; xmp_ns_category_map[i].id != NULL; i++) {
- if (strcmp (xmp_ns_category_map[i].id, s) == 0) {
- cat = xmp_ns_category_map[i].category;
- break;
- }
- }
-
- return cat;
-}
-
-static void
-xmp_entry_insert (EomExifDetails *view, XmpStringPtr xmp_schema,
- XmpStringPtr xmp_path, XmpStringPtr xmp_prop)
-{
- GtkTreeStore *store;
- EomExifDetailsPrivate *priv;
- ExifCategory cat;
- char *path;
- gchar *key;
-
- priv = view->priv;
-
- key = g_strconcat (xmp_string_cstr (xmp_schema), ":",
- xmp_string_cstr (xmp_path), NULL);
-
- store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
-
- path = g_hash_table_lookup (priv->id_path_hash, key);
-
- if (path != NULL) {
- set_row_data (store, path, NULL,
- xmp_string_cstr (xmp_path),
- xmp_string_cstr (xmp_prop));
-
- g_free(key);
- }
- else {
- cat = get_xmp_category (xmp_schema);
-
- path = set_row_data (store, NULL, exif_categories[cat].path,
- xmp_string_cstr(xmp_path),
- xmp_string_cstr(xmp_prop));
-
- g_hash_table_insert (priv->id_path_hash, key, path);
- }
-}
-
-void
-eom_exif_details_xmp_update (EomExifDetails *view, XmpPtr data)
-{
- g_return_if_fail (EOM_IS_EXIF_DETAILS (view));
-
- if (data) {
- XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES);
- XmpStringPtr the_schema = xmp_string_new ();
- XmpStringPtr the_path = xmp_string_new ();
- XmpStringPtr the_prop = xmp_string_new ();
-
- while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) {
- xmp_entry_insert (view, the_schema, the_path, the_prop);
- }
-
- xmp_string_free (the_prop);
- xmp_string_free (the_path);
- xmp_string_free (the_schema);
- xmp_iterator_free (iter);
- }
-}
-#endif
diff --git a/src/eom-exif-details.h b/src/eom-exif-details.h
deleted file mode 100644
index b58af49..0000000
--- a/src/eom-exif-details.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Eye Of Mate - EOM Image Exif Details
- *
- * Copyright (C) 2006 The Free Software Foundation
- *
- * Author: Lucas Rocha <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef __EOM_EXIF_DETAILS__
-#define __EOM_EXIF_DETAILS__
-
-#include <glib-object.h>
-#include <gtk/gtk.h>
-#if HAVE_EXIF
-#include <libexif/exif-data.h>
-#endif
-#if HAVE_EXEMPI
-#include <exempi/xmp.h>
-#endif
-
-G_BEGIN_DECLS
-
-typedef struct _EomExifDetails EomExifDetails;
-typedef struct _EomExifDetailsClass EomExifDetailsClass;
-typedef struct _EomExifDetailsPrivate EomExifDetailsPrivate;
-
-#define EOM_TYPE_EXIF_DETAILS (eom_exif_details_get_type ())
-#define EOM_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetails))
-#define EOM_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass))
-#define EOM_IS_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_EXIF_DETAILS))
-#define EOM_IS_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_EXIF_DETAILS))
-#define EOM_EXIF_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass))
-
-struct _EomExifDetails {
- GtkTreeView parent;
-
- EomExifDetailsPrivate *priv;
-};
-
-struct _EomExifDetailsClass {
- GtkTreeViewClass parent_class;
-};
-
-GType eom_exif_details_get_type (void) G_GNUC_CONST;
-
-GtkWidget *eom_exif_details_new (void);
-
-#if HAVE_EXIF
-void eom_exif_details_update (EomExifDetails *view,
- ExifData *data);
-#endif
-#if HAVE_EXEMPI
-void eom_exif_details_xmp_update (EomExifDetails *view,
- XmpPtr xmp_data);
-#endif
-
-G_END_DECLS
-
-#endif /* __EOM_EXIF_DETAILS__ */
diff --git a/src/eom-metadata-details.c b/src/eom-metadata-details.c
new file mode 100644
index 0000000..ebb63bb
--- /dev/null
+++ b/src/eom-metadata-details.c
@@ -0,0 +1,665 @@
+/* Eye Of Mate - EOM Metadata Details
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-metadata-details.h"
+#include "eom-util.h"
+
+#if HAVE_EXIF
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#include <exempi/xmpconsts.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <string.h>
+
+typedef enum {
+ EXIF_CATEGORY_CAMERA,
+ EXIF_CATEGORY_IMAGE_DATA,
+ EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS,
+ EXIF_CATEGORY_GPS_DATA,
+ EXIF_CATEGORY_MAKER_NOTE,
+ EXIF_CATEGORY_OTHER,
+#ifdef HAVE_EXEMPI
+ XMP_CATEGORY_EXIF,
+ XMP_CATEGORY_IPTC,
+ XMP_CATEGORY_RIGHTS,
+ XMP_CATEGORY_OTHER
+#endif
+} MetadataCategory;
+
+typedef struct {
+ char *label;
+ char *path;
+} ExifCategoryInfo;
+
+static ExifCategoryInfo exif_categories[] = {
+ { N_("Camera"), "0" },
+ { N_("Image Data"), "1" },
+ { N_("Image Taking Conditions"), "2" },
+ { N_("GPS Data"), "3" },
+ { N_("Maker Note"), "4" },
+ { N_("Other"), "5" },
+#ifdef HAVE_EXEMPI
+ { N_("XMP Exif"), "6" },
+ { N_("XMP IPTC"), "7" },
+ { N_("XMP Rights Management"), "8" },
+ { N_("XMP Other"), "9" },
+#endif
+ { NULL, NULL }
+};
+
+typedef struct {
+ int id;
+ MetadataCategory category;
+} ExifTagCategory;
+
+#ifdef HAVE_EXIF
+static ExifTagCategory exif_tag_category_map[] = {
+ { EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_INTEROPERABILITY_VERSION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_IMAGE_WIDTH, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_IMAGE_LENGTH, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_BITS_PER_SAMPLE, EXIF_CATEGORY_CAMERA },
+ { EXIF_TAG_COMPRESSION, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_PHOTOMETRIC_INTERPRETATION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FILL_ORDER, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_DOCUMENT_NAME, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_IMAGE_DESCRIPTION, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_MAKE, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_MODEL, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_STRIP_OFFSETS, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_ORIENTATION, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_SAMPLES_PER_PIXEL, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_ROWS_PER_STRIP, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_STRIP_BYTE_COUNTS, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_X_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_Y_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_PLANAR_CONFIGURATION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_TRANSFER_FUNCTION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SOFTWARE, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_DATE_TIME, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_ARTIST, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_WHITE_POINT, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_TRANSFER_RANGE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_PROC, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, },
+ { EXIF_TAG_YCBCR_COEFFICIENTS, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_YCBCR_SUB_SAMPLING, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_YCBCR_POSITIONING, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_REFERENCE_BLACK_WHITE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RELATED_IMAGE_WIDTH, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RELATED_IMAGE_LENGTH, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CFA_REPEAT_PATTERN_DIM, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CFA_PATTERN, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_BATTERY_LEVEL, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_COPYRIGHT, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_EXPOSURE_TIME, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FNUMBER, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_IPTC_NAA, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXIF_IFD_POINTER, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_INTER_COLOR_PROFILE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_PROGRAM, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SPECTRAL_SENSITIVITY, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_GPS_INFO_IFD_POINTER, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_ISO_SPEED_RATINGS, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_OECF, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXIF_VERSION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_COMPONENTS_CONFIGURATION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SHUTTER_SPEED_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_APERTURE_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_BRIGHTNESS_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_EXPOSURE_BIAS_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_MAX_APERTURE_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SUBJECT_DISTANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_METERING_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_LIGHT_SOURCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FLASH, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FOCAL_LENGTH, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SUBJECT_AREA, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_MAKER_NOTE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_USER_COMMENT, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_SUBSEC_TIME, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FLASH_PIX_VERSION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_COLOR_SPACE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_PIXEL_X_DIMENSION, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_RELATED_SOUND_FILE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FLASH_ENERGY, EXIF_CATEGORY_OTHER },
+ { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SUBJECT_LOCATION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_INDEX, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SENSING_METHOD, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FILE_SOURCE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SCENE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_NEW_CFA_PATTERN, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CUSTOM_RENDERED, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_WHITE_BALANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SCENE_CAPTURE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_GAIN_CONTROL, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_CONTRAST, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SATURATION, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SHARPNESS, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_DEVICE_SETTING_DESCRIPTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_IMAGE_UNIQUE_ID, EXIF_CATEGORY_IMAGE_DATA},
+ { -1, -1 }
+};
+#endif
+
+#define MODEL_COLUMN_ATTRIBUTE 0
+#define MODEL_COLUMN_VALUE 1
+
+struct _EomMetadataDetailsPrivate {
+ GtkTreeModel *model;
+
+ GHashTable *id_path_hash;
+ GHashTable *id_path_hash_mnote;
+};
+
+static char* set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value);
+
+static void eom_metadata_details_reset (EomMetadataDetails *exif_details);
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomMetadataDetails, eom_metadata_details, GTK_TYPE_TREE_VIEW)
+
+static void
+eom_metadata_details_dispose (GObject *object)
+{
+ EomMetadataDetailsPrivate *priv;
+
+ priv = EOM_METADATA_DETAILS (object)->priv;
+
+ if (priv->model) {
+ g_object_unref (priv->model);
+ priv->model = NULL;
+ }
+
+ if (priv->id_path_hash) {
+ g_hash_table_destroy (priv->id_path_hash);
+ priv->id_path_hash = NULL;
+ }
+
+ if (priv->id_path_hash_mnote) {
+ g_hash_table_destroy (priv->id_path_hash_mnote);
+ priv->id_path_hash_mnote = NULL;
+ }
+ G_OBJECT_CLASS (eom_metadata_details_parent_class)->dispose (object);
+}
+
+static void
+eom_metadata_details_init (EomMetadataDetails *details)
+{
+ EomMetadataDetailsPrivate *priv;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+
+ details->priv = eom_metadata_details_get_instance_private (details);
+
+ priv = details->priv;
+
+ priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+ priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+
+ /* Tag name column */
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell,
+ "text", MODEL_COLUMN_ATTRIBUTE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (details), column);
+
+ /* Value column */
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "editable", TRUE,
+ NULL);
+ column = gtk_tree_view_column_new_with_attributes (_("Value"), cell,
+ "text", MODEL_COLUMN_VALUE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (details), column);
+
+ eom_metadata_details_reset (details);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (details),
+ GTK_TREE_MODEL (priv->model));
+}
+
+static void
+eom_metadata_details_class_init (EomMetadataDetailsClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_metadata_details_dispose;
+}
+
+#ifdef HAVE_EXIF
+static MetadataCategory
+get_exif_category (ExifEntry *entry)
+{
+ MetadataCategory cat = EXIF_CATEGORY_OTHER;
+ int i;
+
+ /* Some GPS tag IDs overlap with other ones, so check the IFD */
+ if (exif_entry_get_ifd (entry) == EXIF_IFD_GPS) {
+ return EXIF_CATEGORY_GPS_DATA;
+ }
+
+ for (i = 0; exif_tag_category_map [i].id != -1; i++) {
+ if (exif_tag_category_map[i].id == (int) entry->tag) {
+ cat = exif_tag_category_map[i].category;
+ break;
+ }
+ }
+
+ return cat;
+}
+#endif
+
+static char*
+set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value)
+{
+ GtkTreeIter iter;
+ gchar *utf_attribute = NULL;
+ gchar *utf_value = NULL;
+ gboolean iter_valid = FALSE;
+
+ if (!attribute) return NULL;
+
+ if (path != NULL) {
+ iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path);
+ }
+
+ if (!iter_valid) {
+ GtkTreePath *tree_path;
+ GtkTreeIter parent_iter;
+ gboolean parent_valid = FALSE;
+
+ if (parent != NULL) {
+ parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store),
+ &parent_iter,
+ parent);
+ }
+
+ gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL);
+
+ if (path == NULL) {
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+
+ if (tree_path != NULL) {
+ path = gtk_tree_path_to_string (tree_path);
+ gtk_tree_path_free (tree_path);
+ }
+ }
+ }
+
+ utf_attribute = eom_util_make_valid_utf8 (attribute);
+
+ gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1);
+ g_free (utf_attribute);
+
+ if (value != NULL) {
+ utf_value = eom_util_make_valid_utf8 (value);
+ gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1);
+ g_free (utf_value);
+ }
+
+ return path;
+}
+
+#ifdef HAVE_EXIF
+
+static const char *
+eom_exif_entry_get_value (ExifEntry *e,
+ char *buf,
+ guint n_buf)
+{
+ ExifByteOrder bo;
+
+ /* For now we only want to reformat some GPS values */
+ if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS))
+ return exif_entry_get_value (e, buf, n_buf);
+
+ bo = exif_data_get_byte_order (e->parent->parent);
+
+ /* Cast to number to avoid warnings about values not in enumeration */
+ switch ((guint16) e->tag) {
+ case EXIF_TAG_GPS_LATITUDE:
+ case EXIF_TAG_GPS_LONGITUDE:
+ {
+ gsize rational_size;
+ ExifRational r;
+ gfloat h = 0., m = 0.;
+
+
+ rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL);
+ if (G_UNLIKELY (e->components != 3 ||
+ e->format != EXIF_FORMAT_RATIONAL))
+ return exif_entry_get_value (e, buf, n_buf);
+
+ r = exif_get_rational (e->data, bo);
+ if (r.denominator != 0)
+ h = (gfloat)r.numerator / r.denominator;
+
+ r = exif_get_rational (e->data + rational_size, bo);
+ if (r.denominator != 0)
+ m = (gfloat)r.numerator / (gfloat)r.denominator;
+
+ r = exif_get_rational (e->data + (2 * rational_size),
+ bo);
+ if (r.numerator != 0 && r.denominator != 0) {
+ gfloat s;
+
+ s = (gfloat)r.numerator / (gfloat)r.denominator;
+ g_snprintf (buf, n_buf,
+ "%.0f° %.0f' %.2f\"",
+ h, m, s);
+ } else {
+ g_snprintf (buf, n_buf,
+ "%.0f° %.2f'",
+ h, m);
+ }
+
+ break;
+ }
+ case EXIF_TAG_GPS_LATITUDE_REF:
+ case EXIF_TAG_GPS_LONGITUDE_REF:
+ {
+ if (G_UNLIKELY (e->components != 2 ||
+ e->format != EXIF_FORMAT_ASCII))
+ return exif_entry_get_value (e, buf, n_buf);
+
+ switch (e->data[0]) {
+ case 'N':
+ g_snprintf (buf, n_buf, "%s", _("North"));
+ break;
+ case 'E':
+ g_snprintf (buf, n_buf, "%s", _("East"));
+ break;
+ case 'W':
+ g_snprintf (buf, n_buf, "%s", _("West"));
+ break;
+ case 'S':
+ g_snprintf (buf, n_buf, "%s", _("South"));
+ break;
+ default:
+ return exif_entry_get_value (e, buf, n_buf);
+ break;
+ }
+ break;
+ }
+ default:
+ return exif_entry_get_value (e, buf, n_buf);
+ break;
+ }
+
+ return buf;
+}
+
+static void
+exif_entry_cb (ExifEntry *entry, gpointer data)
+{
+ GtkTreeStore *store;
+ EomMetadataDetails *view;
+ EomMetadataDetailsPrivate *priv;
+ MetadataCategory cat;
+ ExifIfd ifd = exif_entry_get_ifd (entry);
+ char *path;
+ char b[1024];
+ const gint key = ifd << 16 | entry->tag;
+
+ /* This should optimize away if comparision is correct */
+ g_warn_if_fail (EXIF_IFD_COUNT <= G_MAXUINT16);
+
+ view = EOM_METADATA_DETAILS (data);
+ priv = view->priv;
+
+ store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+ /* Take the tag's IFD into account when caching their GtkTreePaths.
+ * That should fix key collisions for tags that have the same number
+ * but are stored in different IFDs. Exif tag numbers are 16-bit
+ * values so we should be able to set the high word to the IFD number.
+ */
+ path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (key));
+
+ if (path != NULL) {
+ set_row_data (store,
+ path,
+ NULL,
+ exif_tag_get_name_in_ifd (entry->tag, ifd),
+ eom_exif_entry_get_value (entry, b, sizeof(b)));
+ } else {
+
+ ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ?
+ exif_data_get_mnote_data (entry->parent->parent) : NULL);
+
+ if (mnote) {
+ // Supported MakerNote Found
+ unsigned int i, c = exif_mnote_data_count (mnote);
+
+ for (i = 0; i < c; i++) {
+ path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i));
+ if (path != NULL) {
+ set_row_data (store, path, NULL,
+ exif_mnote_data_get_title (mnote, i),
+ exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+ } else {
+ path = set_row_data (store,
+ NULL,
+ exif_categories[EXIF_CATEGORY_MAKER_NOTE].path,
+ exif_mnote_data_get_title (mnote, i),
+ exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+ g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path);
+ }
+ }
+ } else {
+ cat = get_exif_category (entry);
+
+ path = set_row_data (store,
+ NULL,
+ exif_categories[cat].path,
+ exif_tag_get_name_in_ifd (entry->tag, ifd),
+ eom_exif_entry_get_value (entry, b,
+ sizeof(b)));
+
+ g_hash_table_insert (priv->id_path_hash,
+ GINT_TO_POINTER (key),
+ path);
+ }
+ }
+}
+#endif
+
+#ifdef HAVE_EXIF
+static void
+exif_content_cb (ExifContent *content, gpointer data)
+{
+ exif_content_foreach_entry (content, exif_entry_cb, data);
+}
+#endif
+
+GtkWidget *
+eom_metadata_details_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (EOM_TYPE_METADATA_DETAILS, NULL);
+
+ return GTK_WIDGET (object);
+}
+
+static void
+eom_metadata_details_reset (EomMetadataDetails *details)
+{
+ EomMetadataDetailsPrivate *priv = details->priv;
+ int i;
+
+ gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
+
+ g_hash_table_remove_all (priv->id_path_hash);
+ g_hash_table_remove_all (priv->id_path_hash_mnote);
+
+ for (i = 0; exif_categories [i].label != NULL; i++) {
+ char *translated_string;
+
+ translated_string = gettext (exif_categories[i].label);
+
+ set_row_data (GTK_TREE_STORE (priv->model),
+ exif_categories[i].path,
+ NULL,
+ translated_string,
+ NULL);
+ }
+}
+
+#ifdef HAVE_EXIF
+void
+eom_metadata_details_update (EomMetadataDetails *details, ExifData *data)
+{
+ g_return_if_fail (EOM_IS_METADATA_DETAILS (details));
+
+ eom_metadata_details_reset (details);
+ if (data) {
+ exif_data_foreach_content (data, exif_content_cb, details);
+ }
+}
+#endif /* HAVE_EXIF */
+
+#ifdef HAVE_EXEMPI
+typedef struct {
+ const char *id;
+ MetadataCategory category;
+} XmpNsCategory;
+
+static XmpNsCategory xmp_ns_category_map[] = {
+ { NS_EXIF, XMP_CATEGORY_EXIF},
+ { NS_TIFF, XMP_CATEGORY_EXIF},
+ { NS_XAP, XMP_CATEGORY_EXIF},
+ { NS_XAP_RIGHTS, XMP_CATEGORY_RIGHTS},
+ { NS_EXIF_AUX, XMP_CATEGORY_EXIF},
+ { NS_DC, XMP_CATEGORY_IPTC},
+ { NS_IPTC4XMP, XMP_CATEGORY_IPTC},
+ { NS_CC, XMP_CATEGORY_RIGHTS},
+ { NULL, -1}
+};
+
+static MetadataCategory
+get_xmp_category (XmpStringPtr schema)
+{
+ MetadataCategory cat = XMP_CATEGORY_OTHER;
+ const char *s = xmp_string_cstr(schema);
+ int i;
+
+ for (i = 0; xmp_ns_category_map[i].id != NULL; i++) {
+ if (strcmp (xmp_ns_category_map[i].id, s) == 0) {
+ cat = xmp_ns_category_map[i].category;
+ break;
+ }
+ }
+
+ return cat;
+}
+
+static void
+xmp_entry_insert (EomMetadataDetails *view, XmpStringPtr xmp_schema,
+ XmpStringPtr xmp_path, XmpStringPtr xmp_prop)
+{
+ GtkTreeStore *store;
+ EomMetadataDetailsPrivate *priv;
+ MetadataCategory cat;
+ char *path;
+ gchar *key;
+
+ priv = view->priv;
+
+ key = g_strconcat (xmp_string_cstr (xmp_schema), ":",
+ xmp_string_cstr (xmp_path), NULL);
+
+ store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+ path = g_hash_table_lookup (priv->id_path_hash, key);
+
+ if (path != NULL) {
+ set_row_data (store, path, NULL,
+ xmp_string_cstr (xmp_path),
+ xmp_string_cstr (xmp_prop));
+
+ g_free(key);
+ }
+ else {
+ cat = get_xmp_category (xmp_schema);
+
+ path = set_row_data (store, NULL, exif_categories[cat].path,
+ xmp_string_cstr(xmp_path),
+ xmp_string_cstr(xmp_prop));
+
+ g_hash_table_insert (priv->id_path_hash, key, path);
+ }
+}
+
+void
+eom_metadata_details_xmp_update (EomMetadataDetails *view, XmpPtr data)
+{
+ g_return_if_fail (EOM_IS_METADATA_DETAILS (view));
+
+ if (data) {
+ XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES);
+ XmpStringPtr the_schema = xmp_string_new ();
+ XmpStringPtr the_path = xmp_string_new ();
+ XmpStringPtr the_prop = xmp_string_new ();
+
+ while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) {
+ xmp_entry_insert (view, the_schema, the_path, the_prop);
+ }
+
+ xmp_string_free (the_prop);
+ xmp_string_free (the_path);
+ xmp_string_free (the_schema);
+ xmp_iterator_free (iter);
+ }
+}
+#endif
diff --git a/src/eom-metadata-details.h b/src/eom-metadata-details.h
new file mode 100644
index 0000000..a86e537
--- /dev/null
+++ b/src/eom-metadata-details.h
@@ -0,0 +1,72 @@
+/* Eye Of Mate - EOM Image Exif Details
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __EOM_METADATA_DETAILS__
+#define __EOM_METADATA_DETAILS__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#if HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _EomMetadataDetails EomMetadataDetails;
+typedef struct _EomMetadataDetailsClass EomMetadataDetailsClass;
+typedef struct _EomMetadataDetailsPrivate EomMetadataDetailsPrivate;
+
+#define EOM_TYPE_METADATA_DETAILS (eom_metadata_details_get_type ())
+#define EOM_METADATA_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_METADATA_DETAILS, EomMetadataDetails))
+#define EOM_METADATA_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_METADATA_DETAILS, EomMetadataDetailsClass))
+#define EOM_IS_METADATA_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_METADATA_DETAILS))
+#define EOM_IS_METADATA_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_METADATA_DETAILS))
+#define EOM_METADATA_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_METADATA_DETAILS, EomMetadataDetailsClass))
+
+struct _EomMetadataDetails {
+ GtkTreeView parent;
+
+ EomMetadataDetailsPrivate *priv;
+};
+
+struct _EomMetadataDetailsClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType eom_metadata_details_get_type (void) G_GNUC_CONST;
+
+GtkWidget *eom_metadata_details_new (void);
+
+#if HAVE_EXIF
+void eom_metadata_details_update (EomMetadataDetails *details,
+ ExifData *data);
+#endif
+#if HAVE_EXEMPI
+void eom_metadata_details_xmp_update (EomMetadataDetails *details,
+ XmpPtr xmp_data);
+#endif
+
+G_END_DECLS
+
+#endif /* __EOM_METADATA_DETAILS__ */
diff --git a/src/eom-properties-dialog.c b/src/eom-properties-dialog.c
index 1999040..afe852c 100644
--- a/src/eom-properties-dialog.c
+++ b/src/eom-properties-dialog.c
@@ -48,7 +48,7 @@
#endif
#if HAVE_METADATA
-#include "eom-exif-details.h"
+#include "eom-metadata-details.h"
#endif
enum {
@@ -320,7 +320,7 @@ pd_update_metadata_tab (EomPropertiesDialog *prop_dlg,
eom_exif_util_set_label_text (GTK_LABEL (priv->exif_date_label),
exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
- eom_exif_details_update (EOM_EXIF_DETAILS (priv->exif_details),
+ eom_metadata_details_update (EOM_METADATA_DETAILS (priv->exif_details),
exif_data);
/* exif_data_unref can handle NULL-values */
@@ -356,7 +356,7 @@ pd_update_metadata_tab (EomPropertiesDialog *prop_dlg,
"rights",
priv->xmp_rights_label);
- eom_exif_details_xmp_update (EOM_EXIF_DETAILS (priv->exif_details), xmp_data);
+ eom_metadata_details_xmp_update (EOM_METADATA_DETAILS (priv->exif_details), xmp_data);
xmp_free (xmp_data);
} else {
@@ -690,7 +690,7 @@ eom_properties_dialog_init (EomPropertiesDialog *prop_dlg)
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
- priv->exif_details = eom_exif_details_new ();
+ priv->exif_details = eom_metadata_details_new ();
gtk_widget_set_size_request (priv->exif_details, -1, 170);
gtk_container_set_border_width (GTK_CONTAINER (sw), 6);
gtk_widget_set_vexpand (priv->exif_details, TRUE);