From 8d2d73759dfe0c193c29b7e1f0b90a0873c3b9e7 Mon Sep 17 00:00:00 2001
From: Johannes Hofmann <Johannes.Hofmann@gmx.de>
Date: Tue, 7 Apr 2009 14:30:26 +0200
Subject: switch ImageMetadata to exiv2 (mostly by Konrad Golling)

---
 configure.ac          |   4 +
 src/ImageMetaData.cxx | 323 +++++++++++++++++++++++---------------------------
 2 files changed, 155 insertions(+), 172 deletions(-)

diff --git a/configure.ac b/configure.ac
index de7e818..e9cf00e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,5 +60,9 @@ LIBS="`$GSLCONFIG --libs` $LIBS"
 AC_CHECK_HEADERS([tiffio.h], [], [echo "Error: tiffio.h not found."; exit 1;])
 AC_CHECK_LIB([tiff], [TIFFOpen], [], [echo "Error: libtiff.so not found."; exit 1;])
 
+# Check for exiv2
+AC_CHECK_HEADERS([exiv2/exif.hpp], [], [echo "Error: exiv2/exif.hpp not found."; exit 1;])
+LIBS="$LIBS -lexiv2"
+
 AC_CONFIG_FILES([Makefile src/Makefile])
 AC_OUTPUT
diff --git a/src/ImageMetaData.cxx b/src/ImageMetaData.cxx
index f22a641..1c3b2f5 100644
--- a/src/ImageMetaData.cxx
+++ b/src/ImageMetaData.cxx
@@ -12,12 +12,14 @@
 #include <string.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <assert.h>
 #include <sys/param.h>
 #include <sys/types.h>
-#include <sys/wait.h>
 #include <sys/stat.h>
 
-#include "util.h"
+#include <exiv2/image.hpp>
+#include <exiv2/exif.hpp>
+
 #include "ImageMetaData.H"
 
 ImageMetaData::ImageMetaData() {
@@ -65,87 +67,89 @@ ImageMetaData::save_image(char *in_img, char *out_img) {
 	return save_image_jpgcom(in_img, out_img);
 }
 
-static double
-degminsecstr2double(char *val) {
-    double ret, dv;
-
-    ret = 0.0;
-    for (dv=1.0; dv <= 3600.0; dv = dv * 60.0) {
-        ret = ret + atof(val) / dv;
-        val = strchr(val, ',');
-        if (!val || val[1] == '\0') {
-            break;
-        } else {
-            val++;
+int
+ImageMetaData::load_image_exif(char *name) {
+    Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(name);
+    assert(image.get() != 0);
+    image->readMetadata();
+    Exiv2::ExifData &exifData = image->exifData();
+    if (exifData.empty())
+        {
+        fprintf(stderr, "%s: No Exif data found in the file", name);
+        return 0;
         }
-    }
 
-    return ret;
-}
+    Exiv2::ExifData::iterator pos = exifData.end();
+
+    if (!_manufacturer )
+        {
+        Exiv2::ExifKey key("Exif.Image.Make"); // tag auch wirklich vorhanden?
+        pos = exifData.findKey(key);
+        if (pos != exifData.end() && pos->size() )
+            _manufacturer = strdup(pos->toString().c_str());
+        }
 
-#define EXIF_MANUFACTURER              0x010f
-#define EXIF_MODEL                     0x0110
-#define EXIF_FOCAL_LENGTH              0x920a
-#define EXIF_FOCAL_LENGTH_IN_35MM_FILM 0xa405
-#define EXIF_GPS_LATIITUDE             0x0002
-#define EXIF_GPS_LONGITUDE             0x0004
-#define EXIF_GPS_ALTITUDE              0x0006
+    if(!_model)
+        {
+        Exiv2::ExifKey key("Exif.Image.Model");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end() && pos->size() )
+            _model = strdup(pos->toString().c_str());
+        }
 
-int
-ImageMetaData::load_image_exif(char *name) {
-    const char * args[32];
-    FILE *p;
-    pid_t pid;
-    int status;
-    char buf[1024];
-    char val[1024];
-    int id;
-
-    args[0] = "exif";
-    args[1] = "-i";
-    args[2] = "-m";
-    args[3] = name;
-    args[4] = NULL;
-  
-    p = pexecvp(args[0], const_cast<char * const *>(args), &pid, "r");
-
-    if (p) {
-        while (fgets(buf, sizeof(buf), p) != NULL) {
-            if (sscanf(buf, "%x\t%[^\n]\n", &id, val) != 2) {
-                continue;
+    if (isnan(_focal_length))
+        {
+        Exiv2::ExifKey key("Exif.Photo.FocalLength");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end() && pos->toFloat() >= 0)
+            _focal_length = pos->toFloat();
+        }
+
+    if (isnan(_focal_length_35mm))
+        {
+        Exiv2::ExifKey key("Exif.Photo.FocalLengthIn35mmFilm");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end() && pos->toFloat() >= 0)
+            _focal_length_35mm = pos->toFloat();
+        }
+
+    if (isnan(_longitude))
+        {
+        Exiv2::ExifKey key("Exif.GPSInfo.GPSLongitude");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end())
+            {
+            if ( pos->toFloat() >= 0)
+                _longitude = pos->toFloat();
+            if ( pos->toFloat(1) >= 0)
+                _longitude += pos->toFloat(1)/60;
+            if ( pos->toFloat(2) >= 0)
+                _longitude += pos->toFloat(2)/3600;
             }
+        }
 
-            switch(id) {
-                case EXIF_MANUFACTURER:
-                    if (!_manufacturer) _manufacturer = strdup(val);
-                    break;
-                case EXIF_MODEL:
-                    if (!_model) _model = strdup(val);
-                    break;
-                case EXIF_FOCAL_LENGTH:
-                    if (isnan(_focal_length)) _focal_length = atof(val);
-                    break;
-                case EXIF_FOCAL_LENGTH_IN_35MM_FILM:
-                    if (isnan(_focal_length_35mm)) _focal_length_35mm = atof(val);
-                    break;
-                case EXIF_GPS_LONGITUDE:
-                    if (isnan(_longitude)) _longitude = degminsecstr2double(val);
-                    break;
-                case EXIF_GPS_LATIITUDE:
-                    if (isnan(_latitude)) _latitude = degminsecstr2double(val);
-                    break;
-                case EXIF_GPS_ALTITUDE:
-                    if (isnan(_height)) _height = atof(val);
-                    break;
+    if (isnan(_latitude))
+        {
+        Exiv2::ExifKey key("Exif.GPSInfo.GPSLatitude");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end())
+            {
+            if ( pos->toFloat() >= 0)
+                _latitude = pos->toFloat();
+            if ( pos->toFloat(1) >= 0)
+                _latitude += pos->toFloat(1)/60;
+            if ( pos->toFloat(2) >= 0)
+                _latitude += pos->toFloat(2)/3600;
             }
         }
-    }
 
-    fclose(p);
-    waitpid(pid, &status, 0);
-    if (WEXITSTATUS(status) == 127 || WEXITSTATUS(status) == 126) {
-        fprintf(stderr, "%s not found\n", args[0]);
-    }
+    if (isnan(_height))
+        {
+        Exiv2::ExifKey key("Exif.GPSInfo.GPSAltitude");
+        pos = exifData.findKey(key);
+        if (pos != exifData.end() && pos->toFloat() >= 0)
+            _height = pos->toFloat();
+        }
 
     return 0;
 }
@@ -155,76 +159,74 @@ ImageMetaData::load_image_exif(char *name) {
 
 int
 ImageMetaData::load_image_jpgcom(char *name) {
-    const char * args[32];
-    FILE *p;
-    pid_t pid;
-    int status;
-    char buf[1024];
     double lo, la, he, dir, ni, ti, fr, k0, k1, x0 = 0.0;
     int pt = 0;
     int n, ret = 1;
 
-    args[0] = "rdjpgcom";
-    args[1] = name;
-    args[2] = NULL;
-
-    p = pexecvp(args[0], const_cast<char * const *>(args), &pid, "r");
-
-    if (p) {
-        while (fgets(buf, sizeof(buf), p) != NULL) {
-            if ((n = sscanf(buf, GIPFEL_FORMAT_2,
-                    &lo, &la, &he, &dir, &ni, &ti, &fr, &pt, &k0, &k1, &x0)) >= 8) {
-
-                _longitude = lo;
-                _latitude  = la;
-                _height    = he;
-                _direction = dir;
-                _nick      = ni;
-                _tilt      = ti;
-                _focal_length_35mm = fr;
-                _projection_type = pt;
-
-				if (n >= 10) {
-					_k0 = k0;
-					_k1 = k1;
-					_x0 = x0;
-				}
-
-                ret = 0;
-
-                break;
+    Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(name);
+    assert (image.get() != 0);
+    image->readMetadata();
+    const char *com = image->comment().c_str();
+
+    if ((n = sscanf(com, GIPFEL_FORMAT_2,
+            &lo, &la, &he, &dir, &ni, &ti, &fr, &pt, &k0, &k1, &x0)) >= 8)
+        {
+        _longitude = lo;
+        _latitude  = la;
+        _height    = he;
+        _direction = dir;
+        _nick      = ni;
+        _tilt      = ti;
+        _focal_length_35mm = fr;
+        _projection_type = pt;
+
+        if (n >= 10)
+            {
+            _k0 = k0;
+            _k1 = k1;
+            _x0 = x0;
             }
+        ret = 0;
         }
-
-        fclose(p);
-        waitpid(pid, &status, 0);
-        if (WEXITSTATUS(status) == 127 || WEXITSTATUS(status) == 126) {
-            fprintf(stderr, "%s not found\n", args[0]);
-        }
-    }
-
     return ret;
 }
 
 int
 ImageMetaData::save_image_jpgcom(char *in_img, char *out_img) {
-    const char * args[32];
-    FILE *p;
-    pid_t pid;
     char buf[1024], tmpname[MAXPATHLEN];
-    int status, err = 0;
-    ssize_t n;
-	int tmp_fd;
-	char *dirbuf;
-
-	dirbuf = strdup(out_img);
-	snprintf(tmpname, sizeof(tmpname), "%s/.gipfelXXXXXX", dirname(dirbuf));
-	free(dirbuf);
-	tmp_fd = mkstemp(tmpname);
-	if (tmp_fd < 0) {
-		perror("mkstemp");
-        return 1;
-    }
+    int n, err = 0;
+
+    char* dirbuf = strdup(out_img);
+    snprintf(tmpname, sizeof(tmpname), "%s/.gipfelXXXXXX", dirname(dirbuf));
+    free(dirbuf);
+
+	int in_fd = open(in_img, O_RDONLY);
+	if (in_fd == -1) {
+		perror("open");
+		return 1;
+	}
+
+	int out_fd = open(tmpname, O_WRONLY | O_TRUNC | O_CREAT);
+	if (out_fd == -1) {
+		perror("open");
+		close(in_fd);
+		return 1;
+	}
+
+	while ((n = read(in_fd, buf, sizeof(buf))) != 0) {
+		if (write(out_fd, buf, n) != n) {
+			perror("write");
+			err++;
+			break;
+		}
+	}
+
+	close(in_fd);
+
+    Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(tmpname);
+    assert (image.get() != 0);
+    image->readMetadata();
+    image->clearComment();
 
     snprintf(buf, sizeof(buf), GIPFEL_FORMAT_2,
         _longitude,
@@ -235,49 +237,26 @@ ImageMetaData::save_image_jpgcom(char *in_img, char *out_img) {
         _tilt,
         _focal_length_35mm,
         _projection_type,
-		_k0, _k1, _x0);
-
-    // try to save gipfel data in JPEG comment section
-    args[0] = "wrjpgcom";
-    args[1] = "-replace";
-    args[2] = "-comment";
-    args[3] = buf;
-    args[4] = in_img;
-    args[5] = NULL;
-
-    p = pexecvp(args[0], const_cast<char * const *>(args), &pid, "r");
-
-    if (p) {
-        while ((n = fread(buf, 1, sizeof(buf), p)) != 0) {
-            if (write(tmp_fd, buf, n) != n) {
-                perror("write");
-				err++;
-				break;
-            }
-        }
-        fclose(p);
-        waitpid(pid, &status, 0);
-		if (WEXITSTATUS(status) != 0)
-			err++;
-        if (WEXITSTATUS(status) == 127 || WEXITSTATUS(status) == 126)
-            fprintf(stderr, "%s not found\n", args[0]);
-    } else {
-		perror("pexecvp");
-		err++;
-	}
+        _k0, _k1, _x0);
 
-	fsync(tmp_fd); /* make sure data is on disk before replacing orig file */
-	close(tmp_fd);
 
-	if (!err) {
-		if (rename(tmpname, out_img) != 0) {
-			perror("rename");
-			err++;
-			unlink(tmpname);
-		}
-	}
+    image->setComment(buf);
+    image->writeMetadata();
+
+	fsync(out_fd); /* make sure data is on disk before replacing orig file */
+	close(out_fd);
+
+    struct stat stFileInfo;
+    if (! stat(out_img,&stFileInfo) )
+        unlink(out_img);
+    if (rename(tmpname, out_img) != 0)
+        {
+        perror("rename");
+        err++;
+        unlink(tmpname);
+        }
 
-    return err != 0;
+    return (err != 0);
 }
 
 void
-- 
cgit v1.2.3