- Main Page
- Data Structures
- Files

- File List

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

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/06/2009
    00006 //
    00007 // Filename: src-IL/src/il_sun.c
    00008 //
    00009 // Description: Reads from a Sun RAS file.  Specifications available from
    00010 //                              http://www.fileformat.info/format/sunraster/egff.htm.
    00011 //
    00012 //-----------------------------------------------------------------------------
    00013
    00014
    00015 #include "il_internal.h"
    00016 #ifndef IL_NO_SUN
    00017 #include "il_bits.h"
    00018
    00019 ILboolean       iLoadSunInternal(void);
    00020 ILboolean       iIsValidSun(void);
    00021 ILuint          iSunGetRle(ILubyte *Data, ILuint Length);
    00022
    00023 typedef struct SUNHEAD
    00024 {
    00025         ILuint MagicNumber;      // Magic (identification) number
    00026         ILuint Width;            // Width of image in pixels
    00027         ILuint Height;           // Height of image in pixels
    00028         ILuint Depth;            // Number of bits per pixel
    00029         ILuint Length;           // Size of image data in bytes
    00030         ILuint Type;             // Type of raster file
    00031         ILuint ColorMapType;     // Type of color map
    00032         ILuint ColorMapLength;   // Size of the color map in bytes
    00033 } SUNHEAD;
    00034
    00035 // Data storage types
    00036 #define IL_SUN_OLD              0x00
    00037 #define IL_SUN_STANDARD 0x01
    00038 #define IL_SUN_BYTE_ENC 0x02
    00039 #define IL_SUN_RGB              0x03
    00040 #define IL_SUN_TIFF             0x04
    00041 #define IL_SUN_IFF              0x05
    00042 #define IL_SUN_EXPER    0xFFFF  // Experimental, not supported.
    00043
    00044 // Colormap types
    00045 #define IL_SUN_NO_MAP   0x00
    00046 #define IL_SUN_RGB_MAP  0x01
    00047 #define IL_SUN_RAW_MAP  0x02
    00048
    00049
    00051 ILboolean ilIsValidSun(ILconst_string FileName)
    00052 {
    00053         ILHANDLE        SunFile;
    00054         ILboolean       bSun = IL_FALSE;
    00055
    00056         if (!iCheckExtension(FileName, IL_TEXT("sun")) && !iCheckExtension(FileName, IL_TEXT("ras")) &&
    00057                 !iCheckExtension(FileName, IL_TEXT("im1")) && !iCheckExtension(FileName, IL_TEXT("im8")) &&
    00058                 !iCheckExtension(FileName, IL_TEXT("im24")) && !iCheckExtension(FileName, IL_TEXT("im32")) &&
    00059                 !iCheckExtension(FileName, IL_TEXT("rs"))) {  // Lots of names possible...
    00060                 ilSetError(IL_INVALID_EXTENSION);
    00061                 return bSun;
    00062         }
    00063
    00064         SunFile = iopenr(FileName);
    00065         if (SunFile == NULL) {
    00066                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00067                 return bSun;
    00068         }
    00069
    00070         bSun = ilIsValidSunF(SunFile);
    00071         icloser(SunFile);
    00072
    00073         return bSun;
    00074 }
    00075
    00076
    00078 ILboolean ilIsValidSunF(ILHANDLE File)
    00079 {
    00080         ILuint          FirstPos;
    00081         ILboolean       bRet;
    00082
    00083         iSetInputFile(File);
    00084         FirstPos = itell();
    00085         bRet = iIsValidSun();
    00086         iseek(FirstPos, IL_SEEK_SET);
    00087
    00088         return bRet;
    00089 }
    00090
    00091
    00093 ILboolean ilIsValidSunL(const void *Lump, ILuint Size)
    00094 {
    00095         iSetInputLump(Lump, Size);
    00096         return iIsValidSun();
    00097 }
    00098
    00099
    00100 // Internal function used to get the Sun header from the current file.
    00101 ILboolean iGetSunHead(SUNHEAD *Header)
    00102 {
    00103         Header->MagicNumber = GetBigUInt();
    00104         Header->Width = GetBigUInt();
    00105         Header->Height = GetBigUInt();
    00106         Header->Depth = GetBigUInt();
    00107         Header->Length = GetBigUInt();
    00108         Header->Type = GetBigUInt();
    00109         Header->ColorMapType = GetBigUInt();
    00110         Header->ColorMapLength = GetBigUInt();
    00111
    00112         return IL_TRUE;
    00113 }
    00114
    00115
    00116 // Internal function used to check if the HEADER is a valid SUN header.
    00117 ILboolean iCheckSun(SUNHEAD *Header)
    00118 {
    00119         if (Header->MagicNumber != 0x59A66A95)  // Magic number is always 0x59A66A95.
    00120                 return IL_FALSE;
    00121         if (Header->Width == 0 || Header->Height == 0)  // 0 dimensions are meaningless.
    00122                 return IL_FALSE;
    00123         // These are the only valid depths that I know of.
    00124         if (Header->Depth != 1 && Header->Depth != 8 && Header->Depth != 24 && Header->Depth != 32)
    00125                 return IL_FALSE;
    00126         if (Header->Type > IL_SUN_RGB)  //@TODO: Support further types.
    00127                 return IL_FALSE;
    00128         if (Header->ColorMapType > IL_SUN_RGB_MAP)  //@TODO: Find out more about raw map.
    00129                 return IL_FALSE;
    00130         // Color map cannot be 0 if there is a map indicated.
    00131         if (Header->ColorMapType > IL_SUN_NO_MAP && Header->ColorMapLength == 0)
    00132                 return IL_FALSE;
    00133         //@TODO: These wouldn't make sense.  Are they valid somehow?  Find out...
    00134         if ((Header->Depth == 1 || Header->Depth == 32) && Header->Type == IL_SUN_BYTE_ENC)
    00135                 return IL_FALSE;
    00136
    00137         return IL_TRUE;
    00138 }
    00139
    00140
    00141 // Internal function to get the header and check it.
    00142 ILboolean iIsValidSun()
    00143 {
    00144         SUNHEAD Head;
    00145
    00146         if (!iGetSunHead(&Head))
    00147                 return IL_FALSE;
    00148         iseek(-(ILint)sizeof(SUNHEAD), IL_SEEK_CUR);
    00149
    00150         return iCheckSun(&Head);
    00151 }
    00152
    00153
    00154 // Reads a Sun file
    00155 ILboolean ilLoadSun(ILconst_string FileName)
    00156 {
    00157         ILHANDLE        SunFile;
    00158         ILboolean       bSun = IL_FALSE;
    00159
    00160         SunFile = iopenr(FileName);
    00161         if (SunFile == NULL) {
    00162                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00163                 return bSun;
    00164         }
    00165
    00166         iSetInputFile(SunFile);
    00167
    00168         bSun = ilLoadSunF(SunFile);
    00169
    00170         icloser(SunFile);
    00171
    00172         return bSun;
    00173 }
    00174
    00175
    00177 ILboolean ilLoadSunF(ILHANDLE File)
    00178 {
    00179         ILuint          FirstPos;
    00180         ILboolean       bRet;
    00181
    00182         iSetInputFile(File);
    00183         FirstPos = itell();
    00184         bRet = iLoadSunInternal();
    00185         iseek(FirstPos, IL_SEEK_SET);
    00186
    00187         return bRet;
    00188 }
    00189
    00190
    00192 ILboolean ilLoadSunL(const void *Lump, ILuint Size)
    00193 {
    00194         iSetInputLump(Lump, Size);
    00195         return iLoadSunInternal();
    00196 }
    00197
    00198
    00199 ILboolean iLoadSunInternal(void)
    00200 {
    00201         SUNHEAD Header;
    00202         BITFILE *File;
    00203         ILuint  i, j, Padding, Offset, BytesRead;
    00204         ILubyte PaddingData[16];
    00205
    00206         if (iCurImage == NULL) {
    00207                 ilSetError(IL_ILLEGAL_OPERATION);
    00208                 return IL_FALSE;
    00209         }
    00210
    00211         //@TODO: Right now, iGetSunHead cannot fail.
    00212         if (!iGetSunHead(&Header) || !iCheckSun(&Header)) {
    00213                 ilSetError(IL_INVALID_FILE_HEADER);
    00214                 return IL_FALSE;
    00215         }
    00216
    00217         switch (Header.Depth)
    00218         {
    00219                 case 1:  //@TODO: Find a file to test this on.
    00220                         File = bfile(iGetFile());
    00221                         if (File == NULL)
    00222                                 return IL_FALSE;
    00223
    00224                         if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
    00225                                 return IL_FALSE;
    00226                         if (Header.ColorMapLength != 0) {
    00227                                 // Data should be an index into the color map, but the color map should only be RGB (6 bytes, 2 entries).
    00228                                 if (Header.ColorMapLength != 6) {
    00229                                         ilSetError(IL_INVALID_FILE_HEADER);
    00230                                         return IL_FALSE;
    00231                                 }
    00232                         }
    00233                         iCurImage->Pal.Palette = (ILubyte*)ialloc(6);  // Just need 2 entries in the color map.
    00234                         if (Header.ColorMapLength == 0) {  // Create the color map
    00235                                 iCurImage->Pal.Palette[0] = 0x00;  // Entry for black
    00236                                 iCurImage->Pal.Palette[1] = 0x00;
    00237                                 iCurImage->Pal.Palette[2] = 0x00;
    00238                                 iCurImage->Pal.Palette[3] = 0xFF;  // Entry for white
    00239                                 iCurImage->Pal.Palette[4] = 0xFF;
    00240                                 iCurImage->Pal.Palette[5] = 0xFF;
    00241                         }
    00242                         else {
    00243                                 iread(iCurImage->Pal.Palette, 1, 6);  // Read in the color map.
    00244                         }
    00245                         iCurImage->Pal.PalSize = 6;
    00246                         iCurImage->Pal.PalType = IL_PAL_RGB24;
    00247
    00248                         Padding = (16 - (iCurImage->Width % 16)) % 16;  // Has to be aligned on a 16-bit boundary.  The rest is padding.
    00249
    00250                         // Reads the bits
    00251                         for (i = 0; i < iCurImage->Height; i++) {
    00252                                 bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
    00253                                 //bseek(File, BitPadding, IL_SEEK_CUR);  //@TODO: This function does not work correctly.
    00254                                 bread(PaddingData, 1, Padding, File);  // Skip padding bits.
    00255                         }
    00256                         break;
    00257
    00258
    00259                 case 8:
    00260                         if (Header.ColorMapType == IL_SUN_NO_MAP) {  // Greyscale image
    00261                                 if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
    00262                                         return IL_FALSE;
    00263                         }
    00264                         else {  // Colour-mapped image
    00265                                 if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
    00266                                         return IL_FALSE;
    00267                                 iCurImage->Pal.Palette = (ILubyte*)ialloc(Header.ColorMapLength);  // Allocate color map.
    00268                                 if (iCurImage->Pal.Palette == NULL)
    00269                                         return IL_FALSE;
    00270                                 if (iread(iCurImage->Pal.Palette, 1, Header.ColorMapLength) != Header.ColorMapLength) {  // Read color map.
    00271                                         ilSetError(IL_FILE_READ_ERROR);
    00272                                         return IL_FALSE;
    00273                                 }
    00274
    00275                                 iCurImage->Pal.PalSize = Header.ColorMapLength;
    00276                                 iCurImage->Pal.PalType = IL_PAL_RGB24;
    00277                         }
    00278
    00279                         if (Header.Type != IL_SUN_BYTE_ENC) {  // Regular uncompressed image data
    00280                                 Padding = (2 - (iCurImage->Bps % 2)) % 2;  // Must be padded on a 16-bit boundary (2 bytes)
    00281                                 for (i = 0; i < Header.Height; i++) {
    00282                                         iread(iCurImage->Data + i * Header.Width, 1, iCurImage->Bps);
    00283                                         if (Padding)  // Only possible for padding to be 0 or 1.
    00284                                                 igetc();
    00285                                 }
    00286                         }
    00287                         else {  // RLE image data
    00288                                 for (i = 0; i < iCurImage->Height; i++) {
    00289                                         BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
    00290                                         if (BytesRead % 2)  // Each scanline must be aligned on a 2-byte boundary.
    00291                                                 igetc();  // Skip padding
    00292                                 }
    00293                         }
    00294                         break;
    00295
    00296                 case 24:
    00297                         if (Header.ColorMapLength > 0)  // Ignore any possible colormaps.
    00298                                 iseek(Header.ColorMapLength, IL_SEEK_CUR);
    00299
    00300                         if (Header.Type == IL_SUN_RGB) {
    00301                                 if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
    00302                                         return IL_FALSE;
    00303                         }
    00304                         else {
    00305                                 if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
    00306                                         return IL_FALSE;
    00307                         }
    00308
    00309                         if (Header.Type != IL_SUN_BYTE_ENC) {  // Regular uncompressed image data
    00310                                 Padding = (2 - (iCurImage->Bps % 2)) % 2;  // Must be padded on a 16-bit boundary (2 bytes)
    00311                                 for (i = 0; i < Header.Height; i++) {
    00312                                         iread(iCurImage->Data + i * Header.Width * 3, 1, iCurImage->Bps);
    00313                                         if (Padding)  // Only possible for padding to be 0 or 1.
    00314                                                 igetc();
    00315                                 }
    00316                         }
    00317                         else {  // RLE image data
    00318                                 for (i = 0; i < iCurImage->Height; i++) {
    00319                                         BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
    00320                                         if (BytesRead % 2)  // Each scanline must be aligned on a 2-byte boundary.
    00321                                                 igetc();  // Skip padding
    00322                                 }
    00323                         }
    00324
    00325                         break;
    00326
    00327                 case 32:
    00328                         if (Header.ColorMapLength > 0)  // Ignore any possible colormaps.
    00329                                 iseek(Header.ColorMapLength, IL_SEEK_CUR);
    00330
    00331                         if (Header.Type == IL_SUN_RGB) {
    00332                                 if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
    00333                                         return IL_FALSE;
    00334                         }
    00335                         else {
    00336                                 if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
    00337                                         return IL_FALSE;
    00338                         }
    00339
    00340                         // There is no padding at the end of each scanline.
    00341                         Offset = 0;
    00342                         for (i = 0; i < Header.Height; i++) {
    00343                                 for (j = 0; j < Header.Width; j++) {
    00344                                         igetc();  // There is a pad byte before each pixel.
    00345                                         iCurImage->Data[Offset]   = igetc();
    00346                                         iCurImage->Data[Offset+1] = igetc();
    00347                                         iCurImage->Data[Offset+2] = igetc();
    00348                                 }
    00349                         }
    00350                         break;
    00351
    00352
    00353                 default:  // Should have already been checked with iGetSunHead.
    00354                         return IL_FALSE;
    00355         }
    00356
    00357         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00358         return ilFixImage();
    00359 }
    00360
    00361
    00362 ILuint iSunGetRle(ILubyte *Data, ILuint Length)
    00363 {
    00364         ILuint  i = 0, j;
    00365         ILubyte Flag, Value;
    00366         ILuint  Count;
    00367
    00368         for (i = 0; i < Length; ) {
    00369                 Flag = igetc();
    00370                 if (Flag == 0x80) {  // Run follows (or 1 byte of 0x80)
    00371                         Count = igetc();
    00372                         if (Count == 0) {  // 1 pixel of value (0x80)
    00373                                 *Data = 0x80;
    00374                                 Data++;
    00375                                 i++;
    00376                         }
    00377                         else {  // Here we have a run.
    00378                                 Value = igetc();
    00379                                 Count++;  // Should really be Count+1
    00380                                 for (j = 0; j < Count && i + j < Length; j++, Data++) {
    00381                                         *Data = Value;
    00382                                 }
    00383                                 i += Count;
    00384                         }
    00385                 }
    00386                 else {  // 1 byte of this value (cannot be 0x80)
    00387                         *Data = Flag;
    00388                         Data++;
    00389                         i++;
    00390                 }
    00391         }
    00392
    00393         return i;
    00394 }
    00395
    00396
    00397 #endif//IL_NO_SUN
    00398