Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tiff-document.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 /* FIXME: Should probably buffer calls to libtiff with TIFFSetWarningHandler
21  */
22 
23 #include "config.h"
24 
25 #include <config.h>
26 #include <stdio.h>
27 #include <glib.h>
28 #include <glib/gi18n-lib.h>
29 
30 #include "tiffio.h"
31 #include "tiff2ps.h"
32 #include "tiff-document.h"
33 #include "ev-document-misc.h"
34 #include "ev-file-exporter.h"
35 #include "ev-file-helpers.h"
36 
38 {
40 };
41 
43 {
45 
46  TIFF *tiff;
47  gint n_pages;
49 
50  gchar *uri;
51 };
52 
54 
56 
58  {
61  });
62 
63 static TIFFErrorHandler orig_error_handler = NULL;
64 static TIFFErrorHandler orig_warning_handler = NULL;
65 
66 static void
68 {
69  orig_error_handler = TIFFSetErrorHandler (NULL);
70  orig_warning_handler = TIFFSetWarningHandler (NULL);
71 }
72 
73 static void
75 {
76  TIFFSetErrorHandler (orig_error_handler);
77  TIFFSetWarningHandler (orig_warning_handler);
78 }
79 
80 static gboolean
82  const char *uri,
83  GError **error)
84 {
85  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
86  gchar *filename;
87  TIFF *tiff;
88 
89  filename = g_filename_from_uri (uri, NULL, error);
90  if (!filename)
91  return FALSE;
92 
93  push_handlers ();
94 
95 #ifdef G_OS_WIN32
96 {
97  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, error);
98  if (wfilename == NULL) {
99  return FALSE;
100  }
101 
102  tiff = TIFFOpenW (wfilename, "r");
103 
104  g_free (wfilename);
105 }
106 #else
107  tiff = TIFFOpen (filename, "r");
108 #endif
109  if (tiff) {
110  guint32 w, h;
111 
112  /* FIXME: unused data? why bother here */
113  TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
114  TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
115  }
116 
117  if (!tiff) {
118  pop_handlers ();
119 
120  g_set_error_literal (error,
123  _("Invalid document"));
124 
125  g_free (filename);
126  return FALSE;
127  }
128 
129  tiff_document->tiff = tiff;
130  g_free (tiff_document->uri);
131  g_free (filename);
132  tiff_document->uri = g_strdup (uri);
133 
134  pop_handlers ();
135  return TRUE;
136 }
137 
138 static gboolean
140  const char *uri,
141  GError **error)
142 {
143  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
144 
145  return ev_xfer_uri_simple (tiff_document->uri, uri, error);
146 }
147 
148 static int
150 {
151  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
152 
153  g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
154  g_return_val_if_fail (tiff_document->tiff != NULL, 0);
155 
156  if (tiff_document->n_pages == -1) {
157  push_handlers ();
158  tiff_document->n_pages = 0;
159 
160  do {
161  tiff_document->n_pages ++;
162  }
163  while (TIFFReadDirectory (tiff_document->tiff));
164  pop_handlers ();
165  }
166 
167  return tiff_document->n_pages;
168 }
169 
170 static void
172  gfloat *x_res,
173  gfloat *y_res)
174 {
175  gfloat x = 0.0;
176  gfloat y = 0.0;
177  gushort unit;
178 
179  if (TIFFGetField (tiff_document->tiff, TIFFTAG_XRESOLUTION, &x) &&
180  TIFFGetField (tiff_document->tiff, TIFFTAG_YRESOLUTION, &y)) {
181  if (TIFFGetFieldDefaulted (tiff_document->tiff, TIFFTAG_RESOLUTIONUNIT, &unit)) {
182  if (unit == RESUNIT_CENTIMETER) {
183  x *= 2.54;
184  y *= 2.54;
185  }
186  }
187  }
188 
189  /* Handle 0 values: some software set TIFF resolution as `0 , 0` see bug #646414 */
190  *x_res = x > 0 ? x : 72.0;
191  *y_res = y > 0 ? y : 72.0;
192 }
193 
194 static void
196  EvPage *page,
197  double *width,
198  double *height)
199 {
200  guint32 w, h;
201  gfloat x_res, y_res;
202  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
203 
204  g_return_if_fail (TIFF_IS_DOCUMENT (document));
205  g_return_if_fail (tiff_document->tiff != NULL);
206 
207  push_handlers ();
208  if (TIFFSetDirectory (tiff_document->tiff, page->index) != 1) {
209  pop_handlers ();
210  return;
211  }
212 
213  TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &w);
214  TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &h);
215  tiff_document_get_resolution (tiff_document, &x_res, &y_res);
216  h = h * (x_res / y_res);
217 
218  *width = w;
219  *height = h;
220 
221  pop_handlers ();
222 }
223 
224 static cairo_surface_t *
226  EvRenderContext *rc)
227 {
228  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
229  int width, height;
230  int scaled_width, scaled_height;
231  float x_res, y_res;
232  gint rowstride, bytes;
233  guchar *pixels = NULL;
234  guchar *p;
235  int orientation;
236  cairo_surface_t *surface;
237  cairo_surface_t *rotated_surface;
238  static const cairo_user_data_key_t key;
239 
240  g_return_val_if_fail (TIFF_IS_DOCUMENT (document), NULL);
241  g_return_val_if_fail (tiff_document->tiff != NULL, NULL);
242 
243  push_handlers ();
244  if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
245  pop_handlers ();
246  g_warning("Failed to select page %d", rc->page->index);
247  return NULL;
248  }
249 
250  if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
251  pop_handlers ();
252  g_warning("Failed to read image width");
253  return NULL;
254  }
255 
256  if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
257  pop_handlers ();
258  g_warning("Failed to read image height");
259  return NULL;
260  }
261 
262  if (! TIFFGetField (tiff_document->tiff, TIFFTAG_ORIENTATION, &orientation)) {
263  orientation = ORIENTATION_TOPLEFT;
264  }
265 
266  tiff_document_get_resolution (tiff_document, &x_res, &y_res);
267 
268  pop_handlers ();
269 
270  /* Sanity check the doc */
271  if (width <= 0 || height <= 0) {
272  g_warning("Invalid width or height.");
273  return NULL;
274  }
275 
276 #ifdef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
277  rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
278 #else
279  rowstride = width * 4;
280 #endif
281  if (rowstride / 4 != width) {
282  g_warning("Overflow while rendering document.");
283  /* overflow, or cairo was changed in an unsupported way */
284  return NULL;
285  }
286 
287  bytes = height * rowstride;
288  if (bytes / rowstride != height) {
289  g_warning("Overflow while rendering document.");
290  /* overflow */
291  return NULL;
292  }
293 
294  pixels = g_try_malloc (bytes);
295  if (!pixels) {
296  g_warning("Failed to allocate memory for rendering.");
297  return NULL;
298  }
299 
300  surface = cairo_image_surface_create_for_data (pixels,
301  CAIRO_FORMAT_RGB24,
302  width, height,
303  rowstride);
304  cairo_surface_set_user_data (surface, &key,
305  pixels, (cairo_destroy_func_t)g_free);
306 
307  TIFFReadRGBAImageOriented (tiff_document->tiff,
308  width, height,
309  (uint32 *)pixels,
310  orientation, 0);
311  pop_handlers ();
312 
313  /* Convert the format returned by libtiff to
314  * what cairo expects
315  */
316  p = pixels;
317  while (p < pixels + bytes) {
318  guint32 *pixel = (guint32*)p;
319  guint8 r = TIFFGetR(*pixel);
320  guint8 g = TIFFGetG(*pixel);
321  guint8 b = TIFFGetB(*pixel);
322  guint8 a = TIFFGetA(*pixel);
323 
324  *pixel = (a << 24) | (r << 16) | (g << 8) | b;
325 
326  p += 4;
327  }
328 
329  ev_render_context_compute_scaled_size (rc, width, height * (x_res / y_res),
330  &scaled_width, &scaled_height);
331  rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
332  scaled_width, scaled_height,
333  rc->rotation);
334  cairo_surface_destroy (surface);
335 
336  return rotated_surface;
337 }
338 
339 static GdkPixbuf *
341  EvRenderContext *rc)
342 {
343  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
344  int width, height;
345  int scaled_width, scaled_height;
346  float x_res, y_res;
347  gint rowstride, bytes;
348  guchar *pixels = NULL;
349  GdkPixbuf *pixbuf;
350  GdkPixbuf *scaled_pixbuf;
351  GdkPixbuf *rotated_pixbuf;
352 
353  push_handlers ();
354  if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
355  pop_handlers ();
356  return NULL;
357  }
358 
359  if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
360  pop_handlers ();
361  return NULL;
362  }
363 
364  if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
365  pop_handlers ();
366  return NULL;
367  }
368 
369  tiff_document_get_resolution (tiff_document, &x_res, &y_res);
370 
371  pop_handlers ();
372 
373  /* Sanity check the doc */
374  if (width <= 0 || height <= 0)
375  return NULL;
376 
377  rowstride = width * 4;
378  if (rowstride / 4 != width)
379  /* overflow */
380  return NULL;
381 
382  bytes = height * rowstride;
383  if (bytes / rowstride != height)
384  /* overflow */
385  return NULL;
386 
387  pixels = g_try_malloc (bytes);
388  if (!pixels)
389  return NULL;
390 
391  pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
392  width, height, rowstride,
393  (GdkPixbufDestroyNotify) g_free, NULL);
394  TIFFReadRGBAImageOriented (tiff_document->tiff,
395  width, height,
396  (uint32 *)pixels,
397  ORIENTATION_TOPLEFT, 0);
398  pop_handlers ();
399 
400  ev_render_context_compute_scaled_size (rc, width, height * (x_res / y_res),
401  &scaled_width, &scaled_height);
402  scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
403  scaled_width, scaled_height,
404  GDK_INTERP_BILINEAR);
405  g_object_unref (pixbuf);
406 
407  rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation);
408  g_object_unref (scaled_pixbuf);
409 
410  return rotated_pixbuf;
411 }
412 
413 static gchar *
415  EvPage *page)
416 {
417  TiffDocument *tiff_document = TIFF_DOCUMENT (document);
418  static gchar *label;
419 
420  if (TIFFGetField (tiff_document->tiff, TIFFTAG_PAGENAME, &label) &&
421  g_utf8_validate (label, -1, NULL)) {
422  return g_strdup (label);
423  }
424 
425  return NULL;
426 }
427 
428 static void
429 tiff_document_finalize (GObject *object)
430 {
431  TiffDocument *tiff_document = TIFF_DOCUMENT (object);
432 
433  if (tiff_document->tiff)
434  TIFFClose (tiff_document->tiff);
435  if (tiff_document->uri)
436  g_free (tiff_document->uri);
437 
438  G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
439 }
440 
441 static void
443 {
444  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
445  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
446 
447  gobject_class->finalize = tiff_document_finalize;
448 
449  ev_document_class->load = tiff_document_load;
450  ev_document_class->save = tiff_document_save;
451  ev_document_class->get_n_pages = tiff_document_get_n_pages;
452  ev_document_class->get_page_size = tiff_document_get_page_size;
453  ev_document_class->render = tiff_document_render;
454  ev_document_class->get_thumbnail = tiff_document_get_thumbnail;
455  ev_document_class->get_page_label = tiff_document_get_page_label;
456 }
457 
458 /* postscript exporter implementation */
459 static void
462 {
463  TiffDocument *document = TIFF_DOCUMENT (exporter);
464 
465  document->ps_export_ctx = tiff2ps_context_new(fc->filename);
466 }
467 
468 static void
470 {
471  TiffDocument *document = TIFF_DOCUMENT (exporter);
472 
473  if (document->ps_export_ctx == NULL)
474  return;
475  if (TIFFSetDirectory (document->tiff, rc->page->index) != 1)
476  return;
477  tiff2ps_process_page (document->ps_export_ctx, document->tiff,
478  0, 0, 0, 0, 0);
479 }
480 
481 static void
483 {
484  TiffDocument *document = TIFF_DOCUMENT (exporter);
485 
486  if (document->ps_export_ctx == NULL)
487  return;
489 }
490 
493 {
499 }
500 
501 static void
503 {
508 }
509 
510 static void
512 {
513  tiff_document->n_pages = -1;
514 }