mirror of
https://github.com/love2d/megasource.git
synced 2026-08-17 11:11:35 +02:00
660 lines
16 KiB
C
660 lines
16 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// ImageLib Sources
|
|
// Copyright (C) 2000-2008 by Denton Woods (this file by thakis / Denton)
|
|
// Last modified: 02/09/2009
|
|
//
|
|
// Filename: src-IL/src/il_hdr.c
|
|
//
|
|
// Description: Reads/writes a RADIANCE High Dynamic Range Image
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "il_internal.h"
|
|
#ifndef IL_NO_HDR
|
|
#include "il_hdr.h"
|
|
#include "il_endian.h"
|
|
|
|
|
|
//! Checks if the file specified in FileName is a valid .hdr file.
|
|
ILboolean ilIsValidHdr(ILconst_string FileName)
|
|
{
|
|
ILHANDLE HdrFile;
|
|
ILboolean bHdr = IL_FALSE;
|
|
|
|
if (!iCheckExtension(FileName, IL_TEXT("hdr"))) {
|
|
ilSetError(IL_INVALID_EXTENSION);
|
|
return bHdr;
|
|
}
|
|
|
|
HdrFile = iopenr(FileName);
|
|
if (HdrFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bHdr;
|
|
}
|
|
|
|
bHdr = ilIsValidHdrF(HdrFile);
|
|
icloser(HdrFile);
|
|
|
|
return bHdr;
|
|
}
|
|
|
|
|
|
//! Checks if the ILHANDLE contains a valid .hdr file at the current position.
|
|
ILboolean ilIsValidHdrF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iIsValidHdr();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Checks if Lump is a valid .hdr lump.
|
|
ILboolean ilIsValidHdrL(const void *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iIsValidHdr();
|
|
}
|
|
|
|
|
|
// Internal function used to get the .hdr header from the current file.
|
|
ILboolean iGetHdrHead(HDRHEADER *Header)
|
|
{
|
|
ILboolean done = IL_FALSE;
|
|
char a, b;
|
|
char x[3], y[3]; //changed 20050217: added space for the '\0' char
|
|
char buff[81]; // 01-19-2009: Added space for the '\0'.
|
|
ILuint count = 0;
|
|
|
|
iread(Header->Signature, 1, 10);
|
|
|
|
//skip lines until an empty line is found.
|
|
//this marks the end of header information,
|
|
//the next line contains the image's dimension.
|
|
|
|
//TODO: read header contents into variables
|
|
//(EXPOSURE, orientation, xyz correction, ...)
|
|
|
|
if (iread(&a, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
|
|
while (!done) {
|
|
if (iread(&b, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
if (b == '\n' && a == '\n')
|
|
done = IL_TRUE;
|
|
else
|
|
a = b;
|
|
}
|
|
|
|
//read dimensions (note that this assumes a somewhat valid image)
|
|
if (iread(&a, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
while (a != '\n') {
|
|
if (count >= 80) { // Line shouldn't be this long at all.
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
buff[count] = a;
|
|
if (iread(&a, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
++count;
|
|
}
|
|
buff[count] = '\0';
|
|
|
|
//note that this is not the 100% correct way to load hdr images:
|
|
//in a perfect world we would check if there's a +/- X/Y in front
|
|
//of width and heigth and mirror + rotate the image after decoding
|
|
//according to that. But HDRShop doesn't do that either (and that's
|
|
//my reference program :) ) and it's just a rotate and a mirror,
|
|
//nothing that really changes the appearance of the loaded image...
|
|
//(The code as it is now assumes that y contains "-Y" and x contains
|
|
//"+X" after the following line)
|
|
|
|
// The 2 has to be in the %s format specifier to prevent buffer overruns.
|
|
sscanf(buff, "%2s %d %2s %d", y, &Header->Height, x, &Header->Width);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Internal function to get the header and check it.
|
|
ILboolean iIsValidHdr()
|
|
{
|
|
char Head[10];
|
|
ILint Read;
|
|
|
|
Read = iread(Head, 1, 10);
|
|
iseek(-Read, IL_SEEK_CUR); // Go ahead and restore to previous state
|
|
if (Read != 10)
|
|
return IL_FALSE;
|
|
|
|
return
|
|
strnicmp(Head, "#?RADIANCE", 10) == 0
|
|
|| strnicmp(Head, "#?RGBE", 6) == 0;
|
|
}
|
|
|
|
|
|
// Internal function used to check if the HEADER is a valid .hdr header.
|
|
ILboolean iCheckHdr(HDRHEADER *Header)
|
|
{
|
|
return
|
|
strnicmp(Header->Signature, "#?RADIANCE", 10) == 0
|
|
|| strnicmp(Header->Signature, "#?RGBE", 6) == 0;
|
|
}
|
|
|
|
|
|
//! Reads a .hdr file
|
|
ILboolean ilLoadHdr(ILconst_string FileName)
|
|
{
|
|
ILHANDLE HdrFile;
|
|
ILboolean bHdr = IL_FALSE;
|
|
|
|
HdrFile = iopenr(FileName);
|
|
if (HdrFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bHdr;
|
|
}
|
|
|
|
bHdr = ilLoadHdrF(HdrFile);
|
|
icloser(HdrFile);
|
|
|
|
return bHdr;
|
|
}
|
|
|
|
|
|
//! Reads an already-opened .hdr file
|
|
ILboolean ilLoadHdrF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iLoadHdrInternal();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Reads from a memory "lump" that contains a .hdr
|
|
ILboolean ilLoadHdrL(const void *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iLoadHdrInternal();
|
|
}
|
|
|
|
|
|
// Internal function used to load the .hdr.
|
|
ILboolean iLoadHdrInternal()
|
|
{
|
|
HDRHEADER Header;
|
|
ILfloat *data;
|
|
ILubyte *scanline;
|
|
ILuint i, j, e, r, g, b;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (!iGetHdrHead(&Header)) {
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
if (!iCheckHdr(&Header)) {
|
|
//iseek(-(ILint)sizeof(HDRHEAD), IL_SEEK_CUR);
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// Update the current image with the new dimensions
|
|
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_FLOAT, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
|
|
//read image data
|
|
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
|
iPreCache(iCurImage->Width / 8 * iCurImage->Height);
|
|
|
|
data = (ILfloat*)iCurImage->Data;
|
|
scanline = (ILubyte*)ialloc(Header.Width*4);
|
|
for (i = 0; i < Header.Height; ++i) {
|
|
ReadScanline(scanline, Header.Width);
|
|
|
|
//convert hdrs internal format to floats
|
|
for (j = 0; j < 4*Header.Width; j += 4) {
|
|
ILuint *ee;
|
|
ILfloat t, *ff;
|
|
e = scanline[j + 3];
|
|
r = scanline[j + 0];
|
|
g = scanline[j + 1];
|
|
b = scanline[j + 2];
|
|
|
|
//t = (float)pow(2.f, ((ILint)e) - 128);
|
|
if (e != 0)
|
|
e = (e - 1) << 23;
|
|
|
|
// All this just to avoid stric-aliasing warnings...
|
|
// was: t = *(ILfloat*)&e
|
|
ee = &e;
|
|
ff = (ILfloat*)ee;
|
|
t = *ff;
|
|
|
|
data[0] = (r/255.0f)*t;
|
|
data[1] = (g/255.0f)*t;
|
|
data[2] = (b/255.0f)*t;
|
|
data += 3;
|
|
}
|
|
}
|
|
iUnCache();
|
|
ifree(scanline);
|
|
|
|
return ilFixImage();
|
|
}
|
|
|
|
void ReadScanline(ILubyte *scanline, ILuint w) {
|
|
ILubyte *runner;
|
|
ILuint r, g, b, e, read, shift;
|
|
|
|
r = igetc();
|
|
g = igetc();
|
|
b = igetc();
|
|
e = igetc();
|
|
|
|
//check if the scanline is in the new format
|
|
//if so, e, r, g, g are stored separated and are
|
|
//rle-compressed independently.
|
|
if (r == 2 && g == 2) {
|
|
ILuint length = (b << 8) | e;
|
|
ILuint j, t, k;
|
|
if (length > w)
|
|
length = w; //fix broken files
|
|
for (k = 0; k < 4; ++k) {
|
|
runner = scanline + k;
|
|
j = 0;
|
|
while (j < length) {
|
|
t = igetc();
|
|
if (t > 128) { //Run?
|
|
ILubyte val = igetc();
|
|
t &= 127;
|
|
//copy current byte
|
|
while (t > 0 && j < length) {
|
|
*runner = val;
|
|
runner += 4;
|
|
--t;
|
|
++j;
|
|
}
|
|
}
|
|
else { //No Run.
|
|
//read new bytes
|
|
while (t > 0 && j < length) {
|
|
*runner = igetc();
|
|
runner += 4;
|
|
--t;
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return; //done decoding a scanline in separated format
|
|
}
|
|
|
|
//if we come here, we are dealing with old-style scanlines
|
|
shift = 0;
|
|
read = 0;
|
|
runner = scanline;
|
|
while (read < w) {
|
|
if (read != 0) {
|
|
r = igetc();
|
|
g = igetc();
|
|
b = igetc();
|
|
e = igetc();
|
|
}
|
|
|
|
//if all three mantissas are 1, then this is a rle
|
|
//count dword
|
|
if (r == 1 && g == 1 && b == 1) {
|
|
ILuint length = e;
|
|
ILuint j;
|
|
for (j = length << shift; j > 0 && read < w; --j) {
|
|
memcpy(runner, runner - 4, 4);
|
|
runner += 4;
|
|
++read;
|
|
}
|
|
//if more than one rle count dword is read
|
|
//consecutively, they are higher order bytes
|
|
//of the first read value. shift keeps track of
|
|
//that.
|
|
shift += 8;
|
|
}
|
|
else {
|
|
runner[0] = r;
|
|
runner[1] = g;
|
|
runner[2] = b;
|
|
runner[3] = e;
|
|
|
|
shift = 0;
|
|
runner += 4;
|
|
++read;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//! Writes a Hdr file
|
|
ILboolean ilSaveHdr(const ILstring FileName)
|
|
{
|
|
ILHANDLE HdrFile;
|
|
ILuint HdrSize;
|
|
|
|
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
|
if (iFileExists(FileName)) {
|
|
ilSetError(IL_FILE_ALREADY_EXISTS);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
HdrFile = iopenw(FileName);
|
|
if (HdrFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
HdrSize = ilSaveHdrF(HdrFile);
|
|
iclosew(HdrFile);
|
|
|
|
if (HdrSize == 0)
|
|
return IL_FALSE;
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Writes a Hdr to an already-opened file
|
|
ILuint ilSaveHdrF(ILHANDLE File)
|
|
{
|
|
ILuint Pos;
|
|
iSetOutputFile(File);
|
|
Pos = itellw();
|
|
if (iSaveHdrInternal() == IL_FALSE)
|
|
return 0; // Error occurred
|
|
return itellw() - Pos; // Return the number of bytes written.
|
|
}
|
|
|
|
|
|
//! Writes a Hdr to a memory "lump"
|
|
ILuint ilSaveHdrL(void *Lump, ILuint Size)
|
|
{
|
|
ILuint Pos;
|
|
iSetOutputLump(Lump, Size);
|
|
Pos = itellw();
|
|
if (iSaveHdrInternal() == IL_FALSE)
|
|
return 0; // Error occurred
|
|
return itellw() - Pos; // Return the number of bytes written.
|
|
}
|
|
|
|
|
|
//
|
|
// Much of the saving code is based on the code by Bruce Walter,
|
|
// available at http://www.graphics.cornell.edu/online/formats/rgbe/.
|
|
//
|
|
// The actual source code file is
|
|
// http://www.graphics.cornell.edu/online/formats/rgbe/rgbe.c
|
|
//
|
|
|
|
|
|
/* standard conversion from float pixels to rgbe pixels */
|
|
/* note: you can remove the "inline"s if your compiler complains about it */
|
|
//static INLINE void
|
|
static void
|
|
float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
|
|
{
|
|
float v;
|
|
int e;
|
|
|
|
v = red;
|
|
if (green > v) v = green;
|
|
if (blue > v) v = blue;
|
|
if (v < 1e-32) {
|
|
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
|
}
|
|
else {
|
|
v = (float)(frexp(v,&e) * 256.0/v);
|
|
rgbe[0] = (unsigned char) (red * v);
|
|
rgbe[1] = (unsigned char) (green * v);
|
|
rgbe[2] = (unsigned char) (blue * v);
|
|
rgbe[3] = (unsigned char) (e + 128);
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
ILuint valid; /* indicate which fields are valid */
|
|
ILbyte programtype[16]; /* listed at beginning of file to identify it
|
|
* after "#?". defaults to "RGBE" */
|
|
ILfloat gamma; /* image has already been gamma corrected with
|
|
* given gamma. defaults to 1.0 (no correction) */
|
|
ILfloat exposure; /* a value of 1.0 in an image corresponds to
|
|
* <exposure> watts/steradian/m^2.
|
|
* defaults to 1.0 */
|
|
} rgbe_header_info;
|
|
|
|
/* flags indicating which fields in an rgbe_header_info are valid */
|
|
#define RGBE_VALID_PROGRAMTYPE 0x01
|
|
#define RGBE_VALID_GAMMA 0x02
|
|
#define RGBE_VALID_EXPOSURE 0x04
|
|
|
|
/* offsets to red, green, and blue components in a data (float) pixel */
|
|
#define RGBE_DATA_RED 0
|
|
#define RGBE_DATA_GREEN 1
|
|
#define RGBE_DATA_BLUE 2
|
|
/* number of floats per pixel */
|
|
#define RGBE_DATA_SIZE 3
|
|
|
|
|
|
/* default minimal header. modify if you want more information in header */
|
|
ILboolean RGBE_WriteHeader(ILuint width, ILuint height, rgbe_header_info *info)
|
|
{
|
|
char *programtype = "RGBE";
|
|
|
|
if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
|
|
programtype = info->programtype;
|
|
if (ilprintf("#?%s\n",programtype) < 0)
|
|
return IL_FALSE;
|
|
/* The #? is to identify file type, the programtype is optional. */
|
|
if (info && (info->valid & RGBE_VALID_GAMMA)) {
|
|
if (ilprintf("GAMMA=%g\n",info->gamma) < 0)
|
|
return IL_FALSE;
|
|
}
|
|
if (info && (info->valid & RGBE_VALID_EXPOSURE)) {
|
|
if (ilprintf("EXPOSURE=%g\n",info->exposure) < 0)
|
|
return IL_FALSE;
|
|
}
|
|
if (ilprintf("FORMAT=32-bit_rle_rgbe\n\n") < 0)
|
|
return IL_FALSE;
|
|
if (ilprintf("-Y %d +X %d\n", height, width) < 0)
|
|
return IL_FALSE;
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
/* simple write routine that does not use run length encoding */
|
|
/* These routines can be made faster by allocating a larger buffer and
|
|
fread-ing and iwrite-ing the data in larger chunks */
|
|
int RGBE_WritePixels(float *data, int numpixels)
|
|
{
|
|
unsigned char rgbe[4];
|
|
|
|
while (numpixels-- > 0) {
|
|
float2rgbe(rgbe,data[RGBE_DATA_RED],data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
|
data += RGBE_DATA_SIZE;
|
|
if (iwrite(rgbe, sizeof(rgbe), 1) < 1)
|
|
return IL_FALSE;
|
|
}
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
/* The code below is only needed for the run-length encoded files. */
|
|
/* Run length encoding adds considerable complexity but does */
|
|
/* save some space. For each scanline, each channel (r,g,b,e) is */
|
|
/* encoded separately for better compression. */
|
|
|
|
ILboolean RGBE_WriteBytes_RLE(ILubyte *data, ILuint numbytes)
|
|
{
|
|
#define MINRUNLENGTH 4
|
|
ILuint cur, beg_run, run_count, old_run_count, nonrun_count;
|
|
ILubyte buf[2];
|
|
|
|
cur = 0;
|
|
while (cur < numbytes) {
|
|
beg_run = cur;
|
|
/* find next run of length at least 4 if one exists */
|
|
run_count = old_run_count = 0;
|
|
while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
|
|
beg_run += run_count;
|
|
old_run_count = run_count;
|
|
run_count = 1;
|
|
// 01-25-2009: Moved test for beg_run + run_count first so that it is
|
|
// tested first. This keeps it from going out of bounds by 1.
|
|
while((beg_run + run_count < numbytes) && (run_count < 127) &&
|
|
(data[beg_run] == data[beg_run + run_count]))
|
|
run_count++;
|
|
}
|
|
/* if data before next big run is a short run then write it as such */
|
|
if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
|
|
buf[0] = 128 + old_run_count; /*write short run*/
|
|
buf[1] = data[cur];
|
|
if (iwrite(buf,sizeof(buf[0])*2,1) < 1)
|
|
return IL_FALSE;
|
|
cur = beg_run;
|
|
}
|
|
/* write out bytes until we reach the start of the next run */
|
|
while(cur < beg_run) {
|
|
nonrun_count = beg_run - cur;
|
|
if (nonrun_count > 128)
|
|
nonrun_count = 128;
|
|
buf[0] = nonrun_count;
|
|
if (iwrite(buf,sizeof(buf[0]),1) < 1)
|
|
return IL_FALSE;
|
|
if (iwrite(&data[cur],sizeof(data[0])*nonrun_count,1) < 1)
|
|
return IL_FALSE;
|
|
cur += nonrun_count;
|
|
}
|
|
/* write out next run if one was found */
|
|
if (run_count >= MINRUNLENGTH) {
|
|
buf[0] = 128 + run_count;
|
|
buf[1] = data[beg_run];
|
|
if (iwrite(buf,sizeof(buf[0])*2,1) < 1)
|
|
return IL_FALSE;
|
|
cur += run_count;
|
|
}
|
|
}
|
|
return IL_TRUE;
|
|
#undef MINRUNLENGTH
|
|
}
|
|
|
|
|
|
// Internal function used to save the Hdr.
|
|
ILboolean iSaveHdrInternal()
|
|
{
|
|
ILimage *TempImage;
|
|
rgbe_header_info stHeader;
|
|
unsigned char rgbe[4];
|
|
ILubyte *buffer;
|
|
ILfloat *data;
|
|
ILuint i;
|
|
ILboolean bRet;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
stHeader.exposure = 0;
|
|
stHeader.gamma = 0;
|
|
stHeader.programtype[0] = 0;
|
|
stHeader.valid = 0;
|
|
|
|
if (iCurImage->Format != IL_UNSIGNED_BYTE) {
|
|
TempImage = iConvertImage(iCurImage, IL_RGB, IL_FLOAT);
|
|
if (TempImage == NULL)
|
|
return IL_FALSE;
|
|
}
|
|
else
|
|
TempImage = iCurImage;
|
|
|
|
if (!RGBE_WriteHeader(TempImage->Width, TempImage->Height, &stHeader))
|
|
return IL_FALSE;
|
|
|
|
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
|
iFlipBuffer(TempImage->Data, TempImage->Depth, TempImage->Bps, TempImage->Height);
|
|
data = (ILfloat*)TempImage->Data;
|
|
|
|
if ((TempImage->Width < 8)||(TempImage->Width > 0x7fff)) {
|
|
/* run length encoding is not allowed so write flat*/
|
|
bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height);
|
|
if (iCurImage != TempImage)
|
|
ilCloseImage(TempImage);
|
|
return bRet;
|
|
}
|
|
buffer = (ILubyte*)ialloc(sizeof(ILubyte)*4*TempImage->Width);
|
|
if (buffer == NULL) {
|
|
/* no buffer space so write flat */
|
|
bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height);
|
|
if (iCurImage != TempImage)
|
|
ilCloseImage(TempImage);
|
|
return bRet;
|
|
}
|
|
|
|
while(TempImage->Height-- > 0) {
|
|
rgbe[0] = 2;
|
|
rgbe[1] = 2;
|
|
rgbe[2] = TempImage->Width >> 8;
|
|
rgbe[3] = TempImage->Width & 0xFF;
|
|
if (iwrite(rgbe, sizeof(rgbe), 1) < 1) {
|
|
free(buffer);
|
|
if (iCurImage != TempImage)
|
|
ilCloseImage(TempImage);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
for(i=0;i<TempImage->Width;i++) {
|
|
float2rgbe(rgbe,data[RGBE_DATA_RED],data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
|
buffer[i] = rgbe[0];
|
|
buffer[i+TempImage->Width] = rgbe[1];
|
|
buffer[i+2*TempImage->Width] = rgbe[2];
|
|
buffer[i+3*TempImage->Width] = rgbe[3];
|
|
data += RGBE_DATA_SIZE;
|
|
}
|
|
/* write out each of the four channels separately run length encoded */
|
|
/* first red, then green, then blue, then exponent */
|
|
for(i=0;i<4;i++) {
|
|
if (RGBE_WriteBytes_RLE(&buffer[i*TempImage->Width],TempImage->Width) != IL_TRUE) {
|
|
ifree(buffer);
|
|
if (iCurImage != TempImage)
|
|
ilCloseImage(TempImage);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
}
|
|
ifree(buffer);
|
|
|
|
if (iCurImage != TempImage)
|
|
ilCloseImage(TempImage);
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
#endif//IL_NO_HDR
|