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
37 struct _TiffDocumentClass
38 {
39 EvDocumentClass parent_class;
40 };
41
42 struct _TiffDocument
43 {
44 EvDocument parent_instance;
45
46 TIFF *tiff;
47 gint n_pages;
48 TIFF2PSContext *ps_export_ctx;
49
50 gchar *uri;
51 };
52
53 typedef struct _TiffDocumentClass TiffDocumentClass;
54
55 static void tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface);
56
57 EV_BACKEND_REGISTER_WITH_CODE (TiffDocument, tiff_document,
58 {
59 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
60 tiff_document_document_file_exporter_iface_init);
61 });
62
63 static TIFFErrorHandler orig_error_handler = NULL;
64 static TIFFErrorHandler orig_warning_handler = NULL;
65
66 static void
push_handlers(void)67 push_handlers (void)
68 {
69 orig_error_handler = TIFFSetErrorHandler (NULL);
70 orig_warning_handler = TIFFSetWarningHandler (NULL);
71 }
72
73 static void
pop_handlers(void)74 pop_handlers (void)
75 {
76 TIFFSetErrorHandler (orig_error_handler);
77 TIFFSetWarningHandler (orig_warning_handler);
78 }
79
80 static gboolean
tiff_document_load(EvDocument * document,const char * uri,GError ** error)81 tiff_document_load (EvDocument *document,
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,
121 EV_DOCUMENT_ERROR,
122 EV_DOCUMENT_ERROR_INVALID,
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
tiff_document_save(EvDocument * document,const char * uri,GError ** error)139 tiff_document_save (EvDocument *document,
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
tiff_document_get_n_pages(EvDocument * document)149 tiff_document_get_n_pages (EvDocument *document)
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
tiff_document_get_resolution(TiffDocument * tiff_document,gfloat * x_res,gfloat * y_res)171 tiff_document_get_resolution (TiffDocument *tiff_document,
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
tiff_document_get_page_size(EvDocument * document,EvPage * page,double * width,double * height)195 tiff_document_get_page_size (EvDocument *document,
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 *
tiff_document_render(EvDocument * document,EvRenderContext * rc)225 tiff_document_render (EvDocument *document,
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 rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
277 if (rowstride / 4 != width) {
278 g_warning("Overflow while rendering document.");
279 /* overflow, or cairo was changed in an unsupported way */
280 return NULL;
281 }
282
283 if (height >= INT_MAX / rowstride) {
284 g_warning("Overflow while rendering document.");
285 /* overflow */
286 return NULL;
287 }
288 bytes = height * rowstride;
289
290 pixels = g_try_malloc (bytes);
291 if (!pixels) {
292 g_warning("Failed to allocate memory for rendering.");
293 return NULL;
294 }
295
296 if (!TIFFReadRGBAImageOriented (tiff_document->tiff,
297 width, height,
298 (uint32 *)pixels,
299 orientation, 0)) {
300 g_warning ("Failed to read TIFF image.");
301 g_free (pixels);
302 return NULL;
303 }
304
305 surface = cairo_image_surface_create_for_data (pixels,
306 CAIRO_FORMAT_RGB24,
307 width, height,
308 rowstride);
309 cairo_surface_set_user_data (surface, &key,
310 pixels, (cairo_destroy_func_t)g_free);
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 *
tiff_document_get_thumbnail(EvDocument * document,EvRenderContext * rc)340 tiff_document_get_thumbnail (EvDocument *document,
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 if (width >= INT_MAX / 4)
378 /* overflow */
379 return NULL;
380 rowstride = width * 4;
381
382 if (height >= INT_MAX / rowstride)
383 /* overflow */
384 return NULL;
385 bytes = height * rowstride;
386
387 pixels = g_try_malloc (bytes);
388 if (!pixels)
389 return NULL;
390
391 if (!TIFFReadRGBAImageOriented (tiff_document->tiff,
392 width, height,
393 (uint32 *)pixels,
394 ORIENTATION_TOPLEFT, 0)) {
395 g_free (pixels);
396 return NULL;
397 }
398
399 pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
400 width, height, rowstride,
401 (GdkPixbufDestroyNotify) g_free, NULL);
402 pop_handlers ();
403
404 ev_render_context_compute_scaled_size (rc, width, height * (x_res / y_res),
405 &scaled_width, &scaled_height);
406 scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
407 scaled_width, scaled_height,
408 GDK_INTERP_BILINEAR);
409 g_object_unref (pixbuf);
410
411 rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation);
412 g_object_unref (scaled_pixbuf);
413
414 return rotated_pixbuf;
415 }
416
417 static gchar *
tiff_document_get_page_label(EvDocument * document,EvPage * page)418 tiff_document_get_page_label (EvDocument *document,
419 EvPage *page)
420 {
421 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
422 static gchar *label;
423
424 if (TIFFGetField (tiff_document->tiff, TIFFTAG_PAGENAME, &label) &&
425 g_utf8_validate (label, -1, NULL)) {
426 return g_strdup (label);
427 }
428
429 return NULL;
430 }
431
432 static void
tiff_document_finalize(GObject * object)433 tiff_document_finalize (GObject *object)
434 {
435 TiffDocument *tiff_document = TIFF_DOCUMENT (object);
436
437 if (tiff_document->tiff)
438 TIFFClose (tiff_document->tiff);
439 if (tiff_document->uri)
440 g_free (tiff_document->uri);
441
442 G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
443 }
444
445 static void
tiff_document_class_init(TiffDocumentClass * klass)446 tiff_document_class_init (TiffDocumentClass *klass)
447 {
448 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
449 EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
450
451 gobject_class->finalize = tiff_document_finalize;
452
453 ev_document_class->load = tiff_document_load;
454 ev_document_class->save = tiff_document_save;
455 ev_document_class->get_n_pages = tiff_document_get_n_pages;
456 ev_document_class->get_page_size = tiff_document_get_page_size;
457 ev_document_class->render = tiff_document_render;
458 ev_document_class->get_thumbnail = tiff_document_get_thumbnail;
459 ev_document_class->get_page_label = tiff_document_get_page_label;
460 }
461
462 /* postscript exporter implementation */
463 static void
tiff_document_file_exporter_begin(EvFileExporter * exporter,EvFileExporterContext * fc)464 tiff_document_file_exporter_begin (EvFileExporter *exporter,
465 EvFileExporterContext *fc)
466 {
467 TiffDocument *document = TIFF_DOCUMENT (exporter);
468
469 document->ps_export_ctx = tiff2ps_context_new(fc->filename);
470 }
471
472 static void
tiff_document_file_exporter_do_page(EvFileExporter * exporter,EvRenderContext * rc)473 tiff_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
474 {
475 TiffDocument *document = TIFF_DOCUMENT (exporter);
476
477 if (document->ps_export_ctx == NULL)
478 return;
479 if (TIFFSetDirectory (document->tiff, rc->page->index) != 1)
480 return;
481 tiff2ps_process_page (document->ps_export_ctx, document->tiff,
482 0, 0, 0, 0, 0);
483 }
484
485 static void
tiff_document_file_exporter_end(EvFileExporter * exporter)486 tiff_document_file_exporter_end (EvFileExporter *exporter)
487 {
488 TiffDocument *document = TIFF_DOCUMENT (exporter);
489
490 if (document->ps_export_ctx == NULL)
491 return;
492 tiff2ps_context_finalize(document->ps_export_ctx);
493 }
494
495 static EvFileExporterCapabilities
tiff_document_file_exporter_get_capabilities(EvFileExporter * exporter)496 tiff_document_file_exporter_get_capabilities (EvFileExporter *exporter)
497 {
498 return EV_FILE_EXPORTER_CAN_PAGE_SET |
499 EV_FILE_EXPORTER_CAN_COPIES |
500 EV_FILE_EXPORTER_CAN_COLLATE |
501 EV_FILE_EXPORTER_CAN_REVERSE |
502 EV_FILE_EXPORTER_CAN_GENERATE_PS;
503 }
504
505 static void
tiff_document_document_file_exporter_iface_init(EvFileExporterInterface * iface)506 tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface)
507 {
508 iface->begin = tiff_document_file_exporter_begin;
509 iface->do_page = tiff_document_file_exporter_do_page;
510 iface->end = tiff_document_file_exporter_end;
511 iface->get_capabilities = tiff_document_file_exporter_get_capabilities;
512 }
513
514 static void
tiff_document_init(TiffDocument * tiff_document)515 tiff_document_init (TiffDocument *tiff_document)
516 {
517 tiff_document->n_pages = -1;
518 }
519