workaround exif crash
[booh] / ext / rbbooh.cc
index f2dfca04d9a8fb2ca1f751f924d99a159cb7c49c..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,7 +99,7 @@ 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;
@@ -128,7 +133,7 @@ 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;
@@ -175,47 +180,42 @@ static VALUE modify_bg(VALUE self, VALUE state, VALUE color) {
         return self;
 }
 
-static int counter = 0;
-
 // internalize pixbuf loading for 30% more speedup
-static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE interruptable, VALUE area_prepared_signal_id) {
-        int interruptable_ = RTEST(interruptable);
+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));
         }
-        counter++;
+        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);
                 }
-                if (counter < 52) {
-                        // if the user scrolls too fast between thumbnails, there can be large amount of recursions,
-                        // and program may abort - probably on exhausted stack size; this figure is completely empiric
-                        while (gtk_events_pending()) {
-                                gtk_main_iteration();
-                        }
-                        if (interruptable_ && RTEST(rb_eval_string("$interrupt_loading"))) {
-                                // interrupted, case when the user clicked/keyboarded too quickly for this image to
-                                // display; we cancel this loading, but before we disconnect the area-prepared
-                                // signal handler, else the call to gdk_pixbuf_loader_get_pixbuf will take ages
-                                // (between 100 and 400 ms on my p4 for a large photo!)
-                                g_signal_handler_disconnect(loader, NUM2INT(area_prepared_signal_id));
-                                gdk_pixbuf_loader_close(loader, NULL);
-                                fclose(f);
-                                counter--;
-                                return Qfalse;
-                        }
+                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);
-        counter--;
-        return Qtrue;
+        return INT2NUM(0);
 }
 
 extern "C" {
@@ -234,7 +234,7 @@ Init_libadds()
     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, 3);
+    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);