1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 03/07/2009
6 //
7 // Filename: src-IL/src/il_tiff.c
8 //
9 // Description: Tiff (.tif) functions
10 //
11 //-----------------------------------------------------------------------------
12
13
14 #include "il_internal.h"
15 #ifndef IL_NO_TIF
16
17 #include "tiffio.h"
18
19 #include <time.h>
20 #include "il_manip.h"
21
22 #define MAGIC_HEADER1 0x4949
23 #define MAGIC_HEADER2 0x4D4D
24
25
26 #if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
27 #if defined(_MSC_VER) || defined(__BORLANDC__)
28 #ifndef _DEBUG
29 #pragma comment(lib, "libtiff.lib")
30 #else
31 #pragma comment(lib, "libtiff-d.lib")
32 #endif
33 #endif
34 #endif
35
36
37 /*----------------------------------------------------------------------------*/
38
39 // No need for a separate header
40 static ILboolean iLoadTiffInternal(void);
41 static char* iMakeString(void);
42 static TIFF* iTIFFOpen(char *Mode);
43 static ILboolean iSaveTiffInternal(/*ILconst_string Filename*/);
44
45 /*----------------------------------------------------------------------------*/
46
ilisValidTiffExtension(ILconst_string FileName)47 ILboolean ilisValidTiffExtension(ILconst_string FileName)
48 {
49 if (!iCheckExtension((ILstring)FileName, IL_TEXT("tif")) &&
50 !iCheckExtension((ILstring)FileName, IL_TEXT("tiff")))
51 return IL_FALSE;
52 else
53 return IL_TRUE;
54 }
55
56 /*----------------------------------------------------------------------------*/
57
58 //! Checks if the file specified in FileName is a valid tiff file.
ilIsValidTiff(ILconst_string FileName)59 ILboolean ilIsValidTiff(ILconst_string FileName)
60 {
61 ILHANDLE TiffFile;
62 ILboolean bTiff = IL_FALSE;
63
64 if (!ilisValidTiffExtension((ILstring) FileName)) {
65 ilSetError(IL_INVALID_EXTENSION);
66 return bTiff;
67 }
68
69 TiffFile = iopenr((ILstring)FileName);
70 if (TiffFile == NULL) {
71 ilSetError(IL_COULD_NOT_OPEN_FILE);
72 return bTiff;
73 }
74
75 bTiff = ilIsValidTiffF(TiffFile);
76 icloser(TiffFile);
77
78 return bTiff;
79 }
80
81 /*----------------------------------------------------------------------------*/
82
ilisValidTiffFunc()83 ILboolean ilisValidTiffFunc()
84 {
85 ILushort Header1, Header2;
86
87 Header1 = GetLittleUShort();
88
89 if (Header1 != MAGIC_HEADER1 && Header1 != MAGIC_HEADER2)
90 return IL_FALSE;
91
92 if (Header1 == MAGIC_HEADER1)
93 Header2 = GetLittleUShort();
94 else
95 Header2 = GetBigUShort();
96
97 if (Header2 != 42)
98 return IL_FALSE;
99
100 return IL_TRUE;
101 }
102
103 /*----------------------------------------------------------------------------*/
104
105 //! Checks if the ILHANDLE contains a valid tiff file at the current position.
ilIsValidTiffF(ILHANDLE File)106 ILboolean ilIsValidTiffF(ILHANDLE File)
107 {
108 ILuint FirstPos;
109 ILboolean bRet;
110
111 iSetInputFile(File);
112 FirstPos = itell();
113 bRet = ilisValidTiffFunc();
114 iseek(FirstPos, IL_SEEK_SET);
115
116 return bRet;
117 }
118
119 /*----------------------------------------------------------------------------*/
120
121 //! Checks if Lump is a valid Tiff lump.
ilIsValidTiffL(const void * Lump,ILuint Size)122 ILboolean ilIsValidTiffL(const void *Lump, ILuint Size)
123 {
124 iSetInputLump(Lump, Size);
125 return ilisValidTiffFunc();
126 }
127
128 /*----------------------------------------------------------------------------*/
129
130 //! Reads a Tiff file
ilLoadTiff(ILconst_string FileName)131 ILboolean ilLoadTiff(ILconst_string FileName)
132 {
133 ILHANDLE TiffFile;
134 ILboolean bTiff = IL_FALSE;
135
136 TiffFile = iopenr(FileName);
137 if (TiffFile == NULL) {
138 ilSetError(IL_COULD_NOT_OPEN_FILE);
139 }
140 else {
141 bTiff = ilLoadTiffF(TiffFile);
142 icloser(TiffFile);
143 }
144
145 return bTiff;
146 }
147
148 /*----------------------------------------------------------------------------*/
149
150 //! Reads an already-opened Tiff file
ilLoadTiffF(ILHANDLE File)151 ILboolean ilLoadTiffF(ILHANDLE File)
152 {
153 ILuint FirstPos;
154 ILboolean bRet;
155
156 iSetInputFile(File);
157 FirstPos = itell();
158 bRet = iLoadTiffInternal();
159 iseek(FirstPos, IL_SEEK_SET);
160
161 return bRet;
162 }
163
164 /*----------------------------------------------------------------------------*/
165
166 //! Reads from a memory "lump" that contains a Tiff
ilLoadTiffL(const void * Lump,ILuint Size)167 ILboolean ilLoadTiffL(const void *Lump, ILuint Size)
168 {
169 iSetInputLump(Lump, Size);
170 return iLoadTiffInternal();
171 }
172
173 /*----------------------------------------------------------------------------*/
174
warningHandler(const char * mod,const char * fmt,va_list ap)175 void warningHandler(const char* mod, const char* fmt, va_list ap)
176 {
177 mod; fmt; ap;
178 //char buff[1024];
179 //vsnprintf(buff, 1024, fmt, ap);
180 }
181
errorHandler(const char * mod,const char * fmt,va_list ap)182 void errorHandler(const char* mod, const char* fmt, va_list ap)
183 {
184 mod; fmt; ap;
185 //char buff[1024];
186 //vsnprintf(buff, 1024, fmt, ap);
187 }
188
189 ////
190
191 /*
192 ILboolean iLoadTiffInternal (TIFF* tif, ILimage* Image)
193 {
194 ////
195
196 uint16 photometric, planarconfig, orientation;
197 uint16 samplesperpixel, bitspersample, *sampleinfo, extrasamples;
198 uint32 w, h, d, linesize, tilewidth, tilelength;
199 ILushort si;
200
201 ////
202
203 TIFFSetDirectory(tif, directory);
204 ////
205
206 // Process fields
207
208 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
209 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
210
211 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH, &d); //TODO: d is ignored...
212 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
213 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
214 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
215 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &orientation);
216
217 linesize = TIFFScanlineSize(tif);
218
219 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
220 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
221
222 tilewidth = w; tilelength = h;
223 TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tilewidth);
224 TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tilelength);
225
226 ////
227
228 if (extrasamples != 0) {
229 return IL_FALSE;
230 }
231
232 ////
233
234 if (!Image) {
235 int type = IL_UNSIGNED_BYTE;
236 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
237 if(!ilTexImage(w, h, 1, 1, IL_LUMINANCE, type, NULL)) {
238 TIFFClose(tif);
239 return IL_FALSE;
240 }
241 iCurImage->NumNext = 0;
242 Image = iCurImage;
243 }
244 else {
245 Image->Next = ilNewImage(w, h, 1, 1, 1);
246 if(Image->Next == NULL) {
247 TIFFClose(tif);
248 return IL_FALSE;
249 }
250 Image = Image->Next;
251 iCurImage->NumNext++;
252 }
253 }
254 */
255
256 ////
257
258
259 // Internal function used to load the Tiff.
iLoadTiffInternal()260 ILboolean iLoadTiffInternal()
261 {
262 TIFF *tif;
263 uint16 photometric, planarconfig, orientation;
264 uint16 samplesperpixel, bitspersample, *sampleinfo, extrasamples;
265 uint32 w, h, d, linesize, tilewidth, tilelength;
266 ILubyte *pImageData;
267 ILuint i, ProfileLen, DirCount = 0;
268 void *Buffer;
269 ILimage *Image, *TempImage;
270 ILushort si;
271 ILfloat x_position, x_resolution, y_position, y_resolution;
272 //TIFFRGBAImage img;
273 //char emsg[1024];
274
275 // to avoid high order bits garbage when used as shorts
276 w = h = d = linesize = tilewidth = tilelength = 0;
277
278 if (iCurImage == NULL) {
279 ilSetError(IL_ILLEGAL_OPERATION);
280 return IL_FALSE;
281 }
282
283 TIFFSetWarningHandler (NULL);
284 TIFFSetErrorHandler (NULL);
285
286 //for debugging only
287 //TIFFSetWarningHandler(warningHandler);
288 //TIFFSetErrorHandler(errorHandler);
289
290 tif = iTIFFOpen("r");
291 if (tif == NULL) {
292 ilSetError(IL_COULD_NOT_OPEN_FILE);
293 return IL_FALSE;
294 }
295
296 do {
297 DirCount++;
298 } while (TIFFReadDirectory(tif));
299
300 /*
301 if (!ilTexImage(1, 1, 1, 1, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
302 TIFFClose(tif);
303 return IL_FALSE;
304 }
305 Image = iCurImage;
306 for (i = 1; i < DirCount; i++) {
307 Image->Next = ilNewImage(1, 1, 1, 1, 1);
308 if (Image->Next == NULL) {
309 TIFFClose(tif);
310 return IL_FALSE;
311 }
312 Image = Image->Next;
313 }
314 iCurImage->NumNext = DirCount - 1;
315 */
316 Image = NULL;
317 for (i = 0; i < DirCount; i++) {
318 TIFFSetDirectory(tif, (tdir_t)i);
319 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
320 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
321
322 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH, &d); //TODO: d is ignored...
323 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
324 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
325 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
326 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &orientation);
327
328 linesize = TIFFScanlineSize(tif);
329
330 //added 2003-08-31
331 //1 bpp tiffs are not neccessarily greyscale, they can
332 //have a palette (photometric == 3)...get this information
333 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
334 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
335
336 //special-case code for frequent data cases that may be read more
337 //efficiently than with the TIFFReadRGBAImage() interface.
338
339 //added 2004-05-12
340 //Get tile sizes and use TIFFReadRGBAImage() for tiled images for now
341 tilewidth = w; tilelength = h;
342 TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tilewidth);
343 TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tilelength);
344
345
346 if (extrasamples == 0
347 && samplesperpixel == 1 //luminance or palette
348 && (bitspersample == 8 || bitspersample == 1 || bitspersample == 16)
349 && (photometric == PHOTOMETRIC_MINISWHITE
350 || photometric == PHOTOMETRIC_MINISBLACK
351 || photometric == PHOTOMETRIC_PALETTE)
352 && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
353 && tilewidth == w && tilelength == h
354 ) {
355 ILubyte* strip;
356 tsize_t stripsize;
357 ILuint y;
358 uint32 rowsperstrip, j, linesread;
359
360 //TODO: 1 bit/pixel images should not be stored as 8 bits...
361 //(-> add new format)
362 if (!Image) {
363 int type = IL_UNSIGNED_BYTE;
364 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
365 if (!ilTexImage(w, h, 1, 1, IL_LUMINANCE, type, NULL)) {
366 TIFFClose(tif);
367 return IL_FALSE;
368 }
369 Image = iCurImage;
370 }
371 else {
372 Image->Next = ilNewImage(w, h, 1, 1, 1);
373 if (Image->Next == NULL) {
374 TIFFClose(tif);
375 return IL_FALSE;
376 }
377 Image = Image->Next;
378 }
379
380 if (photometric == PHOTOMETRIC_PALETTE) { //read palette
381 uint16 *red, *green, *blue;
382 //ILboolean is16bitpalette = IL_FALSE;
383 ILubyte *entry;
384 uint32 count = 1 << bitspersample, j;
385
386 TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
387
388 Image->Format = IL_COLOUR_INDEX;
389 Image->Pal.PalSize = (count)*3;
390 Image->Pal.PalType = IL_PAL_RGB24;
391 Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
392 entry = Image->Pal.Palette;
393 for (j = 0; j < count; ++j) {
394 entry[0] = (ILubyte)(red[j] >> 8);
395 entry[1] = (ILubyte)(green[j] >> 8);
396 entry[2] = (ILubyte)(blue[j] >> 8);
397
398 entry += 3;
399 }
400 }
401
402 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
403 stripsize = TIFFStripSize(tif);
404
405 strip = (ILubyte*)ialloc(stripsize);
406
407 if (bitspersample == 8 || bitspersample == 16) {
408 ILubyte *dat = Image->Data;
409 for (y = 0; y < h; y += rowsperstrip) {
410 //the last strip may contain less data if the image
411 //height is not evenly divisible by rowsperstrip
412 if (y + rowsperstrip > h) {
413 stripsize = linesize*(h - y);
414 linesread = h - y;
415 }
416 else
417 linesread = rowsperstrip;
418
419 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
420 ilSetError(IL_LIB_TIFF_ERROR);
421 ifree(strip);
422 TIFFClose(tif);
423 return IL_FALSE;
424 }
425
426 if (photometric == PHOTOMETRIC_MINISWHITE) { //invert channel
427 uint32 k, t2;
428 for (j = 0; j < linesread; ++j) {
429 t2 = j*linesize;
430 //this works for 16bit images as well: the two bytes
431 //making up a pixel can be inverted independently
432 for (k = 0; k < Image->Bps; ++k)
433 dat[k] = ~strip[t2 + k];
434 dat += w;
435 }
436 }
437 else
438 for(j = 0; j < linesread; ++j)
439 memcpy(&Image->Data[(y + j)*Image->Bps], &strip[j*linesize], Image->Bps);
440 }
441 }
442 else if (bitspersample == 1) {
443 //TODO: add a native format to devil, so we don't have to
444 //unpack the values here
445 ILubyte mask, curr, *dat = Image->Data;
446 uint32 k, sx, t2;
447 for (y = 0; y < h; y += rowsperstrip) {
448 //the last strip may contain less data if the image
449 //height is not evenly divisible by rowsperstrip
450 if (y + rowsperstrip > h) {
451 stripsize = linesize*(h - y);
452 linesread = h - y;
453 }
454 else
455 linesread = rowsperstrip;
456
457 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
458 ilSetError(IL_LIB_TIFF_ERROR);
459 ifree(strip);
460 TIFFClose(tif);
461 return IL_FALSE;
462 }
463
464 for (j = 0; j < linesread; ++j) {
465 k = 0;
466 sx = 0;
467 t2 = j*linesize;
468 while (k < w) {
469 curr = strip[t2 + sx];
470 if (photometric == PHOTOMETRIC_MINISWHITE)
471 curr = ~curr;
472 for (mask = 0x80; mask != 0 && k < w; mask >>= 1){
473 if((curr & mask) != 0)
474 dat[k] = 255;
475 else
476 dat[k] = 0;
477 ++k;
478 }
479 ++sx;
480 }
481 dat += w;
482 }
483 }
484 }
485
486 ifree(strip);
487
488 if(orientation == ORIENTATION_TOPLEFT)
489 Image->Origin = IL_ORIGIN_UPPER_LEFT;
490 else if(orientation == ORIENTATION_BOTLEFT)
491 Image->Origin = IL_ORIGIN_LOWER_LEFT;
492 }
493 //for 16bit rgb images:
494 else if (extrasamples == 0
495 && samplesperpixel == 3
496 && (bitspersample == 8 || bitspersample == 16)
497 && photometric == PHOTOMETRIC_RGB
498 && planarconfig == 1
499 && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
500 && tilewidth == w && tilelength == h
501 ) {
502 ILubyte *strip, *dat;
503 tsize_t stripsize;
504 ILuint y;
505 uint32 rowsperstrip, j, linesread;
506
507 if (!Image) {
508 int type = IL_UNSIGNED_BYTE;
509 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
510 if(!ilTexImage(w, h, 1, 3, IL_RGB, type, NULL)) {
511 TIFFClose(tif);
512 return IL_FALSE;
513 }
514 Image = iCurImage;
515 }
516 else {
517 Image->Next = ilNewImage(w, h, 1, 1, 1);
518 if(Image->Next == NULL) {
519 TIFFClose(tif);
520 return IL_FALSE;
521 }
522 Image = Image->Next;
523 }
524
525 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
526 stripsize = TIFFStripSize(tif);
527
528 strip = (ILubyte*)ialloc(stripsize);
529
530 dat = Image->Data;
531 for (y = 0; y < h; y += rowsperstrip) {
532 //the last strip may contain less data if the image
533 //height is not evenly divisible by rowsperstrip
534 if (y + rowsperstrip > h) {
535 stripsize = linesize*(h - y);
536 linesread = h - y;
537 }
538 else
539 linesread = rowsperstrip;
540
541 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
542 ilSetError(IL_LIB_TIFF_ERROR);
543 ifree(strip);
544 TIFFClose(tif);
545 return IL_FALSE;
546 }
547
548 for(j = 0; j < linesread; ++j)
549 memcpy(&Image->Data[(y + j)*Image->Bps], &strip[j*linesize], Image->Bps);
550 }
551
552 ifree(strip);
553
554 if(orientation == ORIENTATION_TOPLEFT)
555 Image->Origin = IL_ORIGIN_UPPER_LEFT;
556 else if(orientation == ORIENTATION_BOTLEFT)
557 Image->Origin = IL_ORIGIN_LOWER_LEFT;
558 }/*
559 else if (extrasamples == 0 && samplesperpixel == 3 //rgb
560 && (bitspersample == 8 || bitspersample == 1 || bitspersample == 16)
561 && photometric == PHOTOMETRIC_RGB
562 && (planarconfig == PLANARCONFIG_CONTIG || planarcon
563 && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
564 ) {
565 }
566 */
567 else {
568 //not direclty supported format
569 if(!Image) {
570 if(!ilTexImage(w, h, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
571 TIFFClose(tif);
572 return IL_FALSE;
573 }
574 Image = iCurImage;
575 }
576 else {
577 Image->Next = ilNewImage(w, h, 1, 4, 1);
578 if(Image->Next == NULL) {
579 TIFFClose(tif);
580 return IL_FALSE;
581 }
582 Image = Image->Next;
583 }
584
585 if (samplesperpixel == 4) {
586 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
587 if (!sampleinfo || sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) {
588 si = EXTRASAMPLE_ASSOCALPHA;
589 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, &si);
590 }
591 }
592 /*
593 if (!ilResizeImage(Image, Image->Width, Image->Height, 1, 4, 1)) {
594 TIFFClose(tif);
595 return IL_FALSE;
596 }
597 */
598 Image->Format = IL_RGBA;
599 Image->Type = IL_UNSIGNED_BYTE;
600
601 // Siigron: added u_long cast to shut up compiler warning
602 //2003-08-31: changed flag from 1 (exit on error) to 0 (keep decoding)
603 //this lets me view text.tif, but can give crashes with unsupported
604 //tiffs...
605 //2003-09-04: keep flag 1 for official version for now
606 if (!TIFFReadRGBAImage(tif, Image->Width, Image->Height, (uint32*)Image->Data, 0)) {
607 TIFFClose(tif);
608 ilSetError(IL_LIB_TIFF_ERROR);
609 return IL_FALSE;
610 }
611 Image->Origin = IL_ORIGIN_LOWER_LEFT; // eiu...dunno if this is right
612
613 #if BYTE_ORDER == BIG_ENDIAN //TIFFReadRGBAImage reads abgr on big endian, convert to rgba
614 EndianSwapData(Image);
615 #endif
616
617 /*
618 The following switch() should not be needed,
619 because we take care of the special cases that needed
620 these conversions. But since not all special cases
621 are handled right now, keep it :)
622 */
623 //TODO: put switch into the loop??
624 TempImage = iCurImage;
625 iCurImage = Image; //ilConvertImage() converts iCurImage
626 switch (samplesperpixel)
627 {
628 case 1:
629 //added 2003-08-31 to keep palettized tiffs colored
630 if(photometric != 3)
631 ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE);
632 else //strip alpha as tiff supports no alpha palettes
633 ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
634 break;
635
636 case 3:
637 //TODO: why the ifdef??
638 #if BYTE_ORDER == LITTLE_ENDIAN
639 ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
640 #endif
641 break;
642
643 case 4:
644 pImageData = Image->Data;
645 //removed on 2003-08-26...why was this here? libtiff should and does
646 //take care of these things???
647 /*
648 //invert alpha
649 #if BYTE_ORDER == LITTLE_ENDIAN
650 pImageData += 3;
651 #endif
652 for (i = Image->Width * Image->Height; i > 0; i--) {
653 *pImageData ^= 255;
654 pImageData += 4;
655 }
656 */
657 break;
658 }
659 iCurImage = TempImage;
660
661 } //else not directly supported format
662
663 if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &ProfileLen, &Buffer)) {
664 if (Image->Profile && Image->ProfileSize)
665 ifree(Image->Profile);
666 Image->Profile = (ILubyte*)ialloc(ProfileLen);
667 if (Image->Profile == NULL) {
668 TIFFClose(tif);
669 return IL_FALSE;
670 }
671
672 memcpy(Image->Profile, Buffer, ProfileLen);
673 Image->ProfileSize = ProfileLen;
674
675 //removed on 2003-08-24 as explained in bug 579574 on sourceforge
676 //_TIFFfree(Buffer);
677 }
678
679 // dangelo: read offset from tiff tags.
680 //If nothing is stored in these tags, then this must be an "uncropped" TIFF
681 //file, in which case, the "full size" width/height is the same as the
682 //"cropped" width and height
683 //
684 // the full size is currently not supported by DevIL
685 //if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &(c->full_width)) ==
686 // 0)
687 // (c->full_width = c->cropped_width);
688 //if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &(c->full_height)) ==
689 // 0)
690 // (c->full_height = c->cropped_height);
691
692 if (TIFFGetField(tif, TIFFTAG_XPOSITION, &x_position) == 0)
693 x_position = 0;
694 if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &x_resolution) == 0)
695 x_resolution = 0;
696 if (TIFFGetField(tif, TIFFTAG_YPOSITION, &y_position) == 0)
697 y_position = 0;
698 if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &y_resolution) == 0)
699 y_resolution = 0;
700
701 //offset in pixels of "cropped" image from top left corner of
702 //full image (rounded to nearest integer)
703 Image->OffX = (uint32) ((x_position * x_resolution) + 0.49);
704 Image->OffY = (uint32) ((y_position * y_resolution) + 0.49);
705
706
707 /*
708 Image = Image->Next;
709 if (Image == NULL) // Should never happen except when we reach the end, but check anyway.
710 break;
711 */
712 } //for tiff directories
713
714 TIFFClose(tif);
715
716 return ilFixImage();
717 }
718
719 /*----------------------------------------------------------------------------*/
720
721 /////////////////////////////////////////////////////////////////////////////////////////
722 // Extension to load tiff files from memory
723 // Marco Fabbricatore (fabbrica@ai-lab.fh-furtwangen.de)
724 /////////////////////////////////////////////////////////////////////////////////////////
725
726 static tsize_t
_tiffFileReadProc(thandle_t fd,tdata_t pData,tsize_t tSize)727 _tiffFileReadProc(thandle_t fd, tdata_t pData, tsize_t tSize)
728 {
729 fd;
730 return iread(pData, 1, tSize);
731 }
732
733 /*----------------------------------------------------------------------------*/
734
735 // We have trouble sometimes reading when writing a file. Specifically, the only time
736 // I have seen libtiff call this is at the beginning of writing a tiff, before
737 // anything is ever even written! Also, we have to return 0, no matter what tSize
738 // is. If we return tSize like would be expected, then TIFFClientOpen fails.
739 static tsize_t
_tiffFileReadProcW(thandle_t fd,tdata_t pData,tsize_t tSize)740 _tiffFileReadProcW(thandle_t fd, tdata_t pData, tsize_t tSize)
741 {
742 fd;
743 return 0;
744 }
745
746 /*----------------------------------------------------------------------------*/
747
748 static tsize_t
_tiffFileWriteProc(thandle_t fd,tdata_t pData,tsize_t tSize)749 _tiffFileWriteProc(thandle_t fd, tdata_t pData, tsize_t tSize)
750 {
751 fd;
752 return iwrite(pData, 1, tSize);
753 }
754
755 /*----------------------------------------------------------------------------*/
756
757 static toff_t
_tiffFileSeekProc(thandle_t fd,toff_t tOff,int whence)758 _tiffFileSeekProc(thandle_t fd, toff_t tOff, int whence)
759 {
760 fd;
761 /* we use this as a special code, so avoid accepting it */
762 if (tOff == 0xFFFFFFFF)
763 return 0xFFFFFFFF;
764
765 iseek(tOff, whence);
766 return itell();
767 //return tOff;
768 }
769
770 /*----------------------------------------------------------------------------*/
771
772 static toff_t
_tiffFileSeekProcW(thandle_t fd,toff_t tOff,int whence)773 _tiffFileSeekProcW(thandle_t fd, toff_t tOff, int whence)
774 {
775 /* we use this as a special code, so avoid accepting it */
776 if (tOff == 0xFFFFFFFF)
777 return 0xFFFFFFFF;
778
779 iseekw(tOff, whence);
780 return itellw();
781 //return tOff;
782 }
783
784 /*----------------------------------------------------------------------------*/
785
786 static int
_tiffFileCloseProc(thandle_t fd)787 _tiffFileCloseProc(thandle_t fd)
788 {
789 fd;
790 return (0);
791 }
792
793 /*----------------------------------------------------------------------------*/
794
795 static toff_t
_tiffFileSizeProc(thandle_t fd)796 _tiffFileSizeProc(thandle_t fd)
797 {
798 ILint Offset, Size;
799 Offset = itell();
800 iseek(0, IL_SEEK_END);
801 Size = itell();
802 iseek(Offset, IL_SEEK_SET);
803
804 fd;
805
806 return Size;
807 }
808
809 /*----------------------------------------------------------------------------*/
810
811 static toff_t
_tiffFileSizeProcW(thandle_t fd)812 _tiffFileSizeProcW(thandle_t fd)
813 {
814 ILint Offset, Size;
815 Offset = itellw();
816 iseekw(0, IL_SEEK_END);
817 Size = itellw();
818 iseekw(Offset, IL_SEEK_SET);
819
820 return Size;
821 }
822
823 /*----------------------------------------------------------------------------*/
824
825 #ifdef __BORLANDC__
826 #pragma argsused
827 #endif
828 static int
_tiffDummyMapProc(thandle_t fd,tdata_t * pbase,toff_t * psize)829 _tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
830 {
831 fd; pbase; psize;
832 return 0;
833 }
834
835 /*----------------------------------------------------------------------------*/
836
837 #ifdef __BORLANDC__
838 #pragma argsused
839 #endif
840 static void
_tiffDummyUnmapProc(thandle_t fd,tdata_t base,toff_t size)841 _tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
842 {
843 fd; base; size;
844 return;
845 }
846
847 /*----------------------------------------------------------------------------*/
848
iTIFFOpen(char * Mode)849 TIFF *iTIFFOpen(char *Mode)
850 {
851 TIFF *tif;
852
853 if (Mode[0] == 'w')
854 tif = TIFFClientOpen("TIFFMemFile", Mode,
855 NULL,
856 _tiffFileReadProcW, _tiffFileWriteProc,
857 _tiffFileSeekProcW, _tiffFileCloseProc,
858 _tiffFileSizeProcW, _tiffDummyMapProc,
859 _tiffDummyUnmapProc);
860 else
861 tif = TIFFClientOpen("TIFFMemFile", Mode,
862 NULL,
863 _tiffFileReadProc, _tiffFileWriteProc,
864 _tiffFileSeekProc, _tiffFileCloseProc,
865 _tiffFileSizeProc, _tiffDummyMapProc,
866 _tiffDummyUnmapProc);
867
868 return tif;
869 }
870
871 /*----------------------------------------------------------------------------*/
872
873
874 //! Writes a Tiff file
ilSaveTiff(const ILstring FileName)875 ILboolean ilSaveTiff(const ILstring FileName)
876 {
877 ILHANDLE TiffFile;
878 ILuint TiffSize;
879
880 if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
881 if (iFileExists(FileName)) {
882 ilSetError(IL_FILE_ALREADY_EXISTS);
883 return IL_FALSE;
884 }
885 }
886
887 TiffFile = iopenw(FileName);
888 if (TiffFile == NULL) {
889 ilSetError(IL_COULD_NOT_OPEN_FILE);
890 return IL_FALSE;
891 }
892
893 TiffSize = ilSaveTiffF(TiffFile);
894 iclosew(TiffFile);
895
896 if (TiffSize == 0)
897 return IL_FALSE;
898 return IL_TRUE;
899 }
900
901
902 //! Writes a Tiff to an already-opened file
ilSaveTiffF(ILHANDLE File)903 ILuint ilSaveTiffF(ILHANDLE File)
904 {
905 ILuint Pos;
906 iSetOutputFile(File);
907 Pos = itellw();
908 if (iSaveTiffInternal() == IL_FALSE)
909 return 0; // Error occurred
910 return itellw() - Pos; // Return the number of bytes written.
911 }
912
913
914 //! Writes a Tiff to a memory "lump"
ilSaveTiffL(void * Lump,ILuint Size)915 ILuint ilSaveTiffL(void *Lump, ILuint Size)
916 {
917 ILuint Pos = itellw();
918 iSetOutputLump(Lump, Size);
919 if (iSaveTiffInternal() == IL_FALSE)
920 return 0; // Error occurred
921 return itellw() - Pos; // Return the number of bytes written.
922 }
923
924
925 // @TODO: Accept palettes!
926
927 // Internal function used to save the Tiff.
iSaveTiffInternal()928 ILboolean iSaveTiffInternal(/*ILconst_string Filename*/)
929 {
930 ILenum Format;
931 ILenum Compression;
932 ILuint ixLine;
933 TIFF *File;
934 char Description[512];
935 ILimage *TempImage;
936 const char *str;
937 ILboolean SwapColors;
938 ILubyte *OldData;
939
940 if(iCurImage == NULL) {
941 ilSetError(IL_ILLEGAL_OPERATION);
942 return IL_FALSE;
943 }
944
945 #if 1
946 TIFFSetWarningHandler (NULL);
947 TIFFSetErrorHandler (NULL);
948 #else
949 //for debugging only
950 TIFFSetWarningHandler(warningHandler);
951 TIFFSetErrorHandler(errorHandler);
952 #endif
953 if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION)
954 Compression = COMPRESSION_LZW;
955 else
956 Compression = COMPRESSION_NONE;
957
958 if (iCurImage->Format == IL_COLOUR_INDEX) {
959 if (ilGetBppPal(iCurImage->Pal.PalType) == 4) // Preserve the alpha.
960 TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
961 else
962 TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
963
964 if (TempImage == NULL) {
965 return IL_FALSE;
966 }
967 }
968 else {
969 TempImage = iCurImage;
970 }
971
972 /*#ifndef _UNICODE
973 File = TIFFOpen(Filename, "w");
974 #else
975 File = TIFFOpenW(Filename, "w");
976 #endif*/
977
978 // Control writing functions ourself.
979 File = iTIFFOpen("w");
980 if (File == NULL) {
981 ilSetError(IL_COULD_NOT_OPEN_FILE);
982 return IL_FALSE;
983 }
984
985 sprintf(Description, "Tiff generated by %s", ilGetString(IL_VERSION_NUM));
986
987 TIFFSetField(File, TIFFTAG_IMAGEWIDTH, TempImage->Width);
988 TIFFSetField(File, TIFFTAG_IMAGELENGTH, TempImage->Height);
989 TIFFSetField(File, TIFFTAG_COMPRESSION, Compression);
990 if((TempImage->Format == IL_LUMINANCE) || (TempImage->Format == IL_LUMINANCE_ALPHA))
991 TIFFSetField(File, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
992 else
993 TIFFSetField(File, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
994 TIFFSetField(File, TIFFTAG_BITSPERSAMPLE, TempImage->Bpc << 3);
995 TIFFSetField(File, TIFFTAG_SAMPLESPERPIXEL, TempImage->Bpp);
996 if ((TempImage->Bpp == ilGetBppFormat(IL_RGBA)) ||
997 (TempImage->Bpp == ilGetBppFormat(IL_LUMINANCE_ALPHA)))
998 TIFFSetField(File, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA);
999 TIFFSetField(File, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
1000 TIFFSetField(File, TIFFTAG_ROWSPERSTRIP, 1);
1001 TIFFSetField(File, TIFFTAG_SOFTWARE, ilGetString(IL_VERSION_NUM));
1002 /*TIFFSetField(File, TIFFTAG_DOCUMENTNAME,
1003 iGetString(IL_TIF_DOCUMENTNAME_STRING) ?
1004 iGetString(IL_TIF_DOCUMENTNAME_STRING) : FileName);
1005 */
1006 str = iGetString(IL_TIF_DOCUMENTNAME_STRING);
1007 if (str) {
1008 TIFFSetField(File, TIFFTAG_DOCUMENTNAME, str);
1009 ifree(str);
1010 }
1011
1012
1013 str = iGetString(IL_TIF_AUTHNAME_STRING);
1014 if (iGetString(IL_TIF_AUTHNAME_STRING)) {
1015 TIFFSetField(File, TIFFTAG_ARTIST, str);
1016 ifree(str);
1017 }
1018
1019 str = iGetString(IL_TIF_HOSTCOMPUTER_STRING);
1020 if (str) {
1021 TIFFSetField(File, TIFFTAG_HOSTCOMPUTER, str);
1022 ifree(str);
1023 }
1024
1025 str = iGetString(IL_TIF_HOSTCOMPUTER_STRING);
1026 if (str) {
1027 TIFFSetField(File, TIFFTAG_IMAGEDESCRIPTION, str);
1028 ifree(str);
1029 }
1030
1031 // Set the date and time string.
1032 TIFFSetField(File, TIFFTAG_DATETIME, iMakeString());
1033
1034 // 24/4/2003
1035 // Orientation flag is not always supported (Photoshop, ...), orient the image data
1036 // and set it always to normal view
1037 TIFFSetField(File, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
1038 if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
1039 ILubyte* Data = iGetFlipped(TempImage);
1040 OldData = TempImage->Data;
1041 TempImage->Data = Data;
1042 }
1043 else
1044 OldData = TempImage->Data;
1045
1046 /*
1047 TIFFSetField(File, TIFFTAG_ORIENTATION,
1048 TempImage->Origin == IL_ORIGIN_UPPER_LEFT ? ORIENTATION_TOPLEFT : ORIENTATION_BOTLEFT);
1049 */
1050
1051 Format = TempImage->Format;
1052 SwapColors = (Format == IL_BGR || Format == IL_BGRA);
1053 if (SwapColors)
1054 ilSwapColours();
1055
1056 for (ixLine = 0; ixLine < TempImage->Height; ++ixLine) {
1057 if (TIFFWriteScanline(File, TempImage->Data + ixLine * TempImage->Bps, ixLine, 0) < 0) {
1058 TIFFClose(File);
1059 ilSetError(IL_LIB_TIFF_ERROR);
1060 if (SwapColors)
1061 ilSwapColours();
1062 if (TempImage->Data != OldData) {
1063 ifree( TempImage->Data );
1064 TempImage->Data = OldData;
1065 }
1066 if (TempImage != iCurImage)
1067 ilCloseImage(TempImage);
1068 return IL_FALSE;
1069 }
1070 }
1071
1072 if (SwapColors)
1073 ilSwapColours();
1074
1075 if (TempImage->Data != OldData) {
1076 ifree(TempImage->Data);
1077 TempImage->Data = OldData;
1078 }
1079
1080 if (TempImage != iCurImage)
1081 ilCloseImage(TempImage);
1082
1083 TIFFClose(File);
1084
1085 return IL_TRUE;
1086 }
1087
1088 /*----------------------------------------------------------------------------*/
1089 // Makes a neat date string for the date field.
1090 // From http://www.awaresystems.be/imaging/tiff/tifftags/datetime.html :
1091 // The format is: "YYYY:MM:DD HH:MM:SS", with hours like those on
1092 // a 24-hour clock, and one space character between the date and the
1093 // time. The length of the string, including the terminating NUL, is
1094 // 20 bytes.)
iMakeString()1095 char *iMakeString()
1096 {
1097 static char TimeStr[20];
1098 time_t Time;
1099 struct tm *CurTime;
1100
1101 imemclear(TimeStr, 20);
1102
1103 time(&Time);
1104 #ifdef _WIN32
1105 _tzset();
1106 #endif
1107 CurTime = localtime(&Time);
1108
1109 strftime(TimeStr, 20, "%Y:%m:%d %H:%M:%S", CurTime);
1110
1111 return TimeStr;
1112 }
1113
1114 /*----------------------------------------------------------------------------*/
1115
1116 #endif//IL_NO_TIF
1117