io-tiff.c 18.9 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
/* GdkPixbuf library - TIFF image loader
3
 *
4
 * Copyright (C) 1999 Mark Crichton
5 6 7 8
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Mark Crichton <crichton@gimp.org>
 *          Federico Mena-Quintero <federico@gimp.org>
9
 *          Jonathan Blandford <jrb@redhat.com>
10
 *          Sren Sandmann <sandmann@daimi.au.dk>
11 12
 *
 * This library is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU Lesser General Public
14 15 16 17 18 19
 * 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
20
 * Lesser General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Lesser General Public
23 24 25
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
26 27 28 29 30
 */

/* Following code (almost) blatantly ripped from Imlib */

#include <config.h>
31 32
#include <stdlib.h>
#include <string.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
33
#ifdef HAVE_UNISTD_H
34
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
35
#endif
36
#include <tiffio.h>
37
#include <errno.h>
38
#include "gdk-pixbuf-private.h"
39
#include "gdk-pixbuf-io.h"
40

Tor Lillqvist's avatar
Tor Lillqvist committed
41 42
#ifdef G_OS_WIN32
#include <fcntl.h>
43 44
#include <io.h>
#define lseek(a,b,c) _lseek(a,b,c)
Tor Lillqvist's avatar
Tor Lillqvist committed
45 46
#define O_RDWR _O_RDWR
#endif
47 48


49 50
typedef struct _TiffContext TiffContext;
struct _TiffContext
51
{
52
	GdkPixbufModuleSizeFunc size_func;
53 54
	GdkPixbufModulePreparedFunc prepare_func;
	GdkPixbufModuleUpdatedFunc update_func;
55
	gpointer user_data;
56 57 58 59 60
        
        guchar *buffer;
        guint allocated;
        guint used;
        guint pos;
61 62 63
};


64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
/* There's no user data for the error handlers, so we just have to
 * put a big-ass lock on the whole TIFF loader
 */
G_LOCK_DEFINE_STATIC (tiff_loader);
static char *global_error = NULL;
static TIFFErrorHandler orig_error_handler = NULL;
static TIFFErrorHandler orig_warning_handler = NULL;

static void
tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
{
        /* Don't print anything; we should not be dumping junk to
         * stderr, since that may be bad for some apps.
         */

        /* libTIFF seems to occasionally warn about things that
         * are really errors, so maybe we should just call tiff_error_handler
         * here.
         */
}

static void
tiff_error_handler (const char *mod, const char *fmt, va_list ap)
{
        if (global_error) {                
                /* Blah, loader called us twice */
                return;
        }

        global_error = g_strdup_vprintf (fmt, ap);
}

static void
tiff_push_handlers (void)
{
        if (global_error)
                g_warning ("TIFF loader left crufty global_error around, FIXME");
        
        orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
        orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
}

static void
tiff_pop_handlers (void)
{
        if (global_error)
                g_warning ("TIFF loader left crufty global_error around, FIXME");
        
        TIFFSetErrorHandler (orig_error_handler);
        TIFFSetWarningHandler (orig_warning_handler);
}

static void
tiff_set_error (GError    **error,
                int         error_code,
                const char *msg)
{
        /* Take the error message from libtiff and merge it with
         * some context we provide.
         */
        if (global_error) {
126 127 128 129 130
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             error_code,
                             "%s%s%s", msg, ": ", global_error);

131 132 133
                g_free (global_error);
                global_error = NULL;
        }
134 135 136 137 138
        else {
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             error_code, msg);
        }
139 140 141 142
}



143 144 145 146 147
static void free_buffer (guchar *pixels, gpointer data)
{
	g_free (pixels);
}

148
static gboolean tifflibversion (int *major, int *minor, int *revision)
149
{
150 151 152 153
        if (sscanf (TIFFGetVersion(), 
                    "LIBTIFF, Version %d.%d.%d", 
                    major, minor, revision) < 3)
                return FALSE;
154

155
        return TRUE;
156 157
}

158
static GdkPixbuf *
159
tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
160
{
161
	guchar *pixels = NULL;
162
	gint width, height, rowstride, bytes;
163
	GdkPixbuf *pixbuf;
164 165 166
#if TIFFLIB_VERSION >= 20031226
        gint major, minor, revision;
#endif
167

168 169 170 171
        /* We're called with the lock held. */
        
        g_return_val_if_fail (global_error == NULL, NULL);

172
	if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width) || global_error) {
173 174 175 176 177 178
                tiff_set_error (error,
                                GDK_PIXBUF_ERROR_FAILED,
                                _("Could not get image width (bad TIFF file)"));
                return NULL;
        }
        
179
        if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height) || global_error) {
180 181 182 183 184 185
                tiff_set_error (error,
                                GDK_PIXBUF_ERROR_FAILED,
                                _("Could not get image height (bad TIFF file)"));
                return NULL;
        }

186
        if (width <= 0 || height <= 0) {
187 188 189
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
190 191
                             _("Width or height of TIFF image is zero"));
                return NULL;                
192
        }
193
        
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
        rowstride = width * 4;
        if (rowstride / 4 != width) { /* overflow */
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                             _("Dimensions of TIFF image too large"));
                return NULL;                
        }
        
        bytes = height * rowstride;
        if (bytes / rowstride != height) { /* overflow */
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                             _("Dimensions of TIFF image too large"));
                return NULL;                
        }

212 213 214 215 216 217 218 219 220
	if (context && context->size_func) {
                gint w = width;
                gint h = height;
		(* context->size_func) (&w, &h, context->user_data);
                
                if (w == 0 || h == 0)
                    return NULL;
        }

221 222 223
        pixels = g_try_malloc (bytes);

        if (!pixels) {
224 225 226 227
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                             _("Insufficient memory to open TIFF file"));
228
                return NULL;
229
        }
230

231 232 233 234 235
	pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
                                           width, height, rowstride,
                                           free_buffer, NULL);
        if (!pixbuf) {
                g_free (pixels);
236 237 238 239
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                             _("Insufficient memory to open TIFF file"));
240
                return NULL;
241 242 243 244 245 246
        }

        G_UNLOCK (tiff_loader);
	if (context)
		(* context->prepare_func) (pixbuf, NULL, context->user_data);
        G_LOCK (tiff_loader);
247

248 249 250 251 252 253 254 255 256 257 258
#if TIFFLIB_VERSION >= 20031226
        if (tifflibversion(&major, &minor, &revision) && major == 3 &&
            (minor > 6 || (minor == 6 && revision > 0))) {                
                if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) 
                {
                        tiff_set_error (error,
                                        GDK_PIXBUF_ERROR_FAILED,
                                        _("Failed to load RGB data from TIFF file"));
                        g_object_unref (pixbuf);
                        return NULL;
                }
259

260
#if G_BYTE_ORDER == G_BIG_ENDIAN
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
                /* Turns out that the packing used by TIFFRGBAImage depends on 
                 * the host byte order... 
                 */ 
                while (pixels < pixbuf->pixels + bytes) {
                        uint32 pixel = *(uint32 *)pixels;
                        int r = TIFFGetR(pixel);
                        int g = TIFFGetG(pixel);
                        int b = TIFFGetB(pixel);
                        int a = TIFFGetA(pixel);
                        *pixels++ = r;
                        *pixels++ = g;
                        *pixels++ = b;
                        *pixels++ = a;
                }
#endif
Matthias Clasen's avatar
Matthias Clasen committed
276
        }
277
        else 
Matthias Clasen's avatar
Matthias Clasen committed
278
#endif
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
              {
                uint32 *rast, *tmp_rast;
                gint x, y;
                guchar *tmppix;

                /* Yes, it needs to be _TIFFMalloc... */
                rast = (uint32 *) _TIFFmalloc (width * height * sizeof (uint32));
                if (!rast) {
                        g_set_error (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to open TIFF file"));
                        g_object_unref (pixbuf);
                        
                        return NULL;
                }
                if (!TIFFReadRGBAImage (tiff, width, height, rast, 1) || global_error) {
                        tiff_set_error (error,
                                        GDK_PIXBUF_ERROR_FAILED,
                                        _("Failed to load RGB data from TIFF file"));
                        g_object_unref (pixbuf);
                        _TIFFfree (rast);
                        
                        return NULL;
                }
                
                pixels = gdk_pixbuf_get_pixels (pixbuf);
                
                g_assert (pixels);
                
                tmppix = pixels;
                
                for (y = 0; y < height; y++) {
                        /* Unexplainable...are tiffs backwards? */
                        /* Also looking at the GIMP plugin, this
                         * whole reading thing can be a bit more
                         * robust.
                         */
                        tmp_rast = rast + ((height - y - 1) * width);
                        for (x = 0; x < width; x++) {
                                tmppix[0] = TIFFGetR (*tmp_rast);
                                tmppix[1] = TIFFGetG (*tmp_rast);
                                tmppix[2] = TIFFGetB (*tmp_rast);
                                tmppix[3] = TIFFGetA (*tmp_rast);
                                tmp_rast++;
                                tmppix += 4;
                        }
                }
                
                _TIFFfree (rast);
             }
Matthias Clasen's avatar
Matthias Clasen committed
330

331 332
        G_UNLOCK (tiff_loader);
	if (context)
333
		(* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
334 335 336
        G_LOCK (tiff_loader);
        
        return pixbuf;
337
}
338

339

340

341
/* Static loader */
342

343 344
static GdkPixbuf *
gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
345
{
346 347 348 349 350 351 352 353 354 355 356
        TIFF *tiff;
        int fd;
        GdkPixbuf *pixbuf;
        
        g_return_val_if_fail (f != NULL, NULL);

        G_LOCK (tiff_loader);

        tiff_push_handlers ();
        
        fd = fileno (f);
357 358 359 360 361 362 363

        /* On OSF, apparently fseek() works in some on-demand way, so
         * the fseek gdk_pixbuf_new_from_file() doesn't work here
         * since we are using the raw file descriptor. So, we call lseek() on the fd
         * before using it. (#60840)
         */
        lseek (fd, 0, SEEK_SET);
364 365
        tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
        
366 367 368 369
        if (!tiff || global_error) {
                tiff_set_error (error,
                                GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                _("Failed to open TIFF image"));
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
                tiff_pop_handlers ();

                G_UNLOCK (tiff_loader);
                return NULL;
        }

        pixbuf = tiff_image_parse (tiff, NULL, error);
        
        TIFFClose (tiff);
        if (global_error) {
                tiff_set_error (error,
                                GDK_PIXBUF_ERROR_FAILED,
                                _("TIFFClose operation failed"));
        }
        
        tiff_pop_handlers ();

        G_UNLOCK (tiff_loader);
        
        return pixbuf;
390
}
391

392 393 394


/* Progressive loader */
395

396
static gpointer
397 398 399
gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
                                   GdkPixbufModulePreparedFunc prepare_func,
				   GdkPixbufModuleUpdatedFunc update_func,
Havoc Pennington's avatar
Havoc Pennington committed
400 401
				   gpointer user_data,
                                   GError **error)
402
{
403 404 405
	TiffContext *context;
        
	context = g_new0 (TiffContext, 1);
406
	context->size_func = size_func;
407
	context->prepare_func = prepare_func;
Jonathan Blandford's avatar
Jonathan Blandford committed
408
	context->update_func = update_func;
409
	context->user_data = user_data;
410 411 412 413 414 415 416
        context->buffer = NULL;
        context->allocated = 0;
        context->used = 0;
        context->pos = 0;
        
	return context;
}
417

418 419 420 421 422 423 424 425 426 427 428 429
static tsize_t
tiff_read (thandle_t handle, tdata_t buf, tsize_t size)
{
        TiffContext *context = (TiffContext *)handle;
        
        if (context->pos + size > context->used)
                return 0;
        
        memcpy (buf, context->buffer + context->pos, size);
        context->pos += size;
        return size;
}
430

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
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)
{
        TiffContext *context = (TiffContext *)handle;
        
        switch (whence) {
        case SEEK_SET:
                if (offset > context->used || offset < 0)
                        return -1;
                context->pos = offset;
                break;
        case SEEK_CUR:
                if (offset + context->pos >= context->used)
                        return -1;
                context->pos += offset;
                break;
        case SEEK_END:
                if (offset + context->used > context->used)
                        return -1;
                context->pos = context->used + offset;
                break;
        default:
                return -1;
                break;
        }
        return context->pos;
}

static int
tiff_close (thandle_t context)
{
        return 0;
}

static toff_t
tiff_size (thandle_t handle)
{
        TiffContext *context = (TiffContext *)handle;
        
        return context->used;
}

static int
tiff_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
{
        TiffContext *context = (TiffContext *)handle;
        
        *buf = context->buffer;
        *size = context->used;
        
        return 0;
}

static void
tiff_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
{
493 494
}

495 496 497
static gboolean
gdk_pixbuf__tiff_image_stop_load (gpointer data,
                                  GError **error)
498
{
499 500 501
        TiffContext *context = data;
        TIFF *tiff;
        gboolean retval;
502
        
503
        g_return_val_if_fail (data != NULL, FALSE);
504

505 506 507 508 509 510 511 512 513
        G_LOCK (tiff_loader);
        
        tiff_push_handlers ();
        
        tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data, 
                               tiff_read, tiff_write, 
                               tiff_seek, tiff_close, 
                               tiff_size, 
                               tiff_map_file, tiff_unmap_file);
514 515 516 517
        if (!tiff || global_error) {
                tiff_set_error (error,
                                GDK_PIXBUF_ERROR_FAILED,
                                _("Failed to load TIFF image"));
518 519
                retval = FALSE;
        } else {
520
                GdkPixbuf *pixbuf;
521 522 523
                
                pixbuf = tiff_image_parse (tiff, context, error);
                if (pixbuf)
524
                        g_object_unref (pixbuf);
525
                retval = pixbuf != NULL;
526 527 528 529 530
                if (global_error)
                        {
                                tiff_set_error (error,
                                                GDK_PIXBUF_ERROR_FAILED,
                                                _("Failed to load TIFF image"));
531 532
                                tiff_pop_handlers ();

533 534
                                retval = FALSE;
                        }
535
        }
536

537 538 539
        if (tiff)
                TIFFClose (tiff);

540
        g_assert (!global_error);
541 542 543 544 545
        
        g_free (context->buffer);
        g_free (context);

        tiff_pop_handlers ();
546

547 548 549 550
        G_UNLOCK (tiff_loader);

        return retval;
}
551

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
static gboolean
make_available_at_least (TiffContext *context, guint needed)
{
        guchar *new_buffer = NULL;
        guint need_alloc;
        
        need_alloc = context->used + needed;
        if (need_alloc > context->allocated) {
                guint new_size = 1;
                while (new_size < need_alloc)
                        new_size *= 2;
                
                new_buffer = g_try_realloc (context->buffer, new_size);
                if (new_buffer) {
                        context->buffer = new_buffer;
                        context->allocated = new_size;
                        return TRUE;
                }
                return FALSE;
        }
572
        return TRUE;
573 574
}

575 576 577
static gboolean
gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
                                       guint size, GError **error)
578
{
579 580
	TiffContext *context = (TiffContext *) data;
        
581
	g_return_val_if_fail (data != NULL, FALSE);
582 583
        
        if (!make_available_at_least (context, size)) {
584
                g_set_error (error,
585 586 587 588 589 590 591 592
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                             _("Insufficient memory to open TIFF file"));
                return FALSE;
        }
        
        memcpy (context->buffer + context->used, buf, size);
        context->used += size;
593 594
	return TRUE;
}
595

596
void
597
MODULE_ENTRY (tiff, fill_vtable) (GdkPixbufModule *module)
598
{
599 600 601 602
        module->load = gdk_pixbuf__tiff_image_load;
        module->begin_load = gdk_pixbuf__tiff_image_begin_load;
        module->stop_load = gdk_pixbuf__tiff_image_stop_load;
        module->load_increment = gdk_pixbuf__tiff_image_load_increment;
603
}
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628

void
MODULE_ENTRY (tiff, fill_info) (GdkPixbufFormat *info)
{
        static GdkPixbufModulePattern signature[] = {
                { "MM \x2a", "  z ", 100 },
                { "II\x2a ", "   z", 100 },
                { NULL, NULL, 0 }
        };
	static gchar * mime_types[] = {
		"image/tiff",
		NULL
	};
	static gchar * extensions[] = {
		"tiff",
		"tif",
		NULL
	};

	info->name = "tiff";
        info->signature = signature;
	info->description = N_("The TIFF image format");
	info->mime_types = mime_types;
	info->extensions = extensions;
	info->flags = 0;
629
	info->license = "LGPL";
630
}