4 * Copyright (C) 2008 - 2011 The Geeqie Team
6 * Author: Vladimir Nadvornik
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
13 /* based on code from GdkPixbuf library - TIFF image loader
15 * Copyright (C) 1999 Mark Crichton
16 * Copyright (C) 1999 The Free Software Foundation
18 * Authors: Mark Crichton <crichton@gimp.org>
19 * Federico Mena-Quintero <federico@gimp.org>
20 * Jonathan Blandford <jrb@redhat.com>
21 * S�ren Sandmann <sandmann@daimi.au.dk>
23 * This library is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU Lesser General Public
25 * License as published by the Free Software Foundation; either
26 * version 2 of the License, or (at your option) any later version.
28 * This library is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31 * Lesser General Public License for more details.
33 * You should have received a copy of the GNU Lesser General Public
34 * License along with this library; if not, write to the
35 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
36 * Boston, MA 02111-1307, USA.
41 #include "image-load.h"
42 #include "image_load_tiff.h"
48 typedef struct _ImageLoaderTiff ImageLoaderTiff;
49 struct _ImageLoaderTiff {
50 ImageLoaderBackendCbAreaUpdated area_updated_cb;
51 ImageLoaderBackendCbSize size_cb;
52 ImageLoaderBackendCbAreaPrepared area_prepared_cb;
57 guint requested_width;
58 guint requested_height;
67 static void free_buffer (guchar *pixels, gpointer data)
73 tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
75 ImageLoaderTiff *context = (ImageLoaderTiff *)handle;
77 if (context->pos + size > context->used)
80 memcpy (buf, context->buffer + context->pos, size);
86 tiff_load_write (thandle_t handle, tdata_t buf, tsize_t size)
92 tiff_load_seek (thandle_t handle, toff_t offset, int whence)
94 ImageLoaderTiff *context = (ImageLoaderTiff *)handle;
99 if (offset > context->used)
101 context->pos = offset;
104 if (offset + context->pos >= context->used)
106 context->pos += offset;
109 if (offset + context->used > context->used)
111 context->pos = context->used + offset;
121 tiff_load_close (thandle_t context)
127 tiff_load_size (thandle_t handle)
129 ImageLoaderTiff *context = (ImageLoaderTiff *)handle;
130 return context->used;
134 tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
136 ImageLoaderTiff *context = (ImageLoaderTiff *)handle;
138 *buf = (tdata_t *) context->buffer;
139 *size = context->used;
145 tiff_load_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
149 static gboolean image_loader_tiff_load (gpointer loader, const guchar *buf, gsize count, GError **error)
151 ImageLoaderTiff *lt = (ImageLoaderTiff *) loader;
154 guchar *pixels = NULL;
155 gint width, height, rowstride, bytes;
162 TIFFSetWarningHandler(NULL);
164 tiff = TIFFClientOpen ( "libtiff-geeqie", "r", lt,
165 tiff_load_read, tiff_load_write,
166 tiff_load_seek, tiff_load_close,
168 tiff_load_map_file, tiff_load_unmap_file);
171 DEBUG_1("Failed to open TIFF image");
176 if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width))
178 DEBUG_1("Could not get image width (bad TIFF file)");
183 if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height))
185 DEBUG_1("Could not get image height (bad TIFF file)");
190 if (width <= 0 || height <= 0)
192 DEBUG_1("Width or height of TIFF image is zero");
197 rowstride = width * 4;
198 if (rowstride / 4 != width)
200 DEBUG_1("Dimensions of TIFF image too large");
205 bytes = height * rowstride;
206 if (bytes / rowstride != height)
208 DEBUG_1("Dimensions of TIFF image too large");
213 lt->requested_width = width;
214 lt->requested_height = height;
215 lt->size_cb(loader, lt->requested_width, lt->requested_height, lt->data);
217 pixels = g_try_malloc (bytes);
221 DEBUG_1("Insufficient memory to open TIFF file");
226 lt->pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
227 width, height, rowstride,
232 DEBUG_1("Insufficient memory to open TIFF file");
237 lt->area_prepared_cb(loader, lt->data);
239 if (TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
243 guchar *wrk_line = (guchar *)g_malloc(width * sizeof (uint32));
245 for (row = 0; row < height; row += rowsperstrip)
247 int rows_to_write, i_row;
253 /* Read the strip into an RGBA array */
254 if (!TIFFReadRGBAStrip(tiff, row, (uint32 *)(pixels + row * rowstride))) {
259 * Figure out the number of scanlines actually in this strip.
261 if (row + (int)rowsperstrip > height)
262 rows_to_write = height - row;
264 rows_to_write = rowsperstrip;
267 * For some reason the TIFFReadRGBAStrip() function chooses the
268 * lower left corner as the origin. Vertically mirror scanlines.
270 for (i_row = 0; i_row < rows_to_write / 2; i_row++)
272 guchar *top_line, *bottom_line;
274 top_line = pixels + (row + i_row) * rowstride;
275 bottom_line = pixels + (row + rows_to_write - i_row - 1) * rowstride;
277 memcpy(wrk_line, top_line, 4*width);
278 memcpy(top_line, bottom_line, 4*width);
279 memcpy(bottom_line, wrk_line, 4*width);
281 lt->area_updated_cb(loader, 0, row, width, rows_to_write, lt->data);
287 /* fallback, tiled tiff */
288 if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1))
294 #if G_BYTE_ORDER == G_BIG_ENDIAN
295 /* Turns out that the packing used by TIFFRGBAImage depends on
296 * the host byte order...
299 guchar *ptr = pixels;
300 while (ptr < pixels + bytes)
302 uint32 pixel = *(uint32 *)ptr;
303 int r = TIFFGetR(pixel);
304 int g = TIFFGetG(pixel);
305 int b = TIFFGetB(pixel);
306 int a = TIFFGetA(pixel);
315 lt->area_updated_cb(loader, 0, 0, width, height, lt->data);
323 static gpointer image_loader_tiff_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
325 ImageLoaderTiff *loader = g_new0(ImageLoaderTiff, 1);
327 loader->area_updated_cb = area_updated_cb;
328 loader->size_cb = size_cb;
329 loader->area_prepared_cb = area_prepared_cb;
331 return (gpointer) loader;
335 static void image_loader_tiff_set_size(gpointer loader, int width, int height)
337 ImageLoaderTiff *lt = (ImageLoaderTiff *) loader;
338 lt->requested_width = width;
339 lt->requested_height = height;
342 static GdkPixbuf* image_loader_tiff_get_pixbuf(gpointer loader)
344 ImageLoaderTiff *lt = (ImageLoaderTiff *) loader;
348 static gchar* image_loader_tiff_get_format_name(gpointer loader)
350 return g_strdup("tiff");
352 static gchar** image_loader_tiff_get_format_mime_types(gpointer loader)
354 static gchar *mime[] = {"image/tiff", NULL};
355 return g_strdupv(mime);
358 static gboolean image_loader_tiff_close(gpointer loader, GError **error)
363 static void image_loader_tiff_abort(gpointer loader)
365 ImageLoaderTiff *lt = (ImageLoaderTiff *) loader;
369 static void image_loader_tiff_free(gpointer loader)
371 ImageLoaderTiff *lt = (ImageLoaderTiff *) loader;
372 if (lt->pixbuf) g_object_unref(lt->pixbuf);
377 void image_loader_backend_set_tiff(ImageLoaderBackend *funcs)
379 funcs->loader_new = image_loader_tiff_new;
380 funcs->set_size = image_loader_tiff_set_size;
381 funcs->load = image_loader_tiff_load;
383 funcs->get_pixbuf = image_loader_tiff_get_pixbuf;
384 funcs->close = image_loader_tiff_close;
385 funcs->abort = image_loader_tiff_abort;
386 funcs->free = image_loader_tiff_free;
388 funcs->get_format_name = image_loader_tiff_get_format_name;
389 funcs->get_format_mime_types = image_loader_tiff_get_format_mime_types;
395 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */