]> www.fi.muni.cz Git - evince.git/blob - tiff/tiff-document.c
Massive changes. We now support text selection of pdfs, and not just
[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,
209                              EvRenderContext *rc)
210 {
211   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
212   int width, height;
213   gint rowstride, bytes;
214   guchar *pixels = NULL;
215   GdkPixbuf *pixbuf;
216   GdkPixbuf *scaled_pixbuf;
217   GdkPixbuf *rotated_pixbuf;
218
219   g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
220   g_return_val_if_fail (tiff_document->tiff != NULL, 0);
221
222   push_handlers ();
223   if (TIFFSetDirectory (tiff_document->tiff, rc->page) != 1)
224     {
225       pop_handlers ();
226       return NULL;
227     }
228
229   if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width))
230     {
231       pop_handlers ();
232       return NULL;
233     }
234
235   if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height))
236     {
237       pop_handlers ();
238       return NULL;
239     }
240
241   pop_handlers ();
242
243   /* Sanity check the doc */
244   if (width <= 0 || height <= 0)
245     return NULL;                
246         
247   rowstride = width * 4;
248   if (rowstride / 4 != width)
249     /* overflow */
250     return NULL;                
251         
252   bytes = height * rowstride;
253   if (bytes / rowstride != height)
254     /* overflow */
255     return NULL;                
256
257   pixels = g_try_malloc (bytes);
258   if (!pixels)
259     return NULL;
260
261   pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
262                                      width, height, rowstride,
263                                      (GdkPixbufDestroyNotify) g_free, NULL);
264
265   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
266   TIFFReadRGBAImageOriented (tiff_document->tiff, width, height, (uint32 *)gdk_pixbuf_get_pixels (pixbuf), ORIENTATION_TOPLEFT, 1);
267   pop_handlers ();
268
269   scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
270                                            width * rc->scale,
271                                            height * rc->scale,
272                                            GDK_INTERP_BILINEAR);
273   g_object_unref (pixbuf);
274
275   rotated_pixbuf = rotate_pixbuf (document, scaled_pixbuf);
276   g_object_unref (scaled_pixbuf);
277
278   return rotated_pixbuf;
279 }
280
281 static void
282 tiff_document_finalize (GObject *object)
283 {
284         TiffDocument *tiff_document = TIFF_DOCUMENT (object);
285
286         TIFFClose (tiff_document->tiff);
287
288         G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
289 }
290
291 static void
292 tiff_document_class_init (TiffDocumentClass *klass)
293 {
294         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
295
296         gobject_class->finalize = tiff_document_finalize;
297 }
298
299 static gboolean
300 tiff_document_can_get_text (EvDocument *document)
301 {
302         return FALSE;
303 }
304
305 static EvDocumentInfo *
306 tiff_document_get_info (EvDocument *document)
307 {
308         EvDocumentInfo *info;
309
310         info = g_new0 (EvDocumentInfo, 1);
311         info->fields_mask = 0;
312
313         return info;
314 }
315
316 static void
317 tiff_document_document_iface_init (EvDocumentIface *iface)
318 {
319         iface->load = tiff_document_load;
320         iface->save = tiff_document_save;
321         iface->can_get_text = tiff_document_can_get_text;
322         iface->get_n_pages = tiff_document_get_n_pages;
323         iface->get_page_size = tiff_document_get_page_size;
324         iface->render_pixbuf = tiff_document_render_pixbuf;
325         iface->get_info = tiff_document_get_info;
326         iface->get_orientation = tiff_document_get_orientation;
327         iface->set_orientation = tiff_document_set_orientation;
328 }
329
330 static GdkPixbuf *
331 tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
332                                         gint                  page,
333                                         gint                  size,
334                                         gboolean              border)
335 {
336   EvRenderContext *rc;
337   GdkPixbuf *pixbuf;
338   gdouble w, h;
339
340   tiff_document_get_page_size (EV_DOCUMENT (document),
341                                page,
342                                &w, &h);
343
344   rc = ev_render_context_new (EV_ORIENTATION_PORTRAIT, page, size/w);
345   pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
346   g_object_unref (G_OBJECT (rc));
347
348   if (border)
349     {
350       GdkPixbuf *tmp_pixbuf = pixbuf;
351       pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
352       g_object_unref (tmp_pixbuf);
353     }
354
355   return pixbuf;
356 }
357
358 static void
359 tiff_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
360                                          gint                  page,
361                                          gint                  suggested_width,
362                                          gint                 *width,
363                                          gint                 *height)
364 {
365   gdouble page_ratio;
366   gdouble w, h;
367
368   tiff_document_get_page_size (EV_DOCUMENT (document),
369                                page,
370                                &w, &h);
371   g_return_if_fail (w > 0);
372   page_ratio = h/w;
373   *width = suggested_width;
374   *height = (gint) (suggested_width * page_ratio);
375 }
376
377 static void
378 tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
379 {
380   iface->get_thumbnail = tiff_document_thumbnails_get_thumbnail;
381   iface->get_dimensions = tiff_document_thumbnails_get_dimensions;
382 }
383
384
385 static void
386 tiff_document_init (TiffDocument *tiff_document)
387 {
388   tiff_document->n_pages = -1;
389   tiff_document->orientation = EV_ORIENTATION_PORTRAIT;
390 }