]> www.fi.muni.cz Git - evince.git/blob - tiff/tiff-document.c
a4c8638ab3042a4512f4e4a2841d216dff7a3077
[evince.git] / tiff / tiff-document.c
1
2 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
3 /*
4  * Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /* FIXME: Shoudl probably buffer calls to libtiff with TIFFSetWarningHandler
22  */
23 #include "tiffio.h"
24 #include "tiff-document.h"
25 #include "ev-document-thumbnails.h"
26 #include "ev-document-misc.h"
27
28 struct _TiffDocumentClass
29 {
30   GObjectClass parent_class;
31 };
32
33 struct _TiffDocument
34 {
35   GObject parent_instance;
36
37   TIFF *tiff;
38   gint n_pages;
39   EvOrientation orientation;
40 };
41
42 typedef struct _TiffDocumentClass TiffDocumentClass;
43
44 static void tiff_document_document_iface_init (EvDocumentIface *iface);
45 static void tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
46
47 G_DEFINE_TYPE_WITH_CODE (TiffDocument, tiff_document, G_TYPE_OBJECT,
48                          { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
49                                                   tiff_document_document_iface_init);
50                            G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
51                                                   tiff_document_document_thumbnails_iface_init);
52                          });
53
54 static TIFFErrorHandler orig_error_handler = NULL;
55 static TIFFErrorHandler orig_warning_handler = NULL;
56
57 static void
58 push_handlers (void)
59 {
60   orig_error_handler = TIFFSetErrorHandler (NULL);
61   orig_warning_handler = TIFFSetWarningHandler (NULL);
62 }
63
64 static void
65 pop_handlers (void)
66 {
67   TIFFSetErrorHandler (orig_error_handler);
68   TIFFSetWarningHandler (orig_warning_handler);
69 }
70
71 static gboolean
72 tiff_document_load (EvDocument  *document,
73                     const char  *uri,
74                     GError     **error)
75 {
76   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
77   gchar *filename;
78   TIFF *tiff;
79
80   push_handlers ();
81   /* FIXME: We could actually load uris  */
82   filename = g_filename_from_uri (uri, NULL, error);
83   if (!filename)
84     {
85       pop_handlers ();
86       return FALSE;
87     }
88
89   tiff = TIFFOpen (filename, "r");
90   if (tiff)
91     {
92       guint32 w, h;
93       
94       TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
95       TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
96     }
97   if (!tiff)
98     {
99       pop_handlers ();
100       return FALSE;
101     }
102   tiff_document->tiff = tiff;
103
104   pop_handlers ();
105   return TRUE;
106 }
107
108 static gboolean
109 tiff_document_save (EvDocument  *document,
110                       const char  *uri,
111                       GError     **error)
112 {
113         return FALSE;
114 }
115
116 static int
117 tiff_document_get_n_pages (EvDocument  *document)
118 {
119   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
120
121   g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
122   g_return_val_if_fail (tiff_document->tiff != NULL, 0);
123
124   if (tiff_document->n_pages == -1)
125     {
126       push_handlers ();
127       tiff_document->n_pages = 0;
128       do
129         {
130           tiff_document->n_pages ++;
131         }
132       while (TIFFReadDirectory (tiff_document->tiff));
133       pop_handlers ();
134     }
135
136   return tiff_document->n_pages;
137 }
138
139 static void
140 tiff_document_get_page_size (EvDocument   *document,
141                              int           page,
142                              double       *width,
143                              double       *height)
144 {
145   guint32 w, h;
146   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
147
148   g_return_if_fail (TIFF_IS_DOCUMENT (document));
149   g_return_if_fail (tiff_document->tiff != NULL);
150
151   push_handlers ();
152   if (TIFFSetDirectory (tiff_document->tiff, page) != 1)
153     {
154       pop_handlers ();
155       return;
156     }
157
158   TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &w);
159   TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &h);
160
161   if (tiff_document->orientation == EV_ORIENTATION_PORTRAIT ||
162       tiff_document->orientation ==  EV_ORIENTATION_UPSIDEDOWN) {
163     *width = w;
164     *height = h;
165   } else {
166     *width = h;
167     *height = w;
168   }
169   pop_handlers ();
170 }
171
172 static EvOrientation
173 tiff_document_get_orientation (EvDocument *document)
174 {
175         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
176
177         return tiff_document->orientation;
178 }
179
180 static void
181 tiff_document_set_orientation (EvDocument *document,
182                              EvOrientation   orientation)
183 {
184         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
185
186         tiff_document->orientation = orientation;
187 }
188
189 static GdkPixbuf *
190 rotate_pixbuf (EvDocument *document, GdkPixbuf *pixbuf)
191 {
192         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
193
194         switch (tiff_document->orientation)
195         {
196                 case EV_ORIENTATION_LANDSCAPE:
197                         return gdk_pixbuf_rotate_simple (pixbuf, 90);
198                 case EV_ORIENTATION_UPSIDEDOWN:
199                         return gdk_pixbuf_rotate_simple (pixbuf, 180);
200                 case EV_ORIENTATION_SEASCAPE:
201                         return gdk_pixbuf_rotate_simple (pixbuf, 270);
202                 default:
203                         return g_object_ref (pixbuf);
204         }
205 }
206
207 static GdkPixbuf *
208 tiff_document_render_pixbuf (EvDocument  *document, int page, double scale)
209 {
210   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
211   int width, height;
212   gint rowstride, bytes;
213   guchar *pixels = NULL;
214   GdkPixbuf *pixbuf;
215   GdkPixbuf *scaled_pixbuf;
216   GdkPixbuf *rotated_pixbuf;
217
218   g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
219   g_return_val_if_fail (tiff_document->tiff != NULL, 0);
220
221   push_handlers ();
222   if (TIFFSetDirectory (tiff_document->tiff, page) != 1)
223     {
224       pop_handlers ();
225       return NULL;
226     }
227
228   if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width))
229     {
230       pop_handlers ();
231       return NULL;
232     }
233
234   if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height))
235     {
236       pop_handlers ();
237       return NULL;
238     }
239
240   pop_handlers ();
241
242   /* Sanity check the doc */
243   if (width <= 0 || height <= 0)
244     return NULL;                
245         
246   rowstride = width * 4;
247   if (rowstride / 4 != width)
248     /* overflow */
249     return NULL;                
250         
251   bytes = height * rowstride;
252   if (bytes / rowstride != height)
253     /* overflow */
254     return NULL;                
255
256   pixels = g_try_malloc (bytes);
257   if (!pixels)
258     return NULL;
259
260   pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
261                                      width, height, rowstride,
262                                      (GdkPixbufDestroyNotify) g_free, NULL);
263
264   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
265   TIFFReadRGBAImageOriented (tiff_document->tiff, width, height, (uint32 *)gdk_pixbuf_get_pixels (pixbuf), ORIENTATION_TOPLEFT, 1);
266   pop_handlers ();
267
268   scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
269                                            width * scale,
270                                            height * scale,
271                                            GDK_INTERP_BILINEAR);
272   g_object_unref (pixbuf);
273
274   rotated_pixbuf = rotate_pixbuf (document, scaled_pixbuf);
275   g_object_unref (scaled_pixbuf);
276
277   return rotated_pixbuf;
278 }
279
280 static void
281 tiff_document_finalize (GObject *object)
282 {
283         TiffDocument *tiff_document = TIFF_DOCUMENT (object);
284
285         TIFFClose (tiff_document->tiff);
286
287         G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
288 }
289
290 static void
291 tiff_document_class_init (TiffDocumentClass *klass)
292 {
293         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
294
295         gobject_class->finalize = tiff_document_finalize;
296 }
297
298 static gboolean
299 tiff_document_can_get_text (EvDocument *document)
300 {
301         return FALSE;
302 }
303
304 static EvDocumentInfo *
305 tiff_document_get_info (EvDocument *document)
306 {
307         EvDocumentInfo *info;
308
309         info = g_new0 (EvDocumentInfo, 1);
310         info->fields_mask = 0;
311
312         return info;
313 }
314
315 static void
316 tiff_document_document_iface_init (EvDocumentIface *iface)
317 {
318         iface->load = tiff_document_load;
319         iface->save = tiff_document_save;
320         iface->can_get_text = tiff_document_can_get_text;
321         iface->get_n_pages = tiff_document_get_n_pages;
322         iface->get_page_size = tiff_document_get_page_size;
323         iface->render_pixbuf = tiff_document_render_pixbuf;
324         iface->get_info = tiff_document_get_info;
325         iface->get_orientation = tiff_document_get_orientation;
326         iface->set_orientation = tiff_document_set_orientation;
327 }
328
329 static GdkPixbuf *
330 tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
331                                         gint                  page,
332                                         gint                  size,
333                                         gboolean              border)
334 {
335   GdkPixbuf *pixbuf;
336   gdouble w, h;
337
338   tiff_document_get_page_size (EV_DOCUMENT (document),
339                                page,
340                                &w, &h);
341
342   pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document),
343                                         page,
344                                         size/w);
345
346   if (border)
347     {
348       GdkPixbuf *tmp_pixbuf = pixbuf;
349       pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
350       g_object_unref (tmp_pixbuf);
351     }
352
353   return pixbuf;
354 }
355
356 static void
357 tiff_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
358                                          gint                  page,
359                                          gint                  suggested_width,
360                                          gint                 *width,
361                                          gint                 *height)
362 {
363   gdouble page_ratio;
364   gdouble w, h;
365
366   tiff_document_get_page_size (EV_DOCUMENT (document),
367                                page,
368                                &w, &h);
369   g_return_if_fail (w > 0);
370   page_ratio = h/w;
371   *width = suggested_width;
372   *height = (gint) (suggested_width * page_ratio);
373 }
374
375 static void
376 tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
377 {
378   iface->get_thumbnail = tiff_document_thumbnails_get_thumbnail;
379   iface->get_dimensions = tiff_document_thumbnails_get_dimensions;
380 }
381
382
383 static void
384 tiff_document_init (TiffDocument *tiff_document)
385 {
386   tiff_document->n_pages = -1;
387   tiff_document->orientation = EV_ORIENTATION_PORTRAIT;
388 }