1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 TIFF image support using libtiff.
35 #include "../../config.h"
37 #include "core/GP_Pixel.h"
38 #include "core/GP_GetPutPixel.h"
39 #include "core/GP_Debug.h"
43 #define TIFF_HEADER_LITTLE "II\x2a\0"
44 #define TIFF_HEADER_BIG "MM\0\x2a"
46 int GP_MatchTIFF(const void *buf
)
48 if (!memcmp(buf
, TIFF_HEADER_LITTLE
, 4))
51 if (!memcmp(buf
, TIFF_HEADER_BIG
, 4))
61 static const char *compression_name(uint16_t compression
)
63 switch (compression
) {
64 case COMPRESSION_NONE
:
66 case COMPRESSION_CCITTRLE
:
67 return "CCITT modified Huffman RLE";
68 /* COMPRESSION_CCITTFAX3 == COMPRESSION_CCITT_T4 */
69 case COMPRESSION_CCITTFAX3
:
70 return "CCITT Group 3 fax encoding / CCITT T.4 (TIFF 6 name)";
71 /* COMPRESSION_CCITTFAX4 == COMPRESSION_CCITT_T6 */
72 case COMPRESSION_CCITTFAX4
:
73 return "CCITT Group 4 fax encoding / CCITT T.6 (TIFF 6 name)";
76 case COMPRESSION_OJPEG
:
78 case COMPRESSION_JPEG
:
80 case COMPRESSION_NEXT
:
81 return "NeXT 2 bit RLE";
82 case COMPRESSION_CCITTRLEW
:
83 return "#1 w/ word alignment";
84 case COMPRESSION_PACKBITS
:
85 return "Macintosh RLE";
86 case COMPRESSION_THUNDERSCAN
:
87 return "ThunderScan RLE";
93 static const char *photometric_name(uint16_t photometric
)
95 switch (photometric
) {
96 case PHOTOMETRIC_MINISWHITE
:
97 return "Min is White";
98 case PHOTOMETRIC_MINISBLACK
:
99 return "Min is black";
100 case PHOTOMETRIC_RGB
:
102 case PHOTOMETRIC_PALETTE
:
104 case PHOTOMETRIC_MASK
:
106 case PHOTOMETRIC_SEPARATED
:
108 case PHOTOMETRIC_YCBCR
:
110 case PHOTOMETRIC_CIELAB
:
112 case PHOTOMETRIC_ICCLAB
:
114 case PHOTOMETRIC_ITULAB
:
116 case PHOTOMETRIC_LOGL
:
118 case PHOTOMETRIC_LOGLUV
:
126 /* compulsory tiff data */
129 uint16_t bits_per_sample
;
131 /* either strips or tiles should be set */
132 uint32_t rows_per_strip
;
137 /* pixel type related values */
138 uint16_t photometric
;
141 static int read_header(TIFF
*tiff
, struct tiff_header
*header
)
143 /* all these fields are compulsory in tiff image */
144 if (!TIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &header
->w
)) {
145 GP_DEBUG(1, "Failed to read Width");
149 if (!TIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &header
->h
)) {
150 GP_DEBUG(1, "Failed to read Height");
154 if (!TIFFGetField(tiff
, TIFFTAG_COMPRESSION
, &header
->compress
)) {
155 GP_DEBUG(1, "Failed to read Compression Type");
159 if (!TIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
,
160 &header
->bits_per_sample
)) {
161 GP_DEBUG(1, "Failed to read Bits Per Sample");
165 GP_DEBUG(1, "TIFF image %ux%u Compression: %s, Bits Per Sample: %u",
166 header
->w
, header
->h
,
167 compression_name(header
->compress
), header
->bits_per_sample
);
169 /* If set tiff is saved in tiles */
170 if (TIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &header
->tile_w
) &&
171 TIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &header
->tile_h
)) {
172 GP_DEBUG(1, "TIFF is tiled in %ux%u",
173 header
->tile_w
, header
->tile_h
);
174 header
->rows_per_strip
= 0;
178 if (!TIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &header
->rows_per_strip
)) {
179 GP_DEBUG(1, "TIFF not saved in tiles nor strips");
183 GP_DEBUG(1, "TIFF is saved in strips");
200 static struct tag tags
[] = {
201 {TIFFTAG_IMAGEDESCRIPTION
, "Image Description", REC_STRING
},
202 {TIFFTAG_MAKE
, "Make", REC_STRING
},
203 {TIFFTAG_MODEL
, "Model", REC_STRING
},
204 {TIFFTAG_ORIENTATION
, "Orientation", REC_SHORT
},
205 {TIFFTAG_SAMPLESPERPIXEL
, "Samples per Pixel", REC_SHORT
},
206 {TIFFTAG_XRESOLUTION
, "X Resolution", REC_FLOAT
},
207 {TIFFTAG_YRESOLUTION
, "Y Resolution", REC_FLOAT
},
208 {TIFFTAG_RESOLUTIONUNIT
, "Resolution Unit", REC_SHORT
},
209 {TIFFTAG_SOFTWARE
, "Software", REC_STRING
},
210 {TIFFTAG_DATETIME
, "Date Time", REC_STRING
},
211 {TIFFTAG_ARTIST
, "Artist", REC_STRING
},
212 {TIFFTAG_HOSTCOMPUTER
, "Host Computer", REC_STRING
},
213 {TIFFTAG_COPYRIGHT
, "Copyright", REC_STRING
},
217 static void fill_metadata(TIFF
*tiff
, struct tiff_header
*header
,
218 GP_DataStorage
*storage
)
226 GP_DataStorageAddInt(storage
, NULL
, "Width", header
->w
);
227 GP_DataStorageAddInt(storage
, NULL
, "Height", header
->h
);
228 GP_DataStorageAddString(storage
, NULL
, "Compression",
229 compression_name(header
->compress
));
230 GP_DataStorageAddInt(storage
, NULL
, "Bits per Sample",
231 header
->bits_per_sample
);
233 for (i
= 0; tags
[i
].name
; i
++) {
235 val
.id
= tags
[i
].name
;
237 switch (tags
[i
].type
) {
239 val
.type
= GP_DATA_STRING
;
240 flag
= TIFFGetField(tiff
, tags
[i
].tag
, &(val
.value
.str
));
243 val
.type
= GP_DATA_INT
;
244 flag
= TIFFGetField(tiff
, tags
[i
].tag
, &s
);
248 val
.type
= GP_DATA_DOUBLE
;
249 flag
= TIFFGetField(tiff
, tags
[i
].tag
, &f
);
253 GP_WARN("Unhandled type %i", tags
[i
].type
);
257 GP_DataStorageAdd(storage
, NULL
, &val
);
263 static GP_PixelType
match_grayscale_pixel_type(TIFF
*tiff
,
264 struct tiff_header
*header
)
266 if (!TIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
,
267 &header
->bits_per_sample
)) {
268 GP_DEBUG(1, "Have 1bit Bitmap");
272 switch (header
->bits_per_sample
) {
274 GP_DEBUG(1, "Have 1bit Bitmap");
277 GP_DEBUG(1, "Have 2bit Grayscale");
280 GP_DEBUG(1, "Have 4bit Grayscale");
283 GP_DEBUG(1, "Have 8bit Grayscale");
286 GP_DEBUG(1, "Have 16bit Grayscale");
289 GP_DEBUG(1, "Unimplemented bits per sample %u",
290 (unsigned) header
->bits_per_sample
);
291 return GP_PIXEL_UNKNOWN
;
295 static GP_PixelType
match_rgb_pixel_type(TIFF
*tiff
, struct tiff_header
*header
)
299 if (!TIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
)) {
300 GP_DEBUG(1, "Failed to get Samples Per Pixel");
304 GP_DEBUG(1, "Have %u samples per pixel", (unsigned) samples
);
306 uint16_t bps
= header
->bits_per_sample
;
308 /* Mach RGB pixel type with given pixel sizes */
310 return GP_PixelRGBLookup(bps
, 0, bps
, bps
,
311 bps
, 2*bps
, 0, 0, 3*bps
);
313 GP_DEBUG(1, "Unsupported");
314 return GP_PIXEL_UNKNOWN
;
317 static GP_PixelType
match_pixel_type(TIFF
*tiff
, struct tiff_header
*header
)
319 if (!TIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &header
->photometric
))
320 return GP_PIXEL_UNKNOWN
;
322 GP_DEBUG(1, "Have photometric %s",
323 photometric_name(header
->photometric
));
325 switch (header
->photometric
) {
326 /* 1-bit or 4, 8-bit grayscale */
327 case PHOTOMETRIC_MINISWHITE
:
328 case PHOTOMETRIC_MINISBLACK
:
329 return match_grayscale_pixel_type(tiff
, header
);
330 case PHOTOMETRIC_RGB
:
331 return match_rgb_pixel_type(tiff
, header
);
332 /* The palete is RGB161616 map it to BGR888 for now */
333 case PHOTOMETRIC_PALETTE
:
334 return GP_PIXEL_RGB888
;
336 GP_DEBUG(1, "Unimplemented photometric interpretation %u",
337 (unsigned) header
->photometric
);
338 return GP_PIXEL_UNKNOWN
;
342 static uint16_t get_idx(uint8_t *row
, uint32_t x
, uint16_t bps
)
346 return !!(row
[x
/8] & (1<<(7 - x
%8)));
348 return (row
[x
/4] >> (2*(3 - x
%4))) & 0x03;
350 return (row
[x
/2] >> (4*(!(x
%2)))) & 0x0f;
354 return ((uint16_t*)row
)[x
];
357 GP_DEBUG(1, "Unsupported bits per sample %u", (unsigned) bps
);
361 static int tiff_read_palette(TIFF
*tiff
, GP_Pixmap
*res
,
362 struct tiff_header
*header
,
363 GP_ProgressCallback
*callback
)
365 if (TIFFIsTiled(tiff
)) {
370 if (header
->bits_per_sample
> 48) {
371 GP_DEBUG(1, "Bits per sample too big %u",
372 (unsigned)header
->bits_per_sample
);
376 unsigned int palette_size
= (1<<header
->bits_per_sample
);
377 uint16_t *palette_r
, *palette_g
, *palette_b
;
378 uint32_t x
, y
, scanline_size
;
380 GP_DEBUG(1, "Pallete size %u", palette_size
);
382 if (!TIFFGetField(tiff
, TIFFTAG_COLORMAP
, &palette_r
, &palette_g
, &palette_b
)) {
383 GP_DEBUG(1, "Failed to read palette");
387 scanline_size
= TIFFScanlineSize(tiff
);
389 GP_DEBUG(1, "Scanline size %u", (unsigned) scanline_size
);
391 uint8_t buf
[scanline_size
];
393 /* Read image strips scanline by scanline */
394 for (y
= 0; y
< header
->h
; y
++) {
395 if (TIFFReadScanline(tiff
, buf
, y
, 0) != 1) {
396 //TODO: Make use of TIFF ERROR
397 GP_DEBUG(1, "Error reading scanline");
401 for (x
= 0; x
< header
->w
; x
++) {
402 uint16_t i
= get_idx(buf
, x
, header
->bits_per_sample
);
404 if (i
>= palette_size
) {
405 GP_WARN("Invalid palette index %u",
410 GP_Pixel p
= GP_Pixel_CREATE_RGB888(palette_r
[i
]>>8,
414 GP_PutPixel_Raw_24BPP(res
, x
, y
, p
);
417 if (GP_ProgressCallbackReport(callback
, y
, res
->h
, res
->w
)) {
418 GP_DEBUG(1, "Operation aborted");
423 GP_ProgressCallbackDone(callback
);
427 //Temporary, the bitendians strikes again
428 #include "core/GP_BitSwap.h"
431 * Direct read -> data in image are in right format.
433 static int tiff_read(TIFF
*tiff
, GP_Pixmap
*res
, struct tiff_header
*header
,
434 GP_ProgressCallback
*callback
)
437 uint16_t planar_config
, samples
, s
;
439 GP_DEBUG(1, "Reading tiff data");
441 if (TIFFIsTiled(tiff
)) {
446 //ASSERT ScanlineSize == w!
448 /* Figure out number of planes */
449 if (!TIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar_config
))
452 switch (planar_config
) {
454 GP_DEBUG(1, "Planar config = 1, all samples are in one plane");
458 if (!TIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
)) {
459 GP_DEBUG(1, "Planar config = 2, samples per pixel undefined");
462 GP_DEBUG(1, "Have %u samples per pixel", (unsigned)samples
);
465 GP_DEBUG(1, "Unimplemented planar config = %u",
466 (unsigned)planar_config
);
470 /* Read image strips scanline by scanline */
471 for (y
= 0; y
< header
->h
; y
++) {
472 uint8_t *addr
= GP_PIXEL_ADDR(res
, 0, y
);
474 //TODO: Does not work with RowsPerStrip > 1 -> needs StripOrientedIO
475 for (s
= 0; s
< samples
; s
++) {
476 if (TIFFReadScanline(tiff
, addr
, y
, s
) != 1) {
477 //TODO: Make use of TIFF ERROR
478 GP_DEBUG(1, "Error reading scanline");
482 //Temporary, till bitendians are fixed
483 switch (res
->pixel_type
) {
485 GP_BitSwapRow_B1(addr
, res
->bytes_per_row
);
488 GP_BitSwapRow_B2(addr
, res
->bytes_per_row
);
491 GP_BitSwapRow_B4(addr
, res
->bytes_per_row
);
497 /* We need to negate the values when Min is White */
498 if (header
->photometric
== PHOTOMETRIC_MINISWHITE
)
499 for (i
= 0; i
< res
->bytes_per_row
; i
++)
503 if (GP_ProgressCallbackReport(callback
, y
, res
->h
, res
->w
)) {
504 GP_DEBUG(1, "Operation aborted");
509 GP_ProgressCallbackDone(callback
);
513 static tsize_t
tiff_io_read(thandle_t io
, void *buf
, tsize_t size
)
515 return GP_IORead(io
, buf
, size
);
518 static tsize_t
tiff_io_write(thandle_t io
, void *buf
, tsize_t size
)
520 return GP_IOWrite(io
, buf
, size
);
523 static toff_t
tiff_io_seek(thandle_t io
, toff_t offset
, int whence
)
525 return GP_IOSeek(io
, offset
, whence
);
528 static int tiff_io_close(thandle_t
GP_UNUSED(io
))
533 static toff_t
tiff_io_size(thandle_t io
)
535 return GP_IOSize(io
);
539 static int tiff_io_map(thandle_t io, void **base, toff_t *size)
541 GP_WARN("stub called");
545 static void tiff_io_unmap(thandle_t io, void *base, toff_t size)
547 GP_WARN("stub called");
552 int GP_ReadTIFFEx(GP_IO
*io
, GP_Pixmap
**img
, GP_DataStorage
*storage
,
553 GP_ProgressCallback
*callback
)
556 struct tiff_header header
;
558 GP_PixelType pixel_type
;
561 tiff
= TIFFClientOpen("GFXprim IO", "r", io
, tiff_io_read
,
562 tiff_io_write
, tiff_io_seek
, tiff_io_close
,
563 tiff_io_size
, NULL
, NULL
);
566 GP_DEBUG(1, "TIFFClientOpen failed");
571 if ((err
= read_header(tiff
, &header
)))
575 fill_metadata(tiff
, &header
, storage
);
580 pixel_type
= match_pixel_type(tiff
, &header
);
582 if (pixel_type
== GP_PIXEL_UNKNOWN
) {
587 res
= GP_PixmapAlloc(header
.w
, header
.h
, pixel_type
);
591 GP_DEBUG(1, "Malloc failed");
595 switch (header
.photometric
) {
596 case PHOTOMETRIC_PALETTE
:
597 err
= tiff_read_palette(tiff
, res
, &header
, callback
);
600 err
= tiff_read(tiff
, res
, &header
, callback
);
619 static int save_grayscale(TIFF
*tiff
, const GP_Pixmap
*src
,
620 GP_ProgressCallback
*callback
)
623 uint8_t buf
[src
->bytes_per_row
];
626 TIFFSetField(tiff
, TIFFTAG_BITSPERSAMPLE
, src
->bpp
);
627 TIFFSetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, 1);
628 TIFFSetField(tiff
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_MINISBLACK
);
629 TIFFSetField(tiff
, TIFFTAG_FILLORDER
, FILLORDER_MSB2LSB
);
631 for (y
= 0; y
< src
->h
; y
++) {
632 uint8_t *addr
= GP_PIXEL_ADDR(src
, 0, y
);
634 if (src
->bpp
< 8 && !src
->bit_endian
) {
635 for (x
= 0; x
< src
->bytes_per_row
; x
++) {
636 switch (src
->pixel_type
) {
638 buf
[x
] = GP_BIT_SWAP_B1(addr
[x
]);
641 buf
[x
] = GP_BIT_SWAP_B2(addr
[x
]);
644 buf
[x
] = GP_BIT_SWAP_B4(addr
[x
]);
647 GP_BUG("Uh, oh, do we need swap?");
653 ret
= TIFFWriteEncodedStrip(tiff
, y
, addr
, src
->bytes_per_row
);
657 GP_DEBUG(1, "TIFFWriteEncodedStrip failed");
661 if (GP_ProgressCallbackReport(callback
, y
, src
->h
, src
->w
)) {
662 GP_DEBUG(1, "Operation aborted");
670 static int save_rgb(TIFF
*tiff
, const GP_Pixmap
*src
,
671 GP_ProgressCallback
*callback
)
673 uint8_t buf
[src
->w
* 3];
676 TIFFSetField(tiff
, TIFFTAG_BITSPERSAMPLE
, 8);
677 TIFFSetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, 3);
678 TIFFSetField(tiff
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_RGB
);
680 for (y
= 0; y
< src
->h
; y
++) {
681 uint8_t *addr
= GP_PIXEL_ADDR(src
, 0, y
);
683 switch (src
->pixel_type
) {
684 case GP_PIXEL_RGB888
:
685 for (x
= 0; x
< src
->bytes_per_row
; x
+=3) {
686 buf
[x
+ 2] = addr
[x
];
687 buf
[x
+ 1] = addr
[x
+ 1];
688 buf
[x
] = addr
[x
+ 2];
692 case GP_PIXEL_xRGB8888
:
693 for (x
= 0; x
< src
->bytes_per_row
; x
+=4) {
694 buf
[3*(x
/4) + 2] = addr
[x
];
695 buf
[3*(x
/4) + 1] = addr
[x
+ 1];
696 buf
[3*(x
/4)] = addr
[x
+ 2];
704 TIFFWriteEncodedStrip(tiff
, y
, addr
, src
->w
* 3);
706 if (GP_ProgressCallbackReport(callback
, y
, src
->h
, src
->w
)) {
707 GP_DEBUG(1, "Operation aborted");
715 static GP_PixelType save_ptypes
[] = {
726 int GP_WriteTIFF(const GP_Pixmap
*src
, GP_IO
*io
,
727 GP_ProgressCallback
*callback
)
732 GP_DEBUG(1, "Writing TIFF to I/O (%p)", io
);
734 if (GP_PixelHasFlags(src
->pixel_type
, GP_PIXEL_HAS_ALPHA
)) {
735 GP_DEBUG(1, "Alpha channel not supported yet");
740 switch (src
->pixel_type
) {
746 case GP_PIXEL_RGB888
:
747 case GP_PIXEL_BGR888
:
748 case GP_PIXEL_xRGB8888
:
751 GP_DEBUG(1, "Unsupported pixel type %s",
752 GP_PixelTypeName(src
->pixel_type
));
757 /* Open TIFF image */
758 tiff
= TIFFClientOpen("GFXprim IO", "w", io
, tiff_io_read
,
759 tiff_io_write
, tiff_io_seek
, tiff_io_close
,
760 tiff_io_size
, NULL
, NULL
);
763 GP_DEBUG(1, "TIFFClientOpen failed");
768 /* Set required fields */
769 TIFFSetField(tiff
, TIFFTAG_IMAGEWIDTH
, src
->w
);
770 TIFFSetField(tiff
, TIFFTAG_IMAGELENGTH
, src
->h
);
771 TIFFSetField(tiff
, TIFFTAG_ROWSPERSTRIP
, 1);
772 TIFFSetField(tiff
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
);
774 switch (src
->pixel_type
) {
775 case GP_PIXEL_RGB888
:
776 case GP_PIXEL_BGR888
:
777 case GP_PIXEL_xRGB8888
:
778 err
= save_rgb(tiff
, src
, callback
);
784 err
= save_grayscale(tiff
, src
, callback
);
787 GP_BUG("Wrong pixel type");
798 GP_ProgressCallbackDone(callback
);
804 int GP_ReadTIFFEx(GP_IO
GP_UNUSED(*io
), GP_Pixmap
GP_UNUSED(**img
),
805 GP_DataStorage
GP_UNUSED(*storage
),
806 GP_ProgressCallback
GP_UNUSED(*callback
))
812 int GP_WriteTIFF(const GP_Pixmap
GP_UNUSED(*src
), GP_IO
GP_UNUSED(*io
),
813 GP_ProgressCallback
GP_UNUSED(*callback
))
819 #endif /* HAVE_TIFF */
821 GP_Pixmap
*GP_LoadTIFF(const char *src_path
, GP_ProgressCallback
*callback
)
823 return GP_LoaderLoadImage(&GP_TIFF
, src_path
, callback
);
826 GP_Pixmap
*GP_ReadTIFF(GP_IO
*io
, GP_ProgressCallback
*callback
)
828 return GP_LoaderReadImage(&GP_TIFF
, io
, callback
);
831 int GP_LoadTIFFEx(const char *src_path
, GP_Pixmap
**img
,
832 GP_DataStorage
*storage
, GP_ProgressCallback
*callback
)
834 return GP_LoaderLoadImageEx(&GP_TIFF
, src_path
, img
, storage
, callback
);
837 int GP_SaveTIFF(const GP_Pixmap
*src
, const char *dst_path
,
838 GP_ProgressCallback
*callback
)
840 return GP_LoaderSaveImage(&GP_TIFF
, src
, dst_path
, callback
);
843 struct GP_Loader GP_TIFF
= {
845 .Read
= GP_ReadTIFFEx
,
846 .Write
= GP_WriteTIFF
,
847 .save_ptypes
= save_ptypes
,
849 .Match
= GP_MatchTIFF
,
851 .fmt_name
= "Tag Image File Format",
852 .extensions
= {"tif", "tiff", NULL
},