2 * Copyright (C) 1999 Mark Crichton
3 * Copyright (C) 1999 The Free Software Foundation
4 * Copyright (C) 2004 John Ellis
5 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * Authors: Mark Crichton <crichton@gimp.org>
8 * Federico Mena-Quintero <federico@gimp.org>
9 * Jonathan Blandford <jrb@redhat.com>
10 * S�ren Sandmann <sandmann@daimi.au.dk>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "image-load-tiff.h"
38 #include <gdk-pixbuf/gdk-pixbuf.h>
39 #include <glib-object.h>
45 #include "image-load.h"
50 struct ImageLoaderTiff : public ImageLoaderBackend
53 ~ImageLoaderTiff() override;
55 void init(AreaUpdatedCb area_updated_cb, SizePreparedCb size_prepared_cb, AreaPreparedCb area_prepared_cb, gpointer data) override;
56 void set_size(int width, int height) override;
57 gboolean write(const guchar *buf, gsize &chunk_size, gsize count, GError **error) override;
58 GdkPixbuf *get_pixbuf() override;
59 void abort() override;
60 gchar *get_format_name() override;
61 gchar **get_format_mime_types() override;
62 void set_page_num(gint page_num) override;
63 gint get_page_total() override;
66 AreaUpdatedCb area_updated_cb;
67 SizePreparedCb size_prepared_cb;
68 AreaPreparedCb area_prepared_cb;
72 guint requested_width;
73 guint requested_height;
88 void free_buffer (guchar *pixels, gpointer)
93 tsize_t tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
95 auto context = static_cast<GqTiffContext *>(handle);
97 if (context->pos + size > context->used)
100 memcpy (buf, context->buffer + context->pos, size);
101 context->pos += size;
105 tsize_t tiff_load_write (thandle_t, tdata_t, tsize_t)
110 toff_t tiff_load_seek (thandle_t handle, toff_t offset, int whence)
112 auto context = static_cast<GqTiffContext *>(handle);
117 if (offset > context->used)
119 context->pos = offset;
122 if (offset + context->pos >= context->used)
124 context->pos += offset;
127 if (offset + context->used > context->used)
129 context->pos = context->used + offset;
138 int tiff_load_close (thandle_t)
143 toff_t tiff_load_size (thandle_t handle)
145 auto context = static_cast<GqTiffContext *>(handle);
146 return context->used;
149 int tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
151 auto context = static_cast<GqTiffContext *>(handle);
153 *buf = const_cast<guchar *>(context->buffer);
154 *size = context->used;
159 void tiff_load_unmap_file (thandle_t, tdata_t, toff_t)
163 gboolean ImageLoaderTiff::write(const guchar *buf, gsize &chunk_size, gsize count, GError **)
166 guchar *pixels = nullptr;
171 guint32 rowsperstrip;
174 TIFFSetWarningHandler(nullptr);
176 GqTiffContext context{buf, count, 0};
177 tiff = TIFFClientOpen ( "libtiff-geeqie", "r", &context,
178 tiff_load_read, tiff_load_write,
179 tiff_load_seek, tiff_load_close,
181 tiff_load_map_file, tiff_load_unmap_file);
184 DEBUG_1("Failed to open TIFF image");
190 } while (TIFFReadDirectory(tiff));
192 page_total = dircount;
194 if (!TIFFSetDirectory(tiff, page_num))
196 DEBUG_1("Failed to open TIFF image");
201 if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width))
203 DEBUG_1("Could not get image width (bad TIFF file)");
208 if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height))
210 DEBUG_1("Could not get image height (bad TIFF file)");
215 if (width <= 0 || height <= 0)
217 DEBUG_1("Width or height of TIFF image is zero");
222 rowstride = width * 4;
223 if (rowstride / 4 != width)
225 DEBUG_1("Dimensions of TIFF image too large: width %d", width);
230 bytes = static_cast<size_t>(height) * rowstride;
231 if (bytes / rowstride != static_cast<size_t>(height))
233 DEBUG_1("Dimensions of TIFF image too large: height %d", height);
238 requested_width = width;
239 requested_height = height;
240 size_prepared_cb(nullptr, requested_width, requested_height, data);
242 pixels = static_cast<guchar *>(g_try_malloc (bytes));
246 DEBUG_1("Insufficient memory to open TIFF file: need %zu", bytes);
251 pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
252 width, height, rowstride,
253 free_buffer, nullptr);
257 DEBUG_1("Insufficient memory to open TIFF file");
262 area_prepared_cb(nullptr, data);
264 if (TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
268 const size_t line_bytes = width * sizeof(guint32);
269 auto wrk_line = static_cast<guchar *>(g_malloc(line_bytes));
271 for (row = 0; row < height; row += rowsperstrip)
280 /* Read the strip into an RGBA array */
281 if (!TIFFReadRGBAStrip(tiff, row, reinterpret_cast<guint32 *>(pixels + row * rowstride))) {
286 * Figure out the number of scanlines actually in this strip.
288 if (row + static_cast<int>(rowsperstrip) > height)
289 rows_to_write = height - row;
291 rows_to_write = rowsperstrip;
294 * For some reason the TIFFReadRGBAStrip() function chooses the
295 * lower left corner as the origin. Vertically mirror scanlines.
297 for (i_row = 0; i_row < rows_to_write / 2; i_row++)
302 top_line = pixels + (row + i_row) * rowstride;
303 bottom_line = pixels + (row + rows_to_write - i_row - 1) * rowstride;
305 memcpy(wrk_line, top_line, line_bytes);
306 memcpy(top_line, bottom_line, line_bytes);
307 memcpy(bottom_line, wrk_line, line_bytes);
309 area_updated_cb(nullptr, 0, row, width, rows_to_write, data);
315 /* fallback, tiled tiff */
316 if (!TIFFReadRGBAImageOriented (tiff, width, height, reinterpret_cast<guint32 *>(pixels), ORIENTATION_TOPLEFT, 1))
322 #if G_BYTE_ORDER == G_BIG_ENDIAN
323 /* Turns out that the packing used by TIFFRGBAImage depends on
324 * the host byte order...
327 guchar *ptr = pixels;
328 while (ptr < pixels + bytes)
330 guint32 pixel = *(guint32 *)ptr;
331 int r = TIFFGetR(pixel);
332 int g = TIFFGetG(pixel);
333 int b = TIFFGetB(pixel);
334 int a = TIFFGetA(pixel);
343 area_updated_cb(nullptr, 0, 0, width, height, data);
352 void ImageLoaderTiff::init(AreaUpdatedCb area_updated_cb, SizePreparedCb size_prepared_cb, AreaPreparedCb area_prepared_cb, gpointer data)
354 this->area_updated_cb = area_updated_cb;
355 this->size_prepared_cb = size_prepared_cb;
356 this->area_prepared_cb = area_prepared_cb;
360 void ImageLoaderTiff::set_size(int width, int height)
362 requested_width = width;
363 requested_height = height;
366 GdkPixbuf *ImageLoaderTiff::get_pixbuf()
371 gchar *ImageLoaderTiff::get_format_name()
373 return g_strdup("tiff");
376 gchar **ImageLoaderTiff::get_format_mime_types()
378 static const gchar *mime[] = {"image/tiff", nullptr};
379 return g_strdupv(const_cast<gchar **>(mime));
382 void ImageLoaderTiff::abort()
387 ImageLoaderTiff::~ImageLoaderTiff()
389 if (pixbuf) g_object_unref(pixbuf);
392 void ImageLoaderTiff::set_page_num(gint page_num)
394 this->page_num = page_num;
397 gint ImageLoaderTiff::get_page_total()
404 std::unique_ptr<ImageLoaderBackend> get_image_loader_backend_tiff()
406 return std::make_unique<ImageLoaderTiff>();
410 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */