From 6b10cce682e89fbaf432895f1442af2f06517f58 Mon Sep 17 00:00:00 2001 From: Jacob Boerema Date: Mon, 13 Jan 2025 16:15:27 -0500 Subject: [PATCH] app, libgimpbase: add creation date/time metadata... when creating a new image. We add a new function `gimp_metadata_set_creation_date` to `libgimpbase/gimpmetadata` to handle setting all relevant metadata tags. We add a local function `gimp_image_new_add_creation_metadata` to add the creation date metadata to relevant functions that create new images. We write tags for both the creation date and several modified dates for IPTC, XMP and Exif metadata. All these use different ways to express date/time and timezones and I can already see we need to have another look at other places where we handle modified dates. This solves the second part of #7287, adding metadata about the date/time a new image was created. --- app/core/gimpimage-new.c | 33 ++++++++++++++ libgimpbase/gimpbase.def | 1 + libgimpbase/gimpmetadata.c | 92 ++++++++++++++++++++++++++++++++++++++ libgimpbase/gimpmetadata.h | 2 + 4 files changed, 128 insertions(+) diff --git a/app/core/gimpimage-new.c b/app/core/gimpimage-new.c index 758ee98bf0..e983563b75 100644 --- a/app/core/gimpimage-new.c +++ b/app/core/gimpimage-new.c @@ -43,6 +43,7 @@ #include "gimpimage.h" #include "gimpimage-color-profile.h" #include "gimpimage-colormap.h" +#include "gimpimage-metadata.h" #include "gimpimage-new.h" #include "gimpimage-undo.h" #include "gimplayer.h" @@ -101,6 +102,26 @@ gimp_image_new_set_last_template (Gimp *gimp, G_OBJECT (gimp->image_new_last_template), 0); } +void +gimp_image_new_add_creation_metadata (GimpImage *image) +{ + GimpMetadata *metadata; + + metadata = gimp_image_get_metadata (image); + if (! metadata) + { + g_critical ("Metadata not found. Should not happen!"); + } + else + { + GDateTime *datetime; + + datetime = g_date_time_new_now_local (); + gimp_metadata_set_creation_date (metadata, datetime); + g_date_time_unref (datetime); + } +} + GimpImage * gimp_image_new_from_template (Gimp *gimp, GimpTemplate *template, @@ -182,6 +203,8 @@ gimp_image_new_from_template (Gimp *gimp, gimp_image_add_layer (image, layer, NULL, 0, FALSE); + gimp_image_new_add_creation_metadata (image); + gimp_image_undo_enable (image); gimp_image_clean_all (image); @@ -285,6 +308,8 @@ gimp_image_new_from_drawable (Gimp *gimp, gimp_image_add_layer (new_image, new_layer, NULL, 0, TRUE); + gimp_image_new_add_creation_metadata (new_image); + gimp_image_undo_enable (new_image); return new_image; @@ -535,6 +560,8 @@ gimp_image_new_from_drawables (Gimp *gimp, gimp_image_new_copy_drawables (image, drawables, new_image, tag_copies, NULL, NULL, NULL, NULL); + gimp_image_new_add_creation_metadata (new_image); + gimp_image_undo_enable (new_image); return new_image; @@ -581,6 +608,8 @@ gimp_image_new_from_component (Gimp *gimp, gimp_image_add_layer (new_image, layer, NULL, 0, TRUE); + gimp_image_new_add_creation_metadata (new_image); + gimp_image_undo_enable (new_image); return new_image; @@ -630,6 +659,8 @@ gimp_image_new_from_buffer (Gimp *gimp, gimp_image_add_layer (image, layer, NULL, 0, TRUE); + gimp_image_new_add_creation_metadata (image); + gimp_image_undo_enable (image); return image; @@ -691,6 +722,8 @@ gimp_image_new_from_pixbuf (Gimp *gimp, gimp_image_add_layer (new_image, layer, NULL, 0, TRUE); + gimp_image_new_add_creation_metadata (new_image); + gimp_image_undo_enable (new_image); return new_image; diff --git a/libgimpbase/gimpbase.def b/libgimpbase/gimpbase.def index 71e7668098..6ffe519ddd 100644 --- a/libgimpbase/gimpbase.def +++ b/libgimpbase/gimpbase.def @@ -116,6 +116,7 @@ EXPORTS gimp_metadata_serialize gimp_metadata_set_bits_per_sample gimp_metadata_set_colorspace + gimp_metadata_set_creation_date gimp_metadata_set_from_exif gimp_metadata_set_from_iptc gimp_metadata_set_from_xmp diff --git a/libgimpbase/gimpmetadata.c b/libgimpbase/gimpmetadata.c index 9476d91716..b0948b29c2 100644 --- a/libgimpbase/gimpmetadata.c +++ b/libgimpbase/gimpmetadata.c @@ -1681,6 +1681,98 @@ gimp_metadata_set_resolution (GimpMetadata *metadata, "Exif.Image.ResolutionUnit", buffer, NULL); } +/** + * gimp_metadata_set_creation_date: + * @metadata: A #GimpMetadata instance. + * @datetime: A #GDateTime value + * + * Sets `Iptc.Application2.DateCreated`, `Iptc.Application2.TimeCreated`, + * `Exif.Image.DateTime`, `Exif.Image.DateTimeOriginal`, + * `Exif.Photo.DateTimeOriginal`, `Exif.Photo.DateTimeDigitized`, + * `Exif.Photo.OffsetTime`, `Exif.Photo.OffsetTimeOriginal`, + * `Exif.Photo.OffsetTimeDigitized`, `Xmp.xmp.CreateDate`, `Xmp.xmp.ModifyDate`, + * `Xmp.xmp.MetadataDate`, `Xmp.photoshop.DateCreated` of @metadata. + * + * Since: 3.0 + */ +void +gimp_metadata_set_creation_date (GimpMetadata *metadata, + GDateTime *datetime) +{ + gchar *datetime_buf = NULL; + GExiv2Metadata *g2metadata = GEXIV2_METADATA (metadata); + + g_return_if_fail (GIMP_IS_METADATA (metadata)); + + /* IPTC: set creation date and time; there is no tag for modified date/time. */ + + datetime_buf = g_date_time_format (datetime, "%Y-%m-%d"); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Iptc.Application2.DateCreated", + datetime_buf, NULL); + g_free (datetime_buf); + + /* time and timezone */ + datetime_buf = g_date_time_format (datetime, "%T\%:z"); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Iptc.Application2.TimeCreated", + datetime_buf, NULL); + g_free (datetime_buf); + + /* Exif: Exif.Image.DateTime = Modified datetime + * Exif.Image.DateTimeOriginal and Exif.Photo.DateTimeOriginal = When the + * original image data was generated. + * Exif.Photo.DateTimeDigitized = when the image was stored as digital data. + */ + datetime_buf = g_date_time_format (datetime, "%Y:%m:%d %T"); + + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Image.DateTime", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Image.DateTimeOriginal", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Photo.DateTimeOriginal", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Photo.DateTimeDigitized", + datetime_buf, NULL); + g_free (datetime_buf); + + /* Timezone is separate */ + datetime_buf = g_date_time_format (datetime, "\%:z"); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Photo.OffsetTime", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Photo.OffsetTimeOriginal", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Exif.Photo.OffsetTimeDigitized", + datetime_buf, NULL); + g_free (datetime_buf); + + /* XMP: Xmp.photoshop.DateCreated = date when the original image was + * taken, this can be before Xmp.xmp.CreateDate. */ + datetime_buf = g_date_time_format (datetime, "%Y:%m:%dT%T\%:z"); + + gexiv2_metadata_try_set_tag_string (g2metadata, + "Xmp.xmp.CreateDate", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Xmp.xmp.ModifyDate", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Xmp.xmp.MetadataDate", + datetime_buf, NULL); + gexiv2_metadata_try_set_tag_string (g2metadata, + "Xmp.photoshop.DateCreated", + datetime_buf, NULL); + + g_free (datetime_buf); +} + /** * gimp_metadata_get_colorspace: * @metadata: A #GimpMetadata instance. diff --git a/libgimpbase/gimpmetadata.h b/libgimpbase/gimpmetadata.h index 60fb4c9dac..8f7b028612 100644 --- a/libgimpbase/gimpmetadata.h +++ b/libgimpbase/gimpmetadata.h @@ -142,6 +142,8 @@ void gimp_metadata_set_resolution (GimpMetadata *metada gdouble xres, gdouble yres, GimpUnit *unit); +void gimp_metadata_set_creation_date (GimpMetadata *metadata, + GDateTime *datetime); GimpMetadataColorspace gimp_metadata_get_colorspace (GimpMetadata *metadata);