]> www.fi.muni.cz Git - evince.git/blob - tiff/tiff-document.c
scale the reported height by using the resolution aspect ratio
[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       /* FIXME: unused data? why bother here */
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   gfloat x_res, y_res;
147   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
148
149   g_return_if_fail (TIFF_IS_DOCUMENT (document));
150   g_return_if_fail (tiff_document->tiff != NULL);
151
152   push_handlers ();
153   if (TIFFSetDirectory (tiff_document->tiff, page) != 1)
154     {
155       pop_handlers ();
156       return;
157     }
158
159   TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &w);
160   TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &h);
161   TIFFGetField (tiff_document->tiff, TIFFTAG_XRESOLUTION, &x_res);
162   TIFFGetField (tiff_document->tiff, TIFFTAG_YRESOLUTION, &y_res);
163   h = h * (x_res / y_res);
164
165   if (tiff_document->orientation == EV_ORIENTATION_PORTRAIT ||
166       tiff_document->orientation ==  EV_ORIENTATION_UPSIDEDOWN) {
167     *width = w;
168     *height = h;
169   } else {
170     *width = h;
171     *height = w;
172   }
173   pop_handlers ();
174 }
175
176 static EvOrientation
177 tiff_document_get_orientation (EvDocument *document)
178 {
179         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
180
181         return tiff_document->orientation;
182 }
183
184 static void
185 tiff_document_set_orientation (EvDocument *document,
186                              EvOrientation   orientation)
187 {
188         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
189
190         tiff_document->orientation = orientation;
191 }
192
193 static GdkPixbuf *
194 rotate_pixbuf (EvDocument *document, GdkPixbuf *pixbuf)
195 {
196         TiffDocument *tiff_document = TIFF_DOCUMENT (document);
197
198         switch (tiff_document->orientation)
199         {
200                 case EV_ORIENTATION_LANDSCAPE:
201                         return gdk_pixbuf_rotate_simple (pixbuf, 90);
202                 case EV_ORIENTATION_UPSIDEDOWN:
203                         return gdk_pixbuf_rotate_simple (pixbuf, 180);
204                 case EV_ORIENTATION_SEASCAPE:
205                         return gdk_pixbuf_rotate_simple (pixbuf, 270);
206                 default:
207                         return g_object_ref (pixbuf);
208         }
209 }
210
211 static GdkPixbuf *
212 tiff_document_render_pixbuf (EvDocument      *document,
213                              EvRenderContext *rc)
214 {
215   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
216   int width, height;
217   float x_res, y_res;
218   gint rowstride, bytes;
219   guchar *pixels = NULL;
220   GdkPixbuf *pixbuf;
221   GdkPixbuf *scaled_pixbuf;
222   GdkPixbuf *rotated_pixbuf;
223
224   g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
225   g_return_val_if_fail (tiff_document->tiff != NULL, 0);
226
227   push_handlers ();
228   if (TIFFSetDirectory (tiff_document->tiff, rc->page) != 1)
229     {
230       pop_handlers ();
231       return NULL;
232     }
233
234   if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width))
235     {
236       pop_handlers ();
237       return NULL;
238     }
239
240   if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height))
241     {
242       pop_handlers ();
243       return NULL;
244     }
245
246   if (!TIFFGetField (tiff_document->tiff, TIFFTAG_XRESOLUTION, &x_res))
247     {
248       pop_handlers ();
249       return NULL;
250     }
251
252   if (! TIFFGetField (tiff_document->tiff, TIFFTAG_YRESOLUTION, &y_res))
253     {
254       pop_handlers ();
255       return NULL;
256     }
257
258   pop_handlers ();
259
260   /* Sanity check the doc */
261   if (width <= 0 || height <= 0)
262     return NULL;                
263         
264   rowstride = width * 4;
265   if (rowstride / 4 != width)
266     /* overflow */
267     return NULL;                
268         
269   bytes = height * rowstride;
270   if (bytes / rowstride != height)
271     /* overflow */
272     return NULL;                
273
274   pixels = g_try_malloc (bytes);
275   if (!pixels)
276     return NULL;
277
278   pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
279                                      width, height, rowstride,
280                                      (GdkPixbufDestroyNotify) g_free, NULL);
281
282   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
283   TIFFReadRGBAImageOriented (tiff_document->tiff, width, height, (uint32 *)gdk_pixbuf_get_pixels (pixbuf), ORIENTATION_TOPLEFT, 1);
284   pop_handlers ();
285
286   scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
287                                            width * rc->scale,
288                                            height * rc->scale * (x_res/y_res),
289                                            GDK_INTERP_BILINEAR);
290   g_object_unref (pixbuf);
291
292   rotated_pixbuf = rotate_pixbuf (document, scaled_pixbuf);
293   g_object_unref (scaled_pixbuf);
294
295   return rotated_pixbuf;
296 }
297
298 static void
299 tiff_document_finalize (GObject *object)
300 {
301         TiffDocument *tiff_document = TIFF_DOCUMENT (object);
302
303         TIFFClose (tiff_document->tiff);
304
305         G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
306 }
307
308 static void
309 tiff_document_class_init (TiffDocumentClass *klass)
310 {
311         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
312
313         gobject_class->finalize = tiff_document_finalize;
314 }
315
316 static gboolean
317 tiff_document_can_get_text (EvDocument *document)
318 {
319         return FALSE;
320 }
321
322 static EvDocumentInfo *
323 tiff_document_get_info (EvDocument *document)
324 {
325         EvDocumentInfo *info;
326
327         info = g_new0 (EvDocumentInfo, 1);
328         info->fields_mask = 0;
329
330         return info;
331 }
332
333 static void
334 tiff_document_document_iface_init (EvDocumentIface *iface)
335 {
336         iface->load = tiff_document_load;
337         iface->save = tiff_document_save;
338         iface->can_get_text = tiff_document_can_get_text;
339         iface->get_n_pages = tiff_document_get_n_pages;
340         iface->get_page_size = tiff_document_get_page_size;
341         iface->render_pixbuf = tiff_document_render_pixbuf;
342         iface->get_info = tiff_document_get_info;
343         iface->get_orientation = tiff_document_get_orientation;
344         iface->set_orientation = tiff_document_set_orientation;
345 }
346
347 static GdkPixbuf *
348 tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
349                                         gint                  page,
350                                         gint                  size,
351                                         gboolean              border)
352 {
353   EvRenderContext *rc;
354   GdkPixbuf *pixbuf;
355   gdouble w, h;
356
357   tiff_document_get_page_size (EV_DOCUMENT (document),
358                                page,
359                                &w, &h);
360
361   rc = ev_render_context_new (EV_ORIENTATION_PORTRAIT, page, size/w);
362   pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
363   g_object_unref (G_OBJECT (rc));
364
365   if (border)
366     {
367       GdkPixbuf *tmp_pixbuf = pixbuf;
368       pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
369       g_object_unref (tmp_pixbuf);
370     }
371
372   return pixbuf;
373 }
374
375 static void
376 tiff_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
377                                          gint                  page,
378                                          gint                  suggested_width,
379                                          gint                 *width,
380                                          gint                 *height)
381 {
382   gdouble page_ratio;
383   gdouble w, h;
384
385   tiff_document_get_page_size (EV_DOCUMENT (document),
386                                page,
387                                &w, &h);
388   g_return_if_fail (w > 0);
389   page_ratio = h/w;
390   *width = suggested_width;
391   *height = (gint) (suggested_width * page_ratio);
392 }
393
394 static void
395 tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
396 {
397   iface->get_thumbnail = tiff_document_thumbnails_get_thumbnail;
398   iface->get_dimensions = tiff_document_thumbnails_get_dimensions;
399 }
400
401
402 static void
403 tiff_document_init (TiffDocument *tiff_document)
404 {
405   tiff_document->n_pages = -1;
406   tiff_document->orientation = EV_ORIENTATION_PORTRAIT;
407 }