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