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