switch to libexiv2, it can write EXIF data
authorgc <gc>
Sun, 3 Feb 2008 15:19:53 +0000 (15:19 +0000)
committergc <gc>
Sun, 3 Feb 2008 15:19:53 +0000 (15:19 +0000)
INSTALL
ext/build.sh [new file with mode: 0755]
ext/extconf.rb
ext/rbbooh.c
lib/booh/booh-lib.rb

diff --git a/INSTALL b/INSTALL
index ebd874a..4f55943 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -6,7 +6,7 @@ This software requires for compiling:
 - ruby-gettext >= 0.8.0
 - ruby-gtk2 >= 0.12
 - devel of ruby-gnome2 (mkmf-gnome2.rb, rbgobject.h)
-- devel of libexif
+- devel of libexiv2
 
     Note: theoretically, gtk and ruby-gtk2 are not needed if
     you're gonna use only the backend script (the only lost
@@ -21,7 +21,6 @@ And for runtime:
 For runtime, not strictly needed but nice to have:
 
 - transcode and mencoder (not strictly needed if you won't manipulate any video)
-- exif (to be able to show all EXIF data of a picture)
 
 
         Compiling and Installing Quick Start
@@ -31,8 +30,7 @@ Type this as normal user:
  # ruby setup.rb config
  # ruby setup.rb setup
  # cd ext
- # ruby extconf.rb
- # make
+ # ./build.sh
 
 And type this as superuser:
 
diff --git a/ext/build.sh b/ext/build.sh
new file mode 100755 (executable)
index 0000000..dfe3b0f
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+ruby extconf.rb || exit 1
+#- we use libexiv2 which is a C++ library, this is dirty but I don't want
+#- to mess with extconf.rb and ruby mkmf
+perl -pi -e 's/CC = gcc/CC = c++/' Makefile
+make
+
index 09c9b51..785e552 100644 (file)
@@ -10,8 +10,8 @@ PKGConfig.have_package('gtk+-2.0') or exit 1
 have_func("gdk_pixbuf_set_option")
 have_header("gdk-pixbuf/gdk-pixbuf-io.h")
 
-#- directo libexif access for image orientation
-PKGConfig.have_package('libexif') or exit 1
+#- direct exiv2 access for some EXIF stuff
+PKGConfig.have_package('exiv2') or exit 1
 
 #- does it do something good, actually?
 setup_win32(PACKAGE_NAME)
index 746f9e9..2e59e92 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);
+}
 }
index cac7b01..0f4ca1d 100644 (file)
@@ -255,7 +255,7 @@ module Booh
     end
 
     def guess_rotate(filename)
-        #- identify is slow, try with libexif if available (4ms vs 35ms)
+        #- identify is slow, try with libexiv2 if available (4ms vs 35ms)
         if $no_libadds
             if $no_identify
                 return 0