[gthumb] added a custom tiff loader
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] added a custom tiff loader
- Date: Sun, 8 Dec 2013 17:53:18 +0000 (UTC)
commit 7fe050eb472ca80d900b911c2150772af26019dc
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Dec 8 17:36:43 2013 +0100
added a custom tiff loader
configure.ac | 1 +
extensions/cairo_io/Makefile.am | 6 +
extensions/cairo_io/cairo-image-surface-tiff.c | 312 ++++++++++++++++++++++++
extensions/cairo_io/cairo-image-surface-tiff.h | 42 ++++
extensions/cairo_io/main.c | 8 +
5 files changed, 369 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index fb5a191..22af454 100644
--- a/configure.ac
+++ b/configure.ac
@@ -387,6 +387,7 @@ if test x$enable_tiff = xyes ; then
unset SAVE_CFLAGS
fi
AC_SUBST(TIFF_LIBS)
+AM_CONDITIONAL(ENABLE_TIFF, test "x$enable_tiff" = xyes)
dnl ===========================================================================
diff --git a/extensions/cairo_io/Makefile.am b/extensions/cairo_io/Makefile.am
index 9d1c730..5e211ed 100644
--- a/extensions/cairo_io/Makefile.am
+++ b/extensions/cairo_io/Makefile.am
@@ -66,6 +66,12 @@ libcairo_io_la_SOURCES += \
gth-image-saver-webp.h
endif
+if ENABLE_TIFF
+libcairo_io_la_SOURCES += \
+ cairo-image-surface-tiff.c \
+ cairo-image-surface-tiff.h
+endif
+
libcairo_io_la_CFLAGS = $(GTHUMB_CFLAGS) $(JPEG_CFLAGS) $(LIBRSVG_CFLAGS) -I$(top_srcdir)
-I$(top_builddir)/gthumb
libcairo_io_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
libcairo_io_la_LIBADD = $(GTHUMB_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) $(LIBRSVG_LIBS) $(LIBWEBP_LIBS)
diff --git a/extensions/cairo_io/cairo-image-surface-tiff.c b/extensions/cairo_io/cairo-image-surface-tiff.c
new file mode 100644
index 0000000..df26682
--- /dev/null
+++ b/extensions/cairo_io/cairo-image-surface-tiff.c
@@ -0,0 +1,312 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2013 Free Software Foundation, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <tiff.h>
+#include <tiffio.h>
+#include "cairo-image-surface-tiff.h"
+
+
+#define HANDLE(x) ((Handle *) (x))
+
+
+typedef struct {
+ GInputStream *istream;
+ GCancellable *cancellable;
+ goffset size;
+} Handle;
+
+
+static tsize_t
+tiff_read (thandle_t handle, tdata_t buf, tsize_t size)
+{
+ Handle *h = HANDLE (handle);
+ return g_input_stream_read (G_INPUT_STREAM (h->istream), buf, size, h->cancellable, NULL);
+}
+
+
+static tsize_t
+tiff_write (thandle_t handle, tdata_t buf, tsize_t size)
+{
+ return -1;
+}
+
+
+static toff_t
+tiff_seek (thandle_t handle, toff_t offset, int whence)
+{
+ Handle *h = HANDLE (handle);
+ GSeekType seek_type;
+
+ seek_type = G_SEEK_SET;
+ switch (whence) {
+ case SEEK_SET:
+ seek_type = G_SEEK_SET;
+ break;
+ case SEEK_CUR:
+ seek_type = G_SEEK_CUR;
+ break;
+ case SEEK_END:
+ seek_type = G_SEEK_END;
+ break;
+ }
+
+ if (! g_seekable_seek (G_SEEKABLE (h->istream), offset, seek_type, h->cancellable, NULL))
+ return -1;
+
+ return g_seekable_tell (G_SEEKABLE (h->istream));
+}
+
+
+static int
+tiff_close (thandle_t context)
+{
+ return 0;
+}
+
+
+static toff_t
+tiff_size (thandle_t handle)
+{
+ return (toff_t) HANDLE (handle)->size;
+}
+
+
+static void
+tiff_error_handler (const char *module, const char *fmt, va_list ap)
+{
+ /* do not print warnings and errors */
+}
+
+
+GthImage *
+_cairo_image_surface_create_from_tiff (GInputStream *istream,
+ GthFileData *file_data,
+ int requested_size,
+ int *original_width_p,
+ int *original_height_p,
+ gboolean *loaded_original_p,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GthImage *image;
+ Handle handle;
+ TIFF *tif;
+ gboolean first_directory;
+ int best_directory;
+ int max_width, max_height, min_diff;
+ uint32 image_width;
+ uint32 image_height;
+ uint32 spp;
+ uint16 extrasamples;
+ uint16 *sampleinfo;
+ uint16 orientation;
+ char emsg[1024];
+ cairo_surface_t *surface;
+ cairo_surface_metadata_t*metadata;
+ uint32 *raster;
+
+ image = gth_image_new ();
+ handle.cancellable = cancellable;
+ handle.size = 0;
+
+ if ((file_data != NULL) && (file_data->info != NULL)) {
+ handle.istream = g_buffered_input_stream_new (istream);
+ handle.size = g_file_info_get_size (file_data->info);
+ }
+ else {
+ void *data;
+ gsize size;
+
+ /* read the whole stream to get the file size */
+
+ if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error))
+ return image;
+ handle.istream = g_memory_input_stream_new_from_data (data, size, g_free);
+ handle.size = size;
+ }
+
+
+ TIFFSetErrorHandler (tiff_error_handler);
+ TIFFSetWarningHandler (tiff_error_handler);
+
+ tif = TIFFClientOpen ("gth-tiff-reader", "r",
+ &handle,
+ tiff_read,
+ tiff_write,
+ tiff_seek,
+ tiff_close,
+ tiff_size,
+ NULL,
+ NULL);
+
+ if (tif == NULL) {
+ g_object_unref (handle.istream);
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ "Couldn't allocate memory for writing TIFF file");
+ return image;
+ }
+
+ /* find the best image to load */
+
+ first_directory = TRUE;
+ best_directory = -1;
+ max_width = -1;
+ max_height = -1;
+ min_diff = 0;
+ do {
+ uint32 image_width;
+ uint32 image_height;
+
+ if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width) != 1)
+ continue;
+ if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height) != 1)
+ continue;
+
+ if (! TIFFRGBAImageOK (tif, emsg))
+ continue;
+
+ if (image_width > max_width) {
+ max_width = image_width;
+ max_height = image_height;
+ if (requested_size <= 0)
+ best_directory = TIFFCurrentDirectory (tif);
+ }
+
+ if (requested_size > 0) {
+ int diff = abs (requested_size - image_width);
+
+ if (first_directory) {
+ min_diff = diff;
+ best_directory = TIFFCurrentDirectory (tif);
+ }
+ else if (diff < min_diff) {
+ min_diff = diff;
+ best_directory = TIFFCurrentDirectory (tif);
+ }
+ }
+
+ first_directory = FALSE;
+ }
+ while (TIFFReadDirectory (tif));
+
+ if (best_directory == -1) {
+ TIFFClose (tif);
+ g_object_unref (handle.istream);
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Invalid TIFF format");
+ return image;
+ }
+
+ /* read the image */
+
+ TIFFSetDirectory (tif, best_directory);
+ TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width);
+ TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height);
+ TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
+ if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1)
+ orientation = ORIENTATION_TOPLEFT;
+
+ if (original_width_p)
+ *original_width_p = max_width;
+ if (original_height_p)
+ *original_height_p = max_height;
+ if (loaded_original_p)
+ *loaded_original_p = (max_width == image_width);
+
+ surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height);
+ if (surface == NULL) {
+ TIFFClose (tif);
+ g_object_unref (handle.istream);
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ "Couldn't allocate memory for writing TIFF file");
+ return image;
+ }
+
+ metadata = _cairo_image_surface_get_metadata (surface);
+ metadata->has_alpha = (extrasamples == 1) || (spp == 4);
+ metadata->original_width = max_width;
+ metadata->original_width = max_height;
+
+ raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32));
+ if (raster == NULL) {
+ cairo_surface_destroy (surface);
+ TIFFClose (tif);
+ g_object_unref (handle.istream);
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ "Couldn't allocate memory for writing TIFF file");
+ return image;
+ }
+
+ if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) {
+ guchar *surface_row;
+ int line_step;
+ int x, y;
+ guchar r, g, b, a;
+ uint32 *src_pixel;
+
+ surface_row = _cairo_image_surface_flush_and_get_data (surface);
+ line_step = cairo_image_surface_get_stride (surface);
+ src_pixel = raster;
+ for (y = 0; y < image_height; y++) {
+ guchar *dest_pixel = surface_row;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ goto stop_loading;
+
+ for (x = 0; x < image_width; x++) {
+ r = TIFFGetR (*src_pixel);
+ g = TIFFGetG (*src_pixel);
+ b = TIFFGetB (*src_pixel);
+ a = TIFFGetA (*src_pixel);
+ CAIRO_SET_RGBA (dest_pixel, r, g, b, a);
+
+ dest_pixel += 4;
+ src_pixel += 1;
+ }
+
+ surface_row += line_step;
+ }
+ }
+
+stop_loading:
+
+ cairo_surface_mark_dirty (surface);
+ if (! g_cancellable_is_cancelled (cancellable))
+ gth_image_set_cairo_surface (image, surface);
+
+ _TIFFfree (raster);
+ cairo_surface_destroy (surface);
+ TIFFClose (tif);
+ g_object_unref (handle.istream);
+
+ return image;
+}
diff --git a/extensions/cairo_io/cairo-image-surface-tiff.h b/extensions/cairo_io/cairo-image-surface-tiff.h
new file mode 100644
index 0000000..cf1d812
--- /dev/null
+++ b/extensions/cairo_io/cairo-image-surface-tiff.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2013 Free Software Foundation, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAIRO_IMAGE_SURFACE_TIFF_H
+#define CAIRO_IMAGE_SURFACE_TIFF_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+GthImage * _cairo_image_surface_create_from_tiff (GInputStream *istream,
+ GthFileData *file_data,
+ int requested_size,
+ int *original_width,
+ int *original_height,
+ gboolean *loaded_original,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* CAIRO_IMAGE_SURFACE_TIFF_H */
diff --git a/extensions/cairo_io/main.c b/extensions/cairo_io/main.c
index 7d5ece1..1661b2a 100644
--- a/extensions/cairo_io/main.c
+++ b/extensions/cairo_io/main.c
@@ -25,6 +25,7 @@
#include "cairo-image-surface-jpeg.h"
#include "cairo-image-surface-png.h"
#include "cairo-image-surface-svg.h"
+#include "cairo-image-surface-tiff.h"
#include "cairo-image-surface-webp.h"
#include "cairo-image-surface-xcf.h"
#include "gth-image-saver-jpeg.h"
@@ -62,6 +63,13 @@ gthumb_extension_activate (void)
gth_main_register_type ("image-saver", GTH_TYPE_IMAGE_SAVER_TGA);
gth_main_register_type ("image-saver", GTH_TYPE_IMAGE_SAVER_TIFF);
+#ifdef HAVE_LIBTIFF
+ gth_main_register_image_loader_func (_cairo_image_surface_create_from_tiff,
+ GTH_IMAGE_FORMAT_CAIRO_SURFACE,
+ "image/tiff",
+ NULL);
+#endif
+
#ifdef HAVE_LIBWEBP
gth_main_register_image_loader_func (_cairo_image_surface_create_from_webp,
GTH_IMAGE_FORMAT_CAIRO_SURFACE,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]