[Nautilus-list] Re: Faster jpeg thumbnailing patch
- From: Alexander Larsson <alla lysator liu se>
- To: nautilus-list lists eazel com
- Subject: [Nautilus-list] Re: Faster jpeg thumbnailing patch
- Date: Fri, 27 Apr 2001 10:43:30 +0200 (CEST)
On Fri, 27 Apr 2001, Alexander Larsson wrote:
> Attached to this mail is a patch that increases the performance when
> thumbnailing large jpeg images. It does so by using the built in scaling
> in libjpeg. This means that libjpeg doesn't have to decompress the whole
> file when scaling down (high frequency components of the DCT are
> ignored). Loading and scaling down jpegs are much faster than loading the
> whole picture and then scaling it down.
>
> Please cc me for replies, i'm not on nautilus-list.
Apparently it needed some better error handling to handle broken
jpeg files. Here is an updated patch.
/Alex
Index: acconfig.h
===================================================================
RCS file: /cvs/gnome/nautilus/acconfig.h,v
retrieving revision 1.24
diff -u -p -r1.24 acconfig.h
--- acconfig.h 2001/04/11 12:37:37 1.24
+++ acconfig.h 2001/04/26 23:15:09
@@ -8,6 +8,7 @@
#undef HAVE_GETTEXT
#undef HAVE_LC_MESSAGES
#undef HAVE_MEDUSA
+#undef HAVE_LIBJPEG
#undef HAVE_STPCPY
#undef HAVE_LIBBZ2
#undef HAVE_AMMONITE
Index: configure.in
===================================================================
RCS file: /cvs/gnome/nautilus/configure.in,v
retrieving revision 1.326
diff -u -p -r1.326 configure.in
--- configure.in 2001/04/21 00:23:46 1.326
+++ configure.in 2001/04/26 23:15:12
@@ -793,6 +793,27 @@ dnl =======================
dnl = End tests for libpng
dnl =======================
+dnl ====================================
+dnl = Begin tests for libjpeg
+dnl ====================================
+ if test -z "$LIBJPEG"; then
+ AC_CHECK_LIB(jpeg, jpeg_start_decompress,
+ AC_CHECK_HEADER(jpeglib.h,
+ jpeg_ok=yes,
+ jpeg_ok=no),
+ AC_MSG_WARN(*** (jpeg library not found) ***), -lm)
+ if test "$jpeg_ok" = yes; then
+ JPEG='jpeg'; LIBJPEG='-ljpeg'
+ AC_DEFINE(HAVE_LIBJPEG)
+ else
+ AC_MSG_WARN(*** JPEG loader will not be built (jpeg header file not found) ***)
+ fi
+ fi
+
+AC_SUBST(LIBJPEG)
+dnl =======================
+dnl = End tests for libjpeg
+dnl =======================
dnl =======================
dnl = Set up for library directories
Index: libnautilus-extensions/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-extensions/Makefile.am,v
retrieving revision 1.184
diff -u -p -r1.184 Makefile.am
--- libnautilus-extensions/Makefile.am 2001/04/20 02:01:40 1.184
+++ libnautilus-extensions/Makefile.am 2001/04/26 23:15:18
@@ -48,6 +48,7 @@ libnautilus_extensions_la_LDFLAGS = \
$(GNOMECANVASPIXBUF_LIBS) \
$(GNOME_LIBS) \
$(LIBPNG) \
+ $(LIBJPEG) \
$(MEDUSA_LIBS) \
$(OAF_LIBS) \
$(VFS_LIBS) \
@@ -117,6 +118,7 @@ libnautilus_extensions_la_SOURCES = \
nautilus-sound.c \
nautilus-theme.c \
nautilus-thumbnails.c \
+ nautilus-thumbnails-jpeg.c \
nautilus-trash-directory.c \
nautilus-trash-file.c \
nautilus-trash-monitor.c \
@@ -192,6 +194,7 @@ noinst_HEADERS = \
nautilus-sound.h \
nautilus-theme.h \
nautilus-thumbnails.h \
+ nautilus-thumbnails-jpeg.h \
nautilus-trash-directory.h \
nautilus-trash-file.h \
nautilus-trash-monitor.h \
Index: libnautilus-extensions/nautilus-thumbnails.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-extensions/nautilus-thumbnails.c,v
retrieving revision 1.18
diff -u -p -r1.18 nautilus-thumbnails.c
--- libnautilus-extensions/nautilus-thumbnails.c 2001/04/04 11:28:54 1.18
+++ libnautilus-extensions/nautilus-thumbnails.c 2001/04/26 23:15:20
@@ -24,6 +24,7 @@
#include <config.h>
#include "nautilus-thumbnails.h"
+#include "nautilus-thumbnails-jpeg.h"
#include "nautilus-directory-notify.h"
#include "nautilus-icon-factory-private.h"
@@ -593,6 +594,14 @@ make_thumbnails (gpointer data)
fclose (f);
}
}
+#ifdef HAVE_LIBJPEG
+ } else if (nautilus_file_is_mime_type (file, "image/jpeg")) {
+ if (info->thumbnail_uri != NULL)
+ full_size_image =
+ nautilus_thumbnail_load_scaled_jpeg (info->thumbnail_uri,
+ 96,
+ 96);
+#endif
} else {
if (info->thumbnail_uri != NULL)
full_size_image = eel_gdk_pixbuf_load (info->thumbnail_uri);
--- /dev/null Thu Aug 24 11:00:32 2000
+++ libnautilus-extensions/nautilus-thumbnails-jpeg.h Fri Apr 27 00:10:40 2001
@@ -0,0 +1,36 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails-jpeg.h: Fast loading of scaled jpeg images
+
+ Copyright (C) 2001 Red Hat Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl redhat com>
+*/
+
+#ifndef NAUTILUS_THUMBNAILS_JPEG_H
+#define NAUTILUS_THUMBNAILS_JPEG_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+GdkPixbuf *
+nautilus_thumbnail_load_scaled_jpeg (const char *uri,
+ int target_width,
+ int target_heigh);
+
+#endif /* NAUTILUS_THUMBNAILS_JPEG_H */
+
--- /dev/null Thu Aug 24 11:00:32 2000
+++ libnautilus-extensions/nautilus-thumbnails-jpeg.c Fri Apr 27 10:28:44 2001
@@ -0,0 +1,255 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails-jpeg.c: Fast loading of scaled jpeg images
+
+ Copyright (C) 2001 Red Hat Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl redhat com>
+*/
+
+#include <config.h>
+
+#ifdef HAVE_LIBJPEG
+#include <stdlib.h>
+#include <stdio.h>
+#include <jpeglib.h>
+#include <setjmp.h>
+#include <libgnomevfs/gnome-vfs-types.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+
+#include "nautilus-thumbnails-jpeg.h"
+
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ GnomeVFSHandle *handle;
+ JOCTET * buffer;
+} GnomeVFSSource;
+
+struct error_handler_data {
+ struct jpeg_error_mgr pub;
+ sigjmp_buf setjmp_buffer;
+};
+
+#define INPUT_BUF_SIZE 4096
+
+static void
+fatal_error_handler (j_common_ptr cinfo)
+{
+ struct error_handler_data *errmgr = (struct error_handler_data *) cinfo->err;
+
+ siglongjmp (errmgr->setjmp_buffer, 1);
+
+ g_assert_not_reached ();
+}
+
+static void
+output_message_handler (j_common_ptr cinfo)
+{
+ /* This method keeps libjpeg from dumping crap to stderr */
+}
+
+static void
+init_source (j_decompress_ptr cinfo)
+{
+}
+
+static gboolean
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ GnomeVFSSource *src = (GnomeVFSSource *) cinfo->src;
+ GnomeVFSFileSize nbytes;
+ GnomeVFSResult result;
+
+ result = gnome_vfs_read (src->handle,
+ src->buffer,
+ INPUT_BUF_SIZE,
+ &nbytes);
+
+ if (result != GNOME_VFS_OK || nbytes == 0) {
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+
+ return TRUE;
+}
+
+static void
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ GnomeVFSSource *src = (GnomeVFSSource *) cinfo->src;
+
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ fill_input_buffer(cinfo);
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void
+term_source (j_decompress_ptr cinfo)
+{
+ GnomeVFSSource *src = (GnomeVFSSource *) cinfo->src;
+ g_free (src->buffer);
+ src->buffer = NULL;
+}
+
+static void
+vfs_src (j_decompress_ptr cinfo, GnomeVFSHandle *handle)
+{
+ GnomeVFSSource *src;
+
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *) g_new (GnomeVFSSource, 1);
+ src = (GnomeVFSSource *) cinfo->src;
+ src->buffer = g_malloc (INPUT_BUF_SIZE * sizeof (JOCTET));
+ }
+
+ src = (GnomeVFSSource *) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->handle = handle;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+static int
+calculate_divisor (int width,
+ int height,
+ int target_width,
+ int target_height)
+{
+ if (width/8 > target_width && height/8 > target_height)
+ return 8;
+ if (width/4 > target_width && height/4 > target_height)
+ return 4;
+ if (width/2 > target_width && height/2 > target_height)
+ return 2;
+ return 1;
+}
+
+static void
+free_buffer (guchar *pixels, gpointer data)
+{
+ g_free (pixels);
+}
+
+GdkPixbuf *
+nautilus_thumbnail_load_scaled_jpeg (const char *uri,
+ int target_width,
+ int target_height)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct error_handler_data jerr;
+ GnomeVFSHandle *handle;
+ unsigned char *lines[1];
+ guchar *buffer = NULL;
+ guchar *pixels = NULL;
+ guchar *ptr = NULL;
+ GnomeVFSResult result;
+ unsigned int i;
+
+ result = gnome_vfs_open (&handle,
+ uri,
+ GNOME_VFS_OPEN_READ);
+ if (result != GNOME_VFS_OK) {
+ return NULL;
+ }
+
+
+ cinfo.err = jpeg_std_error (&jerr.pub);
+ jerr.pub.error_exit = fatal_error_handler;
+ jerr.pub.output_message = output_message_handler;
+
+ if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+ /* Whoops there was a jpeg error */
+ g_free (pixels);
+ g_free (buffer);
+
+ jpeg_destroy_decompress (&cinfo);
+ return NULL;
+ }
+
+ jpeg_create_decompress (&cinfo);
+
+ vfs_src (&cinfo, handle);
+
+ jpeg_read_header(&cinfo, TRUE);
+
+ cinfo.scale_num = 1;
+ cinfo.scale_denom = calculate_divisor (cinfo.image_width,
+ cinfo.image_height,
+ target_width,
+ target_height);
+ cinfo.dct_method = JDCT_FASTEST;
+ cinfo.do_fancy_upsampling = FALSE;
+
+ jpeg_start_decompress(&cinfo);
+
+ pixels = g_malloc (cinfo.output_width * cinfo.output_height * 3);
+
+ if (cinfo.num_components == 1) {
+ /* Allocate extra buffer for grayscale data */
+ buffer = g_malloc (cinfo.output_width);
+ lines[0] = buffer;
+ ptr = pixels;
+ } else
+ lines[0] = pixels;
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ jpeg_read_scanlines (&cinfo, lines, 1);
+
+ if (cinfo.num_components == 1) {
+ /* Convert grayscale to rgb */
+ for (i = 0; i < cinfo.output_width; i++) {
+ ptr[i*3] = buffer[i];
+ ptr[i*3+1] = buffer[i];
+ ptr[i*3+2] = buffer[i];
+ }
+ ptr += cinfo.output_width * 3;
+ } else
+ lines[0] += cinfo.output_width * 3;
+ }
+
+ g_free (buffer);
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, FALSE, 8,
+ cinfo.output_width,
+ cinfo.output_height,
+ cinfo.output_width * 3,
+ free_buffer, NULL);
+}
+
+
+#endif /* HAVE_LIBJPEG */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]