Commit bcca96ec authored by Paolo Bacchilega's avatar Paolo Bacchilega
Browse files

[metadata] write comment data in the image as well

write the metadata in the image as exif/iptc/xmp format
sync the image embedded data and the .comment metadata
parent 58cbce0f
......@@ -122,6 +122,7 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
GtkTextIter start;
GtkTextIter end;
char *text;
GthMetadata *metadata;
int i;
char **tagv;
GList *tags;
......@@ -129,14 +130,41 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
self = GTH_EDIT_COMMENT_PAGE (base);
/* comment */
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (GET_WIDGET ("note_text")));
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
g_file_info_set_attribute_string (self->priv->file_data->info, "comment::note", text);
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "Embedded::Image::Comment",
"raw", text,
"formatted", text,
NULL);
g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Comment", G_OBJECT (metadata));
g_object_unref (metadata);
g_free (text);
g_file_info_set_attribute_string (self->priv->file_data->info, "comment::place", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))));
g_file_info_set_attribute_string (self->priv->file_data->info, "comment::time", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)));
/* location */
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "Embedded::Image::Location",
"raw", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))),
"formatted", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))),
NULL);
g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Location", G_OBJECT (metadata));
g_object_unref (metadata);
/* date */
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "Embedded::Image::Date",
"raw", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)),
"formatted", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)),
NULL);
g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Date", G_OBJECT (metadata));
g_object_unref (metadata);
/* tags */
tagv = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (self->priv->tags_entry));
tags = NULL;
......@@ -144,7 +172,6 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
tags = g_list_prepend (tags, tagv[i]);
tags = g_list_reverse (tags);
string_list = gth_string_list_new (tags);
g_file_info_set_attribute_object (self->priv->file_data->info, "comment::categories", G_OBJECT (string_list));
g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Keywords", G_OBJECT (string_list));
g_object_unref (string_list);
......
......@@ -112,41 +112,69 @@ gth_metadata_provider_comment_write (GthMetadataProvider *self,
GthFileData *file_data,
const char *attributes)
{
if (_g_file_attributes_matches (attributes, "comment::*")) {
GthComment *comment;
char *data;
gsize length;
GthStringList *categories;
GFile *comment_file;
GFile *comment_folder;
comment = gth_comment_new ();
gth_comment_set_note (comment, g_file_info_get_attribute_string (file_data->info, "comment::note"));
gth_comment_set_place (comment, g_file_info_get_attribute_string (file_data->info, "comment::place"));
gth_comment_set_time_from_exif_format (comment, g_file_info_get_attribute_string (file_data->info, "comment::time"));
GthComment *comment;
GthMetadata *metadata;
const char *text;
char *data;
gsize length;
GthStringList *categories;
GFile *comment_file;
GFile *comment_folder;
comment = gth_comment_new ();
/* comment */
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Comment");
if (metadata == NULL)
text = g_file_info_get_attribute_string (file_data->info, "comment::note");
else
text = gth_metadata_get_raw (metadata);
gth_comment_set_note (comment, text);
/* location */
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Location");
if (metadata == NULL)
text = g_file_info_get_attribute_string (file_data->info, "comment::place");
else
text = gth_metadata_get_raw (metadata);
gth_comment_set_place (comment, text);
/* time */
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Date");
if (metadata == NULL)
text = g_file_info_get_attribute_string (file_data->info, "comment::time");
else
text = gth_metadata_get_raw (metadata);
gth_comment_set_time_from_exif_format (comment, text);
/* keywords */
categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Keywords");
if (categories == NULL)
categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "comment::categories");
if (categories != NULL) {
GList *list;
GList *scan;
list = gth_string_list_get_list (categories);
for (scan = list; scan; scan = scan->next)
gth_comment_add_category (comment, (char *) scan->data);
}
data = gth_comment_to_data (comment, &length);
comment_file = gth_comment_get_comment_file (file_data->file);
comment_folder = g_file_get_parent (comment_file);
g_file_make_directory (comment_folder, NULL, NULL);
g_write_file (comment_file, FALSE, 0, data, length, NULL, NULL);
g_object_unref (comment_folder);
g_object_unref (comment_file);
g_free (data);
g_object_unref (comment);
if (categories != NULL) {
GList *list;
GList *scan;
list = gth_string_list_get_list (categories);
for (scan = list; scan; scan = scan->next)
gth_comment_add_category (comment, (char *) scan->data);
}
data = gth_comment_to_data (comment, &length);
comment_file = gth_comment_get_comment_file (file_data->file);
comment_folder = g_file_get_parent (comment_file);
g_file_make_directory (comment_folder, NULL, NULL);
g_write_file (comment_file, FALSE, 0, data, length, NULL, NULL);
g_object_unref (comment_folder);
g_object_unref (comment_file);
g_free (data);
g_object_unref (comment);
}
......@@ -175,7 +203,7 @@ gth_metadata_provider_constructor (GType type,
self = GTH_METADATA_PROVIDER (obj);
g_object_set (self, "readable-attributes", "comment::*", NULL);
g_object_set (self, "writable-attributes", "comment::*", NULL);
g_object_set (self, "writable-attributes", "comment::*,Embedded::Image::*", NULL);
return obj;
}
......
......@@ -74,6 +74,99 @@ comments__add_sidecars_cb (GFile *file,
}
void
comments__read_metadata_ready_cb (GthFileData *file_data,
const char *attributes)
{
if (_g_file_attributes_matches (attributes, "Embedded::Image::*")
&& _g_file_attributes_matches (attributes, "comment::*"))
{
gboolean write_comment = FALSE;
GthMetadata *metadata;
const char *text;
GthComment *comment;
GPtrArray *keywords;
int i;
GthStringList *categories;
comment = gth_comment_new ();
gth_comment_set_note (comment, g_file_info_get_attribute_string (file_data->info, "comment::note"));
gth_comment_set_place (comment, g_file_info_get_attribute_string (file_data->info, "comment::place"));
gth_comment_set_time_from_exif_format (comment, g_file_info_get_attribute_string (file_data->info, "comment::time"));
keywords = gth_comment_get_categories (comment);
for (i = 0; i < keywords->len; i++)
gth_comment_add_category (comment, g_ptr_array_index (keywords, i));
/* sync embedded data and .comment data if required */
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Comment");
if (metadata != NULL) {
text = g_file_info_get_attribute_string (file_data->info, "comment::note");
if (g_strcmp0 (gth_metadata_get_raw (metadata), text) != 0) {
gth_comment_set_note (comment, gth_metadata_get_raw (metadata));
write_comment = TRUE;
}
}
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Location");
if (metadata != NULL) {
text = g_file_info_get_attribute_string (file_data->info, "comment::place");
if (g_strcmp0 (gth_metadata_get_raw (metadata), text) != 0) {
gth_comment_set_place (comment, gth_metadata_get_raw (metadata));
write_comment = TRUE;
}
}
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Date");
if (metadata != NULL) {
text = g_file_info_get_attribute_string (file_data->info, "comment::time");
if (g_strcmp0 (gth_metadata_get_raw (metadata), text) != 0) {
gth_comment_set_time_from_exif_format (comment, gth_metadata_get_raw (metadata));
write_comment = TRUE;
}
}
categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Keywords");
if (categories != NULL) {
GthStringList *comment_categories;
comment_categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "comment::categories");
if (! gth_string_list_equal (categories, comment_categories)) {
GList *list;
GList *scan;
gth_comment_clear_categories (comment);
list = gth_string_list_get_list (categories);
for (scan = list; scan; scan = scan->next)
gth_comment_add_category (comment, scan->data);
write_comment = TRUE;
}
}
if (write_comment) {
GFile *comment_file;
char *buffer;
gsize size;
buffer = gth_comment_to_data (comment, &size);
comment_file = gth_comment_get_comment_file (file_data->file);
g_write_file (comment_file,
FALSE,
G_FILE_CREATE_NONE,
buffer,
size,
NULL,
NULL);
g_object_unref (comment_file);
g_free (buffer);
}
g_object_unref (comment);
}
}
G_MODULE_EXPORT void
gthumb_extension_activate (void)
{
......@@ -103,6 +196,7 @@ gthumb_extension_activate (void)
"display-name", _("Tag"),
NULL);
gth_hook_add_callback ("add-sidecars", 10, G_CALLBACK (comments__add_sidecars_cb), NULL);
gth_hook_add_callback ("read-metadata-ready", 10, G_CALLBACK (comments__read_metadata_ready_cb), NULL);
}
......
......@@ -21,6 +21,7 @@
*/
#include <config.h>
#include <glib.h>
#include <exiv2/basicio.hpp>
#include <exiv2/error.hpp>
#include <exiv2/image.hpp>
......@@ -121,8 +122,8 @@ const char *_ORIENTATION_TAG_NAMES[] = {
const char *_COMMENT_TAG_NAMES[] = {
"Exif::Photo::UserComment",
"Exif::Image::ImageDescription",
"Xmp::tiff::ImageDescription",
"Xmp::dc::description",
"Xmp::tiff::ImageDescription",
"Iptc::Application2::Caption",
"Iptc::Application2::Headline",
NULL
......@@ -240,22 +241,42 @@ set_attribute_from_tagset (GFileInfo *info,
static void
set_attributes_from_tagsets (GFileInfo *info)
set_string_list_attribute_from_tagset (GFileInfo *info,
const char *attribute,
const char *tagset[])
{
/*set_attribute_from_tagset (info, "Exif::Photo::ExposureTime", _EXPOSURE_TIME_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::ExposureMode", _EXPOSURE_MODE_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::ISOSpeedRatings", _ISOSPEED_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::ApertureValue", _APERTURE_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::FocalLength", _FOCAL_LENGTH_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::ShutterSpeedValue", _SHUTTER_SPEED_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Image::Make", _MAKE_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Image::Model", _MODEL_TAG_NAMES);
set_attribute_from_tagset (info, "Exif::Photo::Flash", _FLASH_TAG_NAMES);*/
GObject *metadata;
int i;
char *raw;
char **keywords;
GthStringList *string_list;
metadata = NULL;
for (i = 0; tagset[i] != NULL; i++) {
metadata = g_file_info_get_attribute_object (info, tagset[i]);
if (metadata != NULL)
break;
}
if (metadata == NULL)
return;
g_object_get (metadata, "raw", &raw, NULL);
keywords = g_strsplit (raw, " ", -1);
string_list = gth_string_list_new_from_strv (keywords);
g_file_info_set_attribute_object (info, attribute, G_OBJECT (string_list));
g_strfreev (keywords);
g_free (raw);
}
static void
set_attributes_from_tagsets (GFileInfo *info)
{
set_attribute_from_tagset (info, "Embedded::Image::DateTime", _DATE_TAG_NAMES);
set_attribute_from_tagset (info, "Embedded::Image::Comment", _COMMENT_TAG_NAMES);
set_attribute_from_tagset (info, "Embedded::Image::Location", _LOCATION_TAG_NAMES);
set_attribute_from_tagset (info, "Embedded::Image::Keywords", _KEYWORDS_TAG_NAMES);
set_string_list_attribute_from_tagset (info, "Embedded::Image::Keywords", _KEYWORDS_TAG_NAMES);
set_attribute_from_tagset (info, "Embedded::Image::Orientation", _ORIENTATION_TAG_NAMES);
}
......@@ -515,8 +536,9 @@ exiv2_write_metadata_private (Exiv2::Image::AutoPtr image,
try {
ed[key] = gth_metadata_get_raw (metadatum);
}
catch (...) {
catch (Exiv2::AnyError& e) {
/* we don't care about invalid key errors */
g_warning ("%s", e.what());
}
g_free (key);
......@@ -597,8 +619,9 @@ exiv2_write_metadata_private (Exiv2::Image::AutoPtr image,
try {
id[key] = gth_metadata_get_raw (metadatum);
}
catch (...) {
catch (Exiv2::AnyError& e) {
/* we don't care about invalid key errors */
g_warning ("%s", e.what());
}
g_free (key);
......@@ -621,10 +644,17 @@ exiv2_write_metadata_private (Exiv2::Image::AutoPtr image,
xd.erase (iter);
try {
ed[key] = gth_metadata_get_raw (metadatum);
/*if (strcmp (key, "Xmp.dc.description") == 0) {
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::langAlt);
v->read(gth_metadata_get_raw (metadatum));
xd.add (Exiv2::XmpKey (key), v.get());
}
else FIXME */
xd[key] = gth_metadata_get_raw (metadatum);
}
catch (...) {
catch (Exiv2::AnyError& e) {
/* we don't care about invalid key errors */
g_warning ("%s", e.what());
}
g_free (key);
......
......@@ -8,4 +8,4 @@ Version=1.0
[Loader]
Type=module
File=%LIBRARY%
After=image_rotation
After=image_rotation;comments
......@@ -82,7 +82,61 @@ gth_metadata_provider_exiv2_write (GthMetadataProvider *self,
GthFileData *file_data,
const char *attributes)
{
/* FIXME */
void *buffer = NULL;
gsize size;
GError *error = NULL;
GObject *metadata;
if (! g_load_file_in_buffer (file_data->file, &buffer, &size, &error))
return;
metadata = g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Comment");
if (metadata != NULL) {
g_file_info_set_attribute_object (file_data->info, "Exif::Photo::UserComment", metadata);
g_file_info_set_attribute_object (file_data->info, "Xmp::dc::description", metadata);
g_file_info_set_attribute_object (file_data->info, "Iptc::Application2::Headline", metadata);
}
metadata = g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Location");
if (metadata != NULL) {
g_file_info_set_attribute_object (file_data->info, "Xmp::iptc::Location", metadata);
g_file_info_set_attribute_object (file_data->info, "Iptc::Application2::LocationName", metadata);
}
metadata = g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Keywords");
if (metadata != NULL) {
GthMetadata *meta;
char *raw;
meta = gth_metadata_new ();
raw = gth_file_data_get_attribute_as_string (file_data, "Embedded::Image::Keywords");
g_object_set (meta, "id", "Embedded::Image::Keywords", "raw", raw, NULL);
g_file_info_set_attribute_object (file_data->info, "Xmp::iptc::Keywords", G_OBJECT (meta));
g_file_info_set_attribute_object (file_data->info, "Iptc::Application2::Keywords", G_OBJECT (meta));
g_free (raw);
g_object_unref (meta);
}
if (exiv2_write_metadata_to_buffer (&buffer,
&size,
file_data->info,
NULL,
&error))
{
g_write_file (file_data->file,
FALSE,
G_FILE_CREATE_NONE,
buffer,
size,
NULL,
&error);
}
if (buffer != NULL)
g_free (buffer);
g_clear_error (&error);
}
......@@ -111,6 +165,7 @@ gth_metadata_provider_constructor (GType type,
self = GTH_METADATA_PROVIDER (obj);
g_object_set (self, "readable-attributes", "Exif::*,Xmp::*,Iptc::*", NULL);
g_object_set (self, "writable-attributes", "Exif::*,Xmp::*,Iptc::*,Embedded::Image::*", NULL);
return obj;
}
......
......@@ -34,7 +34,7 @@
#define GTH_FILE_PROPERTIES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_FILE_PROPERTIES, GthFilePropertiesPrivate))
#define FONT_SCALE (0.85)
#define COMMENT_HEIGHT 150
#define COMMENT_HEIGHT 100
#define CATEGORY_SIZE 1000
......
......@@ -159,6 +159,15 @@ gth_main_register_default_hooks (void)
*/
gth_hook_register ("add-sidecars", 2);
/**
* Called after a file metadata has been read. Used to syncronize
* embedded metadata with the .comment file.
*
* @file_data (GthFileData *): the file
* @attributes (const char *): the attributes read for the file
*/
gth_hook_register ("read-metadata-ready", 2);
/**
* Called when creating the preferences dialog to add other tabs to
* the dialog.
......
......@@ -354,6 +354,12 @@ read_metadata_thread (gpointer data)
g_object_unref (metadata_provider);
}
if (! cancelled)
for (scan = rmtd->files; scan; scan = scan->next) {
GthFileData *file_data = scan->data;
gth_hook_invoke ("read-metadata-ready", file_data, rmtd->attributes);
}
g_mutex_lock (rmtd->mutex);
rmtd->thread_done = TRUE;
g_mutex_unlock (rmtd->mutex);
......
......@@ -20,6 +20,7 @@
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "glib-utils.h"
#include "gth-string-list.h"
......@@ -155,3 +156,24 @@ gth_string_list_join (GthStringList *list,
return g_string_free (str, FALSE);
}
gboolean
gth_string_list_equal (GthStringList *list1,
GthStringList *list2)
{
GList *keys1;
GList *keys2;
GList *scan;
keys1 = list1->priv->list;
keys2 = list2->priv->list;
if (g_list_length (keys1) != g_list_length (keys2))
return FALSE;
for (scan = keys1; scan; scan = scan->next)
if (! g_list_find_custom (keys2, scan->data, (GCompareFunc) strcmp))
return FALSE;
return TRUE;
}
......@@ -55,6 +55,8 @@ GthStringList * gth_string_list_new_from_ptr_array (GPtrArray *array);
GList * gth_string_list_get_list (GthStringList *list);
char * gth_string_list_join (GthStringList *list,
const char *separator);
gboolean gth_string_list_equal (GthStringList *list1,
GthStringList *list2);
G_END_DECLS
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment