- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-IL/src/il_tiff.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2008 by Denton Woods
    00005 // Last modified: 01/24/2009
    00006 //
    00007 // Filename: src-IL/src/il_tiff.c
    00008 //
    00009 // Description: Tiff (.tif) functions
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 #include "il_internal.h"
    00015 #ifndef IL_NO_TIF
    00016
    00017 #include "tiffio.h"
    00018
    00019 #include <time.h>
    00020 #include "il_manip.h"
    00021
    00022 #define MAGIC_HEADER1   0x4949
    00023 #define MAGIC_HEADER2   0x4D4D
    00024
    00025
    00026 #if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
    00027         #if defined(_MSC_VER) || defined(__BORLANDC__)
    00028                 #ifndef _DEBUG
    00029                         #pragma comment(lib, "libtiff.lib")
    00030                 #else
    00031                         #pragma comment(lib, "libtiff-d.lib")
    00032                 #endif
    00033         #endif
    00034 #endif
    00035
    00036
    00037 /*----------------------------------------------------------------------------*/
    00038
    00039 // No need for a separate header
    00040 static ILboolean iLoadTiffInternal(void);
    00041 static char*     iMakeString(void);
    00042 static TIFF*     iTIFFOpen(char *Mode);
    00043 static ILboolean iSaveTiffInternal(/*ILconst_string Filename*/);
    00044
    00045 /*----------------------------------------------------------------------------*/
    00046
    00047 ILboolean ilisValidTiffExtension(ILconst_string FileName)
    00048 {
    00049         if (!iCheckExtension((ILstring)FileName, IL_TEXT("tif")) &&
    00050                 !iCheckExtension((ILstring)FileName, IL_TEXT("tiff")))
    00051                 return IL_FALSE;
    00052         else
    00053                 return IL_TRUE;
    00054 }
    00055
    00056 /*----------------------------------------------------------------------------*/
    00057
    00059 ILboolean ilIsValidTiff(ILconst_string FileName)
    00060 {
    00061         ILHANDLE        TiffFile;
    00062         ILboolean       bTiff = IL_FALSE;
    00063
    00064         if (!ilisValidTiffExtension((ILstring) FileName)) {
    00065                 ilSetError(IL_INVALID_EXTENSION);
    00066                 return bTiff;
    00067         }
    00068
    00069         TiffFile = iopenr((ILstring)FileName);
    00070         if (TiffFile == NULL) {
    00071                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00072                 return bTiff;
    00073         }
    00074
    00075         bTiff = ilIsValidTiffF(TiffFile);
    00076         icloser(TiffFile);
    00077
    00078         return bTiff;
    00079 }
    00080
    00081 /*----------------------------------------------------------------------------*/
    00082
    00083 ILboolean ilisValidTiffFunc()
    00084 {
    00085         ILushort Header1, Header2;
    00086
    00087         Header1 = GetLittleUShort();
    00088
    00089         if (Header1 != MAGIC_HEADER1 && Header1 != MAGIC_HEADER2)
    00090                 return IL_FALSE;
    00091
    00092         if (Header1 == MAGIC_HEADER1)
    00093                 Header2 = GetLittleUShort();
    00094         else
    00095                 Header2 = GetBigUShort();
    00096
    00097         if (Header2 != 42)
    00098                 return IL_FALSE;
    00099
    00100         return IL_TRUE;
    00101 }
    00102
    00103 /*----------------------------------------------------------------------------*/
    00104
    00106 ILboolean ilIsValidTiffF(ILHANDLE File)
    00107 {
    00108         ILuint          FirstPos;
    00109         ILboolean       bRet;
    00110
    00111         iSetInputFile(File);
    00112         FirstPos = itell();
    00113         bRet = ilisValidTiffFunc();
    00114         iseek(FirstPos, IL_SEEK_SET);
    00115
    00116         return bRet;
    00117 }
    00118
    00119 /*----------------------------------------------------------------------------*/
    00120
    00122 ILboolean ilIsValidTiffL(const void *Lump, ILuint Size)
    00123 {
    00124         iSetInputLump(Lump, Size);
    00125         return ilisValidTiffFunc();
    00126 }
    00127
    00128 /*----------------------------------------------------------------------------*/
    00129
    00131 ILboolean ilLoadTiff(ILconst_string FileName)
    00132 {
    00133         ILHANDLE        TiffFile;
    00134         ILboolean       bTiff = IL_FALSE;
    00135
    00136         TiffFile = iopenr(FileName);
    00137         if (TiffFile == NULL) {
    00138                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00139         }
    00140         else {
    00141                 bTiff = ilLoadTiffF(TiffFile);
    00142                 icloser(TiffFile);
    00143         }
    00144
    00145         return bTiff;
    00146 }
    00147
    00148 /*----------------------------------------------------------------------------*/
    00149
    00151 ILboolean ilLoadTiffF(ILHANDLE File)
    00152 {
    00153         ILuint          FirstPos;
    00154         ILboolean       bRet;
    00155
    00156         iSetInputFile(File);
    00157         FirstPos = itell();
    00158         bRet = iLoadTiffInternal();
    00159         iseek(FirstPos, IL_SEEK_SET);
    00160
    00161         return bRet;
    00162 }
    00163
    00164 /*----------------------------------------------------------------------------*/
    00165
    00167 ILboolean ilLoadTiffL(const void *Lump, ILuint Size)
    00168 {
    00169         iSetInputLump(Lump, Size);
    00170         return iLoadTiffInternal();
    00171 }
    00172
    00173 /*----------------------------------------------------------------------------*/
    00174
    00175 void warningHandler(const char* mod, const char* fmt, va_list ap)
    00176 {
    00177         mod; fmt; ap;
    00178         //char buff[1024];
    00179         //vsnprintf(buff, 1024, fmt, ap);
    00180 }
    00181
    00182 void errorHandler(const char* mod, const char* fmt, va_list ap)
    00183 {
    00184         mod; fmt; ap;
    00185         //char buff[1024];
    00186         //vsnprintf(buff, 1024, fmt, ap);
    00187 }
    00188
    00190
    00191 /*
    00192 ILboolean iLoadTiffInternal (TIFF* tif, ILimage* Image)
    00193 {
    00195
    00196         uint16   photometric, planarconfig, orientation;
    00197         uint16   samplesperpixel, bitspersample, *sampleinfo, extrasamples;
    00198         uint32   w, h, d, linesize, tilewidth, tilelength;
    00199         ILushort si;
    00200
    00202
    00203         TIFFSetDirectory(tif, directory);
    00205
    00206         // Process fields
    00207
    00208         TIFFGetField(tif, TIFFTAG_IMAGEWIDTH,  &w);
    00209         TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
    00210
    00211         TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH,      &d); //TODO: d is ignored...
    00212         TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
    00213         TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE,   &bitspersample);
    00214         TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,    &extrasamples, &sampleinfo);
    00215         TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION,     &orientation);
    00216
    00217         linesize = TIFFScanlineSize(tif);
    00218
    00219         TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC,  &photometric);
    00220         TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
    00221
    00222         tilewidth = w; tilelength = h;
    00223         TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH,  &tilewidth);
    00224         TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tilelength);
    00225
    00227
    00228         if (extrasamples != 0) {
    00229                 return IL_FALSE;
    00230         }
    00231
    00233
    00234         if (!Image) {
    00235                 int type = IL_UNSIGNED_BYTE;
    00236                 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
    00237                 if(!ilTexImage(w, h, 1, 1, IL_LUMINANCE, type, NULL)) {
    00238                         TIFFClose(tif);
    00239                         return IL_FALSE;
    00240                 }
    00241                 iCurImage->NumNext = 0;
    00242                 Image = iCurImage;
    00243         }
    00244         else {
    00245                 Image->Next = ilNewImage(w, h, 1, 1, 1);
    00246                 if(Image->Next == NULL) {
    00247                         TIFFClose(tif);
    00248                         return IL_FALSE;
    00249                 }
    00250                 Image = Image->Next;
    00251                 iCurImage->NumNext++;
    00252         }
    00253 }
    00254 */
    00255
    00257
    00258
    00259 // Internal function used to load the Tiff.
    00260 ILboolean iLoadTiffInternal()
    00261 {
    00262         TIFF     *tif;
    00263         uint16   photometric, planarconfig, orientation;
    00264         uint16   samplesperpixel, bitspersample, *sampleinfo, extrasamples;
    00265         uint32   w, h, d, linesize, tilewidth, tilelength;
    00266         ILubyte  *pImageData;
    00267         ILuint   i, ProfileLen, DirCount = 0;
    00268         void     *Buffer;
    00269         ILimage  *Image, *TempImage;
    00270         ILushort si;
    00271         ILfloat  x_position, x_resolution, y_position, y_resolution;
    00272         //TIFFRGBAImage img;
    00273         //char emsg[1024];
    00274
    00275         // to avoid high order bits garbage when used as shorts
    00276         w = h = d = linesize = tilewidth = tilelength = 0;
    00277
    00278         if (iCurImage == NULL) {
    00279                 ilSetError(IL_ILLEGAL_OPERATION);
    00280                 return IL_FALSE;
    00281         }
    00282
    00283         TIFFSetWarningHandler (NULL);
    00284         TIFFSetErrorHandler   (NULL);
    00285
    00286         //for debugging only
    00287         //TIFFSetWarningHandler(warningHandler);
    00288         //TIFFSetErrorHandler(errorHandler);
    00289
    00290         tif = iTIFFOpen("r");
    00291         if (tif == NULL) {
    00292                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00293                 return IL_FALSE;
    00294         }
    00295
    00296         do {
    00297                 DirCount++;
    00298         } while (TIFFReadDirectory(tif));
    00299
    00300         /*
    00301          if (!ilTexImage(1, 1, 1, 1, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
    00302                  TIFFClose(tif);
    00303                  return IL_FALSE;
    00304         }
    00305         Image = iCurImage;
    00306         for (i = 1; i < DirCount; i++) {
    00307                  Image->Next = ilNewImage(1, 1, 1, 1, 1);
    00308                 if (Image->Next == NULL) {
    00309                         TIFFClose(tif);
    00310                         return IL_FALSE;
    00311                 }
    00312                 Image = Image->Next;
    00313         }
    00314         iCurImage->NumNext = DirCount - 1;
    00315         */
    00316         Image = NULL;
    00317         for (i = 0; i < DirCount; i++) {
    00318                 TIFFSetDirectory(tif, (tdir_t)i);
    00319                 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH,  &w);
    00320                 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
    00321
    00322                 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH,          &d); //TODO: d is ignored...
    00323                 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
    00324                 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE,       &bitspersample);
    00325                 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,        &extrasamples, &sampleinfo);
    00326                 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION,         &orientation);
    00327
    00328                 linesize = TIFFScanlineSize(tif);
    00329
    00330                 //added 2003-08-31
    00331                 //1 bpp tiffs are not neccessarily greyscale, they can
    00332                 //have a palette (photometric == 3)...get this information
    00333                 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC,  &photometric);
    00334                 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
    00335
    00336                 //special-case code for frequent data cases that may be read more
    00337                 //efficiently than with the TIFFReadRGBAImage() interface.
    00338
    00339                 //added 2004-05-12
    00340                 //Get tile sizes and use TIFFReadRGBAImage() for tiled images for now
    00341                 tilewidth = w; tilelength = h;
    00342                 TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH,  &tilewidth);
    00343                 TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tilelength);
    00344
    00345
    00346                 if (extrasamples == 0
    00347                         && samplesperpixel == 1  //luminance or palette
    00348                         && (bitspersample == 8 || bitspersample == 1 || bitspersample == 16)
    00349                         && (photometric == PHOTOMETRIC_MINISWHITE
    00350                                 || photometric == PHOTOMETRIC_MINISBLACK
    00351                                 || photometric == PHOTOMETRIC_PALETTE)
    00352                         && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
    00353                         && tilewidth == w && tilelength == h
    00354                         ) {
    00355                         ILubyte* strip;
    00356                         tsize_t stripsize;
    00357                         ILuint y;
    00358                         uint32 rowsperstrip, j, linesread;
    00359
    00360                         //TODO: 1 bit/pixel images should not be stored as 8 bits...
    00361                         //(-> add new format)
    00362                         if (!Image) {
    00363                                 int type = IL_UNSIGNED_BYTE;
    00364                                 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
    00365                                 if (!ilTexImage(w, h, 1, 1, IL_LUMINANCE, type, NULL)) {
    00366                                         TIFFClose(tif);
    00367                                         return IL_FALSE;
    00368                                 }
    00369                                 Image = iCurImage;
    00370                         }
    00371                         else {
    00372                                 Image->Next = ilNewImage(w, h, 1, 1, 1);
    00373                                 if (Image->Next == NULL) {
    00374                                         TIFFClose(tif);
    00375                                         return IL_FALSE;
    00376                                 }
    00377                                 Image = Image->Next;
    00378                         }
    00379
    00380                         if (photometric == PHOTOMETRIC_PALETTE) { //read palette
    00381                                 uint16 *red, *green, *blue;
    00382                                 //ILboolean is16bitpalette = IL_FALSE;
    00383                                 ILubyte *entry;
    00384                                 uint32 count = 1 << bitspersample, j;
    00385
    00386                                 TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
    00387
    00388                                 Image->Format = IL_COLOUR_INDEX;
    00389                                 Image->Pal.PalSize = (count)*3;
    00390                                 Image->Pal.PalType = IL_PAL_RGB24;
    00391                                 Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
    00392                                 entry = Image->Pal.Palette;
    00393                                 for (j = 0; j < count; ++j) {
    00394                                         entry[0] = (ILubyte)(red[j] >> 8);
    00395                                         entry[1] = (ILubyte)(green[j] >> 8);
    00396                                         entry[2] = (ILubyte)(blue[j] >> 8);
    00397
    00398                                         entry += 3;
    00399                                 }
    00400                         }
    00401
    00402                         TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
    00403                         stripsize = TIFFStripSize(tif);
    00404
    00405                         strip = (ILubyte*)ialloc(stripsize);
    00406
    00407                         if (bitspersample == 8 || bitspersample == 16) {
    00408                                 ILubyte *dat = Image->Data;
    00409                                 for (y = 0; y < h; y += rowsperstrip) {
    00410                                         //the last strip may contain less data if the image
    00411                                         //height is not evenly divisible by rowsperstrip
    00412                                         if (y + rowsperstrip > h) {
    00413                                                 stripsize = linesize*(h - y);
    00414                                                 linesread = h - y;
    00415                                         }
    00416                                         else
    00417                                                 linesread = rowsperstrip;
    00418
    00419                                         if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
    00420                                                 ilSetError(IL_LIB_TIFF_ERROR);
    00421                                                 ifree(strip);
    00422                                                 TIFFClose(tif);
    00423                                                 return IL_FALSE;
    00424                                         }
    00425
    00426                                         if (photometric == PHOTOMETRIC_MINISWHITE) { //invert channel
    00427                                                 uint32 k, t2;
    00428                                                 for (j = 0; j < linesread; ++j) {
    00429                                                         t2 = j*linesize;
    00430                                                         //this works for 16bit images as well: the two bytes
    00431                                                         //making up a pixel can be inverted independently
    00432                                                         for (k = 0; k < Image->Bps; ++k)
    00433                                                                 dat[k] = ~strip[t2 + k];
    00434                                                         dat += w;
    00435                                                 }
    00436                                         }
    00437                                         else
    00438                                                 for(j = 0; j < linesread; ++j)
    00439                                                         memcpy(&Image->Data[(y + j)*Image->Bps], &strip[j*linesize], Image->Bps);
    00440                                 }
    00441                         }
    00442                         else if (bitspersample == 1) {
    00443                                 //TODO: add a native format to devil, so we don't have to
    00444                                 //unpack the values here
    00445                                 ILubyte mask, curr, *dat = Image->Data;
    00446                                 uint32 k, sx, t2;
    00447                                 for (y = 0; y < h; y += rowsperstrip) {
    00448                                         //the last strip may contain less data if the image
    00449                                         //height is not evenly divisible by rowsperstrip
    00450                                         if (y + rowsperstrip > h) {
    00451                                                 stripsize = linesize*(h - y);
    00452                                                 linesread = h - y;
    00453                                         }
    00454                                         else
    00455                                                 linesread = rowsperstrip;
    00456
    00457                                         if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
    00458                                                 ilSetError(IL_LIB_TIFF_ERROR);
    00459                                                 ifree(strip);
    00460                                                 TIFFClose(tif);
    00461                                                 return IL_FALSE;
    00462                                         }
    00463
    00464                                         for (j = 0; j < linesread; ++j) {
    00465                                                 k = 0;
    00466                                                 sx = 0;
    00467                                                 t2 = j*linesize;
    00468                                                 while (k < w) {
    00469                                                         curr = strip[t2 + sx];
    00470                                                         if (photometric == PHOTOMETRIC_MINISWHITE)
    00471                                                                 curr = ~curr;
    00472                                                         for (mask = 0x80; mask != 0 && k < w; mask >>= 1){
    00473                                                                 if((curr & mask) != 0)
    00474                                                                         dat[k] = 255;
    00475                                                                 else
    00476                                                                         dat[k] = 0;
    00477                                                                 ++k;
    00478                                                         }
    00479                                                         ++sx;
    00480                                                 }
    00481                                                 dat += w;
    00482                                         }
    00483                                 }
    00484                         }
    00485
    00486                         ifree(strip);
    00487
    00488                         if(orientation == ORIENTATION_TOPLEFT)
    00489                                 Image->Origin = IL_ORIGIN_UPPER_LEFT;
    00490                         else if(orientation == ORIENTATION_BOTLEFT)
    00491                                 Image->Origin = IL_ORIGIN_LOWER_LEFT;
    00492                 }
    00493                 //for 16bit rgb images:
    00494                 else if (extrasamples == 0
    00495                         && samplesperpixel == 3
    00496                         && (bitspersample == 8 || bitspersample == 16)
    00497                         && photometric == PHOTOMETRIC_RGB
    00498                         && planarconfig == 1
    00499                         && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
    00500                         && tilewidth == w && tilelength == h
    00501                         ) {
    00502                         ILubyte *strip, *dat;
    00503                         tsize_t stripsize;
    00504                         ILuint y;
    00505                         uint32 rowsperstrip, j, linesread;
    00506
    00507                         if (!Image) {
    00508                                 int type = IL_UNSIGNED_BYTE;
    00509                                 if (bitspersample == 16) type = IL_UNSIGNED_SHORT;
    00510                                 if(!ilTexImage(w, h, 1, 3, IL_RGB, type, NULL)) {
    00511                                         TIFFClose(tif);
    00512                                         return IL_FALSE;
    00513                                 }
    00514                                 Image = iCurImage;
    00515                         }
    00516                         else {
    00517                                 Image->Next = ilNewImage(w, h, 1, 1, 1);
    00518                                 if(Image->Next == NULL) {
    00519                                         TIFFClose(tif);
    00520                                         return IL_FALSE;
    00521                                 }
    00522                                 Image = Image->Next;
    00523                         }
    00524
    00525                         TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
    00526                         stripsize = TIFFStripSize(tif);
    00527
    00528                         strip = (ILubyte*)ialloc(stripsize);
    00529
    00530                         dat = Image->Data;
    00531                         for (y = 0; y < h; y += rowsperstrip) {
    00532                                 //the last strip may contain less data if the image
    00533                                 //height is not evenly divisible by rowsperstrip
    00534                                 if (y + rowsperstrip > h) {
    00535                                         stripsize = linesize*(h - y);
    00536                                         linesread = h - y;
    00537                                 }
    00538                                 else
    00539                                         linesread = rowsperstrip;
    00540
    00541                                 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) {
    00542                                         ilSetError(IL_LIB_TIFF_ERROR);
    00543                                         ifree(strip);
    00544                                         TIFFClose(tif);
    00545                                         return IL_FALSE;
    00546                                 }
    00547
    00548                                 for(j = 0; j < linesread; ++j)
    00549                                                 memcpy(&Image->Data[(y + j)*Image->Bps], &strip[j*linesize], Image->Bps);
    00550                         }
    00551
    00552                         ifree(strip);
    00553
    00554                         if(orientation == ORIENTATION_TOPLEFT)
    00555                                 Image->Origin = IL_ORIGIN_UPPER_LEFT;
    00556                         else if(orientation == ORIENTATION_BOTLEFT)
    00557                                 Image->Origin = IL_ORIGIN_LOWER_LEFT;
    00558                 }/*
    00559                 else if (extrasamples == 0 && samplesperpixel == 3  //rgb
    00560                                         && (bitspersample == 8 || bitspersample == 1 || bitspersample == 16)
    00561                                         && photometric == PHOTOMETRIC_RGB
    00562                                         && (planarconfig == PLANARCONFIG_CONTIG || planarcon
    00563                                                 && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT)
    00564                                         ) {
    00565                 }
    00566                                 */
    00567                 else {
    00568                                 //not direclty supported format
    00569                         if(!Image) {
    00570                                 if(!ilTexImage(w, h, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
    00571                                         TIFFClose(tif);
    00572                                         return IL_FALSE;
    00573                                 }
    00574                                 Image = iCurImage;
    00575                         }
    00576                         else {
    00577                                 Image->Next = ilNewImage(w, h, 1, 4, 1);
    00578                                 if(Image->Next == NULL) {
    00579                                         TIFFClose(tif);
    00580                                         return IL_FALSE;
    00581                                 }
    00582                                 Image = Image->Next;
    00583                         }
    00584
    00585                         if (samplesperpixel == 4) {
    00586                                 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
    00587                                 if (!sampleinfo || sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) {
    00588                                         si = EXTRASAMPLE_ASSOCALPHA;
    00589                                         TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, &si);
    00590                                 }
    00591                         }
    00592                         /*
    00593                          if (!ilResizeImage(Image, Image->Width, Image->Height, 1, 4, 1)) {
    00594                                  TIFFClose(tif);
    00595                                  return IL_FALSE;
    00596                          }
    00597                          */
    00598                         Image->Format = IL_RGBA;
    00599                         Image->Type = IL_UNSIGNED_BYTE;
    00600
    00601                         // Siigron: added u_long cast to shut up compiler warning
    00602                         //2003-08-31: changed flag from 1 (exit on error) to 0 (keep decoding)
    00603                         //this lets me view text.tif, but can give crashes with unsupported
    00604                         //tiffs...
    00605                         //2003-09-04: keep flag 1 for official version for now
    00606                         if (!TIFFReadRGBAImage(tif, Image->Width, Image->Height, (uint32*)Image->Data, 0)) {
    00607                                 TIFFClose(tif);
    00608                                 ilSetError(IL_LIB_TIFF_ERROR);
    00609                                 return IL_FALSE;
    00610                         }
    00611                         Image->Origin = IL_ORIGIN_LOWER_LEFT;  // eiu...dunno if this is right
    00612
    00613 #ifdef __BIG_ENDIAN__ //TIFFReadRGBAImage reads abgr on big endian, convert to rgba
    00614                         EndianSwapData(Image);
    00615 #endif
    00616
    00617                         /*
    00618                          The following switch() should not be needed,
    00619                          because we take care of the special cases that needed
    00620                          these conversions. But since not all special cases
    00621                          are handled right now, keep it :)
    00622                          */
    00623                         //TODO: put switch into the loop??
    00624                         TempImage = iCurImage;
    00625                         iCurImage = Image; //ilConvertImage() converts iCurImage
    00626                         switch (samplesperpixel)
    00627                         {
    00628                                 case 1:
    00629                                         //added 2003-08-31 to keep palettized tiffs colored
    00630                                         if(photometric != 3)
    00631                                                 ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE);
    00632                                         else //strip alpha as tiff supports no alpha palettes
    00633                                                 ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
    00634                                         break;
    00635
    00636                                 case 3:
    00637                                         //TODO: why the ifdef??
    00638 #ifdef __LITTLE_ENDIAN__
    00639                                         ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
    00640 #endif
    00641                                         break;
    00642
    00643                                 case 4:
    00644                                         pImageData = Image->Data;
    00645                                         //removed on 2003-08-26...why was this here? libtiff should and does
    00646                                         //take care of these things???
    00647                                         /*
    00648                                         //invert alpha
    00649 #ifdef __LITTLE_ENDIAN__
    00650                                         pImageData += 3;
    00651 #endif
    00652                                         for (i = Image->Width * Image->Height; i > 0; i--) {
    00653                                                 *pImageData ^= 255;
    00654                                                 pImageData += 4;
    00655                                         }
    00656                                         */
    00657                                         break;
    00658                         }
    00659                         iCurImage = TempImage;
    00660
    00661                 } //else not directly supported format
    00662
    00663                 if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &ProfileLen, &Buffer)) {
    00664                         if (Image->Profile && Image->ProfileSize)
    00665                                 ifree(Image->Profile);
    00666                         Image->Profile = (ILubyte*)ialloc(ProfileLen);
    00667                         if (Image->Profile == NULL) {
    00668                                 TIFFClose(tif);
    00669                                 return IL_FALSE;
    00670                         }
    00671
    00672                         memcpy(Image->Profile, Buffer, ProfileLen);
    00673                         Image->ProfileSize = ProfileLen;
    00674
    00675                         //removed on 2003-08-24 as explained in bug 579574 on sourceforge
    00676                         //_TIFFfree(Buffer);
    00677                 }
    00678
    00679                 // dangelo: read offset from tiff tags.
    00680                 //If nothing is stored in these tags, then this must be an "uncropped" TIFF
    00681                 //file, in which case, the "full size" width/height is the same as the
    00682                 //"cropped" width and height
    00683                 //
    00684                 // the full size is currently not supported by DevIL
    00685                 //if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &(c->full_width)) ==
    00686                 //        0)
    00687                 //    (c->full_width = c->cropped_width);
    00688                 //if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &(c->full_height)) ==
    00689                 //        0)
    00690                 //    (c->full_height = c->cropped_height);
    00691
    00692                 if (TIFFGetField(tif, TIFFTAG_XPOSITION, &x_position) == 0)
    00693                     x_position = 0;
    00694                 if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &x_resolution) == 0)
    00695                     x_resolution = 0;
    00696                 if (TIFFGetField(tif, TIFFTAG_YPOSITION, &y_position) == 0)
    00697                     y_position = 0;
    00698                 if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &y_resolution) == 0)
    00699                     y_resolution = 0;
    00700
    00701                 //offset in pixels of "cropped" image from top left corner of
    00702                 //full image (rounded to nearest integer)
    00703                 Image->OffX = (uint32) ((x_position * x_resolution) + 0.49);
    00704                 Image->OffY = (uint32) ((y_position * y_resolution) + 0.49);
    00705
    00706
    00707                 /*
    00708                  Image = Image->Next;
    00709                  if (Image == NULL)  // Should never happen except when we reach the end, but check anyway.
    00710                  break;
    00711                  */
    00712         } //for tiff directories
    00713
    00714         TIFFClose(tif);
    00715
    00716         ilFixImage();
    00717
    00718         return IL_TRUE;
    00719 }
    00720
    00721 /*----------------------------------------------------------------------------*/
    00722
    00724 // Extension to load tiff files from memory
    00725 // Marco Fabbricatore (fabbrica@ai-lab.fh-furtwangen.de)
    00727
    00728 static tsize_t
    00729 _tiffFileReadProc(thandle_t fd, tdata_t pData, tsize_t tSize)
    00730 {
    00731         fd;
    00732         return iread(pData, 1, tSize);
    00733 }
    00734
    00735 /*----------------------------------------------------------------------------*/
    00736
    00737 // We have trouble sometimes reading when writing a file.  Specifically, the only time
    00738 //  I have seen libtiff call this is at the beginning of writing a tiff, before
    00739 //  anything is ever even written!  Also, we have to return 0, no matter what tSize
    00740 //  is.  If we return tSize like would be expected, then TIFFClientOpen fails.
    00741 static tsize_t
    00742 _tiffFileReadProcW(thandle_t fd, tdata_t pData, tsize_t tSize)
    00743 {
    00744         fd;
    00745         return 0;
    00746 }
    00747
    00748 /*----------------------------------------------------------------------------*/
    00749
    00750 static tsize_t
    00751 _tiffFileWriteProc(thandle_t fd, tdata_t pData, tsize_t tSize)
    00752 {
    00753         fd;
    00754         return iwrite(pData, 1, tSize);
    00755 }
    00756
    00757 /*----------------------------------------------------------------------------*/
    00758
    00759 static toff_t
    00760 _tiffFileSeekProc(thandle_t fd, toff_t tOff, int whence)
    00761 {
    00762         fd;
    00763         /* we use this as a special code, so avoid accepting it */
    00764         if (tOff == 0xFFFFFFFF)
    00765                 return 0xFFFFFFFF;
    00766
    00767         iseek(tOff, whence);
    00768         return itell();
    00769         //return tOff;
    00770 }
    00771
    00772 /*----------------------------------------------------------------------------*/
    00773
    00774 static toff_t
    00775 _tiffFileSeekProcW(thandle_t fd, toff_t tOff, int whence)
    00776 {
    00777         /* we use this as a special code, so avoid accepting it */
    00778         if (tOff == 0xFFFFFFFF)
    00779                 return 0xFFFFFFFF;
    00780
    00781         iseekw(tOff, whence);
    00782         return itellw();
    00783         //return tOff;
    00784 }
    00785
    00786 /*----------------------------------------------------------------------------*/
    00787
    00788 static int
    00789 _tiffFileCloseProc(thandle_t fd)
    00790 {
    00791         fd;
    00792         return (0);
    00793 }
    00794
    00795 /*----------------------------------------------------------------------------*/
    00796
    00797 static toff_t
    00798 _tiffFileSizeProc(thandle_t fd)
    00799 {
    00800         ILint Offset, Size;
    00801         Offset = itell();
    00802         iseek(0, IL_SEEK_END);
    00803         Size = itell();
    00804         iseek(Offset, IL_SEEK_SET);
    00805
    00806         fd;
    00807
    00808         return Size;
    00809 }
    00810
    00811 /*----------------------------------------------------------------------------*/
    00812
    00813 static toff_t
    00814 _tiffFileSizeProcW(thandle_t fd)
    00815 {
    00816         ILint Offset, Size;
    00817         Offset = itellw();
    00818         iseekw(0, IL_SEEK_END);
    00819         Size = itellw();
    00820         iseekw(Offset, IL_SEEK_SET);
    00821
    00822         return Size;
    00823 }
    00824
    00825 /*----------------------------------------------------------------------------*/
    00826
    00827 #ifdef __BORLANDC__
    00828 #pragma argsused
    00829 #endif
    00830 static int
    00831 _tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
    00832 {
    00833         fd; pbase; psize;
    00834         return 0;
    00835 }
    00836
    00837 /*----------------------------------------------------------------------------*/
    00838
    00839 #ifdef __BORLANDC__
    00840 #pragma argsused
    00841 #endif
    00842 static void
    00843 _tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
    00844 {
    00845         fd; base; size;
    00846         return;
    00847 }
    00848
    00849 /*----------------------------------------------------------------------------*/
    00850
    00851 TIFF *iTIFFOpen(char *Mode)
    00852 {
    00853         TIFF *tif;
    00854
    00855         if (Mode[0] == 'w')
    00856                 tif = TIFFClientOpen("TIFFMemFile", Mode,
    00857                                                         NULL,
    00858                                                         _tiffFileReadProcW, _tiffFileWriteProc,
    00859                                                         _tiffFileSeekProcW, _tiffFileCloseProc,
    00860                                                         _tiffFileSizeProcW, _tiffDummyMapProc,
    00861                                                         _tiffDummyUnmapProc);
    00862         else
    00863                 tif = TIFFClientOpen("TIFFMemFile", Mode,
    00864                                                         NULL,
    00865                                                         _tiffFileReadProc, _tiffFileWriteProc,
    00866                                                         _tiffFileSeekProc, _tiffFileCloseProc,
    00867                                                         _tiffFileSizeProc, _tiffDummyMapProc,
    00868                                                         _tiffDummyUnmapProc);
    00869
    00870         return tif;
    00871 }
    00872
    00873 /*----------------------------------------------------------------------------*/
    00874
    00875
    00877 ILboolean ilSaveTiff(const ILstring FileName)
    00878 {
    00879         ILHANDLE        TiffFile;
    00880         ILuint          TiffSize;
    00881
    00882         if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
    00883                 if (iFileExists(FileName)) {
    00884                         ilSetError(IL_FILE_ALREADY_EXISTS);
    00885                         return IL_FALSE;
    00886                 }
    00887         }
    00888
    00889         TiffFile = iopenw(FileName);
    00890         if (TiffFile == NULL) {
    00891                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00892                 return IL_FALSE;
    00893         }
    00894
    00895         TiffSize = ilSaveTiffF(TiffFile);
    00896         iclosew(TiffFile);
    00897
    00898         if (TiffSize == 0)
    00899                 return IL_FALSE;
    00900         return IL_TRUE;
    00901 }
    00902
    00903
    00905 ILuint ilSaveTiffF(ILHANDLE File)
    00906 {
    00907         ILuint Pos;
    00908         iSetOutputFile(File);
    00909         Pos = itellw();
    00910         if (iSaveTiffInternal() == IL_FALSE)
    00911                 return 0;  // Error occurred
    00912         return itellw() - Pos;  // Return the number of bytes written.
    00913 }
    00914
    00915
    00917 ILuint ilSaveTiffL(void *Lump, ILuint Size)
    00918 {
    00919         ILuint Pos = itellw();
    00920         iSetOutputLump(Lump, Size);
    00921         if (iSaveTiffInternal() == IL_FALSE)
    00922                 return 0;  // Error occurred
    00923         return itellw() - Pos;  // Return the number of bytes written.
    00924 }
    00925
    00926
    00927 // @TODO:  Accept palettes!
    00928
    00929 // Internal function used to save the Tiff.
    00930 ILboolean iSaveTiffInternal(/*ILconst_string Filename*/)
    00931 {
    00932         ILenum  Format;
    00933         ILenum  Compression;
    00934         ILuint  ixLine;
    00935         TIFF    *File;
    00936         char    Description[512];
    00937         ILimage *TempImage;
    00938         const char      *str;
    00939         ILboolean SwapColors;
    00940         ILubyte *OldData;
    00941
    00942         if(iCurImage == NULL) {
    00943                 ilSetError(IL_ILLEGAL_OPERATION);
    00944                 return IL_FALSE;
    00945         }
    00946
    00947 #if 1
    00948         TIFFSetWarningHandler (NULL);
    00949         TIFFSetErrorHandler   (NULL);
    00950 #else
    00951         //for debugging only
    00952         TIFFSetWarningHandler(warningHandler);
    00953         TIFFSetErrorHandler(errorHandler);
    00954 #endif
    00955         if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION)
    00956                 Compression = COMPRESSION_LZW;
    00957         else
    00958                 Compression = COMPRESSION_NONE;
    00959
    00960         if (iCurImage->Format == IL_COLOUR_INDEX) {
    00961                 if (ilGetBppPal(iCurImage->Pal.PalType) == 4)  // Preserve the alpha.
    00962                         TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
    00963                 else
    00964                         TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
    00965
    00966                 if (TempImage == NULL) {
    00967                         return IL_FALSE;
    00968                 }
    00969         }
    00970         else {
    00971                 TempImage = iCurImage;
    00972         }
    00973
    00974         /*#ifndef _UNICODE
    00975                 File = TIFFOpen(Filename, "w");
    00976         #else
    00977                 File = TIFFOpenW(Filename, "w");
    00978         #endif*/
    00979
    00980         // Control writing functions ourself.
    00981         File = iTIFFOpen("w");
    00982         if (File == NULL) {
    00983                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00984                 return IL_FALSE;
    00985         }
    00986
    00987         sprintf(Description, "Tiff generated by %s", ilGetString(IL_VERSION_NUM));
    00988
    00989         TIFFSetField(File, TIFFTAG_IMAGEWIDTH, TempImage->Width);
    00990         TIFFSetField(File, TIFFTAG_IMAGELENGTH, TempImage->Height);
    00991         TIFFSetField(File, TIFFTAG_COMPRESSION, Compression);
    00992         TIFFSetField(File, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    00993         TIFFSetField(File, TIFFTAG_BITSPERSAMPLE, TempImage->Bpc << 3);
    00994         TIFFSetField(File, TIFFTAG_SAMPLESPERPIXEL, TempImage->Bpp);
    00995         if (TempImage->Bpp == 4) //TODO: LUMINANCE, LUMINANCE_ALPHA
    00996                 TIFFSetField(File, TIFFTAG_MATTEING, 1);
    00997         TIFFSetField(File, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    00998         TIFFSetField(File, TIFFTAG_ROWSPERSTRIP, 1);
    00999         TIFFSetField(File, TIFFTAG_SOFTWARE, ilGetString(IL_VERSION_NUM));
    01000         /*TIFFSetField(File, TIFFTAG_DOCUMENTNAME,
    01001                 iGetString(IL_TIF_DOCUMENTNAME_STRING) ?
    01002                 iGetString(IL_TIF_DOCUMENTNAME_STRING) : FileName);
    01003 */
    01004         str = iGetString(IL_TIF_DOCUMENTNAME_STRING);
    01005         if (str) {
    01006                 TIFFSetField(File, TIFFTAG_DOCUMENTNAME, str);
    01007                 ifree(str);
    01008         }
    01009
    01010
    01011         str = iGetString(IL_TIF_AUTHNAME_STRING);
    01012         if (iGetString(IL_TIF_AUTHNAME_STRING)) {
    01013                 TIFFSetField(File, TIFFTAG_ARTIST, str);
    01014                 ifree(str);
    01015         }
    01016
    01017         str = iGetString(IL_TIF_HOSTCOMPUTER_STRING);
    01018         if (str) {
    01019                 TIFFSetField(File, TIFFTAG_HOSTCOMPUTER, str);
    01020                 ifree(str);
    01021         }
    01022
    01023         str = iGetString(IL_TIF_HOSTCOMPUTER_STRING);
    01024         if (str) {
    01025                 TIFFSetField(File, TIFFTAG_IMAGEDESCRIPTION, str);
    01026                 ifree(str);
    01027         }
    01028
    01029         // Set the date and time string.
    01030         TIFFSetField(File, TIFFTAG_DATETIME, iMakeString());
    01031
    01032         // 24/4/2003
    01033         // Orientation flag is not always supported (Photoshop, ...), orient the image data
    01034         // and set it always to normal view
    01035         TIFFSetField(File, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
    01036         if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    01037                 ILubyte* Data = iGetFlipped(TempImage);
    01038                 OldData = TempImage->Data;
    01039                 TempImage->Data = Data;
    01040         }
    01041         else
    01042                 OldData = TempImage->Data;
    01043
    01044         /*
    01045          TIFFSetField(File, TIFFTAG_ORIENTATION,
    01046                                   TempImage->Origin == IL_ORIGIN_UPPER_LEFT ? ORIENTATION_TOPLEFT : ORIENTATION_BOTLEFT);
    01047          */
    01048
    01049         Format = TempImage->Format;
    01050         SwapColors = (Format == IL_BGR || Format == IL_BGRA);
    01051         if (SwapColors)
    01052                 ilSwapColours();
    01053
    01054         for (ixLine = 0; ixLine < TempImage->Height; ++ixLine) {
    01055                 if (TIFFWriteScanline(File, TempImage->Data + ixLine * TempImage->Bps, ixLine, 0) < 0) {
    01056                         TIFFClose(File);
    01057                         ilSetError(IL_LIB_TIFF_ERROR);
    01058                         if (SwapColors)
    01059                                 ilSwapColours();
    01060                         if (TempImage->Data != OldData) {
    01061                                 ifree( TempImage->Data );
    01062                                 TempImage->Data = OldData;
    01063                         }
    01064                         if (TempImage != iCurImage)
    01065                                 ilCloseImage(TempImage);
    01066                         return IL_FALSE;
    01067                 }
    01068         }
    01069
    01070         if (SwapColors)
    01071                 ilSwapColours();
    01072
    01073         if (TempImage->Data != OldData) {
    01074                 ifree(TempImage->Data);
    01075                 TempImage->Data = OldData;
    01076         }
    01077
    01078         if (TempImage != iCurImage)
    01079                 ilCloseImage(TempImage);
    01080
    01081         TIFFClose(File);
    01082
    01083         return IL_TRUE;
    01084 }
    01085
    01086 /*----------------------------------------------------------------------------*/
    01087 // Makes a neat date string for the date field.
    01088 // From http://www.awaresystems.be/imaging/tiff/tifftags/datetime.html :
    01089 // The format is: "YYYY:MM:DD HH:MM:SS", with hours like those on
    01090 // a 24-hour clock, and one space character between the date and the
    01091 // time. The length of the string, including the terminating NUL, is
    01092 // 20 bytes.)
    01093 char *iMakeString()
    01094 {
    01095         static char TimeStr[20];
    01096         time_t          Time;
    01097         struct tm       *CurTime;
    01098
    01099         imemclear(TimeStr, 20);
    01100
    01101         time(&Time);
    01102 #ifdef _WIN32
    01103         _tzset();
    01104 #endif
    01105         CurTime = localtime(&Time);
    01106
    01107         strftime(TimeStr, 20, "%Y:%m:%d %H:%M:%S", CurTime);
    01108
    01109         return TimeStr;
    01110 }
    01111
    01112 /*----------------------------------------------------------------------------*/
    01113
    01114 #endif//IL_NO_TIF