Coverage Report

Created: 2026-07-24 06:03

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