[solang] Improved content-type guessing and Gdk::PixbufLoader selection



commit 10293221d0b5715b1c7842faf4535248995ea5e9
Author: Debarshi Ray <rishi gnu org>
Date:   Mon Dec 7 03:38:00 2009 +0200

    Improved content-type guessing and Gdk::PixbufLoader selection
    
    + ContentTypeRepo::get_content_type should pass some data from the
      beginning of the file to Gio::content_type_guess. Otherwise if a
      file has been renamed to have a weird extension it will lead to
      uncertainty.
    + ThumbbufMaker should explicitly chose a Gdk::PixbufLoader. This
      prevents things like trying to load a RAW using the TIFF loader
      instead of a RAW loader like the one provided by libopenraw.

 src/attribute/thumbnail.cpp      |    4 ++
 src/common/content-type-repo.cpp |   27 +++++++++++-
 src/common/thumbbuf-maker.cpp    |   92 +++++++++++++++++++++++++++++++++++---
 src/common/thumbbuf-maker.h      |    3 +
 4 files changed, 118 insertions(+), 8 deletions(-)
---
diff --git a/src/attribute/thumbnail.cpp b/src/attribute/thumbnail.cpp
index 223690f..1bd2ebe 100644
--- a/src/attribute/thumbnail.cpp
+++ b/src/attribute/thumbnail.cpp
@@ -255,6 +255,10 @@ Thumbnail::generate_using_gdkpixbuf(const PhotoPtr & photo,
                                  new_size_hint.get_y(),
                                  true);
     const PixbufPtr thumbnail = thumbbuf_maker(photo);
+    if (0 == thumbnail)
+    {
+        return;
+    }
 
     thumbnail->save( get_path(), "jpeg" );    
 
diff --git a/src/common/content-type-repo.cpp b/src/common/content-type-repo.cpp
index c7c52f6..e70f118 100644
--- a/src/common/content-type-repo.cpp
+++ b/src/common/content-type-repo.cpp
@@ -67,10 +67,35 @@ ContentTypeRepo::init() throw()
 Glib::ustring
 ContentTypeRepo::get_content_type(const std::string &filename ) const throw()
 {
+    DataInputStreamPtr fin;
+
+    if (true == Glib::file_test(filename, Glib::FILE_TEST_EXISTS))
+    {
+        const FilePtr file = Gio::File::create_for_path(filename);
+
+        try
+        {
+            fin = Gio::DataInputStream::create(file->read());
+        }
+        catch(const Gio::Error & e)
+        {
+            g_warning("%s", e.what().c_str());
+        }
+    }
+
+    const gint SNIFF_BUFFER_SIZE = 4096; // From gdk-pixbuf-io.c
+    guint8 buffer[SNIFF_BUFFER_SIZE];
+    gssize nread = 0;
+
+    if (0 != fin)
+    {
+        nread = fin->read(buffer, sizeof(buffer));
+    }
+
     bool uncertain = false;
     Glib::ustring contentType
         = Gio::content_type_guess(
-                filename, std::string(), uncertain );
+                filename, buffer, nread, uncertain );
 
     if( uncertain )
         return Glib::ustring();
diff --git a/src/common/thumbbuf-maker.cpp b/src/common/thumbbuf-maker.cpp
index a7c0fd5..6e9ed7b 100644
--- a/src/common/thumbbuf-maker.cpp
+++ b/src/common/thumbbuf-maker.cpp
@@ -20,6 +20,11 @@
 #include "config.h"
 #endif // HAVE_CONFIG_H
 
+#include <cstdio>
+
+#include <giomm.h>
+
+#include "content-type-repo.h"
 #include "photo.h"
 #include "thumbbuf-maker.h"
 #include "thumbnail.h"
@@ -48,6 +53,23 @@ ThumbbufMaker::~ThumbbufMaker() throw()
 {
 }
 
+PixbufLoaderPtr
+ThumbbufMaker::create_pixbuf_loader(const std::string & path) const
+                                    throw(Gdk::PixbufError)
+{
+    const ContentTypeRepoPtr content_type_repo
+                                 = ContentTypeRepo::instance();
+    const Glib::ustring content_type
+        = content_type_repo->get_content_type(path);
+
+    if (false == content_type_repo->is_gdk_supported(content_type))
+    {
+        throw Gdk::PixbufError(Gdk::PixbufError::UNKNOWN_TYPE, "");
+    }
+
+    return Gdk::PixbufLoader::create(content_type, true);
+}
+
 ThumbbufMaker &
 ThumbbufMaker::operator=(const ThumbbufMaker & source) throw()
 {
@@ -93,19 +115,67 @@ ThumbbufMaker::operator()(const PhotoPtr & photo) throw()
         }
     }
 
-    PixbufPtr pixbuf;
+    PixbufLoaderPtr pixbuf_loader;
     try
     {
-        pixbuf = Gdk::Pixbuf::create_from_file(path, width_, -1, true);
+        pixbuf_loader = create_pixbuf_loader(path);
     }
-    catch (const Glib::FileError & e)
+    catch(const Gdk::PixbufError & e)
     {
         g_warning("%s", e.what().c_str());
         return PixbufPtr(0);
     }
+
+    const FilePtr file = Gio::File::create_for_path(path);
+    DataInputStreamPtr fin;
+
+    try
+    {
+        fin = Gio::DataInputStream::create(file->read());
+    }
+    catch(const Gio::Error & e)
+    {
+        g_warning("%s", e.what().c_str());
+        return PixbufPtr(0);
+    }
+
+    gssize nread;
+    guint8 buffer[BUFSIZ];
+
+    while (0 < (nread = fin->read(buffer, sizeof(buffer))))
+    {
+        try
+        {
+            pixbuf_loader->write(buffer, nread);
+        }
+        catch (const Glib::FileError & e)
+        {
+            g_warning("%s", e.what().c_str());
+            break;
+        }
+        catch (const Gdk::PixbufError & e)
+        {
+            g_warning("%s", e.what().c_str());
+            break;
+        }
+    }
+
+    try
+    {
+        pixbuf_loader->close();
+    }
+    catch (const Glib::FileError & e)
+    {
+        g_warning("%s", e.what().c_str());
+    }
     catch (const Gdk::PixbufError & e)
     {
         g_warning("%s", e.what().c_str());
+    }
+
+    PixbufPtr pixbuf = pixbuf_loader->get_pixbuf();
+    if (0 == pixbuf)
+    {
         return PixbufPtr(0);
     }
 
@@ -115,16 +185,24 @@ ThumbbufMaker::operator()(const PhotoPtr & photo) throw()
                                 pixbuf->gobj()), false);
     }
 
-    const double height = static_cast<double>(pixbuf->get_height());
+    const gint height = pixbuf->get_height();
+    const gint width = pixbuf->get_width();
+    const gdouble aspect_ratio = static_cast<gdouble>(width)
+                                 / static_cast<gdouble>(height);
 
-    if (height_ < height)
+    if (height > width)
     {
-        const double width = static_cast<double>(pixbuf->get_width());
-        const double aspect_ratio = width / height;
         pixbuf = pixbuf->scale_simple(
                      static_cast<gint>(height_ * aspect_ratio),
                      height_, Gdk::INTERP_BILINEAR);
     }
+    else
+    {
+        pixbuf = pixbuf->scale_simple(
+                     width_,
+                     static_cast<gint>(width_ / aspect_ratio),
+                     Gdk::INTERP_BILINEAR);
+    }
 
     return pixbuf;
 }
diff --git a/src/common/thumbbuf-maker.h b/src/common/thumbbuf-maker.h
index ed454d8..c8df27f 100644
--- a/src/common/thumbbuf-maker.h
+++ b/src/common/thumbbuf-maker.h
@@ -46,6 +46,9 @@ class ThumbbufMaker :
         operator()(const PhotoPtr & photo) throw();
 
     protected:
+        PixbufLoaderPtr
+        create_pixbuf_loader(const std::string & path) const
+                             throw(Gdk::PixbufError);
 
     private:
         bool rotate_;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]