workaround exif crash
[booh] / ext / rbbooh.cc
index b32bfdb85eb64e7193082ac7b6f259e9f27cc8db..e276442e7c637e9e8ee2f2e8e8bb394e4f5a6356 100644 (file)
@@ -9,7 +9,7 @@
  * called Boo, so this one will be it "Booh". Or whatever.
  *
  *
- * Copyright (c) 2005-2008 Guillaume Cottenceau
+ * Copyright (c) 2005-2010 Guillaume Cottenceau
  *
  * This software may be freely redistributed under the terms of the GNU
  * public license version 2.
@@ -24,6 +24,7 @@
 
 #include <exiv2/image.hpp>
 #include <exiv2/exif.hpp>
+#include <exiv2/error.hpp>
 
 #define GDK_PIXBUF_ENABLE_BACKEND
 #include <gtk/gtk.h>
@@ -34,6 +35,8 @@
 static VALUE whitebalance(VALUE self, VALUE level) {
         double red_filter[256], blue_filter[256];
         int i, x, y;
+        int maxx = gdk_pixbuf_get_width(_SELF(self));
+        int maxy = gdk_pixbuf_get_height(_SELF(self));
         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
 
@@ -47,9 +50,9 @@ static VALUE whitebalance(VALUE self, VALUE level) {
                 blue_filter[i] = pow(((double)i)/255, factor) * 255;
         }
     
-        for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
+        for (y = 0; y < maxy; y++) {
                 guchar* pixline = &(pixels[rowstride*y]);
-                for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
+                for (x = 0; x < maxx; x++) {
                         pixline[x*3]   = (guchar) red_filter[pixline[x*3]];
                         pixline[x*3+2] = (guchar) blue_filter[pixline[x*3+2]];
                 }
@@ -61,6 +64,8 @@ static VALUE whitebalance(VALUE self, VALUE level) {
 static VALUE gammacorrect(VALUE self, VALUE level) {
         double filter[256];
         int i, x, y;
+        int maxx = gdk_pixbuf_get_width(_SELF(self));
+        int maxy = gdk_pixbuf_get_height(_SELF(self));
         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
 
@@ -73,9 +78,9 @@ static VALUE gammacorrect(VALUE self, VALUE level) {
                 filter[i] = pow(((double)i)/255, factor) * 255;
         }
     
-        for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
+        for (y = 0; y < maxy; y++) {
                 guchar* pixline = &(pixels[rowstride*y]);
-                for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
+                for (x = 0; x < maxx; x++) {
                         pixline[x*3]   = (guchar) filter[pixline[x*3]];
                         pixline[x*3+1] = (guchar) filter[pixline[x*3+1]];
                         pixline[x*3+2] = (guchar) filter[pixline[x*3+2]];
@@ -94,12 +99,13 @@ static VALUE exif_orientation(VALUE module, VALUE filename) {
                         return Qnil;
                 }
                 Exiv2::ExifData::const_iterator i = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"));
-                if (i != exifData.end()) {
+                if (i != exifData.end() && i->count() > 0) {
                         return INT2NUM(i->value().toLong());
                 }
                 return Qnil;
         } catch (Exiv2::AnyError& e) {
-                std::cout << "Caught Exiv2 exception: " << e << "\n";
+                // actually, I don't care about exceptions because I will try non JPG images
+                // std::cerr << "Caught Exiv2 exception: " << e << "\n";
                 return Qnil;
         }
 }
@@ -112,7 +118,8 @@ static VALUE exif_set_orientation(VALUE module, VALUE filename, VALUE val) {
                 exifData["Exif.Image.Orientation"] = uint16_t(NUM2INT(val));
                 image->writeMetadata();
         } catch (Exiv2::AnyError& e) {
-                std::cout << "Caught Exiv2 exception: " << e << "\n";
+                // actually, I don't care about exceptions because I will try non JPG images
+                // std::cout << "Caught Exiv2 exception: " << e << "\n";
         }
         return Qnil;
 }
@@ -126,12 +133,13 @@ static VALUE exif_datetimeoriginal(VALUE module, VALUE filename) {
                         return Qnil;
                 }
                 Exiv2::ExifData::const_iterator i = exifData.findKey(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"));
-                if (i != exifData.end()) {
+                if (i != exifData.end() && i->count() > 0) {
                         return rb_str_new2(i->value().toString().c_str());
                 }
                 return Qnil;
         } catch (Exiv2::AnyError& e) {
-                std::cout << "Caught Exiv2 exception: " << e << "\n";
+                // actually, I don't care about exceptions because I will try non JPG images
+                // std::cout << "Caught Exiv2 exception: " << e << "\n";
                 return Qnil;
         }
 }
@@ -172,6 +180,44 @@ static VALUE modify_bg(VALUE self, VALUE state, VALUE color) {
         return self;
 }
 
+// internalize pixbuf loading for 30% more speedup
+static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE offset) {
+        char buf[65536];
+        size_t amount;
+        size_t off = NUM2INT(offset);
+        GdkPixbufLoader* loader = GDK_PIXBUF_LOADER(RVAL2GOBJ(self));
+        GError* error = NULL;
+        FILE* f = fopen(RVAL2CSTR(path), "r");
+        if (!f) {
+                gdk_pixbuf_loader_close(loader, NULL);
+                rb_raise(rb_eRuntimeError, "Unable to open file %s for reading", RVAL2CSTR(path));
+        }
+        if (off > 0) {
+                if (fseek(f, off, SEEK_SET) != 0) {
+                        rb_raise(rb_eRuntimeError, "Unable to seek file %s", RVAL2CSTR(path));
+                        fclose(f);
+                        return 0;
+                }
+        }
+        while ((amount = fread(buf, 1, 65536, f)) > 0) {
+                if (!gdk_pixbuf_loader_write(loader, (const guchar*) buf, amount, &error)) {
+                        gdk_pixbuf_loader_close(loader, NULL);
+                        fclose(f);
+                        RAISE_GERROR(error);
+                }
+                off += amount;
+                if (gtk_events_pending() && !feof(f)) {
+                        // interrupted, case when the user clicked/keyboarded too quickly for this image to
+                        // display; we temporarily interrupt this loading
+                        fclose(f);
+                        return INT2NUM(off);
+                }
+        }
+        gdk_pixbuf_loader_close(loader, NULL);
+        fclose(f);
+        return INT2NUM(0);
+}
+
 extern "C" {
 void 
 Init_libadds()
@@ -187,6 +233,9 @@ Init_libadds()
     cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GTK_TYPE_WIDGET, Qnil);
     rb_define_method(cinfo->klass, "modify_bg", (VALUE (*)(...)) modify_bg, 2);
 
+    cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_PIXBUF_LOADER, Qnil);
+    rb_define_method(cinfo->klass, "load_not_freezing_ui", (VALUE (*)(...)) load_not_freezing_ui, 2);
+
     VALUE exif = rb_define_module("Exif");
     rb_define_module_function(exif, "orientation", (VALUE (*)(...)) exif_orientation, 1);
     rb_define_module_function(exif, "set_orientation", (VALUE (*)(...)) exif_set_orientation, 2);