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