]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tiff.c
Don't use string concatentation in translated strings
[~andy/gtk] / gdk-pixbuf / io-tiff.c
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  * Copyright (C) 1999 The Free Software Foundation
6  *
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>
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  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * 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  * License along with this library; if not, write to the
24  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25  * Boston, MA 02111-1307, USA.
26  */
27
28 /* Following code (almost) blatantly ripped from Imlib */
29
30 #include "config.h"
31 #include <stdlib.h>
32 #include <string.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <tiffio.h>
37 #include <errno.h>
38 #include "gdk-pixbuf-private.h"
39 #include "gdk-pixbuf-io.h"
40
41 #ifdef G_OS_WIN32
42 #include <fcntl.h>
43 #include <io.h>
44 #define lseek(a,b,c) _lseek(a,b,c)
45 #define O_RDWR _O_RDWR
46 #endif
47 \f
48
49 typedef struct _TiffContext TiffContext;
50 struct _TiffContext
51 {
52         GdkPixbufModuleSizeFunc size_func;
53         GdkPixbufModulePreparedFunc prepare_func;
54         GdkPixbufModuleUpdatedFunc update_func;
55         gpointer user_data;
56         
57         guchar *buffer;
58         guint allocated;
59         guint used;
60         guint pos;
61 };
62
63 \f
64
65 static char *global_error = NULL;
66 static TIFFErrorHandler orig_error_handler = NULL;
67 static TIFFErrorHandler orig_warning_handler = NULL;
68
69 static void
70 tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
71 {
72         /* Don't print anything; we should not be dumping junk to
73          * stderr, since that may be bad for some apps.
74          */
75
76         /* libTIFF seems to occasionally warn about things that
77          * are really errors, so maybe we should just call tiff_error_handler
78          * here.
79          */
80 }
81
82 static void
83 tiff_error_handler (const char *mod, const char *fmt, va_list ap)
84 {
85         if (global_error) {                
86                 /* Blah, loader called us twice */
87                 return;
88         }
89
90         global_error = g_strdup_vprintf (fmt, ap);
91 }
92
93 static void
94 tiff_push_handlers (void)
95 {
96         if (global_error)
97                 g_warning ("TIFF loader left crufty global_error around, FIXME");
98         
99         orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
100         orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
101 }
102
103 static void
104 tiff_pop_handlers (void)
105 {
106         if (global_error)
107                 g_warning ("TIFF loader left crufty global_error around, FIXME");
108         
109         TIFFSetErrorHandler (orig_error_handler);
110         TIFFSetWarningHandler (orig_warning_handler);
111 }
112
113 static void
114 tiff_set_error (GError    **error,
115                 int         error_code,
116                 const char *msg)
117 {
118         /* Take the error message from libtiff and merge it with
119          * some context we provide.
120          */
121         if (global_error) {
122                 g_set_error (error,
123                              GDK_PIXBUF_ERROR,
124                              error_code,
125                              "%s%s%s", msg, ": ", global_error);
126
127                 g_free (global_error);
128                 global_error = NULL;
129         }
130         else {
131                 g_set_error_literal (error,
132                                      GDK_PIXBUF_ERROR,
133                                      error_code, msg);
134         }
135 }
136
137 \f
138
139 static void free_buffer (guchar *pixels, gpointer data)
140 {
141         g_free (pixels);
142 }
143
144 static GdkPixbuf *
145 tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
146 {
147         guchar *pixels = NULL;
148         gint width, height, rowstride, bytes;
149         GdkPixbuf *pixbuf;
150         uint16 orientation = 0;
151         uint16 transform = 0;
152         uint16 codec;
153         gchar *icc_profile_base64;
154         const gchar *icc_profile;
155         guint icc_profile_size;
156         gint retval;
157
158         /* We're called with the lock held. */
159         
160         g_return_val_if_fail (global_error == NULL, NULL);
161
162         if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width) || global_error) {
163                 tiff_set_error (error,
164                                 GDK_PIXBUF_ERROR_FAILED,
165                                 _("Could not get image width (bad TIFF file)"));
166                 return NULL;
167         }
168         
169         if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height) || global_error) {
170                 tiff_set_error (error,
171                                 GDK_PIXBUF_ERROR_FAILED,
172                                 _("Could not get image height (bad TIFF file)"));
173                 return NULL;
174         }
175
176         if (width <= 0 || height <= 0) {
177                 g_set_error_literal (error,
178                                      GDK_PIXBUF_ERROR,
179                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
180                                      _("Width or height of TIFF image is zero"));
181                 return NULL;                
182         }
183         
184         rowstride = width * 4;
185         if (rowstride / 4 != width) { /* overflow */
186                 g_set_error_literal (error,
187                                      GDK_PIXBUF_ERROR,
188                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
189                                      _("Dimensions of TIFF image too large"));
190                 return NULL;                
191         }
192         
193         bytes = height * rowstride;
194         if (bytes / rowstride != height) { /* overflow */
195                 g_set_error_literal (error,
196                                      GDK_PIXBUF_ERROR,
197                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
198                                      _("Dimensions of TIFF image too large"));
199                 return NULL;                
200         }
201
202         if (context && context->size_func) {
203                 gint w = width;
204                 gint h = height;
205                 (* context->size_func) (&w, &h, context->user_data);
206                 
207                 /* This is a signal that this function is being called
208                    to support gdk_pixbuf_get_file_info, so we can stop
209                    parsing the tiff file at this point. It is not an
210                    error condition. */
211
212                 if (w == 0 || h == 0)
213                     return NULL;
214         }
215
216         pixels = g_try_malloc (bytes);
217
218         if (!pixels) {
219                 g_set_error_literal (error,
220                                      GDK_PIXBUF_ERROR,
221                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
222                                      _("Insufficient memory to open TIFF file"));
223                 return NULL;
224         }
225
226         pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
227                                            width, height, rowstride,
228                                            free_buffer, NULL);
229         if (!pixbuf) {
230                 g_free (pixels);
231                 g_set_error_literal (error,
232                                      GDK_PIXBUF_ERROR,
233                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
234                                      _("Insufficient memory to open TIFF file"));
235                 return NULL;
236         }
237
238         /* Set the "orientation" key associated with this image. libtiff 
239            orientation handling is odd, so further processing is required
240            by higher-level functions based on this tag. If the embedded
241            orientation tag is 1-4, libtiff flips/mirrors the image as
242            required, and no client processing is required - so we report 
243            no orientation. Orientations 5-8 require rotations which would 
244            swap the width and height of the image. libtiff does not do this. 
245            Instead it interprets orientations 5-8 the same as 1-4. 
246            See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548.
247            To correct for this, the client must apply the transform normally
248            used for orientation 5 to both orientations 5 and 7, and apply
249            the transform normally used for orientation 7 for both
250            orientations 6 and 8. Then everythings works out OK! */
251         
252         TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation);
253
254         switch (orientation) {
255                 case 5:
256                 case 7:
257                         transform = 5;
258                         break;
259                 case 6:
260                 case 8:
261                         transform = 7;
262                         break;
263                 default:
264                         transform = 0;
265                         break;
266         }
267
268         if (transform > 0 ) {
269                 gchar str[5];
270                 g_snprintf (str, sizeof (str), "%d", transform);
271                 gdk_pixbuf_set_option (pixbuf, "orientation", str);
272         }
273
274         TIFFGetField (tiff, TIFFTAG_COMPRESSION, &codec);
275         if (codec > 0) {
276           gchar str[5];
277           g_snprintf (str, sizeof (str), "%d", codec);
278           gdk_pixbuf_set_option (pixbuf, "compression", str);
279         }
280
281         /* Extract embedded ICC profile */
282         retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile);
283         if (retval == 1) {
284                 icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
285                 gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
286                 g_free (icc_profile_base64);
287         }
288
289         if (context && context->prepare_func)
290                 (* context->prepare_func) (pixbuf, NULL, context->user_data);
291
292         if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) {
293                 tiff_set_error (error,
294                                 GDK_PIXBUF_ERROR_FAILED,
295                                 _("Failed to load RGB data from TIFF file"));
296                 g_object_unref (pixbuf);
297                 return NULL;
298         }
299
300 #if G_BYTE_ORDER == G_BIG_ENDIAN
301         /* Turns out that the packing used by TIFFRGBAImage depends on 
302          * the host byte order... 
303          */ 
304         while (pixels < pixbuf->pixels + bytes) {
305                 uint32 pixel = *(uint32 *)pixels;
306                 int r = TIFFGetR(pixel);
307                 int g = TIFFGetG(pixel);
308                 int b = TIFFGetB(pixel);
309                 int a = TIFFGetA(pixel);
310                 *pixels++ = r;
311                 *pixels++ = g;
312                 *pixels++ = b;
313                 *pixels++ = a;
314         }
315 #endif
316
317         if (context && context->update_func)
318                 (* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
319
320         return pixbuf;
321 }
322
323 \f
324
325 /* Static loader */
326
327 static GdkPixbuf *
328 gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
329 {
330         TIFF *tiff;
331         int fd;
332         GdkPixbuf *pixbuf;
333         
334         g_return_val_if_fail (f != NULL, NULL);
335
336         tiff_push_handlers ();
337         
338         fd = fileno (f);
339
340         /* On OSF, apparently fseek() works in some on-demand way, so
341          * the fseek gdk_pixbuf_new_from_file() doesn't work here
342          * since we are using the raw file descriptor. So, we call lseek() on the fd
343          * before using it. (#60840)
344          */
345         lseek (fd, 0, SEEK_SET);
346         tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
347         
348         if (!tiff || global_error) {
349                 tiff_set_error (error,
350                                 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
351                                 _("Failed to open TIFF image"));
352                 tiff_pop_handlers ();
353
354                 return NULL;
355         }
356
357         pixbuf = tiff_image_parse (tiff, NULL, error);
358         
359         TIFFClose (tiff);
360         if (global_error) {
361                 tiff_set_error (error,
362                                 GDK_PIXBUF_ERROR_FAILED,
363                                 _("TIFFClose operation failed"));
364         }
365         
366         tiff_pop_handlers ();
367
368         return pixbuf;
369 }
370
371 \f
372
373 /* Progressive loader */
374
375 static gpointer
376 gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
377                                    GdkPixbufModulePreparedFunc prepare_func,
378                                    GdkPixbufModuleUpdatedFunc update_func,
379                                    gpointer user_data,
380                                    GError **error)
381 {
382         TiffContext *context;
383         
384         context = g_new0 (TiffContext, 1);
385         context->size_func = size_func;
386         context->prepare_func = prepare_func;
387         context->update_func = update_func;
388         context->user_data = user_data;
389         context->buffer = NULL;
390         context->allocated = 0;
391         context->used = 0;
392         context->pos = 0;
393         
394         return context;
395 }
396
397 static tsize_t
398 tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
399 {
400         TiffContext *context = (TiffContext *)handle;
401         
402         if (context->pos + size > context->used)
403                 return 0;
404         
405         memcpy (buf, context->buffer + context->pos, size);
406         context->pos += size;
407         return size;
408 }
409
410 static tsize_t
411 tiff_load_write (thandle_t handle, tdata_t buf, tsize_t size)
412 {
413         return -1;
414 }
415
416 static toff_t
417 tiff_load_seek (thandle_t handle, toff_t offset, int whence)
418 {
419         TiffContext *context = (TiffContext *)handle;
420         
421         switch (whence) {
422         case SEEK_SET:
423                 if (offset > context->used)
424                         return -1;
425                 context->pos = offset;
426                 break;
427         case SEEK_CUR:
428                 if (offset + context->pos >= context->used)
429                         return -1;
430                 context->pos += offset;
431                 break;
432         case SEEK_END:
433                 if (offset + context->used > context->used)
434                         return -1;
435                 context->pos = context->used + offset;
436                 break;
437         default:
438                 return -1;
439         }
440         return context->pos;
441 }
442
443 static int
444 tiff_load_close (thandle_t context)
445 {
446         return 0;
447 }
448
449 static toff_t
450 tiff_load_size (thandle_t handle)
451 {
452         TiffContext *context = (TiffContext *)handle;
453         
454         return context->used;
455 }
456
457 static int
458 tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
459 {
460         TiffContext *context = (TiffContext *)handle;
461         
462         *buf = context->buffer;
463         *size = context->used;
464         
465         return 0;
466 }
467
468 static void
469 tiff_load_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
470 {
471 }
472
473 static gboolean
474 gdk_pixbuf__tiff_image_stop_load (gpointer data,
475                                   GError **error)
476 {
477         TiffContext *context = data;
478         TIFF *tiff;
479         gboolean retval;
480         
481         g_return_val_if_fail (data != NULL, FALSE);
482
483         tiff_push_handlers ();
484         
485         tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data, 
486                                tiff_load_read, tiff_load_write, 
487                                tiff_load_seek, tiff_load_close, 
488                                tiff_load_size, 
489                                tiff_load_map_file, tiff_load_unmap_file);
490         if (!tiff || global_error) {
491                 tiff_set_error (error,
492                                 GDK_PIXBUF_ERROR_FAILED,
493                                 _("Failed to load TIFF image"));
494                 retval = FALSE;
495         } else {
496                 GdkPixbuf *pixbuf;
497                 
498                 pixbuf = tiff_image_parse (tiff, context, error);
499                 if (pixbuf)
500                         g_object_unref (pixbuf);
501                 retval = pixbuf != NULL;
502                 if (global_error)
503                         {
504                                 tiff_set_error (error,
505                                                 GDK_PIXBUF_ERROR_FAILED,
506                                                 _("Failed to load TIFF image"));
507                                 tiff_pop_handlers ();
508
509                                 retval = FALSE;
510                         }
511         }
512
513         if (tiff)
514                 TIFFClose (tiff);
515
516         g_assert (!global_error);
517         
518         g_free (context->buffer);
519         g_free (context);
520
521         tiff_pop_handlers ();
522
523         return retval;
524 }
525
526 static gboolean
527 make_available_at_least (TiffContext *context, guint needed)
528 {
529         guchar *new_buffer = NULL;
530         guint need_alloc;
531         
532         need_alloc = context->used + needed;
533         if (need_alloc > context->allocated) {
534                 guint new_size = 1;
535                 while (new_size < need_alloc)
536                         new_size *= 2;
537                 
538                 new_buffer = g_try_realloc (context->buffer, new_size);
539                 if (new_buffer) {
540                         context->buffer = new_buffer;
541                         context->allocated = new_size;
542                         return TRUE;
543                 }
544                 return FALSE;
545         }
546         return TRUE;
547 }
548
549 static gboolean
550 gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
551                                        guint size, GError **error)
552 {
553         TiffContext *context = (TiffContext *) data;
554         
555         g_return_val_if_fail (data != NULL, FALSE);
556         
557         if (!make_available_at_least (context, size)) {
558                 g_set_error_literal (error,
559                                      GDK_PIXBUF_ERROR,
560                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
561                                      _("Insufficient memory to open TIFF file"));
562                 return FALSE;
563         }
564         
565         memcpy (context->buffer + context->used, buf, size);
566         context->used += size;
567         return TRUE;
568 }
569
570 typedef struct {
571         gchar *buffer;
572         guint allocated;
573         guint used;
574         guint pos;
575 } TiffSaveContext;
576
577 static tsize_t
578 tiff_save_read (thandle_t handle, tdata_t buf, tsize_t size)
579 {
580         return -1;
581 }
582
583 static tsize_t
584 tiff_save_write (thandle_t handle, tdata_t buf, tsize_t size)
585 {
586         TiffSaveContext *context = (TiffSaveContext *)handle;
587
588         /* Modify buffer length */
589         if (context->pos + size > context->used)
590                 context->used = context->pos + size;
591
592         /* Realloc */
593         if (context->used > context->allocated) {
594                 context->buffer = g_realloc (context->buffer, context->pos + size);
595                 context->allocated = context->used;
596         }
597
598         /* Now copy the data */
599         memcpy (context->buffer + context->pos, buf, size);
600
601         /* Update pos */
602         context->pos += size;
603
604         return size;
605 }
606
607 static toff_t
608 tiff_save_seek (thandle_t handle, toff_t offset, int whence)
609 {
610         TiffSaveContext *context = (TiffSaveContext *)handle;
611
612         switch (whence) {
613         case SEEK_SET:
614                 context->pos = offset;
615                 break;
616         case SEEK_CUR:
617                 context->pos += offset;
618                 break;
619         case SEEK_END:
620                 context->pos = context->used + offset;
621                 break;
622         default:
623                 return -1;
624         }
625         return context->pos;
626 }
627
628 static int
629 tiff_save_close (thandle_t context)
630 {
631         return 0;
632 }
633
634 static toff_t
635 tiff_save_size (thandle_t handle)
636 {
637         return -1;
638 }
639
640 static TiffSaveContext *
641 create_save_context (void)
642 {
643         TiffSaveContext *context;
644
645         context = g_new (TiffSaveContext, 1);
646         context->buffer = NULL;
647         context->allocated = 0;
648         context->used = 0;
649         context->pos = 0;
650
651         return context;
652 }
653
654 static void
655 free_save_context (TiffSaveContext *context)
656 {
657         g_free (context->buffer);
658         g_free (context);
659 }
660
661 static gboolean
662 gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc   save_func,
663                                          gpointer            user_data,
664                                          GdkPixbuf          *pixbuf, 
665                                          gchar             **keys,
666                                          gchar             **values,
667                                          GError            **error)
668 {
669         TIFF *tiff;
670         gint width, height, rowstride;
671         guchar *pixels;
672         gboolean has_alpha;
673         gushort alpha_samples[1] = { EXTRASAMPLE_UNASSALPHA };
674         int y;
675         TiffSaveContext *context;
676         gboolean retval;
677         guchar *icc_profile = NULL;
678         gsize icc_profile_size = 0;
679
680         tiff_push_handlers ();
681
682         context = create_save_context ();
683         tiff = TIFFClientOpen ("libtiff-pixbuf", "w", context,  
684                                tiff_save_read, tiff_save_write, 
685                                tiff_save_seek, tiff_save_close, 
686                                tiff_save_size, 
687                                NULL, NULL);
688
689         if (!tiff || global_error) {
690                 tiff_set_error (error,
691                                 GDK_PIXBUF_ERROR_FAILED,
692                                 _("Failed to save TIFF image"));
693
694                 tiff_pop_handlers ();
695
696                 free_save_context (context);
697                 return FALSE;
698         }
699
700         rowstride = gdk_pixbuf_get_rowstride (pixbuf);
701         pixels = gdk_pixbuf_get_pixels (pixbuf);
702
703         has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
704
705         height = gdk_pixbuf_get_height (pixbuf);
706         width = gdk_pixbuf_get_width (pixbuf);
707
708         TIFFSetField (tiff, TIFFTAG_IMAGEWIDTH, width);
709         TIFFSetField (tiff, TIFFTAG_IMAGELENGTH, height);
710         TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 8);
711         TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, has_alpha ? 4 : 3);
712         TIFFSetField (tiff, TIFFTAG_ROWSPERSTRIP, height);
713
714         /* libtiff supports a number of 'codecs' such as:
715            1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
716         if (keys && *keys && values && *values) {
717             guint i = 0;
718
719             while (keys[i]) {
720                 if (g_str_equal (keys[i], "compression")) {
721                     guint16 codec = strtol (values[i], NULL, 0);
722                     if (TIFFIsCODECConfigured (codec))
723                         TIFFSetField (tiff, TIFFTAG_COMPRESSION, codec);
724                     else {
725                         tiff_set_error (error,
726                                         GDK_PIXBUF_ERROR_FAILED,
727                                         _("TIFF compression doesn't refer to a valid codec."));
728                         retval = FALSE;
729                         goto cleanup;
730                     }
731                 } else if (g_str_equal (keys[i], "icc-profile")) {
732                         /* decode from base64 */
733                         icc_profile = g_base64_decode (values[i], &icc_profile_size);
734                         if (icc_profile_size < 127) {
735                             g_set_error (error,
736                                          GDK_PIXBUF_ERROR,
737                                          GDK_PIXBUF_ERROR_BAD_OPTION,
738                                          _("Color profile has invalid length %d."),
739                                          (gint)icc_profile_size);
740                             retval = FALSE;
741                             goto cleanup;
742                         }
743                 }
744                 i++;
745             }
746         }
747
748         if (has_alpha)
749                 TIFFSetField (tiff, TIFFTAG_EXTRASAMPLES, 1, alpha_samples);
750
751         TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
752         TIFFSetField (tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);        
753         TIFFSetField (tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
754
755         if (icc_profile != NULL)
756                 TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile);
757
758         for (y = 0; y < height; y++) {
759                 if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1 ||
760                     global_error)
761                         break;
762         }
763
764         if (global_error) {
765                 tiff_set_error (error,
766                                 GDK_PIXBUF_ERROR_FAILED,
767                                 _("Failed to write TIFF data"));
768
769                 TIFFClose (tiff);
770                 retval = FALSE;
771                 goto cleanup;
772         }
773
774         TIFFClose (tiff);
775         if (global_error) {
776                 tiff_set_error (error,
777                                 GDK_PIXBUF_ERROR_FAILED,
778                                 _("TIFFClose operation failed"));
779                 retval = FALSE;
780                 goto cleanup;
781         }
782
783
784         /* Now call the callback */
785         retval = save_func (context->buffer, context->used, error, user_data);
786
787 cleanup:
788         g_free (icc_profile);
789         tiff_pop_handlers ();
790         free_save_context (context);
791         return retval;
792 }
793
794 static gboolean
795 save_to_file_cb (const gchar *buf,
796                  gsize count,
797                  GError **error,
798                  gpointer data)
799 {
800         gint bytes;
801         
802         while (count > 0) {
803                 bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
804                 if (bytes <= 0)
805                         break;
806                 count -= bytes;
807                 buf += bytes;
808         }
809
810         if (count) {
811                 g_set_error_literal (error,
812                                      GDK_PIXBUF_ERROR,
813                                      GDK_PIXBUF_ERROR_FAILED,
814                                      _("Couldn't write to TIFF file"));
815                 return FALSE;
816         }
817         
818         return TRUE;
819 }
820
821 static gboolean
822 gdk_pixbuf__tiff_image_save (FILE          *f, 
823                              GdkPixbuf     *pixbuf, 
824                              gchar        **keys,
825                              gchar        **values,
826                              GError       **error)
827 {
828         return gdk_pixbuf__tiff_image_save_to_callback (save_to_file_cb,
829                                                         f, pixbuf, keys,
830                                                         values, error);
831 }
832
833 #ifndef INCLUDE_tiff
834 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
835 #else
836 #define MODULE_ENTRY(function) void _gdk_pixbuf__tiff_ ## function
837 #endif
838
839 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
840 {
841         module->load = gdk_pixbuf__tiff_image_load;
842         module->begin_load = gdk_pixbuf__tiff_image_begin_load;
843         module->stop_load = gdk_pixbuf__tiff_image_stop_load;
844         module->load_increment = gdk_pixbuf__tiff_image_load_increment;
845         module->save = gdk_pixbuf__tiff_image_save;
846         module->save_to_callback = gdk_pixbuf__tiff_image_save_to_callback;
847 }
848
849 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
850 {
851         static GdkPixbufModulePattern signature[] = {
852                 { "MM \x2a", "  z ", 100 },
853                 { "II\x2a ", "   z", 100 },
854                 { "II* \020   CR\002 ", "   z zzz   z", 0 },
855                 { NULL, NULL, 0 }
856         };
857         static gchar * mime_types[] = {
858                 "image/tiff",
859                 NULL
860         };
861         static gchar * extensions[] = {
862                 "tiff",
863                 "tif",
864                 NULL
865         };
866
867         info->name = "tiff";
868         info->signature = signature;
869         info->description = N_("The TIFF image format");
870         info->mime_types = mime_types;
871         info->extensions = extensions;
872         /* not threadsafe, due to the error handler handling */
873         info->flags = GDK_PIXBUF_FORMAT_WRITABLE;
874         info->license = "LGPL";
875 }