diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/generators.c | 26 | ||||
| -rw-r--r-- | src/items.c | 39 | ||||
| -rw-r--r-- | src/items.h | 2 | ||||
| -rw-r--r-- | src/jpeg-utils.cpp | 170 | ||||
| -rw-r--r-- | src/jpeg-utils.h | 14 |
5 files changed, 215 insertions, 36 deletions
diff --git a/src/generators.c b/src/generators.c index 9c65d8e..fe62b39 100644 --- a/src/generators.c +++ b/src/generators.c @@ -146,6 +146,22 @@ get_image_paths (TGallerySetup *setup, } +static void +metadata_apply_overrides (ExifData *exif_data, + TGallerySetup *setup, + TAlbum *items, + TIndexItem *item) +{ + g_return_if_fail (exif_data != NULL); + + g_free (exif_data->override_copyright); + exif_data->override_copyright = g_strdup (setup->add_copyright); + exif_data->timezone_shift = item->metadata_tz_shift; + if (exif_data->timezone_shift == 0) + exif_data->timezone_shift = items->metadata_tz_shift; +} + + /* * generate_image: generate needed image sizes */ @@ -167,6 +183,7 @@ generate_image (TGallerySetup *setup, int quality; GList *l; TImageSize *image_size; + ExifData *exif_data; res = ! query_update; @@ -230,8 +247,12 @@ generate_image (TGallerySetup *setup, } } } - if (! is_thumbnail) - modify_exif (img_dst, setup->erase_exif_thumbnail, setup->add_copyright); + if (! is_thumbnail) { + exif_data = exif_data_new_empty (); + metadata_apply_overrides (exif_data, setup, items, item); + modify_exif (img_dst, exif_data, setup->erase_exif_thumbnail); + exif_data_free (exif_data); + } g_free (img_src); g_free (img_dst); @@ -754,6 +775,7 @@ write_html_image (TGallerySetup *setup, if (exif == NULL) log_error ("write_html_image: error getting exif data from file \"%s\"\n", img_dst); } + metadata_apply_overrides (exif, setup, parent_items, item); /* Test for basic EXIF keys presence */ if (exif != NULL && exif_has_key (exif, EXIF_APERTURE) && exif_has_key (exif, EXIF_FOCAL_LENGTH) && diff --git a/src/items.c b/src/items.c index a0c2534..6ac7e56 100644 --- a/src/items.c +++ b/src/items.c @@ -30,6 +30,30 @@ #include "atom-writer.h" + +static int +parse_timezone_string (const gchar *str) +{ + int hour = 0; + int min = 0; + float f; + char *endptr = NULL; + + /* Expecting +-hh:mm format */ + if (sscanf (str, "%d:%d", &hour, &min) != 2) { + /* Try simple float conversion instead */ + f = strtof (str, &endptr); + if (endptr == NULL || *endptr != '\0') { + log_error ("Invalid timezone string \"%s\", ignoring.\n", str); + return 0; + } + return (int)(f * 60); + } + + return hour * 60 + min; +} + + /* * parse_album_xml: XML parser for gallery index.xml files */ @@ -92,6 +116,13 @@ parse_album_xml (const gchar *filename, TPathInfo *path_info) index->meta_description = xml_file_get_node_value (xml, "/gallery/general/meta/description/text()"); index->meta_keywords = xml_file_get_node_value (xml, "/gallery/general/meta/keywords/text()"); + s = xml_file_get_node_attribute (xml, "/gallery/general/metadata/timezone", "shift"); + if (s != NULL) { + index->metadata_tz_shift = parse_timezone_string (s2); + g_free (s2); + } + + index->nofullsize = xml_file_get_node_present (xml, "/gallery/general/nofullsize"); index->fullsize = xml_file_get_node_present (xml, "/gallery/general/fullsize"); @@ -219,6 +250,14 @@ parse_album_xml (const gchar *filename, TPathInfo *path_info) item->metadata_external_exif = xml_file_get_node_attribute (xml, s, "src"); g_free (s); + s = g_strdup_printf ("/gallery/items/*[%d]/metadata/timezone", i + 1); + s2 = xml_file_get_node_attribute (xml, s, "shift"); + g_free (s); + if (s2 != NULL) { + item->metadata_tz_shift = parse_timezone_string (s2); + g_free (s2); + } + if (item->path || item->preview) { g_ptr_array_add (index->items, item); } else { diff --git a/src/items.h b/src/items.h index 15baeae..2b36927 100644 --- a/src/items.h +++ b/src/items.h @@ -64,6 +64,7 @@ typedef struct { gchar *auth_username; gchar *auth_passwd; TAuthType auth_type; + int metadata_tz_shift; /* minutes */ } TAlbum; typedef struct { @@ -81,6 +82,7 @@ typedef struct { TIndexItemType type; gboolean hidden; gchar *metadata_external_exif; + int metadata_tz_shift; /* minutes */ } TIndexItem; typedef struct { diff --git a/src/jpeg-utils.cpp b/src/jpeg-utils.cpp index bee9562..df3c94e 100644 --- a/src/jpeg-utils.cpp +++ b/src/jpeg-utils.cpp @@ -30,11 +30,55 @@ #include "gallery-utils.h" -struct ExifData { +struct ExifDataPrivate { Exiv2::Image::AutoPtr image; }; +static struct tm * +parse_exif_date (const char *str) +{ + struct tm *tm; + char *res; + + tm = (struct tm *) g_malloc0 (sizeof (struct tm)); + + res = strptime (str, "%Y:%m:%d %H:%M:%S", tm); + if (res == NULL || *res != '\0') + return NULL; + + /* FIXME: what was this used for? */ +#if 0 + tm->tm_year -= 1900; + tm->tm_mon--; +#endif + mktime (tm); + + return tm; +} + +static void +shift_time (struct tm *tm, int offset_min) +{ + time_t t; + struct tm *new_t; + + if (offset_min != 0) { + /* FIXME: converting between time formats could make some data lost, better to operate over struct tm directly */ + t = mktime (tm); + if (t == (time_t) -1) { + log_error ("Cannot shift time %p by %d minutes\n", tm, offset_min); + return; + } + + t += offset_min * 60; + + new_t = localtime (&t); + memcpy (tm, new_t, sizeof (struct tm)); + } +} + + /* * EXIF and IPTC info retrieval, keeps the source file open until freed */ @@ -43,12 +87,12 @@ read_exif (const gchar *filename) { ExifData *data; - data = (ExifData*) g_malloc0 (sizeof (ExifData)); + data = exif_data_new_empty (); try { - data->image = Exiv2::ImageFactory::open (filename); - g_assert (data->image.get() != 0); - data->image->readMetadata(); + data->priv->image = Exiv2::ImageFactory::open (filename); + g_assert (data->priv->image.get() != 0); + data->priv->image->readMetadata(); } catch (Exiv2::AnyError& e) { @@ -60,11 +104,24 @@ read_exif (const gchar *filename) return data; } +ExifData * +exif_data_new_empty () +{ + ExifData *data; + + data = (ExifData*) g_malloc0 (sizeof (ExifData)); + data->priv = (ExifDataPrivate*) g_malloc0 (sizeof (ExifDataPrivate)); + + return data; +} + void exif_data_free (ExifData *data) { if (data) { - /* FIXME: free data->image */ + g_free (data->override_copyright); + /* FIXME: free data->priv->image */ + g_free (data->priv); g_free (data); } } @@ -103,18 +160,18 @@ get_exif_data (ExifData *exif, const gchar *key) try { if (g_strcmp0 (key, JPEG_COMMENT) == 0) { - return g_strdup (exif->image->comment().c_str()); + return g_strdup (exif->priv->image->comment().c_str()); } if (g_str_has_prefix (key, "Exif.")) { - Exiv2::ExifData &exifData = exif->image->exifData(); + Exiv2::ExifData &exifData = exif->priv->image->exifData(); if (! exifData.empty()) { return g_strdup (exifData[key].toString().c_str()); } } if (g_str_has_prefix (key, "Iptc.")) { - Exiv2::IptcData &iptcData = exif->image->iptcData(); + Exiv2::IptcData &iptcData = exif->priv->image->iptcData(); if (! iptcData.empty()) { return g_strdup (iptcData[key].toString().c_str()); } @@ -136,7 +193,7 @@ get_exif_data_fixed (ExifData *exif, const gchar *key) try { if (g_str_has_prefix (key, "Exif.")) { - Exiv2::ExifData &exifData = exif->image->exifData(); + Exiv2::ExifData &exifData = exif->priv->image->exifData(); if (exifData.empty()) return NULL; @@ -153,24 +210,29 @@ get_exif_data_fixed (ExifData *exif, const gchar *key) } catch (...) { } if (! val || strlen (val) == 0) try { + val = exifData["Exif.Photo.DateTimeDigitized"].toString().c_str(); + } catch (...) { } + if (! val || strlen (val) == 0) + try { + /* usually a modification date */ val = exifData["Exif.Image.DateTime"].toString().c_str(); } catch (...) { } if (val && strlen (val) > 0) { - struct tm tt; + struct tm *tt; char conv[1024]; memset (&conv, 0, sizeof (conv)); - memset (&tt, 0, sizeof (struct tm)); - - if (sscanf (val, "%d:%d:%d %d:%d:%d", &tt.tm_year, &tt.tm_mon, &tt.tm_mday, &tt.tm_hour, &tt.tm_min, &tt.tm_sec) == 6) - { - tt.tm_year -= 1900; - tt.tm_mon--; - mktime (&tt); - if (strftime (&conv[0], sizeof (conv), "%c", &tt)) - return g_strdup (&conv[0]); + + tt = parse_exif_date (val); + if (tt) { + shift_time (tt, exif->timezone_shift); + if (strftime (&conv[0], sizeof (conv), "%c", tt)) { + g_free (tt); + return g_strdup (&conv[0]); } + g_free (tt); + } } } @@ -214,7 +276,7 @@ get_exif_data_fixed (ExifData *exif, const gchar *key) } if (g_str_has_prefix (key, "Iptc.")) { - Exiv2::IptcData &iptcData = exif->image->iptcData(); + Exiv2::IptcData &iptcData = exif->priv->image->iptcData(); if (iptcData.empty()) return NULL; } @@ -239,16 +301,16 @@ exif_has_key (ExifData *exif, const gchar *key) try { if (g_strcmp0 (key, JPEG_COMMENT) == 0) { - return (! exif->image->comment().empty()); + return (! exif->priv->image->comment().empty()); } if (g_str_has_prefix (key, "Exif.")) { - Exiv2::ExifData &exifData = exif->image->exifData(); + Exiv2::ExifData &exifData = exif->priv->image->exifData(); return !exifData.empty() && exifData[key].count() > 0; } if (g_str_has_prefix (key, "Iptc.")) { - Exiv2::IptcData &iptcData = exif->image->iptcData(); + Exiv2::IptcData &iptcData = exif->priv->image->iptcData(); return !iptcData.empty() && iptcData[key].count() > 0; } @@ -450,17 +512,50 @@ calculate_sizes (const unsigned long max_width, const unsigned long max_height, } } +static gboolean +shift_exif_time (Exiv2::ExifData& exifData, const char *key, int amount) +{ + const char *s; + gboolean res; + + res = FALSE; + try { + if (exifData[key].count() > 0) { + s = exifData[key].toString().c_str(); + + if (s && strlen (s) > 0) { + struct tm *tt; + char conv[1024]; + + memset (&conv, 0, sizeof (conv)); + + tt = parse_exif_date (s); + if (tt) { + shift_time (tt, amount); + if (strftime (&conv[0], sizeof (conv), "%Y:%m:%d %H:%M:%S", tt)) { + exifData[key] = (const char *) &conv[0]; + res = TRUE; + } + g_free (tt); + } + } + } + } catch (...) { } + + return res; +} /* * modify_exif: - strip thumbnail stored in EXIF table - * - add copyright to Exif::Image::Copyright and Iptc::Application2::Copyright + * - write down overriden keys */ void -modify_exif (const gchar *filename, gboolean strip_thumbnail, const gchar *add_copyright) +modify_exif (const gchar *filename, ExifData *exif, gboolean strip_thumbnail) { gboolean modified; + gboolean res; - if (! strip_thumbnail && add_copyright == NULL) + if (! strip_thumbnail && exif == NULL) return; modified = FALSE; @@ -470,10 +565,23 @@ modify_exif (const gchar *filename, gboolean strip_thumbnail, const gchar *add_c image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); - if (add_copyright) { - exifData["Exif.Image.Copyright"] = add_copyright; - image->iptcData()["Iptc.Application2.Copyright"] = add_copyright; - modified = TRUE; + + if (exif) { + if (exif->override_copyright) { + exifData["Exif.Image.Copyright"] = exif->override_copyright; + image->iptcData()["Iptc.Application2.Copyright"] = exif->override_copyright; + modified = TRUE; + } + + if (exif->timezone_shift != 0 && !exifData.empty()) { + /* need original data to calculate the shift from */ + res = shift_exif_time (exifData, "Exif.Photo.DateTimeOriginal", exif->timezone_shift); + res = shift_exif_time (exifData, "Exif.Photo.DateTimeDigitized", exif->timezone_shift) || res; + if (! res) + /* usually a modification date, shift as a last option */ + shift_exif_time (exifData, "Exif.Image.DateTime", exif->timezone_shift); + modified = TRUE; + } } if (strip_thumbnail && ! exifData.empty()) { diff --git a/src/jpeg-utils.h b/src/jpeg-utils.h index 86602a2..89a2cd4 100644 --- a/src/jpeg-utils.h +++ b/src/jpeg-utils.h @@ -45,13 +45,21 @@ G_BEGIN_DECLS #define JPEG_COMMENT "Jpeg.Comment" -typedef struct ExifData ExifData; +typedef struct ExifDataPrivate ExifDataPrivate; + +typedef struct { + ExifDataPrivate *priv; + + gchar *override_copyright; + int timezone_shift; +} ExifData; /* * EXIF and IPTC info retrieval, keeps the source file open until freed */ ExifData * read_exif (const gchar *filename); +ExifData * exif_data_new_empty (); void exif_data_free (ExifData *data); /* @@ -95,9 +103,9 @@ void calculate_sizes (const unsigned long max_width, const unsigned long max_hei /* * modify_exif: - strip thumbnail stored in EXIF table - * - add copyright to Exif::Image::Copyright and Iptc::Application2::Copyright + * - write down overriden keys */ -void modify_exif (const gchar *filename, gboolean strip_thumbnail, const gchar *add_copyright); +void modify_exif (const gchar *filename, ExifData *exif, gboolean strip_thumbnail); G_END_DECLS |
