io-tiff.c 33.8 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
 *          S�ren Sandmann <sandmann@daimi.au.dk>
11 12
 *          Christian Dywan <christian@lanedo.com>
 *          Mukund Sivaraman <muks@banu.com>
13 14
 *
 * This library is free software; you can redistribute it and/or
15
 * modify it under the terms of the GNU Lesser General Public
16 17 18 19 20 21
 * 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
22
 * Lesser General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public
25
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 27 28 29
 */

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

30
#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 "fallback-c89.c"
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
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.
         */
}

static void
72
tiff_set_handlers (void)
73
{
74 75
        TIFFSetErrorHandler (tiff_warning_handler);
        TIFFSetWarningHandler (tiff_warning_handler);
76 77 78 79
}



80 81 82 83 84
static void free_buffer (guchar *pixels, gpointer data)
{
	g_free (pixels);
}

85
static GdkPixbuf *
86
tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
87
{
88
	guchar *pixels = NULL;
89
	gint width, height, rowstride, bytes;
90
	GdkPixbuf *pixbuf;
91
	guint16 bits_per_sample = 0;
92 93
	uint16 orientation = 0;
	uint16 transform = 0;
94
        uint16 codec;
95 96 97
        gchar *icc_profile_base64;
        const gchar *icc_profile;
        guint icc_profile_size;
98 99
        uint16 resolution_unit;
        gchar *density_str;
100
        gint retval;
101

102 103
        /* We're called with the lock held. */

104 105 106 107 108
	if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width)) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Could not get image width (bad TIFF file)"));
109 110 111
                return NULL;
        }
        
112 113 114 115 116
        if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height)) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Could not get image height (bad TIFF file)"));
117 118 119
                return NULL;
        }

120
        if (width <= 0 || height <= 0) {
121 122 123 124
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Width or height of TIFF image is zero"));
125
                return NULL;                
126
        }
127 128

        if (width > G_MAXINT / 4) { /* overflow */
129 130 131 132
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Dimensions of TIFF image too large"));
133 134
                return NULL;                
        }
135 136 137 138

        rowstride = width * 4;

        if (height > G_MAXINT / rowstride) { /* overflow */
139 140 141 142
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Dimensions of TIFF image too large"));
143 144 145
                return NULL;                
        }

146 147
        bytes = height * rowstride;

148 149 150 151 152
	if (context && context->size_func) {
                gint w = width;
                gint h = height;
		(* context->size_func) (&w, &h, context->user_data);
                
153 154 155 156 157
		/* This is a signal that this function is being called
		   to support gdk_pixbuf_get_file_info, so we can stop
		   parsing the tiff file at this point. It is not an
		   error condition. */

158
                if (w == 0 || h == 0)
159 160 161
                    return NULL;
        }

162 163 164
        pixels = g_try_malloc (bytes);

        if (!pixels) {
165 166 167 168
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to open TIFF file"));
169
                return NULL;
170
        }
171

172 173 174 175 176
	pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
                                           width, height, rowstride,
                                           free_buffer, NULL);
        if (!pixbuf) {
                g_free (pixels);
177 178 179 180
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to open TIFF file"));
181
                return NULL;
182 183
        }

184 185 186 187 188 189 190 191 192
        /* Save the bits per sample as an option since pixbufs are
           expected to be always 8 bits per sample. */
        TIFFGetField (tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
        if (bits_per_sample > 0) {
                gchar str[5];
                g_snprintf (str, sizeof (str), "%d", bits_per_sample);
                gdk_pixbuf_set_option (pixbuf, "bits-per-sample", str);
        }

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
	/* Set the "orientation" key associated with this image. libtiff 
	   orientation handling is odd, so further processing is required
	   by higher-level functions based on this tag. If the embedded
	   orientation tag is 1-4, libtiff flips/mirrors the image as
	   required, and no client processing is required - so we report 
	   no orientation. Orientations 5-8 require rotations which would 
	   swap the width and height of the image. libtiff does not do this. 
	   Instead it interprets orientations 5-8 the same as 1-4. 
	   See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548.
	   To correct for this, the client must apply the transform normally
	   used for orientation 5 to both orientations 5 and 7, and apply
	   the transform normally used for orientation 7 for both
	   orientations 6 and 8. Then everythings works out OK! */
	
	TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation);

	switch (orientation) {
		case 5:
		case 7:
			transform = 5;
			break;
		case 6:
		case 8:
			transform = 7;
			break;
		default:
			transform = 0;
			break;
	}

	if (transform > 0 ) {
		gchar str[5];
225
		g_snprintf (str, sizeof (str), "%d", transform);
226 227 228
		gdk_pixbuf_set_option (pixbuf, "orientation", str);
	}

229 230 231 232 233 234 235
        TIFFGetField (tiff, TIFFTAG_COMPRESSION, &codec);
        if (codec > 0) {
          gchar str[5];
          g_snprintf (str, sizeof (str), "%d", codec);
          gdk_pixbuf_set_option (pixbuf, "compression", str);
        }

236 237 238 239 240 241 242 243
        /* Extract embedded ICC profile */
        retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile);
        if (retval == 1) {
                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
                gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
                g_free (icc_profile_base64);
        }

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
        retval = TIFFGetField (tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit);
        if (retval == 1) {
                float x_resolution = 0, y_resolution = 0;

                TIFFGetField (tiff, TIFFTAG_XRESOLUTION, &x_resolution);
                TIFFGetField (tiff, TIFFTAG_YRESOLUTION, &y_resolution);

                switch (resolution_unit) {
                case RESUNIT_INCH:
                        density_str = g_strdup_printf ("%d", (int) round (x_resolution));
                        gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
                        g_free (density_str);
                        density_str = g_strdup_printf ("%d", (int) round (y_resolution));
                        gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
                        g_free (density_str);
                        break;
                case RESUNIT_CENTIMETER:
                        density_str = g_strdup_printf ("%d", DPCM_TO_DPI (x_resolution));
                        gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
                        g_free (density_str);
                        density_str = g_strdup_printf ("%d", DPCM_TO_DPI (y_resolution));
                        gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
                        g_free (density_str);
                        break;
                }
        }

271
	if (context && context->prepare_func)
272
		(* context->prepare_func) (pixbuf, NULL, context->user_data);
273

274 275 276 277 278
	if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1)) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Failed to load RGB data from TIFF file"));
279 280 281
		g_object_unref (pixbuf);
		return NULL;
	}
282

283 284 285 286 287
	/* Flag multi-page documents, because this loader only handles the
	   first page. The client app may wish to warn the user. */
        if (TIFFReadDirectory (tiff))
                gdk_pixbuf_set_option (pixbuf, "multipage", "yes");

288
#if G_BYTE_ORDER == G_BIG_ENDIAN
289 290 291 292 293 294 295 296 297 298 299 300 301 302
	/* 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;
	}
303
#endif
Matthias Clasen's avatar
Matthias Clasen committed
304

305
	if (context && context->update_func)
306
		(* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
307

308
        return pixbuf;
309
}
310

311

312

313
/* Static loader */
314

315 316
static GdkPixbuf *
gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
317
{
318 319 320 321 322 323
        TIFF *tiff;
        int fd;
        GdkPixbuf *pixbuf;
        
        g_return_val_if_fail (f != NULL, NULL);

324 325
        tiff_set_handlers ();

326
        fd = fileno (f);
327 328 329 330 331 332 333

        /* 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);
334 335
        tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");

336 337 338 339 340
        if (!tiff) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Failed to open TIFF image"));
341 342 343 344
                return NULL;
        }

        pixbuf = tiff_image_parse (tiff, NULL, error);
345

346 347 348
        TIFFClose (tiff);

        return pixbuf;
349
}
350

351 352 353


/* Progressive loader */
354

355
static gpointer
356 357 358
gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
                                   GdkPixbufModulePreparedFunc prepare_func,
				   GdkPixbufModuleUpdatedFunc update_func,
Havoc Pennington's avatar
Havoc Pennington committed
359 360
				   gpointer user_data,
                                   GError **error)
361
{
362 363 364
	TiffContext *context;
        
	context = g_new0 (TiffContext, 1);
365
	context->size_func = size_func;
366
	context->prepare_func = prepare_func;
Jonathan Blandford's avatar
Jonathan Blandford committed
367
	context->update_func = update_func;
368
	context->user_data = user_data;
369 370 371 372 373 374 375
        context->buffer = NULL;
        context->allocated = 0;
        context->used = 0;
        context->pos = 0;
        
	return context;
}
376

377
static tsize_t
378
tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
379 380 381 382 383 384 385 386 387 388
{
        TiffContext *context = (TiffContext *)handle;
        
        if (context->pos + size > context->used)
                return 0;
        
        memcpy (buf, context->buffer + context->pos, size);
        context->pos += size;
        return size;
}
389

390
static tsize_t
391
tiff_load_write (thandle_t handle, tdata_t buf, tsize_t size)
392 393 394 395 396
{
        return -1;
}

static toff_t
397
tiff_load_seek (thandle_t handle, toff_t offset, int whence)
398 399 400 401 402
{
        TiffContext *context = (TiffContext *)handle;
        
        switch (whence) {
        case SEEK_SET:
Matthias Clasen's avatar
Matthias Clasen committed
403
                if (offset > context->used)
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
                        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;
        }
        return context->pos;
}

static int
424
tiff_load_close (thandle_t context)
425 426 427 428 429
{
        return 0;
}

static toff_t
430
tiff_load_size (thandle_t handle)
431 432 433 434 435 436 437
{
        TiffContext *context = (TiffContext *)handle;
        
        return context->used;
}

static int
438
tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
439 440 441 442 443 444 445 446 447 448
{
        TiffContext *context = (TiffContext *)handle;
        
        *buf = context->buffer;
        *size = context->used;
        
        return 0;
}

static void
449
tiff_load_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
450
{
451 452
}

453 454 455
static gboolean
gdk_pixbuf__tiff_image_stop_load (gpointer data,
                                  GError **error)
456
{
457 458
        TiffContext *context = data;
        TIFF *tiff;
459
        gboolean retval = FALSE;
460
        
461
        g_return_val_if_fail (data != NULL, FALSE);
462

463 464
        tiff_set_handlers ();

465
        tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data, 
466 467 468 469
                               tiff_load_read, tiff_load_write, 
                               tiff_load_seek, tiff_load_close, 
                               tiff_load_size, 
                               tiff_load_map_file, tiff_load_unmap_file);
470 471 472 473 474
        if (!tiff) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Failed to load TIFF image"));
475
        } else {
476
                GdkPixbuf *pixbuf;
477 478
                
                pixbuf = tiff_image_parse (tiff, context, error);
479 480 481
                retval = (pixbuf != NULL);
                g_clear_object (&pixbuf);
                /* tiff_image_parse() can return NULL on success in a particular case */
482 483 484 485 486 487
                if (!retval && error && !*error) {
                        g_set_error_literal (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_FAILED,
                                             _("Failed to load TIFF image"));
                }
488
        }
489

490 491 492
        if (tiff)
                TIFFClose (tiff);

493 494 495 496 497
        g_free (context->buffer);
        g_free (context);

        return retval;
}
498

499 500 501 502 503 504 505 506 507 508 509
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;
510

511 512 513 514 515 516 517 518
                new_buffer = g_try_realloc (context->buffer, new_size);
                if (new_buffer) {
                        context->buffer = new_buffer;
                        context->allocated = new_size;
                        return TRUE;
                }
                return FALSE;
        }
519
        return TRUE;
520 521
}

522 523 524
static gboolean
gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
                                       guint size, GError **error)
525
{
526 527
	TiffContext *context = (TiffContext *) data;
        
528
	g_return_val_if_fail (data != NULL, FALSE);
529
        
530 531
        tiff_set_handlers ();

532
        if (!make_available_at_least (context, size)) {
533 534 535 536
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to open TIFF file"));
537 538 539 540 541
                return FALSE;
        }
        
        memcpy (context->buffer + context->used, buf, size);
        context->used += size;
542 543
	return TRUE;
}
544

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 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 629 630 631 632 633 634 635
typedef struct {
        gchar *buffer;
        guint allocated;
        guint used;
        guint pos;
} TiffSaveContext;

static tsize_t
tiff_save_read (thandle_t handle, tdata_t buf, tsize_t size)
{
        return -1;
}

static tsize_t
tiff_save_write (thandle_t handle, tdata_t buf, tsize_t size)
{
        TiffSaveContext *context = (TiffSaveContext *)handle;

        /* Modify buffer length */
        if (context->pos + size > context->used)
                context->used = context->pos + size;

        /* Realloc */
        if (context->used > context->allocated) {
                context->buffer = g_realloc (context->buffer, context->pos + size);
                context->allocated = context->used;
        }

        /* Now copy the data */
        memcpy (context->buffer + context->pos, buf, size);

        /* Update pos */
        context->pos += size;

        return size;
}

static toff_t
tiff_save_seek (thandle_t handle, toff_t offset, int whence)
{
        TiffSaveContext *context = (TiffSaveContext *)handle;

        switch (whence) {
        case SEEK_SET:
                context->pos = offset;
                break;
        case SEEK_CUR:
                context->pos += offset;
                break;
        case SEEK_END:
                context->pos = context->used + offset;
                break;
        default:
                return -1;
        }
        return context->pos;
}

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

static toff_t
tiff_save_size (thandle_t handle)
{
        return -1;
}

static TiffSaveContext *
create_save_context (void)
{
        TiffSaveContext *context;

        context = g_new (TiffSaveContext, 1);
        context->buffer = NULL;
        context->allocated = 0;
        context->used = 0;
        context->pos = 0;

        return context;
}

static void
free_save_context (TiffSaveContext *context)
{
        g_free (context->buffer);
        g_free (context);
}

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
static void
copy_gray_row (gint     *dest,
               guchar   *src,
               gint      width,
               gboolean  has_alpha)
{
        gint i;
        guchar *p;

        p = src;
        for (i = 0; i < width; i++) {
                int pr, pg, pb, pv;

                pr = *p++;
                pg = *p++;
                pb = *p++;

                if (has_alpha) {
                        int pa = *p++;

                        /* Premul alpha to simulate it */
                        if (pa > 0) {
                                pr = pr * pa / 255;
                                pg = pg * pa / 255;
                                pb = pb * pa / 255;
                        } else {
                                pr = pg = pb = 0;
                        }
                }

                /* Calculate value MAX(MAX(r,g),b) */
                pv = pr > pg ? pr : pg;
                pv = pv > pb ? pv : pb;

                *dest++ = pv;
        }
}

674 675 676 677 678 679 680 681 682 683
static gboolean
gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc   save_func,
                                         gpointer            user_data,
                                         GdkPixbuf          *pixbuf, 
                                         gchar             **keys,
                                         gchar             **values,
                                         GError            **error)
{
        TIFF *tiff;
        gint width, height, rowstride;
684 685 686
        const gchar *bits_per_sample = NULL;
        long bps;
        const gchar *compression = NULL;
687 688 689 690 691 692
        guchar *pixels;
        gboolean has_alpha;
        gushort alpha_samples[1] = { EXTRASAMPLE_UNASSALPHA };
        int y;
        TiffSaveContext *context;
        gboolean retval;
693
        const gchar *icc_profile = NULL;
694 695
        const gchar *x_dpi = NULL;
        const gchar *y_dpi = NULL;
696
        guint16 codec;
697

698
        tiff_set_handlers ();
699 700 701 702 703 704 705 706

        context = create_save_context ();
        tiff = TIFFClientOpen ("libtiff-pixbuf", "w", context,  
                               tiff_save_read, tiff_save_write, 
                               tiff_save_seek, tiff_save_close, 
                               tiff_save_size, 
                               NULL, NULL);

707 708 709 710 711
        if (!tiff) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Failed to save TIFF image"));
712 713 714 715 716 717 718 719 720 721 722 723
                free_save_context (context);
                return FALSE;
        }

        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
        pixels = gdk_pixbuf_get_pixels (pixbuf);

        has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);

        height = gdk_pixbuf_get_height (pixbuf);
        width = gdk_pixbuf_get_width (pixbuf);

724 725 726 727 728
        /* Guaranteed by the caller. */
        g_assert (width >= 0);
        g_assert (height >= 0);
        g_assert (rowstride >= 0);

729 730 731
        TIFFSetField (tiff, TIFFTAG_IMAGEWIDTH, width);
        TIFFSetField (tiff, TIFFTAG_IMAGELENGTH, height);

732 733 734 735 736 737
        /* libtiff supports a number of 'codecs' such as:
           1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
        if (keys && *keys && values && *values) {
            guint i = 0;

            while (keys[i]) {
738 739 740 741 742 743
                    if (g_str_equal (keys[i], "bits-per-sample"))
                            bits_per_sample = values[i];
                    else if (g_str_equal (keys[i], "compression"))
                            compression = values[i];
                    else if (g_str_equal (keys[i], "icc-profile"))
                            icc_profile = values[i];
744 745 746 747
                    else if (g_str_equal (keys[i], "x-dpi"))
                            x_dpi = values[i];
                    else if (g_str_equal (keys[i], "y-dpi"))
                            y_dpi = values[i];
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
                   i++;
            }
        }

        /* Use 8 bits per sample by default, if none was recorded or
           specified. */
        if (!bits_per_sample)
                bits_per_sample = "8";

        /* Use DEFLATE compression (8) by default, if none was recorded
           or specified. */
        if (!compression)
                compression = "8";

        /* libtiff supports a number of 'codecs' such as:
           1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
764
        codec = strtol (compression, NULL, 0);
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795

        if (TIFFIsCODECConfigured (codec))
                TIFFSetField (tiff, TIFFTAG_COMPRESSION, codec);
        else {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("TIFF compression doesn't refer to a valid codec."));
                retval = FALSE;
                goto cleanup;
        }

        /* We support 1-bit or 8-bit saving */
        bps = atol (bits_per_sample);
        if (bps == 1) {
                TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 1);
                TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
                TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
                TIFFSetField (tiff, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
        } else if (bps == 8) {
                TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 8);
                TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, has_alpha ? 4 : 3);
                TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);

                if (has_alpha)
                        TIFFSetField (tiff, TIFFTAG_EXTRASAMPLES, 1, alpha_samples);

                if (icc_profile != NULL) {
                        guchar *icc_profile_buf;
                        gsize icc_profile_size;

796
                        /* decode from base64 */
797
                        icc_profile_buf = g_base64_decode (icc_profile, &icc_profile_size);
798
                        if (icc_profile_size < 127) {
799 800 801 802 803 804 805 806
                                g_set_error (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_BAD_OPTION,
                                             _("Color profile has invalid length %d."),
                                             (gint) icc_profile_size);
                                retval = FALSE;
                                g_free (icc_profile_buf);
                                goto cleanup;
807
                        }
808

809 810 811 812 813 814 815 816 817 818 819 820
                        TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile_buf);
                        g_free (icc_profile_buf);
                }
        } else {
                /* The passed bits-per-sample is not supported. */
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("TIFF bits-per-sample doesn't contain a supported value."));
                retval = FALSE;
                goto cleanup;
         }
821

822 823
        TIFFSetField (tiff, TIFFTAG_ROWSPERSTRIP, height);
        TIFFSetField (tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
824 825
        TIFFSetField (tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
        if (bps == 1) {
                guchar *mono_row;
                gint *dith_row_1, *dith_row_2, *dith_row_tmp;

                dith_row_1 = g_new (gint, width);
                dith_row_2 = g_new (gint, width);
                mono_row = g_malloc ((width + 7) / 8);

                copy_gray_row (dith_row_1, pixels, width, has_alpha);

                for (y = 0; y < height; y++) {
                        guint x;
                        gint *p;

                        memset (mono_row, 0, (width + 7) / 8);
841

842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
                        if (y > 0) {
                                dith_row_tmp = dith_row_1;
                                dith_row_1 = dith_row_2;
                                dith_row_2 = dith_row_tmp;
                        }

                        if (y < (height - 1))
                                copy_gray_row (dith_row_2, pixels + ((y + 1) * rowstride), width, has_alpha);

                        p = dith_row_1;
                        for (x = 0; x < width; x++) {
                                gint p_old, p_new, quant_error;

                                /* Apply Floyd-Steinberg dithering */

                                p_old = *p++;

                                if (p_old > 127)
                                        p_new = 255;
                                else
                                        p_new = 0;

                                quant_error = p_old - p_new;
                                if (x < (width - 1))
                                        dith_row_1[x + 1] += 7 * quant_error / 16;
                                if (y < (height - 1)) {
                                        if (x > 0)
                                                dith_row_2[x - 1] += 3 * quant_error / 16;

                                        dith_row_2[x] += 5 * quant_error / 16;

                                        if (x < (width - 1))
                                                dith_row_2[x + 1] += quant_error / 16;
                                }

                                if (p_new > 127)
                                        mono_row[x / 8] |= (0x1 << (7 - (x % 8)));
                        }

                        if (TIFFWriteScanline (tiff, mono_row, y, 0) == -1)
                                break;
                }
                g_free (mono_row);
                g_free (dith_row_1);
                g_free (dith_row_2);
        } else {
                for (y = 0; y < height; y++) {
                        if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1)
                                break;
                }
892 893
        }

894 895 896 897 898
        if (y < height) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Failed to write TIFF data"));
899
                TIFFClose (tiff);
900 901
                retval = FALSE;
                goto cleanup;
902 903
        }

904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
        if (x_dpi != NULL && y_dpi != NULL) {
                char *endptr = NULL;
                uint16 resolution_unit = RESUNIT_INCH;
                float x_dpi_value, y_dpi_value;

                x_dpi_value = strtol (x_dpi, &endptr, 10);
                if (x_dpi[0] != '\0' && *endptr != '\0')
                        x_dpi_value = -1;
                if (x_dpi_value <= 0) {
                    g_set_error (error,
                                 GDK_PIXBUF_ERROR,
                                 GDK_PIXBUF_ERROR_BAD_OPTION,
                                 _("TIFF x-dpi must be greater than zero; value '%s' is not allowed."),
                                 x_dpi);
                    retval = FALSE;
                    goto cleanup;
                }
                y_dpi_value = strtol (y_dpi, &endptr, 10);
                if (y_dpi[0] != '\0' && *endptr != '\0')
                        y_dpi_value = -1;
                if (y_dpi_value <= 0) {
                    g_set_error (error,
                                 GDK_PIXBUF_ERROR,
                                 GDK_PIXBUF_ERROR_BAD_OPTION,
                                 _("TIFF y-dpi must be greater than zero; value '%s' is not allowed."),
                                 y_dpi);
                    retval = FALSE;
                    goto cleanup;
                }

                TIFFSetField (tiff, TIFFTAG_RESOLUTIONUNIT, resolution_unit);
                TIFFSetField (tiff, TIFFTAG_XRESOLUTION, x_dpi_value);
                TIFFSetField (tiff, TIFFTAG_YRESOLUTION, y_dpi_value);
        }

939 940 941 942 943
        TIFFClose (tiff);

        /* Now call the callback */
        retval = save_func (context->buffer, context->used, error, user_data);

944 945
cleanup:
        free_save_context (context);
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
        return retval;
}

static gboolean
save_to_file_cb (const gchar *buf,
		 gsize count,
		 GError **error,
		 gpointer data)
{
	gint bytes;
	
	while (count > 0) {
		bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
		if (bytes <= 0)
			break;
		count -= bytes;
		buf += bytes;
	}

	if (count) {
966 967 968 969
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
                                     _("Couldn't write to TIFF file"));
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
		return FALSE;
	}
	
	return TRUE;
}

static gboolean
gdk_pixbuf__tiff_image_save (FILE          *f, 
                             GdkPixbuf     *pixbuf, 
                             gchar        **keys,
                             gchar        **values,
                             GError       **error)
{
	return gdk_pixbuf__tiff_image_save_to_callback (save_to_file_cb,
                                                        f, pixbuf, keys,
                                                        values, error);
}

988 989 990 991 992 993 994 995 996 997 998 999 1000
static gboolean
gdk_pixbuf__tiff_is_save_option_supported (const gchar *option_key)
{
        if (g_strcmp0 (option_key, "bits-per-sample") == 0 ||
            g_strcmp0 (option_key, "compression") == 0 ||
            g_strcmp0 (option_key, "icc-profile") == 0 ||
            g_strcmp0 (option_key, "x-dpi") == 0 ||
            g_strcmp0 (option_key, "y-dpi") == 0)
                return TRUE;

        return FALSE;
}

1001
#ifndef INCLUDE_tiff
1002
#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1003
#else
1004
#define MODULE_ENTRY(function) void _gdk_pixbuf__tiff_ ## function
1005 1006
#endif

1007
MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1008
{
1009 1010 1011 1012
        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;
1013 1014
        module->save = gdk_pixbuf__tiff_image_save;
        module->save_to_callback = gdk_pixbuf__tiff_image_save_to_callback;
1015
        module->is_save_option_supported = gdk_pixbuf__tiff_is_save_option_supported;
1016
}
1017

1018
MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1019
{
1020
        static const GdkPixbufModulePattern signature[] = {
1021 1022
                { "MM \x2a", "  z ", 100 },
                { "II\x2a ", "   z", 100 },
1023
                { "II* \020   CR\002 ", "   z zzz   z", 0 },
1024 1025
                { NULL, NULL, 0 }
        };
1026
	static const gchar *mime_types[] = {
1027 1028 1029
		"image/tiff",
		NULL
	};
1030
	static const gchar *extensions[] = {
1031 1032 1033 1034 1035 1036
		"tiff",
		"tif",
		NULL
	};

	info->name = "tiff";
1037
        info->signature = (GdkPixbufModulePattern *) signature;
1038
	info->description = NC_("image format", "TIFF");
1039 1040
	info->mime_types = (gchar **) mime_types;
	info->extensions = (gchar **) extensions;
1041
	info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1042
	info->license = "LGPL";
1043
}