[Xfce4-commits] <tumbler:master> Add a fast JPEG thumbnailer with EXIF thumbnail support.

Jannis Pohlmann noreply at xfce.org
Tue Dec 8 23:24:05 CET 2009


Updating branch refs/heads/master
         to 14a1df9c282c0a3979bf85c0481c07d48e97cca7 (commit)
       from ee8b152274adaa5c2b0e89dba1bc0f70588eb402 (commit)

commit 14a1df9c282c0a3979bf85c0481c07d48e97cca7
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Tue Dec 8 23:20:27 2009 +0100

    Add a fast JPEG thumbnailer with EXIF thumbnail support.
    
    This basically is a copy of the JPEG thumbnailer Benedikt Meurer wrote
    for ThunarVFS. It might be a little rough around the edges but I
    verified that it works as it did in ThunarVFS. I'm aware of a few bugs
    related to rotation and stuff though that were reported against
    ThunarVFS.

 acinclude.m4                                       |   43 +
 configure.ac                                       |   27 +-
 plugins/Makefile.am                                |    1 +
 .../Makefile.am                                    |   28 +-
 .../jpeg-thumbnailer-plugin.c}                     |   10 +-
 .../jpeg-thumbnailer-provider.c}                   |   61 +-
 .../jpeg-thumbnailer/jpeg-thumbnailer-provider.h   |   43 +
 plugins/jpeg-thumbnailer/jpeg-thumbnailer.c        |  830 ++++++++++++++++++++
 plugins/jpeg-thumbnailer/jpeg-thumbnailer.h        |   43 +
 po/POTFILES.in                                     |    3 +
 po/ast.po                                          |   17 +-
 po/ca.po                                           |   17 +-
 po/da.po                                           |   17 +-
 po/en_GB.po                                        |   17 +-
 po/fr.po                                           |   17 +-
 po/gl.po                                           |   17 +-
 po/ja.po                                           |   17 +-
 po/lv.po                                           |   17 +-
 po/pt.po                                           |   17 +-
 po/tr.po                                           |   17 +-
 po/tumbler.pot                                     |   17 +-
 po/zh_CN.po                                        |   17 +-
 22 files changed, 1183 insertions(+), 110 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index ecb740a..568b4d7 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -79,6 +79,49 @@ AC_MSG_RESULT([$ac_tumbler_font_thumbnailer])
 
 
 
+dnl TUMBLER_JPEG_THUMBNAILER()
+dnl
+dnl Check whether to build and install the JPEG thumbnailer plugin with 
+dnl EXIF support.
+dnl
+AC_DEFUN([TUMBLER_JPEG_THUMBNAILER],
+[
+AC_ARG_ENABLE([jpeg-thumbnailer], [AC_HELP_STRING([--disable-jpeg-thumbnailer], [Don't build the JPEG thumbnailer plugin with EXIF support])],
+  [ac_tumbler_jpeg_thumbnailer=$enableval], [ac_tumbler_jpeg_thumbnailer=yes])
+if test x"$ac_tumbler_jpeg_thumbnailer" = x"yes"; then
+  dnl Check for gdk-pixbuf 
+  PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.14], 
+  [
+    dnl Check for libjpeg
+    LIBJPEG_LIBS=""
+    LIBJPEG_CFLAGS=""
+    AC_CHECK_LIB([jpeg], [jpeg_start_decompress],
+    [
+      AC_CHECK_HEADER([jpeglib.h],
+      [
+        LIBJPEG_LIBS="-ljpeg -lm"
+      ],
+      [
+        dnl We can only build the JPEG thumbnailer if the JPEG headers are available
+        ac_tumbler_jpeg_thumbnailer=no
+      ])
+    ],
+    [
+      dnl We can only build the JPEG thumbnailer if libjpeg is available
+      ac_tumbler_jpeg_thumbnailer=no
+    ])
+    AC_SUBST([LIBJPEG_CFLAGS])
+    AC_SUBST([LIBJPEG_LIBS])
+  ], [ac_tumbler_jpeg_thumbnailer=no])
+fi
+
+AC_MSG_CHECKING([whether to build the JPEG thumbnailer plugin with EXIF support])
+AM_CONDITIONAL([TUMBLER_JPEG_THUMBNAILER], [test x"$ac_tumbler_jpeg_thumbnailer" = x"yes"])
+AC_MSG_RESULT([$ac_tumbler_jpeg_thumbnailer])
+])
+
+
+
 dnl TUMBLER_XDG_CACHE()
 dnl
 dnl Check whether to build and install the freedesktop.org cache plugin.
diff --git a/configure.ac b/configure.ac
index 0ab0a30..1704bad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,7 +106,9 @@ dnl ***************************************
 dnl *** Check for standard header files ***
 dnl ***************************************
 AC_HEADER_STDC()
-AC_CHECK_HEADERS([unistd.h sched.h linux/sched.h syscall.h sys/types.h sys/stat.h])
+AC_CHECK_HEADERS([fcntl.h linux/sched.h memory.h sched.h setjmp.h stdio.h \
+                  stdlib.h string.h syscall.h sys/mman.h sys/types.h \
+                  sys/stat.h unistd.h])
 
 dnl ************************************
 dnl *** Check for standard functions ***
@@ -148,8 +150,9 @@ PKG_CHECK_MODULES([DBUS_GLIB], [dbus-glib-1 >= 0.72])
 dnl *************************
 dnl *** Check for plugins ***
 dnl *************************
-TUMBLER_PIXBUF_THUMBNAILER()
 TUMBLER_FONT_THUMBNAILER()
+TUMBLER_JPEG_THUMBNAILER()
+TUMBLER_PIXBUF_THUMBNAILER()
 TUMBLER_XDG_CACHE()
 
 dnl ***********************************
@@ -176,6 +179,7 @@ docs/reference/tumbler/Makefile
 docs/reference/tumbler/version.xml
 plugins/Makefile
 plugins/font-thumbnailer/Makefile
+plugins/jpeg-thumbnailer/Makefile
 plugins/pixbuf-thumbnailer/Makefile
 plugins/xdg-cache/Makefile
 po/Makefile.in
@@ -191,23 +195,28 @@ dnl ***************************
 echo
 echo "Build Configuration:"
 echo
-echo "  * Debug:                            $enable_debug"
+echo "  * Debug:                                     $enable_debug"
 echo
 echo "Plugins:"
 echo
 if test x"$ac_tumbler_pixbuf_thumbnailer" = x"yes"; then
-echo "  * GdkPixbuf thumbnailer plugin:     yes"
+echo "  * GdkPixbuf thumbnailer plugin:              yes"
 else
-echo "  * GdkPixbuf thumbnailer plugin:     no"
+echo "  * GdkPixbuf thumbnailer plugin:              no"
 fi
 if test x"$ac_tumbler_font_thumbnailer" = x"yes"; then
-echo "  * FreeType font thumbnailer plugin: yes"
+echo "  * FreeType font thumbnailer plugin:          yes"
+else
+echo "  * FreeType font thumbnailer plugin:          no"
+fi
+if test x"$ac_tumbler_jpeg_thumbnailer" = x"yes"; then
+echo "  * JPEG thumbnailer plugin with EXIF support: yes"
 else
-echo "  * FreeType font thumbnailer plugin: no"
+echo "  * JPEG thumbnailer plugin with EXIF support: no"
 fi
 if test x"$ac_tumbler_xdg_cache" = x"yes"; then
-echo "  * Freedesktop.org cache plugin:     yes"
+echo "  * Freedesktop.org cache plugin:              yes"
 else
-echo "  * Freedesktop.org cache plugin:     no"
+echo "  * Freedesktop.org cache plugin:              no"
 fi
 echo
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 047ba61..983884b 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -19,5 +19,6 @@
 
 SUBDIRS =								\
 	font-thumbnailer						\
+	jpeg-thumbnailer						\
 	pixbuf-thumbnailer						\
 	xdg-cache
diff --git a/plugins/font-thumbnailer/Makefile.am b/plugins/jpeg-thumbnailer/Makefile.am
similarity index 73%
copy from plugins/font-thumbnailer/Makefile.am
copy to plugins/jpeg-thumbnailer/Makefile.am
index a56c0ea..d4d88a5 100644
--- a/plugins/font-thumbnailer/Makefile.am
+++ b/plugins/jpeg-thumbnailer/Makefile.am
@@ -17,42 +17,42 @@
 # Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
-if TUMBLER_FONT_THUMBNAILER
+if TUMBLER_JPEG_THUMBNAILER
 
 tumbler_plugindir = $(libdir)/tumbler-$(TUMBLER_VERSION_API)/plugins
 tumbler_plugin_LTLIBRARIES =						\
-	tumbler-font-thumbnailer.la
+	tumbler-jpeg-thumbnailer.la
 
-tumbler_font_thumbnailer_la_SOURCES =					\
-	font-thumbnailer-plugin.c					\
-	font-thumbnailer-provider.c					\
-	font-thumbnailer-provider.h					\
-	font-thumbnailer.c						\
-	font-thumbnailer.h
+tumbler_jpeg_thumbnailer_la_SOURCES =					\
+	jpeg-thumbnailer-plugin.c					\
+	jpeg-thumbnailer-provider.c					\
+	jpeg-thumbnailer-provider.h					\
+	jpeg-thumbnailer.c						\
+	jpeg-thumbnailer.h
 
-tumbler_font_thumbnailer_la_CFLAGS =					\
+tumbler_jpeg_thumbnailer_la_CFLAGS =					\
 	-I$(top_builddir)						\
 	-I$(top_builddir)/plugins					\
 	-I$(top_srcdir)							\
 	-I$(top_srcdir)/plugins						\
-	-DG_LOG_DOMAIN=\"tumbler-font-thumbnailer\"			\
+	-DG_LOG_DOMAIN=\"tumbler-jpeg-thumbnailer\"			\
 	-DPACKAGE_LOCALE_DIR=\"$(localedir)\"				\
 	$(GDK_PIXBUF_CFLAGS)						\
 	$(GIO_CFLAGS)							\
 	$(GLIB_CFLAGS)							\
-	$(FREETYPE_CFLAGS)						\
+	$(LIBJPEG_CFLAGS)						\
 	$(PLATFORM_CPPFLAGS)
 
-tumbler_font_thumbnailer_la_LDFLAGS =					\
+tumbler_jpeg_thumbnailer_la_LDFLAGS =					\
 	-avoid-version							\
 	-export-dynamic							\
 	-module								\
 	$(PLATFORM_LDFLAGS)
 
-tumbler_font_thumbnailer_la_LIBADD =					\
+tumbler_jpeg_thumbnailer_la_LIBADD =					\
 	$(GDK_PIXBUF_LIBS)						\
 	$(GIO_LIBS)							\
 	$(GLIB_LIBS)							\
-	$(FREETYPE_LIBS)
+	$(LIBJPEG_LIBS)
 
 endif
diff --git a/plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c
similarity index 89%
copy from plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c
copy to plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c
index 0cf1fc3..3665291 100644
--- a/plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c
+++ b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c
@@ -28,8 +28,8 @@
 
 #include <tumbler/tumbler.h>
 
-#include <pixbuf-thumbnailer/pixbuf-thumbnailer-provider.h>
-#include <pixbuf-thumbnailer/pixbuf-thumbnailer.h>
+#include <jpeg-thumbnailer/jpeg-thumbnailer-provider.h>
+#include <jpeg-thumbnailer/jpeg-thumbnailer.h>
 
 
 
@@ -63,11 +63,11 @@ tumbler_plugin_initialize (TumblerProviderPlugin *plugin)
 #endif
 
   /* register the types provided by this plugin */
-  pixbuf_thumbnailer_register (plugin);
-  pixbuf_thumbnailer_provider_register (plugin);
+  jpeg_thumbnailer_register (plugin);
+  jpeg_thumbnailer_provider_register (plugin);
 
   /* set up the plugin provider type list */
-  type_list[0] = TYPE_PIXBUF_THUMBNAILER_PROVIDER;
+  type_list[0] = TYPE_JPEG_THUMBNAILER_PROVIDER;
 }
 
 
diff --git a/plugins/font-thumbnailer/font-thumbnailer-provider.c b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.c
similarity index 59%
copy from plugins/font-thumbnailer/font-thumbnailer-provider.c
copy to plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.c
index 65158a5..4e01498 100644
--- a/plugins/font-thumbnailer/font-thumbnailer-provider.c
+++ b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.c
@@ -29,47 +29,47 @@
 
 #include <tumbler/tumbler.h>
 
-#include <font-thumbnailer/font-thumbnailer-provider.h>
-#include <font-thumbnailer/font-thumbnailer.h>
+#include <jpeg-thumbnailer/jpeg-thumbnailer-provider.h>
+#include <jpeg-thumbnailer/jpeg-thumbnailer.h>
 
 
 
-static void   font_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface);
-static GList *font_thumbnailer_provider_get_thumbnailers          (TumblerThumbnailerProvider      *provider);
+static void   jpeg_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface);
+static GList *jpeg_thumbnailer_provider_get_thumbnailers          (TumblerThumbnailerProvider      *provider);
 
 
 
-struct _FontThumbnailerProviderClass
+struct _JPEGThumbnailerProviderClass
 {
   GObjectClass __parent__;
 };
 
-struct _FontThumbnailerProvider
+struct _JPEGThumbnailerProvider
 {
   GObject __parent__;
 };
 
 
 
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (FontThumbnailerProvider,
-                                font_thumbnailer_provider,
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (JPEGThumbnailerProvider,
+                                jpeg_thumbnailer_provider,
                                 G_TYPE_OBJECT,
                                 0,
                                 TUMBLER_ADD_INTERFACE (TUMBLER_TYPE_THUMBNAILER_PROVIDER,
-                                                       font_thumbnailer_provider_thumbnailer_provider_init));
+                                                       jpeg_thumbnailer_provider_thumbnailer_provider_init));
 
 
 
 void
-font_thumbnailer_provider_register (TumblerProviderPlugin *plugin)
+jpeg_thumbnailer_provider_register (TumblerProviderPlugin *plugin)
 {
-  font_thumbnailer_provider_register_type (G_TYPE_MODULE (plugin));
+  jpeg_thumbnailer_provider_register_type (G_TYPE_MODULE (plugin));
 }
 
 
 
 static void
-font_thumbnailer_provider_class_init (FontThumbnailerProviderClass *klass)
+jpeg_thumbnailer_provider_class_init (JPEGThumbnailerProviderClass *klass)
 {
   GObjectClass *gobject_class;
 
@@ -79,55 +79,48 @@ font_thumbnailer_provider_class_init (FontThumbnailerProviderClass *klass)
 
 
 static void
-font_thumbnailer_provider_class_finalize (FontThumbnailerProviderClass *klass)
+jpeg_thumbnailer_provider_class_finalize (JPEGThumbnailerProviderClass *klass)
 {
 }
 
 
 
 static void
-font_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface)
+jpeg_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface)
 {
-  iface->get_thumbnailers = font_thumbnailer_provider_get_thumbnailers;
+  iface->get_thumbnailers = jpeg_thumbnailer_provider_get_thumbnailers;
 }
 
 
 
 static void
-font_thumbnailer_provider_init (FontThumbnailerProvider *provider)
+jpeg_thumbnailer_provider_init (JPEGThumbnailerProvider *provider)
 {
 }
 
 
 
 static GList *
-font_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider)
+jpeg_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider)
 {
-  static const gchar *mime_types[] = 
-  { 
-    "application/x-font-otf",
-    "application/x-font-pcf",
-    "application/x-font-ttf",
-    "application/x-font-type1",
-    NULL,
-  };
-  FontThumbnailer    *thumbnailer;
-  GList              *thumbnailers = NULL;
-  GStrv               uri_schemes;
-
-  /* determine the URI schemes supported by GIO */
+  JPEGThumbnailer *thumbnailer;
+  const gchar     *mime_types[] = { "image/jpeg", NULL };
+  GList           *thumbnailers = NULL;
+  GStrv            uri_schemes;
+
+  /* determine which URI schemes are supported by GIO */
   uri_schemes = tumbler_util_get_supported_uri_schemes ();
 
   /* create the pixbuf thumbnailer */
-  thumbnailer = g_object_new (TYPE_FONT_THUMBNAILER, 
+  thumbnailer = g_object_new (TYPE_JPEG_THUMBNAILER, 
                               "uri-schemes", uri_schemes, "mime-types", mime_types, 
                               NULL);
 
+  /* free URI schemes and MIME types */
+  g_strfreev (uri_schemes);
+
   /* add the thumbnailer to the list */
   thumbnailers = g_list_append (thumbnailers, thumbnailer);
 
-  /* free URI schemes */
-  g_strfreev (uri_schemes);
-
   return thumbnailers;
 }
diff --git a/plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.h b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.h
new file mode 100644
index 0000000..829800d
--- /dev/null
+++ b/plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.h
@@ -0,0 +1,43 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General 
+ * Public License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __JPEG_THUMBNAILER_PROVIDER_H__
+#define __JPEG_THUMBNAILER_PROVIDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_JPEG_THUMBNAILER_PROVIDER            (jpeg_thumbnailer_provider_get_type ())
+#define JPEG_THUMBNAILER_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_JPEG_THUMBNAILER_PROVIDER, JPEGThumbnailerProvider))
+#define JPEG_THUMBNAILER_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_JPEG_THUMBNAILER_PROVIDER, JPEGThumbnailerProviderClass))
+#define IS_JPEG_THUMBNAILER_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_JPEG_THUMBNAILER_PROVIDER))
+#define IS_JPEG_THUMBNAILER_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_JPEG_THUMBNAILER_PROVIDER)
+#define JPEG_THUMBNAILER_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_JPEG_THUMBNAILER_PROVIDER, JPEGThumbnailerProviderClass))
+
+typedef struct _JPEGThumbnailerProviderClass JPEGThumbnailerProviderClass;
+typedef struct _JPEGThumbnailerProvider      JPEGThumbnailerProvider;
+
+GType jpeg_thumbnailer_provider_get_type (void) G_GNUC_CONST;
+void  jpeg_thumbnailer_provider_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__JPEG_THUMBNAILER_PROVIDER_H__ */
diff --git a/plugins/jpeg-thumbnailer/jpeg-thumbnailer.c b/plugins/jpeg-thumbnailer/jpeg-thumbnailer.c
new file mode 100644
index 0000000..ddbc172
--- /dev/null
+++ b/plugins/jpeg-thumbnailer/jpeg-thumbnailer.c
@@ -0,0 +1,830 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General 
+ * Public License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Based on code written by Alexander Larsson <alexl at redhat.com>
+ * for libgnomeui.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <math.h>
+
+#include <jpeglib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <tumbler/tumbler.h>
+
+#include <jpeg-thumbnailer/jpeg-thumbnailer.h>
+
+
+
+static void jpeg_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+                                     GCancellable               *cancellable,
+                                     TumblerFileInfo            *info);
+
+
+
+struct _JPEGThumbnailerClass
+{
+  TumblerAbstractThumbnailerClass __parent__;
+};
+
+struct _JPEGThumbnailer
+{
+  TumblerAbstractThumbnailer __parent__;
+};
+
+
+
+G_DEFINE_DYNAMIC_TYPE (JPEGThumbnailer, 
+                       jpeg_thumbnailer,
+                       TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
+
+
+
+void
+jpeg_thumbnailer_register (TumblerProviderPlugin *plugin)
+{
+  jpeg_thumbnailer_register_type (G_TYPE_MODULE (plugin));
+}
+
+
+
+static void
+jpeg_thumbnailer_class_init (JPEGThumbnailerClass *klass)
+{
+  TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
+
+  abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
+  abstractthumbnailer_class->create = jpeg_thumbnailer_create;
+}
+
+
+
+static void
+jpeg_thumbnailer_class_finalize (JPEGThumbnailerClass *klass)
+{
+}
+
+
+
+static void
+jpeg_thumbnailer_init (JPEGThumbnailer *thumbnailer)
+{
+}
+
+
+
+static void
+tvtj_noop (void)
+{
+}
+
+
+
+typedef struct
+{
+  struct jpeg_error_mgr mgr;
+  jmp_buf               setjmp_buffer;
+} TvtjErrorHandler;
+
+
+
+static void
+fatal_error_handler (j_common_ptr cinfo)
+{
+  TvtjErrorHandler *handler = (TvtjErrorHandler *) cinfo->err;
+  longjmp (handler->setjmp_buffer, 1);
+}
+
+
+
+static gboolean
+tvtj_fill_input_buffer (j_decompress_ptr cinfo)
+{
+  struct jpeg_source_mgr *source = cinfo->src;
+
+  /* return a fake EOI marker so we will eventually terminate */
+  if (G_LIKELY (source->bytes_in_buffer == 0))
+    {
+      static const JOCTET FAKE_EOI[2] =
+      {
+        (JOCTET) 0xff,
+        (JOCTET) JPEG_EOI,
+      };
+
+      source->next_input_byte = FAKE_EOI;
+      source->bytes_in_buffer = G_N_ELEMENTS (FAKE_EOI);
+    }
+
+  return TRUE;
+}
+
+
+
+static void
+tvtj_skip_input_data (j_decompress_ptr cinfo,
+                      glong            num_bytes)
+{
+  struct jpeg_source_mgr *source = cinfo->src;
+
+  if (G_LIKELY (num_bytes > 0))
+    {
+      num_bytes = MIN (num_bytes, (glong) source->bytes_in_buffer);
+
+      source->next_input_byte += num_bytes;
+      source->bytes_in_buffer -= num_bytes;
+    }
+}
+
+
+
+static inline gint
+tvtj_denom (gint width,
+            gint height,
+            gint size)
+{
+  if (width > size * 8 && height > size * 8)
+    return 8;
+  else if (width > size * 4 && height > size * 4)
+    return 4;
+  else if (width > size * 2 && height > size * 2)
+    return 2;
+  else
+    return 1;
+}
+
+
+
+static inline void
+tvtj_convert_cmyk_to_rgb (j_decompress_ptr cinfo,
+                          guchar          *line)
+{
+  guchar *p;
+  gint    c, k, m, n, y;
+
+  g_return_if_fail (cinfo != NULL);
+  g_return_if_fail (cinfo->output_components == 4);
+  g_return_if_fail (cinfo->out_color_space == JCS_CMYK);
+
+  for (n = cinfo->output_width, p = line; n > 0; --n, p += 4)
+    {
+      c = p[0];
+      m = p[1];
+      y = p[2];
+      k = p[3];
+
+      if (cinfo->saw_Adobe_marker)
+        {
+          p[0] = k * c / 255;
+          p[1] = k * m / 255;
+          p[2] = k * y / 255;
+        }
+      else
+        {
+          p[0] = (255 - k) * (255 - c) / 255;
+          p[1] = (255 - k) * (255 - m) / 255;
+          p[2] = (255 - k) * (255 - y) / 255;
+        }
+
+      p[3] = 255;
+    }
+}
+
+
+
+static GdkPixbuf*
+tvtj_jpeg_load (const JOCTET *content,
+                gsize         length,
+                gint          size)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_source_mgr        source;
+  TvtjErrorHandler              handler;
+  guchar                       *lines[1];
+  guchar                       *buffer = NULL;
+  guchar                       *pixels = NULL;
+  guchar                       *p;
+  gint                          out_num_components;
+  guint                         n;
+
+  /* setup JPEG error handling */
+  cinfo.err = jpeg_std_error (&handler.mgr);
+  handler.mgr.error_exit = fatal_error_handler;
+  handler.mgr.output_message = (gpointer) tvtj_noop;
+  if (setjmp (handler.setjmp_buffer))
+    goto error;
+
+  /* setup the source */
+  source.bytes_in_buffer = length;
+  source.next_input_byte = content;
+  source.init_source = (gpointer) tvtj_noop;
+  source.fill_input_buffer = tvtj_fill_input_buffer;
+  source.skip_input_data = tvtj_skip_input_data;
+  source.resync_to_restart = jpeg_resync_to_restart;
+  source.term_source = (gpointer) tvtj_noop;
+
+  /* setup the JPEG decompress struct */
+  jpeg_create_decompress (&cinfo);
+  cinfo.src = &source;
+
+  /* read the JPEG header from the file */
+  jpeg_read_header (&cinfo, TRUE);
+
+  /* configure the JPEG decompress struct */
+  cinfo.scale_num = 1;
+  cinfo.scale_denom = tvtj_denom (cinfo.image_width, cinfo.image_height, size);
+  cinfo.dct_method = JDCT_FASTEST;
+  cinfo.do_fancy_upsampling = FALSE;
+
+  /* calculate the output dimensions */
+  jpeg_calc_output_dimensions (&cinfo);
+
+  /* verify the JPEG color space */
+  if (cinfo.out_color_space != JCS_GRAYSCALE
+      && cinfo.out_color_space != JCS_CMYK
+      && cinfo.out_color_space != JCS_RGB)
+    {
+      /* we don't support this color space */
+      goto error;
+    }
+
+  /* start the decompression */
+  jpeg_start_decompress (&cinfo);
+
+  /* allocate the pixel buffer and extra space for grayscale data */
+  if (G_LIKELY (cinfo.num_components != 1))
+    {
+      pixels = g_malloc (cinfo.output_width * cinfo.output_height * cinfo.num_components);
+      out_num_components = cinfo.num_components;
+      lines[0] = pixels;
+    }
+  else
+    {
+      pixels = g_malloc (cinfo.output_width * cinfo.output_height * 3);
+      buffer = g_malloc (cinfo.output_width);
+      out_num_components = 3;
+      lines[0] = buffer;
+    }
+
+  /* process the JPEG data */
+  for (p = pixels; cinfo.output_scanline < cinfo.output_height; )
+    {
+      jpeg_read_scanlines (&cinfo, lines, 1);
+
+      /* convert the data to RGB */
+      if (cinfo.num_components == 1)
+        {
+          for (n = 0; n < cinfo.output_width; ++n)
+            {
+              p[n * 3 + 0] = buffer[n];
+              p[n * 3 + 1] = buffer[n];
+              p[n * 3 + 2] = buffer[n];
+            }
+          p += cinfo.output_width * 3;
+        }
+      else
+        {
+          if (cinfo.out_color_space == JCS_CMYK)
+            tvtj_convert_cmyk_to_rgb (&cinfo, lines[0]);
+          lines[0] += cinfo.output_width * cinfo.num_components;
+        }
+    }
+
+  /* release the grayscale buffer */
+  g_free (buffer);
+  buffer = NULL;
+
+  /* finish the JPEG decompression */
+  jpeg_finish_decompress (&cinfo);
+  jpeg_destroy_decompress (&cinfo);
+
+  /* generate a pixbuf for the pixel data */
+  return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB,
+                                   (cinfo.out_color_components == 4), 8,
+                                   cinfo.output_width, cinfo.output_height,
+                                   cinfo.output_width * out_num_components,
+                                   (GdkPixbufDestroyNotify) g_free, NULL);
+
+error:
+  jpeg_destroy_decompress (&cinfo);
+  g_free (buffer);
+  g_free (pixels);
+  return NULL;
+}
+
+
+
+typedef struct
+{
+  const guchar *data_ptr;
+  guint         data_len;
+
+  guint         thumb_compression;
+  union
+  {
+    struct /* thumbnail JPEG */
+    {
+      guint     length;
+      guint     offset;
+    } thumb_jpeg;
+    struct /* thumbnail TIFF */
+    {
+      guint     length;
+      guint     offset;
+      guint     interp;
+      guint     height;
+      guint     width;
+    } thumb_tiff;
+  } thumb;
+
+  gboolean      big_endian;
+} TvtjExif;
+
+
+
+static guint
+tvtj_exif_get_ushort (const TvtjExif *exif,
+                      const guchar   *data)
+{
+  if (G_UNLIKELY (exif->big_endian))
+    return ((data[0] << 8) | data[1]);
+  else
+    return ((data[1] << 8) | data[0]);
+}
+
+
+
+static guint
+tvtj_exif_get_ulong (const TvtjExif *exif,
+                     const guchar   *data)
+{
+  if (G_UNLIKELY (exif->big_endian))
+    return ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
+  else
+    return ((data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]);
+}
+
+
+
+static void
+tvtj_exif_parse_ifd (TvtjExif     *exif,
+                     const guchar *ifd_ptr,
+                     guint         ifd_len,
+                     GSList       *ifd_previous_list)
+{
+  const guchar *subifd_ptr;
+  GSList        ifd_list;
+  guint         subifd_off;
+  guint         value;
+  guint         tag;
+  guint         n;
+
+  /* make sure we have a valid IFD here */
+  if (G_UNLIKELY (ifd_len < 2))
+    return;
+
+  /* make sure we don't recurse into IFDs that are already being processed */
+  if (g_slist_find (ifd_previous_list, ifd_ptr) != NULL)
+    return;
+  ifd_list.next = ifd_previous_list;
+  ifd_list.data = (gpointer) ifd_ptr;
+
+  /* determine the number of entries */
+  n = tvtj_exif_get_ushort (exif, ifd_ptr);
+
+  /* advance to the IFD content */
+  ifd_ptr += 2;
+  ifd_len -= 2;
+
+  /* validate the number of entries */
+  if (G_UNLIKELY (n * 12 > ifd_len))
+    n = ifd_len / 12;
+
+  /* process all IFD entries */
+  for (; n > 0; ifd_ptr += 12, --n)
+    {
+      /* determine the tag of this entry */
+      tag = tvtj_exif_get_ushort (exif, ifd_ptr);
+      if (tag == 0x8769 || tag == 0xa005)
+        {
+          /* check if we have a valid sub IFD offset here */
+          subifd_off = tvtj_exif_get_ulong (exif, ifd_ptr + 8);
+          subifd_ptr = exif->data_ptr + subifd_off;
+          if (G_LIKELY (subifd_off < exif->data_len))
+            {
+              /* process the sub IFD recursively */
+              tvtj_exif_parse_ifd (exif, subifd_ptr, exif->data_len - subifd_off, &ifd_list);
+            }
+        }
+      else if (tag == 0x0103)
+        {
+          /* verify that we have an ushort here (format 3) */
+          if (tvtj_exif_get_ushort (exif, ifd_ptr + 2) == 3)
+            {
+              /* determine the thumbnail compression */
+              exif->thumb_compression = tvtj_exif_get_ushort (exif, ifd_ptr + 8);
+            }
+        }
+      else if (tag == 0x0100 || tag == 0x0101 || tag == 0x0106 || tag == 0x0111 || tag == 0x0117)
+        {
+          /* this can be either ushort or ulong */
+          if (tvtj_exif_get_ushort (exif, ifd_ptr + 2) == 3)
+            value = tvtj_exif_get_ushort (exif, ifd_ptr + 8);
+          else if (tvtj_exif_get_ushort (exif, ifd_ptr + 2) == 4)
+            value = tvtj_exif_get_ulong (exif, ifd_ptr + 8);
+          else
+            value = 0;
+
+          /* and remember it appropriately */
+          if (tag == 0x0100)
+            exif->thumb.thumb_tiff.width = value;
+          else if (tag == 0x0100)
+            exif->thumb.thumb_tiff.height = value;
+          else if (tag == 0x0106)
+            exif->thumb.thumb_tiff.interp = value;
+          else if (tag == 0x0111)
+            exif->thumb.thumb_tiff.offset = value;
+          else
+            exif->thumb.thumb_tiff.length = value;
+        }
+      else if (tag == 0x0201 || tag == 0x0202)
+        {
+          /* verify that we have an ulong here (format 4) */
+          if (tvtj_exif_get_ushort (exif, ifd_ptr + 2) == 4)
+            {
+              /* determine the value (thumbnail JPEG offset or length) */
+              value = tvtj_exif_get_ulong (exif, ifd_ptr + 8);
+
+              /* and remember it appropriately */
+              if (G_LIKELY (tag == 0x201))
+                exif->thumb.thumb_jpeg.offset = value;
+              else
+                exif->thumb.thumb_jpeg.length = value;
+            }
+        }
+    }
+
+  /* check for link to next IFD */
+  subifd_off = tvtj_exif_get_ulong (exif, ifd_ptr);
+  if (subifd_off != 0 && subifd_off < exif->data_len)
+    {
+      /* parse next IFD recursively as well */
+      tvtj_exif_parse_ifd (exif, exif->data_ptr + subifd_off, exif->data_len - subifd_off, &ifd_list);
+    }
+}
+
+
+
+static GdkPixbuf*
+tvtj_exif_extract_thumbnail (const guchar *data,
+                             guint         length,
+                             gint          size)
+{
+  TvtjExif exif;
+  guint    offset;
+
+  /* make sure we have enough data */
+  if (G_UNLIKELY (length < 6 + 8))
+    return NULL;
+
+  /* validate Exif header */
+  if (memcmp (data, "Exif\0\0", 6) != 0)
+    return NULL;
+
+  /* advance to TIFF header */
+  data += 6;
+  length -= 6;
+
+  /* setup Exif data struct */
+  memset (&exif, 0, sizeof (exif));
+  exif.data_ptr = data;
+  exif.data_len = length;
+
+  /* determine byte order */
+  if (memcmp (data, "II", 2) == 0)
+    exif.big_endian = FALSE;
+  else if (memcmp (data, "MM", 2) == 0)
+    exif.big_endian = TRUE;
+  else
+    return NULL;
+
+  /* validate the TIFF header */
+  if (tvtj_exif_get_ushort (&exif, data + 2) != 0x2a)
+    return NULL;
+
+  /* determine the first IFD offset */
+  offset = tvtj_exif_get_ulong (&exif, data + 4);
+
+  /* validate the offset */
+  if (G_LIKELY (offset < length))
+    {
+      /* parse the first IFD (recursively parses the remaining...) */
+      tvtj_exif_parse_ifd (&exif, data + offset, length - offset, NULL);
+
+      /* check thumbnail compression type */
+      if (G_LIKELY (exif.thumb_compression == 6)) /* JPEG */
+        {
+          /* check if we have a valid thumbnail JPEG */
+          if (exif.thumb.thumb_jpeg.offset > 0 && exif.thumb.thumb_jpeg.length > 0
+              && exif.thumb.thumb_jpeg.offset + exif.thumb.thumb_jpeg.length <= length)
+            {
+              /* try to load the embedded thumbnail JPEG */
+              return tvtj_jpeg_load (data + exif.thumb.thumb_jpeg.offset, exif.thumb.thumb_jpeg.length, size);
+            }
+        }
+      else if (exif.thumb_compression == 1) /* Uncompressed */
+        {
+          /* check if we have a valid thumbnail (current only RGB interpretations) */
+          if (G_LIKELY (exif.thumb.thumb_tiff.interp == 2)
+              && exif.thumb.thumb_tiff.offset > 0 && exif.thumb.thumb_tiff.length > 0
+              && exif.thumb.thumb_tiff.offset + exif.thumb.thumb_tiff.length <= length
+              && exif.thumb.thumb_tiff.height * exif.thumb.thumb_tiff.width == exif.thumb.thumb_tiff.length)
+            {
+              /* plain RGB data, just what we need for a GdkPixbuf */
+              return gdk_pixbuf_new_from_data (g_memdup (data + exif.thumb.thumb_tiff.offset, exif.thumb.thumb_tiff.length),
+                                               GDK_COLORSPACE_RGB, FALSE, 8, exif.thumb.thumb_tiff.width,
+                                               exif.thumb.thumb_tiff.height, exif.thumb.thumb_tiff.width,
+                                               (GdkPixbufDestroyNotify) g_free, NULL);
+            }
+        }
+    }
+
+  return NULL;
+}
+
+
+
+static GdkPixbuf*
+tvtj_jpeg_load_thumbnail (const JOCTET *content,
+                          gsize         length,
+                          gint          size)
+{
+  guint marker_len;
+  guint marker;
+  gsize n;
+
+  /* valid JPEG headers begin with SOI (Start Of Image) */
+  if (G_LIKELY (length >= 2 && content[0] == 0xff && content[1] == 0xd8))
+    {
+      /* search for an EXIF marker */
+      for (length -= 2, n = 2; n < length; )
+        {
+          /* check for valid marker start */
+          if (G_UNLIKELY (content[n++] != 0xff))
+            break;
+
+          /* determine the next marker */
+          marker = content[n];
+
+          /* skip additional padding */
+          if (G_UNLIKELY (marker == 0xff))
+            continue;
+
+          /* stop at SOS marker */
+          if (marker == 0xda)
+            break;
+
+          /* advance */
+          ++n;
+
+          /* check if valid */
+          if (G_UNLIKELY (n + 2 >= length))
+            break;
+
+          /* determine the marker length */
+          marker_len = (content[n] << 8) | content[n + 1];
+
+          /* check if we have an exif marker here */
+          if (marker == 0xe1 && n + marker_len <= length)
+            {
+              /* try to extract the Exif thumbnail */
+              return tvtj_exif_extract_thumbnail (content + n + 2, marker_len - 2, size);
+            }
+
+          /* try next one then */
+          n += marker_len;
+        }
+    }
+
+  return NULL;
+}
+
+
+
+static void
+free_image_data (TumblerImageData *data)
+{
+  if (data == NULL)
+    return;
+
+  /* TODO */
+}
+
+
+
+static void
+jpeg_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+                         GCancellable               *cancellable,
+                         TumblerFileInfo            *info)
+{
+  TumblerThumbnailFlavor *flavor;
+  TumblerImageData        data;
+  TumblerThumbnail       *thumbnail;
+  struct stat             statb;
+  const gchar            *uri;
+  GdkPixbuf              *pixbuf;
+  gboolean                streaming_needed = TRUE;
+  JOCTET                 *content;
+  GError                 *error = NULL;
+  GFile                  *file;
+  gchar                  *path;
+  gsize                   length;
+  gint                    fd;
+  gint                    height;
+  gint                    width;
+  gint                    size;
+
+  g_return_if_fail (IS_JPEG_THUMBNAILER (thumbnailer));
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (TUMBLER_IS_FILE_INFO (info));
+
+  /* do nothing if cancelled */
+  if (g_cancellable_is_cancelled (cancellable)) 
+    return;
+
+  uri = tumbler_file_info_get_uri (info);
+
+  /* try to open the source file for reading */
+  file = g_file_new_for_uri (uri);
+
+  thumbnail = tumbler_file_info_get_thumbnail (info);
+  g_assert (thumbnail != NULL);
+
+  flavor = tumbler_thumbnail_get_flavor (thumbnail);
+  g_assert (flavor != NULL);
+
+  tumbler_thumbnail_flavor_get_size (flavor, &width, &height);
+  size = MIN (width, height);
+
+#ifdef HAVE_MMAP
+  if (g_file_is_native (file))
+    {
+      path = g_file_get_path (file);
+
+      /* try to open the file at the given path */
+      fd = open (path, O_RDONLY);
+      if (G_LIKELY (fd >= 0))
+        {
+          /* determine the status of the file */
+          if (G_LIKELY (fstat (fd, &statb) == 0 && statb.st_size > 0))
+            {
+              /* try to mmap the file */
+              content = (JOCTET *) mmap (NULL, statb.st_size, PROT_READ, 
+                                         MAP_SHARED, fd, 0);
+
+              /* verify whether the mmap was successful */
+              if (G_LIKELY (content != (JOCTET *) MAP_FAILED))
+                {
+                  /* try to load the embedded thumbnail first */
+                  pixbuf = tvtj_jpeg_load_thumbnail (content, statb.st_size, size);
+                  if (pixbuf == NULL)
+                    {
+                      /* fall back to loading and scaling the image itself */
+                      pixbuf = tvtj_jpeg_load (content, statb.st_size, size);
+
+                      if (pixbuf == NULL)
+                        {
+                          g_set_error (&error, TUMBLER_ERROR, 
+                                       TUMBLER_ERROR_INVALID_FORMAT,
+                                       _("Thumbnail could not be inferred from file contents"));
+                        }
+                    }
+
+                  /* we have successfully mmapped the file. we may not have
+                   * a thumbnail but trying to read the image from a stream
+                   * won't help us here, so we don't need to attempt streaming
+                   * as a fallback */
+                  streaming_needed = FALSE;
+                }
+
+              /* unmap the file content */
+              munmap ((void *) content, statb.st_size);
+            }
+
+          /* close the file */
+          close (fd);
+        }
+
+      g_free (path);
+    }
+#endif
+
+  if (streaming_needed)
+    {
+      g_file_load_contents (file, cancellable, (gchar **)&content, &length, 
+                            NULL, &error);
+
+      if (error == NULL)
+        {
+          pixbuf = tvtj_jpeg_load_thumbnail (content, length, size);
+
+          if (pixbuf == NULL)
+            {
+              pixbuf = tvtj_jpeg_load (content, length, size);
+              if (pixbuf == NULL)
+                {
+                  g_set_error (&error, TUMBLER_ERROR, TUMBLER_ERROR_INVALID_FORMAT,
+                               _("Thumbnail could not be inferred from file contents"));
+                }
+            }
+        }
+    }
+
+  /* either we have an error now or we have a valid thumbnail pixbuf */
+  g_assert (error != NULL || pixbuf != NULL);
+
+  if (pixbuf != NULL)
+    {
+      data.data = gdk_pixbuf_get_pixels (pixbuf);
+      data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+      data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
+      data.width = gdk_pixbuf_get_width (pixbuf);
+      data.height = gdk_pixbuf_get_height (pixbuf);
+      data.rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+      data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (pixbuf);
+
+      tumbler_thumbnail_save_image_data (thumbnail, &data, 
+                                         tumbler_file_info_get_mtime (info), 
+                                         NULL, &error);
+
+      g_object_unref (pixbuf);
+    }
+
+  if (error != NULL)
+    {
+      g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      g_signal_emit_by_name (thumbnailer, "ready", uri);
+    }
+
+  g_object_unref (flavor);
+  g_object_unref (thumbnail);
+  g_object_unref (file);
+}
diff --git a/plugins/jpeg-thumbnailer/jpeg-thumbnailer.h b/plugins/jpeg-thumbnailer/jpeg-thumbnailer.h
new file mode 100644
index 0000000..e5f0325
--- /dev/null
+++ b/plugins/jpeg-thumbnailer/jpeg-thumbnailer.h
@@ -0,0 +1,43 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General 
+ * Public License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __JPEG_THUMBNAILER_H__
+#define __JPEG_THUMBNAILER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_JPEG_THUMBNAILER            (jpeg_thumbnailer_get_type ())
+#define JPEG_THUMBNAILER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_JPEG_THUMBNAILER, JPEGThumbnailer))
+#define JPEG_THUMBNAILER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_JPEG_THUMBNAILER, JPEGThumbnailerClass))
+#define IS_JPEG_THUMBNAILER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_JPEG_THUMBNAILER))
+#define IS_JPEG_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_JPEG_THUMBNAILER)
+#define JPEG_THUMBNAILER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_JPEG_THUMBNAILER, JPEGThumbnailerClass))
+
+typedef struct _JPEGThumbnailerClass   JPEGThumbnailerClass;
+typedef struct _JPEGThumbnailer        JPEGThumbnailer;
+
+GType jpeg_thumbnailer_get_type (void) G_GNUC_CONST;
+void  jpeg_thumbnailer_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__JPEG_THUMBNAILER_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7b9bc3d..c68c85b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,9 @@ plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-provider.c
 plugins/font-thumbnailer/font-thumbnailer-plugin.c
 plugins/font-thumbnailer/font-thumbnailer.c
 plugins/font-thumbnailer/font-thumbnailer-provider.c
+plugins/jpeg-thumbnailer/jpeg-thumbnailer.c
+plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c
+plugins/jpeg-thumbnailer/jpeg-thumbnailer-provider.c
 plugins/xdg-cache/xdg-cache-thumbnail.c
 plugins/xdg-cache/xdg-cache-plugin.c
 plugins/xdg-cache/xdg-cache-cache.c
diff --git a/po/ast.po b/po/ast.po
index 39b6161..afd71e0 100644
--- a/po/ast.po
+++ b/po/ast.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-10-20 22:26+0100\n"
 "Last-Translator: astur <malditoastur at gmail.com>\n"
 "Language-Team: en_GB\n"
@@ -144,16 +144,19 @@ msgstr "Falló al cargar plugin \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Conflictu de versión: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Aniciar el complementu Tumbler Pixbuf Thumbnailer"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Apagar el complementu Tumbler Pixbuf Thumbnailer"
 
@@ -178,23 +181,29 @@ msgid "Could not load file contents: %s"
 msgstr "Nun pueden cargase los conteníos del ficheru: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "Nun pudo abrise'l ficheru fonte: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Nun puede afitase'l mapa de carauter: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Nun pueden renderizase glyphs: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/ca.po b/po/ca.po
index ef47e30..0156dc2 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-12-03 18:30+0100\n"
 "Last-Translator: Harald Servat <redcrash at gmail.com>\n"
 "Language-Team: Catalan <xfce-i18n at xfce.org>\n"
@@ -149,16 +149,19 @@ msgstr "No s'ha pogut carregar el connector «%s»: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Versió errònia: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "S'està iniciant el connector de Tumbler de miniatures Pixbuf"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "S'està apagant el connector de Tumbler de miniatures Pixbuf"
 
@@ -183,23 +186,29 @@ msgid "Could not load file contents: %s"
 msgstr "No s'ha pogut llegir el contingut del fitxer: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "No s'ha pogut obrir el fitxer: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "No s'ha pogut establir el mapa de caràcters: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "No s'han pogut representar el glif: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/da.po b/po/da.po
index dc605fd..ce9cd7c 100644
--- a/po/da.po
+++ b/po/da.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Tumbler 1.0.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-12-03 13:08+0100\n"
 "Last-Translator: Per Kongstad <p_kongstad at op.pl>\n"
 "Language-Team: Danish <dansk at dansk-gruppen.dk>\n"
@@ -147,16 +147,19 @@ msgstr "Kunne ikke indlæse udvidelsesmodul  \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Version uoverensstemmelse: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Initialiserer udvidelsesmodulet Tumbler Pixbuf Thumbnailer"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Lukker udvidelsesmodulet Tumbler Pixbuf Thumbnailer ned"
 
@@ -181,23 +184,29 @@ msgid "Could not load file contents: %s"
 msgstr "Kunne ikke indlæse filindhold: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "Kunne ikke åbne skrifttypefil: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Kunne ikke indstille til tegntilknytningen: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Kunne ikke rendere glyphs: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/en_GB.po b/po/en_GB.po
index 6a40d3a..4f53796 100644
--- a/po/en_GB.po
+++ b/po/en_GB.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-08-18 21:35+1000\n"
 "Last-Translator: Jeff Bailes <thepizzaking at gmail.com>\n"
 "Language-Team: en_GB\n"
@@ -144,16 +144,19 @@ msgstr "Failed to load plugin \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Version mismatch: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Initialising the Tumbler Pixbuf Thumbnailer plugin"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 
@@ -180,23 +183,29 @@ msgid "Could not load file contents: %s"
 msgstr "Could not save thumbnail to \"%s\""
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, fuzzy, c-format
 msgid "Could not open font file: %s"
 msgstr "Could not save thumbnail to \"%s\""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr ""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr ""
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/fr.po b/po/fr.po
index 526cb57..3c130fa 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-12-03 10:19+0100\n"
 "Last-Translator: Douart Patrick <patrick.2 at laposte.net>\n"
 "Language-Team: French <i18n-xfce at xfce.org>\n"
@@ -157,16 +157,19 @@ msgstr "Impossible de charger le greffon \"%s\" : %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Incompatibilité de versions: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Initialisation du greffon de vignettes pixbuf"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Arrêt du greffon de vignettes pixbuf"
 
@@ -192,23 +195,29 @@ msgid "Could not load file contents: %s"
 msgstr "Impossible de charger le contenu du fichier: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "Impossible d'ouvrir le fichier de la police: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Impossible de définir le caractère de la carte: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, fuzzy, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Ne pouvait rendre glyphs: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/gl.po b/po/gl.po
index 2ab67ed..9eb159b 100644
--- a/po/gl.po
+++ b/po/gl.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Transifex master\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-11-06 13:43+0100\n"
 "Last-Translator: Leandro Regueiro <leandro.regueiro at gmail.com>\n"
 "Language-Team: Galician <proxecto at trasno.net>\n"
@@ -155,16 +155,19 @@ msgstr "Fallo ao cargar o engadido \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "As versións non coinciden: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Iniciando o engadido miniaturizador de Pixbuf de Tumbler"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Apagando o engadido miniaturizador de Pixbuf de Tumbler"
 
@@ -189,23 +192,29 @@ msgid "Could not load file contents: %s"
 msgstr "Non foi posible cargar o ficheiro: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr ""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Non se puido definir o mapa de caracteres: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Non foi posible debuxar os glifos: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/ja.po b/po/ja.po
index 699a656..491d431 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler 0.0.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-07 23:41+0900\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-12-07 23:40+0900\n"
 "Last-Translator: Masato Hashimoto <cabezon.hashimoto at gmail.com>\n"
 "Language-Team: Japanese\n"
@@ -147,6 +147,7 @@ msgstr "プラグイン \"%s\" の読み込みに失敗しました: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
@@ -154,11 +155,13 @@ msgstr "バージョン不整合です: %s"
 
 # DEBUG message
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 
 # DEBUG message
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 
@@ -185,23 +188,29 @@ msgid "Could not load file contents: %s"
 msgstr "ファイルの内容を読み込めませんでした: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "フォントファイルを開けませんでした: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "キャラクタマップを設定できませんでした: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "グリフをレンダリングできませんでした: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/lv.po b/po/lv.po
index 5f33d5f..4b280b7 100644
--- a/po/lv.po
+++ b/po/lv.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-10-16 18:19+0100\n"
 "Last-Translator: Rihards Prieditis <rprieditis at gmail.com>\n"
 "Language-Team: Latvian <translation-team-lv at lists.sourceforge.net>\n"
@@ -146,16 +146,19 @@ msgstr "Neizdevās ielādēt spraudni \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Versiju nesakritība: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Inicializē Tumble Pixbuf sīktēlotāja spraudni"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Izslēdz Tumble Pixbuf sīktēlotāja spraudni"
 
@@ -180,23 +183,29 @@ msgid "Could not load file contents: %s"
 msgstr "Neizdevās ielādēt faila saturu: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "Neizdevās atvērt fonta failu: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Neizdevās uzstādīt rakstzīmju karti: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Neizdevās vizualizēt glyphs: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/pt.po b/po/pt.po
index 3565a97..668ac1f 100644
--- a/po/pt.po
+++ b/po/pt.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-12-01 02:23-0000\n"
 "Last-Translator: Sergio Marques <smarquespt at gmail.com>\n"
 "Language-Team: \n"
@@ -146,16 +146,19 @@ msgstr "Falha ao carregar o plugin \"%s\": %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Conflito de versão: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Iniciar o plugin de Tumbler Pixbuf Thumbnailer"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Desligando o plugin Tumbler Pixbuf Thumbnailer"
 
@@ -180,23 +183,29 @@ msgid "Could not load file contents: %s"
 msgstr "Não foi possível carregar o ficheiro: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "não foi possível abrir o ficheiro de fontes: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "Não foi possível definir o mapa de caracteres: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "Não foi possivel renderizar glyphs: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/tr.po b/po/tr.po
index 9dcb689..48bda74 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -2,7 +2,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Xfce Tumbler Turkish Translation\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: \n"
 "Last-Translator: Samed Beyribey <ras0ir at eventualis.org>\n"
 "Language-Team: Xfce-TR <xfce-tr at googlegroups.com>\n"
@@ -139,16 +139,19 @@ msgstr "\"%s\" eklentisi yüklenemedi: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "Sürüm çakışması: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Tumbler Pixbuf Önizleyici eklentisi çalıştırılıyor"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "Tumbler Pixbuf Önizleyici eklentisi kapatılıyor"
 
@@ -175,23 +178,29 @@ msgid "Could not load file contents: %s"
 msgstr "Önizleme \"%s\" konumuna kaydedilemedi"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, fuzzy, c-format
 msgid "Could not open font file: %s"
 msgstr "Önizleme \"%s\" konumuna kaydedilemedi"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr ""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr ""
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/tumbler.pot b/po/tumbler.pot
index 5f5cf3f..4398662 100644
--- a/po/tumbler.pot
+++ b/po/tumbler.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -144,16 +144,19 @@ msgstr ""
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr ""
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr ""
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr ""
 
@@ -178,23 +181,29 @@ msgid "Could not load file contents: %s"
 msgstr ""
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr ""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr ""
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr ""
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 8a1e2b1..84b2eb0 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: tumbler\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-05 12:41+0100\n"
+"POT-Creation-Date: 2009-12-08 23:18+0100\n"
 "PO-Revision-Date: 2009-11-18 20:37+0800\n"
 "Last-Translator: Hunt Xu <huntxu at live.cn>\n"
 "Language-Team: Chinese (simplified) <xfce-i18n at xfce.org>\n"
@@ -145,16 +145,19 @@ msgstr "载入插件 \"%s\" 失败: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:57
 #: ../plugins/font-thumbnailer/font-thumbnailer-plugin.c:57
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:57
 #: ../plugins/xdg-cache/xdg-cache-plugin.c:52
 #, c-format
 msgid "Version mismatch: %s"
 msgstr "版本不符: %s"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:62
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:62
 msgid "Initializing the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "正在初始化 Tumbler 图像缩略图查看插件"
 
 #: ../plugins/pixbuf-thumbnailer/pixbuf-thumbnailer-plugin.c:79
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer-plugin.c:79
 msgid "Shutting down the Tumbler Pixbuf Thumbnailer plugin"
 msgstr "正在关闭 Tumbler 图像缩略图查看插件"
 
@@ -179,23 +182,29 @@ msgid "Could not load file contents: %s"
 msgstr "无法读取文件内容: %s"
 
 #. the font file could not be loaded, emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:495
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:494
 #, c-format
 msgid "Could not open font file: %s"
 msgstr "无法打开字体文件: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:520
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:518
 #, c-format
 msgid "Could not set the character map: %s"
 msgstr "无法设置字符映射: %s"
 
 #. emit an error signal
-#: ../plugins/font-thumbnailer/font-thumbnailer.c:548
+#: ../plugins/font-thumbnailer/font-thumbnailer.c:545
 #, c-format
 msgid "Could not render glyphs: %s"
 msgstr "无法渲染字型: %s"
 
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:753
+#: ../plugins/jpeg-thumbnailer/jpeg-thumbnailer.c:791
+#, c-format
+msgid "Thumbnail could not be inferred from file contents"
+msgstr ""
+
 #: ../plugins/xdg-cache/xdg-cache-thumbnail.c:382
 #, c-format
 msgid "Could not save thumbnail to \"%s\""



More information about the Xfce4-commits mailing list