mirror of
https://github.com/love2d/love-android.git
synced 2026-08-17 11:11:23 +02:00
764 lines
18 KiB
C
764 lines
18 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// ImageLib Sources
|
|
// Copyright (C) 2000-2009 by Denton Woods
|
|
// Last modified: 03/07/2009
|
|
//
|
|
// Filename: src-IL/src/il_sgi.c
|
|
//
|
|
// Description: Reads and writes Silicon Graphics Inc. (.sgi) files.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "il_internal.h"
|
|
#ifndef IL_NO_SGI
|
|
#include "il_sgi.h"
|
|
#include "il_manip.h"
|
|
#include <limits.h>
|
|
|
|
static char *FName = NULL;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*! Checks if the file specified in FileName is a valid .sgi file. */
|
|
ILboolean ilIsValidSgi(ILconst_string FileName)
|
|
{
|
|
ILHANDLE SgiFile;
|
|
ILboolean bSgi = IL_FALSE;
|
|
|
|
if (!iCheckExtension(FileName, IL_TEXT("sgi"))) {
|
|
ilSetError(IL_INVALID_EXTENSION);
|
|
return bSgi;
|
|
}
|
|
|
|
FName = (char*)FileName;
|
|
|
|
SgiFile = iopenr(FileName);
|
|
if (SgiFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bSgi;
|
|
}
|
|
|
|
bSgi = ilIsValidSgiF(SgiFile);
|
|
icloser(SgiFile);
|
|
|
|
return bSgi;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*! Checks if the ILHANDLE contains a valid .sgi file at the current position.*/
|
|
ILboolean ilIsValidSgiF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iIsValidSgi();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
//! Checks if Lump is a valid .sgi lump.
|
|
ILboolean ilIsValidSgiL(const void *Lump, ILuint Size)
|
|
{
|
|
FName = NULL;
|
|
iSetInputLump(Lump, Size);
|
|
return iIsValidSgi();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
// Internal function used to get the .sgi header from the current file.
|
|
ILboolean iGetSgiHead(iSgiHeader *Header)
|
|
{
|
|
Header->MagicNum = GetBigUShort();
|
|
Header->Storage = (ILbyte)igetc();
|
|
Header->Bpc = (ILbyte)igetc();
|
|
Header->Dim = GetBigUShort();
|
|
Header->XSize = GetBigUShort();
|
|
Header->YSize = GetBigUShort();
|
|
Header->ZSize = GetBigUShort();
|
|
Header->PixMin = GetBigInt();
|
|
Header->PixMax = GetBigInt();
|
|
Header->Dummy1 = GetBigInt();
|
|
iread(Header->Name, 1, 80);
|
|
Header->ColMap = GetBigInt();
|
|
iread(Header->Dummy, 1, 404);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Internal function to get the header and check it. */
|
|
ILboolean iIsValidSgi()
|
|
{
|
|
iSgiHeader Head;
|
|
|
|
if (!iGetSgiHead(&Head))
|
|
return IL_FALSE;
|
|
iseek(-(ILint)sizeof(iSgiHeader), IL_SEEK_CUR); // Go ahead and restore to previous state
|
|
|
|
return iCheckSgi(&Head);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Internal function used to check if the HEADER is a valid .sgi header. */
|
|
ILboolean iCheckSgi(iSgiHeader *Header)
|
|
{
|
|
if (Header->MagicNum != SGI_MAGICNUM)
|
|
return IL_FALSE;
|
|
if (Header->Storage != SGI_RLE && Header->Storage != SGI_VERBATIM)
|
|
return IL_FALSE;
|
|
if (Header->Bpc == 0 || Header->Dim == 0)
|
|
return IL_FALSE;
|
|
if (Header->XSize == 0 || Header->YSize == 0 || Header->ZSize == 0)
|
|
return IL_FALSE;
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*! Reads a SGI file */
|
|
ILboolean ilLoadSgi(ILconst_string FileName)
|
|
{
|
|
ILHANDLE SgiFile;
|
|
ILboolean bSgi = IL_FALSE;
|
|
|
|
SgiFile = iopenr(FileName);
|
|
if (SgiFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bSgi;
|
|
}
|
|
|
|
bSgi = ilLoadSgiF(SgiFile);
|
|
icloser(SgiFile);
|
|
|
|
return bSgi;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*! Reads an already-opened SGI file */
|
|
ILboolean ilLoadSgiF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iLoadSgiInternal();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*! Reads from a memory "lump" that contains a SGI image */
|
|
ILboolean ilLoadSgiL(const void *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iLoadSgiInternal();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Internal function used to load the SGI image */
|
|
ILboolean iLoadSgiInternal()
|
|
{
|
|
iSgiHeader Header;
|
|
ILboolean bSgi;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (!iGetSgiHead(&Header))
|
|
return IL_FALSE;
|
|
if (!iCheckSgi(&Header)) {
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// Bugfix for #1060946.
|
|
// The ZSize should never really be 2 by the specifications. Some
|
|
// application is outputting these, and it looks like the ZSize
|
|
// should really be 1.
|
|
if (Header.ZSize == 2)
|
|
Header.ZSize = 1;
|
|
|
|
if (Header.Storage == SGI_RLE) { // RLE
|
|
bSgi = iReadRleSgi(&Header);
|
|
}
|
|
else { // Non-RLE //(Header.Storage == SGI_VERBATIM)
|
|
bSgi = iReadNonRleSgi(&Header);
|
|
}
|
|
|
|
if (!bSgi)
|
|
return IL_FALSE;
|
|
return ilFixImage();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
ILboolean iReadRleSgi(iSgiHeader *Head)
|
|
{
|
|
#ifdef __LITTLE_ENDIAN__
|
|
ILuint ixTable;
|
|
#endif
|
|
ILuint ChanInt = 0;
|
|
ILuint ixPlane, ixHeight,ixPixel, RleOff, RleLen;
|
|
ILuint *OffTable=NULL, *LenTable=NULL, TableSize, Cur;
|
|
ILubyte **TempData=NULL;
|
|
|
|
if (!iNewSgi(Head))
|
|
return IL_FALSE;
|
|
|
|
TableSize = Head->YSize * Head->ZSize;
|
|
OffTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
|
|
LenTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
|
|
if (OffTable == NULL || LenTable == NULL)
|
|
goto cleanup_error;
|
|
if (iread(OffTable, TableSize * sizeof(ILuint), 1) != 1)
|
|
goto cleanup_error;
|
|
if (iread(LenTable, TableSize * sizeof(ILuint), 1) != 1)
|
|
goto cleanup_error;
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
// Fix the offset/len table (it's big endian format)
|
|
for (ixTable = 0; ixTable < TableSize; ixTable++) {
|
|
iSwapUInt(OffTable + ixTable);
|
|
iSwapUInt(LenTable + ixTable);
|
|
}
|
|
#endif //__LITTLE_ENDIAN__
|
|
|
|
// We have to create a temporary buffer for the image, because SGI
|
|
// images are plane-separated.
|
|
TempData = (ILubyte**)ialloc(Head->ZSize * sizeof(ILubyte*));
|
|
if (TempData == NULL)
|
|
goto cleanup_error;
|
|
imemclear(TempData, Head->ZSize * sizeof(ILubyte*)); // Just in case ialloc fails then cleanup_error.
|
|
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
|
TempData[ixPlane] = (ILubyte*)ialloc(Head->XSize * Head->YSize * Head->Bpc);
|
|
if (TempData[ixPlane] == NULL)
|
|
goto cleanup_error;
|
|
}
|
|
|
|
// Read the Planes into the temporary memory
|
|
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
|
for (ixHeight = 0, Cur = 0; ixHeight < Head->YSize;
|
|
ixHeight++, Cur += Head->XSize * Head->Bpc) {
|
|
|
|
RleOff = OffTable[ixHeight + ixPlane * Head->YSize];
|
|
RleLen = LenTable[ixHeight + ixPlane * Head->YSize];
|
|
|
|
// Seeks to the offset table position
|
|
iseek(RleOff, IL_SEEK_SET);
|
|
if (iGetScanLine((TempData[ixPlane]) + (ixHeight * Head->XSize * Head->Bpc),
|
|
Head, RleLen) != Head->XSize * Head->Bpc) {
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
goto cleanup_error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DW: Removed on 05/25/2002.
|
|
/*// Check if an alphaplane exists and invert it
|
|
if (Head->ZSize == 4) {
|
|
for (ixPixel=0; (ILint)ixPixel<Head->XSize * Head->YSize; ixPixel++) {
|
|
TempData[3][ixPixel] = TempData[3][ixPixel] ^ 255;
|
|
}
|
|
}*/
|
|
|
|
// Assemble the image from its planes
|
|
for (ixPixel = 0; ixPixel < iCurImage->SizeOfData;
|
|
ixPixel += Head->ZSize * Head->Bpc, ChanInt += Head->Bpc) {
|
|
for (ixPlane = 0; (ILint)ixPlane < Head->ZSize * Head->Bpc; ixPlane += Head->Bpc) {
|
|
iCurImage->Data[ixPixel + ixPlane] = TempData[ixPlane][ChanInt];
|
|
if (Head->Bpc == 2)
|
|
iCurImage->Data[ixPixel + ixPlane + 1] = TempData[ixPlane][ChanInt + 1];
|
|
}
|
|
}
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
if (Head->Bpc == 2)
|
|
sgiSwitchData(iCurImage->Data, iCurImage->SizeOfData);
|
|
#endif
|
|
|
|
ifree(OffTable);
|
|
ifree(LenTable);
|
|
|
|
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
|
ifree(TempData[ixPlane]);
|
|
}
|
|
ifree(TempData);
|
|
|
|
return IL_TRUE;
|
|
|
|
cleanup_error:
|
|
ifree(OffTable);
|
|
ifree(LenTable);
|
|
if (TempData) {
|
|
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
|
ifree(TempData[ixPlane]);
|
|
}
|
|
ifree(TempData);
|
|
}
|
|
|
|
return IL_FALSE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
ILint iGetScanLine(ILubyte *ScanLine, iSgiHeader *Head, ILuint Length)
|
|
{
|
|
ILushort Pixel, Count; // For current pixel
|
|
ILuint BppRead = 0, CurPos = 0, Bps = Head->XSize * Head->Bpc;
|
|
|
|
while (BppRead < Length && CurPos < Bps)
|
|
{
|
|
Pixel = 0;
|
|
if (iread(&Pixel, Head->Bpc, 1) != 1)
|
|
return -1;
|
|
|
|
#ifndef __LITTLE_ENDIAN__
|
|
iSwapUShort(&Pixel);
|
|
#endif
|
|
|
|
if (!(Count = (Pixel & 0x7f))) // If 0, line ends
|
|
return CurPos;
|
|
if (Pixel & 0x80) { // If top bit set, then it is a "run"
|
|
if (iread(ScanLine, Head->Bpc, Count) != Count)
|
|
return -1;
|
|
BppRead += Head->Bpc * Count + Head->Bpc;
|
|
ScanLine += Head->Bpc * Count;
|
|
CurPos += Head->Bpc * Count;
|
|
}
|
|
else {
|
|
if (iread(&Pixel, Head->Bpc, 1) != 1)
|
|
return -1;
|
|
#ifndef __LITTLE_ENDIAN__
|
|
iSwapUShort(&Pixel);
|
|
#endif
|
|
if (Head->Bpc == 1) {
|
|
while (Count--) {
|
|
*ScanLine = (ILubyte)Pixel;
|
|
ScanLine++;
|
|
CurPos++;
|
|
}
|
|
}
|
|
else {
|
|
while (Count--) {
|
|
*(ILushort*)ScanLine = Pixel;
|
|
ScanLine += 2;
|
|
CurPos += 2;
|
|
}
|
|
}
|
|
BppRead += Head->Bpc + Head->Bpc;
|
|
}
|
|
}
|
|
|
|
return CurPos;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
// Much easier to read - just assemble from planes, no decompression
|
|
ILboolean iReadNonRleSgi(iSgiHeader *Head)
|
|
{
|
|
ILuint i, c;
|
|
// ILint ChanInt = 0; Unused
|
|
ILint ChanSize;
|
|
ILboolean Cache = IL_FALSE;
|
|
|
|
if (!iNewSgi(Head)) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST) {
|
|
Cache = IL_TRUE;
|
|
ChanSize = Head->XSize * Head->YSize * Head->Bpc;
|
|
iPreCache(ChanSize);
|
|
}
|
|
|
|
for (c = 0; c < iCurImage->Bpp; c++) {
|
|
for (i = c; i < iCurImage->SizeOfData; i += iCurImage->Bpp) {
|
|
if (iread(iCurImage->Data + i, 1, 1) != 1) {
|
|
if (Cache)
|
|
iUnCache();
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Cache)
|
|
iUnCache();
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void sgiSwitchData(ILubyte *Data, ILuint SizeOfData)
|
|
{
|
|
ILubyte Temp;
|
|
ILuint i;
|
|
#ifdef ALTIVEC_GCC
|
|
i = 0;
|
|
union {
|
|
vector unsigned char vec;
|
|
vector unsigned int load;
|
|
}inversion_vector;
|
|
|
|
inversion_vector.load = (vector unsigned int)\
|
|
{0x01000302,0x05040706,0x09080B0A,0x0D0C0F0E};
|
|
while( i <= SizeOfData-16 ) {
|
|
vector unsigned char data = vec_ld(i,Data);
|
|
vec_perm(data,data,inversion_vector.vec);
|
|
vec_st(data,i,Data);
|
|
i+=16;
|
|
}
|
|
SizeOfData -= i;
|
|
#endif
|
|
for (i = 0; i < SizeOfData; i += 2) {
|
|
Temp = Data[i];
|
|
Data[i] = Data[i+1];
|
|
Data[i+1] = Temp;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
// Just an internal convenience function for reading SGI files
|
|
ILboolean iNewSgi(iSgiHeader *Head)
|
|
{
|
|
if (!ilTexImage(Head->XSize, Head->YSize, Head->Bpc, (ILubyte)Head->ZSize, 0, IL_UNSIGNED_BYTE, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
|
|
|
switch (Head->ZSize)
|
|
{
|
|
case 1:
|
|
iCurImage->Format = IL_LUMINANCE;
|
|
break;
|
|
/*case 2:
|
|
iCurImage->Format = IL_LUMINANCE_ALPHA;
|
|
break;*/
|
|
case 3:
|
|
iCurImage->Format = IL_RGB;
|
|
break;
|
|
case 4:
|
|
iCurImage->Format = IL_RGBA;
|
|
break;
|
|
default:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
switch (Head->Bpc)
|
|
{
|
|
case 1:
|
|
if (Head->PixMin < 0)
|
|
iCurImage->Type = IL_BYTE;
|
|
else
|
|
iCurImage->Type = IL_UNSIGNED_BYTE;
|
|
break;
|
|
case 2:
|
|
if (Head->PixMin < 0)
|
|
iCurImage->Type = IL_SHORT;
|
|
else
|
|
iCurImage->Type = IL_UNSIGNED_SHORT;
|
|
break;
|
|
default:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
//! Writes a SGI file
|
|
ILboolean ilSaveSgi(const ILstring FileName)
|
|
{
|
|
ILHANDLE SgiFile;
|
|
ILuint SgiSize;
|
|
|
|
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
|
if (iFileExists(FileName)) {
|
|
ilSetError(IL_FILE_ALREADY_EXISTS);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
SgiFile = iopenw(FileName);
|
|
if (SgiFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
SgiSize = ilSaveSgiF(SgiFile);
|
|
iclosew(SgiFile);
|
|
|
|
if (SgiSize == 0)
|
|
return IL_FALSE;
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Writes a Sgi to an already-opened file
|
|
ILuint ilSaveSgiF(ILHANDLE File)
|
|
{
|
|
ILuint Pos;
|
|
iSetOutputFile(File);
|
|
Pos = itellw();
|
|
if (iSaveSgiInternal() == IL_FALSE)
|
|
return 0; // Error occurred
|
|
return itellw() - Pos; // Return the number of bytes written.
|
|
}
|
|
|
|
|
|
//! Writes a Sgi to a memory "lump"
|
|
ILuint ilSaveSgiL(void *Lump, ILuint Size)
|
|
{
|
|
ILuint Pos;
|
|
iSetOutputLump(Lump, Size);
|
|
Pos = itellw();
|
|
if (iSaveSgiInternal() == IL_FALSE)
|
|
return 0; // Error occurred
|
|
return itellw() - Pos; // Return the number of bytes written.
|
|
}
|
|
|
|
|
|
ILenum DetermineSgiType(ILenum Type)
|
|
{
|
|
if (Type > IL_UNSIGNED_SHORT) {
|
|
if (iCurImage->Type == IL_INT)
|
|
return IL_SHORT;
|
|
return IL_UNSIGNED_SHORT;
|
|
}
|
|
return Type;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
// Rle does NOT work yet.
|
|
|
|
// Internal function used to save the Sgi.
|
|
ILboolean iSaveSgiInternal()
|
|
{
|
|
ILuint i, c;
|
|
ILboolean Compress;
|
|
ILimage *Temp = iCurImage;
|
|
ILubyte *TempData;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (iCurImage->Format != IL_LUMINANCE
|
|
//while the sgi spec doesn't directly forbid rgb files with 2
|
|
//channels, they are quite uncommon and most apps don't support
|
|
//them. so convert lum_a images to rgba before writing.
|
|
//&& iCurImage->Format != IL_LUMINANCE_ALPHA
|
|
&& iCurImage->Format != IL_RGB
|
|
&& iCurImage->Format != IL_RGBA) {
|
|
if (iCurImage->Format == IL_BGRA || iCurImage->Format == IL_LUMINANCE_ALPHA)
|
|
Temp = iConvertImage(iCurImage, IL_RGBA, DetermineSgiType(iCurImage->Type));
|
|
else
|
|
Temp = iConvertImage(iCurImage, IL_RGB, DetermineSgiType(iCurImage->Type));
|
|
}
|
|
else if (iCurImage->Type > IL_UNSIGNED_SHORT) {
|
|
Temp = iConvertImage(iCurImage, iCurImage->Format, DetermineSgiType(iCurImage->Type));
|
|
}
|
|
|
|
//compression of images with 2 bytes per channel doesn't work yet
|
|
Compress = iGetInt(IL_SGI_RLE) && Temp->Bpc == 1;
|
|
|
|
if (Temp == NULL)
|
|
return IL_FALSE;
|
|
|
|
SaveBigUShort(SGI_MAGICNUM); // 'Magic' number
|
|
if (Compress)
|
|
iputc(1);
|
|
else
|
|
iputc(0);
|
|
|
|
if (Temp->Type == IL_UNSIGNED_BYTE)
|
|
iputc(1);
|
|
else if (Temp->Type == IL_UNSIGNED_SHORT)
|
|
iputc(2);
|
|
// Need to error here if not one of the two...
|
|
|
|
if (Temp->Format == IL_LUMINANCE || Temp->Format == IL_COLOUR_INDEX)
|
|
SaveBigUShort(2);
|
|
else
|
|
SaveBigUShort(3);
|
|
|
|
SaveBigUShort((ILushort)Temp->Width);
|
|
SaveBigUShort((ILushort)Temp->Height);
|
|
SaveBigUShort((ILushort)Temp->Bpp);
|
|
|
|
switch (Temp->Type)
|
|
{
|
|
case IL_BYTE:
|
|
SaveBigInt(SCHAR_MIN); // Minimum pixel value
|
|
SaveBigInt(SCHAR_MAX); // Maximum pixel value
|
|
break;
|
|
case IL_UNSIGNED_BYTE:
|
|
SaveBigInt(0); // Minimum pixel value
|
|
SaveBigInt(UCHAR_MAX); // Maximum pixel value
|
|
break;
|
|
case IL_SHORT:
|
|
SaveBigInt(SHRT_MIN); // Minimum pixel value
|
|
SaveBigInt(SHRT_MAX); // Maximum pixel value
|
|
break;
|
|
case IL_UNSIGNED_SHORT:
|
|
SaveBigInt(0); // Minimum pixel value
|
|
SaveBigInt(USHRT_MAX); // Maximum pixel value
|
|
break;
|
|
}
|
|
|
|
SaveBigInt(0); // Dummy value
|
|
|
|
if (FName) {
|
|
c = ilCharStrLen(FName);
|
|
c = c < 79 ? 79 : c;
|
|
iwrite(FName, 1, c);
|
|
c = 80 - c;
|
|
for (i = 0; i < c; i++) {
|
|
iputc(0);
|
|
}
|
|
}
|
|
else {
|
|
for (i = 0; i < 80; i++) {
|
|
iputc(0);
|
|
}
|
|
}
|
|
|
|
SaveBigUInt(0); // Colormap
|
|
|
|
// Padding
|
|
for (i = 0; i < 101; i++) {
|
|
SaveLittleInt(0);
|
|
}
|
|
|
|
|
|
if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT) {
|
|
TempData = iGetFlipped(Temp);
|
|
if (TempData == NULL) {
|
|
if (Temp!= iCurImage)
|
|
ilCloseImage(Temp);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
TempData = Temp->Data;
|
|
}
|
|
|
|
|
|
if (!Compress) {
|
|
for (c = 0; c < Temp->Bpp; c++) {
|
|
for (i = c; i < Temp->SizeOfData; i += Temp->Bpp) {
|
|
iputc(TempData[i]); // Have to save each colour plane separately.
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
iSaveRleSgi(TempData, Temp->Width, Temp->Height, Temp->Bpp, Temp->Bps);
|
|
}
|
|
|
|
|
|
if (TempData != Temp->Data)
|
|
ifree(TempData);
|
|
if (Temp != iCurImage)
|
|
ilCloseImage(Temp);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
ILboolean iSaveRleSgi(ILubyte *Data, ILuint w, ILuint h, ILuint numChannels,
|
|
ILuint bps)
|
|
{
|
|
//works only for sgi files with only 1 bpc
|
|
|
|
ILuint c, i, y, j;
|
|
ILubyte *ScanLine = NULL, *CompLine = NULL;
|
|
ILuint *StartTable = NULL, *LenTable = NULL;
|
|
ILuint TableOff, DataOff = 0;
|
|
|
|
ScanLine = (ILubyte*)ialloc(w);
|
|
CompLine = (ILubyte*)ialloc(w * 2 + 1); // Absolute worst case.
|
|
StartTable = (ILuint*)ialloc(h * numChannels * sizeof(ILuint));
|
|
LenTable = (ILuint*)icalloc(h * numChannels, sizeof(ILuint));
|
|
if (!ScanLine || !CompLine || !StartTable || !LenTable) {
|
|
ifree(ScanLine);
|
|
ifree(CompLine);
|
|
ifree(StartTable);
|
|
ifree(LenTable);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// These just contain dummy values at this point.
|
|
TableOff = itellw();
|
|
iwrite(StartTable, sizeof(ILuint), h * numChannels);
|
|
iwrite(LenTable, sizeof(ILuint), h * numChannels);
|
|
|
|
DataOff = itellw();
|
|
for (c = 0; c < numChannels; c++) {
|
|
for (y = 0; y < h; y++) {
|
|
i = y * bps + c;
|
|
for (j = 0; j < w; j++, i += numChannels) {
|
|
ScanLine[j] = Data[i];
|
|
}
|
|
|
|
ilRleCompressLine(ScanLine, w, 1, CompLine, LenTable + h * c + y, IL_SGICOMP);
|
|
iwrite(CompLine, 1, *(LenTable + h * c + y));
|
|
}
|
|
}
|
|
|
|
iseekw(TableOff, IL_SEEK_SET);
|
|
|
|
j = h * numChannels;
|
|
for (y = 0; y < j; y++) {
|
|
StartTable[y] = DataOff;
|
|
DataOff += LenTable[y];
|
|
#ifdef __LITTLE_ENDIAN__
|
|
iSwapUInt(&StartTable[y]);
|
|
iSwapUInt(&LenTable[y]);
|
|
#endif
|
|
}
|
|
|
|
iwrite(StartTable, sizeof(ILuint), h * numChannels);
|
|
iwrite(LenTable, sizeof(ILuint), h * numChannels);
|
|
|
|
ifree(ScanLine);
|
|
ifree(CompLine);
|
|
ifree(StartTable);
|
|
ifree(LenTable);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
#endif//IL_NO_SGI
|