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-document-thumbnails.h"
35 #include "ev-file-exporter.h"
36 #include "ev-file-helpers.h"
37
38 struct _TiffDocumentClass
39 {
40 EvDocumentClass parent_class;
41 };
42
43 struct _TiffDocument
44 {
45 EvDocument parent_instance;
46
47 TIFF *tiff;
48 gint n_pages;
49 TIFF2PSContext *ps_export_ctx;
50
51 gchar *uri;
52 };
53
54 typedef struct _TiffDocumentClass TiffDocumentClass;
55
56 static void tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
57 static void tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface);
58
59 EV_BACKEND_REGISTER_WITH_CODE (TiffDocument, tiff_document,
60 {
61 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
62 tiff_document_document_thumbnails_iface_init);
63 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
64 tiff_document_document_file_exporter_iface_init);
65 });
66
67 static TIFFErrorHandler orig_error_handler = NULL;
68 static TIFFErrorHandler orig_warning_handler = NULL;
69
70 static void
push_handlers(void)71 push_handlers (void)
72 {
73 orig_error_handler = TIFFSetErrorHandler (NULL);
74 orig_warning_handler = TIFFSetWarningHandler (NULL);
75 }
76
77 static void
pop_handlers(void)78 pop_handlers (void)
79 {
80 TIFFSetErrorHandler (orig_error_handler);
81 TIFFSetWarningHandler (orig_warning_handler);
82 }
83
84 static gboolean
tiff_document_load(EvDocument * document,const char * uri,GError ** error)85 tiff_document_load (EvDocument *document,
86 const char *uri,
87 GError **error)
88 {
89 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
90 gchar *filename;
91 TIFF *tiff;
92
93 filename = g_filename_from_uri (uri, NULL, error);
94 if (!filename)
95 return FALSE;
96
97 push_handlers ();
98
99 tiff = TIFFOpen (filename, "r");
100 if (tiff) {
101 guint32 w, h;
102
103 /* FIXME: unused data? why bother here */
104 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
105 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
106 }
107
108 if (!tiff) {
109 pop_handlers ();
110
111 g_set_error_literal (error,
112 EV_DOCUMENT_ERROR,
113 EV_DOCUMENT_ERROR_INVALID,
114 _("Invalid document"));
115
116 g_free (filename);
117 return FALSE;
118 }
119
120 tiff_document->tiff = tiff;
121 g_free (tiff_document->uri);
122 g_free (filename);
123 tiff_document->uri = g_strdup (uri);
124
125 pop_handlers ();
126 return TRUE;
127 }
128
129 static gboolean
tiff_document_save(EvDocument * document,const char * uri,GError ** error)130 tiff_document_save (EvDocument *document,
131 const char *uri,
132 GError **error)
133 {
134 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
135
136 return ev_xfer_uri_simple (tiff_document->uri, uri, error);
137 }
138
139 static int
tiff_document_get_n_pages(EvDocument * document)140 tiff_document_get_n_pages (EvDocument *document)
141 {
142 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
143
144 g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
145 g_return_val_if_fail (tiff_document->tiff != NULL, 0);
146
147 if (tiff_document->n_pages == -1) {
148 push_handlers ();
149 tiff_document->n_pages = 0;
150
151 do {
152 tiff_document->n_pages ++;
153 }
154 while (TIFFReadDirectory (tiff_document->tiff));
155 pop_handlers ();
156 }
157
158 return tiff_document->n_pages;
159 }
160
161 static void
tiff_document_get_resolution(TiffDocument * tiff_document,gfloat * x_res,gfloat * y_res)162 tiff_document_get_resolution (TiffDocument *tiff_document,
163 gfloat *x_res,
164 gfloat *y_res)
165 {
166 gfloat x = 72.0, y = 72.0;
167 gushort unit;
168
169 if (TIFFGetField (tiff_document->tiff, TIFFTAG_XRESOLUTION, &x) &&
170 TIFFGetField (tiff_document->tiff, TIFFTAG_YRESOLUTION, &y)) {
171 if (TIFFGetFieldDefaulted (tiff_document->tiff, TIFFTAG_RESOLUTIONUNIT, &unit)) {
172 if (unit == RESUNIT_CENTIMETER) {
173 x *= 2.54;
174 y *= 2.54;
175 }
176 }
177 }
178
179 *x_res = x;
180 *y_res = y;
181 }
182
183 static void
tiff_document_get_page_size(EvDocument * document,EvPage * page,double * width,double * height)184 tiff_document_get_page_size (EvDocument *document,
185 EvPage *page,
186 double *width,
187 double *height)
188 {
189 guint32 w, h;
190 gfloat x_res, y_res;
191 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
192
193 g_return_if_fail (TIFF_IS_DOCUMENT (document));
194 g_return_if_fail (tiff_document->tiff != NULL);
195
196 push_handlers ();
197 if (TIFFSetDirectory (tiff_document->tiff, page->index) != 1) {
198 pop_handlers ();
199 return;
200 }
201
202 TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &w);
203 TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &h);
204 tiff_document_get_resolution (tiff_document, &x_res, &y_res);
205 h = h * (x_res / y_res);
206
207 *width = w;
208 *height = h;
209
210 pop_handlers ();
211 }
212
213 static cairo_surface_t *
tiff_document_render(EvDocument * document,EvRenderContext * rc)214 tiff_document_render (EvDocument *document,
215 EvRenderContext *rc)
216 {
217 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
218 int width, height;
219 float x_res, y_res;
220 gint rowstride, bytes;
221 guchar *pixels = NULL;
222 guchar *p;
223 int orientation;
224 cairo_surface_t *surface;
225 cairo_surface_t *rotated_surface;
226 static const cairo_user_data_key_t key;
227
228 g_return_val_if_fail (TIFF_IS_DOCUMENT (document), NULL);
229 g_return_val_if_fail (tiff_document->tiff != NULL, NULL);
230
231 push_handlers ();
232 if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
233 pop_handlers ();
234 g_warning("Failed to select page %d", rc->page->index);
235 return NULL;
236 }
237
238 if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
239 pop_handlers ();
240 g_warning("Failed to read image width");
241 return NULL;
242 }
243
244 if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
245 pop_handlers ();
246 g_warning("Failed to read image height");
247 return NULL;
248 }
249
250 if (! TIFFGetField (tiff_document->tiff, TIFFTAG_ORIENTATION, &orientation)) {
251 orientation = ORIENTATION_TOPLEFT;
252 }
253
254 tiff_document_get_resolution (tiff_document, &x_res, &y_res);
255
256 pop_handlers ();
257
258 /* Sanity check the doc */
259 if (width <= 0 || height <= 0) {
260 g_warning("Invalid width or height.");
261 return NULL;
262 }
263
264 rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
265 if (rowstride / 4 != width) {
266 g_warning("Overflow while rendering document.");
267 /* overflow, or cairo was changed in an unsupported way */
268 return NULL;
269 }
270
271 bytes = height * rowstride;
272 if (bytes / rowstride != height) {
273 g_warning("Overflow while rendering document.");
274 /* overflow */
275 return NULL;
276 }
277
278 pixels = g_try_malloc (bytes);
279 if (!pixels) {
280 g_warning("Failed to allocate memory for rendering.");
281 return NULL;
282 }
283
284 surface = cairo_image_surface_create_for_data (pixels,
285 CAIRO_FORMAT_RGB24,
286 width, height,
287 rowstride);
288 cairo_surface_set_user_data (surface, &key,
289 pixels, (cairo_destroy_func_t)g_free);
290
291 TIFFReadRGBAImageOriented (tiff_document->tiff,
292 width, height,
293 (uint32 *)pixels,
294 orientation, 0);
295 pop_handlers ();
296
297 /* Convert the format returned by libtiff to
298 * what cairo expects
299 */
300 p = pixels;
301 while (p < pixels + bytes) {
302 guint32 *pixel = (guint32*)p;
303 guint8 r = TIFFGetR(*pixel);
304 guint8 g = TIFFGetG(*pixel);
305 guint8 b = TIFFGetB(*pixel);
306 guint8 a = TIFFGetA(*pixel);
307
308 *pixel = (a << 24) | (r << 16) | (g << 8) | b;
309
310 p += 4;
311 }
312
313 rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
314 (width * rc->scale) + 0.5,
315 (height * rc->scale * (x_res / y_res)) + 0.5,
316 rc->rotation);
317 cairo_surface_destroy (surface);
318
319 return rotated_surface;
320 }
321
322 static GdkPixbuf *
tiff_document_render_pixbuf(EvDocument * document,EvRenderContext * rc)323 tiff_document_render_pixbuf (EvDocument *document,
324 EvRenderContext *rc)
325 {
326 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
327 int width, height;
328 float x_res, y_res;
329 gint rowstride, bytes;
330 guchar *pixels = NULL;
331 GdkPixbuf *pixbuf;
332 GdkPixbuf *scaled_pixbuf;
333 GdkPixbuf *rotated_pixbuf;
334
335 push_handlers ();
336 if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
337 pop_handlers ();
338 return NULL;
339 }
340
341 if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
342 pop_handlers ();
343 return NULL;
344 }
345
346 if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
347 pop_handlers ();
348 return NULL;
349 }
350
351 tiff_document_get_resolution (tiff_document, &x_res, &y_res);
352
353 pop_handlers ();
354
355 /* Sanity check the doc */
356 if (width <= 0 || height <= 0)
357 return NULL;
358
359 rowstride = width * 4;
360 if (rowstride / 4 != width)
361 /* overflow */
362 return NULL;
363
364 bytes = height * rowstride;
365 if (bytes / rowstride != height)
366 /* overflow */
367 return NULL;
368
369 pixels = g_try_malloc (bytes);
370 if (!pixels)
371 return NULL;
372
373 pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
374 width, height, rowstride,
375 (GdkPixbufDestroyNotify) g_free, NULL);
376 TIFFReadRGBAImageOriented (tiff_document->tiff,
377 width, height,
378 (uint32 *)pixels,
379 ORIENTATION_TOPLEFT, 0);
380 pop_handlers ();
381
382 scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
383 width * rc->scale,
384 height * rc->scale * (x_res / y_res),
385 GDK_INTERP_BILINEAR);
386 g_object_unref (pixbuf);
387
388 rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation);
389 g_object_unref (scaled_pixbuf);
390
391 return rotated_pixbuf;
392 }
393
394 static gchar *
tiff_document_get_page_label(EvDocument * document,EvPage * page)395 tiff_document_get_page_label (EvDocument *document,
396 EvPage *page)
397 {
398 TiffDocument *tiff_document = TIFF_DOCUMENT (document);
399 static gchar *label;
400
401 if (TIFFGetField (tiff_document->tiff, TIFFTAG_PAGENAME, &label) &&
402 g_utf8_validate (label, -1, NULL)) {
403 return g_strdup (label);
404 }
405
406 return NULL;
407 }
408
409 static void
tiff_document_finalize(GObject * object)410 tiff_document_finalize (GObject *object)
411 {
412 TiffDocument *tiff_document = TIFF_DOCUMENT (object);
413
414 if (tiff_document->tiff)
415 TIFFClose (tiff_document->tiff);
416 if (tiff_document->uri)
417 g_free (tiff_document->uri);
418
419 G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
420 }
421
422 static void
tiff_document_class_init(TiffDocumentClass * klass)423 tiff_document_class_init (TiffDocumentClass *klass)
424 {
425 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
426 EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
427
428 gobject_class->finalize = tiff_document_finalize;
429
430 ev_document_class->load = tiff_document_load;
431 ev_document_class->save = tiff_document_save;
432 ev_document_class->get_n_pages = tiff_document_get_n_pages;
433 ev_document_class->get_page_size = tiff_document_get_page_size;
434 ev_document_class->render = tiff_document_render;
435 ev_document_class->get_page_label = tiff_document_get_page_label;
436 }
437
438 static GdkPixbuf *
tiff_document_thumbnails_get_thumbnail(EvDocumentThumbnails * document,EvRenderContext * rc,gboolean border)439 tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
440 EvRenderContext *rc,
441 gboolean border)
442 {
443 GdkPixbuf *pixbuf;
444
445 pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
446
447 if (border) {
448 GdkPixbuf *tmp_pixbuf = pixbuf;
449
450 pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
451 g_object_unref (tmp_pixbuf);
452 }
453
454 return pixbuf;
455 }
456
457 static void
tiff_document_thumbnails_get_dimensions(EvDocumentThumbnails * document,EvRenderContext * rc,gint * width,gint * height)458 tiff_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
459 EvRenderContext *rc,
460 gint *width,
461 gint *height)
462 {
463 gdouble page_width, page_height;
464
465 tiff_document_get_page_size (EV_DOCUMENT (document),
466 rc->page,
467 &page_width, &page_height);
468
469 if (rc->rotation == 90 || rc->rotation == 270) {
470 *width = (gint) (page_height * rc->scale);
471 *height = (gint) (page_width * rc->scale);
472 } else {
473 *width = (gint) (page_width * rc->scale);
474 *height = (gint) (page_height * rc->scale);
475 }
476 }
477
478 static void
tiff_document_document_thumbnails_iface_init(EvDocumentThumbnailsInterface * iface)479 tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
480 {
481 iface->get_thumbnail = tiff_document_thumbnails_get_thumbnail;
482 iface->get_dimensions = tiff_document_thumbnails_get_dimensions;
483 }
484
485 /* postscript exporter implementation */
486 static void
tiff_document_file_exporter_begin(EvFileExporter * exporter,EvFileExporterContext * fc)487 tiff_document_file_exporter_begin (EvFileExporter *exporter,
488 EvFileExporterContext *fc)
489 {
490 TiffDocument *document = TIFF_DOCUMENT (exporter);
491
492 document->ps_export_ctx = tiff2ps_context_new(fc->filename);
493 }
494
495 static void
tiff_document_file_exporter_do_page(EvFileExporter * exporter,EvRenderContext * rc)496 tiff_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
497 {
498 TiffDocument *document = TIFF_DOCUMENT (exporter);
499
500 if (document->ps_export_ctx == NULL)
501 return;
502 if (TIFFSetDirectory (document->tiff, rc->page->index) != 1)
503 return;
504 tiff2ps_process_page (document->ps_export_ctx, document->tiff,
505 0, 0, 0, 0, 0);
506 }
507
508 static void
tiff_document_file_exporter_end(EvFileExporter * exporter)509 tiff_document_file_exporter_end (EvFileExporter *exporter)
510 {
511 TiffDocument *document = TIFF_DOCUMENT (exporter);
512
513 if (document->ps_export_ctx == NULL)
514 return;
515 tiff2ps_context_finalize(document->ps_export_ctx);
516 }
517
518 static EvFileExporterCapabilities
tiff_document_file_exporter_get_capabilities(EvFileExporter * exporter)519 tiff_document_file_exporter_get_capabilities (EvFileExporter *exporter)
520 {
521 return EV_FILE_EXPORTER_CAN_PAGE_SET |
522 EV_FILE_EXPORTER_CAN_COPIES |
523 EV_FILE_EXPORTER_CAN_COLLATE |
524 EV_FILE_EXPORTER_CAN_REVERSE |
525 EV_FILE_EXPORTER_CAN_GENERATE_PS;
526 }
527
528 static void
tiff_document_document_file_exporter_iface_init(EvFileExporterInterface * iface)529 tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface)
530 {
531 iface->begin = tiff_document_file_exporter_begin;
532 iface->do_page = tiff_document_file_exporter_do_page;
533 iface->end = tiff_document_file_exporter_end;
534 iface->get_capabilities = tiff_document_file_exporter_get_capabilities;
535 }
536
537 static void
tiff_document_init(TiffDocument * tiff_document)538 tiff_document_init (TiffDocument *tiff_document)
539 {
540 tiff_document->n_pages = -1;
541 }
542