il_sgi.c
Upload User: wmy0603
Upload Date: 2022-05-02
Package Size: 1808k
Code Size: 18k
Development Platform:

Visual C++

  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_sgi.c
  8. //
  9. // Description: Reads and writes Silicon Graphics Inc. (.sgi) files.
  10. //
  11. //-----------------------------------------------------------------------------
  12. #include "il_internal.h"
  13. #ifndef IL_NO_SGI
  14. #include "il_sgi.h"
  15. #include "il_manip.h"
  16. #include <limits.h>
  17. static char *FName = NULL;
  18. /*----------------------------------------------------------------------------*/
  19. /*! Checks if the file specified in FileName is a valid .sgi file. */
  20. ILboolean ilIsValid_SGI(ILconst_string FileName)
  21. {
  22. ILHANDLE SgiFile;
  23. ILboolean bSgi = IL_FALSE;
  24. if (!iCheckExtension(FileName, IL_TEXT("sgi"))) {
  25. ilSetError(IL_INVALID_EXTENSION);
  26. return bSgi;
  27. }
  28. FName = (char*)FileName;
  29. SgiFile = iopenr(FileName);
  30. if (SgiFile == NULL) {
  31. ilSetError(IL_COULD_NOT_OPEN_FILE);
  32. return bSgi;
  33. }
  34. bSgi = ilIsValidF_SGI(SgiFile);
  35. icloser(SgiFile);
  36. return bSgi;
  37. }
  38. /*----------------------------------------------------------------------------*/
  39. /*! Checks if the ILHANDLE contains a valid .sgi file at the current position.*/
  40. ILboolean ilIsValidF_SGI(ILHANDLE File)
  41. {
  42. ILuint FirstPos;
  43. ILboolean bRet;
  44. iSetInputFile(File);
  45. FirstPos = itell();
  46. bRet = iIsValidSgi();
  47. iseek(FirstPos, IL_SEEK_SET);
  48. return bRet;
  49. }
  50. /*----------------------------------------------------------------------------*/
  51. //! Checks if Lump is a valid .sgi lump.
  52. ILboolean ilIsValidL_SGI(const void *Lump, ILuint Size)
  53. {
  54. FName = NULL;
  55. iSetInputLump(Lump, Size);
  56. return iIsValidSgi();
  57. }
  58. /*----------------------------------------------------------------------------*/
  59. // Internal function used to get the .sgi header from the current file.
  60. ILboolean iGetSgiHead(iSgiHeader *Header)
  61. {
  62. Header->MagicNum = GetBigUShort();
  63. Header->Storage = (ILbyte)igetc();
  64. Header->Bpc = (ILbyte)igetc();
  65. Header->Dim = GetBigUShort();
  66. Header->XSize = GetBigUShort();
  67. Header->YSize = GetBigUShort();
  68. Header->ZSize = GetBigUShort();
  69. Header->PixMin = GetBigInt();
  70. Header->PixMax = GetBigInt();
  71. Header->Dummy1 = GetBigInt();
  72. iread(Header->Name, 1, 80);
  73. Header->ColMap = GetBigInt();
  74. iread(Header->Dummy, 1, 404);
  75. return IL_TRUE;
  76. }
  77. /*----------------------------------------------------------------------------*/
  78. /* Internal function to get the header and check it. */
  79. ILboolean iIsValidSgi()
  80. {
  81. iSgiHeader Head;
  82. if (!iGetSgiHead(&Head))
  83. return IL_FALSE;
  84. iseek(-(ILint)sizeof(iSgiHeader), IL_SEEK_CUR);  // Go ahead and restore to previous state
  85. return iCheckSgi(&Head);
  86. }
  87. /*----------------------------------------------------------------------------*/
  88. /* Internal function used to check if the HEADER is a valid .sgi header. */
  89. ILboolean iCheckSgi(iSgiHeader *Header)
  90. {
  91. if (Header->MagicNum != SGI_MAGICNUM)
  92. return IL_FALSE;
  93. if (Header->Storage != SGI_RLE && Header->Storage != SGI_VERBATIM)
  94. return IL_FALSE;
  95. if (Header->Bpc == 0 || Header->Dim == 0)
  96. return IL_FALSE;
  97. if (Header->XSize == 0 || Header->YSize == 0 || Header->ZSize == 0)
  98. return IL_FALSE;
  99. return IL_TRUE;
  100. }
  101. /*----------------------------------------------------------------------------*/
  102. /*! Reads a SGI file */
  103. ILboolean ilLoad_SGI(ILconst_string FileName)
  104. {
  105. ILHANDLE SgiFile;
  106. ILboolean bSgi = IL_FALSE;
  107. SgiFile = iopenr(FileName);
  108. if (SgiFile == NULL) {
  109. ilSetError(IL_COULD_NOT_OPEN_FILE);
  110. return bSgi;
  111. }
  112. bSgi = ilLoadF_SGI(SgiFile);
  113. icloser(SgiFile);
  114. return bSgi;
  115. }
  116. /*----------------------------------------------------------------------------*/
  117. /*! Reads an already-opened SGI file */
  118. ILboolean ilLoadF_SGI(ILHANDLE File)
  119. {
  120. ILuint FirstPos;
  121. ILboolean bRet;
  122. iSetInputFile(File);
  123. FirstPos = itell();
  124. bRet = iLoadSgiInternal();
  125. iseek(FirstPos, IL_SEEK_SET);
  126. return bRet;
  127. }
  128. /*----------------------------------------------------------------------------*/
  129. /*! Reads from a memory "lump" that contains a SGI image */
  130. ILboolean ilLoadL_SGI(const void *Lump, ILuint Size)
  131. {
  132. iSetInputLump(Lump, Size);
  133. return iLoadSgiInternal();
  134. }
  135. /*----------------------------------------------------------------------------*/
  136. /* Internal function used to load the SGI image */
  137. ILboolean iLoadSgiInternal()
  138. {
  139. iSgiHeader Header;
  140. ILboolean bSgi;
  141. if (iCurImage == NULL) {
  142. ilSetError(IL_ILLEGAL_OPERATION);
  143. return IL_FALSE;
  144. }
  145. if (!iGetSgiHead(&Header))
  146. return IL_FALSE;
  147. if (!iCheckSgi(&Header)) {
  148. ilSetError(IL_INVALID_FILE_HEADER);
  149. return IL_FALSE;
  150. }
  151. // Bugfix for #1060946.
  152. //  The ZSize should never really be 2 by the specifications.  Some
  153. //  application is outputting these, and it looks like the ZSize
  154. //  should really be 1.
  155. if (Header.ZSize == 2)
  156. Header.ZSize = 1;
  157. if (Header.Storage == SGI_RLE) {  // RLE
  158. bSgi = iReadRleSgi(&Header);
  159. }
  160. else {  // Non-RLE  //(Header.Storage == SGI_VERBATIM)
  161. bSgi = iReadNonRleSgi(&Header);
  162. }
  163. if (!bSgi)
  164. return IL_FALSE;
  165. return ilFixImage();
  166. }
  167. /*----------------------------------------------------------------------------*/
  168. ILboolean iReadRleSgi(iSgiHeader *Head)
  169. {
  170. #ifdef __LITTLE_ENDIAN__
  171. ILuint ixTable;
  172. #endif
  173. ILuint  ChanInt = 0;
  174. ILuint   ixPlane, ixHeight,ixPixel, RleOff, RleLen;
  175. ILuint *OffTable=NULL, *LenTable=NULL, TableSize, Cur;
  176. ILubyte **TempData=NULL;
  177. if (!iNewSgi(Head))
  178. return IL_FALSE;
  179. TableSize = Head->YSize * Head->ZSize;
  180. OffTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
  181. LenTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
  182. if (OffTable == NULL || LenTable == NULL)
  183. goto cleanup_error;
  184. if (iread(OffTable, TableSize * sizeof(ILuint), 1) != 1)
  185. goto cleanup_error;
  186. if (iread(LenTable, TableSize * sizeof(ILuint), 1) != 1)
  187. goto cleanup_error;
  188. #ifdef __LITTLE_ENDIAN__
  189. // Fix the offset/len table (it's big endian format)
  190. for (ixTable = 0; ixTable < TableSize; ixTable++) {
  191. iSwapUInt(OffTable + ixTable);
  192. iSwapUInt(LenTable + ixTable);
  193. }
  194. #endif //__LITTLE_ENDIAN__
  195. // We have to create a temporary buffer for the image, because SGI
  196. // images are plane-separated.
  197. TempData = (ILubyte**)ialloc(Head->ZSize * sizeof(ILubyte*));
  198. if (TempData == NULL)
  199. goto cleanup_error;
  200. imemclear(TempData, Head->ZSize * sizeof(ILubyte*));  // Just in case ialloc fails then cleanup_error.
  201. for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
  202. TempData[ixPlane] = (ILubyte*)ialloc(Head->XSize * Head->YSize * Head->Bpc);
  203. if (TempData[ixPlane] == NULL)
  204. goto cleanup_error;
  205. }
  206. // Read the Planes into the temporary memory
  207. for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
  208. for (ixHeight = 0, Cur = 0; ixHeight < Head->YSize;
  209. ixHeight++, Cur += Head->XSize * Head->Bpc) {
  210. RleOff = OffTable[ixHeight + ixPlane * Head->YSize];
  211. RleLen = LenTable[ixHeight + ixPlane * Head->YSize];
  212. // Seeks to the offset table position
  213. iseek(RleOff, IL_SEEK_SET);
  214. if (iGetScanLine((TempData[ixPlane]) + (ixHeight * Head->XSize * Head->Bpc),
  215. Head, RleLen) != Head->XSize * Head->Bpc) {
  216. ilSetError(IL_ILLEGAL_FILE_VALUE);
  217. goto cleanup_error;
  218. }
  219. }
  220. }
  221. // DW: Removed on 05/25/2002.
  222. /*// Check if an alphaplane exists and invert it
  223. if (Head->ZSize == 4) {
  224. for (ixPixel=0; (ILint)ixPixel<Head->XSize * Head->YSize; ixPixel++) {
  225.   TempData[3][ixPixel] = TempData[3][ixPixel] ^ 255;
  226.   }
  227. }*/
  228. // Assemble the image from its planes
  229. for (ixPixel = 0; ixPixel < iCurImage->SizeOfData;
  230. ixPixel += Head->ZSize * Head->Bpc, ChanInt += Head->Bpc) {
  231. for (ixPlane = 0; (ILint)ixPlane < Head->ZSize * Head->Bpc; ixPlane += Head->Bpc) {
  232. iCurImage->Data[ixPixel + ixPlane] = TempData[ixPlane][ChanInt];
  233. if (Head->Bpc == 2)
  234. iCurImage->Data[ixPixel + ixPlane + 1] = TempData[ixPlane][ChanInt + 1];
  235. }
  236. }
  237. #ifdef __LITTLE_ENDIAN__
  238. if (Head->Bpc == 2)
  239. sgiSwitchData(iCurImage->Data, iCurImage->SizeOfData);
  240. #endif
  241. ifree(OffTable);
  242. ifree(LenTable);
  243. for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
  244. ifree(TempData[ixPlane]);
  245. }
  246. ifree(TempData);
  247. return IL_TRUE;
  248. cleanup_error:
  249. ifree(OffTable);
  250. ifree(LenTable);
  251. if (TempData) {
  252. for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
  253. ifree(TempData[ixPlane]);
  254. }
  255. ifree(TempData);
  256. }
  257. return IL_FALSE;
  258. }
  259. /*----------------------------------------------------------------------------*/
  260. ILint iGetScanLine(ILubyte *ScanLine, iSgiHeader *Head, ILuint Length)
  261. {
  262. ILushort Pixel, Count;  // For current pixel
  263. ILuint  BppRead = 0, CurPos = 0, Bps = Head->XSize * Head->Bpc;
  264. while (BppRead < Length && CurPos < Bps)
  265. {
  266. Pixel = 0;
  267. if (iread(&Pixel, Head->Bpc, 1) != 1)
  268. return -1;
  269. #ifndef __LITTLE_ENDIAN__
  270. iSwapUShort(&Pixel);
  271. #endif
  272. if (!(Count = (Pixel & 0x7f)))  // If 0, line ends
  273. return CurPos;
  274. if (Pixel & 0x80) {  // If top bit set, then it is a "run"
  275. if (iread(ScanLine, Head->Bpc, Count) != Count)
  276. return -1;
  277. BppRead += Head->Bpc * Count + Head->Bpc;
  278. ScanLine += Head->Bpc * Count;
  279. CurPos += Head->Bpc * Count;
  280. }
  281. else {
  282. if (iread(&Pixel, Head->Bpc, 1) != 1)
  283. return -1;
  284. #ifndef __LITTLE_ENDIAN__
  285. iSwapUShort(&Pixel);
  286. #endif
  287. if (Head->Bpc == 1) {
  288. while (Count--) {
  289. *ScanLine = (ILubyte)Pixel;
  290. ScanLine++;
  291. CurPos++;
  292. }
  293. }
  294. else {
  295. while (Count--) {
  296. *(ILushort*)ScanLine = Pixel;
  297. ScanLine += 2;
  298. CurPos += 2;
  299. }
  300. }
  301. BppRead += Head->Bpc + Head->Bpc;
  302. }
  303. }
  304. return CurPos;
  305. }
  306. /*----------------------------------------------------------------------------*/
  307. // Much easier to read - just assemble from planes, no decompression
  308. ILboolean iReadNonRleSgi(iSgiHeader *Head)
  309. {
  310. ILuint i, c;
  311. // ILint ChanInt = 0; Unused
  312. ILint  ChanSize;
  313. ILboolean Cache = IL_FALSE;
  314. if (!iNewSgi(Head)) {
  315. return IL_FALSE;
  316. }
  317. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST) {
  318. Cache = IL_TRUE;
  319. ChanSize = Head->XSize * Head->YSize * Head->Bpc;
  320. iPreCache(ChanSize);
  321. }
  322. for (c = 0; c < iCurImage->Bpp; c++) {
  323. for (i = c; i < iCurImage->SizeOfData; i += iCurImage->Bpp) {
  324. if (iread(iCurImage->Data + i, 1, 1) != 1) {
  325. if (Cache)
  326. iUnCache();
  327. return IL_FALSE;
  328. }
  329. }
  330. }
  331. if (Cache)
  332. iUnCache();
  333. return IL_TRUE;
  334. }
  335. /*----------------------------------------------------------------------------*/
  336. void sgiSwitchData(ILubyte *Data, ILuint SizeOfData)
  337. {
  338. ILubyte Temp;
  339. ILuint i;
  340. #ifdef ALTIVEC_GCC
  341. i = 0;
  342. union {
  343. vector unsigned char vec;
  344. vector unsigned int load;
  345. }inversion_vector;
  346. inversion_vector.load  = (vector unsigned int)
  347. {0x01000302,0x05040706,0x09080B0A,0x0D0C0F0E};
  348. while( i <= SizeOfData-16 ) {
  349. vector unsigned char data = vec_ld(i,Data);
  350. vec_perm(data,data,inversion_vector.vec);
  351. vec_st(data,i,Data);
  352. i+=16;
  353. }
  354. SizeOfData -= i;
  355. #endif
  356. for (i = 0; i < SizeOfData; i += 2) {
  357. Temp = Data[i];
  358. Data[i] = Data[i+1];
  359. Data[i+1] = Temp;
  360. }
  361. return;
  362. }
  363. /*----------------------------------------------------------------------------*/
  364. // Just an internal convenience function for reading SGI files
  365. ILboolean iNewSgi(iSgiHeader *Head)
  366. {
  367. if (!ilTexImage(Head->XSize, Head->YSize, Head->Bpc, (ILubyte)Head->ZSize, 0, IL_UNSIGNED_BYTE, NULL)) {
  368. return IL_FALSE;
  369. }
  370. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  371. switch (Head->ZSize)
  372. {
  373. case 1:
  374. iCurImage->Format = IL_LUMINANCE;
  375. break;
  376. /*case 2:
  377. iCurImage->Format = IL_LUMINANCE_ALPHA; 
  378. break;*/
  379. case 3:
  380. iCurImage->Format = IL_RGB;
  381. break;
  382. case 4:
  383. iCurImage->Format = IL_RGBA;
  384. break;
  385. default:
  386. ilSetError(IL_ILLEGAL_FILE_VALUE);
  387. return IL_FALSE;
  388. }
  389. switch (Head->Bpc)
  390. {
  391. case 1:
  392. if (Head->PixMin < 0)
  393. iCurImage->Type = IL_BYTE;
  394. else
  395. iCurImage->Type = IL_UNSIGNED_BYTE;
  396. break;
  397. case 2:
  398. if (Head->PixMin < 0)
  399. iCurImage->Type = IL_SHORT;
  400. else
  401. iCurImage->Type = IL_UNSIGNED_SHORT;
  402. break;
  403. default:
  404. ilSetError(IL_ILLEGAL_FILE_VALUE);
  405. return IL_FALSE;
  406. }
  407. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  408. return IL_TRUE;
  409. }
  410. /*----------------------------------------------------------------------------*/
  411. //! Writes a SGI file
  412. ILboolean ilSave_SGI(const ILstring FileName)
  413. {
  414. ILHANDLE SgiFile;
  415. ILuint SgiSize;
  416. if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
  417. if (iFileExists(FileName)) {
  418. ilSetError(IL_FILE_ALREADY_EXISTS);
  419. return IL_FALSE;
  420. }
  421. }
  422. SgiFile = iopenw(FileName);
  423. if (SgiFile == NULL) {
  424. ilSetError(IL_COULD_NOT_OPEN_FILE);
  425. return IL_FALSE;
  426. }
  427. SgiSize = ilSaveF_SGI(SgiFile);
  428. iclosew(SgiFile);
  429. if (SgiSize == 0)
  430. return IL_FALSE;
  431. return IL_TRUE;
  432. }
  433. //! Writes a Sgi to an already-opened file
  434. ILuint ilSaveF_SGI(ILHANDLE File)
  435. {
  436. ILuint Pos;
  437. iSetOutputFile(File);
  438. Pos = itellw();
  439. if (iSaveSgiInternal() == IL_FALSE)
  440. return 0;  // Error occurred
  441. return itellw() - Pos;  // Return the number of bytes written.
  442. }
  443. //! Writes a Sgi to a memory "lump"
  444. ILuint ilSaveL_SGI(void *Lump, ILuint Size)
  445. {
  446. ILuint Pos;
  447. iSetOutputLump(Lump, Size);
  448. Pos = itellw();
  449. if (iSaveSgiInternal() == IL_FALSE)
  450. return 0;  // Error occurred
  451. return itellw() - Pos;  // Return the number of bytes written.
  452. }
  453. ILenum DetermineSgiType(ILenum Type)
  454. {
  455. if (Type > IL_UNSIGNED_SHORT) {
  456. if (iCurImage->Type == IL_INT)
  457. return IL_SHORT;
  458. return IL_UNSIGNED_SHORT;
  459. }
  460. return Type;
  461. }
  462. /*----------------------------------------------------------------------------*/
  463. // Rle does NOT work yet.
  464. // Internal function used to save the Sgi.
  465. ILboolean iSaveSgiInternal()
  466. {
  467. ILuint i, c;
  468. ILboolean Compress;
  469. ILimage *Temp = iCurImage;
  470. ILubyte *TempData;
  471. if (iCurImage == NULL) {
  472. ilSetError(IL_ILLEGAL_OPERATION);
  473. return IL_FALSE;
  474. }
  475. if (iCurImage->Format != IL_LUMINANCE
  476.     //while the sgi spec doesn't directly forbid rgb files with 2
  477.     //channels, they are quite uncommon and most apps don't support
  478.     //them. so convert lum_a images to rgba before writing.
  479.     //&& iCurImage->Format != IL_LUMINANCE_ALPHA
  480.     && iCurImage->Format != IL_RGB
  481.     && iCurImage->Format != IL_RGBA) {
  482. if (iCurImage->Format == IL_BGRA || iCurImage->Format == IL_LUMINANCE_ALPHA)
  483. Temp = iConvertImage(iCurImage, IL_RGBA, DetermineSgiType(iCurImage->Type));
  484. else
  485. Temp = iConvertImage(iCurImage, IL_RGB, DetermineSgiType(iCurImage->Type));
  486. }
  487. else if (iCurImage->Type > IL_UNSIGNED_SHORT) {
  488. Temp = iConvertImage(iCurImage, iCurImage->Format, DetermineSgiType(iCurImage->Type));
  489. }
  490. //compression of images with 2 bytes per channel doesn't work yet
  491. Compress = iGetInt(IL_SGI_RLE) && Temp->Bpc == 1;
  492. if (Temp == NULL)
  493. return IL_FALSE;
  494. SaveBigUShort(SGI_MAGICNUM);  // 'Magic' number
  495. if (Compress)
  496. iputc(1);
  497. else
  498. iputc(0);
  499. if (Temp->Type == IL_UNSIGNED_BYTE)
  500. iputc(1);
  501. else if (Temp->Type == IL_UNSIGNED_SHORT)
  502. iputc(2);
  503. // Need to error here if not one of the two...
  504. if (Temp->Format == IL_LUMINANCE || Temp->Format == IL_COLOUR_INDEX)
  505. SaveBigUShort(2);
  506. else
  507. SaveBigUShort(3);
  508. SaveBigUShort((ILushort)Temp->Width);
  509. SaveBigUShort((ILushort)Temp->Height);
  510. SaveBigUShort((ILushort)Temp->Bpp);
  511. switch (Temp->Type)
  512. {
  513. case IL_BYTE:
  514. SaveBigInt(SCHAR_MIN); // Minimum pixel value
  515. SaveBigInt(SCHAR_MAX); // Maximum pixel value
  516. break;
  517. case IL_UNSIGNED_BYTE:
  518. SaveBigInt(0); // Minimum pixel value
  519. SaveBigInt(UCHAR_MAX); // Maximum pixel value
  520. break;
  521. case IL_SHORT:
  522. SaveBigInt(SHRT_MIN); // Minimum pixel value
  523. SaveBigInt(SHRT_MAX); // Maximum pixel value
  524. break;
  525. case IL_UNSIGNED_SHORT:
  526. SaveBigInt(0); // Minimum pixel value
  527. SaveBigInt(USHRT_MAX); // Maximum pixel value
  528. break;
  529. }
  530. SaveBigInt(0);  // Dummy value
  531. if (FName) {
  532. c = ilCharStrLen(FName);
  533. c = c < 79 ? 79 : c;
  534. iwrite(FName, 1, c);
  535. c = 80 - c;
  536. for (i = 0; i < c; i++) {
  537. iputc(0);
  538. }
  539. }
  540. else {
  541. for (i = 0; i < 80; i++) {
  542. iputc(0);
  543. }
  544. }
  545. SaveBigUInt(0);  // Colormap
  546. // Padding
  547. for (i = 0; i < 101; i++) {
  548. SaveLittleInt(0);
  549. }
  550. if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT) {
  551. TempData = iGetFlipped(Temp);
  552. if (TempData == NULL) {
  553. if (Temp!= iCurImage)
  554. ilCloseImage(Temp);
  555. return IL_FALSE;
  556. }
  557. }
  558. else {
  559. TempData = Temp->Data;
  560. }
  561. if (!Compress) {
  562. for (c = 0; c < Temp->Bpp; c++) {
  563. for (i = c; i < Temp->SizeOfData; i += Temp->Bpp) {
  564. iputc(TempData[i]);  // Have to save each colour plane separately.
  565. }
  566. }
  567. }
  568. else {
  569. iSaveRleSgi(TempData, Temp->Width, Temp->Height, Temp->Bpp, Temp->Bps);
  570. }
  571. if (TempData != Temp->Data)
  572. ifree(TempData);
  573. if (Temp != iCurImage)
  574. ilCloseImage(Temp);
  575. return IL_TRUE;
  576. }
  577. /*----------------------------------------------------------------------------*/
  578. ILboolean iSaveRleSgi(ILubyte *Data, ILuint w, ILuint h, ILuint numChannels,
  579. ILuint bps)
  580. {
  581. //works only for sgi files with only 1 bpc
  582. ILuint c, i, y, j;
  583. ILubyte *ScanLine = NULL, *CompLine = NULL;
  584. ILuint *StartTable = NULL, *LenTable = NULL;
  585. ILuint TableOff, DataOff = 0;
  586. ScanLine = (ILubyte*)ialloc(w);
  587. CompLine = (ILubyte*)ialloc(w * 2 + 1);  // Absolute worst case.
  588. StartTable = (ILuint*)ialloc(h * numChannels * sizeof(ILuint));
  589. LenTable = (ILuint*)icalloc(h * numChannels, sizeof(ILuint));
  590. if (!ScanLine || !CompLine || !StartTable || !LenTable) {
  591. ifree(ScanLine);
  592. ifree(CompLine);
  593. ifree(StartTable);
  594. ifree(LenTable);
  595. return IL_FALSE;
  596. }
  597. // These just contain dummy values at this point.
  598. TableOff = itellw();
  599. iwrite(StartTable, sizeof(ILuint), h * numChannels);
  600. iwrite(LenTable, sizeof(ILuint), h * numChannels);
  601. DataOff = itellw();
  602. for (c = 0; c < numChannels; c++) {
  603. for (y = 0; y < h; y++) {
  604. i = y * bps + c;
  605. for (j = 0; j < w; j++, i += numChannels) {
  606. ScanLine[j] = Data[i];
  607. }
  608. ilRleCompressLine(ScanLine, w, 1, CompLine, LenTable + h * c + y, IL_SGICOMP);
  609. iwrite(CompLine, 1, *(LenTable + h * c + y));
  610. }
  611. }
  612. iseekw(TableOff, IL_SEEK_SET);
  613. j = h * numChannels;
  614. for (y = 0; y < j; y++) {
  615. StartTable[y] = DataOff;
  616. DataOff += LenTable[y];
  617. #ifdef __LITTLE_ENDIAN__
  618. iSwapUInt(&StartTable[y]);
  619.   iSwapUInt(&LenTable[y]);
  620. #endif
  621. }
  622. iwrite(StartTable, sizeof(ILuint), h * numChannels);
  623. iwrite(LenTable, sizeof(ILuint), h * numChannels);
  624. ifree(ScanLine);
  625. ifree(CompLine);
  626. ifree(StartTable);
  627. ifree(LenTable);
  628. return IL_TRUE;
  629. }
  630. /*----------------------------------------------------------------------------*/
  631. #endif//IL_NO_SGI