switch to libexiv2, it can write EXIF data
[booh] / ext / rbbooh.c
index 746f9e95cf3ba23433295a3168662abd27418aae..2e59e9264f0e656d71db5e113105e65bb65de30b 100644 (file)
 
 #include <math.h>
 
+#include <exiv2/image.hpp>
+#include <exiv2/exif.hpp>
+
 #define GDK_PIXBUF_ENABLE_BACKEND
 #include <gtk/gtk.h>
 #include "rbgobject.h"
 
 #define _SELF(s) GDK_PIXBUF(RVAL2GOBJ(s)) 
 
-#include <libexif/exif-data.h>
-
 static VALUE whitebalance(VALUE self, VALUE level) {
         double red_filter[256], blue_filter[256];
         int i, x, y;
@@ -84,63 +85,55 @@ static VALUE gammacorrect(VALUE self, VALUE level) {
         return self;
 }
 
-static ExifEntry* exif_entry(VALUE filename, ExifTag tag, ExifData** data) {
-        unsigned int i;
-
-        *data = exif_data_new_from_file(StringValuePtr(filename));
-        if (*data == NULL) {
-                fprintf(stderr, "libexif failed loading file '%s'\n", StringValuePtr(filename));
-                return NULL;
-        }
-
-       for (i = 0; i < EXIF_IFD_COUNT; i++) {
-                ExifEntry* entry = exif_content_get_entry((*data)->ifd[i], tag);
-               if (entry)
-                        return entry;
+static VALUE exif_orientation(VALUE module, VALUE filename) {
+        try {
+                Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(StringValuePtr(filename));
+                image->readMetadata();
+                Exiv2::ExifData &exifData = image->exifData();
+                if (exifData.empty()) {
+                        return Qnil;
+                }
+                Exiv2::ExifData::const_iterator i = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"));
+                if (i != exifData.end()) {
+                        return INT2NUM(i->value().toLong());
+                }
+                return Qnil;
+        } catch (Exiv2::AnyError& e) {
+                std::cout << "Caught Exiv2 exception: " << e << "\n";
+                return Qnil;
         }
-
-        return NULL;
 }
 
-static VALUE exif_orientation(VALUE module, VALUE filename) {
-        ExifData* data = NULL;
-        ExifEntry* entry;
-
-        entry = exif_entry(filename, EXIF_TAG_ORIENTATION, &data);
-
-        if (entry != NULL) {
-                VALUE ret;
-                ExifByteOrder o;
-                ExifShort v_short;
-                if (!entry || !entry->parent || !entry->parent->parent)
-                        return Qnil;
-                o = exif_data_get_byte_order(entry->parent->parent);
-                v_short = exif_get_short(entry->data, o);
-                ret = INT2NUM(v_short);
-                exif_data_free(data);
-                return ret;
-       }
-        
-        if (data)
-                exif_data_free(data);
+static VALUE exif_set_orientation(VALUE module, VALUE filename, VALUE val) {
+        try {
+                Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(StringValuePtr(filename));
+                image->readMetadata();
+                Exiv2::ExifData &exifData = image->exifData();
+                exifData["Exif.Image.Orientation"] = uint16_t(NUM2INT(val));
+                image->writeMetadata();
+        } catch (Exiv2::AnyError& e) {
+                std::cout << "Caught Exiv2 exception: " << e << "\n";
+        }
         return Qnil;
 }
 
 static VALUE exif_datetimeoriginal(VALUE module, VALUE filename) {
-        ExifData* data = NULL;
-        ExifEntry* entry;
-
-        entry = exif_entry(filename, EXIF_TAG_DATE_TIME_ORIGINAL, &data);
-
-        if (entry != NULL) {
-                VALUE ret = rb_str_new((const char*) entry->data, entry->size);
-                exif_data_free(data);
-                return ret;
-       }
-
-        if (data)
-                exif_data_free(data);
-        return Qnil;
+        try {
+                Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(StringValuePtr(filename));
+                image->readMetadata();
+                Exiv2::ExifData &exifData = image->exifData();
+                if (exifData.empty()) {
+                        return Qnil;
+                }
+                Exiv2::ExifData::const_iterator i = exifData.findKey(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"));
+                if (i != exifData.end()) {
+                        return rb_str_new2(i->value().toString().c_str());
+                }
+                return Qnil;
+        } catch (Exiv2::AnyError& e) {
+                std::cout << "Caught Exiv2 exception: " << e << "\n";
+                return Qnil;
+        }
 }
 
 // internalize drawing "video" borders, it is too slow in ruby (0.12 secs on my p4 2.8 GHz, whereas it's barely measurable with this implementation)
@@ -163,7 +156,7 @@ static VALUE draw_borders(VALUE self, VALUE pixbuf, VALUE x1, VALUE x2, VALUE ys
 // (bugged as of rg2 0.16.0)
 static VALUE rotate_noleak(VALUE self, VALUE angle) {
         VALUE ret;
-        GdkPixbuf* dest = gdk_pixbuf_rotate_simple(_SELF(self), RVAL2GENUM(angle, GDK_TYPE_PIXBUF_ROTATION));
+        GdkPixbuf* dest = gdk_pixbuf_rotate_simple(_SELF(self), (GdkPixbufRotation) RVAL2GENUM(angle, GDK_TYPE_PIXBUF_ROTATION));
         if (dest == NULL)
                 return Qnil;
         ret = GOBJ2RVAL(dest);
@@ -174,26 +167,29 @@ static VALUE rotate_noleak(VALUE self, VALUE angle) {
 // internalize allowing to pass Qnil to RVAL2BOXED to have NULL passed to Gtk
 // (bugged as of rg2 0.16.0)
 static VALUE modify_bg(VALUE self, VALUE state, VALUE color) {
-        gtk_widget_modify_bg(GTK_WIDGET(RVAL2GOBJ(self)), RVAL2GENUM(state, GTK_TYPE_STATE_TYPE),
+        gtk_widget_modify_bg(GTK_WIDGET(RVAL2GOBJ(self)), (GtkStateType) RVAL2GENUM(state, GTK_TYPE_STATE_TYPE),
                              NIL_P(color) ? NULL : (GdkColor*) RVAL2BOXED(color, GDK_TYPE_COLOR));
         return self;
 }
 
+extern "C" {
 void 
 Init_libadds()
 {
     RGObjClassInfo* cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_PIXBUF, Qnil);
-    rb_define_method(cinfo->klass, "whitebalance!", whitebalance, 1); 
-    rb_define_method(cinfo->klass, "gammacorrect!", gammacorrect, 1); 
-    rb_define_method(cinfo->klass, "rotate", rotate_noleak, 1); 
+    rb_define_method(cinfo->klass, "whitebalance!", (VALUE (*)(...)) whitebalance, 1); 
+    rb_define_method(cinfo->klass, "gammacorrect!", (VALUE (*)(...)) gammacorrect, 1); 
+    rb_define_method(cinfo->klass, "rotate", (VALUE (*)(...)) rotate_noleak, 1); 
 
     cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_DRAWABLE, Qnil);
-    rb_define_method(cinfo->klass, "draw_borders", draw_borders, 5);
+    rb_define_method(cinfo->klass, "draw_borders", (VALUE (*)(...)) draw_borders, 5);
 
     cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GTK_TYPE_WIDGET, Qnil);
-    rb_define_method(cinfo->klass, "modify_bg", modify_bg, 2);
+    rb_define_method(cinfo->klass, "modify_bg", (VALUE (*)(...)) modify_bg, 2);
 
     VALUE exif = rb_define_module("Exif");
-    rb_define_module_function(exif, "orientation", exif_orientation, 1);
-    rb_define_module_function(exif, "datetimeoriginal", exif_datetimeoriginal, 1);
+    rb_define_module_function(exif, "orientation", (VALUE (*)(...)) exif_orientation, 1);
+    rb_define_module_function(exif, "set_orientation", (VALUE (*)(...)) exif_set_orientation, 2);
+    rb_define_module_function(exif, "datetimeoriginal", (VALUE (*)(...)) exif_datetimeoriginal, 1);
+}
 }