1 // ==========================================================
2 // TIFF Loader and Writer
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Hervé Drolon (drolon@infonie.fr)
7 // - Markus Loibl (markus.loibl@epost.de)
8 // - Luca Piergentili (l.pierge@terra.es)
9 // - Detlev Vendt (detlev.vendt@brillit.de)
10 // - Mihail Naydenov (mnaydenov@users.sourceforge.net)
11 //
12 // This file is part of FreeImage 3
13 //
14 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
15 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
16 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
17 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
18 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
19 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
20 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
21 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
22 // THIS DISCLAIMER.
23 //
24 // Use at your own risk!
25 // ==========================================================
26 
27 #ifdef _MSC_VER
28 #pragma warning (disable : 4786) // identifier was truncated to 'number' characters
29 #endif
30 
31 #ifdef unix
32 #undef unix
33 #endif
34 #ifdef __unix
35 #undef __unix
36 #endif
37 
38 #include "FreeImage.h"
39 #include "Utilities.h"
40 #include "../LibTIFF4/tiffiop.h"
41 #include "../Metadata/FreeImageTag.h"
42 #include "../OpenEXR/Half/half.h"
43 
44 #include "FreeImageIO.h"
45 #include "PSDParser.h"
46 
47 // --------------------------------------------------------------------------
48 // GeoTIFF profile (see XTIFF.cpp)
49 // --------------------------------------------------------------------------
50 void XTIFFInitialize();
51 BOOL tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib);
52 BOOL tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib);
53 
54 // --------------------------------------------------------------------------
55 // TIFF Exif profile (see XTIFF.cpp)
56 // ----------------------------------------------------------
57 BOOL tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib);
58 BOOL tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib);
59 
60 // --------------------------------------------------------------------------
61 //   LogLuv conversion functions interface (see TIFFLogLuv.cpp)
62 // --------------------------------------------------------------------------
63 void tiff_ConvertLineXYZToRGB(BYTE *target, BYTE *source, double stonits, int width_in_pixels);
64 void tiff_ConvertLineRGBToXYZ(BYTE *target, BYTE *source, int width_in_pixels);
65 
66 // ----------------------------------------------------------
67 
68 /** Supported loading methods */
69 typedef enum {
70 	LoadAsRBGA			= 0,
71 	LoadAsCMYK			= 1,
72 	LoadAs8BitTrns		= 2,
73 	LoadAsGenericStrip	= 3,
74 	LoadAsTiled			= 4,
75 	LoadAsLogLuv		= 5,
76 	LoadAsHalfFloat		= 6
77 } TIFFLoadMethod;
78 
79 // ----------------------------------------------------------
80 //   local prototypes
81 // ----------------------------------------------------------
82 
83 static tmsize_t _tiffReadProc(thandle_t handle, void* buf, tmsize_t size);
84 static tmsize_t _tiffWriteProc(thandle_t handle, void* buf, tmsize_t size);
85 static toff_t _tiffSeekProc(thandle_t handle, toff_t off, int whence);
86 static int _tiffCloseProc(thandle_t fd);
87 static int _tiffMapProc(thandle_t fd, void** pbase, toff_t* psize);
88 static void _tiffUnmapProc(thandle_t fd, void* base, toff_t size);
89 
90 static uint16 CheckColormap(int n, uint16* r, uint16* g, uint16* b);
91 static uint16 GetPhotometric(FIBITMAP *dib);
92 
93 static void ReadResolution(TIFF *tiff, FIBITMAP *dib);
94 static void WriteResolution(TIFF *tiff, FIBITMAP *dib);
95 
96 static void ReadPalette(TIFF *tiff, uint16 photometric, uint16 bitspersample, FIBITMAP *dib);
97 
98 static FIBITMAP* CreateImageType(BOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, uint16 bitspersample, uint16 samplesperpixel);
99 static FREE_IMAGE_TYPE ReadImageType(TIFF *tiff, uint16 bitspersample, uint16 samplesperpixel);
100 static void WriteImageType(TIFF *tiff, FREE_IMAGE_TYPE fit);
101 
102 static void WriteCompression(TIFF *tiff, uint16 bitspersample, uint16 samplesperpixel, uint16 photometric, int flags);
103 
104 static BOOL tiff_read_iptc_profile(TIFF *tiff, FIBITMAP *dib);
105 static BOOL tiff_read_xmp_profile(TIFF *tiff, FIBITMAP *dib);
106 static BOOL tiff_read_exif_profile(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib);
107 static void ReadMetadata(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib);
108 
109 static BOOL tiff_write_iptc_profile(TIFF *tiff, FIBITMAP *dib);
110 static BOOL tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib);
111 static void WriteMetadata(TIFF *tiff, FIBITMAP *dib);
112 
113 static TIFFLoadMethod FindLoadMethod(TIFF *tif, uint16 photometric, uint16 bitspersample, uint16 samplesperpixel, FREE_IMAGE_TYPE image_type, int flags);
114 
115 static void ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMAP *dib);
116 
117 
118 // ==========================================================
119 // Plugin Interface
120 // ==========================================================
121 
122 static int s_format_id;
123 
124 typedef struct {
125     FreeImageIO *io;
126 	fi_handle handle;
127 	TIFF *tif;
128 } fi_TIFFIO;
129 
130 // ----------------------------------------------------------
131 //   libtiff interface
132 // ----------------------------------------------------------
133 
134 static tmsize_t
_tiffReadProc(thandle_t handle,void * buf,tmsize_t size)135 _tiffReadProc(thandle_t handle, void *buf, tmsize_t size) {
136 	fi_TIFFIO *fio = (fi_TIFFIO*)handle;
137 	return fio->io->read_proc(buf, (unsigned)size, 1, fio->handle) * size;
138 }
139 
140 static tmsize_t
_tiffWriteProc(thandle_t handle,void * buf,tmsize_t size)141 _tiffWriteProc(thandle_t handle, void *buf, tmsize_t size) {
142 	fi_TIFFIO *fio = (fi_TIFFIO*)handle;
143 	return fio->io->write_proc(buf, (unsigned)size, 1, fio->handle) * size;
144 }
145 
146 static toff_t
_tiffSeekProc(thandle_t handle,toff_t off,int whence)147 _tiffSeekProc(thandle_t handle, toff_t off, int whence) {
148 	fi_TIFFIO *fio = (fi_TIFFIO*)handle;
149 	fio->io->seek_proc(fio->handle, (long)off, whence);
150 	return fio->io->tell_proc(fio->handle);
151 }
152 
153 static int
_tiffCloseProc(thandle_t fd)154 _tiffCloseProc(thandle_t fd) {
155 	return 0;
156 }
157 
158 #include <sys/stat.h>
159 
160 static toff_t
_tiffSizeProc(thandle_t handle)161 _tiffSizeProc(thandle_t handle) {
162     fi_TIFFIO *fio = (fi_TIFFIO*)handle;
163     long currPos = fio->io->tell_proc(fio->handle);
164     fio->io->seek_proc(fio->handle, 0, SEEK_END);
165     long fileSize = fio->io->tell_proc(fio->handle);
166     fio->io->seek_proc(fio->handle, currPos, SEEK_SET);
167     return fileSize;
168 }
169 
170 static int
_tiffMapProc(thandle_t,void ** base,toff_t * size)171 _tiffMapProc(thandle_t, void** base, toff_t* size) {
172 	return 0;
173 }
174 
175 static void
_tiffUnmapProc(thandle_t,void * base,toff_t size)176 _tiffUnmapProc(thandle_t, void* base, toff_t size) {
177 }
178 
179 /**
180 Open a TIFF file descriptor for reading or writing
181 @param handle File handle
182 @param name Name of the file handle
183 @param mode Specifies if the file is to be opened for reading ("r") or writing ("w")
184 */
185 TIFF *
TIFFFdOpen(thandle_t handle,const char * name,const char * mode)186 TIFFFdOpen(thandle_t handle, const char *name, const char *mode) {
187 	TIFF *tif;
188 
189 	// Open the file; the callback will set everything up
190 	tif = TIFFClientOpen(name, mode, handle,
191 	    _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
192 	    _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
193 
194 	return tif;
195 }
196 
197 /**
198 Open a TIFF file for reading or writing
199 @param name
200 @param mode
201 */
202 TIFF*
TIFFOpen(const char * name,const char * mode)203 TIFFOpen(const char* name, const char* mode) {
204 	return 0;
205 }
206 
207 // ----------------------------------------------------------
208 //   TIFF library FreeImage-specific routines.
209 // ----------------------------------------------------------
210 
211 void*
_TIFFmalloc(tmsize_t s)212 _TIFFmalloc(tmsize_t s) {
213 	return malloc(s);
214 }
215 
216 void*
_TIFFcalloc(tmsize_t nmemb,tmsize_t siz)217 _TIFFcalloc(tmsize_t nmemb, tmsize_t siz) {
218 	if (nmemb == 0 || siz == 0) {
219 		return ((void *)NULL);
220 	}
221 	return calloc((size_t)nmemb, (size_t)siz);
222 }
223 
224 void
_TIFFfree(void * p)225 _TIFFfree(void *p) {
226 	free(p);
227 }
228 
229 void*
_TIFFrealloc(void * p,tmsize_t s)230 _TIFFrealloc(void* p, tmsize_t s) {
231 	return realloc(p, s);
232 }
233 
234 void
_TIFFmemset(void * p,int v,tmsize_t c)235 _TIFFmemset(void* p, int v, tmsize_t c) {
236 	memset(p, v, (size_t) c);
237 }
238 
239 void
_TIFFmemcpy(void * d,const void * s,tmsize_t c)240 _TIFFmemcpy(void* d, const void* s, tmsize_t c) {
241 	memcpy(d, s, (size_t) c);
242 }
243 
244 int
_TIFFmemcmp(const void * p1,const void * p2,tmsize_t c)245 _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c) {
246 	return (memcmp(p1, p2, (size_t) c));
247 }
248 
249 // ----------------------------------------------------------
250 //   in FreeImage warnings and errors are disabled
251 // ----------------------------------------------------------
252 
253 static void
msdosWarningHandler(const char * module,const char * fmt,va_list ap)254 msdosWarningHandler(const char* module, const char* fmt, va_list ap) {
255 }
256 
257 TIFFErrorHandler _TIFFwarningHandler = msdosWarningHandler;
258 
259 static void
msdosErrorHandler(const char * module,const char * fmt,va_list ap)260 msdosErrorHandler(const char* module, const char* fmt, va_list ap) {
261 
262 	// use this for diagnostic only (do not use otherwise, even in DEBUG mode)
263 	/*
264 	if (module != NULL) {
265 		char msg[1024];
266 		vsprintf(msg, fmt, ap);
267 		FreeImage_OutputMessageProc(s_format_id, "%s: %s", module, msg);
268 	}
269 	*/
270 }
271 
272 TIFFErrorHandler _TIFFerrorHandler = msdosErrorHandler;
273 
274 // ----------------------------------------------------------
275 
276 #define CVT(x)      (((x) * 255L) / ((1L<<16)-1))
277 #define	SCALE(x)	(((x)*((1L<<16)-1))/255)
278 
279 // ==========================================================
280 // Internal functions
281 // ==========================================================
282 
283 static uint16
CheckColormap(int n,uint16 * r,uint16 * g,uint16 * b)284 CheckColormap(int n, uint16* r, uint16* g, uint16* b) {
285     while (n-- > 0) {
286         if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) {
287 			return 16;
288 		}
289 	}
290 
291     return 8;
292 }
293 
294 /**
295 Get the TIFFTAG_PHOTOMETRIC value from the dib
296 */
297 static uint16
GetPhotometric(FIBITMAP * dib)298 GetPhotometric(FIBITMAP *dib) {
299 	FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
300 	switch(color_type) {
301 		case FIC_MINISWHITE:	// min value is white
302 			return PHOTOMETRIC_MINISWHITE;
303 		case FIC_MINISBLACK:	// min value is black
304 			return PHOTOMETRIC_MINISBLACK;
305 		case FIC_PALETTE:		// color map indexed
306 			return PHOTOMETRIC_PALETTE;
307 		case FIC_RGB:			// RGB color model
308 		case FIC_RGBALPHA:		// RGB color model with alpha channel
309 			return PHOTOMETRIC_RGB;
310 		case FIC_CMYK:			// CMYK color model
311 			return PHOTOMETRIC_RGB;	// default to RGB unless the save flag is set to TIFF_CMYK
312 		default:
313 			return PHOTOMETRIC_MINISBLACK;
314 	}
315 }
316 
317 /**
318 Get the resolution from the TIFF and fill the dib with universal units
319 */
320 static void
ReadResolution(TIFF * tiff,FIBITMAP * dib)321 ReadResolution(TIFF *tiff, FIBITMAP *dib) {
322 	float fResX = 300.0;
323 	float fResY = 300.0;
324 	uint16 resUnit = RESUNIT_INCH;
325 
326 	TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit);
327 	TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &fResX);
328 	TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &fResY);
329 
330 	// If we don't have a valid resolution unit and valid resolution is specified then assume inch
331 	if (resUnit == RESUNIT_NONE && fResX > 0.0 && fResY > 0.0) {
332 		resUnit = RESUNIT_INCH;
333 	}
334 	if (resUnit == RESUNIT_INCH) {
335 		FreeImage_SetDotsPerMeterX(dib, (unsigned) (fResX/0.0254000 + 0.5));
336 		FreeImage_SetDotsPerMeterY(dib, (unsigned) (fResY/0.0254000 + 0.5));
337 	} else if(resUnit == RESUNIT_CENTIMETER) {
338 		FreeImage_SetDotsPerMeterX(dib, (unsigned) (fResX*100.0 + 0.5));
339 		FreeImage_SetDotsPerMeterY(dib, (unsigned) (fResY*100.0 + 0.5));
340 	}
341 }
342 
343 /**
344 Set the resolution to the TIFF using english units
345 */
346 static void
WriteResolution(TIFF * tiff,FIBITMAP * dib)347 WriteResolution(TIFF *tiff, FIBITMAP *dib) {
348 	double res;
349 
350 	TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
351 
352 	res = (unsigned long) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterX(dib));
353 	TIFFSetField(tiff, TIFFTAG_XRESOLUTION, res);
354 
355 	res = (unsigned long) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterY(dib));
356 	TIFFSetField(tiff, TIFFTAG_YRESOLUTION, res);
357 }
358 
359 /**
360 Fill the dib palette according to the TIFF photometric
361 */
362 static void
ReadPalette(TIFF * tiff,uint16 photometric,uint16 bitspersample,FIBITMAP * dib)363 ReadPalette(TIFF *tiff, uint16 photometric, uint16 bitspersample, FIBITMAP *dib) {
364 	RGBQUAD *pal = FreeImage_GetPalette(dib);
365 
366 	switch(photometric) {
367 		case PHOTOMETRIC_MINISBLACK:	// bitmap and greyscale image types
368 		case PHOTOMETRIC_MINISWHITE:
369 			// Monochrome image
370 
371 			if (bitspersample == 1) {
372 				if (photometric == PHOTOMETRIC_MINISWHITE) {
373 					pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255;
374 					pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 0;
375 				} else {
376 					pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
377 					pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
378 				}
379 
380 			} else if ((bitspersample == 4) ||(bitspersample == 8)) {
381 				// need to build the scale for greyscale images
382 				int ncolors = FreeImage_GetColorsUsed(dib);
383 
384 				if (photometric == PHOTOMETRIC_MINISBLACK) {
385 					for (int i = 0; i < ncolors; i++) {
386 						pal[i].rgbRed	=
387 						pal[i].rgbGreen =
388 						pal[i].rgbBlue	= (BYTE)(i*(255/(ncolors-1)));
389 					}
390 				} else {
391 					for (int i = 0; i < ncolors; i++) {
392 						pal[i].rgbRed	=
393 						pal[i].rgbGreen =
394 						pal[i].rgbBlue	= (BYTE)(255-i*(255/(ncolors-1)));
395 					}
396 				}
397 			}
398 
399 			break;
400 
401 		case PHOTOMETRIC_PALETTE:	// color map indexed
402 			uint16 *red;
403 			uint16 *green;
404 			uint16 *blue;
405 
406 			TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue);
407 
408 			// load the palette in the DIB
409 
410 			if (CheckColormap(1<<bitspersample, red, green, blue) == 16) {
411 				for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
412 					pal[i].rgbRed =(BYTE) CVT(red[i]);
413 					pal[i].rgbGreen = (BYTE) CVT(green[i]);
414 					pal[i].rgbBlue = (BYTE) CVT(blue[i]);
415 				}
416 			} else {
417 				for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
418 					pal[i].rgbRed = (BYTE) red[i];
419 					pal[i].rgbGreen = (BYTE) green[i];
420 					pal[i].rgbBlue = (BYTE) blue[i];
421 				}
422 			}
423 
424 			break;
425 	}
426 }
427 
428 /**
429 Allocate a FIBITMAP
430 @param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
431 @param fit Image type
432 @param width Image width in pixels
433 @param height Image height in pixels
434 @param bitspersample # bits per sample
435 @param samplesperpixel # samples per pixel
436 @return Returns the allocated image if successful, returns NULL otherwise
437 */
438 static FIBITMAP*
CreateImageType(BOOL header_only,FREE_IMAGE_TYPE fit,int width,int height,uint16 bitspersample,uint16 samplesperpixel)439 CreateImageType(BOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, uint16 bitspersample, uint16 samplesperpixel) {
440 	FIBITMAP *dib = NULL;
441 
442 	if((width < 0) || (height < 0)) {
443 		// check for malicious images
444 		return NULL;
445 	}
446 
447 	int bpp = bitspersample * samplesperpixel;
448 
449 	if(fit == FIT_BITMAP) {
450 		// standard bitmap type
451 
452 		if(bpp == 16) {
453 
454 			if((samplesperpixel == 2) && (bitspersample == 8)) {
455 				// 8-bit indexed + 8-bit alpha channel -> convert to 8-bit transparent
456 				dib = FreeImage_AllocateHeader(header_only, width, height, 8);
457 			} else {
458 				// 16-bit RGB -> expect it to be 565
459 				dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
460 			}
461 
462 		}
463 		else {
464 
465 			dib = FreeImage_AllocateHeader(header_only, width, height, MIN(bpp, 32), FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
466 		}
467 
468 
469 	} else {
470 		// other bitmap types
471 
472 		dib = FreeImage_AllocateHeaderT(header_only, fit, width, height, bpp);
473 	}
474 
475 	return dib;
476 }
477 
478 /**
479 Read the TIFFTAG_SAMPLEFORMAT tag and convert to FREE_IMAGE_TYPE
480 @param tiff LibTIFF TIFF Handle
481 @param bitspersample # bit per sample
482 @param samplesperpixel # samples per pixel
483 @return Returns the image type as a FREE_IMAGE_TYPE value
484 */
485 static FREE_IMAGE_TYPE
ReadImageType(TIFF * tiff,uint16 bitspersample,uint16 samplesperpixel)486 ReadImageType(TIFF *tiff, uint16 bitspersample, uint16 samplesperpixel) {
487 	uint16 sampleformat = 0;
488 	FREE_IMAGE_TYPE fit = FIT_BITMAP ;
489 
490 	uint16 bpp = bitspersample * samplesperpixel;
491 
492 	// try the sampleformat tag
493     if(TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat)) {
494 
495         switch (sampleformat) {
496 			case SAMPLEFORMAT_UINT:
497 				switch (bpp) {
498 					case 1:
499 					case 4:
500 					case 8:
501 					case 24:
502 						fit = FIT_BITMAP;
503 						break;
504 					case 16:
505 						// 8-bit + alpha or 16-bit greyscale
506 						if(samplesperpixel == 2) {
507 							fit = FIT_BITMAP;
508 						} else {
509 							fit = FIT_UINT16;
510 						}
511 						break;
512 					case 32:
513 						if(samplesperpixel == 4) {
514 							fit = FIT_BITMAP;
515 						} else {
516 							fit = FIT_UINT32;
517 						}
518 						break;
519 					case 48:
520 						if(samplesperpixel == 3) {
521 							fit = FIT_RGB16;
522 						}
523 						break;
524 					case 64:
525 						if(samplesperpixel == 4) {
526 							fit = FIT_RGBA16;
527 						}
528 						break;
529 				}
530 				break;
531 
532 			case SAMPLEFORMAT_INT:
533 				switch (bpp) {
534 					case 16:
535 						if(samplesperpixel == 3) {
536 							fit = FIT_BITMAP;
537 						} else {
538 							fit = FIT_INT16;
539 						}
540 						break;
541 					case 32:
542 						fit = FIT_INT32;
543 						break;
544 				}
545 				break;
546 
547 			case SAMPLEFORMAT_IEEEFP:
548 				switch (bpp) {
549 					case 32:
550 						fit = FIT_FLOAT;
551 						break;
552 					case 48:
553 						// 3 x half float => convert to RGBF
554 						if((samplesperpixel == 3) && (bitspersample == 16)) {
555 							fit = FIT_RGBF;
556 						}
557 						break;
558 					case 64:
559 						if(samplesperpixel == 2) {
560 							fit = FIT_FLOAT;
561 						} else {
562 							fit = FIT_DOUBLE;
563 						}
564 						break;
565 					case 96:
566 						fit = FIT_RGBF;
567 						break;
568 					default:
569 						if(bpp >= 128) {
570 							fit = FIT_RGBAF;
571 						}
572 					break;
573 				}
574 				break;
575 			case SAMPLEFORMAT_COMPLEXIEEEFP:
576 				switch (bpp) {
577 					case 64:
578 						break;
579 					case 128:
580 						fit = FIT_COMPLEX;
581 						break;
582 				}
583 				break;
584 
585 			}
586     }
587 	// no sampleformat tag : assume SAMPLEFORMAT_UINT
588 	else {
589 		if(samplesperpixel == 1) {
590 			switch (bpp) {
591 				case 16:
592 					fit = FIT_UINT16;
593 					break;
594 
595 				case 32:
596 					fit = FIT_UINT32;
597 					break;
598 			}
599 		}
600 		else if(samplesperpixel == 3) {
601 			if(bpp == 48) fit = FIT_RGB16;
602 		}
603 		else if(samplesperpixel >= 4) {
604 			if(bitspersample == 16) {
605 				fit = FIT_RGBA16;
606 			}
607 		}
608 
609 	}
610 
611     return fit;
612 }
613 
614 /**
615 Convert FREE_IMAGE_TYPE and write TIFFTAG_SAMPLEFORMAT
616 @param tiff LibTIFF TIFF Handle
617 @param fit Image type as a FREE_IMAGE_TYPE value
618 */
619 static void
WriteImageType(TIFF * tiff,FREE_IMAGE_TYPE fit)620 WriteImageType(TIFF *tiff, FREE_IMAGE_TYPE fit) {
621 	switch(fit) {
622 		case FIT_BITMAP:	// standard image: 1-, 4-, 8-, 16-, 24-, 32-bit
623 		case FIT_UINT16:	// array of unsigned short	: unsigned 16-bit
624 		case FIT_UINT32:	// array of unsigned long	: unsigned 32-bit
625 		case FIT_RGB16:		// 48-bit RGB image			: 3 x 16-bit
626 		case FIT_RGBA16:	// 64-bit RGBA image		: 4 x 16-bit
627 			TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
628 			break;
629 
630 		case FIT_INT16:		// array of short	: signed 16-bit
631 		case FIT_INT32:		// array of long	: signed 32-bit
632 			TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
633 			break;
634 
635 		case FIT_FLOAT:		// array of float	: 32-bit
636 		case FIT_DOUBLE:	// array of double	: 64-bit
637 		case FIT_RGBF:		// 96-bit RGB float image	: 3 x 32-bit IEEE floating point
638 		case FIT_RGBAF:		// 128-bit RGBA float image	: 4 x 32-bit IEEE floating point
639 			TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
640 			break;
641 
642 		case FIT_COMPLEX:	// array of COMPLEX : 2 x 64-bit
643 			TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_COMPLEXIEEEFP);
644 			break;
645 	}
646 }
647 
648 /**
649 Select the compression algorithm
650 @param tiff LibTIFF TIFF Handle
651 @param
652 */
653 static void
WriteCompression(TIFF * tiff,uint16 bitspersample,uint16 samplesperpixel,uint16 photometric,int flags)654 WriteCompression(TIFF *tiff, uint16 bitspersample, uint16 samplesperpixel, uint16 photometric, int flags) {
655 	uint16 compression;
656 	uint16 bitsperpixel = bitspersample * samplesperpixel;
657 
658 	if(photometric == PHOTOMETRIC_LOGLUV) {
659 		compression = COMPRESSION_SGILOG;
660 	} else if ((flags & TIFF_PACKBITS) == TIFF_PACKBITS) {
661 		compression = COMPRESSION_PACKBITS;
662 	} else if ((flags & TIFF_DEFLATE) == TIFF_DEFLATE) {
663 		compression = COMPRESSION_DEFLATE;
664 	} else if ((flags & TIFF_ADOBE_DEFLATE) == TIFF_ADOBE_DEFLATE) {
665 		compression = COMPRESSION_ADOBE_DEFLATE;
666 	} else if ((flags & TIFF_NONE) == TIFF_NONE) {
667 		compression = COMPRESSION_NONE;
668 	} else if ((bitsperpixel == 1) && ((flags & TIFF_CCITTFAX3) == TIFF_CCITTFAX3)) {
669 		compression = COMPRESSION_CCITTFAX3;
670 	} else if ((bitsperpixel == 1) && ((flags & TIFF_CCITTFAX4) == TIFF_CCITTFAX4)) {
671 		compression = COMPRESSION_CCITTFAX4;
672 	} else if ((flags & TIFF_LZW) == TIFF_LZW) {
673 		compression = COMPRESSION_LZW;
674 	} else if ((flags & TIFF_JPEG) == TIFF_JPEG) {
675 		if(((bitsperpixel == 8) && (photometric != PHOTOMETRIC_PALETTE)) || (bitsperpixel == 24)) {
676 			compression = COMPRESSION_JPEG;
677 			// RowsPerStrip must be multiple of 8 for JPEG
678 			uint32 rowsperstrip = (uint32) -1;
679 			rowsperstrip = TIFFDefaultStripSize(tiff, rowsperstrip);
680             rowsperstrip = rowsperstrip + (8 - (rowsperstrip % 8));
681 			// overwrite previous RowsPerStrip
682 			TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
683 		} else {
684 			// default to LZW
685 			compression = COMPRESSION_LZW;
686 		}
687 	}
688 	else {
689 		// default compression scheme
690 
691 		switch(bitsperpixel) {
692 			case 1:
693 				compression = COMPRESSION_CCITTFAX4;
694 				break;
695 
696 			case 4:
697 			case 8:
698 			case 16:
699 			case 24:
700 			case 32:
701 				compression = COMPRESSION_LZW;
702 				break;
703 			case 48:
704 			case 64:
705 			case 96:
706 			case 128:
707 				compression = COMPRESSION_LZW;
708 				break;
709 
710 			default :
711 				compression = COMPRESSION_NONE;
712 				break;
713 		}
714 	}
715 
716 	TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression);
717 
718 	if(compression == COMPRESSION_LZW) {
719 		// This option is only meaningful with LZW compression: a predictor value of 2
720 		// causes each scanline of the output image to undergo horizontal differencing
721 		// before it is encoded; a value of 1 forces each scanline to be encoded without differencing.
722 
723 		// Found on LibTIFF mailing list :
724 		// LZW without differencing works well for 1-bit images, 4-bit grayscale images,
725 		// and many palette-color images. But natural 24-bit color images and some 8-bit
726 		// grayscale images do much better with differencing.
727 
728 		if((bitspersample == 8) || (bitspersample == 16)) {
729 			if ((bitsperpixel >= 8) && (photometric != PHOTOMETRIC_PALETTE)) {
730 				TIFFSetField(tiff, TIFFTAG_PREDICTOR, 2);
731 			} else {
732 				TIFFSetField(tiff, TIFFTAG_PREDICTOR, 1);
733 			}
734 		} else {
735 			TIFFSetField(tiff, TIFFTAG_PREDICTOR, 1);
736 		}
737 	}
738 	else if((compression == COMPRESSION_CCITTFAX3) || (compression == COMPRESSION_CCITTFAX4)) {
739 		uint32 imageLength = 0;
740 		TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imageLength);
741 		// overwrite previous RowsPerStrip
742 		TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, imageLength);
743 
744 		if(compression == COMPRESSION_CCITTFAX3) {
745 			// try to be compliant with the TIFF Class F specification
746 			// that documents the TIFF tags specific to FAX applications
747 			// see http://palimpsest.stanford.edu/bytopic/imaging/std/tiff-f.html
748 			uint32 group3options = GROUP3OPT_2DENCODING | GROUP3OPT_FILLBITS;
749 			TIFFSetField(tiff, TIFFTAG_GROUP3OPTIONS, group3options);	// 2d-encoded, has aligned EOL
750 			TIFFSetField(tiff, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);	// lsb-to-msb fillorder
751 		}
752 	}
753 }
754 
755 // ==========================================================
756 // TIFF metadata routines
757 // ==========================================================
758 
759 /**
760 	Read the TIFFTAG_RICHTIFFIPTC tag (IPTC/NAA or Adobe Photoshop profile)
761 */
762 static BOOL
tiff_read_iptc_profile(TIFF * tiff,FIBITMAP * dib)763 tiff_read_iptc_profile(TIFF *tiff, FIBITMAP *dib) {
764 	BYTE *profile = NULL;
765 	uint32 profile_size = 0;
766 
767     if(TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC, &profile_size, &profile) == 1) {
768 		if (TIFFIsByteSwapped(tiff) != 0) {
769 			TIFFSwabArrayOfLong((uint32 *) profile, (unsigned long)profile_size);
770 		}
771 
772 		return read_iptc_profile(dib, profile, 4 * profile_size);
773 	}
774 
775 	return FALSE;
776 }
777 
778 /**
779 	Read the TIFFTAG_XMLPACKET tag (XMP profile)
780 	@param dib Input FIBITMAP
781 	@param tiff LibTIFF TIFF handle
782 	@return Returns TRUE if successful, FALSE otherwise
783 */
784 static BOOL
tiff_read_xmp_profile(TIFF * tiff,FIBITMAP * dib)785 tiff_read_xmp_profile(TIFF *tiff, FIBITMAP *dib) {
786 	BYTE *profile = NULL;
787 	uint32 profile_size = 0;
788 
789 	if (TIFFGetField(tiff, TIFFTAG_XMLPACKET, &profile_size, &profile) == 1) {
790 		// create a tag
791 		FITAG *tag = FreeImage_CreateTag();
792 		if(!tag) return FALSE;
793 
794 		FreeImage_SetTagID(tag, TIFFTAG_XMLPACKET);	// 700
795 		FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
796 		FreeImage_SetTagLength(tag, profile_size);
797 		FreeImage_SetTagCount(tag, profile_size);
798 		FreeImage_SetTagType(tag, FIDT_ASCII);
799 		FreeImage_SetTagValue(tag, profile);
800 
801 		// store the tag
802 		FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
803 
804 		// destroy the tag
805 		FreeImage_DeleteTag(tag);
806 
807 		return TRUE;
808 	}
809 
810 	return FALSE;
811 }
812 
813 /**
814 	Read the Exif profile embedded in a TIFF
815 	@param dib Input FIBITMAP
816 	@param tiff LibTIFF TIFF handle
817 	@return Returns TRUE if successful, FALSE otherwise
818 */
819 static BOOL
tiff_read_exif_profile(FreeImageIO * io,fi_handle handle,TIFF * tiff,FIBITMAP * dib)820 tiff_read_exif_profile(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib) {
821 	BOOL bResult = FALSE;
822 	toff_t exif_offset = 0;
823 
824 	// read EXIF-TIFF tags
825 	bResult = tiff_read_exif_tags(tiff, TagLib::EXIF_MAIN, dib);
826 
827 	// get the IFD offset
828 	if(TIFFGetField(tiff, TIFFTAG_EXIFIFD, &exif_offset)) {
829 
830 		const long tell_pos = io->tell_proc(handle);
831 		const uint16 cur_dir = TIFFCurrentDirectory(tiff);
832 
833 		// read EXIF tags
834 		if (TIFFReadEXIFDirectory(tiff, exif_offset)) {
835 			// read all known exif tags
836 			bResult = tiff_read_exif_tags(tiff, TagLib::EXIF_EXIF, dib);
837 		}
838 
839 		io->seek_proc(handle, tell_pos, SEEK_SET);
840 		TIFFSetDirectory(tiff, cur_dir);
841 	}
842 
843 	return bResult;
844 }
845 
846 /**
847 Read TIFF special profiles
848 */
849 static void
ReadMetadata(FreeImageIO * io,fi_handle handle,TIFF * tiff,FIBITMAP * dib)850 ReadMetadata(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib) {
851 
852 	// IPTC/NAA
853 	tiff_read_iptc_profile(tiff, dib);
854 
855 	// Adobe XMP
856 	tiff_read_xmp_profile(tiff, dib);
857 
858 	// GeoTIFF
859 	tiff_read_geotiff_profile(tiff, dib);
860 
861 	// Exif-TIFF
862 	tiff_read_exif_profile(io, handle, tiff, dib);
863 }
864 
865 // ----------------------------------------------------------
866 
867 /**
868 	Write the TIFFTAG_RICHTIFFIPTC tag (IPTC/NAA or Adobe Photoshop profile)
869 */
870 static BOOL
tiff_write_iptc_profile(TIFF * tiff,FIBITMAP * dib)871 tiff_write_iptc_profile(TIFF *tiff, FIBITMAP *dib) {
872 	if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
873 		BYTE *profile = NULL;
874 		uint32 profile_size = 0;
875 		// create a binary profile
876 		if(write_iptc_profile(dib, &profile, &profile_size)) {
877 			uint32 iptc_size = profile_size;
878 			iptc_size += (4-(iptc_size & 0x03)); // Round up for long word alignment
879 			BYTE *iptc_profile = (BYTE*)malloc(iptc_size);
880 			if(!iptc_profile) {
881 				free(profile);
882 				return FALSE;
883 			}
884 			memset(iptc_profile, 0, iptc_size);
885 			memcpy(iptc_profile, profile, profile_size);
886 			if (TIFFIsByteSwapped(tiff)) {
887 				TIFFSwabArrayOfLong((uint32 *) iptc_profile, (unsigned long)iptc_size/4);
888 			}
889 			// Tag is type TIFF_LONG so byte length is divided by four
890 			TIFFSetField(tiff, TIFFTAG_RICHTIFFIPTC, iptc_size/4, iptc_profile);
891 			// release the profile data
892 			free(iptc_profile);
893 			free(profile);
894 
895 			return TRUE;
896 		}
897 	}
898 
899 	return FALSE;
900 }
901 
902 /**
903 	Write the TIFFTAG_XMLPACKET tag (XMP profile)
904 	@param dib Input FIBITMAP
905 	@param tiff LibTIFF TIFF handle
906 	@return Returns TRUE if successful, FALSE otherwise
907 */
908 static BOOL
tiff_write_xmp_profile(TIFF * tiff,FIBITMAP * dib)909 tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib) {
910 	FITAG *tag_xmp = NULL;
911 	FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp);
912 
913 	if(tag_xmp && (NULL != FreeImage_GetTagValue(tag_xmp))) {
914 
915 		TIFFSetField(tiff, TIFFTAG_XMLPACKET, (uint32)FreeImage_GetTagLength(tag_xmp), (BYTE*)FreeImage_GetTagValue(tag_xmp));
916 
917 		return TRUE;
918 	}
919 
920 	return FALSE;
921 }
922 
923 /**
924 	Write the Exif profile to TIFF
925 	@param dib Input FIBITMAP
926 	@param tiff LibTIFF TIFF handle
927 	@return Returns TRUE if successful, FALSE otherwise
928 */
929 static BOOL
tiff_write_exif_profile(TIFF * tiff,FIBITMAP * dib)930 tiff_write_exif_profile(TIFF *tiff, FIBITMAP *dib) {
931 	BOOL bResult = FALSE;
932 
933 	// write EXIF_MAIN tags, EXIF_EXIF not supported yet
934 	bResult = tiff_write_exif_tags(tiff, TagLib::EXIF_MAIN, dib);
935 
936 	return bResult;
937 }
938 
939 /**
940 Write TIFF special profiles
941 */
942 static void
WriteMetadata(TIFF * tiff,FIBITMAP * dib)943 WriteMetadata(TIFF *tiff, FIBITMAP *dib) {
944 	// IPTC
945 	tiff_write_iptc_profile(tiff, dib);
946 
947 	// Adobe XMP
948 	tiff_write_xmp_profile(tiff, dib);
949 
950 	// EXIF_MAIN tags
951 	tiff_write_exif_profile(tiff, dib);
952 
953 	// GeoTIFF tags
954 	tiff_write_geotiff_profile(tiff, dib);
955 }
956 
957 // ==========================================================
958 // Plugin Implementation
959 // ==========================================================
960 
961 static const char * DLL_CALLCONV
Format()962 Format() {
963 	return "TIFF";
964 }
965 
966 static const char * DLL_CALLCONV
Description()967 Description() {
968 	return "Tagged Image File Format";
969 }
970 
971 static const char * DLL_CALLCONV
Extension()972 Extension() {
973 	return "tif,tiff";
974 }
975 
976 static const char * DLL_CALLCONV
RegExpr()977 RegExpr() {
978 	return "^[MI][MI][\\x01*][\\x01*]";
979 }
980 
981 static const char * DLL_CALLCONV
MimeType()982 MimeType() {
983 	return "image/tiff";
984 }
985 
986 static BOOL DLL_CALLCONV
Validate(FreeImageIO * io,fi_handle handle)987 Validate(FreeImageIO *io, fi_handle handle) {
988 	BYTE tiff_id1[] = { 0x49, 0x49, 0x2A, 0x00 };	// Classic TIFF, little-endian
989 	BYTE tiff_id2[] = { 0x4D, 0x4D, 0x00, 0x2A };	// Classic TIFF, big-endian
990 	BYTE tiff_id3[] = { 0x49, 0x49, 0x2B, 0x00 };	// Big TIFF, little-endian
991 	BYTE tiff_id4[] = { 0x4D, 0x4D, 0x00, 0x2B };	// Big TIFF, big-endian
992 	BYTE signature[4] = { 0, 0, 0, 0 };
993 
994 	io->read_proc(signature, 1, 4, handle);
995 
996 	if(memcmp(tiff_id1, signature, 4) == 0)
997 		return TRUE;
998 	if(memcmp(tiff_id2, signature, 4) == 0)
999 		return TRUE;
1000 	if(memcmp(tiff_id3, signature, 4) == 0)
1001 		return TRUE;
1002 	if(memcmp(tiff_id4, signature, 4) == 0)
1003 		return TRUE;
1004 
1005 	return FALSE;
1006 }
1007 
1008 static BOOL DLL_CALLCONV
SupportsExportDepth(int depth)1009 SupportsExportDepth(int depth) {
1010 	return (
1011 			(depth == 1)  ||
1012 			(depth == 4)  ||
1013 			(depth == 8)  ||
1014 			(depth == 24) ||
1015 			(depth == 32)
1016 		);
1017 }
1018 
1019 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)1020 SupportsExportType(FREE_IMAGE_TYPE type) {
1021 	return (
1022 		(type == FIT_BITMAP)  ||
1023 		(type == FIT_UINT16)  ||
1024 		(type == FIT_INT16)   ||
1025 		(type == FIT_UINT32)  ||
1026 		(type == FIT_INT32)   ||
1027 		(type == FIT_FLOAT)   ||
1028 		(type == FIT_DOUBLE)  ||
1029 		(type == FIT_COMPLEX) ||
1030 		(type == FIT_RGB16)   ||
1031 		(type == FIT_RGBA16)  ||
1032 		(type == FIT_RGBF)    ||
1033 		(type == FIT_RGBAF)
1034 	);
1035 }
1036 
1037 static BOOL DLL_CALLCONV
SupportsICCProfiles()1038 SupportsICCProfiles() {
1039 	return TRUE;
1040 }
1041 
1042 static BOOL DLL_CALLCONV
SupportsNoPixels()1043 SupportsNoPixels() {
1044 	return TRUE;
1045 }
1046 
1047 // ----------------------------------------------------------
1048 
1049 static void * DLL_CALLCONV
Open(FreeImageIO * io,fi_handle handle,BOOL read)1050 Open(FreeImageIO *io, fi_handle handle, BOOL read) {
1051 	// wrapper for TIFF I/O
1052 	fi_TIFFIO *fio = (fi_TIFFIO*)malloc(sizeof(fi_TIFFIO));
1053 	if(!fio) return NULL;
1054 	fio->io = io;
1055 	fio->handle = handle;
1056 
1057 	if (read) {
1058 		fio->tif = TIFFFdOpen((thandle_t)fio, "", "r");
1059 	} else {
1060 		// mode = "w"	: write Classic TIFF
1061 		// mode = "w8"	: write Big TIFF
1062 		fio->tif = TIFFFdOpen((thandle_t)fio, "", "w");
1063 	}
1064 	if(fio->tif == NULL) {
1065 		free(fio);
1066 		FreeImage_OutputMessageProc(s_format_id, "Error while opening TIFF: data is invalid");
1067 		return NULL;
1068 	}
1069 	return fio;
1070 }
1071 
1072 static void DLL_CALLCONV
Close(FreeImageIO * io,fi_handle handle,void * data)1073 Close(FreeImageIO *io, fi_handle handle, void *data) {
1074 	if(data) {
1075 		fi_TIFFIO *fio = (fi_TIFFIO*)data;
1076 		TIFFClose(fio->tif);
1077 		free(fio);
1078 	}
1079 }
1080 
1081 // ----------------------------------------------------------
1082 
1083 static int DLL_CALLCONV
PageCount(FreeImageIO * io,fi_handle handle,void * data)1084 PageCount(FreeImageIO *io, fi_handle handle, void *data) {
1085 	if(data) {
1086 		fi_TIFFIO *fio = (fi_TIFFIO*)data;
1087 		TIFF *tif = (TIFF *)fio->tif;
1088 		int nr_ifd = 0;
1089 
1090 		do {
1091 			nr_ifd++;
1092 		} while (TIFFReadDirectory(tif));
1093 
1094 		return nr_ifd;
1095 	}
1096 
1097 	return 0;
1098 }
1099 
1100 // ----------------------------------------------------------
1101 
1102 /**
1103 check for uncommon bitspersample values (e.g. 10, 12, ...)
1104 @param photometric TIFFTAG_PHOTOMETRIC tiff tag
1105 @param bitspersample TIFFTAG_BITSPERSAMPLE tiff tag
1106 @param samplesperpixel TIFFTAG_SAMPLESPERPIXEL tiff tag
1107 @return Returns FALSE if a uncommon bit-depth is encountered, returns TRUE otherwise
1108 */
1109 static BOOL
IsValidBitsPerSample(uint16 photometric,uint16 bitspersample,uint16 samplesperpixel)1110 IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesperpixel) {
1111 
1112 	switch(bitspersample) {
1113 		case 1:
1114 		case 4:
1115 			if((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_PALETTE)) {
1116 				return TRUE;
1117 			} else {
1118 				return FALSE;
1119 			}
1120 			break;
1121 		case 8:
1122 			return TRUE;
1123 		case 16:
1124 			if(photometric != PHOTOMETRIC_PALETTE) {
1125 				return TRUE;
1126 			} else {
1127 				return FALSE;
1128 			}
1129 			break;
1130 		case 32:
1131 			if((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_LOGLUV)) {
1132 				return TRUE;
1133 			} else if((photometric == PHOTOMETRIC_RGB) && (samplesperpixel == 3) || (samplesperpixel == 4)) {
1134 				// RGB[A]F
1135 				return TRUE;
1136 			} else {
1137 				return FALSE;
1138 			}
1139 			break;
1140 		case 64:
1141 		case 128:
1142 			if(photometric == PHOTOMETRIC_MINISBLACK) {
1143 				return TRUE;
1144 			} else {
1145 				return FALSE;
1146 			}
1147 			break;
1148 		default:
1149 			return FALSE;
1150 	}
1151 }
1152 
1153 static TIFFLoadMethod
FindLoadMethod(TIFF * tif,FREE_IMAGE_TYPE image_type,int flags)1154 FindLoadMethod(TIFF *tif, FREE_IMAGE_TYPE image_type, int flags) {
1155 	uint16 bitspersample	= (uint16)-1;
1156 	uint16 samplesperpixel	= (uint16)-1;
1157 	uint16 photometric		= (uint16)-1;
1158 	uint16 planar_config	= (uint16)-1;
1159 
1160 	TIFFLoadMethod loadMethod = LoadAsGenericStrip;
1161 
1162 	TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
1163 	TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
1164 	TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
1165 	TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar_config);
1166 
1167 	BOOL bIsTiled = (TIFFIsTiled(tif) == 0) ? FALSE:TRUE;
1168 
1169 	switch(photometric) {
1170 		// convert to 24 or 32 bits RGB if the image is full color
1171 		case PHOTOMETRIC_RGB:
1172 			if((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
1173 				// load 48-bit RGB and 64-bit RGBA without conversion
1174 				loadMethod = LoadAsGenericStrip;
1175 			}
1176 			else if(image_type == FIT_RGBF) {
1177 				if((samplesperpixel == 3) && (bitspersample == 16)) {
1178 					// load 3 x 16-bit half as RGBF
1179 					loadMethod = LoadAsHalfFloat;
1180 				}
1181 			}
1182 			break;
1183 		case PHOTOMETRIC_YCBCR:
1184 		case PHOTOMETRIC_CIELAB:
1185 		case PHOTOMETRIC_ICCLAB:
1186 		case PHOTOMETRIC_ITULAB:
1187 			loadMethod = LoadAsRBGA;
1188 			break;
1189 		case PHOTOMETRIC_LOGLUV:
1190 			loadMethod = LoadAsLogLuv;
1191 			break;
1192 		case PHOTOMETRIC_SEPARATED:
1193 			// if image is PHOTOMETRIC_SEPARATED _and_ comes with an ICC profile,
1194 			// then the image should preserve its original (CMYK) colour model and
1195 			// should be read as CMYK (to keep the match of pixel and profile and
1196 			// to avoid multiple conversions. Conversion can be done by changing
1197 			// the profile from it's original CMYK to an RGB profile with an
1198 			// apropriate color management system. Works with non-tiled TIFFs.
1199 			if(!bIsTiled) {
1200 				loadMethod = LoadAsCMYK;
1201 			}
1202 			break;
1203 		case PHOTOMETRIC_MINISWHITE:
1204 		case PHOTOMETRIC_MINISBLACK:
1205 		case PHOTOMETRIC_PALETTE:
1206 			// When samplesperpixel = 2 and bitspersample = 8, set the image as a
1207 			// 8-bit indexed image + 8-bit alpha layer image
1208 			// and convert to a 8-bit image with a transparency table
1209 			if((samplesperpixel > 1) && (bitspersample == 8)) {
1210 				loadMethod = LoadAs8BitTrns;
1211 			} else {
1212 				loadMethod = LoadAsGenericStrip;
1213 			}
1214 			break;
1215 		default:
1216 			loadMethod = LoadAsGenericStrip;
1217 			break;
1218 	}
1219 
1220 	if((loadMethod == LoadAsGenericStrip) && bIsTiled) {
1221 		loadMethod = LoadAsTiled;
1222 	}
1223 
1224 	return loadMethod;
1225 }
1226 
1227 // ==========================================================
1228 // TIFF thumbnail routines
1229 // ==========================================================
1230 
1231 static FIBITMAP * DLL_CALLCONV
1232 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data);
1233 
1234 /**
1235 Read embedded thumbnail
1236 */
1237 static void
ReadThumbnail(FreeImageIO * io,fi_handle handle,void * data,TIFF * tiff,FIBITMAP * dib)1238 ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMAP *dib) {
1239 	FIBITMAP* thumbnail = NULL;
1240 
1241 	// read exif thumbnail (IFD 1) ...
1242 
1243 	/*
1244 	// this code can cause unwanted recursion causing an overflow, it is thus disabled until we have a better solution
1245 	// do we really need to read a thumbnail from the Exif segment ? knowing that TIFF store the thumbnail in the subIFD ...
1246 	//
1247 	toff_t exif_offset = 0;
1248 	if(TIFFGetField(tiff, TIFFTAG_EXIFIFD, &exif_offset)) {
1249 
1250 		if(!TIFFLastDirectory(tiff)) {
1251 			// save current position
1252 			const long tell_pos = io->tell_proc(handle);
1253 			const uint16 cur_dir = TIFFCurrentDirectory(tiff);
1254 
1255 			// load the thumbnail
1256 			int page = 1;
1257 			int flags = TIFF_DEFAULT;
1258 			thumbnail = Load(io, handle, page, flags, data);
1259 			// store the thumbnail (remember to release it before return)
1260 			FreeImage_SetThumbnail(dib, thumbnail);
1261 
1262 			// restore current position
1263 			io->seek_proc(handle, tell_pos, SEEK_SET);
1264 			TIFFSetDirectory(tiff, cur_dir);
1265 		}
1266 	}
1267 	*/
1268 
1269 	// ... or read the first subIFD
1270 
1271 	if(!thumbnail) {
1272 		uint16 subIFD_count = 0;
1273 		toff_t* subIFD_offsets = NULL;
1274 
1275 		// This will also read the first (and only) subIFD from a Photoshop-created "pyramid" file.
1276 		// Subsequent, smaller images are 'nextIFD' in that subIFD. Currently we only load the first one.
1277 
1278 		if(TIFFGetField(tiff, TIFFTAG_SUBIFD, &subIFD_count, &subIFD_offsets)) {
1279 			if(subIFD_count > 0) {
1280 				// save current position
1281 				const long tell_pos = io->tell_proc(handle);
1282 				const uint16 cur_dir = TIFFCurrentDirectory(tiff);
1283 
1284 				if(TIFFSetSubDirectory(tiff, subIFD_offsets[0])) {
1285 					// load the thumbnail
1286 					int page = -1;
1287 					int flags = TIFF_DEFAULT;
1288 					thumbnail = Load(io, handle, page, flags, data);
1289 					// store the thumbnail (remember to release it before return)
1290 					FreeImage_SetThumbnail(dib, thumbnail);
1291 				}
1292 
1293 				// restore current position
1294 				io->seek_proc(handle, tell_pos, SEEK_SET);
1295 				TIFFSetDirectory(tiff, cur_dir);
1296 			}
1297 		}
1298 	}
1299 
1300 	// ... or read Photoshop thumbnail
1301 
1302 	if(!thumbnail) {
1303 		uint32 ps_size = 0;
1304 		void *ps_data = NULL;
1305 
1306 		if(TIFFGetField(tiff, TIFFTAG_PHOTOSHOP, &ps_size, &ps_data)) {
1307 			FIMEMORY *handle = FreeImage_OpenMemory((BYTE*)ps_data, ps_size);
1308 
1309 			FreeImageIO io;
1310 			SetMemoryIO(&io);
1311 
1312 			psdParser parser;
1313 			parser.ReadImageResources(&io, handle, ps_size);
1314 
1315 			FreeImage_SetThumbnail(dib, parser.GetThumbnail());
1316 
1317 			FreeImage_CloseMemory(handle);
1318 		}
1319 	}
1320 
1321 	// release thumbnail
1322 	FreeImage_Unload(thumbnail);
1323 }
1324 
1325 // --------------------------------------------------------------------------
1326 
1327 static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)1328 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
1329 	if (!handle || !data ) {
1330 		return NULL;
1331 	}
1332 
1333 	TIFF   *tif = NULL;
1334 	uint32 height = 0;
1335 	uint32 width = 0;
1336 	uint16 bitspersample = 1;
1337 	uint16 samplesperpixel = 1;
1338 	uint32 rowsperstrip = (uint32)-1;
1339 	uint16 photometric = PHOTOMETRIC_MINISWHITE;
1340 	uint16 compression = (uint16)-1;
1341 	uint16 planar_config;
1342 
1343 	FIBITMAP *dib = NULL;
1344 	uint32 iccSize = 0;		// ICC profile length
1345 	void *iccBuf = NULL;	// ICC profile data
1346 
1347 	const BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
1348 
1349 	try {
1350 		fi_TIFFIO *fio = (fi_TIFFIO*)data;
1351 		tif = fio->tif;
1352 
1353 		if (page != -1) {
1354 			if (!tif || !TIFFSetDirectory(tif, (uint16)page)) {
1355 				throw "Error encountered while opening TIFF file";
1356 			}
1357 		}
1358 
1359 		const BOOL asCMYK = (flags & TIFF_CMYK) == TIFF_CMYK;
1360 
1361 		// first, get the photometric, the compression and basic metadata
1362 		// ---------------------------------------------------------------------------------
1363 
1364 		TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
1365 		TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
1366 
1367 		// check for HDR formats
1368 		// ---------------------------------------------------------------------------------
1369 
1370 		if(photometric == PHOTOMETRIC_LOGLUV) {
1371 			// check the compression
1372 			if(compression != COMPRESSION_SGILOG && compression != COMPRESSION_SGILOG24) {
1373 				throw "Only support SGILOG compressed LogLuv data";
1374 			}
1375 			// set decoder to output in IEEE 32-bit float XYZ values
1376 			TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
1377 		}
1378 
1379 		// ---------------------------------------------------------------------------------
1380 
1381 		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
1382 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
1383 		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
1384 		TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
1385 		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1386 		TIFFGetField(tif, TIFFTAG_ICCPROFILE, &iccSize, &iccBuf);
1387 		TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar_config);
1388 
1389 		// check for unsupported formats
1390 		// ---------------------------------------------------------------------------------
1391 
1392 		if(IsValidBitsPerSample(photometric, bitspersample, samplesperpixel) == FALSE) {
1393 			FreeImage_OutputMessageProc(s_format_id,
1394 				"Unable to handle this format: bitspersample = %d, samplesperpixel = %d, photometric = %d",
1395 				(int)bitspersample, (int)samplesperpixel, (int)photometric);
1396 			throw (char*)NULL;
1397 		}
1398 
1399 		// ---------------------------------------------------------------------------------
1400 
1401 		// get image data type
1402 
1403 		FREE_IMAGE_TYPE image_type = ReadImageType(tif, bitspersample, samplesperpixel);
1404 
1405 		// get the most appropriate loading method
1406 
1407 		TIFFLoadMethod loadMethod = FindLoadMethod(tif, image_type, flags);
1408 
1409 		// ---------------------------------------------------------------------------------
1410 
1411 		if(loadMethod == LoadAsRBGA) {
1412 			// ---------------------------------------------------------------------------------
1413 			// RGB[A] loading using the TIFFReadRGBAImage() API
1414 			// ---------------------------------------------------------------------------------
1415 
1416 			BOOL has_alpha = FALSE;
1417 
1418 			// Read the whole image into one big RGBA buffer and then
1419 			// convert it to a DIB. This is using the traditional
1420 			// TIFFReadRGBAImage() API that we trust.
1421 
1422 			uint32 *raster = NULL;
1423 
1424 			if(!header_only) {
1425 
1426 				raster = (uint32*)_TIFFmalloc(width * height * sizeof(uint32));
1427 				if (raster == NULL) {
1428 					throw FI_MSG_ERROR_MEMORY;
1429 				}
1430 
1431 				// read the image in one chunk into an RGBA array
1432 
1433 				if (!TIFFReadRGBAImage(tif, width, height, raster, 1)) {
1434 					_TIFFfree(raster);
1435 					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
1436 				}
1437 			}
1438 			// TIFFReadRGBAImage always deliveres 3 or 4 samples per pixel images
1439 			// (RGB or RGBA, see below). Cut-off possibly present channels (additional
1440 			// alpha channels) from e.g. Photoshop. Any CMYK(A..) is now treated as RGB,
1441 			// any additional alpha channel on RGB(AA..) is lost on conversion to RGB(A)
1442 
1443 			if(samplesperpixel > 4) { // TODO Write to Extra Channels
1444 				FreeImage_OutputMessageProc(s_format_id, "Warning: %d additional alpha channel(s) ignored", samplesperpixel-4);
1445 				samplesperpixel = 4;
1446 			}
1447 
1448 			// create a new DIB (take care of different samples-per-pixel in case
1449 			// of converted CMYK image (RGB conversion is on sample per pixel less)
1450 
1451 			if (photometric == PHOTOMETRIC_SEPARATED && samplesperpixel == 4) {
1452 				samplesperpixel = 3;
1453 			}
1454 
1455 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, samplesperpixel);
1456 			if (dib == NULL) {
1457 				// free the raster pointer and output an error if allocation failed
1458 				if(raster) {
1459 					_TIFFfree(raster);
1460 				}
1461 				throw FI_MSG_ERROR_DIB_MEMORY;
1462 			}
1463 
1464 			// fill in the resolution (english or universal)
1465 
1466 			ReadResolution(tif, dib);
1467 
1468 			if(!header_only) {
1469 
1470 				// read the raster lines and save them in the DIB
1471 				// with RGB mode, we have to change the order of the 3 samples RGB
1472 				// We use macros for extracting components from the packed ABGR
1473 				// form returned by TIFFReadRGBAImage.
1474 
1475 				uint32 *row = &raster[0];
1476 
1477 				if (samplesperpixel == 4) {
1478 					// 32-bit RGBA
1479 					for (uint32 y = 0; y < height; y++) {
1480 						BYTE *bits = FreeImage_GetScanLine(dib, y);
1481 						for (uint32 x = 0; x < width; x++) {
1482 							bits[FI_RGBA_BLUE]	= (BYTE)TIFFGetB(row[x]);
1483 							bits[FI_RGBA_GREEN] = (BYTE)TIFFGetG(row[x]);
1484 							bits[FI_RGBA_RED]	= (BYTE)TIFFGetR(row[x]);
1485 							bits[FI_RGBA_ALPHA] = (BYTE)TIFFGetA(row[x]);
1486 
1487 							if (bits[FI_RGBA_ALPHA] != 0) {
1488 								has_alpha = TRUE;
1489 							}
1490 
1491 							bits += 4;
1492 						}
1493 						row += width;
1494 					}
1495 				} else {
1496 					// 24-bit RGB
1497 					for (uint32 y = 0; y < height; y++) {
1498 						BYTE *bits = FreeImage_GetScanLine(dib, y);
1499 						for (uint32 x = 0; x < width; x++) {
1500 							bits[FI_RGBA_BLUE]	= (BYTE)TIFFGetB(row[x]);
1501 							bits[FI_RGBA_GREEN] = (BYTE)TIFFGetG(row[x]);
1502 							bits[FI_RGBA_RED]	= (BYTE)TIFFGetR(row[x]);
1503 
1504 							bits += 3;
1505 						}
1506 						row += width;
1507 					}
1508 				}
1509 
1510 				_TIFFfree(raster);
1511 			}
1512 
1513 			// ### Not correct when header only
1514 			FreeImage_SetTransparent(dib, has_alpha);
1515 
1516 		} else if(loadMethod == LoadAs8BitTrns) {
1517 			// ---------------------------------------------------------------------------------
1518 			// 8-bit + 8-bit alpha layer loading
1519 			// ---------------------------------------------------------------------------------
1520 
1521 			// create a new 8-bit DIB
1522 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, MIN<uint16>(2, samplesperpixel));
1523 			if (dib == NULL) {
1524 				throw FI_MSG_ERROR_MEMORY;
1525 			}
1526 
1527 			// fill in the resolution (english or universal)
1528 
1529 			ReadResolution(tif, dib);
1530 
1531 			// set up the colormap based on photometric
1532 
1533 			ReadPalette(tif, photometric, bitspersample, dib);
1534 
1535 			// calculate the line + pitch (separate for scr & dest)
1536 
1537 			const tmsize_t src_line = TIFFScanlineSize(tif);
1538 			// here, the pitch is 2x less than the original as we only keep the first layer
1539 			int dst_pitch = FreeImage_GetPitch(dib);
1540 
1541 			// transparency table for 8-bit + 8-bit alpha images
1542 
1543 			BYTE trns[256];
1544 			// clear the transparency table
1545 			memset(trns, 0xFF, 256 * sizeof(BYTE));
1546 
1547 			// In the tiff file the lines are saved from up to down
1548 			// In a DIB the lines must be saved from down to up
1549 
1550 			BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
1551 
1552 			// read the tiff lines and save them in the DIB
1553 
1554 			if(planar_config == PLANARCONFIG_CONTIG && !header_only) {
1555 
1556 				BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
1557 				if(buf == NULL) {
1558 					throw FI_MSG_ERROR_MEMORY;
1559 				}
1560 
1561 				for (uint32 y = 0; y < height; y += rowsperstrip) {
1562 					int32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
1563 
1564 					if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, nrow * src_line) == -1) {
1565 						free(buf);
1566 						throw FI_MSG_ERROR_PARSING;
1567 					}
1568 					for (int l = 0; l < nrow; l++) {
1569 						BYTE *p = bits;
1570 						BYTE *b = buf + l * src_line;
1571 
1572 						for(uint32 x = 0; x < (uint32)(src_line / samplesperpixel); x++) {
1573 							// copy the 8-bit layer
1574 							*p = b[0];
1575 							// convert the 8-bit alpha layer to a trns table
1576 							trns[ b[0] ] = b[1];
1577 
1578 							p++;
1579 							b += samplesperpixel;
1580 						}
1581 						bits -= dst_pitch;
1582 					}
1583 				}
1584 
1585 				free(buf);
1586 			}
1587 			else if(planar_config == PLANARCONFIG_SEPARATE && !header_only) {
1588 				tmsize_t stripsize = TIFFStripSize(tif) * sizeof(BYTE);
1589 				BYTE *buf = (BYTE*)malloc(2 * stripsize);
1590 				if(buf == NULL) {
1591 					throw FI_MSG_ERROR_MEMORY;
1592 				}
1593 				BYTE *grey = buf;
1594 				BYTE *alpha = buf + stripsize;
1595 
1596 				for (uint32 y = 0; y < height; y += rowsperstrip) {
1597 					int32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
1598 
1599 					if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), grey, nrow * src_line) == -1) {
1600 						free(buf);
1601 						throw FI_MSG_ERROR_PARSING;
1602 					}
1603 					if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 1), alpha, nrow * src_line) == -1) {
1604 						free(buf);
1605 						throw FI_MSG_ERROR_PARSING;
1606 					}
1607 
1608 					for (int l = 0; l < nrow; l++) {
1609 						BYTE *p = bits;
1610 						BYTE *g = grey + l * src_line;
1611 						BYTE *a = alpha + l * src_line;
1612 
1613 						for(uint32 x = 0; x < (uint32)(src_line); x++) {
1614 							// copy the 8-bit layer
1615 							*p = g[0];
1616 							// convert the 8-bit alpha layer to a trns table
1617 							trns[ g[0] ] = a[0];
1618 
1619 							p++;
1620 							g++;
1621 							a++;
1622 						}
1623 						bits -= dst_pitch;
1624 					}
1625 				}
1626 
1627 				free(buf);
1628 
1629 			}
1630 
1631 			FreeImage_SetTransparencyTable(dib, &trns[0], 256);
1632 			FreeImage_SetTransparent(dib, TRUE);
1633 
1634 		} else if(loadMethod == LoadAsCMYK) {
1635 			// ---------------------------------------------------------------------------------
1636 			// CMYK loading
1637 			// ---------------------------------------------------------------------------------
1638 
1639 			// At this place, samplesperpixel could be > 4, esp. when a CMYK(A) format
1640 			// is recognized. Where all other formats are handled straight-forward, this
1641 			// format has to be handled special
1642 
1643 			BOOL isCMYKA = (photometric == PHOTOMETRIC_SEPARATED) && (samplesperpixel > 4);
1644 
1645 			// We use a temp dib to store the alpha for the CMYKA to RGBA conversion
1646 			// NOTE this is until we have Extra channels implementation.
1647 			// Also then it will be possible to merge LoadAsCMYK with LoadAsGenericStrip
1648 
1649 			FIBITMAP *alpha = NULL;
1650 			unsigned alpha_pitch = 0;
1651 			BYTE *alpha_bits = NULL;
1652 			unsigned alpha_Bpp = 0;
1653 
1654 			if(isCMYKA && !asCMYK && !header_only) {
1655 				if(bitspersample == 16) {
1656 					alpha = FreeImage_AllocateT(FIT_UINT16, width, height);
1657 				} else if (bitspersample == 8) {
1658 					alpha = FreeImage_Allocate(width, height, 8);
1659 				}
1660 
1661 				if(!alpha) {
1662 					FreeImage_OutputMessageProc(s_format_id, "Failed to allocate temporary alpha channel");
1663 				} else {
1664 					alpha_bits = FreeImage_GetScanLine(alpha, height - 1);
1665 					alpha_pitch = FreeImage_GetPitch(alpha);
1666 					alpha_Bpp = FreeImage_GetBPP(alpha) / 8;
1667 				}
1668 
1669 			}
1670 
1671 			// create a new DIB
1672 			const uint16 chCount = MIN<uint16>(samplesperpixel, 4);
1673 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, chCount);
1674 			if (dib == NULL) {
1675 				FreeImage_Unload(alpha);
1676 				throw FI_MSG_ERROR_MEMORY;
1677 			}
1678 
1679 			// fill in the resolution (english or universal)
1680 
1681 			ReadResolution(tif, dib);
1682 
1683 			if(!header_only) {
1684 
1685 				// calculate the line + pitch (separate for scr & dest)
1686 
1687 				const tmsize_t src_line = TIFFScanlineSize(tif);
1688 				const tmsize_t dst_line = FreeImage_GetLine(dib);
1689 				const unsigned dib_pitch = FreeImage_GetPitch(dib);
1690 				const unsigned dibBpp = FreeImage_GetBPP(dib) / 8;
1691 				const unsigned Bpc = dibBpp / chCount;
1692 				const unsigned srcBpp = bitspersample * samplesperpixel / 8;
1693 
1694 				assert(Bpc <= 2); //< CMYK is only BYTE or SHORT
1695 
1696 				// In the tiff file the lines are save from up to down
1697 				// In a DIB the lines must be saved from down to up
1698 
1699 				BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
1700 
1701 				// read the tiff lines and save them in the DIB
1702 
1703 				BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
1704 				if(buf == NULL) {
1705 					FreeImage_Unload(alpha);
1706 					throw FI_MSG_ERROR_MEMORY;
1707 				}
1708 
1709 				if(planar_config == PLANARCONFIG_CONTIG) {
1710 
1711 					// - loop for strip blocks -
1712 
1713 					for (uint32 y = 0; y < height; y += rowsperstrip) {
1714 						const int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
1715 
1716 						if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, strips * src_line) == -1) {
1717 							free(buf);
1718 							FreeImage_Unload(alpha);
1719 							throw FI_MSG_ERROR_PARSING;
1720 						}
1721 
1722 						// - loop for strips -
1723 
1724 						if(src_line != dst_line) {
1725 							// CMYKA+
1726 							if(alpha) {
1727 								for (int l = 0; l < strips; l++) {
1728 									for(BYTE *pixel = bits, *al_pixel = alpha_bits, *src_pixel =  buf + l * src_line; pixel < bits + dib_pitch; pixel += dibBpp, al_pixel += alpha_Bpp, src_pixel += srcBpp) {
1729 										// copy pixel byte by byte
1730 										BYTE b = 0;
1731 										for( ; b < dibBpp; ++b) {
1732 											pixel[b] =  src_pixel[b];
1733 										}
1734 										// TODO write the remaining bytes to extra channel(s)
1735 
1736 										// HACK write the first alpha to a separate dib (assume BYTE or WORD)
1737 										al_pixel[0] = src_pixel[b];
1738 										if(Bpc > 1) {
1739 											al_pixel[1] = src_pixel[b + 1];
1740 										}
1741 
1742 									}
1743 									bits -= dib_pitch;
1744 									alpha_bits -= alpha_pitch;
1745 								}
1746 							}
1747 							else {
1748 								// alpha/extra channels alloc failed
1749 								for (int l = 0; l < strips; l++) {
1750 									for(BYTE* pixel = bits, * src_pixel =  buf + l * src_line; pixel < bits + dst_line; pixel += dibBpp, src_pixel += srcBpp) {
1751 										AssignPixel(pixel, src_pixel, dibBpp);
1752 									}
1753 									bits -= dib_pitch;
1754 								}
1755 							}
1756 						}
1757 						else {
1758 							// CMYK to CMYK
1759 							for (int l = 0; l < strips; l++) {
1760 								BYTE *b = buf + l * src_line;
1761 								memcpy(bits, b, src_line);
1762 								bits -= dib_pitch;
1763 							}
1764 						}
1765 
1766 					} // height
1767 
1768 				}
1769 				else if(planar_config == PLANARCONFIG_SEPARATE) {
1770 
1771 					BYTE *dib_strip = bits;
1772 					BYTE *al_strip = alpha_bits;
1773 
1774 					// - loop for strip blocks -
1775 
1776 					for (uint32 y = 0; y < height; y += rowsperstrip) {
1777 						const int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
1778 
1779 						// - loop for channels (planes) -
1780 
1781 						for(uint16 sample = 0; sample < samplesperpixel; sample++) {
1782 
1783 							if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, sample), buf, strips * src_line) == -1) {
1784 								free(buf);
1785 								FreeImage_Unload(alpha);
1786 								throw FI_MSG_ERROR_PARSING;
1787 							}
1788 
1789 							BYTE *dst_strip = dib_strip;
1790 							unsigned dst_pitch = dib_pitch;
1791 							uint16 ch = sample;
1792 							unsigned Bpp = dibBpp;
1793 
1794 							if(sample >= chCount) {
1795 								// TODO Write to Extra Channel
1796 
1797 								// HACK redirect write to temp alpha
1798 								if(alpha && sample == chCount) {
1799 
1800 									dst_strip = al_strip;
1801 									dst_pitch = alpha_pitch;
1802 
1803 									ch = 0;
1804 									Bpp = alpha_Bpp;
1805 								}
1806 								else {
1807 									break;
1808 								}
1809 							}
1810 
1811 							const unsigned channelOffset = ch * Bpc;
1812 
1813 							// - loop for strips in block -
1814 
1815 							BYTE *src_line_begin = buf;
1816 							BYTE *dst_line_begin = dst_strip;
1817 							for (int l = 0; l < strips; l++, src_line_begin += src_line, dst_line_begin -= dst_pitch ) {
1818 								// - loop for pixels in strip -
1819 
1820 								const BYTE* const src_line_end = src_line_begin + src_line;
1821 								for (BYTE *src_bits = src_line_begin, * dst_bits = dst_line_begin; src_bits < src_line_end; src_bits += Bpc, dst_bits += Bpp) {
1822 									AssignPixel(dst_bits + channelOffset, src_bits, Bpc);
1823 								} // line
1824 
1825 							} // strips
1826 
1827 						} // channels
1828 
1829 						// done with a strip block, incr to the next
1830 						dib_strip -= strips * dib_pitch;
1831 						al_strip -= strips * alpha_pitch;
1832 
1833 					} //< height
1834 
1835 				}
1836 
1837 				free(buf);
1838 
1839 				if(!asCMYK) {
1840 					ConvertCMYKtoRGBA(dib);
1841 
1842 					// The ICC Profile is invalid, clear it
1843 					iccSize = 0;
1844 					iccBuf = NULL;
1845 
1846 					if(isCMYKA) {
1847 						// HACK until we have Extra channels. (ConvertCMYKtoRGBA will then do the work)
1848 
1849 						FreeImage_SetChannel(dib, alpha, FICC_ALPHA);
1850 						FreeImage_Unload(alpha);
1851 						alpha = NULL;
1852 					}
1853 					else {
1854 						FIBITMAP *t = RemoveAlphaChannel(dib);
1855 						if(t) {
1856 							FreeImage_Unload(dib);
1857 							dib = t;
1858 						}
1859 						else {
1860 							FreeImage_OutputMessageProc(s_format_id, "Cannot allocate memory for buffer. CMYK image converted to RGB + pending Alpha");
1861 						}
1862 					}
1863 				}
1864 
1865 			} // !header_only
1866 
1867 		} else if(loadMethod == LoadAsGenericStrip) {
1868 			// ---------------------------------------------------------------------------------
1869 			// Generic loading
1870 			// ---------------------------------------------------------------------------------
1871 
1872 			// create a new DIB
1873 			const uint16 chCount = MIN<uint16>(samplesperpixel, 4);
1874 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, chCount);
1875 			if (dib == NULL) {
1876 				throw FI_MSG_ERROR_MEMORY;
1877 			}
1878 
1879 			// fill in the resolution (english or universal)
1880 
1881 			ReadResolution(tif, dib);
1882 
1883 			// set up the colormap based on photometric
1884 
1885 			ReadPalette(tif, photometric, bitspersample, dib);
1886 
1887 			if(!header_only) {
1888 				// calculate the line + pitch (separate for scr & dest)
1889 
1890 				const tmsize_t src_line = TIFFScanlineSize(tif);
1891 				const tmsize_t dst_line = FreeImage_GetLine(dib);
1892 				const unsigned dst_pitch = FreeImage_GetPitch(dib);
1893 				const unsigned Bpp = FreeImage_GetBPP(dib) / 8;
1894 				const unsigned srcBpp = bitspersample * samplesperpixel / 8;
1895 
1896 				// In the tiff file the lines are save from up to down
1897 				// In a DIB the lines must be saved from down to up
1898 
1899 				BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
1900 
1901 				// read the tiff lines and save them in the DIB
1902 
1903 				BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
1904 				if(buf == NULL) {
1905 					throw FI_MSG_ERROR_MEMORY;
1906 				}
1907 				memset(buf, 0, TIFFStripSize(tif) * sizeof(BYTE));
1908 
1909 				BOOL bThrowMessage = FALSE;
1910 
1911 				if(planar_config == PLANARCONFIG_CONTIG) {
1912 
1913 					for (uint32 y = 0; y < height; y += rowsperstrip) {
1914 						int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
1915 
1916 						if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, strips * src_line) == -1) {
1917 							// ignore errors as they can be frequent and not really valid errors, especially with fax images
1918 							bThrowMessage = TRUE;
1919 							/*
1920 							free(buf);
1921 							throw FI_MSG_ERROR_PARSING;
1922 							*/
1923 						}
1924 						if(src_line == dst_line) {
1925 							// channel count match
1926 							for (int l = 0; l < strips; l++) {
1927 								memcpy(bits, buf + l * src_line, src_line);
1928 								bits -= dst_pitch;
1929 							}
1930 						}
1931 						else {
1932 							for (int l = 0; l < strips; l++) {
1933 								for(BYTE *pixel = bits, *src_pixel =  buf + l * src_line; pixel < bits + dst_pitch; pixel += Bpp, src_pixel += srcBpp) {
1934 									AssignPixel(pixel, src_pixel, Bpp);
1935 								}
1936 								bits -= dst_pitch;
1937 							}
1938 						}
1939 					}
1940 				}
1941 				else if(planar_config == PLANARCONFIG_SEPARATE) {
1942 
1943 					const unsigned Bpc = bitspersample / 8;
1944 					BYTE* dib_strip = bits;
1945 					// - loop for strip blocks -
1946 
1947 					for (uint32 y = 0; y < height; y += rowsperstrip) {
1948 						const int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
1949 
1950 						// - loop for channels (planes) -
1951 
1952 						for(uint16 sample = 0; sample < samplesperpixel; sample++) {
1953 
1954 							if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, sample), buf, strips * src_line) == -1) {
1955 								// ignore errors as they can be frequent and not really valid errors, especially with fax images
1956 								bThrowMessage = TRUE;
1957 							}
1958 
1959 							if(sample >= chCount) {
1960 								// TODO Write to Extra Channel
1961 								break;
1962 							}
1963 
1964 							const unsigned channelOffset = sample * Bpc;
1965 
1966 							// - loop for strips in block -
1967 
1968 							BYTE* src_line_begin = buf;
1969 							BYTE* dst_line_begin = dib_strip;
1970 							for (int l = 0; l < strips; l++, src_line_begin += src_line, dst_line_begin -= dst_pitch ) {
1971 
1972 								// - loop for pixels in strip -
1973 
1974 								const BYTE* const src_line_end = src_line_begin + src_line;
1975 
1976 								for (BYTE* src_bits = src_line_begin, * dst_bits = dst_line_begin; src_bits < src_line_end; src_bits += Bpc, dst_bits += Bpp) {
1977 									// actually assigns channel
1978 									AssignPixel(dst_bits + channelOffset, src_bits, Bpc);
1979 								} // line
1980 
1981 							} // strips
1982 
1983 						} // channels
1984 
1985 						// done with a strip block, incr to the next
1986 						dib_strip -= strips * dst_pitch;
1987 
1988 					} // height
1989 
1990 				}
1991 				free(buf);
1992 
1993 				if(bThrowMessage) {
1994 					FreeImage_OutputMessageProc(s_format_id, "Warning: parsing error. Image may be incomplete or contain invalid data !");
1995 				}
1996 
1997 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
1998 				SwapRedBlue32(dib);
1999 #endif
2000 
2001 			} // !header only
2002 
2003 		} else if(loadMethod == LoadAsTiled) {
2004 			// ---------------------------------------------------------------------------------
2005 			// Tiled image loading
2006 			// ---------------------------------------------------------------------------------
2007 
2008 			uint32 tileWidth, tileHeight;
2009 			uint32 src_line = 0;
2010 
2011 			// create a new DIB
2012 			dib = CreateImageType( header_only, image_type, width, height, bitspersample, samplesperpixel);
2013 			if (dib == NULL) {
2014 				throw FI_MSG_ERROR_MEMORY;
2015 			}
2016 
2017 			// fill in the resolution (english or universal)
2018 
2019 			ReadResolution(tif, dib);
2020 
2021 			// set up the colormap based on photometric
2022 
2023 			ReadPalette(tif, photometric, bitspersample, dib);
2024 
2025 			// get the tile geometry
2026 			if(!TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth) || !TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileHeight)) {
2027 				throw "Invalid tiled TIFF image";
2028 			}
2029 
2030 			// read the tiff lines and save them in the DIB
2031 
2032 			if(planar_config == PLANARCONFIG_CONTIG && !header_only) {
2033 
2034 				// get the maximum number of bytes required to contain a tile
2035 				tmsize_t tileSize = TIFFTileSize(tif);
2036 
2037 				// allocate tile buffer
2038 				BYTE *tileBuffer = (BYTE*)malloc(tileSize * sizeof(BYTE));
2039 				if(tileBuffer == NULL) {
2040 					throw FI_MSG_ERROR_MEMORY;
2041 				}
2042 
2043 				// calculate src line and dst pitch
2044 				int dst_pitch = FreeImage_GetPitch(dib);
2045 				uint32 tileRowSize = (uint32)TIFFTileRowSize(tif);
2046 				uint32 imageRowSize = (uint32)TIFFScanlineSize(tif);
2047 
2048 
2049 				// In the tiff file the lines are saved from up to down
2050 				// In a DIB the lines must be saved from down to up
2051 
2052 				BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
2053 
2054 				for (uint32 y = 0; y < height; y += tileHeight) {
2055 					int32 nrows = (y + tileHeight > height ? height - y : tileHeight);
2056 
2057 					for (uint32 x = 0, rowSize = 0; x < width; x += tileWidth, rowSize += tileRowSize) {
2058 						memset(tileBuffer, 0, tileSize);
2059 
2060 						// read one tile
2061 						if (TIFFReadTile(tif, tileBuffer, x, y, 0, 0) < 0) {
2062 							free(tileBuffer);
2063 							throw "Corrupted tiled TIFF file";
2064 						}
2065 						// convert to strip
2066 						if(x + tileWidth > width) {
2067 							src_line = imageRowSize - rowSize;
2068 						} else {
2069 							src_line = tileRowSize;
2070 						}
2071 						BYTE *src_bits = tileBuffer;
2072 						BYTE *dst_bits = bits + rowSize;
2073 						for(int k = 0; k < nrows; k++) {
2074 							memcpy(dst_bits, src_bits, src_line);
2075 							src_bits += tileRowSize;
2076 							dst_bits -= dst_pitch;
2077 						}
2078 					}
2079 
2080 					bits -= nrows * dst_pitch;
2081 				}
2082 
2083 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
2084 				SwapRedBlue32(dib);
2085 #endif
2086 				free(tileBuffer);
2087 			}
2088 			else if(planar_config == PLANARCONFIG_SEPARATE) {
2089 				throw "Separated tiled TIFF images are not supported";
2090 			}
2091 
2092 
2093 		} else if(loadMethod == LoadAsLogLuv) {
2094 			// ---------------------------------------------------------------------------------
2095 			// RGBF LogLuv compressed loading
2096 			// ---------------------------------------------------------------------------------
2097 
2098 			double	stonits;	// input conversion to nits
2099 			if (!TIFFGetField(tif, TIFFTAG_STONITS, &stonits)) {
2100 				stonits = 1;
2101 			}
2102 
2103 			// create a new DIB
2104 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, samplesperpixel);
2105 			if (dib == NULL) {
2106 				throw FI_MSG_ERROR_MEMORY;
2107 			}
2108 
2109 			// fill in the resolution (english or universal)
2110 
2111 			ReadResolution(tif, dib);
2112 
2113 			if(planar_config == PLANARCONFIG_CONTIG && !header_only) {
2114 				// calculate the line + pitch (separate for scr & dest)
2115 
2116 				tmsize_t src_line = TIFFScanlineSize(tif);
2117 				int dst_pitch = FreeImage_GetPitch(dib);
2118 
2119 				// In the tiff file the lines are save from up to down
2120 				// In a DIB the lines must be saved from down to up
2121 
2122 				BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
2123 
2124 				// read the tiff lines and save them in the DIB
2125 
2126 				BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
2127 				if(buf == NULL) {
2128 					throw FI_MSG_ERROR_MEMORY;
2129 				}
2130 
2131 				for (uint32 y = 0; y < height; y += rowsperstrip) {
2132 					int32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
2133 
2134 					if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, nrow * src_line) == -1) {
2135 						free(buf);
2136 						throw FI_MSG_ERROR_PARSING;
2137 					}
2138 					// convert from XYZ to RGB
2139 					for (int l = 0; l < nrow; l++) {
2140 						tiff_ConvertLineXYZToRGB(bits, buf + l * src_line, stonits, width);
2141 						bits -= dst_pitch;
2142 					}
2143 				}
2144 
2145 				free(buf);
2146 			}
2147 			else if(planar_config == PLANARCONFIG_SEPARATE) {
2148 				// this cannot happen according to the LogLuv specification
2149 				throw "Unable to handle PLANARCONFIG_SEPARATE LogLuv images";
2150 			}
2151 
2152 		} else if(loadMethod == LoadAsHalfFloat) {
2153 			// ---------------------------------------------------------------------------------
2154 			// RGBF loading from a half format
2155 			// ---------------------------------------------------------------------------------
2156 
2157 			// create a new DIB
2158 			dib = CreateImageType(header_only, image_type, width, height, bitspersample, samplesperpixel);
2159 			if (dib == NULL) {
2160 				throw FI_MSG_ERROR_MEMORY;
2161 			}
2162 
2163 			// fill in the resolution (english or universal)
2164 
2165 			ReadResolution(tif, dib);
2166 
2167 			if(!header_only) {
2168 
2169 				// calculate the line + pitch (separate for scr & dest)
2170 
2171 				tmsize_t src_line = TIFFScanlineSize(tif);
2172 				unsigned dst_pitch = FreeImage_GetPitch(dib);
2173 
2174 				// In the tiff file the lines are save from up to down
2175 				// In a DIB the lines must be saved from down to up
2176 
2177 				BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
2178 
2179 				// read the tiff lines and save them in the DIB
2180 
2181 				if(planar_config == PLANARCONFIG_CONTIG) {
2182 
2183 					BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
2184 					if(buf == NULL) {
2185 						throw FI_MSG_ERROR_MEMORY;
2186 					}
2187 
2188 					for (uint32 y = 0; y < height; y += rowsperstrip) {
2189 						uint32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
2190 
2191 						if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, nrow * src_line) == -1) {
2192 							free(buf);
2193 							throw FI_MSG_ERROR_PARSING;
2194 						}
2195 
2196 						// convert from half (16-bit) to float (32-bit)
2197 						// !!! use OpenEXR half helper class
2198 
2199 						half half_value;
2200 
2201 						for (uint32 l = 0; l < nrow; l++) {
2202 							WORD *src_pixel = (WORD*)(buf + l * src_line);
2203 							float *dst_pixel = (float*)bits;
2204 
2205 							for(tmsize_t x = 0; x < (tmsize_t)(src_line / sizeof(WORD)); x++) {
2206 								half_value.setBits(src_pixel[x]);
2207 								dst_pixel[x] = half_value;
2208 							}
2209 
2210 							bits -= dst_pitch;
2211 						}
2212 					}
2213 
2214 					free(buf);
2215 				}
2216 				else if(planar_config == PLANARCONFIG_SEPARATE) {
2217 					// this use case was never encountered yet
2218 					throw "Unable to handle PLANARCONFIG_SEPARATE RGB half float images";
2219 				}
2220 
2221 			} // !header only
2222 
2223 		} else {
2224 			// ---------------------------------------------------------------------------------
2225 			// Unknown or unsupported format
2226 			// ---------------------------------------------------------------------------------
2227 
2228 			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
2229 		}
2230 
2231 		// copy TIFF metadata (must be done after FreeImage_Allocate)
2232 
2233 		ReadMetadata(io, handle, tif, dib);
2234 
2235 		// copy ICC profile data (must be done after FreeImage_Allocate)
2236 
2237 		FreeImage_CreateICCProfile(dib, iccBuf, iccSize);
2238 		if (photometric == PHOTOMETRIC_SEPARATED) {
2239 			if (asCMYK) {
2240 				// set the ICC profile as CMYK
2241 				FreeImage_GetICCProfile(dib)->flags |= FIICC_COLOR_IS_CMYK;
2242 			}
2243 			else {
2244 				// if original image is CMYK but is converted to RGB, remove ICC profile from Exif-TIFF metadata
2245 				FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, "InterColorProfile", NULL);
2246 			}
2247 		}
2248 
2249 		// copy TIFF thumbnail (must be done after FreeImage_Allocate)
2250 
2251 		ReadThumbnail(io, handle, data, tif, dib);
2252 
2253 		return dib;
2254 
2255 	} catch (const char *message) {
2256 		if(dib)	{
2257 			FreeImage_Unload(dib);
2258 		}
2259 		if(message) {
2260 			FreeImage_OutputMessageProc(s_format_id, message);
2261 		}
2262 		return NULL;
2263 	}
2264 
2265 }
2266 
2267 // --------------------------------------------------------------------------
2268 
2269 /**
2270 Save a single image into a TIF
2271 
2272 @param io FreeImage IO
2273 @param dib The dib to be saved
2274 @param handle FreeImage handle
2275 @param page Page number
2276 @param flags FreeImage TIFF save flag
2277 @param data TIFF plugin context
2278 @param ifd TIFF Image File Directory (0 means save image, > 0 && (page == -1) means save thumbnail)
2279 @param ifdCount 1 if no thumbnail to save, 2 if image + thumbnail to save
2280 @return Returns TRUE if successful, returns FALSE otherwise
2281 */
2282 static BOOL
SaveOneTIFF(FreeImageIO * io,FIBITMAP * dib,fi_handle handle,int page,int flags,void * data,unsigned ifd,unsigned ifdCount)2283 SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data, unsigned ifd, unsigned ifdCount) {
2284 	if (!dib || !handle || !data) {
2285 		return FALSE;
2286 	}
2287 
2288 	try {
2289 		fi_TIFFIO *fio = (fi_TIFFIO*)data;
2290 		TIFF *out = fio->tif;
2291 
2292 		const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
2293 
2294 		const uint32 width = FreeImage_GetWidth(dib);
2295 		const uint32 height = FreeImage_GetHeight(dib);
2296 		const uint16 bitsperpixel = (uint16)FreeImage_GetBPP(dib);
2297 
2298 		const FIICCPROFILE* iccProfile = FreeImage_GetICCProfile(dib);
2299 
2300 		// setup out-variables based on dib and flag options
2301 
2302 		uint16 bitspersample;
2303 		uint16 samplesperpixel;
2304 		uint16 photometric;
2305 
2306 		if(image_type == FIT_BITMAP) {
2307 			// standard image: 1-, 4-, 8-, 16-, 24-, 32-bit
2308 
2309 			samplesperpixel = ((bitsperpixel == 24) ? 3 : ((bitsperpixel == 32) ? 4 : 1));
2310 			bitspersample = bitsperpixel / samplesperpixel;
2311 			photometric	= GetPhotometric(dib);
2312 
2313 			if((bitsperpixel == 8) && FreeImage_IsTransparent(dib)) {
2314 				// 8-bit transparent picture : convert later to 8-bit + 8-bit alpha
2315 				samplesperpixel = 2;
2316 				bitspersample = 8;
2317 			}
2318 			else if(bitsperpixel == 32) {
2319 				// 32-bit images : check for CMYK or alpha transparency
2320 
2321 				if((((iccProfile->flags & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) || ((flags & TIFF_CMYK) == TIFF_CMYK))) {
2322 					// CMYK support
2323 					photometric = PHOTOMETRIC_SEPARATED;
2324 					TIFFSetField(out, TIFFTAG_INKSET, INKSET_CMYK);
2325 					TIFFSetField(out, TIFFTAG_NUMBEROFINKS, 4);
2326 				}
2327 				else if(photometric == PHOTOMETRIC_RGB) {
2328 					// transparency mask support
2329 					uint16 sampleinfo[1];
2330 					// unassociated alpha data is transparency information
2331 					sampleinfo[0] = EXTRASAMPLE_UNASSALPHA;
2332 					TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
2333 				}
2334 			}
2335 		} else if(image_type == FIT_RGB16) {
2336 			// 48-bit RGB
2337 
2338 			samplesperpixel = 3;
2339 			bitspersample = bitsperpixel / samplesperpixel;
2340 			photometric	= PHOTOMETRIC_RGB;
2341 		} else if(image_type == FIT_RGBA16) {
2342 			// 64-bit RGBA
2343 
2344 			samplesperpixel = 4;
2345 			bitspersample = bitsperpixel / samplesperpixel;
2346 			if((((iccProfile->flags & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) || ((flags & TIFF_CMYK) == TIFF_CMYK))) {
2347 				// CMYK support
2348 				photometric = PHOTOMETRIC_SEPARATED;
2349 				TIFFSetField(out, TIFFTAG_INKSET, INKSET_CMYK);
2350 				TIFFSetField(out, TIFFTAG_NUMBEROFINKS, 4);
2351 			}
2352 			else {
2353 				photometric	= PHOTOMETRIC_RGB;
2354 				// transparency mask support
2355 				uint16 sampleinfo[1];
2356 				// unassociated alpha data is transparency information
2357 				sampleinfo[0] = EXTRASAMPLE_UNASSALPHA;
2358 				TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
2359 			}
2360 		} else if(image_type == FIT_RGBF) {
2361 			// 96-bit RGBF => store with a LogLuv encoding ?
2362 
2363 			samplesperpixel = 3;
2364 			bitspersample = bitsperpixel / samplesperpixel;
2365 			// the library converts to and from floating-point XYZ CIE values
2366 			if((flags & TIFF_LOGLUV) == TIFF_LOGLUV) {
2367 				photometric	= PHOTOMETRIC_LOGLUV;
2368 				TIFFSetField(out, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
2369 				// TIFFSetField(out, TIFFTAG_STONITS, 1.0);   // assume unknown
2370 			}
2371 			else {
2372 				// store with default compression (LZW) or with input compression flag
2373 				photometric	= PHOTOMETRIC_RGB;
2374 			}
2375 
2376 		} else if (image_type == FIT_RGBAF) {
2377 			// 128-bit RGBAF => store with default compression (LZW) or with input compression flag
2378 
2379 			samplesperpixel = 4;
2380 			bitspersample = bitsperpixel / samplesperpixel;
2381 			photometric	= PHOTOMETRIC_RGB;
2382 		} else {
2383 			// special image type (int, long, double, ...)
2384 
2385 			samplesperpixel = 1;
2386 			bitspersample = bitsperpixel;
2387 			photometric	= PHOTOMETRIC_MINISBLACK;
2388 		}
2389 
2390 		// set image data type
2391 
2392 		WriteImageType(out, image_type);
2393 
2394 		// write possible ICC profile
2395 
2396 		if (iccProfile->size && iccProfile->data) {
2397 			TIFFSetField(out, TIFFTAG_ICCPROFILE, iccProfile->size, iccProfile->data);
2398 		}
2399 
2400 		// handle standard width/height/bpp stuff
2401 
2402 		TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
2403 		TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
2404 		TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
2405 		TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bitspersample);
2406 		TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
2407 		TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);	// single image plane
2408 		TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
2409 		TIFFSetField(out, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
2410 		TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, (uint32) -1));
2411 
2412 		// handle metrics
2413 
2414 		WriteResolution(out, dib);
2415 
2416 		// multi-paging
2417 
2418 		if (page >= 0) {
2419 			char page_number[20];
2420 			sprintf(page_number, "Page %d", page);
2421 
2422 			TIFFSetField(out, TIFFTAG_SUBFILETYPE, (uint32)FILETYPE_PAGE);
2423 			TIFFSetField(out, TIFFTAG_PAGENUMBER, (uint16)page, (uint16)0);
2424 			TIFFSetField(out, TIFFTAG_PAGENAME, page_number);
2425 
2426 		} else {
2427 			// is it a thumbnail ?
2428 			TIFFSetField(out, TIFFTAG_SUBFILETYPE, (ifd == 0) ? (uint32)0 : (uint32)FILETYPE_REDUCEDIMAGE);
2429 		}
2430 
2431 		// palettes (image colormaps are automatically scaled to 16-bits)
2432 
2433 		if (photometric == PHOTOMETRIC_PALETTE) {
2434 			uint16 *r, *g, *b;
2435 			uint16 nColors = (uint16)FreeImage_GetColorsUsed(dib);
2436 			RGBQUAD *pal = FreeImage_GetPalette(dib);
2437 
2438 			r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * nColors);
2439 			if(r == NULL) {
2440 				throw FI_MSG_ERROR_MEMORY;
2441 			}
2442 			g = r + nColors;
2443 			b = g + nColors;
2444 
2445 			for (int i = nColors - 1; i >= 0; i--) {
2446 				r[i] = SCALE((uint16)pal[i].rgbRed);
2447 				g[i] = SCALE((uint16)pal[i].rgbGreen);
2448 				b[i] = SCALE((uint16)pal[i].rgbBlue);
2449 			}
2450 
2451 			TIFFSetField(out, TIFFTAG_COLORMAP, r, g, b);
2452 
2453 			_TIFFfree(r);
2454 		}
2455 
2456 		// compression tag
2457 
2458 		WriteCompression(out, bitspersample, samplesperpixel, photometric, flags);
2459 
2460 		// metadata
2461 
2462 		WriteMetadata(out, dib);
2463 
2464 		// thumbnail tag
2465 
2466 		if((ifd == 0) && (ifdCount > 1)) {
2467 			uint16 nsubifd = 1;
2468 			uint64 subifd[1];
2469 			subifd[0] = 0;
2470 			TIFFSetField(out, TIFFTAG_SUBIFD, nsubifd, subifd);
2471 		}
2472 
2473 		// read the DIB lines from bottom to top
2474 		// and save them in the TIF
2475 		// -------------------------------------
2476 
2477 		const uint32 pitch = FreeImage_GetPitch(dib);
2478 
2479 		if(image_type == FIT_BITMAP) {
2480 			// standard bitmap type
2481 
2482 			switch(bitsperpixel) {
2483 				case 1 :
2484 				case 4 :
2485 				case 8 :
2486 				{
2487 					if((bitsperpixel == 8) && FreeImage_IsTransparent(dib)) {
2488 						// 8-bit transparent picture : convert to 8-bit + 8-bit alpha
2489 
2490 						// get the transparency table
2491 						BYTE *trns = FreeImage_GetTransparencyTable(dib);
2492 
2493 						BYTE *buffer = (BYTE *)malloc(2 * width * sizeof(BYTE));
2494 						if(buffer == NULL) {
2495 							throw FI_MSG_ERROR_MEMORY;
2496 						}
2497 
2498 						for (int y = height - 1; y >= 0; y--) {
2499 							BYTE *bits = FreeImage_GetScanLine(dib, y);
2500 
2501 							BYTE *p = bits, *b = buffer;
2502 
2503 							for(uint32 x = 0; x < width; x++) {
2504 								// copy the 8-bit layer
2505 								b[0] = *p;
2506 								// convert the trns table to a 8-bit alpha layer
2507 								b[1] = trns[ b[0] ];
2508 
2509 								p++;
2510 								b += samplesperpixel;
2511 							}
2512 
2513 							// write the scanline to disc
2514 
2515 							TIFFWriteScanline(out, buffer, height - y - 1, 0);
2516 						}
2517 
2518 						free(buffer);
2519 					}
2520 					else {
2521 						// other cases
2522 						BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
2523 						if(buffer == NULL) {
2524 							throw FI_MSG_ERROR_MEMORY;
2525 						}
2526 
2527 						for (uint32 y = 0; y < height; y++) {
2528 							// get a copy of the scanline
2529 							memcpy(buffer, FreeImage_GetScanLine(dib, height - y - 1), pitch);
2530 							// write the scanline to disc
2531 							TIFFWriteScanline(out, buffer, y, 0);
2532 						}
2533 						free(buffer);
2534 					}
2535 
2536 					break;
2537 				}
2538 
2539 				case 24:
2540 				case 32:
2541 				{
2542 					BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
2543 					if(buffer == NULL) {
2544 						throw FI_MSG_ERROR_MEMORY;
2545 					}
2546 
2547 					for (uint32 y = 0; y < height; y++) {
2548 						// get a copy of the scanline
2549 
2550 						memcpy(buffer, FreeImage_GetScanLine(dib, height - y - 1), pitch);
2551 
2552 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
2553 						if (photometric != PHOTOMETRIC_SEPARATED) {
2554 							// TIFFs store color data RGB(A) instead of BGR(A)
2555 
2556 							BYTE *pBuf = buffer;
2557 
2558 							for (uint32 x = 0; x < width; x++) {
2559 								INPLACESWAP(pBuf[0], pBuf[2]);
2560 								pBuf += samplesperpixel;
2561 							}
2562 						}
2563 #endif
2564 						// write the scanline to disc
2565 
2566 						TIFFWriteScanline(out, buffer, y, 0);
2567 					}
2568 
2569 					free(buffer);
2570 
2571 					break;
2572 				}
2573 			}//< switch (bitsperpixel)
2574 
2575 		} else if(image_type == FIT_RGBF && (flags & TIFF_LOGLUV) == TIFF_LOGLUV) {
2576 			// RGBF image => store as XYZ using a LogLuv encoding
2577 
2578 			BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
2579 			if(buffer == NULL) {
2580 				throw FI_MSG_ERROR_MEMORY;
2581 			}
2582 
2583 			for (uint32 y = 0; y < height; y++) {
2584 				// get a copy of the scanline and convert from RGB to XYZ
2585 				tiff_ConvertLineRGBToXYZ(buffer, FreeImage_GetScanLine(dib, height - y - 1), width);
2586 				// write the scanline to disc
2587 				TIFFWriteScanline(out, buffer, y, 0);
2588 			}
2589 			free(buffer);
2590 		} else {
2591 			// just dump the dib (tiff supports all dib types)
2592 
2593 			BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
2594 			if(buffer == NULL) {
2595 				throw FI_MSG_ERROR_MEMORY;
2596 			}
2597 
2598 			for (uint32 y = 0; y < height; y++) {
2599 				// get a copy of the scanline
2600 				memcpy(buffer, FreeImage_GetScanLine(dib, height - y - 1), pitch);
2601 				// write the scanline to disc
2602 				TIFFWriteScanline(out, buffer, y, 0);
2603 			}
2604 			free(buffer);
2605 		}
2606 
2607 		// write out the directory tag if we wrote a page other than -1 or if we have a thumbnail to write later
2608 
2609 		if( (page >= 0) || ((ifd == 0) && (ifdCount > 1)) ) {
2610 			TIFFWriteDirectory(out);
2611 			// else: TIFFClose will WriteDirectory
2612 		}
2613 
2614 		return TRUE;
2615 
2616 	} catch(const char *text) {
2617 		FreeImage_OutputMessageProc(s_format_id, text);
2618 		return FALSE;
2619 	}
2620 }
2621 
2622 static BOOL DLL_CALLCONV
Save(FreeImageIO * io,FIBITMAP * dib,fi_handle handle,int page,int flags,void * data)2623 Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
2624 	BOOL bResult = FALSE;
2625 
2626 	// handle thumbnail as SubIFD
2627 	const BOOL bHasThumbnail = (FreeImage_GetThumbnail(dib) != NULL);
2628 	const unsigned ifdCount = bHasThumbnail ? 2 : 1;
2629 
2630 	FIBITMAP *bitmap = dib;
2631 
2632 	for(unsigned ifd = 0; ifd < ifdCount; ifd++) {
2633 		// redirect dib to thumbnail for the second pass
2634 		if(ifd == 1) {
2635 			bitmap = FreeImage_GetThumbnail(dib);
2636 		}
2637 
2638 		bResult = SaveOneTIFF(io, bitmap, handle, page, flags, data, ifd, ifdCount);
2639 		if(!bResult) {
2640 			return FALSE;
2641 		}
2642 	}
2643 
2644 	return bResult;
2645 }
2646 
2647 // ==========================================================
2648 //   Init
2649 // ==========================================================
2650 
2651 void DLL_CALLCONV
InitTIFF(Plugin * plugin,int format_id)2652 InitTIFF(Plugin *plugin, int format_id) {
2653 	s_format_id = format_id;
2654 
2655     // Set up the callback for extended TIFF directory tag support (see XTIFF.cpp)
2656 	// Must be called before using libtiff
2657     XTIFFInitialize();
2658 
2659 	plugin->format_proc = Format;
2660 	plugin->description_proc = Description;
2661 	plugin->extension_proc = Extension;
2662 	plugin->regexpr_proc = RegExpr;
2663 	plugin->open_proc = Open;
2664 	plugin->close_proc = Close;
2665 	plugin->pagecount_proc = PageCount;
2666 	plugin->pagecapability_proc = NULL;
2667 	plugin->load_proc = Load;
2668 	plugin->save_proc = Save;
2669 	plugin->validate_proc = Validate;
2670 	plugin->mime_proc = MimeType;
2671 	plugin->supports_export_bpp_proc = SupportsExportDepth;
2672 	plugin->supports_export_type_proc = SupportsExportType;
2673 	plugin->supports_icc_profiles_proc = SupportsICCProfiles;
2674 	plugin->supports_no_pixels_proc = SupportsNoPixels;
2675 }
2676