]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tiff.c
function doesn't return a value, so don't use g_return_val_if_fail()
[~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 /* There's no user data for the error handlers, so we just have to
66  * put a big-ass lock on the whole TIFF loader
67  */
68 G_LOCK_DEFINE_STATIC (tiff_loader);
69 static char *global_error = NULL;
70 static TIFFErrorHandler orig_error_handler = NULL;
71 static TIFFErrorHandler orig_warning_handler = NULL;
72
73 static void
74 tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
75 {
76         /* Don't print anything; we should not be dumping junk to
77          * stderr, since that may be bad for some apps.
78          */
79
80         /* libTIFF seems to occasionally warn about things that
81          * are really errors, so maybe we should just call tiff_error_handler
82          * here.
83          */
84 }
85
86 static void
87 tiff_error_handler (const char *mod, const char *fmt, va_list ap)
88 {
89         if (global_error) {                
90                 /* Blah, loader called us twice */
91                 return;
92         }
93
94         global_error = g_strdup_vprintf (fmt, ap);
95 }
96
97 static void
98 tiff_push_handlers (void)
99 {
100         if (global_error)
101                 g_warning ("TIFF loader left crufty global_error around, FIXME");
102         
103         orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
104         orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
105 }
106
107 static void
108 tiff_pop_handlers (void)
109 {
110         if (global_error)
111                 g_warning ("TIFF loader left crufty global_error around, FIXME");
112         
113         TIFFSetErrorHandler (orig_error_handler);
114         TIFFSetWarningHandler (orig_warning_handler);
115 }
116
117 static void
118 tiff_set_error (GError    **error,
119                 int         error_code,
120                 const char *msg)
121 {
122         /* Take the error message from libtiff and merge it with
123          * some context we provide.
124          */
125         if (global_error) {
126                 g_set_error (error,
127                              GDK_PIXBUF_ERROR,
128                              error_code,
129                              "%s%s%s", msg, ": ", global_error);
130
131                 g_free (global_error);
132                 global_error = NULL;
133         }
134         else {
135                 g_set_error (error,
136                              GDK_PIXBUF_ERROR,
137                              error_code, msg);
138         }
139 }
140
141 \f
142
143 static void free_buffer (guchar *pixels, gpointer data)
144 {
145         g_free (pixels);
146 }
147
148 #if TIFFLIB_VERSION >= 20031226
149 static gboolean tifflibversion (int *major, int *minor, int *revision)
150 {
151         if (sscanf (TIFFGetVersion(), 
152                     "LIBTIFF, Version %d.%d.%d", 
153                     major, minor, revision) < 3)
154                 return FALSE;
155
156         return TRUE;
157 }
158 #endif
159
160 static GdkPixbuf *
161 tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
162 {
163         guchar *pixels = NULL;
164         gint width, height, rowstride, bytes;
165         GdkPixbuf *pixbuf;
166 #if TIFFLIB_VERSION >= 20031226
167         gint major, minor, revision;
168 #endif
169
170         /* We're called with the lock held. */
171         
172         g_return_val_if_fail (global_error == NULL, NULL);
173
174         if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width) || global_error) {
175                 tiff_set_error (error,
176                                 GDK_PIXBUF_ERROR_FAILED,
177                                 _("Could not get image width (bad TIFF file)"));
178                 return NULL;
179         }
180         
181         if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height) || global_error) {
182                 tiff_set_error (error,
183                                 GDK_PIXBUF_ERROR_FAILED,
184                                 _("Could not get image height (bad TIFF file)"));
185                 return NULL;
186         }
187
188         if (width <= 0 || height <= 0) {
189                 g_set_error (error,
190                              GDK_PIXBUF_ERROR,
191                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
192                              _("Width or height of TIFF image is zero"));
193                 return NULL;                
194         }
195         
196         rowstride = width * 4;
197         if (rowstride / 4 != width) { /* overflow */
198                 g_set_error (error,
199                              GDK_PIXBUF_ERROR,
200                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
201                              _("Dimensions of TIFF image too large"));
202                 return NULL;                
203         }
204         
205         bytes = height * rowstride;
206         if (bytes / rowstride != height) { /* overflow */
207                 g_set_error (error,
208                              GDK_PIXBUF_ERROR,
209                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
210                              _("Dimensions of TIFF image too large"));
211                 return NULL;                
212         }
213
214         if (context && context->size_func) {
215                 gint w = width;
216                 gint h = height;
217                 (* context->size_func) (&w, &h, context->user_data);
218                 
219                 if (w == 0 || h == 0)
220                     return NULL;
221         }
222
223         pixels = g_try_malloc (bytes);
224
225         if (!pixels) {
226                 g_set_error (error,
227                              GDK_PIXBUF_ERROR,
228                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
229                              _("Insufficient memory to open TIFF file"));
230                 return NULL;
231         }
232
233         pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
234                                            width, height, rowstride,
235                                            free_buffer, NULL);
236         if (!pixbuf) {
237                 g_free (pixels);
238                 g_set_error (error,
239                              GDK_PIXBUF_ERROR,
240                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
241                              _("Insufficient memory to open TIFF file"));
242                 return NULL;
243         }
244
245         G_UNLOCK (tiff_loader);
246         if (context)
247                 (* context->prepare_func) (pixbuf, NULL, context->user_data);
248         G_LOCK (tiff_loader);
249
250 #if TIFFLIB_VERSION >= 20031226
251         if (tifflibversion(&major, &minor, &revision) && major == 3 &&
252             (minor > 6 || (minor == 6 && revision > 0))) {                
253                 if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) 
254                 {
255                         tiff_set_error (error,
256                                         GDK_PIXBUF_ERROR_FAILED,
257                                         _("Failed to load RGB data from TIFF file"));
258                         g_object_unref (pixbuf);
259                         return NULL;
260                 }
261
262 #if G_BYTE_ORDER == G_BIG_ENDIAN
263                 /* Turns out that the packing used by TIFFRGBAImage depends on 
264                  * the host byte order... 
265                  */ 
266                 while (pixels < pixbuf->pixels + bytes) {
267                         uint32 pixel = *(uint32 *)pixels;
268                         int r = TIFFGetR(pixel);
269                         int g = TIFFGetG(pixel);
270                         int b = TIFFGetB(pixel);
271                         int a = TIFFGetA(pixel);
272                         *pixels++ = r;
273                         *pixels++ = g;
274                         *pixels++ = b;
275                         *pixels++ = a;
276                 }
277 #endif
278         }
279         else 
280 #endif
281               {
282                 uint32 *rast, *tmp_rast;
283                 gint x, y;
284                 guchar *tmppix;
285
286                 /* Yes, it needs to be _TIFFMalloc... */
287                 rast = (uint32 *) _TIFFmalloc (width * height * sizeof (uint32));
288                 if (!rast) {
289                         g_set_error (error,
290                                      GDK_PIXBUF_ERROR,
291                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
292                                      _("Insufficient memory to open TIFF file"));
293                         g_object_unref (pixbuf);
294                         
295                         return NULL;
296                 }
297                 if (!TIFFReadRGBAImage (tiff, width, height, rast, 1) || global_error) {
298                         tiff_set_error (error,
299                                         GDK_PIXBUF_ERROR_FAILED,
300                                         _("Failed to load RGB data from TIFF file"));
301                         g_object_unref (pixbuf);
302                         _TIFFfree (rast);
303                         
304                         return NULL;
305                 }
306                 
307                 pixels = gdk_pixbuf_get_pixels (pixbuf);
308                 
309                 g_assert (pixels);
310                 
311                 tmppix = pixels;
312                 
313                 for (y = 0; y < height; y++) {
314                         /* Unexplainable...are tiffs backwards? */
315                         /* Also looking at the GIMP plugin, this
316                          * whole reading thing can be a bit more
317                          * robust.
318                          */
319                         tmp_rast = rast + ((height - y - 1) * width);
320                         for (x = 0; x < width; x++) {
321                                 tmppix[0] = TIFFGetR (*tmp_rast);
322                                 tmppix[1] = TIFFGetG (*tmp_rast);
323                                 tmppix[2] = TIFFGetB (*tmp_rast);
324                                 tmppix[3] = TIFFGetA (*tmp_rast);
325                                 tmp_rast++;
326                                 tmppix += 4;
327                         }
328                 }
329                 
330                 _TIFFfree (rast);
331              }
332
333         G_UNLOCK (tiff_loader);
334         if (context)
335                 (* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
336         G_LOCK (tiff_loader);
337         
338         return pixbuf;
339 }
340
341 \f
342
343 /* Static loader */
344
345 static GdkPixbuf *
346 gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
347 {
348         TIFF *tiff;
349         int fd;
350         GdkPixbuf *pixbuf;
351         
352         g_return_val_if_fail (f != NULL, NULL);
353
354         G_LOCK (tiff_loader);
355
356         tiff_push_handlers ();
357         
358         fd = fileno (f);
359
360         /* On OSF, apparently fseek() works in some on-demand way, so
361          * the fseek gdk_pixbuf_new_from_file() doesn't work here
362          * since we are using the raw file descriptor. So, we call lseek() on the fd
363          * before using it. (#60840)
364          */
365         lseek (fd, 0, SEEK_SET);
366         tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
367         
368         if (!tiff || global_error) {
369                 tiff_set_error (error,
370                                 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
371                                 _("Failed to open TIFF image"));
372                 tiff_pop_handlers ();
373
374                 G_UNLOCK (tiff_loader);
375                 return NULL;
376         }
377
378         pixbuf = tiff_image_parse (tiff, NULL, error);
379         
380         TIFFClose (tiff);
381         if (global_error) {
382                 tiff_set_error (error,
383                                 GDK_PIXBUF_ERROR_FAILED,
384                                 _("TIFFClose operation failed"));
385         }
386         
387         tiff_pop_handlers ();
388
389         G_UNLOCK (tiff_loader);
390         
391         return pixbuf;
392 }
393
394 \f
395
396 /* Progressive loader */
397
398 static gpointer
399 gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
400                                    GdkPixbufModulePreparedFunc prepare_func,
401                                    GdkPixbufModuleUpdatedFunc update_func,
402                                    gpointer user_data,
403                                    GError **error)
404 {
405         TiffContext *context;
406         
407         context = g_new0 (TiffContext, 1);
408         context->size_func = size_func;
409         context->prepare_func = prepare_func;
410         context->update_func = update_func;
411         context->user_data = user_data;
412         context->buffer = NULL;
413         context->allocated = 0;
414         context->used = 0;
415         context->pos = 0;
416         
417         return context;
418 }
419
420 static tsize_t
421 tiff_read (thandle_t handle, tdata_t buf, tsize_t size)
422 {
423         TiffContext *context = (TiffContext *)handle;
424         
425         if (context->pos + size > context->used)
426                 return 0;
427         
428         memcpy (buf, context->buffer + context->pos, size);
429         context->pos += size;
430         return size;
431 }
432
433 static tsize_t
434 tiff_write (thandle_t handle, tdata_t buf, tsize_t size)
435 {
436         return -1;
437 }
438
439 static toff_t
440 tiff_seek (thandle_t handle, toff_t offset, int whence)
441 {
442         TiffContext *context = (TiffContext *)handle;
443         
444         switch (whence) {
445         case SEEK_SET:
446                 if (offset > context->used || offset < 0)
447                         return -1;
448                 context->pos = offset;
449                 break;
450         case SEEK_CUR:
451                 if (offset + context->pos >= context->used)
452                         return -1;
453                 context->pos += offset;
454                 break;
455         case SEEK_END:
456                 if (offset + context->used > context->used)
457                         return -1;
458                 context->pos = context->used + offset;
459                 break;
460         default:
461                 return -1;
462                 break;
463         }
464         return context->pos;
465 }
466
467 static int
468 tiff_close (thandle_t context)
469 {
470         return 0;
471 }
472
473 static toff_t
474 tiff_size (thandle_t handle)
475 {
476         TiffContext *context = (TiffContext *)handle;
477         
478         return context->used;
479 }
480
481 static int
482 tiff_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
483 {
484         TiffContext *context = (TiffContext *)handle;
485         
486         *buf = context->buffer;
487         *size = context->used;
488         
489         return 0;
490 }
491
492 static void
493 tiff_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
494 {
495 }
496
497 static gboolean
498 gdk_pixbuf__tiff_image_stop_load (gpointer data,
499                                   GError **error)
500 {
501         TiffContext *context = data;
502         TIFF *tiff;
503         gboolean retval;
504         
505         g_return_val_if_fail (data != NULL, FALSE);
506
507         G_LOCK (tiff_loader);
508         
509         tiff_push_handlers ();
510         
511         tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data, 
512                                tiff_read, tiff_write, 
513                                tiff_seek, tiff_close, 
514                                tiff_size, 
515                                tiff_map_file, tiff_unmap_file);
516         if (!tiff || global_error) {
517                 tiff_set_error (error,
518                                 GDK_PIXBUF_ERROR_FAILED,
519                                 _("Failed to load TIFF image"));
520                 retval = FALSE;
521         } else {
522                 GdkPixbuf *pixbuf;
523                 
524                 pixbuf = tiff_image_parse (tiff, context, error);
525                 if (pixbuf)
526                         g_object_unref (pixbuf);
527                 retval = pixbuf != NULL;
528                 if (global_error)
529                         {
530                                 tiff_set_error (error,
531                                                 GDK_PIXBUF_ERROR_FAILED,
532                                                 _("Failed to load TIFF image"));
533                                 tiff_pop_handlers ();
534
535                                 retval = FALSE;
536                         }
537         }
538
539         if (tiff)
540                 TIFFClose (tiff);
541
542         g_assert (!global_error);
543         
544         g_free (context->buffer);
545         g_free (context);
546
547         tiff_pop_handlers ();
548
549         G_UNLOCK (tiff_loader);
550
551         return retval;
552 }
553
554 static gboolean
555 make_available_at_least (TiffContext *context, guint needed)
556 {
557         guchar *new_buffer = NULL;
558         guint need_alloc;
559         
560         need_alloc = context->used + needed;
561         if (need_alloc > context->allocated) {
562                 guint new_size = 1;
563                 while (new_size < need_alloc)
564                         new_size *= 2;
565                 
566                 new_buffer = g_try_realloc (context->buffer, new_size);
567                 if (new_buffer) {
568                         context->buffer = new_buffer;
569                         context->allocated = new_size;
570                         return TRUE;
571                 }
572                 return FALSE;
573         }
574         return TRUE;
575 }
576
577 static gboolean
578 gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
579                                        guint size, GError **error)
580 {
581         TiffContext *context = (TiffContext *) data;
582         
583         g_return_val_if_fail (data != NULL, FALSE);
584         
585         if (!make_available_at_least (context, size)) {
586                 g_set_error (error,
587                              GDK_PIXBUF_ERROR,
588                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
589                              _("Insufficient memory to open TIFF file"));
590                 return FALSE;
591         }
592         
593         memcpy (context->buffer + context->used, buf, size);
594         context->used += size;
595         return TRUE;
596 }
597
598 void
599 MODULE_ENTRY (tiff, fill_vtable) (GdkPixbufModule *module)
600 {
601         module->load = gdk_pixbuf__tiff_image_load;
602         module->begin_load = gdk_pixbuf__tiff_image_begin_load;
603         module->stop_load = gdk_pixbuf__tiff_image_stop_load;
604         module->load_increment = gdk_pixbuf__tiff_image_load_increment;
605 }
606
607 void
608 MODULE_ENTRY (tiff, fill_info) (GdkPixbufFormat *info)
609 {
610         static GdkPixbufModulePattern signature[] = {
611                 { "MM \x2a", "  z ", 100 },
612                 { "II\x2a ", "   z", 100 },
613                 { NULL, NULL, 0 }
614         };
615         static gchar * mime_types[] = {
616                 "image/tiff",
617                 NULL
618         };
619         static gchar * extensions[] = {
620                 "tiff",
621                 "tif",
622                 NULL
623         };
624
625         info->name = "tiff";
626         info->signature = signature;
627         info->description = N_("The TIFF image format");
628         info->mime_types = mime_types;
629         info->extensions = extensions;
630         info->flags = 0;
631         info->license = "LGPL";
632 }