]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tiff.c
fix .tiff loader.
[~andy/gtk] / gdk-pixbuf / io-tiff.c
1 /* GdkPixbuf library - JPEG image loader
2  *
3  * Copyright (C) 1999 Mark Crichton
4  * Copyright (C) 1999 The Free Software Foundation
5  *
6  * Authors: Mark Crichton <crichton@gimp.org>
7  *          Federico Mena-Quintero <federico@gimp.org>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /* Following code (almost) blatantly ripped from Imlib */
26
27 #include <config.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <tiffio.h>
31 #include "gdk-pixbuf.h"
32 #include "gdk-pixbuf-io.h"
33 #include <unistd.h>
34
35 \f
36
37 typedef struct _TiffData TiffData;
38 struct _TiffData
39 {
40         ModulePreparedNotifyFunc prepare_func;
41         ModuleUpdatedNotifyFunc update_func;
42         gpointer user_data;
43
44         gchar *tempname;
45         FILE *file;
46         gboolean all_okay;
47 };
48
49 \f
50
51 GdkPixbuf *
52 image_load_real (FILE *f, TiffData *context)
53 {
54         TIFF *tiff;
55         guchar *pixels = NULL;
56         guchar *tmppix;
57         gint w, h, x, y, num_pixs, fd;
58         uint32 *rast, *tmp_rast;
59         GdkPixbuf *pixbuf;
60         
61         fd = fileno (f);
62         tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
63
64         if (!tiff)
65                 return NULL;
66
67         TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &w);
68         TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &h);
69         num_pixs = w * h;
70         pixbuf = gdk_pixbuf_new (ART_PIX_RGB, TRUE, 8, w, h);
71
72         if (context)
73                 (* context->prepare_func) (pixbuf, context->user_data);
74
75         /* Yes, it needs to be _TIFFMalloc... */
76         rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
77
78         if (!rast) {
79                 TIFFClose (tiff);
80                 return NULL;
81         }
82
83         if (TIFFReadRGBAImage (tiff, w, h, rast, 0)) {
84                 pixels = gdk_pixbuf_get_pixels (pixbuf);
85                 if (!pixels) {
86                         _TIFFfree (rast);
87                         TIFFClose (tiff);
88                         return NULL;
89                 }
90                 tmppix = pixels;
91
92                 for (y = 0; y < h; y++) {
93                         /* Unexplainable...are tiffs backwards? */
94                         /* Also looking at the GIMP plugin, this
95                          * whole reading thing can be a bit more
96                          * robust.
97                          */
98                         tmp_rast = rast + ((h - y - 1) * w);
99                         for (x = 0; x < w; x++) {
100                                 tmppix[0] = TIFFGetR (*tmp_rast);
101                                 tmppix[1] = TIFFGetG (*tmp_rast);
102                                 tmppix[2] = TIFFGetB (*tmp_rast);
103                                 tmppix[3] = TIFFGetA (*tmp_rast);
104                                 tmp_rast++;
105                                 tmppix += 4;
106                         }
107                 }
108         }
109         _TIFFfree (rast);
110         TIFFClose (tiff);
111
112         if (context) {
113                 gdk_pixbuf_unref (pixbuf);
114                 (* context->update_func) (pixbuf, context->user_data, 0, 0, w, h);
115         }
116
117         return pixbuf;
118 }
119
120 \f
121
122 /* Static loader */
123
124 GdkPixbuf *
125 image_load (FILE *f)
126 {
127         return image_load_real (f, NULL);
128 }
129
130 \f
131
132 /* Progressive loader */
133 /*
134  * Tiff loading progressively cannot be done.  We write it to a file, then load
135  * the file when it's done.  It's not pretty.
136  */
137
138
139 gpointer
140 image_begin_load (ModulePreparedNotifyFunc prepare_func,
141                   ModuleUpdatedNotifyFunc update_func,
142                   gpointer user_data)
143 {
144         TiffData *context;
145         gint fd;
146
147         context = g_new (TiffData, 1);
148         context->prepare_func = prepare_func;
149         context->update_func = update_func;
150         context->user_data = user_data;
151         context->all_okay = TRUE;
152         context->tempname = g_strdup ("/tmp/gdkpixbuf-tif-tmp.XXXXXX");
153         fd = mkstemp (context->tempname);
154         if (fd < 0) {
155                 g_free (context);
156                 return NULL;
157         }
158
159         context->file = fdopen (fd, "w");
160         if (context->file == NULL) {
161                 g_free (context);
162                 return NULL;
163         }
164
165         return context;
166 }
167
168 void
169 image_stop_load (gpointer data)
170 {
171         TiffData *context = (TiffData*) data;
172
173         g_return_if_fail (data != NULL);
174
175         fflush (context->file);
176         rewind (context->file);
177         if (context->all_okay)
178                 image_load_real (context->file, context);
179
180         fclose (context->file);
181         unlink (context->tempname);
182         g_free ((TiffData *) context);
183 }
184
185 gboolean
186 image_load_increment (gpointer data, guchar *buf, guint size)
187 {
188         TiffData *context = (TiffData *) data;
189
190         g_return_val_if_fail (data != NULL, FALSE);
191
192         if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
193                 context->all_okay = FALSE;
194                 return FALSE;
195         }
196
197         return TRUE;
198 }
199