1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - TIFF image loader
3 *
4 * Copyright (C) 1999 Mark Crichton
5 * Copyright (C) 1999 The Free Software Foundation
6 *
7 * Authors: Mark Crichton <crichton@gimp.org>
8 * Federico Mena-Quintero <federico@gimp.org>
9 * Jonathan Blandford <jrb@redhat.com>
10 * S�ren Sandmann <sandmann@daimi.au.dk>
11 * Christian Dywan <christian@lanedo.com>
12 * Mukund Sivaraman <muks@banu.com>
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 */
27
28 /* Following code (almost) blatantly ripped from Imlib */
29
30 #include "config.h"
31 #include <stdlib.h>
32 #include <string.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <tiffio.h>
37 #include <errno.h>
38 #include <glib-object.h>
39 #include <glib/gi18n-lib.h>
40
41 #include "gdk-pixbuf-core.h"
42 #include "gdk-pixbuf-io.h"
43 #include "fallback-c89.c"
44
45 #ifdef G_OS_WIN32
46 #include <fcntl.h>
47 #include <io.h>
48 #include <windows.h>
49 #define lseek(a,b,c) _lseek(a,b,c)
50 #define O_RDWR _O_RDWR
51 #endif
52
53
54 /* Helper macros to convert between density units */
55 #define DPCM_TO_DPI(value) ((int) round ((value) * 2.54))
56
57 typedef struct _TiffContext TiffContext;
58 struct _TiffContext
59 {
60 GdkPixbufModuleSizeFunc size_func;
61 GdkPixbufModulePreparedFunc prepare_func;
62 GdkPixbufModuleUpdatedFunc update_func;
63 gpointer user_data;
64
65 guchar *buffer;
66 guint allocated;
67 guint used;
68 guint pos;
69 };
70
71 static void
tiff_warning_handler(const char * mod,const char * fmt,va_list ap)72 tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
73 {
74 /* Don't print anything; we should not be dumping junk to
75 * stderr, since that may be bad for some apps.
76 */
77 }
78
79 static void
tiff_set_handlers(void)80 tiff_set_handlers (void)
81 {
82 TIFFSetErrorHandler (tiff_warning_handler);
83 TIFFSetWarningHandler (tiff_warning_handler);
84 }
85
86
87
free_buffer(guchar * pixels,gpointer data)88 static void free_buffer (guchar *pixels, gpointer data)
89 {
90 g_free (pixels);
91 }
92
93 static GdkPixbuf *
tiff_image_parse(TIFF * tiff,TiffContext * context,GError ** error)94 tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
95 {
96 guchar *pixels = NULL;
97 gint width, height, rowstride, bytes;
98 GdkPixbuf *pixbuf;
99 guint16 bits_per_sample = 0;
100 uint16 orientation = 0;
101 uint16 transform = 0;
102 uint16 codec;
103 gchar *icc_profile_base64;
104 const gchar *icc_profile;
105 guint icc_profile_size;
106 uint16 resolution_unit;
107 gchar *density_str;
108 gint retval;
109
110 /* We're called with the lock held. */
111
112 if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width)) {
113 g_set_error_literal (error,
114 GDK_PIXBUF_ERROR,
115 GDK_PIXBUF_ERROR_FAILED,
116 _("Could not get image width (bad TIFF file)"));
117 return NULL;
118 }
119
120 if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height)) {
121 g_set_error_literal (error,
122 GDK_PIXBUF_ERROR,
123 GDK_PIXBUF_ERROR_FAILED,
124 _("Could not get image height (bad TIFF file)"));
125 return NULL;
126 }
127
128 if (width <= 0 || height <= 0) {
129 g_set_error_literal (error,
130 GDK_PIXBUF_ERROR,
131 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
132 _("Width or height of TIFF image is zero"));
133 return NULL;
134 }
135
136 if (width > G_MAXINT / 4) { /* overflow */
137 g_set_error_literal (error,
138 GDK_PIXBUF_ERROR,
139 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
140 _("Dimensions of TIFF image too large"));
141 return NULL;
142 }
143
144 rowstride = width * 4;
145
146 if (height > G_MAXINT / rowstride) { /* overflow */
147 g_set_error_literal (error,
148 GDK_PIXBUF_ERROR,
149 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
150 _("Dimensions of TIFF image too large"));
151 return NULL;
152 }
153
154 bytes = height * rowstride;
155
156 if (context && context->size_func) {
157 gint w = width;
158 gint h = height;
159 (* context->size_func) (&w, &h, context->user_data);
160
161 /* This is a signal that this function is being called
162 to support gdk_pixbuf_get_file_info, so we can stop
163 parsing the tiff file at this point. It is not an
164 error condition. */
165
166 if (w == 0 || h == 0)
167 return NULL;
168 }
169
170 pixels = g_try_malloc (bytes);
171
172 if (!pixels) {
173 g_set_error_literal (error,
174 GDK_PIXBUF_ERROR,
175 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
176 _("Insufficient memory to open TIFF file"));
177 return NULL;
178 }
179
180 pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
181 width, height, rowstride,
182 free_buffer, NULL);
183 if (!pixbuf) {
184 g_free (pixels);
185 g_set_error_literal (error,
186 GDK_PIXBUF_ERROR,
187 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
188 _("Insufficient memory to open TIFF file"));
189 return NULL;
190 }
191
192 /* Save the bits per sample as an option since pixbufs are
193 expected to be always 8 bits per sample. */
194 TIFFGetField (tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
195 if (bits_per_sample > 0) {
196 gchar str[5];
197 g_snprintf (str, sizeof (str), "%d", bits_per_sample);
198 gdk_pixbuf_set_option (pixbuf, "bits-per-sample", str);
199 }
200
201 /* Set the "orientation" key associated with this image. libtiff
202 orientation handling is odd, so further processing is required
203 by higher-level functions based on this tag. If the embedded
204 orientation tag is 1-4, libtiff flips/mirrors the image as
205 required, and no client processing is required - so we report
206 no orientation. Orientations 5-8 require rotations which would
207 swap the width and height of the image. libtiff does not do this.
208 Instead it interprets orientations 5-8 the same as 1-4.
209 See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548.
210 To correct for this, the client must apply the transform normally
211 used for orientation 5 to both orientations 5 and 7, and apply
212 the transform normally used for orientation 7 for both
213 orientations 6 and 8. Then everythings works out OK! */
214
215 TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation);
216
217 switch (orientation) {
218 case 5:
219 case 7:
220 transform = 5;
221 break;
222 case 6:
223 case 8:
224 transform = 7;
225 break;
226 default:
227 transform = 0;
228 break;
229 }
230
231 if (transform > 0 ) {
232 gchar str[5];
233 g_snprintf (str, sizeof (str), "%d", transform);
234 gdk_pixbuf_set_option (pixbuf, "orientation", str);
235 }
236
237 TIFFGetField (tiff, TIFFTAG_COMPRESSION, &codec);
238 if (codec > 0) {
239 gchar str[5];
240 g_snprintf (str, sizeof (str), "%d", codec);
241 gdk_pixbuf_set_option (pixbuf, "compression", str);
242 }
243
244 /* Extract embedded ICC profile */
245 retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile);
246 if (retval == 1) {
247 icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
248 gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
249 g_free (icc_profile_base64);
250 }
251
252 retval = TIFFGetField (tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit);
253 if (retval == 1) {
254 float x_resolution = 0, y_resolution = 0;
255
256 TIFFGetField (tiff, TIFFTAG_XRESOLUTION, &x_resolution);
257 TIFFGetField (tiff, TIFFTAG_YRESOLUTION, &y_resolution);
258
259 switch (resolution_unit) {
260 case RESUNIT_INCH:
261 density_str = g_strdup_printf ("%d", (int) round (x_resolution));
262 gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
263 g_free (density_str);
264 density_str = g_strdup_printf ("%d", (int) round (y_resolution));
265 gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
266 g_free (density_str);
267 break;
268 case RESUNIT_CENTIMETER:
269 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (x_resolution));
270 gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
271 g_free (density_str);
272 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (y_resolution));
273 gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
274 g_free (density_str);
275 break;
276 }
277 }
278
279 if (context && context->prepare_func)
280 (* context->prepare_func) (pixbuf, NULL, context->user_data);
281
282 if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1)) {
283 g_set_error_literal (error,
284 GDK_PIXBUF_ERROR,
285 GDK_PIXBUF_ERROR_FAILED,
286 _("Failed to load RGB data from TIFF file"));
287 g_object_unref (pixbuf);
288 return NULL;
289 }
290
291 /* Flag multi-page documents, because this loader only handles the
292 first page. The client app may wish to warn the user. */
293 if (TIFFReadDirectory (tiff))
294 gdk_pixbuf_set_option (pixbuf, "multipage", "yes");
295
296 #if G_BYTE_ORDER == G_BIG_ENDIAN
297 {
298 guchar *pixbuf_pixels = gdk_pixbuf_get_pixels (pixbuf);
299
300 pixels = pixbuf_pixels;
301
302 /* Turns out that the packing used by TIFFRGBAImage depends on
303 * the host byte order...
304 */
305 while (pixels < pixbuf_pixels + bytes) {
306 uint32 pixel = *(uint32 *)pixels;
307 int r = TIFFGetR(pixel);
308 int g = TIFFGetG(pixel);
309 int b = TIFFGetB(pixel);
310 int a = TIFFGetA(pixel);
311 *pixels++ = r;
312 *pixels++ = g;
313 *pixels++ = b;
314 *pixels++ = a;
315 }
316 }
317 #endif
318
319 if (context && context->update_func)
320 (* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
321
322 return pixbuf;
323 }
324
325
326
327 /* Static loader */
328
329 static GdkPixbuf *
gdk_pixbuf__tiff_image_load(FILE * f,GError ** error)330 gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
331 {
332 TIFF *tiff = NULL;
333 int fd;
334 GdkPixbuf *pixbuf;
335
336 g_return_val_if_fail (f != NULL, NULL);
337
338 tiff_set_handlers ();
339
340 fd = fileno (f);
341
342 /* On OSF, apparently fseek() works in some on-demand way, so
343 * the fseek gdk_pixbuf_new_from_file() doesn't work here
344 * since we are using the raw file descriptor. So, we call lseek() on the fd
345 * before using it. (#60840)
346 */
347 lseek (fd, 0, SEEK_SET);
348 #ifndef G_OS_WIN32
349 tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
350 #else
351 /* W32 version of this function takes HANDLE.
352 * What's worse, the caller will close the file,
353 * but TIFFClose() will *also* close it, so we
354 * need to make a duplicate.
355 */
356 {
357 HANDLE h;
358
359 if (DuplicateHandle (GetCurrentProcess (),
360 (HANDLE) _get_osfhandle (fd),
361 GetCurrentProcess (),
362 &h,
363 0,
364 FALSE,
365 DUPLICATE_SAME_ACCESS)) {
366 tiff = TIFFFdOpen ((intptr_t) h, "libpixbuf-tiff", "r");
367 if (tiff == NULL)
368 CloseHandle (h);
369 }
370 }
371 #endif
372
373 if (!tiff) {
374 g_set_error_literal (error,
375 GDK_PIXBUF_ERROR,
376 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
377 _("Failed to open TIFF image"));
378 return NULL;
379 }
380
381 pixbuf = tiff_image_parse (tiff, NULL, error);
382
383 TIFFClose (tiff);
384
385 return pixbuf;
386 }
387
388
389
390 /* Progressive loader */
391
392 static gpointer
gdk_pixbuf__tiff_image_begin_load(GdkPixbufModuleSizeFunc size_func,GdkPixbufModulePreparedFunc prepare_func,GdkPixbufModuleUpdatedFunc update_func,gpointer user_data,GError ** error)393 gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
394 GdkPixbufModulePreparedFunc prepare_func,
395 GdkPixbufModuleUpdatedFunc update_func,
396 gpointer user_data,
397 GError **error)
398 {
399 TiffContext *context;
400
401 context = g_new0 (TiffContext, 1);
402 context->size_func = size_func;
403 context->prepare_func = prepare_func;
404 context->update_func = update_func;
405 context->user_data = user_data;
406 context->buffer = NULL;
407 context->allocated = 0;
408 context->used = 0;
409 context->pos = 0;
410
411 return context;
412 }
413
414 static tsize_t
tiff_load_read(thandle_t handle,tdata_t buf,tsize_t size)415 tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
416 {
417 TiffContext *context = (TiffContext *)handle;
418
419 if (context->pos + size > context->used)
420 return 0;
421
422 memcpy (buf, context->buffer + context->pos, size);
423 context->pos += size;
424 return size;
425 }
426
427 static tsize_t
tiff_load_write(thandle_t handle,tdata_t buf,tsize_t size)428 tiff_load_write (thandle_t handle, tdata_t buf, tsize_t size)
429 {
430 return -1;
431 }
432
433 static toff_t
tiff_load_seek(thandle_t handle,toff_t offset,int whence)434 tiff_load_seek (thandle_t handle, toff_t offset, int whence)
435 {
436 TiffContext *context = (TiffContext *)handle;
437
438 switch (whence) {
439 case SEEK_SET:
440 if (offset > context->used)
441 return -1;
442 context->pos = offset;
443 break;
444 case SEEK_CUR:
445 if (offset + context->pos >= context->used)
446 return -1;
447 context->pos += offset;
448 break;
449 case SEEK_END:
450 if (offset + context->used > context->used)
451 return -1;
452 context->pos = context->used + offset;
453 break;
454 default:
455 return -1;
456 }
457 return context->pos;
458 }
459
460 static int
tiff_load_close(thandle_t context)461 tiff_load_close (thandle_t context)
462 {
463 return 0;
464 }
465
466 static toff_t
tiff_load_size(thandle_t handle)467 tiff_load_size (thandle_t handle)
468 {
469 TiffContext *context = (TiffContext *)handle;
470
471 return context->used;
472 }
473
474 static int
tiff_load_map_file(thandle_t handle,tdata_t * buf,toff_t * size)475 tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
476 {
477 TiffContext *context = (TiffContext *)handle;
478
479 *buf = context->buffer;
480 *size = context->used;
481
482 return 0;
483 }
484
485 static void
tiff_load_unmap_file(thandle_t handle,tdata_t data,toff_t offset)486 tiff_load_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
487 {
488 }
489
490 static gboolean
gdk_pixbuf__tiff_image_stop_load(gpointer data,GError ** error)491 gdk_pixbuf__tiff_image_stop_load (gpointer data,
492 GError **error)
493 {
494 TiffContext *context = data;
495 TIFF *tiff;
496 gboolean retval = FALSE;
497
498 g_return_val_if_fail (data != NULL, FALSE);
499
500 tiff_set_handlers ();
501
502 tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data,
503 tiff_load_read, tiff_load_write,
504 tiff_load_seek, tiff_load_close,
505 tiff_load_size,
506 tiff_load_map_file, tiff_load_unmap_file);
507 if (!tiff) {
508 g_set_error_literal (error,
509 GDK_PIXBUF_ERROR,
510 GDK_PIXBUF_ERROR_FAILED,
511 _("Failed to load TIFF image"));
512 } else {
513 GdkPixbuf *pixbuf;
514
515 pixbuf = tiff_image_parse (tiff, context, error);
516 retval = (pixbuf != NULL);
517 g_clear_object (&pixbuf);
518 /* tiff_image_parse() can return NULL on success in a particular case */
519 if (!retval && error && !*error) {
520 g_set_error_literal (error,
521 GDK_PIXBUF_ERROR,
522 GDK_PIXBUF_ERROR_FAILED,
523 _("Failed to load TIFF image"));
524 }
525 }
526
527 if (tiff)
528 TIFFClose (tiff);
529
530 g_free (context->buffer);
531 g_free (context);
532
533 return retval;
534 }
535
536 static gboolean
make_available_at_least(TiffContext * context,guint needed)537 make_available_at_least (TiffContext *context, guint needed)
538 {
539 guchar *new_buffer = NULL;
540 guint need_alloc;
541
542 need_alloc = context->used + needed;
543 if (need_alloc > context->allocated) {
544 guint new_size = 1;
545 while (new_size < need_alloc) {
546 if (!g_uint_checked_mul (&new_size, new_size, 2)) {
547 new_size = 0;
548 break;
549 }
550 }
551
552 if (new_size == 0)
553 return FALSE;
554
555 new_buffer = g_try_realloc (context->buffer, new_size);
556 if (new_buffer) {
557 context->buffer = new_buffer;
558 context->allocated = new_size;
559 return TRUE;
560 }
561 return FALSE;
562 }
563 return TRUE;
564 }
565
566 static gboolean
gdk_pixbuf__tiff_image_load_increment(gpointer data,const guchar * buf,guint size,GError ** error)567 gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
568 guint size, GError **error)
569 {
570 TiffContext *context = (TiffContext *) data;
571
572 g_return_val_if_fail (data != NULL, FALSE);
573
574 tiff_set_handlers ();
575
576 if (!make_available_at_least (context, size)) {
577 g_set_error_literal (error,
578 GDK_PIXBUF_ERROR,
579 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
580 _("Insufficient memory to open TIFF file"));
581 return FALSE;
582 }
583
584 memcpy (context->buffer + context->used, buf, size);
585 context->used += size;
586 return TRUE;
587 }
588
589 typedef struct {
590 gchar *buffer;
591 guint allocated;
592 guint used;
593 guint pos;
594 } TiffSaveContext;
595
596 static tsize_t
tiff_save_read(thandle_t handle,tdata_t buf,tsize_t size)597 tiff_save_read (thandle_t handle, tdata_t buf, tsize_t size)
598 {
599 return -1;
600 }
601
602 static tsize_t
tiff_save_write(thandle_t handle,tdata_t buf,tsize_t size)603 tiff_save_write (thandle_t handle, tdata_t buf, tsize_t size)
604 {
605 TiffSaveContext *context = (TiffSaveContext *)handle;
606
607 /* Modify buffer length */
608 if (context->pos + size > context->used)
609 context->used = context->pos + size;
610
611 /* Realloc */
612 if (context->used > context->allocated) {
613 context->buffer = g_realloc (context->buffer, context->pos + size);
614 context->allocated = context->used;
615 }
616
617 /* Now copy the data */
618 memcpy (context->buffer + context->pos, buf, size);
619
620 /* Update pos */
621 context->pos += size;
622
623 return size;
624 }
625
626 static toff_t
tiff_save_seek(thandle_t handle,toff_t offset,int whence)627 tiff_save_seek (thandle_t handle, toff_t offset, int whence)
628 {
629 TiffSaveContext *context = (TiffSaveContext *)handle;
630
631 switch (whence) {
632 case SEEK_SET:
633 context->pos = offset;
634 break;
635 case SEEK_CUR:
636 context->pos += offset;
637 break;
638 case SEEK_END:
639 context->pos = context->used + offset;
640 break;
641 default:
642 return -1;
643 }
644 return context->pos;
645 }
646
647 static int
tiff_save_close(thandle_t context)648 tiff_save_close (thandle_t context)
649 {
650 return 0;
651 }
652
653 static toff_t
tiff_save_size(thandle_t handle)654 tiff_save_size (thandle_t handle)
655 {
656 return -1;
657 }
658
659 static TiffSaveContext *
create_save_context(void)660 create_save_context (void)
661 {
662 TiffSaveContext *context;
663
664 context = g_new (TiffSaveContext, 1);
665 context->buffer = NULL;
666 context->allocated = 0;
667 context->used = 0;
668 context->pos = 0;
669
670 return context;
671 }
672
673 static void
free_save_context(TiffSaveContext * context)674 free_save_context (TiffSaveContext *context)
675 {
676 g_free (context->buffer);
677 g_free (context);
678 }
679
680 static void
copy_gray_row(gint * dest,guchar * src,gint width,gboolean has_alpha)681 copy_gray_row (gint *dest,
682 guchar *src,
683 gint width,
684 gboolean has_alpha)
685 {
686 gint i;
687 guchar *p;
688
689 p = src;
690 for (i = 0; i < width; i++) {
691 int pr, pg, pb, pv;
692
693 pr = *p++;
694 pg = *p++;
695 pb = *p++;
696
697 if (has_alpha) {
698 int pa = *p++;
699
700 /* Premul alpha to simulate it */
701 if (pa > 0) {
702 pr = pr * pa / 255;
703 pg = pg * pa / 255;
704 pb = pb * pa / 255;
705 } else {
706 pr = pg = pb = 0;
707 }
708 }
709
710 /* Calculate value MAX(MAX(r,g),b) */
711 pv = pr > pg ? pr : pg;
712 pv = pv > pb ? pv : pb;
713
714 *dest++ = pv;
715 }
716 }
717
718 static gboolean
gdk_pixbuf__tiff_image_save_to_callback(GdkPixbufSaveFunc save_func,gpointer user_data,GdkPixbuf * pixbuf,gchar ** keys,gchar ** values,GError ** error)719 gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func,
720 gpointer user_data,
721 GdkPixbuf *pixbuf,
722 gchar **keys,
723 gchar **values,
724 GError **error)
725 {
726 TIFF *tiff;
727 gint width, height, rowstride;
728 const gchar *bits_per_sample = NULL;
729 long bps;
730 const gchar *compression = NULL;
731 guchar *pixels;
732 gboolean has_alpha;
733 gushort alpha_samples[1] = { EXTRASAMPLE_UNASSALPHA };
734 int y;
735 TiffSaveContext *context;
736 gboolean retval;
737 const gchar *icc_profile = NULL;
738 const gchar *x_dpi = NULL;
739 const gchar *y_dpi = NULL;
740 guint16 codec;
741
742 tiff_set_handlers ();
743
744 context = create_save_context ();
745 tiff = TIFFClientOpen ("libtiff-pixbuf", "w", context,
746 tiff_save_read, tiff_save_write,
747 tiff_save_seek, tiff_save_close,
748 tiff_save_size,
749 NULL, NULL);
750
751 if (!tiff) {
752 g_set_error_literal (error,
753 GDK_PIXBUF_ERROR,
754 GDK_PIXBUF_ERROR_FAILED,
755 _("Failed to save TIFF image"));
756 free_save_context (context);
757 return FALSE;
758 }
759
760 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
761 pixels = gdk_pixbuf_get_pixels (pixbuf);
762
763 has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
764
765 height = gdk_pixbuf_get_height (pixbuf);
766 width = gdk_pixbuf_get_width (pixbuf);
767
768 /* Guaranteed by the caller. */
769 g_assert (width >= 0);
770 g_assert (height >= 0);
771 g_assert (rowstride >= 0);
772
773 TIFFSetField (tiff, TIFFTAG_IMAGEWIDTH, width);
774 TIFFSetField (tiff, TIFFTAG_IMAGELENGTH, height);
775
776 /* libtiff supports a number of 'codecs' such as:
777 1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
778 if (keys && *keys && values && *values) {
779 guint i = 0;
780
781 while (keys[i]) {
782 if (g_str_equal (keys[i], "bits-per-sample"))
783 bits_per_sample = values[i];
784 else if (g_str_equal (keys[i], "compression"))
785 compression = values[i];
786 else if (g_str_equal (keys[i], "icc-profile"))
787 icc_profile = values[i];
788 else if (g_str_equal (keys[i], "x-dpi"))
789 x_dpi = values[i];
790 else if (g_str_equal (keys[i], "y-dpi"))
791 y_dpi = values[i];
792 i++;
793 }
794 }
795
796 /* Use 8 bits per sample by default, if none was recorded or
797 specified. */
798 if (!bits_per_sample)
799 bits_per_sample = "8";
800
801 /* Use DEFLATE compression (8) by default, if none was recorded
802 or specified. */
803 if (!compression)
804 compression = "8";
805
806 /* libtiff supports a number of 'codecs' such as:
807 1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
808 codec = strtol (compression, NULL, 0);
809
810 if (TIFFIsCODECConfigured (codec))
811 TIFFSetField (tiff, TIFFTAG_COMPRESSION, codec);
812 else {
813 g_set_error_literal (error,
814 GDK_PIXBUF_ERROR,
815 GDK_PIXBUF_ERROR_FAILED,
816 _("TIFF compression doesn’t refer to a valid codec."));
817 retval = FALSE;
818 goto cleanup;
819 }
820
821 /* We support 1-bit or 8-bit saving */
822 bps = atol (bits_per_sample);
823 if (bps == 1) {
824 TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 1);
825 TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
826 TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
827 TIFFSetField (tiff, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
828 } else if (bps == 8) {
829 TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 8);
830 TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, has_alpha ? 4 : 3);
831 TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
832
833 if (has_alpha)
834 TIFFSetField (tiff, TIFFTAG_EXTRASAMPLES, 1, alpha_samples);
835
836 if (icc_profile != NULL) {
837 guchar *icc_profile_buf;
838 gsize icc_profile_size;
839
840 /* decode from base64 */
841 icc_profile_buf = g_base64_decode (icc_profile, &icc_profile_size);
842 if (icc_profile_size < 127) {
843 g_set_error (error,
844 GDK_PIXBUF_ERROR,
845 GDK_PIXBUF_ERROR_BAD_OPTION,
846 _("Color profile has invalid length %d."),
847 (gint) icc_profile_size);
848 retval = FALSE;
849 g_free (icc_profile_buf);
850 goto cleanup;
851 }
852
853 TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile_buf);
854 g_free (icc_profile_buf);
855 }
856 } else {
857 /* The passed bits-per-sample is not supported. */
858 g_set_error_literal (error,
859 GDK_PIXBUF_ERROR,
860 GDK_PIXBUF_ERROR_FAILED,
861 _("TIFF bits-per-sample doesn’t contain a supported value."));
862 retval = FALSE;
863 goto cleanup;
864 }
865
866 TIFFSetField (tiff, TIFFTAG_ROWSPERSTRIP, height);
867 TIFFSetField (tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
868 TIFFSetField (tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
869
870 if (bps == 1) {
871 guchar *mono_row;
872 gint *dith_row_1, *dith_row_2, *dith_row_tmp;
873
874 dith_row_1 = g_new (gint, width);
875 dith_row_2 = g_new (gint, width);
876 mono_row = g_malloc ((width + 7) / 8);
877
878 copy_gray_row (dith_row_1, pixels, width, has_alpha);
879
880 for (y = 0; y < height; y++) {
881 guint x;
882 gint *p;
883
884 memset (mono_row, 0, (width + 7) / 8);
885
886 if (y > 0) {
887 dith_row_tmp = dith_row_1;
888 dith_row_1 = dith_row_2;
889 dith_row_2 = dith_row_tmp;
890 }
891
892 if (y < (height - 1))
893 copy_gray_row (dith_row_2, pixels + ((y + 1) * rowstride), width, has_alpha);
894
895 p = dith_row_1;
896 for (x = 0; x < width; x++) {
897 gint p_old, p_new, quant_error;
898
899 /* Apply Floyd-Steinberg dithering */
900
901 p_old = *p++;
902
903 if (p_old > 127)
904 p_new = 255;
905 else
906 p_new = 0;
907
908 quant_error = p_old - p_new;
909 if (x < (width - 1))
910 dith_row_1[x + 1] += 7 * quant_error / 16;
911 if (y < (height - 1)) {
912 if (x > 0)
913 dith_row_2[x - 1] += 3 * quant_error / 16;
914
915 dith_row_2[x] += 5 * quant_error / 16;
916
917 if (x < (width - 1))
918 dith_row_2[x + 1] += quant_error / 16;
919 }
920
921 if (p_new > 127)
922 mono_row[x / 8] |= (0x1 << (7 - (x % 8)));
923 }
924
925 if (TIFFWriteScanline (tiff, mono_row, y, 0) == -1)
926 break;
927 }
928 g_free (mono_row);
929 g_free (dith_row_1);
930 g_free (dith_row_2);
931 } else {
932 for (y = 0; y < height; y++) {
933 if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1)
934 break;
935 }
936 }
937
938 if (y < height) {
939 g_set_error_literal (error,
940 GDK_PIXBUF_ERROR,
941 GDK_PIXBUF_ERROR_FAILED,
942 _("Failed to write TIFF data"));
943 TIFFClose (tiff);
944 retval = FALSE;
945 goto cleanup;
946 }
947
948 if (x_dpi != NULL && y_dpi != NULL) {
949 char *endptr = NULL;
950 uint16 resolution_unit = RESUNIT_INCH;
951 float x_dpi_value, y_dpi_value;
952
953 x_dpi_value = strtol (x_dpi, &endptr, 10);
954 if (x_dpi[0] != '\0' && *endptr != '\0')
955 x_dpi_value = -1;
956 if (x_dpi_value <= 0) {
957 g_set_error (error,
958 GDK_PIXBUF_ERROR,
959 GDK_PIXBUF_ERROR_BAD_OPTION,
960 _("TIFF x-dpi must be greater than zero; value “%s” is not allowed."),
961 x_dpi);
962 retval = FALSE;
963 goto cleanup;
964 }
965 y_dpi_value = strtol (y_dpi, &endptr, 10);
966 if (y_dpi[0] != '\0' && *endptr != '\0')
967 y_dpi_value = -1;
968 if (y_dpi_value <= 0) {
969 g_set_error (error,
970 GDK_PIXBUF_ERROR,
971 GDK_PIXBUF_ERROR_BAD_OPTION,
972 _("TIFF y-dpi must be greater than zero; value “%s” is not allowed."),
973 y_dpi);
974 retval = FALSE;
975 goto cleanup;
976 }
977
978 TIFFSetField (tiff, TIFFTAG_RESOLUTIONUNIT, resolution_unit);
979 TIFFSetField (tiff, TIFFTAG_XRESOLUTION, x_dpi_value);
980 TIFFSetField (tiff, TIFFTAG_YRESOLUTION, y_dpi_value);
981 }
982
983 TIFFClose (tiff);
984
985 /* Now call the callback */
986 retval = save_func (context->buffer, context->used, error, user_data);
987
988 cleanup:
989 free_save_context (context);
990 return retval;
991 }
992
993 static gboolean
save_to_file_cb(const gchar * buf,gsize count,GError ** error,gpointer data)994 save_to_file_cb (const gchar *buf,
995 gsize count,
996 GError **error,
997 gpointer data)
998 {
999 gint bytes;
1000
1001 while (count > 0) {
1002 bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
1003 if (bytes <= 0)
1004 break;
1005 count -= bytes;
1006 buf += bytes;
1007 }
1008
1009 if (count) {
1010 g_set_error_literal (error,
1011 GDK_PIXBUF_ERROR,
1012 GDK_PIXBUF_ERROR_FAILED,
1013 _("Couldn’t write to TIFF file"));
1014 return FALSE;
1015 }
1016
1017 return TRUE;
1018 }
1019
1020 static gboolean
gdk_pixbuf__tiff_image_save(FILE * f,GdkPixbuf * pixbuf,gchar ** keys,gchar ** values,GError ** error)1021 gdk_pixbuf__tiff_image_save (FILE *f,
1022 GdkPixbuf *pixbuf,
1023 gchar **keys,
1024 gchar **values,
1025 GError **error)
1026 {
1027 return gdk_pixbuf__tiff_image_save_to_callback (save_to_file_cb,
1028 f, pixbuf, keys,
1029 values, error);
1030 }
1031
1032 static gboolean
gdk_pixbuf__tiff_is_save_option_supported(const gchar * option_key)1033 gdk_pixbuf__tiff_is_save_option_supported (const gchar *option_key)
1034 {
1035 if (g_strcmp0 (option_key, "bits-per-sample") == 0 ||
1036 g_strcmp0 (option_key, "compression") == 0 ||
1037 g_strcmp0 (option_key, "icc-profile") == 0 ||
1038 g_strcmp0 (option_key, "x-dpi") == 0 ||
1039 g_strcmp0 (option_key, "y-dpi") == 0)
1040 return TRUE;
1041
1042 return FALSE;
1043 }
1044
1045 #ifndef INCLUDE_tiff
1046 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1047 #else
1048 #define MODULE_ENTRY(function) void _gdk_pixbuf__tiff_ ## function
1049 #endif
1050
MODULE_ENTRY(fill_vtable)1051 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1052 {
1053 module->load = gdk_pixbuf__tiff_image_load;
1054 module->begin_load = gdk_pixbuf__tiff_image_begin_load;
1055 module->stop_load = gdk_pixbuf__tiff_image_stop_load;
1056 module->load_increment = gdk_pixbuf__tiff_image_load_increment;
1057 module->save = gdk_pixbuf__tiff_image_save;
1058 module->save_to_callback = gdk_pixbuf__tiff_image_save_to_callback;
1059 module->is_save_option_supported = gdk_pixbuf__tiff_is_save_option_supported;
1060 }
1061
MODULE_ENTRY(fill_info)1062 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1063 {
1064 static const GdkPixbufModulePattern signature[] = {
1065 { "MM \x2a", " z ", 100 },
1066 { "II\x2a ", " z", 100 },
1067 { "II* \020 CR\002 ", " z zzz z", 0 },
1068 { NULL, NULL, 0 }
1069 };
1070 static const gchar *mime_types[] = {
1071 "image/tiff",
1072 NULL
1073 };
1074 static const gchar *extensions[] = {
1075 "tiff",
1076 "tif",
1077 NULL
1078 };
1079
1080 info->name = "tiff";
1081 info->signature = (GdkPixbufModulePattern *) signature;
1082 info->description = NC_("image format", "TIFF");
1083 info->mime_types = (gchar **) mime_types;
1084 info->extensions = (gchar **) extensions;
1085 info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1086 info->license = "LGPL";
1087 }
1088