summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/jpeg-utils.c (renamed from src/jpeg-utils.cpp)759
-rw-r--r--src/jpeg-utils.h15
3 files changed, 334 insertions, 446 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ec7b3b1..fbf8672 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,7 +9,7 @@ AM_CPPFLAGS = \
$(DISABLE_DEPRECATED_CFLAGS) \
$(LIBXML2_CFLAGS) \
$(MAGICKWAND_CFLAGS) \
- $(EXIV2_CFLAGS) \
+ $(GEXIV2_CFLAGS) \
-DG_LOG_DOMAIN=\"cgg\"
bin_PROGRAMS = \
@@ -34,7 +34,7 @@ cgg_SOURCES = \
items.h \
job-manager.h \
job-manager.c \
- jpeg-utils.cpp \
+ jpeg-utils.c \
jpeg-utils.h \
properties-table.c \
properties-table.h \
@@ -52,7 +52,7 @@ cgg_LDADD = \
$(GLIB_LIBS) \
$(LIBXML2_LIBS) \
$(MAGICKWAND_LIBS) \
- $(EXIV2_LIBS) \
+ $(GEXIV2_LIBS) \
-lm
EXTRA_DIST = cgg-dirgen
diff --git a/src/jpeg-utils.cpp b/src/jpeg-utils.c
index 2e214e4..64cfdff 100644
--- a/src/jpeg-utils.cpp
+++ b/src/jpeg-utils.c
@@ -15,14 +15,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#define _XOPEN_SOURCE
+
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
+#include <gexiv2/gexiv2.h>
#ifdef HAVE_IMAGEMAGICK_7
# include <MagickWand/MagickWand.h>
@@ -30,14 +32,12 @@
# include <wand/MagickWand.h>
#endif
-#include <config.h>
-
#include "jpeg-utils.h"
#include "gallery-utils.h"
struct ExifDataPrivate {
- Exiv2::Image::AutoPtr image;
+ GExiv2Metadata *metadata;
};
@@ -48,15 +48,12 @@ void
init_jpeg_utils (void)
{
MagickWandGenesis();
- /* http://dev.exiv2.org/projects/exiv2/wiki/Thread_safety */
- /* https://bugs.kde.org/show_bug.cgi?id=166424 */
- Exiv2::XmpParser::initialize();
+ g_assert (gexiv2_initialize () == TRUE);
}
void
destroy_jpeg_utils (void)
{
- Exiv2::XmpParser::terminate();
MagickWandTerminus();
}
@@ -100,13 +97,35 @@ parse_exif_date (const char *str)
return tm;
}
+static struct tm *
+parse_exif_date_with_overrides (const char *str, ExifData *exif)
+{
+ struct tm *tt;
+
+ if (exif->override_datetime != (time_t) -1) {
+ tt = (struct tm *) g_malloc0 (sizeof (struct tm));
+ localtime_r (&exif->override_datetime, tt);
+ return tt;
+ }
+
+ tt = parse_exif_date (str);
+ if (tt) {
+ shift_time (tt, exif->timezone_shift);
+ return tt;
+ }
+
+ return NULL;
+}
+
static gchar *
-format_exif_time (struct tm *tm)
+format_exif_time (struct tm *tm, const gchar *format_string)
{
char conv[1024];
memset (&conv, 0, sizeof(conv));
- if (strftime (&conv[0], sizeof(conv), "%Y:%m:%d %H:%M:%S", tm))
+ if (strftime (&conv[0], sizeof(conv),
+ format_string ? format_string : "%Y:%m:%d %H:%M:%S",
+ tm))
return g_strdup (&conv[0]);
return NULL;
@@ -119,18 +138,15 @@ ExifData *
read_exif (const gchar *filename)
{
ExifData *data;
+ GError *error = NULL;
- g_assert (filename != NULL);
- data = exif_data_new_empty ();
+ g_return_val_if_fail (filename != NULL, NULL);
- try {
- data->priv->image = Exiv2::ImageFactory::open (filename);
- g_assert (data->priv->image.get() != 0);
- data->priv->image->readMetadata();
- }
- catch (Exiv2::AnyError& e)
- {
- log_error ("read_exif: Caught Exiv2 exception: '%s'\n", e.what());
+ data = exif_data_new_empty ();
+ data->priv->metadata = gexiv2_metadata_new ();
+ if (! gexiv2_metadata_open_path (data->priv->metadata, filename, &error)) {
+ log_error ("read_exif: %s\n", error->message);
+ g_error_free (error);
exif_data_free (data);
return NULL;
}
@@ -156,7 +172,7 @@ exif_data_free (ExifData *data)
g_free (data->override_copyright);
g_free (data->external_exif_data);
g_free (data->override_artist_name);
- /* FIXME: free data->priv->image */
+ g_clear_object (&data->priv->metadata);
g_free (data->priv);
g_free (data);
}
@@ -182,28 +198,9 @@ get_real_key_name (const gchar *key)
return key;
}
-
-/* Returns newly allocated string */
-/* FIXME: for some reason exiv2 returns const strings with unknown lifetime, can't really trust the library */
-#define exiv2_str_val(data,key) g_strdup(data[key].toString().c_str())
-
-static gboolean
-iptc_has_key (Exiv2::IptcData iptcData, const char *key)
-{
- Exiv2::IptcData::const_iterator md;
-
- if (! iptcData.empty()) {
- md = iptcData.findKey(Exiv2::IptcKey(std::string(key)));
- if (md != iptcData.end() && iptcData[key].count() > 0)
- return TRUE;
- }
- return FALSE;
-}
-
-
/*
* Retrieves value of the specified key or NULL if the key does not exist.
- * The key argument belongs to Exiv2 namespace - see http://exiv2.org/tags.html
+ * The key argument belongs to Exiv2 namespace - see https://exiv2.org/metadata.html
*/
gchar *
get_exif_data (ExifData *exif, const gchar *key)
@@ -213,30 +210,41 @@ get_exif_data (ExifData *exif, const gchar *key)
key = get_real_key_name (key);
- try {
- if (g_strcmp0 (key, JPEG_COMMENT) == 0) {
- return g_strdup (exif->priv->image->comment().c_str());
- }
+ if (g_str_equal (key, JPEG_COMMENT))
+ return exif->override_copyright ? g_strdup (exif->override_copyright) : gexiv2_metadata_get_comment (exif->priv->metadata);
- if (g_str_has_prefix (key, "Exif.")) {
- Exiv2::ExifData &exifData = exif->priv->image->exifData();
- if (! exifData.empty()) {
- return exiv2_str_val (exifData, key);
- }
- }
+ if (g_str_equal (key, EXIF_ARTIST) && exif->override_artist_name)
+ return g_strdup (exif->override_artist_name);
- if (g_str_has_prefix (key, "Iptc.")) {
- Exiv2::IptcData &iptcData = exif->priv->image->iptcData();
- if (iptc_has_key (iptcData, key)) {
- return exiv2_str_val (iptcData, key);
- }
- }
+ if (g_str_equal (key, EXIF_APERTURE) && exif->override_aperture != -1)
+ return g_strdup_printf ("%f", exif->override_aperture);
- return NULL;
- }
- catch (...) {
- return NULL;
+ if (g_str_equal (key, EXIF_FOCAL_LENGTH) && exif->override_focal_length != -1)
+ return g_strdup_printf ("%d/%d", (gint) (exif->override_focal_length * 1000000.0), 1000000);
+
+ if ((exif->override_datetime != (time_t) -1 || exif->timezone_shift) &&
+ (g_str_equal (key, EXIF_DATETIME) ||
+ g_str_equal (key, "Exif.Photo.DateTimeOriginal") ||
+ g_str_equal (key, "Exif.Photo.DateTimeDigitized") ||
+ g_str_equal (key, "Exif.Image.DateTime")))
+ {
+ gchar *val;
+ struct tm *tt;
+
+ val = gexiv2_metadata_get_tag_string (exif->priv->metadata, key);
+ if (! val)
+ return NULL;
+
+ tt = parse_exif_date_with_overrides (val, exif);
+ g_free (val);
+ if (tt) {
+ gchar *res = format_exif_time (tt, NULL);
+ g_free (tt);
+ return res;
+ }
}
+
+ return gexiv2_metadata_get_tag_string (exif->priv->metadata, key);
}
gchar *
@@ -245,126 +253,79 @@ get_exif_data_fixed (ExifData *exif, const gchar *key)
g_return_val_if_fail (exif != NULL, NULL);
g_return_val_if_fail (key != NULL, NULL);
- try
- {
- if (g_str_has_prefix (key, "Exif.")) {
- Exiv2::ExifData &exifData = exif->priv->image->exifData();
- if (exifData.empty())
- return NULL;
-
- if (g_str_equal (key, EXIF_APERTURE)) {
- double val = -1;
- if (exif->override_aperture != -1)
- val = exif->override_aperture;
- else {
- if (exifData["Exif.Photo.FNumber"].count() > 0)
- val = exifData["Exif.Photo.FNumber"].toFloat();
- else
- if (exifData["Exif.Photo.ApertureValue"].count() > 0)
- val = exifData["Exif.Photo.ApertureValue"].toFloat();
- }
- if (val >= 0)
- return g_strdup_printf ("&#402;/%.1f", val);
- }
-
- if (g_str_equal (key, EXIF_DATETIME) ||
- g_str_equal (key, "Exif.Photo.DateTimeOriginal") ||
- g_str_equal (key, "Exif.Photo.DateTimeDigitized") ||
- g_str_equal (key, "Exif.Image.DateTime")) {
- gchar *val = NULL;
- try {
- val = exiv2_str_val (exifData, "Exif.Photo.DateTimeOriginal");
- } catch (...) { }
- if (! val || strlen (val) == 0)
- try {
- val = exiv2_str_val (exifData, "Exif.Photo.DateTimeDigitized");
- } catch (...) { }
- if (! val || strlen (val) == 0)
- try {
- /* usually a modification date */
- val = exiv2_str_val (exifData, "Exif.Image.DateTime");
- } catch (...) { }
-
- if (val && strlen (val) > 0) {
- struct tm *tt = NULL;
- char conv[1024];
- gchar *res = NULL;
-
- memset (&conv, 0, sizeof (conv));
-
- if (exif->override_datetime != (time_t) -1) {
- tt = (struct tm *) g_malloc0 (sizeof (struct tm));
- localtime_r (&exif->override_datetime, tt);
- if (strftime (&conv[0], sizeof (conv), exif->datetime_format ? exif->datetime_format : "%c", tt))
- res = g_strdup (&conv[0]);
- }
-
- if (! res) {
- tt = parse_exif_date (val);
- if (tt) {
- shift_time (tt, exif->timezone_shift);
- if (strftime (&conv[0], sizeof (conv), exif->datetime_format ? exif->datetime_format : "%c", tt))
- res = g_strdup (&conv[0]);
- }
- }
+ if (g_str_equal (key, EXIF_APERTURE)) {
+ gdouble aperture = exif->override_aperture != -1 ? aperture = exif->override_aperture : gexiv2_metadata_get_fnumber (exif->priv->metadata);
+ if (aperture != -1.0)
+ return g_strdup_printf ("&#402;/%.1f", aperture);
+ }
- g_free (tt);
- if (res)
- return res;
- }
- g_free (val);
- }
+ if (g_str_equal (key, EXIF_EXPOSURE)) {
+ gint nom, den;
- if (g_str_equal (key, EXIF_EXPOSURE)) {
- float val = exifData["Exif.Photo.ExposureTime"].toFloat();
- if (val > 0) {
- if (val < 0.5)
- return g_strdup_printf ("1/%.0f s", 1/val);
- else
- return g_strdup_printf ("%.1f s", val);
- }
- }
+ if (gexiv2_metadata_get_exposure_time (exif->priv->metadata, &nom, &den)) {
+ gdouble val = (gdouble) nom / (gdouble) den;
+ if (val < 0.5)
+ return g_strdup_printf ("1/%.0f s", 1/val);
+ else
+ return g_strdup_printf ("%.1f s", val);
+ }
+ }
- if (g_str_equal (key, EXIF_FLASH)) {
- long int val = exifData["Exif.Photo.Flash"].toLong();
- if (val > 0 && (val & 1) == 1)
- return g_strdup ("Flash fired");
- else
- return g_strdup ("--");
- }
+ if (g_str_equal (key, EXIF_FLASH)) {
+ glong val = gexiv2_metadata_get_tag_long (exif->priv->metadata, EXIF_FLASH);
+ if (val > 0 && (val & 1) == 1)
+ return g_strdup ("Flash fired");
+ else
+ return g_strdup ("--");
+ }
- if (g_str_equal (key, EXIF_FOCAL_LENGTH)) {
- double val;
- val = exif->override_focal_length != -1 ? exif->override_focal_length : exifData["Exif.Photo.FocalLength"].toFloat();
- if (val >= 0)
- return g_strdup_printf ("%.0f mm", val);
- }
+ if (g_str_equal (key, EXIF_FOCAL_LENGTH)) {
+ gdouble val;
+ val = exif->override_focal_length != -1 ? exif->override_focal_length : gexiv2_metadata_get_focal_length (exif->priv->metadata);
+ if (val >= 0)
+ return g_strdup_printf ("%.0f mm", val);
+ }
- if (g_str_equal (key, EXIF_ISO)) {
- long int val = exifData["Exif.Photo.ISOSpeedRatings"].toLong();
- if (val > 0)
- return g_strdup_printf ("%ld", val);
- }
+ if (g_str_equal (key, EXIF_ISO)) {
+ gint val = gexiv2_metadata_get_iso_speed (exif->priv->metadata);
+ if (val > 0)
+ return g_strdup_printf ("%d", val);
+ }
- if (g_str_equal (key, EXIF_CANON_CAMERA_TEMP)) {
- if (exifData["Exif.CanonSi.0x000c"].count() > 0) {
- int long val = exifData["Exif.CanonSi.0x000c"].toLong();
- if (val > 0)
- return g_strdup_printf ("%ld &deg;C", val - 128);
- }
- }
+ if (g_str_equal (key, EXIF_CANON_CAMERA_TEMP)) {
+ if (gexiv2_metadata_has_tag (exif->priv->metadata, "Exif.CanonSi.0x000c")) {
+ glong val = gexiv2_metadata_get_tag_long (exif->priv->metadata, "Exif.CanonSi.0x000c");
+ if (val > 0)
+ return g_strdup_printf ("%ld &deg;C", val - 128);
}
+ }
- if (g_str_has_prefix (key, "Iptc.")) {
- Exiv2::IptcData &iptcData = exif->priv->image->iptcData();
- if (iptcData.empty())
- return NULL;
+ if (g_str_equal (key, EXIF_DATETIME) ||
+ g_str_equal (key, "Exif.Photo.DateTimeOriginal") ||
+ g_str_equal (key, "Exif.Photo.DateTimeDigitized") ||
+ g_str_equal (key, "Exif.Image.DateTime")) {
+ gchar *val;
+
+ val = gexiv2_metadata_get_tag_string (exif->priv->metadata, "Exif.Photo.DateTimeOriginal");
+ if (! val || strlen (val) == 0)
+ val = gexiv2_metadata_get_tag_string (exif->priv->metadata, "Exif.Photo.DateTimeDigitized");
+ if (! val || strlen (val) == 0)
+ val = gexiv2_metadata_get_tag_string (exif->priv->metadata, "Exif.Image.DateTime"); /* usually a modification date */
+ if (val && strlen (val) > 0) {
+ struct tm *tt;
+
+ tt = parse_exif_date_with_overrides (val, exif);
+ g_free (val);
+ if (tt) {
+ gchar *res = format_exif_time (tt, exif->datetime_format ? exif->datetime_format : "%c");
+ g_free (tt);
+ return res;
+ }
}
- }
- catch (...) {
- return NULL;
+ g_free (val);
}
+ /* fall back to plain value retrieval */
return get_exif_data (exif, key);
}
@@ -374,42 +335,23 @@ get_exif_data_fixed (ExifData *exif, const gchar *key)
gboolean
exif_has_key (ExifData *exif, const gchar *key)
{
- const gchar *rkey;
-
g_return_val_if_fail (exif != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
- rkey = get_real_key_name (key);
-
- try {
- if (g_strcmp0 (rkey, JPEG_COMMENT) == 0) {
- return (! exif->priv->image->comment().empty());
- }
-
- if (g_str_has_prefix (rkey, "Exif.")) {
- Exiv2::ExifData &exifData = exif->priv->image->exifData();
- if (exifData.empty() || exifData[rkey].count() <= 0)
- return FALSE;
+ key = get_real_key_name (key);
- /* Special case for some keys */
- if (g_str_equal (key, EXIF_CANON_CAMERA_TEMP)) {
- int long val = exifData["Exif.CanonSi.0x000c"].toLong();
- return val > 0;
- }
+ if (g_str_equal (key, JPEG_COMMENT)) {
+ gchar *comment = gexiv2_metadata_get_comment (exif->priv->metadata);
+ gboolean ret = comment && strlen (comment) > 0;
+ g_free (comment);
+ return ret;
+ }
- return TRUE;
- }
+ if (g_str_equal (key, EXIF_CANON_CAMERA_TEMP))
+ return gexiv2_metadata_has_tag (exif->priv->metadata, "Exif.CanonSi.0x000c") &&
+ gexiv2_metadata_get_tag_long (exif->priv->metadata, "Exif.CanonSi.0x000c") > 0;
- if (g_str_has_prefix (rkey, "Iptc.")) {
- Exiv2::IptcData &iptcData = exif->priv->image->iptcData();
- return iptc_has_key (iptcData, rkey);
- }
-
- return FALSE;
- }
- catch (...) {
- return FALSE;
- }
+ return gexiv2_metadata_has_tag (exif->priv->metadata, key);
}
@@ -760,7 +702,7 @@ calculate_sizes (const unsigned long max_width, const unsigned long max_height,
unsigned long *width, unsigned long *height)
{
if (max_width > *width && max_height > *height)
- return;
+ return;
double max_ratio = (double) max_width / (double) max_height;
double real_ratio = (double) *width / (double) *height;
@@ -775,130 +717,65 @@ 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)
+shift_exif_time (GExiv2Metadata *metadata, const char *key, int amount)
{
struct tm *tt;
gchar *s;
gchar *st;
- gboolean res;
-
- res = FALSE;
- try {
- if (exifData[key].count() > 0) {
- s = exiv2_str_val (exifData, key);
-
- if (s && strlen (s) > 0) {
- tt = parse_exif_date (s);
- if (tt) {
- shift_time (tt, amount);
- st = format_exif_time (tt);
- if (st)
- exifData[key] = st;
- g_free (st);
- g_free (tt);
- res = TRUE;
- }
- }
- g_free (s);
- }
- } catch (...) { }
-
- return res;
-}
-
-static gboolean
-shift_iptc_time (Exiv2::IptcData &iptcData, const char *date_key, const char *time_key, int amount)
-{
- struct tm tt = {0};
- long int orig_time;
- gboolean res;
- Exiv2::DateValue dval;
- Exiv2::TimeValue tval;
-
- res = FALSE;
- if (iptc_has_key (iptcData, date_key) || iptc_has_key (iptcData, time_key)) {
- orig_time = (iptc_has_key (iptcData, date_key) ? iptcData[date_key].toLong() : 0) +
- (iptc_has_key (iptcData, time_key) ? iptcData[time_key].toLong() : 0);
- if (orig_time > 0) {
- orig_time += amount * 60;
- localtime_r (&orig_time, &tt);
- mktime (&tt);
- if (tt.tm_isdst)
- shift_time (&tt, -60);
-
- dval = Exiv2::DateValue(tt.tm_year + 1900, tt.tm_mon + 1, tt.tm_mday);
- tval = Exiv2::TimeValue(tt.tm_hour, tt.tm_min, tt.tm_sec, 0, 0);
- iptcData[date_key].setValue(&dval);
- iptcData[time_key].setValue(&tval);
- res = TRUE;
- }
- }
-
- return res;
-}
-
-static gboolean
-override_exif_time (Exiv2::ExifData &exifData, const char *key, time_t datetime)
-{
- struct tm tt = {0};
- gchar *st;
- gboolean res;
-
- res = FALSE;
- try {
- if (exifData[key].count() > 0) {
- localtime_r (&datetime, &tt);
- st = format_exif_time (&tt);
+ gboolean res = FALSE;
+
+ s = gexiv2_metadata_get_tag_string (metadata, key);
+ if (s && strlen (s) > 0) {
+ tt = parse_exif_date (s);
+ if (tt) {
+ shift_time (tt, amount);
+ st = format_exif_time (tt, NULL);
if (st)
- exifData[key] = st;
+ res = gexiv2_metadata_set_tag_string (metadata, key, st);
g_free (st);
- res = TRUE;
+ g_free (tt);
}
- } catch (...) { }
+ }
+ g_free (s);
return res;
}
static gboolean
-override_iptc_time (Exiv2::IptcData &iptcData, const char *date_key, const char *time_key, time_t datetime)
+override_exif_time (GExiv2Metadata *metadata, const char *key, time_t datetime)
{
struct tm tt = {0};
- Exiv2::DateValue dval;
- Exiv2::TimeValue tval;
+ gchar *s;
+ gchar *st;
+ gboolean res = FALSE;
- if (iptc_has_key (iptcData, date_key) || iptc_has_key (iptcData, time_key)) {
+ s = gexiv2_metadata_get_tag_string (metadata, key);
+ if (s && strlen (s) > 0) {
localtime_r (&datetime, &tt);
-
- dval = Exiv2::DateValue(tt.tm_year + 1900, tt.tm_mon + 1, tt.tm_mday);
- tval = Exiv2::TimeValue(tt.tm_hour, tt.tm_min, tt.tm_sec, 0, 0);
- iptcData[date_key].setValue(&dval);
- iptcData[time_key].setValue(&tval);
-
- return TRUE;
+ st = format_exif_time (&tt, NULL);
+ if (st)
+ res = gexiv2_metadata_set_tag_string (metadata, key, st);
+ g_free (st);
}
+ g_free (s);
- return FALSE;
+ return res;
}
-
/* List of tags we don't want to copy from external EXIF data since they are related to the RAW file,
- * not the processed image. Note that this list is not by far complete.
+ * not the processed image. Note that this list is far from complete.
*/
-static const gchar * image_size_tags[] = {
+static const gchar *keep_source_tags[] = {
"Exif.Image.ImageWidth",
"Exif.Image.ImageHeight",
"Exif.Image.ImageLength",
"Exif.Image.Orientation",
- "Exif.Photo.PixelXDimension",
- "Exif.Photo.PixelYDimension",
"Exif.Image.XResolution",
"Exif.Image.YResolution",
"Exif.Image.ResolutionUnit",
"Exif.Image.Compression",
"Exif.Image.BitsPerSample",
"Exif.Image.SamplesPerPixel",
- "Exif.Photo.ComponentsConfiguration",
- "Exif.Photo.CompressedBitsPerPixel",
"Exif.Image.JPEGTables",
"Exif.Image.JPEGProc",
"Exif.Image.JPEGInterchangeFormat",
@@ -915,46 +792,82 @@ static const gchar * image_size_tags[] = {
"Exif.Image.ReferenceBlackWhite",
"Exif.Image.PhotometricInterpretation",
"Exif.Image.PlanarConfiguration",
+ "Exif.Photo.ColorSpace",
+ "Exif.Photo.ComponentsConfiguration",
+ "Exif.Photo.CompressedBitsPerPixel",
+ "Exif.Photo.FocalPlaneXResolution",
+ "Exif.Photo.FocalPlaneYResolution",
+ "Exif.Photo.PixelXDimension",
+ "Exif.Photo.PixelYDimension",
+ "Exif.Canon.ColorSpace",
};
static gboolean
-is_image_size_tag (const gchar *s)
+copy_tag (GExiv2Metadata *metadata, GExiv2Metadata *source_metadata, GExiv2Metadata *external_metadata, const gchar *tag)
{
+ gchar *val;
unsigned int i;
+ gboolean res = FALSE;
+
+ /* filter-out tags that should be copied neither from the source or the external metadata */
+ if (g_str_has_prefix (tag, "Exif.Thumbnail.") ||
+ g_str_equal (tag, "Exif.Canon.0x4002") ||
+ g_str_equal (tag, "Exif.Canon.0x4005"))
+ return TRUE;
- for (i = 0; i < G_N_ELEMENTS (image_size_tags); i++)
- if (g_str_equal (s, image_size_tags[i]))
- return TRUE;
- return FALSE;
+ /* should be copied from the source file */
+ for (i = 0; i < G_N_ELEMENTS (keep_source_tags); i++)
+ if (g_str_equal (tag, keep_source_tags[i])) {
+ val = gexiv2_metadata_get_tag_string (source_metadata, tag);
+ if (val)
+ res = gexiv2_metadata_set_tag_string (metadata, tag, val);
+ g_free (val);
+ return res;
+ }
+
+ val = gexiv2_metadata_get_tag_string (external_metadata, tag);
+ if (val)
+ res = gexiv2_metadata_set_tag_string (metadata, tag, val);
+ g_free (val);
+ return res;
}
static void
-copy_metadata (Exiv2::Image::AutoPtr &img, Exiv2::Image::AutoPtr &external_img)
+copy_metadata (GExiv2Metadata *metadata, const gchar *source_img, const gchar *external_img)
{
- Exiv2::ExifData exifData;
- Exiv2::ExifData &img_exifData = img->exifData();
- Exiv2::ExifData &ext_exifData = external_img->exifData();
-
- /* First copy metadata from the external image excluding size tags */
- Exiv2::ExifData::const_iterator end = ext_exifData.end();
- for (Exiv2::ExifData::const_iterator i = ext_exifData.begin(); i != end; ++i) {
- gchar *s = g_strdup (i->key().c_str());
- if (! is_image_size_tag (s))
- exifData[s] = ext_exifData[s];
- g_free (s);
+ GExiv2Metadata *source_metadata;
+ GExiv2Metadata *external_metadata;
+ GError *error = NULL;
+ gchar **tags;
+
+ source_metadata = gexiv2_metadata_new ();
+ if (! gexiv2_metadata_open_path (source_metadata, source_img, &error)) {
+ log_error ("copy_metadata: %s (ignoring...)\n", error->message);
+ g_error_free (error);
+ /* continue with empty source metadata */
}
- /* Copy selected size tags from the processed image */
- end = img_exifData.end();
- for (Exiv2::ExifData::const_iterator i = img_exifData.begin(); i != end; ++i) {
- gchar *s = g_strdup (i->key().c_str());
- if (is_image_size_tag (s))
- exifData[s] = img_exifData[s];
- g_free (s);
+ external_metadata = gexiv2_metadata_new ();
+ if (! gexiv2_metadata_open_path (external_metadata, external_img, &error)) {
+ log_error ("copy_metadata: %s\n", error->message);
+ g_error_free (error);
+ g_object_unref (source_metadata);
+ g_object_unref (external_metadata);
+ return;
}
- img->setMetadata (*external_img);
- img->setExifData (exifData);
+ tags = gexiv2_metadata_get_exif_tags (external_metadata);
+ for (gchar **i = tags; *i; i++)
+ copy_tag (metadata, source_metadata, external_metadata, *i);
+ g_strfreev (tags);
+
+ tags = gexiv2_metadata_get_iptc_tags (external_metadata);
+ for (gchar **i = tags; *i; i++)
+ copy_tag (metadata, source_metadata, external_metadata, *i);
+ g_strfreev (tags);
+
+ g_object_unref (source_metadata);
+ g_object_unref (external_metadata);
}
@@ -966,140 +879,114 @@ copy_metadata (Exiv2::Image::AutoPtr &img, Exiv2::Image::AutoPtr &external_img)
void
modify_exif (const gchar *filename, ExifData *exif, gboolean strip_thumbnail, gboolean strip_xmp)
{
+ GExiv2Metadata *metadata;
+ GError *error = NULL;
gboolean modified;
gboolean res;
g_assert (filename != NULL);
-
- if (! strip_thumbnail && exif == NULL)
+ if (! strip_thumbnail && ! strip_xmp && ! exif)
return;
modified = FALSE;
- try {
- Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open (filename);
- g_assert (image.get() != 0);
-
- image->readMetadata();
-
- /* Write down metadata from external file if supplied */
- if (exif && exif->external_exif_data) {
- Exiv2::Image::AutoPtr ext_image = Exiv2::ImageFactory::open (exif->external_exif_data);
- if (ext_image.get() != 0) {
- ext_image->clearMetadata();
- ext_image->readMetadata();
- copy_metadata (image, ext_image);
- modified = TRUE;
- }
- }
-
- Exiv2::ExifData &exifData = image->exifData();
- Exiv2::IptcData &iptcData = image->iptcData();
-
- if (exif) {
- if (exif->override_copyright) {
- if (! exifData.empty()) {
- exifData["Exif.Image.Copyright"] = exif->override_copyright;
- modified = TRUE;
- }
- if (! iptcData.empty()) {
- iptcData["Iptc.Application2.Copyright"] = exif->override_copyright;
- modified = TRUE;
- }
- }
+ res = FALSE;
- if (exif->timezone_shift != 0 && exif->override_datetime == (time_t) -1) {
- if (! exifData.empty()) {
- res = shift_exif_time (exifData, "Exif.Photo.DateTimeOriginal", exif->timezone_shift);
- res = shift_exif_time (exifData, "Exif.Photo.DateTimeDigitized", exif->timezone_shift) || res;
- res = shift_exif_time (exifData, "Exif.Image.DateTime", exif->timezone_shift) || res;
- modified = TRUE;
- }
- if (! iptcData.empty()) {
- res = shift_iptc_time (iptcData, "Iptc.Application2.DateCreated", "Iptc.Application2.TimeCreated", exif->timezone_shift);
- res = shift_iptc_time (iptcData, "Iptc.Application2.DigitizationDate", "Iptc.Application2.DigitizationTime", exif->timezone_shift) || res;
- if (res)
- modified = TRUE;
- }
- }
+ metadata = gexiv2_metadata_new ();
+ if (! gexiv2_metadata_open_path (metadata, filename, &error)) {
+ log_error ("modify_exif: %s\n", error->message);
+ g_error_free (error);
+ /* gexiv2 cannot operate on empty, newly constructed object, bail out */
+ g_object_unref (metadata);
+ return;
+ }
- if (exif->override_datetime != (time_t) -1 && !exifData.empty()) {
- if (! exifData.empty()) {
- res = override_exif_time (exifData, "Exif.Photo.DateTimeOriginal", exif->override_datetime);
- res = override_exif_time (exifData, "Exif.Photo.DateTimeDigitized", exif->override_datetime) || res;
- res = override_exif_time (exifData, "Exif.Image.DateTime", exif->override_datetime) || res;
- modified = TRUE;
- }
- if (! iptcData.empty()) {
- res = override_iptc_time (iptcData, "Iptc.Application2.DateCreated", "Iptc.Application2.TimeCreated", exif->override_datetime);
- res = override_iptc_time (iptcData, "Iptc.Application2.DigitizationDate", "Iptc.Application2.DigitizationTime", exif->override_datetime) || res;
- if (res)
- modified = TRUE;
- }
- }
+ /* write down metadata from external file if supplied */
+ if (exif->external_exif_data) {
+ gexiv2_metadata_clear (metadata);
+ copy_metadata (metadata, filename, exif->external_exif_data);
+ modified = TRUE;
+ }
- if (exif->override_aperture != -1) {
- if (! exifData.empty()) {
- exifData["Exif.Photo.FNumber"] = Exiv2::floatToRationalCast (exif->override_aperture);
- if (exifData["Exif.Photo.ApertureValue"].count() > 0)
- exifData["Exif.Photo.ApertureValue"] = Exiv2::floatToRationalCast (exif->override_aperture);
- modified = TRUE;
- }
- }
+ if (exif->override_copyright) {
+ if (gexiv2_metadata_set_tag_string (metadata, "Exif.Image.Copyright", exif->override_copyright))
+ modified = TRUE;
+ if (gexiv2_metadata_set_tag_string (metadata, "Iptc.Application2.Copyright", exif->override_copyright))
+ modified = TRUE;
+ }
- if (exif->override_focal_length != -1) {
- if (! exifData.empty()) {
- exifData["Exif.Photo.FocalLength"] = Exiv2::floatToRationalCast (exif->override_focal_length);
- modified = TRUE;
- }
- }
+ if (exif->timezone_shift != 0 && exif->override_datetime == (time_t) -1) {
+ if (gexiv2_metadata_has_exif (metadata)) {
+ res = shift_exif_time (metadata, "Exif.Photo.DateTimeOriginal", exif->timezone_shift) || res;
+ res = shift_exif_time (metadata, "Exif.Photo.DateTimeDigitized", exif->timezone_shift) || res;
+ res = shift_exif_time (metadata, "Exif.Image.DateTime", exif->timezone_shift) || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Exif.Image.TimeZoneOffset") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Exif.Image.PreviewDateTime") || res;
+ }
+ if (gexiv2_metadata_has_iptc (metadata)) {
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DateCreated") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.TimeCreated") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DigitizationDate") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DigitizationTime") || res;
+ }
+ modified = res || modified;
+ }
- if (exif->override_artist_name) {
- if (! exifData.empty()) {
- exifData["Exif.Image.Artist"] = exif->override_artist_name;
- if (exifData["Exif.Photo.CameraOwnerName"].count() >= 1)
- exifData["Exif.Photo.CameraOwnerName"] = exif->override_artist_name;
- if (exifData["Exif.Canon.OwnerName"].count() >= 1)
- exifData["Exif.Canon.OwnerName"] = exif->override_artist_name;
- modified = TRUE;
- }
- }
+ if (exif->override_datetime != (time_t) -1) {
+ if (gexiv2_metadata_has_exif (metadata)) {
+ res = override_exif_time (metadata, "Exif.Photo.DateTimeOriginal", exif->override_datetime);
+ res = override_exif_time (metadata, "Exif.Photo.DateTimeDigitized", exif->override_datetime) || res;
+ res = override_exif_time (metadata, "Exif.Image.DateTime", exif->override_datetime) || res;
}
+ if (gexiv2_metadata_has_iptc (metadata)) {
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DateCreated") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.TimeCreated") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DigitizationDate") || res;
+ res = gexiv2_metadata_clear_tag (metadata, "Iptc.Application2.DigitizationTime") || res;
+ }
+ modified = res || modified;
+ }
+ if (exif->override_aperture != -1) {
+ if (gexiv2_metadata_set_exif_tag_rational (metadata, "Exif.Photo.FNumber", exif->override_aperture * 1000000.0, 1000000))
+ modified = TRUE;
+ if (gexiv2_metadata_set_exif_tag_rational (metadata, "Exif.Photo.ApertureValue", exif->override_aperture * 1000000.0, 1000000))
+ modified = TRUE;
+ if (gexiv2_metadata_set_exif_tag_rational (metadata, "Exif.CanonSi.ApertureValue", exif->override_aperture * 1000000.0, 1000000))
+ modified = TRUE;
+ }
- if (strip_thumbnail && ! exifData.empty()) {
-#ifdef HAVE_EXIFTHUMB
- Exiv2::ExifThumb exifThumb(image->exifData());
- std::string thumbExt = exifThumb.extension();
-#else
- std::string thumbExt = exifData.thumbnailExtension();
-#endif
+ if (exif->override_focal_length != -1) {
+ if (gexiv2_metadata_set_exif_tag_rational (metadata, "Exif.Photo.FocalLength", exif->override_focal_length * 1000000.0, 1000000))
+ modified = TRUE;
+ }
- if (! thumbExt.empty()) {
-#ifdef HAVE_EXIFTHUMB
- exifThumb.erase();
-#else
- exifData.eraseThumbnail();
-#endif
- modified = TRUE;
- }
- }
+ if (exif->override_artist_name) {
+ if (gexiv2_metadata_set_tag_string (metadata, "Exif.Image.Artist", exif->override_artist_name))
+ modified = TRUE;
+ if (gexiv2_metadata_set_tag_string (metadata, "Exif.Photo.CameraOwnerName", exif->override_artist_name))
+ modified = TRUE;
+ if (gexiv2_metadata_set_tag_string (metadata, "Exif.Canon.OwnerName", exif->override_artist_name))
+ modified = TRUE;
+ if (gexiv2_metadata_set_tag_string (metadata, "Iptc.Application2.Byline", exif->override_artist_name))
+ modified = TRUE;
+ }
- if (strip_xmp) {
- if (! image->xmpData().empty()) {
- image->clearXmpData ();
- modified = TRUE;
- }
- if (! image->xmpPacket().empty()) {
- image->clearXmpPacket ();
- modified = TRUE;
- }
- }
+ if (strip_thumbnail) {
+ gexiv2_metadata_erase_exif_thumbnail (metadata);
+ modified = TRUE;
+ }
- if (modified)
- image->writeMetadata();
+ if (strip_xmp && gexiv2_metadata_has_xmp (metadata)) {
+ gexiv2_metadata_clear_xmp (metadata);
+ modified = TRUE;
}
- catch (Exiv2::AnyError& e)
- {
- log_error ("modify_exif: Caught Exiv2 exception: '%s'\n", e.what());
+
+ if (modified) {
+ if (! gexiv2_metadata_save_file (metadata, filename, &error)) {
+ log_error ("modify_exif: couldn't write metadata to '%s': %s\n", filename, error->message);
+ g_error_free (error);
+ }
}
+
+ g_object_unref (metadata);
}
diff --git a/src/jpeg-utils.h b/src/jpeg-utils.h
index 767320a..b73576b 100644
--- a/src/jpeg-utils.h
+++ b/src/jpeg-utils.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
#define CROP_SIMPLE_SHAVE_AMOUNT 0 /* percent */
/* EXIF data known keys */
+/* Exiv2 Tag Reference can be found at http://exiv2.org/metadata.html */
#define EXIF_APERTURE "Exif.Photo.FNumber"
#define EXIF_CAMERA_MODEL "Exif.Image.Model"
#define EXIF_DATETIME "Exif.Photo.DateTimeOriginal"
@@ -99,12 +100,12 @@ gboolean exif_has_key (ExifData *exif, const gchar *key);
*/
gboolean resize_image (const gchar *src, const gchar *dst,
unsigned long size_x, unsigned long size_y,
- int quality,
- gboolean thumbnail,
- gboolean autorotate,
- gboolean hidpi_strict_dimensions,
- ExifData *exif,
- gchar *resize_opts);
+ int quality,
+ gboolean thumbnail,
+ gboolean autorotate,
+ gboolean hidpi_strict_dimensions,
+ ExifData *exif,
+ gchar *resize_opts);
/*
* get_image_sizes: retrieve image dimensions
@@ -118,7 +119,7 @@ void get_image_sizes (const gchar *img,
* calculate_sizes: calculate maximal image sizes within specified limits keeping aspect ratio
*/
void calculate_sizes (const unsigned long max_width, const unsigned long max_height,
- unsigned long *width, unsigned long *height);
+ unsigned long *width, unsigned long *height);
/*
* modify_exif: - strip thumbnail stored in EXIF table