- Main Page
- Data Structures
- Files

- File List

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

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/03/2008
    00006 //
    00007 // Filename: src-IL/src/il_exr.c
    00008 //
    00009 // Description: Reads from and writes to an OpenEXR (.exr) file.
    00010 //                EXR specs available from http://www.openexr.com.
    00011 //                from
    00012 //
    00013 //-----------------------------------------------------------------------------
    00014
    00015
    00016 #include "il_internal.h"
    00017 #ifndef IL_NO_EXR
    00018 #include "il_exr.h"
    00019 #include <zlib.h>
    00020
    00021
    00023 ILboolean ilIsValidExr(ILconst_string FileName)
    00024 {
    00025         ILHANDLE        ExrFile;
    00026         ILboolean       bExr = IL_FALSE;
    00027
    00028         if (!iCheckExtension(FileName, IL_TEXT("exr"))) {
    00029                 ilSetError(IL_INVALID_EXTENSION);
    00030                 return bExr;
    00031         }
    00032
    00033         ExrFile = iopenr(FileName);
    00034         if (ExrFile == NULL) {
    00035                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00036                 return bExr;
    00037         }
    00038
    00039         bExr = ilIsValidExrF(ExrFile);
    00040         icloser(ExrFile);
    00041
    00042         return bExr;
    00043 }
    00044
    00045
    00047 ILboolean ilIsValidExrF(ILHANDLE File)
    00048 {
    00049         ILuint          FirstPos;
    00050         ILboolean       bRet;
    00051
    00052         iSetInputFile(File);
    00053         FirstPos = itell();
    00054         bRet = iIsValidExr();
    00055         iseek(FirstPos, IL_SEEK_SET);
    00056
    00057         return bRet;
    00058 }
    00059
    00060
    00062 ILboolean ilIsValidExrL(const void *Lump, ILuint Size)
    00063 {
    00064         iSetInputLump(Lump, Size);
    00065         return iIsValidExr();
    00066 }
    00067
    00068
    00069 // Internal function used to get the EXR header from the current file.
    00070 ILboolean iGetExrHead(EXRHEAD *Header)
    00071 {
    00072         Header->MagicNumber = GetLittleUInt();
    00073         Header->Version = GetLittleUInt();
    00074
    00075         return IL_TRUE;
    00076 }
    00077
    00078
    00079 // Internal function to get the header and check it.
    00080 ILboolean iIsValidExr()
    00081 {
    00082         EXRHEAD Head;
    00083
    00084         if (!iGetExrHead(&Head))
    00085                 return IL_FALSE;
    00086         iseek(-(ILint)sizeof(EXRHEAD), IL_SEEK_CUR);
    00087
    00088         return iCheckExr(&Head);
    00089 }
    00090
    00091
    00092 // Internal function used to check if the HEADER is a valid EXR header.
    00093 ILboolean iCheckExr(EXRHEAD *Header)
    00094 {
    00095         // The file magic number (signature) is 0x76, 0x2f, 0x31, 0x01
    00096         if (Header->MagicNumber != 0x01312F76)
    00097                 return IL_FALSE;
    00098         // The only valid version so far is version 2.  The upper value has
    00099         //  to do with tiling.
    00100         if (Header->Version != 0x002 && Header->Version != 0x202)
    00101                 return IL_FALSE;
    00102
    00103         return IL_TRUE;
    00104 }
    00105
    00106
    00108 ILboolean ilLoadExr(ILconst_string FileName)
    00109 {
    00110         ILHANDLE        ExrFile;
    00111         ILboolean       bExr = IL_FALSE;
    00112
    00113         ExrFile = iopenr(FileName);
    00114         if (ExrFile == NULL) {
    00115                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00116                 return bExr;
    00117         }
    00118
    00119         bExr = ilLoadExrF(ExrFile);
    00120         icloser(ExrFile);
    00121
    00122         return bExr;
    00123 }
    00124
    00125
    00127 ILboolean ilLoadExrF(ILHANDLE File)
    00128 {
    00129         ILuint          FirstPos;
    00130         ILboolean       bRet;
    00131
    00132         iSetInputFile(File);
    00133         FirstPos = itell();
    00134         bRet = iLoadExrInternal();
    00135         iseek(FirstPos, IL_SEEK_SET);
    00136
    00137         return bRet;
    00138 }
    00139
    00140
    00142 ILboolean ilLoadExrL(const void *Lump, ILuint Size)
    00143 {
    00144         iSetInputLump(Lump, Size);
    00145         return iLoadExrInternal();
    00146 }
    00147
    00148
    00149 ILboolean iExrReadString(char *String, ILuint Length)
    00150 {
    00151         ILuint  i;
    00152
    00153         if (String == NULL) {
    00154                 ilSetError(IL_INTERNAL_ERROR);
    00155                 return IL_FALSE;
    00156         }
    00157
    00158         for (i = 0; i < Length; i++) {
    00159                 String[i] = igetc();
    00160                 if (String[i] == 0)
    00161                         break;
    00162         }
    00163
    00164         // Error if we have already hit the end of the file.
    00165         if (ieof()) {
    00166                 ilSetError(IL_FILE_READ_ERROR);
    00167                 return IL_FALSE;
    00168         }
    00169
    00170         // Will never get to this point if there is a proper terminator (NULL).
    00171         if (i == Length) {
    00172                 ilSetError(IL_INVALID_FILE_HEADER);
    00173                 return IL_FALSE;
    00174         }
    00175
    00176         return IL_TRUE;
    00177 }
    00178
    00179
    00180 // Internal function used to load the EXR.
    00181 ILboolean iLoadExrInternal()
    00182 {
    00183         EXRHEAD         Header;
    00184         ILubyte         Attribute[32], AttType[32], ChanOrder[4], ChanName[32];
    00185         ILuint          AttSize, i, j, c, Pos;
    00186         ILint           NumChannels = -1, PixType = -1, Compression = -1;
    00187         ILuint          PLinear, XSampling, YSampling, Width = 0, Height = 0, XMin, YMin;
    00188         ILboolean       Tiled;
    00189         ILuint          *LineOffsets;  //@TODO: Change this to something guaranteed to be 64-bit and compatible across platforms.
    00190         ILint           ChanOffset[4] = {-1,-1,-1,-1};
    00191         ILenum          Format, Type;
    00192
    00193         if (iCurImage == NULL) {
    00194                 ilSetError(IL_ILLEGAL_OPERATION);
    00195                 return IL_FALSE;
    00196         }
    00197
    00198         if (!iGetExrHead(&Header))
    00199                 return IL_FALSE;
    00200         if (!iCheckExr(&Header)) {
    00201                 ilSetError(IL_INVALID_FILE_HEADER);
    00202                 return IL_FALSE;
    00203         }
    00204
    00205         // Check whether tiling is used.
    00206         Tiled = (Header.Version == 0x202) ? IL_TRUE : IL_FALSE;
    00207         if (Tiled) {  //@TODO: Support tiled files.
    00208                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00209                 return IL_FALSE;
    00210         }
    00211
    00212         // Read in the "header", which consists of a list of attributes.
    00213         while (!ieof()) {
    00214                 // Each attribute name is 1 to 31 characters (NULL-terminated)
    00215                 if (!iExrReadString(Attribute, 32))
    00216                         return IL_FALSE;  // Error is already set.
    00217
    00218                 if (Attribute[0] == 0)  // Signals end of attribute list.
    00219                         break;
    00220
    00221                 // Each of the if statements below uses these.
    00222                 if (!iExrReadString(AttType, 32))  // Read the attribute type (up to 31 bytes plus NULL).
    00223                         return IL_FALSE;
    00224                 AttSize = GetLittleUInt();  // Get the attribute size.
    00225                 if (AttSize == 0) {
    00226                         ilSetError(IL_INVALID_FILE_HEADER);
    00227                         return IL_FALSE;
    00228                 }
    00229
    00230                 Pos = itell();  // Keep track of the position before the attribute is read.
    00231
    00232                 if (!strncmp(Attribute, "channels", strlen("channels"))) {
    00233                         if (strncmp(AttType, "chlist", strlen("chlist"))) {  // Only can be "chlist" for "channels".
    00234                                 ilSetError(IL_INVALID_FILE_HEADER);
    00235                                 return IL_FALSE;
    00236                         }
    00237
    00238                         Pos = itell();  // Need to make sure that the attribute size is correct.
    00239
    00240                         //@TODO: Should this be AttSize-2?
    00241                         for (i = 0; i <= AttSize-1; ) {  // Increased inside the loop.
    00242                                 if (!iExrReadString(ChanName, 32))  // Channels are named separately.
    00243                                         return IL_FALSE;
    00244
    00245                                 if (ChanName[0] == 0)  // Ending the channel list
    00246                                         break;
    00247
    00248                                 // Add to the number of channels found.
    00249                                 if (NumChannels == -1)
    00250                                         NumChannels = 1;
    00251                                 else
    00252                                         NumChannels++;
    00253
    00254                                 if (NumChannels > 4) {  // We cannot support more than 4 channels in a file right now.
    00255                                         ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00256                                         return IL_FALSE;
    00257                                 }
    00258
    00259                                 // R, G, B are stored in the first byte, and that's it.  Anything else is invalid for our use.
    00260                                 //@TODO: Make this not so!
    00261                                 if (ChanName[0] == 'R' || ChanName[0] == 'G' || ChanName[0] == 'B' || ChanName[0] == 'A') {
    00262                                         // ChanOrder is where we're going to keep this "truncated" information.
    00263                                         ChanOrder[NumChannels-1] = ChanName[0];
    00264                                 }
    00265                                 else {
    00266                                         ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00267                                         return IL_FALSE;
    00268                                 }
    00269
    00270                                 if (PixType == -1)  // Not yet initialized
    00271                                         PixType = GetLittleUInt();
    00272                                 else {  //@TODO: We cannot handle formats with differing storage types for each channel.
    00273                                         if (PixType != GetLittleUInt()) {
    00274                                                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00275                                                 return IL_FALSE;
    00276                                         }
    00277                                 }
    00278
    00279                                 //@TODO: pLinear, not sure what it does.
    00280                                 PLinear = igetc();
    00281                                 if (PLinear != 0 && PLinear != 1) {  // Must be either 0 or 1
    00282                                         ilSetError(IL_INVALID_FILE_HEADER);
    00283                                         return IL_FALSE;
    00284                                 }
    00285
    00286                                 iseek(3, IL_SEEK_CUR);  // Reserved values
    00287                                 //@TODO: Find out what these next two values are used for.
    00288                                 XSampling = GetLittleUInt();  // No information in the specs
    00289                                 YSampling = GetLittleUInt();  // Same as above
    00290
    00291                                 i += (strlen(ChanName) + 1 + 16);  // +1 for the NULL character
    00292                         }
    00293                 }
    00294
    00295                 else if (!strncmp(Attribute, "dataWindow", strlen("dataWindow"))) {
    00296                         if (strncmp(AttType, "box2i", strlen("box2i"))) {  // Only can be "box2i" for "dataWindow".
    00297                                 ilSetError(IL_INVALID_FILE_HEADER);
    00298                                 return IL_FALSE;
    00299                         }
    00300
    00301                         XMin = GetLittleUInt();
    00302                         YMin = GetLittleUInt();
    00303                         Width = GetLittleUInt();
    00304                         Height = GetLittleUInt();
    00305
    00306                         // XMin and YMin are normally 0, but they can be > 0 (but < Width/Height).
    00307                         if (XMin >= Width || YMin >= Height) {
    00308                                 ilSetError(IL_INVALID_FILE_HEADER);
    00309                                 return IL_FALSE;
    00310                         }
    00311                         Width = Width - XMin;    // Again, XMin/YMin should normally be 0,
    00312                         Height = Height - YMin;  //  but we will not assume.
    00313                 }
    00314
    00315                 else if (!strncmp(Attribute, "compression", strlen("compression"))) {
    00316                         if (strncmp(AttType, "compression", strlen("compression"))) {  // Only can be "compression" for "compression".
    00317                                 ilSetError(IL_INVALID_FILE_HEADER);
    00318                                 return IL_FALSE;
    00319                         }
    00320
    00321                         if (Compression == -1)  // Has not been initialized
    00322                                 Compression = igetc();
    00323                         else {
    00324                                 if (Compression != igetc()) {  //@TODO: Cannot deal with multiple compression formats.
    00325                                         ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00326                                         return IL_FALSE;
    00327                                 }
    00328                         }
    00329                 }
    00330
    00331                 else {  // We do not care about this attribute right now.
    00332                         iseek(AttSize, IL_SEEK_CUR);  // Just skip it for now (AttSize bytes).
    00333                 }
    00334
    00335                 if (itell() - Pos != AttSize) {  // The attribute size given does not match with the data.
    00336                         ilSetError(IL_INVALID_FILE_HEADER);
    00337                         return IL_FALSE;
    00338                 }
    00339         }
    00340
    00341         if (Width == 0 || Height == 0 || NumChannels == -1) {  // These need to be initialized.
    00342                 ilSetError(IL_INVALID_FILE_HEADER);
    00343                 return IL_FALSE;
    00344         }
    00345
    00346
    00347         switch (Compression)
    00348         {
    00349                 case EXR_NO_COMPRESSION:
    00350                         break;
    00351
    00352                 default:  // Unknown or unsupported compression format
    00353                         ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00354                         return IL_FALSE;
    00355         }
    00356
    00357         if (!ExrGetFormatType(&Format, &Type, ChanOrder))
    00358                 return IL_FALSE;
    00359
    00360         // This format only supports depths of 1.
    00361         ilTexImage(Width, Height, 1, 3, Format, Type, NULL);  //@TODO: NumChannels will not always be 3.
    00362
    00363         LineOffsets = ialloc(iCurImage->Height * sizeof(ILuint));  // Should always be sizeof(ILuint) == 4
    00364         if (LineOffsets == NULL)
    00365                 return IL_FALSE;
    00366
    00367         // Read the line offset table
    00368         for (i = 0; i < iCurImage->Height; i++) {
    00369                 //@TODO: The line offset table has 64-bit integers, but I am truncating them to 32-bits.
    00370                 LineOffsets[i] = GetLittleUInt();
    00371                 iseek(4, IL_SEEK_CUR);  // Dropping the higher 4 bytes right now.
    00372                 if (LineOffsets[i] >= iCurImage->Height) {
    00373                         ilSetError(IL_INVALID_FILE_HEADER);
    00374                         ifree(LineOffsets);
    00375                         return IL_FALSE;
    00376                 }
    00377         }
    00378
    00379         // Initialize any missing channels to 0.
    00380         memset(iCurImage->Data, 0, iCurImage->SizeOfData);
    00381
    00382
    00383         for (i = 0; i < iCurImage->Height; i++) {
    00384                 iseek(LineOffsets[i], IL_SEEK_SET);
    00385                 for (c = 0; c < iCurImage->Bpp; c++) {
    00386                         if (ChanOffset[c] != -1) {  // Channel not initialized.
    00387                                 for (j = 0; j < iCurImage->Width; j++) {
    00388                                         iCurImage->Data[i * iCurImage->Bps + j * iCurImage->Bpp + ChanOffset[c]] = GetLittleUInt();  //@TODO: Not even close to having all data formats possible.
    00389                                 }
    00390                         }
    00391                 }
    00392         }
    00393
    00394
    00395
    00396
    00397
    00398         ifree(LineOffsets);
    00399
    00400         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;  // Correct?
    00401         ilFixImage();
    00402
    00403         return IL_TRUE;
    00404 }
    00405
    00406
    00407 ILboolean ExrGetFormatType(ILuint *Format, ILuint *Type, ILubyte *ChanOrder)
    00408 {
    00409         switch (*Type)
    00410         {
    00411                 case EXR_UINT:
    00412                         *Type = IL_UNSIGNED_INT;
    00413                         break;
    00414
    00415                 case EXR_HALF:
    00416                         *Type = IL_HALF;
    00417                         break;
    00418
    00419                 case EXR_FLOAT:
    00420                         *Type = IL_FLOAT;
    00421                         break;
    00422
    00423                 default:
    00424                         ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00425                         return IL_FALSE;
    00426         }
    00427
    00428         //@TODO: Do other formats.
    00429         *Format = IL_RGB;
    00430
    00431         return IL_TRUE;
    00432 }
    00433
    00434
    00435 #endif//IL_NO_EXR