Commit dc9856cf authored by Ben Touchette's avatar Ben Touchette Committed by Michael Natterer

Bug 769820 - Cannot enter Iptc information when no metadata is available...

...and fails to write it to file when it is

Completely redo metadata editor and viewer code, adds support for
Xmp.xmpMM.History and more.
parent 98f7fc85
......@@ -2548,6 +2548,7 @@ plug-ins/imagemap/images/Makefile
plug-ins/lighting/Makefile
plug-ins/lighting/images/Makefile
plug-ins/map-object/Makefile
plug-ins/metadata/Makefile
plug-ins/pagecurl/Makefile
plug-ins/print/Makefile
plug-ins/pygimp/Makefile
......
......@@ -21,6 +21,7 @@
#include "config.h"
#include <string.h>
#include <sys/time.h>
#include <gtk/gtk.h>
#include <gexiv2/gexiv2.h>
......@@ -31,6 +32,12 @@
#include "libgimp-intl.h"
typedef struct
{
gchar *tag;
gint type;
} xmpstructs;
static void gimp_image_metadata_rotate (gint32 image_ID,
GExiv2Orientation orientation);
......@@ -78,28 +85,6 @@ gimp_image_metadata_load_prepare (gint32 image_ID,
if (metadata)
{
#if 0
{
gchar *xml = gimp_metadata_serialize (metadata);
GimpMetadata *new = gimp_metadata_deserialize (xml);
gchar *xml2 = gimp_metadata_serialize (new);
FILE *f = fopen ("/tmp/gimp-test-xml1", "w");
fprintf (f, "%s", xml);
fclose (f);
f = fopen ("/tmp/gimp-test-xml2", "w");
fprintf (f, "%s", xml2);
fclose (f);
system ("diff -u /tmp/gimp-test-xml1 /tmp/gimp-test-xml2");
g_free (xml);
g_free (xml2);
g_object_unref (new);
}
#endif
gexiv2_metadata_erase_exif_thumbnail (GEXIV2_METADATA (metadata));
}
......@@ -377,6 +362,7 @@ gimp_image_metadata_save_prepare (gint32 image_ID,
return metadata;
}
/**
* gimp_image_metadata_save_finish:
* @image_ID: The image
......@@ -456,7 +442,72 @@ gimp_image_metadata_save_finish (gint32 image_ID,
if ((flags & GIMP_METADATA_SAVE_XMP) && support_xmp)
{
gchar **xmp_data = gexiv2_metadata_get_xmp_tags (GEXIV2_METADATA (metadata));
gchar **xmp_data;
struct timeval timer_usec;
long long int timestamp_usec;
gchar ts[1024];
gimp_metadata_register_xmp_namespaces ();
gettimeofday(&timer_usec, NULL);
timestamp_usec = ((long long int) timer_usec.tv_sec) * 1000000ll +
(long long int) timer_usec.tv_usec;
sprintf((gchar*)&ts, "%lld", timestamp_usec);
gimp_metadata_add_xmp_history (GEXIV2_METADATA (metadata),
"");
gexiv2_metadata_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.TimeStamp",
ts);
gexiv2_metadata_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.xmp.CreatorTool",
N_("GIMP 2.9/2.10"));
gexiv2_metadata_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Version",
GIMP_VERSION);
gexiv2_metadata_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.API",
GIMP_API_VERSION);
gexiv2_metadata_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Platform",
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
"Windows");
#elif defined(__linux__)
"Linux");
#elif defined(__APPLE__) && defined(__MACH__)
"Mac OS");
#elif defined(unix) || defined(__unix__) || defined(__unix)
"Unix");
#else
"Unknown");
#endif
xmp_data = gexiv2_metadata_get_xmp_tags (GEXIV2_METADATA (metadata));
/* Patch necessary structures */
xmpstructs structlist[] =
{
{ "Xmp.iptcExt.LocationCreated", GEXIV2_STRUCTURE_XA_BAG },
{ "Xmp.iptcExt.LocationShown", GEXIV2_STRUCTURE_XA_BAG },
{ "Xmp.iptcExt.ArtworkOrObject", GEXIV2_STRUCTURE_XA_BAG },
{ "Xmp.iptcExt.RegistryId", GEXIV2_STRUCTURE_XA_BAG },
{ "Xmp.xmpMM.History", GEXIV2_STRUCTURE_XA_SEQ },
{ "Xmp.plus.ImageSupplier", GEXIV2_STRUCTURE_XA_SEQ },
{ "Xmp.plus.ImageCreator", GEXIV2_STRUCTURE_XA_SEQ },
{ "Xmp.plus.CopyrightOwner", GEXIV2_STRUCTURE_XA_SEQ },
{ "Xmp.plus.Licensor", GEXIV2_STRUCTURE_XA_SEQ }
};
for (i = 0; i < 9; i++)
{
gexiv2_metadata_set_xmp_tag_struct(GEXIV2_METADATA (new_g2metadata),
structlist[i].tag,
structlist[i].type);
}
for (i = 0; xmp_data[i] != NULL; i++)
{
......
This diff is collapsed.
......@@ -66,6 +66,10 @@ GimpMetadata * gimp_metadata_duplicate (GimpMetadata *metada
GimpMetadata * gimp_metadata_deserialize (const gchar *metadata_xml);
gchar * gimp_metadata_serialize (GimpMetadata *metadata);
gchar * gimp_metadata_get_guid (void);
void gimp_metadata_add_xmp_history (GimpMetadata *metadata,
gchar *state_status);
GimpMetadata * gimp_metadata_load_from_file (GFile *file,
GError **error);
......@@ -77,6 +81,10 @@ gboolean gimp_metadata_set_from_exif (GimpMetadata *metada
const guchar *exif_data,
gint exif_data_length,
GError **error);
gboolean gimp_metadata_set_from_iptc (GimpMetadata *metadata,
const guchar *iptc_data,
gint iptc_data_length,
GError **error);
gboolean gimp_metadata_set_from_xmp (GimpMetadata *metadata,
const guchar *xmp_data,
gint xmp_data_length,
......@@ -105,6 +113,11 @@ void gimp_metadata_set_colorspace (GimpMetadata *metada
gboolean gimp_metadata_is_tag_supported (const gchar *tag,
const gchar *mime_type);
void gimp_metadata_register_xmp_namespace (const gchar* nspace,
const gchar* prefix);
void gimp_metadata_register_xmp_namespaces (void);
G_END_DECLS
#endif /* __GIMP_METADATA_H__ */
......@@ -56,6 +56,7 @@ SUBDIRS = \
imagemap \
lighting \
map-object \
metadata \
pagecurl \
$(print) \
screenshot \
......
......@@ -142,8 +142,6 @@
/mail.exe
/max-rgb
/max-rgb.exe
/metadata
/metadata.exe
/newsprint
/newsprint.exe
/nl-filter
......
......@@ -119,7 +119,6 @@ libexec_PROGRAMS = \
jigsaw \
$(MAIL) \
max-rgb \
metadata \
newsprint \
nl-filter \
oilify \
......@@ -1406,26 +1405,6 @@ max_rgb_LDADD = \
$(INTLLIBS) \
$(max_rgb_RC)
metadata_CFLAGS = $(GEXIV2_CFLAGS)
metadata_SOURCES = \
metadata.c
metadata_LDADD = \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimpmodule) \
$(libgimp) \
$(libgimpmath) \
$(libgimpconfig) \
$(libgimpcolor) \
$(libgimpbase) \
$(GTK_LIBS) \
$(GEXIV2_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(metadata_RC)
newsprint_SOURCES = \
newsprint.c
......
......@@ -68,7 +68,6 @@ hot_RC = hot.rc.o
jigsaw_RC = jigsaw.rc.o
mail_RC = mail.rc.o
max_rgb_RC = max-rgb.rc.o
metadata_RC = metadata.rc.o
newsprint_RC = newsprint.rc.o
nl_filter_RC = nl-filter.rc.o
oilify_RC = oilify.rc.o
......
......@@ -69,7 +69,6 @@
'jigsaw' => { ui => 1 },
'mail' => { ui => 1, optional => 1 },
'max-rgb' => { ui => 1 },
'metadata' => { ui => 1, libs => 'GEXIV2_LIBS', cflags => 'GEXIV2_CFLAGS' },
'newsprint' => { ui => 1 },
'nl-filter' => { ui => 1 },
'oilify' => { ui => 1 },
......
/Makefile.in
/Makefile
/.deps
/_libs
/.libs
/metadata-editor
/metadata-editor.exe
/metadata-viewer
/metadata-viewer.exe
## Process this file with automake to produce Makefile.in
if OS_WIN32
mwindows = -mwindows
else
libm = -lm
endif
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
if HAVE_WINDRES
include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
metadata_editor_RC = metadata-editor.rc.o
metadata_viewer_RC = metadata-viewer.rc.o
endif
AM_LDFLAGS = $(mwindows)
libexecdir = $(gimpplugindir)/plug-ins
libexec_PROGRAMS = \
metadata-editor \
metadata-viewer
metadata_editor_SOURCES = \
metadata-impexp.c \
metadata-xml.c \
metadata-editor.c
metadata_viewer_SOURCES = \
metadata-viewer.c
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(GTK_CFLAGS) \
$(GEGL_CFLAGS) \
-I$(includedir)
metadata_viewer_LDADD = \
$(libm) \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimpconfig) \
$(libgimp) \
$(libgimpcolor) \
$(libgimpmath) \
$(libgimpbase) \
$(GTK_LIBS) \
$(GEXIV2_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(metadata_viewer_RC)
metadata_editor_LDADD = \
$(libm) \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimpconfig) \
$(libgimp) \
$(libgimpcolor) \
$(libgimpmath) \
$(libgimpbase) \
$(GTK_LIBS) \
$(GEXIV2_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(metadata_editor_RC)
This diff is collapsed.
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2016, 2017 Ben Touchette
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __METADATA_EDITOR_H__
#define __METADATA_EDITOR_H__
extern void metadata_editor_write_callback (GtkWidget *dialog,
GtkBuilder *builder,
gint32 image_id);
#endif /* __METADATA_EDITOR_H__ */
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* metadata-editor.c
* Copyright (C) 2016, 2017 Ben Touchette
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <ctype.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include <gexiv2/gexiv2.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
#include "metadata-xml.h"
#include "metadata-misc.h"
#include "metadata-tags.h"
#include "metadata-impexp.h"
#include "metadata-editor.h"
extern gboolean gimpmetadata;
extern gboolean xmptag;
extern gboolean iptctag;
extern gboolean tagvalue;
extern gboolean tagname;
extern gboolean force_write;
extern gchar *str_tag_value;
extern gchar *str_tag_name;
const GMarkupParser xml_markup_parser =
{
xml_parser_start_element,
xml_parser_end_element,
xml_parser_data,
NULL, /* passthrough */
NULL /* error */
};
/* ============================================================================
* ==[ METADATA IMPORT TEMPLATE ]==============================================
* ============================================================================
*/
void
import_file_metadata(metadata_editor *args)
{
GimpXmlParser *xml_parser;
GError *error = NULL;
FILE *file;
gchar *xmldata;
gimpmetadata = FALSE;
xmptag = FALSE;
iptctag = FALSE;
tagvalue = FALSE;
tagname = FALSE;
file = g_fopen (args->filename, "r");
if (file != NULL)
{
/* get xml data from file */
g_file_get_contents (args->filename, &xmldata, NULL, &error);
/* parse xml data fetched from file */
xml_parser = xml_parser_new (&xml_markup_parser, args);
xml_parser_parse_file (xml_parser, args->filename, &error);
xml_parser_free (xml_parser);
fclose (file);
}
}
/* ============================================================================
* ==[ METADATA EXPORT TEMPLATE ]==============================================
* ============================================================================
*/
void
export_file_metadata(metadata_editor *args)
{
GError *error = NULL;
FILE *file;
gchar *value;
gchar *value_utf;
gchar *xmldata;
gint i, size;
if (force_write == TRUE)
{
/* Save fields in case of updates */
metadata_editor_write_callback (args->dialog, args->builder, args->image_id);
/* Fetch a fresh copy of the metadata */
args->metadata = GEXIV2_METADATA (gimp_image_get_metadata (args->image_id));
}
xmldata = g_strconcat ("<?xml version=“1.0” encoding=“utf-8”?>\n",
"<gimp-metadata>\n", NULL);
/* HANDLE IPTC */
for (i = 0; i < G_N_ELEMENTS (equivalent_metadata_tags); i++)
{
int index = equivalent_metadata_tags[i].other_tag_index;
xmldata = g_strconcat (xmldata, "\t<iptc-tag>\n", NULL);
xmldata = g_strconcat (xmldata, "\t\t<tag-name>", NULL);
xmldata = g_strconcat (xmldata, equivalent_metadata_tags[i].tag, NULL);
xmldata = g_strconcat (xmldata, "</tag-name>\n", NULL);
xmldata = g_strconcat (xmldata, "\t\t<tag-mode>", NULL);
xmldata = g_strconcat (xmldata, equivalent_metadata_tags[i].mode, NULL);
xmldata = g_strconcat (xmldata, "</tag-mode>\n", NULL);
xmldata = g_strconcat (xmldata, "\t\t<tag-value>", NULL);
if (!strcmp("single", default_metadata_tags[index].mode) ||
!strcmp("multi", default_metadata_tags[index].mode))
{
value = get_tag_ui_text (args, default_metadata_tags[index].tag,
default_metadata_tags[index].mode);
if (value)
{
value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
xmldata = g_strconcat (xmldata, value_utf, NULL);
}
}
else if (!strcmp("combo", default_metadata_tags[index].mode))
{
gint data = get_tag_ui_combo (args, default_metadata_tags[index].tag,
default_metadata_tags[index].mode);
value = g_malloc(1024);
g_sprintf(value, "%d", data);
xmldata = g_strconcat (xmldata, value, NULL);
g_free(value);
}
else if (!strcmp("list", default_metadata_tags[i].mode))
{
/* No IPTC lists elements at this point */
}
xmldata = g_strconcat (xmldata, "</tag-value>\n", NULL);
xmldata = g_strconcat (xmldata, "\t</iptc-tag>\n", NULL);
}
/* HANDLE XMP */
for (i = 0; i < G_N_ELEMENTS (default_metadata_tags); i++)
{
xmldata = g_strconcat (xmldata, "\t<xmp-tag>\n", NULL);
xmldata = g_strconcat (xmldata, "\t\t<tag-name>", NULL);
xmldata = g_strconcat (xmldata, default_metadata_tags[i].tag, NULL);
xmldata = g_strconcat (xmldata, "</tag-name>\n", NULL);
xmldata = g_strconcat (xmldata, "\t\t<tag-mode>", NULL);
xmldata = g_strconcat (xmldata, default_metadata_tags[i].mode, NULL);
xmldata = g_strconcat (xmldata, "</tag-mode>\n", NULL);
if (!strcmp("single", default_metadata_tags[i].mode) ||
!strcmp("multi", default_metadata_tags[i].mode))
{
xmldata = g_strconcat (xmldata, "\t\t<tag-value>", NULL);
value = get_tag_ui_text (args, default_metadata_tags[i].tag,
default_metadata_tags[i].mode);
if (value)
{
value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
xmldata = g_strconcat (xmldata, value_utf, NULL);
}
xmldata = g_strconcat (xmldata, "</tag-value>\n", NULL);
}
else if (!strcmp("combo", default_metadata_tags[i].mode))
{
gint data;
xmldata = g_strconcat (xmldata, "\t\t<tag-value>", NULL);
data = get_tag_ui_combo (args, default_metadata_tags[i].tag,
default_metadata_tags[i].mode);
value = g_malloc(1024);
g_sprintf(value, "%d", data);
xmldata = g_strconcat (xmldata, value, NULL);
g_free(value);
xmldata = g_strconcat (xmldata, "</tag-value>\n", NULL);
}
else if (!strcmp("list", default_metadata_tags[i].mode))
{
gchar* data;
xmldata = g_strconcat (xmldata, "\t\t<tag-list-value>\n", NULL);
data = get_tag_ui_list (args, default_metadata_tags[i].tag,
default_metadata_tags[i].mode);
xmldata = g_strconcat (xmldata, data, NULL);
if (data)
g_free(data);
xmldata = g_strconcat (xmldata, "\t\t</tag-list-value>\n", NULL);
}
xmldata = g_strconcat (xmldata, "\t</xmp-tag>\n", NULL);
}
xmldata = g_strconcat(xmldata, "</gimp-metadata>\n", NULL);
size = strlen (xmldata);
file = g_fopen (args->filename, "w");
if (file != NULL)
{
g_file_set_contents (args->filename, xmldata, size, &error);
fclose (file);
}
if (xmldata)
{
g_free (xmldata);
}
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2016, 2017 Ben Touchette
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __METADATA_IMPEXP_H__
#define __METADATA_IMPEXP_H__
void
import_file_metadata (metadata_editor *args);
void
export_file_metadata (metadata_editor *args);
#endif /* __METADATA_IMPEXP_H__ */
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2016, 2017 Ben Touchette
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __METADATA_MISC_H__
#define __METADATA_MISC_H__
typedef struct
{
GtkWidget *dialog;
GtkBuilder *builder;
GExiv2Metadata *metadata;
gint32 image_id;
gchar *filename;
} metadata_editor;
typedef struct
{
gchar *tag;
gchar *mode;
gint32 other_tag_index;
gint32 tag_type;
gint32 xmp_type;
} metadata_tag;
typedef struct
{
gchar *data;
gchar *display;
} combobox_str_tag;
typedef struct
{
gint32 data;
gchar *display;
} combobox_int_tag;
typedef struct
{
gchar *header;
gchar *type;
gint32 size;
} TranslateHeaderTag;
typedef struct
{
gchar *id;
gchar *tag;
gchar *mode;
gint32 other_tag_index;
gint32 tag_type;
} TranslateTag;
#endif /* __METADATA_MISC_H__ */
This diff is collapsed.
This diff is collapsed.
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2016, 2017 Ben Touchette
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __METADATA_XML_H__
#define __METADATA_XML_H__
#include "metadata-misc.h"
struct _GimpXmlParser
{
GMarkupParseContext *context;
};
typedef struct _GimpXmlParser GimpXmlParser;