1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-05 21:02:42 +02:00

app, libgimp, libgimpbase: Add preference to allow saving and updating extra metadata

Closes #5856 - provide a way to export images without adding or
changing any metadata.
Handles issue #3490 together with !2367. The latter makes sure that
an image comment when present is favored over similar metadata tags.

This commit makes sure that when you disable the preference to
update metadata automatically, it does not synchronize the
image comment with similar metadata tags (possibly overwriting other
metadata), it does not update the modification date, and does not
add or update software and change history metadata.

This adds a metadata preference (enabled by default) that on export
determines whether we add and update some non essential metadata.

When this setting is disabled, we only touch the metadata that we
cannot avoid (e.g. updating size, presence of thumbnail, etc.).
This commit is contained in:
Jacob Boerema
2025-07-18 19:03:25 -04:00
parent 8e11b1bfb4
commit 877d5b0c1a
12 changed files with 200 additions and 116 deletions

View File

@@ -121,6 +121,7 @@ enum
PROP_EXPORT_METADATA_EXIF,
PROP_EXPORT_METADATA_XMP,
PROP_EXPORT_METADATA_IPTC,
PROP_EXPORT_UPDATE_METADATA,
PROP_DEBUG_POLICY,
PROP_CHECK_UPDATES,
PROP_CHECK_UPDATE_TIMESTAMP,
@@ -793,6 +794,13 @@ gimp_core_config_class_init (GimpCoreConfigClass *klass)
TRUE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_EXPORT_UPDATE_METADATA,
"export-update-metadata",
"Update metadata automatically",
EXPORT_UPDATE_METADATA_BLURB,
TRUE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_ENUM (object_class, PROP_DEBUG_POLICY,
"debug-policy",
"Try generating backtrace upon errors",
@@ -1194,6 +1202,9 @@ gimp_core_config_set_property (GObject *object,
case PROP_EXPORT_METADATA_IPTC:
core_config->export_metadata_iptc = g_value_get_boolean (value);
break;
case PROP_EXPORT_UPDATE_METADATA:
core_config->export_update_metadata = g_value_get_boolean (value);
break;
case PROP_DEBUG_POLICY:
core_config->debug_policy = g_value_get_enum (value);
break;
@@ -1462,6 +1473,9 @@ gimp_core_config_get_property (GObject *object,
case PROP_EXPORT_METADATA_IPTC:
g_value_set_boolean (value, core_config->export_metadata_iptc);
break;
case PROP_EXPORT_UPDATE_METADATA:
g_value_set_boolean (value, core_config->export_update_metadata);
break;
case PROP_DEBUG_POLICY:
g_value_set_enum (value, core_config->debug_policy);
break;

View File

@@ -104,6 +104,7 @@ struct _GimpCoreConfig
gboolean export_metadata_exif;
gboolean export_metadata_xmp;
gboolean export_metadata_iptc;
gboolean export_update_metadata;
GimpDebugPolicy debug_policy;
#ifdef G_OS_WIN32
GimpWin32PointerInputAPI win32_pointer_input_api;

View File

@@ -257,6 +257,15 @@ _("Export XMP metadata by default.")
#define EXPORT_METADATA_IPTC_BLURB \
_("Export IPTC metadata by default.")
/* Translators: tooltip for configuration option (checkbox).
* It determines what metadata is updated when exporting.
*/
#define EXPORT_UPDATE_METADATA_BLURB \
_("When enabled, add and update metadata automatically. When disabled, " \
"only the minimum necessary metadata changes are made, without changing " \
"modification date, synchronizing tags, or updating the software and " \
"change history metadata.")
#define GENERATE_BACKTRACE_BLURB \
_("Try generating debug data for bug reporting when appropriate.")

View File

@@ -1589,6 +1589,9 @@ prefs_dialog_new (Gimp *gimp,
*/
_("Export _IPTC metadata by default when available"),
GTK_BOX (vbox2));
button = prefs_check_button_add (object, "export-update-metadata",
_("Update metadata automatically"),
GTK_BOX (vbox2));
hbox = prefs_hint_box_new (GIMP_ICON_DIALOG_WARNING,
_("Metadata can contain sensitive information."));
gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);

View File

@@ -242,6 +242,7 @@ gimp_plug_in_manager_call_run (GimpPlugInManager *manager,
config.export_exif = core_config->export_metadata_exif;
config.export_xmp = core_config->export_metadata_xmp;
config.export_iptc = core_config->export_metadata_iptc;
config.update_metadata = core_config->export_update_metadata;
config.default_display_id = display_id;
config.app_name = (gchar *) g_get_application_name ();
config.wm_class = (gchar *) gimp_get_program_class (manager->gimp);

View File

@@ -129,6 +129,7 @@ static gboolean _export_exif = FALSE;
static gboolean _export_xmp = FALSE;
static gboolean _export_iptc = FALSE;
static gboolean _export_thumbnail = TRUE;
static gboolean _update_metadata = TRUE;
static gint32 _num_processors = 1;
static GimpCheckSize _check_size = GIMP_CHECK_SIZE_MEDIUM_CHECKS;
static GimpCheckType _check_type = GIMP_CHECK_TYPE_GRAY_CHECKS;
@@ -747,6 +748,28 @@ gimp_export_thumbnail (void)
return _export_thumbnail;
}
/**
* gimp_update_metadata:
*
* Returns whether file plug-ins should update the
* image's metadata.
*
* Note that metadata that reflects the image characteristics
* will still be updated even if this is set to FALSE. This only
* concerns metadata changes that are nonessential, like setting
* GIMP in Exif.Image.Software, synchronizing the comment with its
* equivalent metadata tags, etc.
*
* Returns: TRUE if preferences are set to update the metadata.
*
* Since: 3.1
**/
gboolean
gimp_update_metadata (void)
{
return _update_metadata;
}
/**
* gimp_get_num_processors:
*
@@ -1090,6 +1113,7 @@ _gimp_config (GPConfig *config)
_export_exif = config->export_exif ? TRUE : FALSE;
_export_xmp = config->export_xmp ? TRUE : FALSE;
_export_iptc = config->export_iptc ? TRUE : FALSE;
_update_metadata = config->update_metadata ? TRUE : FALSE;
_export_comment = config->export_comment;
_num_processors = config->num_processors;
_default_display_id = config->default_display_id;

View File

@@ -1061,6 +1061,7 @@ EXPORTS
gimp_tile_width
gimp_trc_type_get_type
gimp_unit_new
gimp_update_metadata
gimp_user_time
gimp_vector_load_procedure_extract_dimensions
gimp_vector_load_procedure_get_type

View File

@@ -186,6 +186,7 @@ gboolean gimp_export_exif (void) G_GNUC_CONST;
gboolean gimp_export_xmp (void) G_GNUC_CONST;
gboolean gimp_export_iptc (void) G_GNUC_CONST;
gboolean gimp_export_thumbnail (void) G_GNUC_CONST;
gboolean gimp_update_metadata (void) G_GNUC_CONST;
gint gimp_get_num_processors (void) G_GNUC_CONST;
GimpCheckSize gimp_check_size (void) G_GNUC_CONST;
GimpCheckType gimp_check_type (void) G_GNUC_CONST;

View File

@@ -132,63 +132,69 @@ gimp_image_metadata_save_prepare (GimpImage *image,
gimp_parasite_free (comment_parasite);
}
if (! gimp_update_metadata ())
*suggested_flags &= ~GIMP_METADATA_UPDATE;
/* Exif */
if (! gimp_export_exif () ||
! gexiv2_metadata_has_exif (g2metadata))
*suggested_flags &= ~GIMP_METADATA_SAVE_EXIF;
if (comment)
if (gimp_update_metadata ())
{
if (comment)
{
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Photo.UserComment",
comment, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Photo.UserComment", error->message);
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Image.ImageDescription",
comment, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Image.ImageDescription", error->message);
g_clear_error (&error);
}
}
g_snprintf (buffer, sizeof (buffer),
"%d:%02d:%02d %02d:%02d:%02d",
g_date_time_get_year (datetime),
g_date_time_get_month (datetime),
g_date_time_get_day_of_month (datetime),
g_date_time_get_hour (datetime),
g_date_time_get_minute (datetime),
g_date_time_get_second (datetime));
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Photo.UserComment",
comment, &error);
"Exif.Image.DateTime",
buffer, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Photo.UserComment", error->message);
G_STRFUNC, "Exif.Image.DateTime", error->message);
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Image.ImageDescription",
comment, &error);
"Exif.Image.Software",
PACKAGE_STRING, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Image.ImageDescription", error->message);
G_STRFUNC, "Exif.Image.Software", error->message);
g_clear_error (&error);
}
}
g_snprintf (buffer, sizeof (buffer),
"%d:%02d:%02d %02d:%02d:%02d",
g_date_time_get_year (datetime),
g_date_time_get_month (datetime),
g_date_time_get_day_of_month (datetime),
g_date_time_get_hour (datetime),
g_date_time_get_minute (datetime),
g_date_time_get_second (datetime));
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Image.DateTime",
buffer, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Image.DateTime", error->message);
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Exif.Image.Software",
PACKAGE_STRING, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Exif.Image.Software", error->message);
g_clear_error (&error);
}
gimp_metadata_set_pixel_size (metadata,
image_width, image_height);
@@ -212,26 +218,29 @@ gimp_image_metadata_save_prepare (GimpImage *image,
g_clear_error (&error);
}
/* XMP uses datetime in ISO 8601 format */
datetime_buf = g_date_time_format (datetime, "%Y:%m:%dT%T\%:z");
if (gimp_update_metadata ())
{
/* XMP uses datetime in ISO 8601 format */
datetime_buf = g_date_time_format (datetime, "%Y:%m:%dT%T\%:z");
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.xmp.ModifyDate",
datetime_buf, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.ModifyDate", error->message);
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.xmp.MetadataDate",
datetime_buf, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.MetadataDate", error->message);
g_clear_error (&error);
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.xmp.ModifyDate",
datetime_buf, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.ModifyDate", error->message);
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.xmp.MetadataDate",
datetime_buf, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.MetadataDate", error->message);
g_clear_error (&error);
}
}
if (! g_strcmp0 (mime_type, "image/tiff"))
@@ -260,14 +269,17 @@ gimp_image_metadata_save_prepare (GimpImage *image,
g_clear_error (&error);
}
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.tiff.DateTime",
datetime_buf, &error);
if (error)
if (gimp_update_metadata ())
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.tiff.DateTime", error->message);
g_clear_error (&error);
gexiv2_metadata_try_set_tag_string (g2metadata,
"Xmp.tiff.DateTime",
datetime_buf, &error);
if (error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.tiff.DateTime", error->message);
g_clear_error (&error);
}
}
}
@@ -320,6 +332,9 @@ gimp_image_metadata_save_prepare (GimpImage *image,
if (! gimp_export_thumbnail ())
*suggested_flags &= ~GIMP_METADATA_SAVE_THUMBNAIL;
if (! gimp_update_metadata ())
*suggested_flags &= ~GIMP_METADATA_UPDATE;
}
/* Color profile */
@@ -748,72 +763,75 @@ gimp_image_metadata_save_filter (GimpImage *image,
GList *exclude_list = NULL;
GList *list;
gettimeofday (&timer_usec, NULL);
timestamp_usec = ((gint64) timer_usec.tv_sec) * 1000000ll +
(gint64) timer_usec.tv_usec;
g_snprintf (ts, sizeof (ts), "%" G_GINT64_FORMAT, timestamp_usec);
gimp_metadata_add_xmp_history (metadata, "");
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.TimeStamp",
ts, &code_error);
if (code_error)
if (gimp_update_metadata ())
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.TimeStamp", code_error->message);
g_clear_error (&code_error);
}
gettimeofday (&timer_usec, NULL);
timestamp_usec = ((gint64) timer_usec.tv_sec) * 1000000ll +
(gint64) timer_usec.tv_usec;
g_snprintf (ts, sizeof (ts), "%" G_GINT64_FORMAT, timestamp_usec);
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.xmp.CreatorTool",
N_("GIMP"), &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.CreatorTool", code_error->message);
g_clear_error (&code_error);
}
gimp_metadata_add_xmp_history (metadata, "");
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Version",
GIMP_VERSION, &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.Version", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.TimeStamp",
ts, &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.TimeStamp", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.API",
GIMP_API_VERSION, &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.API", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.xmp.CreatorTool",
N_("GIMP"), &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.xmp.CreatorTool", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Platform",
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Version",
GIMP_VERSION, &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.Version", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.API",
GIMP_API_VERSION, &code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.API", code_error->message);
g_clear_error (&code_error);
}
gexiv2_metadata_try_set_tag_string (GEXIV2_METADATA (metadata),
"Xmp.GIMP.Platform",
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
"Windows",
"Windows",
#elif defined(__linux__)
"Linux",
"Linux",
#elif defined(__APPLE__) && defined(__MACH__)
"Mac OS",
"Mac OS",
#elif defined(unix) || defined(__unix__) || defined(__unix)
"Unix",
"Unix",
#else
"Unknown",
"Unknown",
#endif
&code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.Platform", code_error->message);
g_clear_error (&code_error);
&code_error);
if (code_error)
{
g_warning ("%s: failed to set metadata '%s': %s\n",
G_STRFUNC, "Xmp.GIMP.Platform", code_error->message);
g_clear_error (&code_error);
}
}
xmp_data = gexiv2_metadata_get_xmp_tags (GEXIV2_METADATA (metadata));

View File

@@ -65,6 +65,8 @@ typedef enum
* Since: 2.10.10
* @GIMP_METADATA_SAVE_COMMENT: Save the image's comment
* Since: 3.0
* @GIMP_METADATA_UPDATE: Update metadata automatically
* Since: 3.1
* @GIMP_METADATA_SAVE_ALL: Save all of the above
*
* What kinds of metadata to save when exporting images.
@@ -77,6 +79,7 @@ typedef enum
GIMP_METADATA_SAVE_THUMBNAIL = 1 << 3,
GIMP_METADATA_SAVE_COLOR_PROFILE = 1 << 4,
GIMP_METADATA_SAVE_COMMENT = 1 << 5,
GIMP_METADATA_UPDATE = 1 << 6,
GIMP_METADATA_SAVE_ALL = 0xffffffff
} GimpMetadataSaveFlags;

View File

@@ -540,6 +540,10 @@ _gp_config_read (GIOChannel *channel,
(guint8 *) &config->export_iptc, 1,
user_data))
goto cleanup;
if (! _gimp_wire_read_int8 (channel,
(guint8 *) &config->update_metadata, 1,
user_data))
goto cleanup;
if (! _gimp_wire_read_int32 (channel,
(guint32 *) &config->default_display_id, 1,
user_data))
@@ -667,6 +671,10 @@ _gp_config_write (GIOChannel *channel,
(const guint8 *) &config->export_iptc, 1,
user_data))
return;
if (! _gimp_wire_write_int8 (channel,
(const guint8 *) &config->update_metadata, 1,
user_data))
return;
if (! _gimp_wire_write_int32 (channel,
(const guint32 *) &config->default_display_id, 1,
user_data))

View File

@@ -130,6 +130,7 @@ struct _GPConfig
gint8 export_exif;
gint8 export_xmp;
gint8 export_iptc;
gint8 update_metadata;
gint32 default_display_id;
gchar *app_name;
gchar *wm_class;