Add DevIL 1.7.8.

This commit is contained in:
rude
2013-09-26 00:20:08 +02:00
parent 6e493fb605
commit c065120c58
487 changed files with 219483 additions and 0 deletions
@@ -0,0 +1,40 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Last modified: 17/04/2005
// by Meloni Dario
//
// Description: Common altivec function.
//
//-----------------------------------------------------------------------------
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif //HAVE_CONFIG_H
#ifdef ALTIVEC_GCC
#include "altivec_common.h"
// from http://developer.apple.com/hardware/ve/alignment.html
/*vector unsigned char load_unaligned( unsigned char *buffer ) {
vector unsigned char MSQ, LSQ;
vector unsigned char mask;
MSQ = vec_ld(0, buffer); // most significant quadword
LSQ = vec_ld(15, buffer); // least significant quadword
mask = vec_lvsl(0, buffer); // create the permute mask
return vec_perm(MSQ, LSQ, mask);// align the data
}*/
vector float fill_vector_f( float value ) {
vector_t vec;
vec.sf[0] = value;
vector float temp = vec_ld(0,vec.sf);
return vec_splat(temp,0);
}
inline unsigned int round16( unsigned int v ) {
return ((int)((v/16)*10)%10) > 0 ? (v/16) : (v/16)+1;
}
#endif
@@ -0,0 +1,230 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif //HAVE_CONFIG_H
#ifdef ALTIVEC_GCC
#include "altivec_typeconversion.h"
static inline void abc2cba_internal( register const vector unsigned char p[4], unsigned char *data, register unsigned int length, unsigned char *newdata ) {
register vector unsigned char d0,d1,d2,t0,t1,t2;
length = eround16(length);
if( length >= 3 ) {
length -= 3;
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
while( length >= 3 ) {
t0 = vec_perm(d0,d1,p[0]);
t1 = vec_perm(d1,d0,p[1]);
t2 = vec_perm(d2,d1,p[2]);
t1 = vec_perm(t1,d2,p[3]);
vec_st(t0,0,newdata);
vec_st(t1,16,newdata);
vec_st(t2,32,newdata);
length -= 3;
data += 16*3;
newdata += 16*3;
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
}
t0 = vec_perm(d0,d1,p[0]);
t1 = vec_perm(d1,d0,p[1]);
t2 = vec_perm(d2,d1,p[2]);
t1 = vec_perm(t1,d2,p[3]);
vec_st(t0,0,newdata);
vec_st(t1,16,newdata);
vec_st(t2,32,newdata);
}
if( length == 2 ) {
d0 = vec_ld(0,data);
d1 = vec_ld(16,data);
t0 = vec_perm(d0,d1,p[0]);
t1 = vec_perm(d1,d0,p[1]);
vec_st(t0,0,newdata);
vec_st(t1,16,newdata);
} else if( length == 1 ) {
d0 = vec_ld(0,data);
t0 = vec_perm(d0,d0,p[0]);
vec_st(t0,0,newdata);
}
}
static inline void abcd2cbad_internal( register const vector unsigned char p, unsigned char *data, unsigned int length, unsigned char *newdata ) {
register vector unsigned char d0,d1,d2,z;
z = vec_splat_u8(0);
length = eround16(length);
if( length >= 3 ) {
length -= 3;
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
while( length >= 3 ) {
d0 = vec_perm(d0,z,p);
d1 = vec_perm(d1,z,p);
d2 = vec_perm(d2,z,p);
vec_st(d0,0,newdata);
vec_st(d1,16,newdata);
vec_st(d2,32,newdata);
length -= 3;
data += 16*3;
newdata += 16*3;
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
}
d0 = vec_perm(d0,z,p);
d1 = vec_perm(d1,z,p);
d2 = vec_perm(d2,z,p);
vec_st(d0,0,newdata);
vec_st(d1,16,newdata);
vec_st(d2,32,newdata);
}
if( length == 2 ) {
d0 = vec_ld(0,data);
d1 = vec_ld(16,data);
d0 = vec_perm(d0,z,p);
d1 = vec_perm(d1,z,p);
vec_st(d0,0,newdata);
vec_st(d1,16,newdata);
} else if( length == 1 ) {
d0 = vec_ld(0,data);
d0 = vec_perm(d0,d0,z);
vec_st(d0,0,newdata);
}
}
// Format conversion function
void abc2cba_byte( ILubyte *data, ILuint length, ILubyte *newdata ) {
const vector unsigned char p[4] =
{ (vector unsigned char)(0x02,0x01,0x00,0x05,0x04,0x03,0x08,0x07,0x06,0x0B,0x0A,0x09,0x0E,0x0D,0x0C,0x11),
(vector unsigned char)(0x00,0x10,0x04,0x03,0x02,0x07,0x06,0x05,0x0A,0x09,0x08,0x0D,0x0C,0x0B,0x0E,0x0F),
(vector unsigned char)(0x1E,0x03,0x02,0x01,0x06,0x05,0x04,0x09,0x08,0x07,0x0C,0x0B,0x0A,0x0F,0x0E,0x0D),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x10,0x0F)};
abc2cba_internal(p,data,length,newdata);
}
void abc2cba_short( ILushort *data, ILuint length, ILushort *newdata ) {
const vector unsigned char p[4] =
{ (vector unsigned char)(0x04,0x05,0x02,0x03,0x00,0x01,0x0A,0x0B,0x08,0x09,0x06,0x07,0x10,0x11,0x0E,0x0F),
(vector unsigned char)(0x1C,0x1D,0x06,0x07,0x04,0x05,0x02,0x03,0x0C,0x0D,0x0A,0x0B,0x08,0x09,0x0E,0x0F),
(vector unsigned char)(0x00,0x01,0x1E,0x1F,0x08,0x09,0x06,0x07,0x04,0x05,0x0E,0x0F,0x0C,0x0D,0x0A,0x0B),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x12,0x13)};
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
}
void abc2cba_int( ILuint *data, ILuint length, ILuint *newdata ) {
const vector unsigned char p[4] =
{ (vector unsigned char)(0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x14,0x15,0x16,0x17),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x1C,0x1D,0x1E,0x1F,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
(vector unsigned char)(0x18,0x19,0x1A,0x1B,0x0C,0x0D,0x0E,0x0F,0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x0C,0x0D,0x0E,0x0F)};
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
}
void abc2cba_double( ILdouble *data, ILuint length, ILdouble *newdata ) {
const vector unsigned char p[4] =
{ (vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
(vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F),
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F)};
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
}
void abcd2cbad_byte( ILubyte *data, ILuint length, ILubyte *newdata ) {
const vector unsigned char p = (vector unsigned char)(0x02,0x01,0x00,0x03,0x06,0x05,0x04,0x07,0x0A,0x09,0x08,0x0B, 0x0E,0x0D,0x0C,0x0F);
abcd2cbad_internal(p,data,length,newdata);
}
void abcd2cbad_short( ILushort *data, ILuint length, ILushort *newdata ) {
const vector unsigned char p = (vector unsigned char)(0x04,0x05,0x02,0x03,0x00,0x01,0x06,0x07,0x0C,0x0D,0x0A,0x0B,0x08,0x09,0x0E,0x0F);
abcd2cbad_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
}
void abcd2cbad_int( ILuint *data, ILuint length, ILuint *newdata ) {
const vector unsigned char p = (vector unsigned char)(0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0C,0x0D,0x0E,0x0F);
abcd2cbad_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
}
void abcd2cbad_double( ILdouble *tdata, ILuint length, ILdouble *tnewdata ) {
register ILubyte *data = (ILubyte*)tdata;
register ILubyte *newdata = (ILubyte*)tnewdata;
const vector unsigned char p = (vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F);
register vector unsigned char d0,d1,d2,d3,t0,t1,t2,t3;
length = eround16(length);
if( length >= 4 ) {
length -= 4;
d3 = vec_ld(48,data);
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
while( length >= 4 ) {
t0 = vec_perm(d0,d1,p);
t1 = vec_perm(d1,d0,p);
t2 = vec_perm(d2,d3,p);
t3 = vec_perm(d3,d2,p);
vec_st(t0,0,newdata);
vec_st(t1,16,newdata);
vec_st(t2,32,newdata);
vec_st(t3,48,newdata);
length -= 4;
data += 16*4;
newdata += 16*4;
d3 = vec_ld(48,data);
d2 = vec_ld(32,data);
d1 = vec_ld(16,data);
d0 = vec_ld(0,data);
}
t0 = vec_perm(d0,d1,p);
t1 = vec_perm(d1,d0,p);
t2 = vec_perm(d2,d3,p);
t3 = vec_perm(d3,d2,p);
vec_st(d0,0,newdata);
vec_st(d1,16,newdata);
vec_st(d2,32,newdata);
vec_st(d3,48,newdata);
}
if( length == 2 ) {
d0 = vec_ld(0,data);
d1 = vec_ld(16,data);
t0 = vec_perm(d0,d1,p);
t1 = vec_perm(d1,d0,p);
vec_st(t0,0,newdata);
vec_st(t1,16,newdata);
}
}
#endif
+287
View File
@@ -0,0 +1,287 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Last modified: 08/17/2008
//
// Filename: src-IL/src/il_alloc.c
//
// Description: Memory allocation functions
//
//-----------------------------------------------------------------------------
#define __ALLOC_C
// Memory leak detection
#ifdef _WIN32
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#ifndef _WIN32_WCE // Does not have this header.
#include <crtdbg.h>
#endif
#endif
#endif//_WIN32
#include "il_internal.h"
#include <stdlib.h>
#include <math.h>
#ifdef MM_MALLOC
#include <mm_malloc.h>
#endif
static void ILAPIENTRY DefaultFreeFunc(const void * CONST_RESTRICT Ptr);
static void* ILAPIENTRY DefaultAllocFunc(const ILsizei Size);
static mAlloc ialloc_ptr = DefaultAllocFunc;
static mFree ifree_ptr = DefaultFreeFunc;
/*** Vector Allocation/Deallocation Function ***/
#ifdef VECTORMEM
void *vec_malloc(const ILsizei size)
{
const ILsizei _size = size % 16 > 0 ? size + 16 - (size % 16) : size; // align size value
#ifdef MM_MALLOC
return _mm_malloc(_size,16);
#else
#ifdef VALLOC
return valloc( _size );
#else
#ifdef POSIX_MEMALIGN
char *buffer;
return posix_memalign((void**)&buffer, 16, _size) == 0 ? buffer : NULL;
#else
#ifdef MEMALIGN
return memalign( 16, _size );
#else
// Memalign hack from ffmpeg for MinGW
void *ptr;
int diff;
ptr = malloc(_size+16+1);
diff= ((-(int)ptr - 1)&15) + 1;
ptr = (void*)(((char*)ptr)+diff);
((char*)ptr)[-1]= diff;
return ptr;
#endif //MEMALIGN
#endif //POSIX_MEMALIGN
#endif //VALLOC
#endif //MM_MALLOC
}
void *ivec_align_buffer(void *buffer, const ILsizei size)
{
if( (ILsizei)buffer % 16 != 0 ) {
void *aligned_buffer = vec_malloc( size );
memcpy( aligned_buffer, buffer, size );
ifree( buffer );
return aligned_buffer;
}
return buffer;
}
#endif
/*** Allocation/Deallocation Function ***/
void* ILAPIENTRY ialloc(const ILsizei Size)
{
void *Ptr = ialloc_ptr(Size);
if (Ptr == NULL)
ilSetError(IL_OUT_OF_MEMORY);
return Ptr;
}
void ILAPIENTRY ifree(const void * CONST_RESTRICT Ptr)
{
if (Ptr == NULL)
return;
ifree_ptr(Ptr);
return;
}
void* ILAPIENTRY icalloc(const ILsizei Size, const ILsizei Num)
{
void *Ptr = ialloc(Size * Num);
if (Ptr == NULL)
return Ptr;
imemclear(Ptr, Size * Num);
return Ptr;
}
/*** Default Allocation/Deallocation Function ***/
static void* ILAPIENTRY DefaultAllocFunc(const ILsizei Size)
{
#ifdef VECTORMEM
return (void*)vec_malloc(Size);
#else
return malloc(Size);
#endif //VECTORMEM
}
static void ILAPIENTRY DefaultFreeFunc(const void * CONST_RESTRICT ptr)
{
if (ptr)
{
#ifdef MM_MALLOC
_mm_free((void*)ptr);
#else
#if defined(VECTORMEM) & !defined(POSIX_MEMALIGN) & !defined(VALLOC) & !defined(MEMALIGN) & !defined(MM_MALLOC)
free(((char*)Ptr) - ((char*)Ptr)[-1]);
#else
free((void*)ptr);
#endif //OTHERS...
#endif //MM_MALLOC
}
}
/*** Manipulate Allocation/Deallocation Function ***/
void ILAPIENTRY ilResetMemory() // Deprecated
{
ialloc_ptr = DefaultAllocFunc;
ifree_ptr = DefaultFreeFunc;
}
void ILAPIENTRY ilSetMemory(mAlloc AllocFunc, mFree FreeFunc)
{
ialloc_ptr = AllocFunc == NULL ? DefaultAllocFunc : AllocFunc;
ifree_ptr = FreeFunc == NULL ? DefaultFreeFunc : FreeFunc;
}
/*#if defined(_WIN32) && defined(_MEM_DEBUG)
#include <windows.h>
int bAtexit = 0;
typedef struct ALLOC_INFO
{
unsigned long address;
unsigned long size;
char file[64];
unsigned long line;
struct ALLOC_INFO *Next;
} ALLOC_INFO;
ALLOC_INFO *AllocList;
void AddTrack(unsigned long addr, unsigned long size, const char *file, unsigned long line)
{
ALLOC_INFO *Temp;
if (AllocList == NULL) {
AllocList = (ALLOC_INFO*)malloc(sizeof(ALLOC_INFO)); // Just assume it succeeds.
AllocList->address = addr;
AllocList->size = size;
AllocList->line = line;
strncpy(AllocList->file, file, 63);
AllocList->Next = NULL;
}
else {
Temp = AllocList;
AllocList = (ALLOC_INFO*)malloc(sizeof(ALLOC_INFO)); // Just assume it succeeds.
AllocList->address = addr;
AllocList->size = size;
AllocList->line = line;
strncpy(AllocList->file, file, 63);
AllocList->Next = Temp;
}
return;
}
void RemoveTrack(unsigned long addr)
{
ALLOC_INFO *Temp, *Prev;
Temp = AllocList;
Prev = NULL;
if (Temp == NULL)
return;
while (Temp != NULL) {
if (Temp->address == addr) {
if (Prev == NULL) {
AllocList = Temp->Next;
free(Temp);
}
else {
Prev->Next = Temp->Next;
free(Temp);
}
break;
}
Prev = Temp;
Temp = Temp->Next;
}
return;
}
void DumpUnfreed(void)
{
unsigned long TotalSize = 0;
char buf[1024];
ALLOC_INFO *i = AllocList;
OutputDebugString("DevIL Unfreed Information:\n");
while (i != NULL) {
sprintf(buf, "%s(%d) : %d bytes unfreed at %d\n", i->file, i->line, i->size, i->address);
OutputDebugString(buf);
TotalSize += i->size;
AllocList = i->Next;
free(i);
i = AllocList;
}
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString(buf);
sprintf(buf, "Total Unfreed: %d bytes\n\n\n", TotalSize);
OutputDebugString(buf);
}
void AddToAtexit()
{
if (bAtexit)
return;
atexit(DumpUnfreed);
bAtexit = 1;
}
void *c_alloc(unsigned long size, unsigned long num, const char *file, unsigned long line)
{
void *ptr;
ptr = calloc(size, num);
if (!ptr)
return NULL;
AddToAtexit();
AddTrack((unsigned long)ptr, size * num, file, line);
return ptr;
}
void *m_alloc(unsigned long size, const char *file, unsigned long line)
{
void *ptr;
ptr = malloc(size);
if (!ptr)
return NULL;
AddToAtexit();
AddTrack((unsigned long)ptr, size, file, line);
return ptr;
}
void f_ree(void *ptr)
{
RemoveTrack((unsigned long)ptr);
free(ptr);
return;
}
#endif//defined(_WIN32) && defined(_MEM_DEBUG)*/
+185
View File
@@ -0,0 +1,185 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 08/14/2004
//
// Filename: src-IL/src/il_bits.c
//
// Description: Implements a file class that reads/writes bits directly.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include "il_bits.h"
// Opens a BITFILE just like fopen opens a FILE.
/*BITFILE *bopen(const char *FileName, const char *Mode)
{
BITFILE *ToReturn = NULL;
if (FileName != NULL) {
ToReturn = (BITFILE*)ialloc(sizeof(BITFILE));
if (ToReturn != NULL) {
iopenr((char*)FileName);
ToReturn->File = iGetFile();
ToReturn->BitPos = 0;
ToReturn->ByteBitOff = 8;
ToReturn->Buff = 0;
}
}
return ToReturn;
}*/
// Converts a FILE to a BITFILE.
BITFILE *bfile(ILHANDLE File)
{
BITFILE *ToReturn = NULL;
if (File != NULL) {
ToReturn = (BITFILE*)ialloc(sizeof(BITFILE));
if (ToReturn != NULL) {
ToReturn->File = File;
ToReturn->BitPos = itell() << 3;
ToReturn->ByteBitOff = 8;
ToReturn->Buff = 0;
}
}
return ToReturn;
}
// Closes an open BITFILE and frees memory for it.
ILint bclose(BITFILE *BitFile)
{
if (BitFile == NULL || BitFile->File == NULL)
return IL_EOF;
// Removed 01-26-2008. The file will get closed later by
// the calling function.
//icloser(BitFile->File);
ifree(BitFile);
return 0;
}
// Returns the current bit position of a BITFILE.
ILint btell(BITFILE *BitFile)
{
return BitFile->BitPos;
}
// Seeks in a BITFILE just like fseek for FILE.
ILint bseek(BITFILE *BitFile, ILuint Offset, ILuint Mode)
{
ILint KeepPos, Len;
if (BitFile == NULL || BitFile->File == NULL)
return 1;
switch (Mode)
{
case IL_SEEK_SET:
if (!iseek(Offset >> 3, Mode)) {
BitFile->BitPos = Offset;
BitFile->ByteBitOff = BitFile->BitPos % 8;
}
break;
case IL_SEEK_CUR:
if (!iseek(Offset >> 3, Mode)) {
BitFile->BitPos += Offset;
BitFile->ByteBitOff = BitFile->BitPos % 8;
}
break;
case IL_SEEK_END:
KeepPos = itell();
iseek(0, IL_SEEK_END);
Len = itell();
iseek(0, IL_SEEK_SET);
if (!iseek(Offset >> 3, Mode)) {
BitFile->BitPos = (Len << 3) + Offset;
BitFile->ByteBitOff = BitFile->BitPos % 8;
}
break;
default:
return 1;
}
return 0;
}
// hehe, "bread". It reads data into Buffer from the BITFILE, just like fread for FILE.
ILint bread(void *Buffer, ILuint Size, ILuint Number, BITFILE *BitFile)
{
// Note that this function is somewhat useless: In binary image
// formats, there are some pad bits after each scanline. This
// function does not take that into account, so you must use bseek to
// skip the calculated value of bits.
ILuint BuffPos = 0, Count = Size * Number;
while (BuffPos < Count) {
if (BitFile->ByteBitOff < 0 || BitFile->ByteBitOff > 7) {
BitFile->ByteBitOff = 7;
if (iread(&BitFile->Buff, 1, 1) != 1) // Reached eof or error...
return BuffPos;
}
*((ILubyte*)(Buffer) + BuffPos) = (ILubyte)!!(BitFile->Buff & (1 << BitFile->ByteBitOff));
BuffPos++;
BitFile->ByteBitOff--;
}
return BuffPos;
}
// Reads bits and puts the first bit in the file as the highest in the return value.
ILuint breadVal(ILuint NumBits, BITFILE *BitFile)
{
ILuint BuffPos = 0;
ILuint Buffer = 0;
// Only returning up to 32 bits at one time
if (NumBits > 32) {
ilSetError(IL_INTERNAL_ERROR);
return 0;
}
while (BuffPos < NumBits) {
Buffer <<= 1;
if (BitFile->ByteBitOff < 0 || BitFile->ByteBitOff > 7) {
BitFile->ByteBitOff = 7;
if (iread(&BitFile->Buff, 1, 1) != 1) // Reached eof or error...
return BuffPos;
}
Buffer = Buffer + (ILubyte)!!(BitFile->Buff & (1 << BitFile->ByteBitOff));
BuffPos++;
BitFile->ByteBitOff--;
}
return BuffPos;
}
// Not implemented yet.
/*ILint bwrite(void *Buffer, ILuint Size, ILuint Number, BITFILE *BitFile)
{
return 0;
}*/
+736
View File
@@ -0,0 +1,736 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/14/2009
//
// Filename: src-IL/src/il_blp.c
//
// Description: Reads from a Blizzard Texture (.blp).
// Specifications were found at http://www.wowwiki.com/BLP_files
// for BLP2 and from
// http://web.archive.org/web/20080117120549/magos.thejefffiles.com/War3ModelEditor/MagosBlpFormat.txt
// for BLP1.
//
//-----------------------------------------------------------------------------
//@TODO: Add support for the BLP1 format as well.
#include "il_internal.h"
#ifndef IL_NO_BLP
#include "il_dds.h"
typedef struct BLP1HEAD
{
ILubyte Sig[4];
ILuint Compression; // Texture type: 0 = JPG, 1 = Paletted
ILuint Flags; // #8 - Uses alpha channel (?)
ILuint Width; // Image width in pixels
ILuint Height; // Image height in pixels
ILuint PictureType; // 3 - Uncompressed index list + alpha list
// 4 - Uncompressed index list + alpha list
// 5 - Uncompressed index list
ILuint PictureSubType; // 1 - ???
ILuint MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
ILuint MipLengths[16]; // The length of each mipmap data block
} BLP1HEAD;
typedef struct BLP2HEAD
{
ILubyte Sig[4]; // "BLP2" signature
ILuint Type; // Texture type: 0 = JPG, 1 = DXTC
ILubyte Compression; // Compression mode: 1 = raw, 2 = DXTC
ILubyte AlphaBits; // 0, 1, or 8
ILubyte AlphaType; // 0, 1, 7 or 8
ILubyte HasMips; // 0 = no mips levels, 1 = has mips (number of levels determined by image size)
ILuint Width; // Image width in pixels
ILuint Height; // Image height in pixels
ILuint MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
ILuint MipLengths[16]; // The length of each mipmap data block
} BLP2HEAD;
// Data formats
#define BLP_TYPE_JPG 0
#define BLP_TYPE_DXTC_RAW 1
#define BLP_RAW 1
#define BLP_DXTC 2
#define BLP_RAW_PLUS_ALPHA1 3
#define BLP_RAW_PLUS_ALPHA2 4
#define BLP_RAW_NO_ALPHA 5
ILboolean iIsValidBlp2(void);
ILboolean iCheckBlp2(BLP2HEAD *Header);
ILboolean iLoadBlpInternal(void);
ILboolean iLoadBlp1(void);
ILboolean iCheckBlp1(BLP1HEAD *Header);
ILboolean iGetBlp1Head(BLP1HEAD *Header);
//! Checks if the file specified in FileName is a valid BLP file.
ILboolean ilIsValidBlp(ILconst_string FileName)
{
ILHANDLE BlpFile;
ILboolean bBlp = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("blp"))) {
ilSetError(IL_INVALID_EXTENSION);
return bBlp;
}
BlpFile = iopenr(FileName);
if (BlpFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bBlp;
}
bBlp = ilIsValidBlpF(BlpFile);
icloser(BlpFile);
return bBlp;
}
//! Checks if the ILHANDLE contains a valid BLP file at the current position.
ILboolean ilIsValidBlpF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidBlp2();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid BLP lump.
ILboolean ilIsValidBlpL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidBlp2();
}
// Internal function used to get the BLP header from the current file.
ILboolean iGetBlp2Head(BLP2HEAD *Header)
{
ILuint i;
iread(Header->Sig, 1, 4);
Header->Type = GetLittleUInt();
Header->Compression = igetc();
Header->AlphaBits = igetc();
Header->AlphaType = igetc();
Header->HasMips = igetc();
Header->Width = GetLittleUInt();
Header->Height = GetLittleUInt();
for (i = 0; i < 16; i++)
Header->MipOffsets[i] = GetLittleUInt();
for (i = 0; i < 16; i++)
Header->MipLengths[i] = GetLittleUInt();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidBlp2(void)
{
BLP2HEAD Header;
if (!iGetBlp2Head(&Header))
return IL_FALSE;
iseek(-148, IL_SEEK_CUR);
return iCheckBlp2(&Header);
}
// Internal function used to check if the HEADER is a valid BLP header.
ILboolean iCheckBlp2(BLP2HEAD *Header)
{
// The file signature is 'BLP2'.
if (strncmp(Header->Sig, "BLP2", 4))
return IL_FALSE;
// Valid types are JPEG and DXTC. JPEG is not common, though.
// WoW only uses DXTC.
if (Header->Type != BLP_TYPE_JPG && Header->Type != BLP_TYPE_DXTC_RAW)
return IL_FALSE;
// For BLP_TYPE_DXTC_RAW, we can have RAW and DXTC compression.
if (Header->Compression != BLP_RAW && Header->Compression != BLP_DXTC)
return IL_FALSE;
// Alpha bits can only be 0, 1 and 8.
if (Header->AlphaBits != 0 && Header->AlphaBits != 1 && Header->AlphaBits != 8)
return IL_FALSE;
// Alpha type can only be 0, 1, 7 and 8.
if (Header->AlphaType != 0 && Header->AlphaType != 1 && Header->AlphaType != 7 && Header->AlphaType != 8)
return IL_FALSE;
// Width or height of 0 makes no sense.
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a BLP file
ILboolean ilLoadBlp(ILconst_string FileName)
{
ILHANDLE BlpFile;
ILboolean bBlp = IL_FALSE;
BlpFile = iopenr(FileName);
if (BlpFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bBlp;
}
bBlp = ilLoadBlpF(BlpFile);
icloser(BlpFile);
return bBlp;
}
//! Reads an already-opened BLP file
ILboolean ilLoadBlpF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadBlpInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a BLP
ILboolean ilLoadBlpL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadBlpInternal();
}
// Internal function used to load the BLP.
ILboolean iLoadBlpInternal(void)
{
BLP2HEAD Header;
ILubyte *CompData;
ILimage *Image;
ILuint Mip, j, x, CompSize, AlphaSize, AlphaOff;
ILint y;
ILboolean BaseCreated = IL_FALSE;
ILubyte *DataAndAlpha = NULL, *Palette = NULL, AlphaMask; //, *JpegHeader, *JpegData;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetBlp2Head(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!iCheckBlp2(&Header)) {
goto check_blp1;
}
//@TODO: Remove this!
if (Header.Type != BLP_TYPE_DXTC_RAW)
return IL_FALSE;
switch (Header.Compression)
{
case BLP_RAW:
for (Mip = 0; Mip < 16; Mip++) { // Possible maximum of 16 mipmaps
if (BaseCreated) {
if (Header.HasMips == 0) // Does not have mipmaps, so we are done.
break;
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
break;
if (Header.MipOffsets[Mip] == 0 || Header.MipLengths == 0) // No more mipmaps in the file.
break;
}
switch (Header.AlphaBits)
{
case 0:
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
Image = iCurImage;
BaseCreated = IL_TRUE;
Image->Pal.Palette = (ILubyte*)ialloc(256 * 4); // 256 entries of ARGB8888 values (1024).
if (Image->Pal.Palette == NULL)
return IL_FALSE;
Image->Pal.PalSize = 1024;
Image->Pal.PalType = IL_PAL_BGRA32; //@TODO: Find out if this is really BGRA data.
if (iread(Image->Pal.Palette, 1, 1024) != 1024) // Read in the palette.
return IL_FALSE;
}
else {
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
// Copy the palette from the first image before we change our Image pointer.
iCopyPalette(&Image->Mipmaps->Pal, &Image->Pal);
// Move to the next mipmap in the linked list.
Image = Image->Mipmaps;
}
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
// These two should be the same (tells us how much data is in the file for this mipmap level).
if (Header.MipLengths[Mip] != Image->SizeOfData) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Finally read in the image data.
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
return IL_FALSE;
break;
case 1:
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
Image = iCurImage;
BaseCreated = IL_TRUE;
Palette = (ILubyte*)ialloc(256 * 4);
if (Palette == NULL)
return IL_FALSE;
// Read in the palette.
if (iread(Palette, 1, 1024) != 1024) {
ifree(Palette);
return IL_FALSE;
}
// We only allocate this once and reuse this buffer with every mipmap (since successive ones are smaller).
DataAndAlpha = (ILubyte*)ialloc(Image->Width * Image->Height);
if (DataAndAlpha == NULL) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
}
else {
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
// Move to the next mipmap in the linked list.
Image = Image->Mipmaps;
}
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
// Determine the size of the alpha data following the color indices.
AlphaSize = Image->Width * Image->Height / 8;
if (AlphaSize == 0)
AlphaSize = 1; // Should never be 0.
// These two should be the same (tells us how much data is in the file for this mipmap level).
if (Header.MipLengths[Mip] != Image->SizeOfData / 4 + AlphaSize) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Seek to the data and read it.
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
if (iread(DataAndAlpha, Image->Width * Image->Height, 1) != 1) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
// Convert the color-indexed data to BGRX.
for (j = 0; j < Image->Width * Image->Height; j++) {
Image->Data[j*4] = Palette[DataAndAlpha[j]*4];
Image->Data[j*4+1] = Palette[DataAndAlpha[j]*4+1];
Image->Data[j*4+2] = Palette[DataAndAlpha[j]*4+2];
}
// Read in the alpha list.
if (iread(DataAndAlpha, AlphaSize, 1) != 1) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
AlphaMask = 0x01; // Lowest bit
AlphaOff = 0;
// The really strange thing about this alpha data is that it is upside-down when compared to the
// regular color-indexed data, so we have to flip it.
for (y = Image->Height - 1; y >= 0; y--) {
for (x = 0; x < Image->Width; x++) {
if (AlphaMask == 0) { // Shifting it past the highest bit makes it 0, since we only have 1 byte.
AlphaOff++; // Move along the alpha buffer.
AlphaMask = 0x01; // Reset the alpha mask.
}
// This is just 1-bit alpha, so it is either on or off.
Image->Data[Image->Bps * y + x * 4 + 3] = DataAndAlpha[AlphaOff] & AlphaMask ? 0xFF : 0x00;
AlphaMask <<= 1;
}
}
break;
default:
//@TODO: Accept any other alpha values?
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
}
// Done, so we can finally free these two.
ifree(DataAndAlpha);
ifree(Palette);
break;
case BLP_DXTC:
for (Mip = 0; Mip < 16; Mip++) { // Possible maximum of 16 mipmaps
//@TODO: Other formats
//if (Header.AlphaBits == 0)
// if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
// return IL_FALSE;
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
Image = iCurImage;
BaseCreated = IL_TRUE;
}
else {
if (Header.HasMips == 0) // Does not have mipmaps, so we are done.
break;
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
break;
if (Header.MipOffsets[Mip] == 0 || Header.MipLengths[Mip] == 0) // No more mipmaps in the file.
break;
//@TODO: Other formats
// ilNewImageFull automatically changes widths and heights of 0 to 1, so we do not have to worry about it.
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
Image = Image->Mipmaps;
}
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
//@TODO: Only do the allocation once.
CompData = (ILubyte*)ialloc(Header.MipLengths[Mip]);
if (CompData == NULL)
return IL_FALSE;
// Read in the compressed mipmap data.
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
if (iread(CompData, 1, Header.MipLengths[Mip]) != Header.MipLengths[Mip]) {
ifree(CompData);
return IL_FALSE;
}
switch (Header.AlphaBits)
{
case 0: // DXT1 without alpha
case 1: // DXT1 with alpha
// Check to make sure that the MipLength reported is the size needed, so that
// DecompressDXT1 does not crash.
CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 8;
if (CompSize != Header.MipLengths[Mip]) {
ilSetError(IL_INVALID_FILE_HEADER);
ifree(CompData);
return IL_FALSE;
}
if (!DecompressDXT1(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
break;
case 8:
// Check to make sure that the MipLength reported is the size needed, so that
// DecompressDXT3/5 do not crash.
CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 16;
if (CompSize != Header.MipLengths[Mip]) {
ifree(CompData);
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
switch (Header.AlphaType)
{
case 0: // All three of
case 1: // these refer to
case 8: // DXT3...
if (!DecompressDXT3(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
break;
case 7: // DXT5 compression
if (!DecompressDXT5(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
break;
//default: // Should already be checked by iCheckBlp2.
}
break;
//default: // Should already be checked by iCheckBlp2.
}
//@TODO: Save DXTC data.
ifree(CompData);
}
break;
//default:
}
return ilFixImage();
check_blp1:
iseek(-148, IL_SEEK_CUR); // Go back the size of the BLP2 header, since we tried reading it.
return iLoadBlp1();
}
ILboolean iGetBlp1Head(BLP1HEAD *Header)
{
ILuint i;
iread(Header->Sig, 1, 4);
Header->Compression = GetLittleUInt();
Header->Flags = GetLittleUInt();
Header->Width = GetLittleUInt();
Header->Height = GetLittleUInt();
Header->PictureType = GetLittleUInt();
Header->PictureSubType = GetLittleUInt();
for (i = 0; i < 16; i++)
Header->MipOffsets[i] = GetLittleUInt();
for (i = 0; i < 16; i++)
Header->MipLengths[i] = GetLittleUInt();
return IL_TRUE;
}
ILboolean iCheckBlp1(BLP1HEAD *Header)
{
// The file signature is 'BLP1'.
if (strncmp(Header->Sig, "BLP1", 4))
return IL_FALSE;
// Valid types are JPEG and RAW. JPEG is not common, though.
if (Header->Compression != BLP_TYPE_JPG && Header->Compression != BLP_RAW)
return IL_FALSE;
//@TODO: Find out what Flags is for.
// PictureType determines whether this has an alpha list.
if (Header->PictureType != BLP_RAW_PLUS_ALPHA1 && Header->PictureType != BLP_RAW_PLUS_ALPHA2
&& Header->PictureType != BLP_RAW_NO_ALPHA)
return IL_FALSE;
// Width or height of 0 makes no sense.
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
return IL_TRUE;
}
ILboolean iLoadBlp1()
{
BLP1HEAD Header;
ILubyte *DataAndAlpha, *Palette;
ILuint i;
ILimage *Image = iCurImage;
ILboolean BaseCreated = IL_FALSE;
#ifndef IL_NO_JPG
ILubyte *JpegHeader, *JpegData;
ILuint JpegHeaderSize;
#endif//IL_NO_JPG
if (!iGetBlp1Head(&Header))
return IL_FALSE;
if (!iCheckBlp1(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
//@TODO: Remove this.
i = 0;
switch (Header.Compression)
{
case BLP_TYPE_JPG:
#ifdef IL_NO_JPG
// We can only do the Jpeg decoding if we do not have IL_NO_JPEG defined.
return IL_FALSE;
#else
JpegHeaderSize = GetLittleUInt();
JpegHeader = (ILubyte*)ialloc(JpegHeaderSize);
if (JpegHeader == NULL)
return IL_FALSE;
// Read the shared Jpeg header.
if (iread(JpegHeader, 1, JpegHeaderSize) != JpegHeaderSize) {
ifree(JpegHeader);
return IL_FALSE;
}
//for (i = 0; i < 16; i++) { // Possible maximum of 16 mipmaps
//@TODO: Check return value?
iseek(Header.MipOffsets[i], IL_SEEK_SET);
JpegData = (ILubyte*)ialloc(JpegHeaderSize + Header.MipLengths[i]);
if (JpegData == NULL) {
ifree(JpegHeader);
return IL_FALSE;
}
memcpy(JpegData, JpegHeader, JpegHeaderSize);
if (iread(JpegData + JpegHeaderSize, Header.MipLengths[i], 1) != 1)
return IL_FALSE;
// Just send the data straight to the Jpeg loader.
if (!ilLoadJpegL(JpegData, JpegHeaderSize + Header.MipLengths[i]))
return IL_FALSE;
// The image data is in BGR(A) order, even though it is Jpeg-compressed.
if (Image->Format == IL_RGBA)
Image->Format = IL_BGRA;
if (Image->Format == IL_RGB)
Image->Format = IL_BGR;
ifree(JpegData);
//}
ifree(JpegHeader);
#endif//IL_NO_JPG
break;
case BLP_RAW:
switch (Header.PictureType)
{
// There is no alpha list, so we just read like a normal indexed image.
case BLP_RAW_NO_ALPHA:
for (i = 0; i < 16; i++) { // Possible maximum of 16 mipmaps
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
Image = iCurImage;
BaseCreated = IL_TRUE;
// We have a BGRA palette.
Image->Pal.Palette = (ILubyte*)ialloc(256 * 4);
if (Image->Pal.Palette == NULL)
return IL_FALSE;
Image->Pal.PalSize = 1024;
Image->Pal.PalType = IL_PAL_BGRA32;
// Read in the palette ...
if (iread(Image->Pal.Palette, 1, 1024) != 1024)
return IL_FALSE;
}
else {
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
break;
if (Header.MipOffsets[i] == 0 || Header.MipLengths[i] == 0) // No more mipmaps in the file.
break;
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOR_INDEX, IL_UNSIGNED_BYTE, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
// Copy the palette from the first image before we change our Image pointer.
Image->Mipmaps->Pal.Palette = (ILubyte*)ialloc(256 * 4);
if (Image->Mipmaps->Pal.Palette == NULL)
return IL_FALSE;
Image->Mipmaps->Pal.PalSize = 1024;
Image->Mipmaps->Pal.PalType = IL_PAL_BGRA32;
memcpy(Image->Mipmaps->Pal.Palette, Image->Pal.Palette, 1024);
// Move to the next mipmap in the linked list.
Image = Image->Mipmaps;
}
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
// Seek to the data and read it.
iseek(Header.MipOffsets[i], IL_SEEK_SET);
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
return IL_FALSE;
}
break;
// These cases are identical and have an alpha list following the image data.
case BLP_RAW_PLUS_ALPHA1:
case BLP_RAW_PLUS_ALPHA2:
// Create the image.
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
DataAndAlpha = (ILubyte*)ialloc(Header.Width * Header.Height);
Palette = (ILubyte*)ialloc(256 * 4);
if (DataAndAlpha == NULL || Palette == NULL) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
// Read in the data and the palette.
if (iread(Palette, 1, 1024) != 1024) {
ifree(Palette);
return IL_FALSE;
}
// Seek to the data and read it.
iseek(Header.MipOffsets[i], IL_SEEK_SET);
if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
// Convert the color-indexed data to BGRX.
for (i = 0; i < Header.Width * Header.Height; i++) {
Image->Data[i*4] = Palette[DataAndAlpha[i]*4];
Image->Data[i*4+1] = Palette[DataAndAlpha[i]*4+1];
Image->Data[i*4+2] = Palette[DataAndAlpha[i]*4+2];
}
// Read in the alpha list.
if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
ifree(DataAndAlpha);
ifree(Palette);
return IL_FALSE;
}
// Finally put the alpha data into the image data.
for (i = 0; i < Header.Width * Header.Height; i++) {
Image->Data[i*4+3] = DataAndAlpha[i];
}
ifree(DataAndAlpha);
ifree(Palette);
break;
}
break;
//default: // Should already be checked by iCheckBlp1.
}
// Set the origin (always upper left).
Image->Origin = IL_ORIGIN_UPPER_LEFT;
return ilFixImage();
}
#endif//IL_NO_BLP
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+148
View File
@@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 10/10/2006
//
// Filename: src-IL/src/il_cut.c
//
// Description: Reads a Dr. Halo .cut file
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_CUT
#include "il_manip.h"
#include "il_pal.h"
#include "il_bits.h"
// Wrap it just in case...
#ifdef _MSC_VER
#pragma pack(push, packed_struct, 1)
#endif
typedef struct CUT_HEAD
{
ILushort Width;
ILushort Height;
ILint Dummy;
} IL_PACKSTRUCT CUT_HEAD;
#ifdef _MSC_VER
#pragma pack(pop, packed_struct)
#endif
ILboolean iLoadCutInternal();
//! Reads a .cut file
ILboolean ilLoadCut(ILconst_string FileName)
{
ILHANDLE CutFile;
ILboolean bCut = IL_FALSE;
CutFile = iopenr(FileName);
if (CutFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bCut;
}
bCut = ilLoadCutF(CutFile);
icloser(CutFile);
return bCut;
}
//! Reads an already-opened .cut file
ILboolean ilLoadCutF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadCutInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .cut
ILboolean ilLoadCutL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadCutInternal();
}
// Note: .Cut support has not been tested yet!
// A .cut can only have 1 bpp.
// We need to add support for the .pal's PSP outputs with these...
ILboolean iLoadCutInternal()
{
CUT_HEAD Header;
ILuint Size, i = 0, j;
ILubyte Count, Run;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Header.Width = GetLittleShort();
Header.Height = GetLittleShort();
Header.Dummy = GetLittleInt();
if (Header.Width == 0 || Header.Height == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) { // always 1 bpp
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
Size = Header.Width * Header.Height;
while (i < Size) {
Count = igetc();
if (Count == 0) { // end of row
igetc(); // Not supposed to be here, but
igetc(); // PSP is putting these two bytes here...WHY?!
continue;
}
if (Count & BIT_7) { // rle-compressed
ClearBits(Count, BIT_7);
Run = igetc();
for (j = 0; j < Count; j++) {
iCurImage->Data[i++] = Run;
}
}
else { // run of pixels
for (j = 0; j < Count; j++) {
iCurImage->Data[i++] = igetc();
}
}
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; // Not sure
/*iCurImage->Pal.Palette = SharedPal.Palette;
iCurImage->Pal.PalSize = SharedPal.PalSize;
iCurImage->Pal.PalType = SharedPal.PalType;*/
return ilFixImage();
}
/* ?????????
void ilPopToast() {
ILstring flipCode = IL_TEXT("#flipCode and www.flipCode.com rule you all.");
flipCode[0] = flipCode[0];
}
*/
#endif//IL_NO_CUT
+486
View File
@@ -0,0 +1,486 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_dcx.c
//
// Description: Reads from a .dcx file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_DCX
#include "il_dcx.h"
#include "il_manip.h"
//! Checks if the file specified in FileName is a valid .dcx file.
ILboolean ilIsValidDcx(ILconst_string FileName)
{
ILHANDLE DcxFile;
ILboolean bDcx = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("dcx"))) {
ilSetError(IL_INVALID_EXTENSION);
return bDcx;
}
DcxFile = iopenr(FileName);
if (DcxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDcx;
}
bDcx = ilIsValidDcxF(DcxFile);
icloser(DcxFile);
return bDcx;
}
//! Checks if the ILHANDLE contains a valid .dcx file at the current position.
ILboolean ilIsValidDcxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidDcx();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .dcx lump.
ILboolean ilIsValidDcxL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidDcx();
}
// Internal function obtain the .dcx header from the current file.
ILboolean iGetDcxHead(DCXHEAD *Head)
{
Head->Xmin = GetLittleUShort();
Head->Ymin = GetLittleUShort();
Head->Xmax = GetLittleUShort();
Head->Ymax = GetLittleUShort();
Head->HDpi = GetLittleUShort();
Head->VDpi = GetLittleUShort();
Head->Bps = GetLittleUShort();
Head->PaletteInfo = GetLittleUShort();
Head->HScreenSize = GetLittleUShort();
Head->VScreenSize = GetLittleUShort();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidDcx()
{
ILuint Signature;
if (iread(&Signature, 1, 4) != 4)
return IL_FALSE;
iseek(-4, IL_SEEK_CUR);
return (Signature == 987654321);
}
// Internal function used to check if the HEADER is a valid .dcx header.
// Should we also do a check on Header->Bpp?
ILboolean iCheckDcx(DCXHEAD *Header)
{
ILuint Test, i;
// There are other versions, but I am not supporting them as of yet.
// Got rid of the Reserved check, because I've seen some .dcx files with invalid values in it.
if (Header->Manufacturer != 10 || Header->Version != 5 || Header->Encoding != 1/* || Header->Reserved != 0*/)
return IL_FALSE;
// See if the padding size is correct
Test = Header->Xmax - Header->Xmin + 1;
/*if (Header->Bpp >= 8) {
if (Test & 1) {
if (Header->Bps != Test + 1)
return IL_FALSE;
}
else {
if (Header->Bps != Test) // No padding
return IL_FALSE;
}
}*/
for (i = 0; i < 54; i++) {
if (Header->Filler[i] != 0)
return IL_FALSE;
}
return IL_TRUE;
}
//! Reads a .dcx file
ILboolean ilLoadDcx(ILconst_string FileName)
{
ILHANDLE DcxFile;
ILboolean bDcx = IL_FALSE;
DcxFile = iopenr(FileName);
if (DcxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDcx;
}
bDcx = ilLoadDcxF(DcxFile);
icloser(DcxFile);
return bDcx;
}
//! Reads an already-opened .dcx file
ILboolean ilLoadDcxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDcxInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .dcx
ILboolean ilLoadDcxL(const void *Lump, ILuint Size) {
iSetInputLump(Lump, Size);
return iLoadDcxInternal();
}
// Internal function used to load the .dcx.
ILboolean iLoadDcxInternal()
{
DCXHEAD Header;
ILuint Signature, i, Entries[1024], Num = 0;
ILimage *Image, *Base;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iIsValidDcx())
return IL_FALSE;
iread(&Signature, 1, 4);
do {
if (iread(&Entries[Num], 1, 4) != 4)
return IL_FALSE;
Num++;
} while (Entries[Num-1] != 0);
for (i = 0; i < Num; i++) {
iseek(Entries[i], IL_SEEK_SET);
iGetDcxHead(&Header);
/*if (!iCheckDcx(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}*/
Image = iUncompressDcx(&Header);
if (Image == NULL)
return IL_FALSE;
if (i == 0) {
ilTexImage(Image->Width, Image->Height, 1, Image->Bpp, Image->Format, Image->Type, Image->Data);
Base = iCurImage;
Base->Origin = IL_ORIGIN_UPPER_LEFT;
ilCloseImage(Image);
}
else {
iCurImage->Next = Image;
iCurImage = iCurImage->Next;
}
}
return ilFixImage();
}
// Internal function to uncompress the .dcx (all .dcx files are rle compressed)
ILimage *iUncompressDcx(DCXHEAD *Header)
{
ILubyte ByteHead, Colour, *ScanLine = NULL /* Only one plane */;
ILuint c, i, x, y;//, Read = 0;
ILimage *Image = NULL;
if (Header->Bpp < 8) {
/*ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;*/
return iUncompressDcxSmall(Header);
}
Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1);
if (Image == NULL)
return NULL;
/*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}*/
Image->Origin = IL_ORIGIN_UPPER_LEFT;
ScanLine = (ILubyte*)ialloc(Header->Bps);
if (ScanLine == NULL)
goto dcx_error;
switch (Image->Bpp)
{
case 1:
Image->Format = IL_COLOUR_INDEX;
Image->Pal.PalType = IL_PAL_RGB24;
Image->Pal.PalSize = 256 * 3; // Need to find out for sure...
Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
if (Image->Pal.Palette == NULL)
goto dcx_error;
break;
//case 2: // No 16-bit images in the dcx format!
case 3:
Image->Format = IL_RGB;
Image->Pal.Palette = NULL;
Image->Pal.PalSize = 0;
Image->Pal.PalType = IL_PAL_NONE;
break;
case 4:
Image->Format = IL_RGBA;
Image->Pal.Palette = NULL;
Image->Pal.PalSize = 0;
Image->Pal.PalType = IL_PAL_NONE;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
goto dcx_error;
}
/*StartPos = itell();
Compressed = (ILubyte*)ialloc(Image->SizeOfData * 4 / 3);
iread(Compressed, 1, Image->SizeOfData * 4 / 3);
for (y = 0; y < Image->Height; y++) {
for (c = 0; c < Image->Bpp; c++) {
x = 0;
while (x < Header->Bps) {
ByteHead = Compressed[Read++];
if ((ByteHead & 0xC0) == 0xC0) {
ByteHead &= 0x3F;
Colour = Compressed[Read++];
for (i = 0; i < ByteHead; i++) {
ScanLine[x++] = Colour;
}
}
else {
ScanLine[x++] = ByteHead;
}
}
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;)
Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x];
}
}
}
ifree(Compressed);
iseek(StartPos + Read, IL_SEEK_SET);*/
//changed 2003-09-01
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
iPreCache(iCurImage->SizeOfData);
//TODO: because the .pcx-code was broken this
//code is probably broken, too
for (y = 0; y < Image->Height; y++) {
for (c = 0; c < Image->Bpp; c++) {
x = 0;
while (x < Header->Bps) {
if (iread(&ByteHead, 1, 1) != 1) {
iUnCache();
goto dcx_error;
}
if ((ByteHead & 0xC0) == 0xC0) {
ByteHead &= 0x3F;
if (iread(&Colour, 1, 1) != 1) {
iUnCache();
goto dcx_error;
}
for (i = 0; i < ByteHead; i++) {
ScanLine[x++] = Colour;
}
}
else {
ScanLine[x++] = ByteHead;
}
}
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;)
Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x];
}
}
}
iUnCache();
ifree(ScanLine);
// Read in the palette
if (Image->Bpp == 1) {
ByteHead = igetc(); // the value 12, because it signals there's a palette for some reason...
// We should do a check to make certain it's 12...
if (ByteHead != 12)
iseek(-1, IL_SEEK_CUR);
if (iread(Image->Pal.Palette, 1, Image->Pal.PalSize) != Image->Pal.PalSize) {
ilCloseImage(Image);
return NULL;
}
}
return Image;
dcx_error:
ifree(ScanLine);
ilCloseImage(Image);
return NULL;
}
ILimage *iUncompressDcxSmall(DCXHEAD *Header)
{
ILuint i = 0, j, k, c, d, x, y, Bps;
ILubyte HeadByte, Colour, Data = 0, *ScanLine = NULL;
ILimage *Image;
Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1);
if (Image == NULL)
return NULL;
/*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}*/
Image->Origin = IL_ORIGIN_UPPER_LEFT;
switch (Header->NumPlanes)
{
case 1:
Image->Format = IL_LUMINANCE;
break;
case 4:
Image->Format = IL_COLOUR_INDEX;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
ilCloseImage(Image);
return NULL;
}
if (Header->NumPlanes == 1) {
for (j = 0; j < Image->Height; j++) {
i = 0;
while (i < Image->Width) {
if (iread(&HeadByte, 1, 1) != 1)
goto file_read_error;
if (HeadByte >= 192) {
HeadByte -= 192;
if (iread(&Data, 1, 1) != 1)
goto file_read_error;
for (c = 0; c < HeadByte; c++) {
k = 128;
for (d = 0; d < 8 && i < Image->Width; d++) {
Image->Data[j * Image->Width + i++] = (!!(Data & k) == 1 ? 255 : 0);
k >>= 1;
}
}
}
else {
k = 128;
for (c = 0; c < 8 && i < Image->Width; c++) {
Image->Data[j * Image->Width + i++] = (!!(HeadByte & k) == 1 ? 255 : 0);
k >>= 1;
}
}
}
if (Data != 0)
igetc(); // Skip pad byte if last byte not a 0
}
}
else { // 4-bit images
Bps = Header->Bps * Header->NumPlanes * 2;
Image->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes).
Image->Pal.PalSize = 16 * 3;
Image->Pal.PalType = IL_PAL_RGB24;
ScanLine = (ILubyte*)ialloc(Bps);
if (Image->Pal.Palette == NULL || ScanLine == NULL) {
ifree(ScanLine);
ilCloseImage(Image);
return NULL;
}
memcpy(Image->Pal.Palette, Header->ColMap, 16 * 3);
imemclear(Image->Data, Image->SizeOfData); // Since we do a += later.
for (y = 0; y < Image->Height; y++) {
for (c = 0; c < Header->NumPlanes; c++) {
x = 0;
while (x < Bps) {
if (iread(&HeadByte, 1, 1) != 1)
goto file_read_error;
if ((HeadByte & 0xC0) == 0xC0) {
HeadByte &= 0x3F;
if (iread(&Colour, 1, 1) != 1)
goto file_read_error;
for (i = 0; i < HeadByte; i++) {
k = 128;
for (j = 0; j < 8; j++) {
ScanLine[x++] = !!(Colour & k);
k >>= 1;
}
}
}
else {
k = 128;
for (j = 0; j < 8; j++) {
ScanLine[x++] = !!(HeadByte & k);
k >>= 1;
}
}
}
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes. ;)
Image->Data[y * Image->Width + x] += ScanLine[x] << c;
}
}
}
ifree(ScanLine);
}
return Image;
file_read_error:
ifree(ScanLine);
ilCloseImage(Image);
return NULL;
}
#endif//IL_NO_DCX
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+606
View File
@@ -0,0 +1,606 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/14/2009
//
// Filename: src-IL/src/il_dicom.c
//
// Description: Reads from a Digital Imaging and Communications in Medicine
// (DICOM) file. Specifications can be found at
// http://en.wikipedia.org/wiki/Dicom.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_DICOM
typedef struct DICOMHEAD
{
ILubyte Signature[4];
ILuint Version;
ILuint Width;
ILuint Height;
ILuint Depth;
ILuint Samples;
ILuint BitsAllocated;
ILuint BitsStored;
ILuint DataLen;
ILboolean BigEndian;
ILenum Encoding;
// For DevIL use only
ILenum Format;
ILenum Type;
} DICOMHEAD;
ILboolean iIsValidDicom(void);
ILboolean iCheckDicom(DICOMHEAD *Header);
ILboolean iLoadDicomInternal(void);
ILboolean iGetDicomHead(DICOMHEAD *Header);
ILboolean SkipElement(DICOMHEAD *Header, ILushort GroupNum, ILushort ElementNum);
ILboolean GetNumericValue(DICOMHEAD *Header, ILushort GroupNum, ILuint *Number);
ILboolean GetUID(ILubyte *UID);
ILuint GetGroupNum(DICOMHEAD *Header);
ILuint GetShort(DICOMHEAD *Header, ILushort GroupNum);
ILuint GetInt(DICOMHEAD *Header, ILushort GroupNum);
ILfloat GetFloat(DICOMHEAD *Header, ILushort GroupNum);
//! Checks if the file specified in FileName is a valid DICOM file.
ILboolean ilIsValidDicom(ILconst_string FileName)
{
ILHANDLE DicomFile;
ILboolean bDicom = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("dicom")) && !iCheckExtension(FileName, IL_TEXT("dcm"))) {
ilSetError(IL_INVALID_EXTENSION);
return bDicom;
}
DicomFile = iopenr(FileName);
if (DicomFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDicom;
}
bDicom = ilIsValidDicomF(DicomFile);
icloser(DicomFile);
return bDicom;
}
//! Checks if the ILHANDLE contains a valid DICOM file at the current position.
ILboolean ilIsValidDicomF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidDicom();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid DICOM lump.
ILboolean ilIsValidDicomL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidDicom();
}
// Internal function to get the header and check it.
ILboolean iIsValidDicom(void)
{
DICOMHEAD Header;
ILuint Pos = itell();
// Clear the header to all 0s to make checks later easier.
memset(&Header, 0, sizeof(DICOMHEAD));
if (!iGetDicomHead(&Header))
return IL_FALSE;
// The length of the header varies, so we just go back to the original position.
iseek(Pos, IL_SEEK_CUR);
return iCheckDicom(&Header);
}
// Internal function used to get the DICOM header from the current file.
ILboolean iGetDicomHead(DICOMHEAD *Header)
{
ILushort GroupNum, ElementNum;
ILboolean ReachedData = IL_FALSE;
ILubyte Var2, UID[65];
// Signature should be "DICM" at position 128.
iseek(128, IL_SEEK_SET);
if (iread(Header->Signature, 1, 4) != 4)
return IL_FALSE;
//@TODO: What about the case when we are reading an image with Big Endian data?
do {
GroupNum = GetGroupNum(Header);
ElementNum = GetShort(Header, GroupNum);;
switch (GroupNum)
{
case 0x02:
switch (ElementNum)
{
/*case 0x01: // Version number
if (!GetNumericValue(&Header->Version))
return IL_FALSE;
if (Header->Version != 0x0100)
return IL_FALSE;
break;*/
case 0x10:
//@TODO: Look at pg. 60 of 07_05pu.pdf (PS 3.5) for more UIDs.
if (!GetUID(UID))
return IL_FALSE;
if (!strncmp(UID, "1.2.840.10008.1.2.2", 64)) // Explicit big endian
Header->BigEndian = IL_TRUE;
else if (!strncmp(UID, "1.2.840.10008.1.2.1", 64)) // Explicit little endian
Header->BigEndian = IL_FALSE;
else if (!strncmp(UID, "1.2.840.10008.1.2", 64)) // Implicit little endian
Header->BigEndian = IL_FALSE;
else
return IL_FALSE; // Unrecognized UID.
break;
default:
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
return IL_FALSE;
}
break;
case 0x28:
switch (ElementNum)
{
case 0x02: // Samples per pixel
if (!GetNumericValue(Header, GroupNum, &Header->Samples))
return IL_FALSE;
break;
case 0x08: // Number of frames, or depth
if (!GetNumericValue(Header, GroupNum, &Header->Depth))
return IL_FALSE;
break;
case 0x10: // The number of rows
if (!GetNumericValue(Header, GroupNum, &Header->Height))
return IL_FALSE;
break;
case 0x11: // The number of columns
if (!GetNumericValue(Header, GroupNum, &Header->Width))
return IL_FALSE;
break;
case 0x100: // Bits allocated per sample
if (!GetNumericValue(Header, GroupNum, &Header->BitsAllocated))
return IL_FALSE;
break;
case 0x101: // Bits stored per sample - Do we really need this information?
if (!GetNumericValue(Header, GroupNum, &Header->BitsStored))
return IL_FALSE;
break;
default:
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
return IL_FALSE;
}
break;
case 0x7FE0:
switch (ElementNum)
{
case 0x10: // This element is the actual pixel data. We are done with the header here.
if (igetc() != 'O') // @TODO: Can we assume that this is always 'O'?
return IL_FALSE;
Var2 = igetc();
if (Var2 != 'B' && Var2 != 'W' && Var2 != 'F') // 'OB', 'OW' and 'OF' accepted for this element.
return IL_FALSE;
GetLittleUShort(); // Skip the 2 reserved bytes.
Header->DataLen = GetInt(Header, GroupNum);//GetLittleUInt();
ReachedData = IL_TRUE;
break;
default:
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
return IL_FALSE;
}
break;
default:
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
return IL_FALSE;
}
} while (!ieof() && !ReachedData);
if (ieof())
return IL_FALSE;
// Some DICOM images do not have the depth (number of frames) field.
if (Header->Depth == 0)
Header->Depth = 1;
switch (Header->BitsAllocated)
{
case 8:
Header->Type = IL_UNSIGNED_BYTE;
break;
case 16:
Header->Type = IL_UNSIGNED_SHORT;
break;
case 32:
Header->Type = IL_FLOAT; //@TODO: Is this ever an integer?
break;
default: //@TODO: Any other types we can deal with?
return IL_FALSE;
}
// Cannot handle more than 4 channels in an image.
if (Header->Samples > 4)
return IL_FALSE;
Header->Format = ilGetFormatBpp(Header->Samples);
return IL_TRUE;
}
ILboolean SkipElement(DICOMHEAD *Header, ILushort GroupNum, ILushort ElementNum)
{
ILubyte VR1, VR2;
ILuint ValLen;
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
VR1 = igetc();
VR2 = igetc();
if ((VR1 == 'O' && VR2 == 'B') || (VR1 == 'O' && VR2 == 'W') || (VR1 == 'O' && VR2 == 'F') ||
(VR1 == 'S' && VR2 == 'Q') || (VR1 == 'U' && VR2 == 'T') || (VR1 == 'U' && VR2 == 'N')) {
// These all have a different format than the other formats, since they can be up to 32 bits long.
GetLittleUShort(); // Values reserved, we do not care about them.
ValLen = GetInt(Header, GroupNum);//GetLittleUInt(); // Length of the rest of the element
if (ValLen % 2) // This length must be even, according to the specs.
return IL_FALSE;
if (ElementNum != 0x00) // Element numbers of 0 tell the size of the full group, so we do not skip this.
// @TODO: We could use this to skip groups that we do not care about.
if (iseek(ValLen, IL_SEEK_CUR))
return IL_FALSE;
}
else {
// These have a length of 16 bits.
ValLen = GetShort(Header, GroupNum);//GetLittleUShort();
//if (ValLen % 2) // This length must be even, according to the specs.
// ValLen++; // Add the extra byte to seek.
//if (ElementNum != 0x00) // Element numbers of 0 tell the size of the full group, so we do not skip this.
// @TODO: We could use this to skip groups that we do not care about.
if (iseek(ValLen, IL_SEEK_CUR))
return IL_FALSE;
}
return IL_TRUE;
}
ILuint GetGroupNum(DICOMHEAD *Header)
{
ILushort GroupNum;
iread(&GroupNum, 1, 2);
// The 0x02 group is always little endian.
if (GroupNum == 0x02) {
UShort(&GroupNum);
return GroupNum;
}
// Now we have to swizzle it if it is not 0x02.
if (Header->BigEndian)
BigUShort(&GroupNum);
else
UShort(&GroupNum);
return GroupNum;
}
ILuint GetShort(DICOMHEAD *Header, ILushort GroupNum)
{
ILushort Num;
iread(&Num, 1, 2);
// The 0x02 group is always little endian.
if (GroupNum == 0x02) {
UShort(&Num);
return Num;
}
// Now we have to swizzle it if it is not 0x02.
if (Header->BigEndian)
BigUShort(&Num);
else
UShort(&Num);
return Num;
}
ILuint GetInt(DICOMHEAD *Header, ILushort GroupNum)
{
ILuint Num;
iread(&Num, 1, 4);
// The 0x02 group is always little endian.
if (GroupNum == 0x02) {
UInt(&Num);
return Num;
}
// Now we have to swizzle it if it is not 0x02.
if (Header->BigEndian)
BigUInt(&Num);
else
UInt(&Num);
return Num;
}
ILfloat GetFloat(DICOMHEAD *Header, ILushort GroupNum)
{
ILfloat Num;
iread(&Num, 1, 4);
// The 0x02 group is always little endian.
if (GroupNum == 0x02) {
Float(&Num);
return Num;
}
// Now we have to swizzle it if it is not 0x02.
if (Header->BigEndian)
BigFloat(&Num);
else
Float(&Num);
return Num;
}
ILboolean GetNumericValue(DICOMHEAD *Header, ILushort GroupNum, ILuint *Number)
{
ILubyte VR1, VR2;
ILushort ValLen;
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
VR1 = igetc();
VR2 = igetc();
if (VR1 == 'U' && VR2 == 'S') { // Unsigned short
ValLen = GetShort(Header, GroupNum);//GetLittleUShort();
if (ValLen != 2) // Must always be 2 for short ('US')
return IL_FALSE;
*((ILushort*)Number) = GetShort(Header, GroupNum);//GetLittleUShort();
return IL_TRUE;
}
if (VR1 == 'U' && VR2 == 'L') { // Unsigned long
ValLen = GetInt(Header, GroupNum);//GetLittleUInt();
if (ValLen != 4) // Must always be 4 for long ('UL')
return IL_FALSE;
*Number = GetInt(Header, GroupNum);
return IL_TRUE;
}
if (VR1 == 'S' && VR2 == 'S') { // Signed short
ValLen = GetShort(Header, GroupNum);
if (ValLen != 2) // Must always be 2 for short ('US')
return IL_FALSE;
*((ILshort*)Number) = GetShort(Header, GroupNum);
return IL_TRUE;
}
if (VR1 == 'S' && VR2 == 'L') { // Signed long
ValLen = GetInt(Header, GroupNum);
if (ValLen != 4) // Must always be 4 for long ('UL')
return IL_FALSE;
*((ILint*)Number) = GetInt(Header, GroupNum);
return IL_TRUE;
}
return IL_FALSE;
}
ILboolean GetUID(ILubyte *UID)
{
ILubyte VR1, VR2;
ILushort ValLen;
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
VR1 = igetc();
VR2 = igetc();
if (VR1 != 'U' || VR2 != 'I') // 'UI' == UID
return IL_FALSE;
ValLen = GetLittleUShort();
if (iread(UID, ValLen, 1) != 1)
return IL_FALSE;
UID[64] = 0; // Just to make sure that our string is terminated.
return IL_TRUE;
}
// Internal function used to check if the HEADER is a valid DICOM header.
ILboolean iCheckDicom(DICOMHEAD *Header)
{
// Always has the signature "DICM" at position 0x80.
if (strncmp(Header->Signature, "DICM", 4))
return IL_FALSE;
// Does not make sense to have any dimension = 0.
if (Header->Width == 0 || Header->Height == 0 || Header->Depth == 0)
return IL_FALSE;
// We can only deal with images that have byte-aligned data.
//@TODO: Take care of any others?
if (Header->BitsAllocated % 8)
return IL_FALSE;
// Check for an invalid format being set (or not set at all).
if (ilGetBppFormat(Header->Format) == 0)
return IL_FALSE;
// Check for an invalid type being set (or not set at all).
if (ilGetBpcType(Header->Type) == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a DICOM file
ILboolean ilLoadDicom(ILconst_string FileName)
{
ILHANDLE DicomFile;
ILboolean bDicom = IL_FALSE;
DicomFile = iopenr(FileName);
if (DicomFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDicom;
}
bDicom = ilLoadDicomF(DicomFile);
icloser(DicomFile);
return bDicom;
}
//! Reads an already-opened DICOM file
ILboolean ilLoadDicomF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDicomInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a DICOM
ILboolean ilLoadDicomL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadDicomInternal();
}
// Internal function used to load the DICOM.
ILboolean iLoadDicomInternal(void)
{
DICOMHEAD Header;
ILuint i;
ILushort TempS, *ShortPtr;
ILfloat TempF, *FloatPtr;
ILboolean Swizzle = IL_FALSE;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
// Clear the header to all 0s to make checks later easier.
memset(&Header, 0, sizeof(DICOMHEAD));
if (!iGetDicomHead(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!iCheckDicom(&Header))
return IL_FALSE;
if (!ilTexImage(Header.Width, Header.Height, Header.Depth, ilGetBppFormat(Header.Format), Header.Format, Header.Type, NULL))
return IL_FALSE;
//@TODO: Find out if the origin is always in the upper left.
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
// Header.DataLen may be larger than SizeOfData, since it has to be padded with a NULL if it is not an even length,
// so we just test to make sure it is at least large enough.
//@TODO: Do this check before ilTexImage call.
if (Header.DataLen < iCurImage->SizeOfData) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// We may have to swap the order of the data.
#ifdef __BIG_ENDIAN__
if (!Header.BigEndian) {
if (Header.Format == IL_RGB)
Header.Format = IL_BGR;
else if (Header.Format == IL_RGBA)
Swizzle = IL_TRUE;
}
#else // Little endian
if (Header.BigEndian) {
if (Header.Format == IL_RGB)
Header.Format = IL_BGR;
if (Header.Format == IL_RGBA)
Swizzle = IL_TRUE;
}
#endif
switch (Header.Type)
{
case IL_UNSIGNED_BYTE:
if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1)
return IL_FALSE;
// Swizzle the data from ABGR to RGBA.
if (Swizzle) {
for (i = 0; i < iCurImage->SizeOfData; i += 4) {
iSwapUInt((ILuint*)(iCurImage->Data + i));
}
}
break;
case IL_UNSIGNED_SHORT:
for (i = 0; i < iCurImage->SizeOfData; i += 2) {
*((ILushort*)(iCurImage->Data + i)) = GetShort(&Header, 0);//GetLittleUShort();
}
// Swizzle the data from ABGR to RGBA.
if (Swizzle) {
ShortPtr = (ILushort*)iCurImage->Data;
for (i = 0; i < iCurImage->SizeOfData / 2; i += 4) {
TempS = ShortPtr[i];
ShortPtr[i] = ShortPtr[i+3];
ShortPtr[i+3] = TempS;
}
}
break;
case IL_FLOAT:
for (i = 0; i < iCurImage->SizeOfData; i += 4) {
*((ILfloat*)(iCurImage->Data + i)) = GetFloat(&Header, 0);//GetLittleFloat();
}
// Swizzle the data from ABGR to RGBA.
if (Swizzle) {
FloatPtr = (ILfloat*)iCurImage->Data;
for (i = 0; i < iCurImage->SizeOfData / 4; i += 4) {
TempF = FloatPtr[i];
FloatPtr[i] = FloatPtr[i+3];
FloatPtr[i+3] = TempF;
}
}
break;
}
return ilFixImage();
}
#endif//IL_NO_DICOM
+272
View File
@@ -0,0 +1,272 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_doom.c
//
// Description: Reads Doom textures and flats
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_DOOM
#include "il_manip.h"
#include "il_pal.h"
#include "il_doompal.h"
ILboolean iLoadDoomInternal(void);
ILboolean iLoadDoomFlatInternal(void);
//
// READ A DOOM IMAGE
//
//! Reads a Doom file
ILboolean ilLoadDoom(ILconst_string FileName)
{
ILHANDLE DoomFile;
ILboolean bDoom = IL_FALSE;
// Not sure of any kind of specified extension...maybe .lmp?
/*if (!iCheckExtension(FileName, "")) {
ilSetError(IL_INVALID_EXTENSION);
return NULL;
}*/
DoomFile = iopenr(FileName);
if (DoomFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDoom;
}
bDoom = ilLoadDoomF(DoomFile);
icloser(DoomFile);
return bDoom;
}
//! Reads an already-opened Doom file
ILboolean ilLoadDoomF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDoomInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Doom texture
ILboolean ilLoadDoomL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadDoomInternal();
}
// From the DTE sources (mostly by Denton Woods with corrections by Randy Heit)
ILboolean iLoadDoomInternal()
{
ILshort width, height, graphic_header[2], column_loop, row_loop;
ILint column_offset, pointer_position, first_pos;
ILubyte post, topdelta, length;
ILubyte *NewData;
ILuint i;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
first_pos = itell(); // Needed to go back to the offset table
width = GetLittleShort();
height = GetLittleShort();
graphic_header[0] = GetLittleShort(); // Not even used
graphic_header[1] = GetLittleShort(); // Not even used
if (!ilTexImage(width, height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
if (iCurImage->Pal.Palette == NULL) {
return IL_FALSE;
}
iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
iCurImage->Pal.PalType = IL_PAL_RGB24;
memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);
// 247 is always the transparent colour (usually cyan)
memset(iCurImage->Data, 247, iCurImage->SizeOfData);
for (column_loop = 0; column_loop < width; column_loop++) {
column_offset = GetLittleInt();
pointer_position = itell();
iseek(first_pos + column_offset, IL_SEEK_SET);
while (1) {
if (iread(&topdelta, 1, 1) != 1)
return IL_FALSE;
if (topdelta == 255)
break;
if (iread(&length, 1, 1) != 1)
return IL_FALSE;
if (iread(&post, 1, 1) != 1)
return IL_FALSE; // Skip extra byte for scaling
for (row_loop = 0; row_loop < length; row_loop++) {
if (iread(&post, 1, 1) != 1)
return IL_FALSE;
if (row_loop + topdelta < height)
iCurImage->Data[(row_loop+topdelta) * width + column_loop] = post;
}
iread(&post, 1, 1); // Skip extra scaling byte
}
iseek(pointer_position, IL_SEEK_SET);
}
// Converts palette entry 247 (cyan) to transparent.
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
if (NewData == NULL) {
return IL_FALSE;
}
for (i = 0; i < iCurImage->SizeOfData; i++) {
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
}
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
4, IL_RGBA, iCurImage->Type, NewData)) {
ifree(NewData);
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
ifree(NewData);
}
return ilFixImage();
}
//
// READ A DOOM FLAT
//
//! Reads a Doom flat file
ILboolean ilLoadDoomFlat(ILconst_string FileName)
{
ILHANDLE FlatFile;
ILboolean bFlat = IL_FALSE;
// Not sure of any kind of specified extension...maybe .lmp?
/*if (!iCheckExtension(FileName, "")) {
ilSetError(IL_INVALID_EXTENSION);
return NULL;
}*/
FlatFile = iopenr(FileName);
if (FlatFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bFlat;
}
bFlat = ilLoadDoomF(FlatFile);
icloser(FlatFile);
return bFlat;
}
//! Reads an already-opened Doom flat file
ILboolean ilLoadDoomFlatF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDoomFlatInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Doom flat
ILboolean ilLoadDoomFlatL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadDoomFlatInternal();
}
// Basically just ireads 4096 bytes and copies the palette
ILboolean iLoadDoomFlatInternal()
{
ILubyte *NewData;
ILuint i;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!ilTexImage(64, 64, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
if (iCurImage->Pal.Palette == NULL) {
return IL_FALSE;
}
iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
iCurImage->Pal.PalType = IL_PAL_RGB24;
memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);
if (iread(iCurImage->Data, 1, 4096) != 4096)
return IL_FALSE;
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
if (NewData == NULL) {
return IL_FALSE;
}
for (i = 0; i < iCurImage->SizeOfData; i++) {
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
}
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
4, IL_RGBA, iCurImage->Type, NewData)) {
ifree(NewData);
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
ifree(NewData);
}
return ilFixImage();
}
#endif
+325
View File
@@ -0,0 +1,325 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/26/2009
//
// Filename: src-IL/src/il_dpx.c
//
// Description: Reads from a Digital Picture Exchange (.dpx) file.
// Specifications for this format were found at
// http://www.cineon.com/ff_draft.php and
// http://www.fileformat.info/format/dpx/.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_DPX
#include "il_dpx.h"
#include "il_bits.h"
ILboolean iLoadDpxInternal(void);
//! Reads a DPX file
ILboolean ilLoadDpx(ILconst_string FileName)
{
ILHANDLE DpxFile;
ILboolean bDpx = IL_FALSE;
DpxFile = iopenr(FileName);
if (DpxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bDpx;
}
bDpx = ilLoadDpxF(DpxFile);
icloser(DpxFile);
return bDpx;
}
//! Reads an already-opened DPX file
ILboolean ilLoadDpxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDpxInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a DPX
ILboolean ilLoadDpxL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadDpxInternal();
}
ILboolean DpxGetFileInfo(DPX_FILE_INFO *FileInfo)
{
//if (iread(FileInfo, 768, 1) != 1)
// return IL_FALSE;
FileInfo->MagicNum = GetBigUInt();
FileInfo->Offset = GetBigUInt();
iread(FileInfo->Vers, 8, 1);
FileInfo->FileSize = GetBigUInt();
FileInfo->DittoKey = GetBigUInt();
FileInfo->GenHdrSize = GetBigUInt();
FileInfo->IndHdrSize = GetBigUInt();
FileInfo->UserDataSize = GetBigUInt();
iread(FileInfo->FileName, 100, 1);
iread(FileInfo->CreateTime, 24, 1);
iread(FileInfo->Creator, 100, 1);
iread(FileInfo->Project, 200, 1);
if (iread(FileInfo->Copyright, 200, 1) != 1)
return IL_FALSE;
FileInfo->Key = GetBigUInt();
iseek(104, IL_SEEK_CUR); // Skip reserved section.
return IL_TRUE;
}
ILboolean GetImageElement(DPX_IMAGE_ELEMENT *ImageElement)
{
ImageElement->DataSign = GetBigUInt();
ImageElement->RefLowData = GetBigUInt();
iread(&ImageElement->RefLowQuantity, 1, 4);
ImageElement->RefHighData = GetBigUInt();
iread(&ImageElement->RefHighQuantity, 1, 4);
ImageElement->Descriptor = igetc();
ImageElement->Transfer = igetc();
ImageElement->Colorimetric = igetc();
ImageElement->BitSize = igetc();
ImageElement->Packing = GetBigUShort();
ImageElement->Encoding = GetBigUShort();
ImageElement->DataOffset = GetBigUInt();
ImageElement->EolPadding = GetBigUInt();
ImageElement->EoImagePadding = GetBigUInt();
if (iread(ImageElement->Description, 32, 1) != 1)
return IL_FALSE;
return IL_TRUE;
}
ILboolean DpxGetImageInfo(DPX_IMAGE_INFO *ImageInfo)
{
ILuint i;
//if (iread(ImageInfo, sizeof(DPX_IMAGE_INFO), 1) != 1)
// return IL_FALSE;
ImageInfo->Orientation = GetBigUShort();
ImageInfo->NumElements = GetBigUShort();
ImageInfo->Width = GetBigUInt();
ImageInfo->Height = GetBigUInt();
for (i = 0; i < 8; i++) {
GetImageElement(&ImageInfo->ImageElement[i]);
}
iseek(52, IL_SEEK_CUR); // Skip padding bytes.
return IL_TRUE;
}
ILboolean DpxGetImageOrient(DPX_IMAGE_ORIENT *ImageOrient)
{
ImageOrient->XOffset = GetBigUInt();
ImageOrient->YOffset = GetBigUInt();
iread(&ImageOrient->XCenter, 4, 1);
iread(&ImageOrient->YCenter, 4, 1);
ImageOrient->XOrigSize = GetBigUInt();
ImageOrient->YOrigSize = GetBigUInt();
iread(ImageOrient->FileName, 100, 1);
iread(ImageOrient->CreationTime, 24, 1);
iread(ImageOrient->InputDev, 32, 1);
if (iread(ImageOrient->InputSerial, 32, 1) != 1)
return IL_FALSE;
ImageOrient->Border[0] = GetBigUShort();
ImageOrient->Border[1] = GetBigUShort();
ImageOrient->Border[2] = GetBigUShort();
ImageOrient->Border[3] = GetBigUShort();
ImageOrient->PixelAspect[0] = GetBigUInt();
ImageOrient->PixelAspect[1] = GetBigUInt();
iseek(28, IL_SEEK_CUR); // Skip reserved bytes.
return IL_TRUE;
}
// Internal function used to load the DPX.
ILboolean iLoadDpxInternal(void)
{
DPX_FILE_INFO FileInfo;
DPX_IMAGE_INFO ImageInfo;
DPX_IMAGE_ORIENT ImageOrient;
// BITFILE *File;
ILuint i, NumElements, CurElem = 0;
ILushort Val, *ShortData;
ILubyte Data[8];
ILenum Format = 0;
ILubyte NumChans = 0;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!DpxGetFileInfo(&FileInfo))
return IL_FALSE;
if (!DpxGetImageInfo(&ImageInfo))
return IL_FALSE;
if (!DpxGetImageOrient(&ImageOrient))
return IL_FALSE;
iseek(ImageInfo.ImageElement[CurElem].DataOffset, IL_SEEK_SET);
//@TODO: Deal with different origins!
switch (ImageInfo.ImageElement[CurElem].Descriptor)
{
case 6: // Luminance data
Format = IL_LUMINANCE;
NumChans = 1;
break;
case 50: // RGB data
Format = IL_RGB;
NumChans = 3;
break;
case 51: // RGBA data
Format = IL_RGBA;
NumChans = 4;
break;
default:
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
// These are all on nice word boundaries.
switch (ImageInfo.ImageElement[CurElem].BitSize)
{
case 8:
case 16:
case 32:
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, NumChans, Format, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1)
return IL_FALSE;
goto finish;
}
// The rest of these do not end on word boundaries.
if (ImageInfo.ImageElement[CurElem].Packing == 1) {
// Here we have it padded out to a word boundary, so the extra bits are filler.
switch (ImageInfo.ImageElement[CurElem].BitSize)
{
case 10:
//@TODO: Support other formats!
/*if (Format != IL_RGB) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}*/
switch (Format)
{
case IL_LUMINANCE:
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
ShortData = (ILushort*)iCurImage->Data;
NumElements = iCurImage->SizeOfData / 2;
for (i = 0; i < NumElements;) {
iread(Data, 1, 2);
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
}
break;
case IL_RGB:
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 3, IL_RGB, IL_UNSIGNED_SHORT, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
ShortData = (ILushort*)iCurImage->Data;
NumElements = iCurImage->SizeOfData / 2;
for (i = 0; i < NumElements;) {
iread(Data, 1, 4);
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
Val = (((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4)) << 6; // Use the next 10 bits.
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
Val = (((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2)) << 6; // And finally use the last 10 bits (ignores the last 2 bits).
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
}
break;
case IL_RGBA: // Is this even a possibility? There is a ton of wasted space here!
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
ShortData = (ILushort*)iCurImage->Data;
NumElements = iCurImage->SizeOfData / 2;
for (i = 0; i < NumElements;) {
iread(Data, 1, 8);
Val = (Data[0] << 2) + ((Data[1] & 0xC0) >> 6); // Use the first 10 bits of the word-aligned data.
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
Val = ((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4); // Use the next 10 bits.
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
Val = ((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2); // Use the next 10 bits.
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
Val = ((Data[3] & 0x03) << 8) + Data[4]; // And finally use the last 10 relevant bits (skips 3 whole bytes worth of padding!).
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Last fill
}
break;
}
break;
//case 1:
//case 12:
default:
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
}
else if (ImageInfo.ImageElement[0].Packing == 0) {
// Here we have the data packed so that it is never aligned on a word boundary.
/*File = bfile(iGetFile());
if (File == NULL)
return IL_FALSE; //@TODO: Error?
ShortData = (ILushort*)iCurImage->Data;
NumElements = iCurImage->SizeOfData / 2;
for (i = 0; i < NumElements; i++) {
//bread(&Val, 1, 10, File);
Val = breadVal(10, File);
ShortData[i] = (Val << 6) | (Val >> 4);
}
bclose(File);*/
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
else {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE; //@TODO: Take care of this in an iCheckDpx* function.
}
finish:
return ilFixImage();
}
#endif//IL_NO_DPX
+278
View File
@@ -0,0 +1,278 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Last modified: 12/06/2006
//
// Filename: src-IL/src/il_endian.c
//
// Description: Takes care of endian issues
//
//-----------------------------------------------------------------------------
#define IL_ENDIAN_C
#include "il_endian.h"
void EndianSwapData(void *_Image)
{
ILuint i;
ILubyte *temp, *s, *d;
ILushort *ShortS, *ShortD;
ILuint *IntS, *IntD;
ILfloat *FltS, *FltD;
ILdouble *DblS, *DblD;
ILimage *Image = (ILimage*)_Image;
switch (Image->Type) {
case IL_BYTE:
case IL_UNSIGNED_BYTE:
switch (Image->Bpp) {
case 3:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
s = Image->Data;
d = temp;
for( i = Image->Width * Image->Height; i > 0; i-- ) {
*d++ = *(s+2);
*d++ = *(s+1);
*d++ = *s;
s += 3;
}
ifree(Image->Data);
Image->Data = temp;
break;
case 4:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
s = Image->Data;
d = temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*d++ = *(s+3);
*d++ = *(s+2);
*d++ = *(s+1);
*d++ = *s;
s += 4;
}
ifree(Image->Data);
Image->Data = temp;
break;
}
break;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
switch (Image->Bpp) {
case 3:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
ShortS = (ILushort*)Image->Data;
ShortD = (ILushort*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*ShortD = *ShortS++; iSwapUShort(ShortD++);
*ShortD = *ShortS++; iSwapUShort(ShortD++);
*ShortD = *ShortS++; iSwapUShort(ShortD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
case 4:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
ShortS = (ILushort*)Image->Data;
ShortD = (ILushort*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*ShortD = *ShortS++; iSwapUShort(ShortD++);
*ShortD = *ShortS++; iSwapUShort(ShortD++);
*ShortD = *ShortS++; iSwapUShort(ShortD++);
*ShortD = *ShortS++; iSwapUShort(ShortD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
}
break;
case IL_INT:
case IL_UNSIGNED_INT:
switch (Image->Bpp)
{
case 3:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
IntS = (ILuint*)Image->Data;
IntD = (ILuint*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*IntD = *IntS++; iSwapUInt(IntD++);
*IntD = *IntS++; iSwapUInt(IntD++);
*IntD = *IntS++; iSwapUInt(IntD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
case 4:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
IntS = (ILuint*)Image->Data;
IntD = (ILuint*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*IntD = *IntS++; iSwapUInt(IntD++);
*IntD = *IntS++; iSwapUInt(IntD++);
*IntD = *IntS++; iSwapUInt(IntD++);
*IntD = *IntS++; iSwapUInt(IntD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
}
break;
case IL_FLOAT:
switch (Image->Bpp)
{
case 3:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
FltS = (ILfloat*)Image->Data;
FltD = (ILfloat*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*FltD = *FltS++; iSwapFloat(FltD++);
*FltD = *FltS++; iSwapFloat(FltD++);
*FltD = *FltS++; iSwapFloat(FltD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
case 4:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
FltS = (ILfloat*)Image->Data;
FltD = (ILfloat*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*FltD = *FltS++; iSwapFloat(FltD++);
*FltD = *FltS++; iSwapFloat(FltD++);
*FltD = *FltS++; iSwapFloat(FltD++);
*FltD = *FltS++; iSwapFloat(FltD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
}
break;
case IL_DOUBLE:
switch (Image->Bpp)
{
case 3:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
DblS = (ILdouble*)Image->Data;
DblD = (ILdouble*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*DblD = *DblS++; iSwapDouble(DblD++);
*DblD = *DblS++; iSwapDouble(DblD++);
*DblD = *DblS++; iSwapDouble(DblD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
case 4:
temp = (ILubyte*)ialloc(Image->SizeOfData);
if (temp == NULL)
return;
DblS = (ILdouble*)Image->Data;
DblD = (ILdouble*)temp;
for (i = Image->Width * Image->Height; i > 0; i--) {
*DblD = *DblS++; iSwapDouble(DblD++);
*DblD = *DblS++; iSwapDouble(DblD++);
*DblD = *DblS++; iSwapDouble(DblD++);
*DblD = *DblS++; iSwapDouble(DblD++);
}
ifree(Image->Data);
Image->Data = temp;
break;
}
break;
}
if( iCurImage->Format == IL_COLOUR_INDEX ) {
switch (iCurImage->Pal.PalType) {
case IL_PAL_RGB24:
case IL_PAL_BGR24:
temp = (ILubyte*)ialloc(Image->Pal.PalSize);
if (temp == NULL)
return;
s = Image->Pal.Palette;
d = temp;
for (i = Image->Pal.PalSize / 3; i > 0; i--) {
*d++ = *(s+2);
*d++ = *(s+1);
*d++ = *s;
s += 3;
}
ifree(Image->Pal.Palette);
Image->Pal.Palette = temp;
break;
case IL_PAL_RGBA32:
case IL_PAL_RGB32:
case IL_PAL_BGRA32:
case IL_PAL_BGR32:
temp = (ILubyte*)ialloc(Image->Pal.PalSize);
if (temp == NULL)
return;
s = Image->Pal.Palette;
d = temp;
for (i = Image->Pal.PalSize / 4; i > 0; i--) {
*d++ = *(s+3);
*d++ = *(s+2);
*d++ = *(s+1);
*d++ = *s;
s += 4;
}
ifree(Image->Pal.Palette);
Image->Pal.Palette = temp;
break;
}
}
return;
}
+56
View File
@@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 06/02/2007
//
// Filename: src-IL/src/il_error.c
//
// Description: The error functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#define IL_ERROR_STACK_SIZE 32 // Needed elsewhere?
ILenum ilErrorNum[IL_ERROR_STACK_SIZE];
ILint ilErrorPlace = (-1);
// Sets the current error
// If you go past the stack size for this, it cycles the errors, almost like a LRU algo.
ILAPI void ILAPIENTRY ilSetError(ILenum Error)
{
ILuint i;
ilErrorPlace++;
if (ilErrorPlace >= IL_ERROR_STACK_SIZE) {
for (i = 0; i < IL_ERROR_STACK_SIZE - 2; i++) {
ilErrorNum[i] = ilErrorNum[i+1];
}
ilErrorPlace = IL_ERROR_STACK_SIZE - 1;
}
ilErrorNum[ilErrorPlace] = Error;
return;
}
//! Gets the last error on the error stack
ILenum ILAPIENTRY ilGetError(void)
{
ILenum ilReturn;
if (ilErrorPlace >= 0) {
ilReturn = ilErrorNum[ilErrorPlace];
ilErrorPlace--;
}
else
ilReturn = IL_NO_ERROR;
return ilReturn;
}
+435
View File
@@ -0,0 +1,435 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_exr.cpp
//
// Description: Reads from an OpenEXR (.exr) file using the OpenEXR library.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_EXR
#ifndef HAVE_CONFIG_H // We are probably on a Windows box .
//#define OPENEXR_DLL
#define HALF_EXPORTS
#endif //HAVE_CONFIG_H
#include "il_exr.h"
#include <ImfRgba.h>
#include <ImfArray.h>
#include <ImfRgbaFile.h>
//#include <ImfTiledRgbaFile.h>
//#include <ImfInputFile.h>
//#include <ImfTiledInputFile.h>
//#include <ImfPreviewImage.h>
//#include <ImfChannelList.h>
#if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "openexr.lib")
#else
#pragma comment(lib, "openexr-d.lib")
#endif
#endif
#endif
//! Checks if the file specified in FileName is a valid EXR file.
ILboolean ilIsValidExr(ILconst_string FileName)
{
ILHANDLE ExrFile;
ILboolean bExr = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("exr"))) {
ilSetError(IL_INVALID_EXTENSION);
return bExr;
}
ExrFile = iopenr(FileName);
if (ExrFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bExr;
}
bExr = ilIsValidExrF(ExrFile);
icloser(ExrFile);
return bExr;
}
//! Checks if the ILHANDLE contains a valid EXR file at the current position.
ILboolean ilIsValidExrF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidExr();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid EXR lump.
ILboolean ilIsValidExrL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidExr();
}
// Internal function used to get the EXR header from the current file.
ILboolean iGetExrHead(EXRHEAD *Header)
{
Header->MagicNumber = GetLittleUInt();
Header->Version = GetLittleUInt();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidExr()
{
EXRHEAD Head;
if (!iGetExrHead(&Head))
return IL_FALSE;
iseek(-8, IL_SEEK_CUR);
return iCheckExr(&Head);
}
// Internal function used to check if the HEADER is a valid EXR header.
ILboolean iCheckExr(EXRHEAD *Header)
{
// The file magic number (signature) is 0x76, 0x2f, 0x31, 0x01
if (Header->MagicNumber != 0x01312F76)
return IL_FALSE;
// The only valid version so far is version 2. The upper value has
// to do with tiling.
if (Header->Version != 0x002 && Header->Version != 0x202)
return IL_FALSE;
return IL_TRUE;
}
// Nothing to do here in the constructor.
ilIStream::ilIStream() : Imf::IStream("N/A")
{
return;
}
bool ilIStream::read(char c[], int n)
{
if (iread(c, 1, n) != n)
return false;
return true;
}
//@TODO: Make this work with 64-bit values.
Imf::Int64 ilIStream::tellg()
{
Imf::Int64 Pos;
// itell only returns a 32-bit value!
Pos = itell();
return Pos;
}
// Note that there is no return value here, even though there probably should be.
//@TODO: Make this work with 64-bit values.
void ilIStream::seekg(Imf::Int64 Pos)
{
// iseek only uses a 32-bit value!
iseek((ILint)Pos, IL_SEEK_SET); // I am assuming this is seeking from the beginning.
return;
}
void ilIStream::clear()
{
return;
}
//! Reads an .exr file.
ILboolean ilLoadExr(ILconst_string FileName)
{
ILHANDLE ExrFile;
ILboolean bExr = IL_FALSE;
ExrFile = iopenr(FileName);
if (ExrFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bExr;
}
bExr = ilLoadExrF(ExrFile);
icloser(ExrFile);
return bExr;
}
//! Reads an already-opened .exr file
ILboolean ilLoadExrF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadExrInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains an .exr
ILboolean ilLoadExrL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadExrInternal();
}
using namespace Imath;
using namespace Imf;
using namespace std;
ILboolean iLoadExrInternal()
{
Array<Rgba> pixels;
Box2i dataWindow;
float pixelAspectRatio;
ILfloat *FloatData;
ilIStream File;
RgbaInputFile in(File);
Rgba a;
dataWindow = in.dataWindow();
pixelAspectRatio = in.pixelAspectRatio();
int dw, dh, dx, dy;
dw = dataWindow.max.x - dataWindow.min.x + 1;
dh = dataWindow.max.y - dataWindow.min.y + 1;
dx = dataWindow.min.x;
dy = dataWindow.min.y;
pixels.resizeErase (dw * dh);
in.setFrameBuffer (pixels - dx - dy * dw, 1, dw);
try
{
in.readPixels (dataWindow.min.y, dataWindow.max.y);
}
catch (const exception &e)
{
// If some of the pixels in the file cannot be read,
// print an error message, and return a partial image
// to the caller.
ilSetError(IL_LIB_EXR_ERROR); // Could I use something a bit more descriptive based on e?
e; // Prevent the compiler from yelling at us about this being unused.
return IL_FALSE;
}
//if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL) == IL_FALSE)
//if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL) == IL_FALSE)
if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_FLOAT, NULL) == IL_FALSE)
return IL_FALSE;
// Determine where the origin is in the original file.
if (in.lineOrder() == INCREASING_Y)
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
else
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
// Better to access FloatData instead of recasting everytime.
FloatData = (ILfloat*)iCurImage->Data;
for (int i = 0; i < dw * dh; i++)
{
// Too much data lost
//iCurImage->Data[i * 4 + 0] = (ILubyte)(pixels[i].r.bits() >> 8);
//iCurImage->Data[i * 4 + 1] = (ILubyte)(pixels[i].g.bits() >> 8);
//iCurImage->Data[i * 4 + 2] = (ILubyte)(pixels[i].b.bits() >> 8);
//iCurImage->Data[i * 4 + 3] = (ILubyte)(pixels[i].a.bits() >> 8);
// The images look kind of washed out with this.
//((ILshort*)(iCurImage->Data))[i * 4 + 0] = pixels[i].r.bits();
//((ILshort*)(iCurImage->Data))[i * 4 + 1] = pixels[i].g.bits();
//((ILshort*)(iCurImage->Data))[i * 4 + 2] = pixels[i].b.bits();
//((ILshort*)(iCurImage->Data))[i * 4 + 3] = pixels[i].a.bits();
// This gives the best results, since no data is lost.
FloatData[i * 4] = pixels[i].r;
FloatData[i * 4 + 1] = pixels[i].g;
FloatData[i * 4 + 2] = pixels[i].b;
FloatData[i * 4 + 3] = pixels[i].a;
}
// Converts the image to predefined type, format and/or origin if needed.
return ilFixImage();
}
// Nothing to do here in the constructor.
ilOStream::ilOStream() : Imf::OStream("N/A")
{
return;
}
void ilOStream::write(const char c[], int n)
{
iwrite(c, 1, n); //@TODO: Throw an exception here.
return;
}
//@TODO: Make this work with 64-bit values.
Imf::Int64 ilOStream::tellp()
{
Imf::Int64 Pos;
// itellw only returns a 32-bit value!
Pos = itellw();
return Pos;
}
// Note that there is no return value here, even though there probably should be.
//@TODO: Make this work with 64-bit values.
void ilOStream::seekp(Imf::Int64 Pos)
{
// iseekw only uses a 32-bit value!
iseekw((ILint)Pos, IL_SEEK_SET); // I am assuming this is seeking from the beginning.
return;
}
//! Writes a Exr file
ILboolean ilSaveExr(const ILstring FileName)
{
ILHANDLE ExrFile;
ILuint ExrSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
ExrFile = iopenw(FileName);
if (ExrFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
ExrSize = ilSaveExrF(ExrFile);
iclosew(ExrFile);
if (ExrSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Exr to an already-opened file
ILuint ilSaveExrF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSaveExrInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Exr to a memory "lump"
ILuint ilSaveExrL(void *Lump, ILuint Size)
{
ILuint Pos = itellw();
iSetOutputLump(Lump, Size);
if (iSaveExrInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
ILboolean iSaveExrInternal()
{
Imath::Box2i DataWindow(Imath::V2i(0, 0), Imath::V2i(iCurImage->Width-1, iCurImage->Height-1));
Imf::LineOrder Order;
if (iCurImage->Origin == IL_ORIGIN_LOWER_LEFT)
Order = DECREASING_Y;
else
Order = INCREASING_Y;
Imf::Header Head(iCurImage->Width, iCurImage->Height, DataWindow, 1, Imath::V2f (0, 0), 1, Order);
ilOStream File;
Imf::RgbaOutputFile Out(File, Head);
ILimage *TempImage = iCurImage;
//@TODO: Can we always assume that Rgba is packed the same?
Rgba *HalfData = (Rgba*)ialloc(TempImage->Width * TempImage->Height * sizeof(Rgba));
if (HalfData == NULL)
return IL_FALSE;
if (iCurImage->Format != IL_RGBA || iCurImage->Type != IL_FLOAT) {
TempImage = iConvertImage(iCurImage, IL_RGBA, IL_FLOAT);
if (TempImage == NULL) {
ifree(HalfData);
return IL_FALSE;
}
}
ILuint Offset = 0;
ILfloat *FloatPtr = (ILfloat*)TempImage->Data;
for (unsigned int y = 0; y < TempImage->Height; y++) {
for (unsigned int x = 0; x < TempImage->Width; x++) {
HalfData[y * TempImage->Width + x].r = FloatPtr[Offset];
HalfData[y * TempImage->Width + x].g = FloatPtr[Offset + 1];
HalfData[y * TempImage->Width + x].b = FloatPtr[Offset + 2];
HalfData[y * TempImage->Width + x].a = FloatPtr[Offset + 3];
Offset += 4; // 4 floats
}
}
Out.setFrameBuffer(HalfData, 1, TempImage->Width);
Out.writePixels(TempImage->Height); //@TODO: Do each scanline separately to keep from using so much memory.
// Free our half data.
ifree(HalfData);
// Destroy our temporary image if we used one.
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_TRUE;
}
#endif //IL_NO_EXR
+290
View File
@@ -0,0 +1,290 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 07/07/2006
//
// Filename: src-IL/src/il_fastconv.c
//
// Description: Converts between several image formats
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifdef ALTIVEC_GCC
#include "altivec_typeconversion.h"
#endif
ILboolean iFastConvert(ILenum DestFormat)
{
ILubyte *BytePtr = iCurImage->Data;
ILushort *ShortPtr = (ILushort*)iCurImage->Data;
ILuint *IntPtr = (ILuint*)iCurImage->Data;
ILfloat *FloatPtr = (ILfloat*)iCurImage->Data;
ILdouble *DblPtr = (ILdouble*)iCurImage->Data;
#ifndef ALTIVEC_GCC
ILuint SizeOfData, i=0;
ILubyte TempByte = 0;
ILushort TempShort = 0;
ILuint TempInt = 0;
ILfloat TempFloat = 0;
ILdouble TempDbl = 0;
#endif
switch (DestFormat)
{
case IL_RGB:
case IL_BGR:
if (iCurImage->Format != IL_RGB && iCurImage->Format != IL_BGR)
return IL_FALSE;
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
#ifdef ALTIVEC_GCC
abc2cba_byte(BytePtr,iCurImage->SizeOfData,BytePtr);
#else
SizeOfData = iCurImage->SizeOfData / 3;
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, BytePtr
mov ecx, SizeOfData
L1:
mov al,[ebx+0]
xchg al,[ebx+2]
mov [ebx+0],al
add ebx,3
loop L1
}
#else
for (i = 0; i < SizeOfData; i++) {
TempByte = BytePtr[0];
BytePtr[0] = BytePtr[2];
BytePtr[2] = TempByte;
BytePtr += 3;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
#ifdef ALTIVEC_GCC
abc2cba_short(ShortPtr,iCurImage->SizeOfData,ShortPtr);
#else
SizeOfData = iCurImage->SizeOfData / 6; // 3*2
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, ShortPtr
mov ecx, SizeOfData
L2:
mov ax,[ebx+0]
xchg ax,[ebx+4]
mov [ebx+0],ax
add ebx,6
loop L2
}
#else
for (i = 0; i < SizeOfData; i++) {
TempShort = ShortPtr[0];
ShortPtr[0] = ShortPtr[2];
ShortPtr[2] = TempShort;
ShortPtr += 3;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_INT:
case IL_UNSIGNED_INT:
#ifdef ALTIVEC_GCC
abc2cba_int(IntPtr,iCurImage->SizeOfData,IntPtr);
#else
SizeOfData = iCurImage->SizeOfData / 12; // 3*4
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, IntPtr
mov ecx, SizeOfData
L3:
mov eax,[ebx+0]
xchg eax,[ebx+8]
mov [ebx+0],ax
add ebx,12
loop L3
}
#else
for (i = 0; i < SizeOfData; i++) {
TempInt = IntPtr[0];
IntPtr[0] = IntPtr[2];
IntPtr[2] = TempInt;
IntPtr += 3;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_FLOAT:
#ifdef ALTIVEC_GCC
abc2cba_float(FloatPtr,iCurImage->SizeOfData,FloatPtr);
#else
SizeOfData = iCurImage->SizeOfData / 12; // 3*4
for (i = 0; i < SizeOfData; i++) {
TempFloat = FloatPtr[0];
FloatPtr[0] = FloatPtr[2];
FloatPtr[2] = TempFloat;
FloatPtr += 3;
}
#endif
return IL_TRUE;
case IL_DOUBLE:
#ifdef ALTIVEC_GCC
abc2cba_double(DblPtr,iCurImage->SizeOfData,DblPtr);
#else
SizeOfData = iCurImage->SizeOfData / 24; // 3*8
for (i = 0; i < SizeOfData; i++) {
TempDbl = DblPtr[0];
DblPtr[0] = DblPtr[2];
DblPtr[2] = TempDbl;
DblPtr += 3;
}
#endif
return IL_TRUE;
}
break;
case IL_RGBA:
case IL_BGRA:
if (iCurImage->Format != IL_RGBA && iCurImage->Format != IL_BGRA)
return IL_FALSE;
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
#ifdef ALTIVEC_GCC
abcd2cbad_byte(BytePtr,iCurImage->SizeOfData,BytePtr);
#else
SizeOfData = iCurImage->SizeOfData / 4;
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, BytePtr
mov ecx, SizeOfData
L4:
mov eax,[ebx]
bswap eax
ror eax,8
mov [ebx], eax
add ebx,4
loop L4
}
#else
for (i = 0; i < SizeOfData; i++) {
TempByte = BytePtr[0];
BytePtr[0] = BytePtr[2];
BytePtr[2] = TempByte;
BytePtr += 4;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
#ifdef ALTIVEC_GCC
abcd2cbad_short(ShortPtr,iCurImage->SizeOfData,ShortPtr);
#else
SizeOfData = iCurImage->SizeOfData / 8; // 4*2
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, ShortPtr
mov ecx, SizeOfData
L5:
mov ax,[ebx+0]
xchg ax,[ebx+4]
mov [ebx+0],ax
add ebx,8
loop L5
}
#else
for (i = 0; i < SizeOfData; i++) {
TempShort = ShortPtr[0];
ShortPtr[0] = ShortPtr[2];
ShortPtr[2] = TempShort;
ShortPtr += 4;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_INT:
case IL_UNSIGNED_INT:
#ifdef ALTIVEC_GCC
abcd2cbad_int(IntPtr,iCurImage->SizeOfData,IntPtr);
#else
SizeOfData = iCurImage->SizeOfData / 16; // 4*4
#ifdef USE_WIN32_ASM
__asm
{
mov ebx, IntPtr
mov ecx, SizeOfData
L6:
mov eax,[ebx+0]
xchg eax,[ebx+8]
mov [ebx+0],ax
add ebx,16
loop L6
}
#else
for (i = 0; i < SizeOfData; i++) {
TempInt = IntPtr[0];
IntPtr[0] = IntPtr[2];
IntPtr[2] = TempInt;
IntPtr += 4;
}
#endif//USE_WIN32_ASM
#endif
return IL_TRUE;
case IL_FLOAT:
#ifdef ALTIVEC_GCC
abcd2cbad_float(FloatPtr,iCurImage->SizeOfData,FloatPtr);
#else
SizeOfData = iCurImage->SizeOfData / 16; // 4*4
for (i = 0; i < SizeOfData; i++) {
TempFloat = FloatPtr[0];
FloatPtr[0] = FloatPtr[2];
FloatPtr[2] = TempFloat;
FloatPtr += 4;
}
#endif
return IL_TRUE;
case IL_DOUBLE:
#ifdef ALTIVEC_GCC
abcd2cbad_double(DblPtr,iCurImage->SizeOfData,DblPtr);
#else
SizeOfData = iCurImage->SizeOfData / 32; // 4*8
for (i = 0; i < SizeOfData; i++) {
TempDbl = DblPtr[0];
DblPtr[0] = DblPtr[2];
DblPtr[2] = TempDbl;
DblPtr += 4;
}
#endif
return IL_TRUE;
}
}
return IL_FALSE;
}
+773
View File
@@ -0,0 +1,773 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/04/2009
//
// Filename: src-IL/src/il_files.c
//
// Description: File handling for DevIL
//
//-----------------------------------------------------------------------------
#define __FILES_C
#include "il_internal.h"
#include <stdarg.h>
// All specific to the next set of functions
ILboolean ILAPIENTRY iEofFile(void);
ILboolean ILAPIENTRY iEofLump(void);
ILint ILAPIENTRY iGetcFile(void);
ILint ILAPIENTRY iGetcLump(void);
ILuint ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number);
ILuint ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number);
ILint ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode);
ILint ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode);
ILint ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode);
ILint ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode);
ILuint ILAPIENTRY iTellRFile(void);
ILuint ILAPIENTRY iTellRLump(void);
ILuint ILAPIENTRY iTellWFile(void);
ILuint ILAPIENTRY iTellWLump(void);
ILint ILAPIENTRY iPutcFile(ILubyte Char);
ILint ILAPIENTRY iPutcLump(ILubyte Char);
ILint ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number);
ILint ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number);
ILHANDLE FileRead = NULL, FileWrite = NULL;
const void *ReadLump = NULL;
void *WriteLump = NULL;
ILuint ReadLumpPos = 0, ReadLumpSize = 0, ReadFileStart = 0, WriteFileStart = 0;
ILuint WriteLumpPos = 0, WriteLumpSize = 0;
fGetcProc GetcProcCopy;
fReadProc ReadProcCopy;
fSeekRProc SeekProcCopy;
fTellRProc TellProcCopy;
ILHANDLE (ILAPIENTRY *iopenCopy)(ILconst_string);
void (ILAPIENTRY *icloseCopy)(ILHANDLE);
fPutcProc PutcProcCopy;
fSeekWProc SeekWProcCopy;
fTellWProc TellWProcCopy;
fWriteProc WriteProcCopy;
ILHANDLE (ILAPIENTRY *iopenwCopy)(ILconst_string);
void (ILAPIENTRY *iclosewCopy)(ILHANDLE);
ILboolean UseCache = IL_FALSE;
ILubyte *Cache = NULL;
ILuint CacheSize, CachePos, CacheStartPos, CacheBytesRead;
// "Fake" size functions
// Definitions are in il_size.c.
ILint ILAPIENTRY iSizeSeek(ILint Offset, ILuint Mode);
ILuint ILAPIENTRY iSizeTell(void);
ILint ILAPIENTRY iSizePutc(ILubyte Char);
ILint ILAPIENTRY iSizeWrite(const void *Buffer, ILuint Size, ILuint Number);
// Just preserves the current read functions and replaces
// the current read functions with the default read funcs.
void ILAPIENTRY iPreserveReadFuncs()
{
// Create backups
GetcProcCopy = GetcProc;
ReadProcCopy = ReadProc;
SeekProcCopy = SeekRProc;
TellProcCopy = TellRProc;
iopenCopy = iopenr;
icloseCopy = icloser;
// Set the standard procs to read
ilResetRead();
return;
}
// Restores the read functions - must be used after iPreserveReadFuncs().
void ILAPIENTRY iRestoreReadFuncs()
{
GetcProc = GetcProcCopy;
ReadProc = ReadProcCopy;
SeekRProc = SeekProcCopy;
TellRProc = TellProcCopy;
iopenr = iopenCopy;
icloser = icloseCopy;
return;
}
// Just preserves the current read functions and replaces
// the current read functions with the default read funcs.
void ILAPIENTRY iPreserveWriteFuncs()
{
// Create backups
PutcProcCopy = PutcProc;
SeekWProcCopy = SeekWProc;
TellWProcCopy = TellWProc;
WriteProcCopy = WriteProc;
iopenwCopy = iopenw;
iclosewCopy = iclosew;
// Set the standard procs to write
ilResetWrite();
return;
}
// Restores the read functions - must be used after iPreserveReadFuncs().
void ILAPIENTRY iRestoreWriteFuncs()
{
PutcProc = PutcProcCopy;
SeekWProc = SeekWProcCopy;
TellWProc = TellWProcCopy;
WriteProc = WriteProcCopy;
iopenw = iopenwCopy;
iclosew = iclosewCopy;
return;
}
// Next 7 functions are the default read functions
ILHANDLE ILAPIENTRY iDefaultOpenR(ILconst_string FileName)
{
#ifndef _UNICODE
return (ILHANDLE)fopen((char*)FileName, "rb");
#else
// Windows has a different function, _wfopen, to open UTF16 files,
// whereas Linux just uses fopen for its UTF8 files.
#ifdef _WIN32
return (ILHANDLE)_wfopen(FileName, L"rb");
#else
return (ILHANDLE)fopen((char*)FileName, "rb");
#endif
#endif//UNICODE
}
void ILAPIENTRY iDefaultCloseR(ILHANDLE Handle)
{
fclose((FILE*)Handle);
return;
}
ILboolean ILAPIENTRY iDefaultEof(ILHANDLE Handle)
{
ILuint OrigPos, FileSize;
// Find out the filesize for checking for the end of file
OrigPos = itell();
iseek(0, IL_SEEK_END);
FileSize = itell();
iseek(OrigPos, IL_SEEK_SET);
if (itell() >= FileSize)
return IL_TRUE;
return IL_FALSE;
}
ILint ILAPIENTRY iDefaultGetc(ILHANDLE Handle)
{
ILint Val;
if (!UseCache) {
Val = fgetc((FILE*)Handle);
if (Val == IL_EOF)
ilSetError(IL_FILE_READ_ERROR);
}
else {
Val = 0;
if (iread(&Val, 1, 1) != 1)
return IL_EOF;
}
return Val;
}
ILint ILAPIENTRY iDefaultRead(void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
{
return (ILint)fread(Buffer, Size, Number, (FILE*)Handle);
}
ILint ILAPIENTRY iDefaultRSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
{
return fseek((FILE*)Handle, Offset, Mode);
}
ILint ILAPIENTRY iDefaultWSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
{
return fseek((FILE*)Handle, Offset, Mode);
}
ILint ILAPIENTRY iDefaultRTell(ILHANDLE Handle)
{
return ftell((FILE*)Handle);
}
ILint ILAPIENTRY iDefaultWTell(ILHANDLE Handle)
{
return ftell((FILE*)Handle);
}
ILHANDLE ILAPIENTRY iDefaultOpenW(ILconst_string FileName)
{
#ifndef _UNICODE
return (ILHANDLE)fopen((char*)FileName, "wb");
#else
// Windows has a different function, _wfopen, to open UTF16 files,
// whereas Linux just uses fopen.
#ifdef _WIN32
return (ILHANDLE)_wfopen(FileName, L"wb");
#else
return (ILHANDLE)fopen((char*)FileName, "wb");
#endif
#endif//UNICODE
}
void ILAPIENTRY iDefaultCloseW(ILHANDLE Handle)
{
fclose((FILE*)Handle);
return;
}
ILint ILAPIENTRY iDefaultPutc(ILubyte Char, ILHANDLE Handle)
{
return fputc(Char, (FILE*)Handle);
}
ILint ILAPIENTRY iDefaultWrite(const void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
{
return (ILint)fwrite(Buffer, Size, Number, (FILE*)Handle);
}
void ILAPIENTRY ilResetRead()
{
ilSetRead(iDefaultOpenR, iDefaultCloseR, iDefaultEof, iDefaultGetc,
iDefaultRead, iDefaultRSeek, iDefaultRTell);
return;
}
void ILAPIENTRY ilResetWrite()
{
ilSetWrite(iDefaultOpenW, iDefaultCloseW, iDefaultPutc,
iDefaultWSeek, iDefaultWTell, iDefaultWrite);
return;
}
//! Allows you to override the default file-reading functions.
void ILAPIENTRY ilSetRead(fOpenRProc Open, fCloseRProc Close, fEofProc Eof, fGetcProc Getc, fReadProc Read, fSeekRProc Seek, fTellRProc Tell)
{
iopenr = Open;
icloser = Close;
EofProc = Eof;
GetcProc = Getc;
ReadProc = Read;
SeekRProc = Seek;
TellRProc = Tell;
return;
}
//! Allows you to override the default file-writing functions.
void ILAPIENTRY ilSetWrite(fOpenRProc Open, fCloseRProc Close, fPutcProc Putc, fSeekWProc Seek, fTellWProc Tell, fWriteProc Write)
{
iopenw = Open;
iclosew = Close;
PutcProc = Putc;
WriteProc = Write;
SeekWProc = Seek;
TellWProc = Tell;
return;
}
// Tells DevIL that we're reading from a file, not a lump
void iSetInputFile(ILHANDLE File)
{
ieof = iEofFile;
igetc = iGetcFile;
iread = iReadFile;
iseek = iSeekRFile;
itell = iTellRFile;
FileRead = File;
ReadFileStart = itell();
}
// Tells DevIL that we're reading from a lump, not a file
void iSetInputLump(const void *Lump, ILuint Size)
{
ieof = iEofLump;
igetc = iGetcLump;
iread = iReadLump;
iseek = iSeekRLump;
itell = iTellRLump;
ReadLump = Lump;
ReadLumpPos = 0;
ReadLumpSize = Size;
}
// Tells DevIL that we're writing to a file, not a lump
void iSetOutputFile(ILHANDLE File)
{
// Helps with ilGetLumpPos().
WriteLump = NULL;
WriteLumpPos = 0;
WriteLumpSize = 0;
iputc = iPutcFile;
iseekw = iSeekWFile;
itellw = iTellWFile;
iwrite = iWriteFile;
FileWrite = File;
}
// This is only called by ilDetermineSize. Associates iputc, etc. with
// "fake" writing functions in il_size.c.
void iSetOutputFake(void)
{
iputc = iSizePutc;
iseekw = iSizeSeek;
itellw = iSizeTell;
iwrite = iSizeWrite;
return;
}
// Tells DevIL that we're writing to a lump, not a file
void iSetOutputLump(void *Lump, ILuint Size)
{
// In this case, ilDetermineSize is currently trying to determine the
// output buffer size. It already has the write functions it needs.
if (Lump == NULL)
return;
iputc = iPutcLump;
iseekw = iSeekWLump;
itellw = iTellWLump;
iwrite = iWriteLump;
WriteLump = Lump;
WriteLumpPos = 0;
WriteLumpSize = Size;
}
ILuint ILAPIENTRY ilGetLumpPos()
{
if (WriteLump)
return WriteLumpPos;
return 0;
}
ILuint ILAPIENTRY ilprintf(const char *Line, ...)
{
char Buffer[2048]; // Hope this is large enough
va_list VaLine;
ILuint i;
va_start(VaLine, Line);
vsprintf(Buffer, Line, VaLine);
va_end(VaLine);
i = ilCharStrLen(Buffer);
iwrite(Buffer, 1, i);
return i;
}
// To pad zeros where needed...
void ipad(ILuint NumZeros)
{
ILuint i = 0;
for (; i < NumZeros; i++)
iputc(0);
return;
}
//
// The rest of the functions following in this file are quite
// self-explanatory, except where commented.
//
// Next 12 functions are the default write functions
ILboolean ILAPIENTRY iEofFile(void)
{
return EofProc((FILE*)FileRead);
}
ILboolean ILAPIENTRY iEofLump(void)
{
if (ReadLumpSize)
return (ReadLumpPos >= ReadLumpSize);
return IL_FALSE;
}
ILint ILAPIENTRY iGetcFile(void)
{
if (!UseCache) {
return GetcProc(FileRead);
}
if (CachePos >= CacheSize) {
iPreCache(CacheSize);
}
CacheBytesRead++;
return Cache[CachePos++];
}
ILint ILAPIENTRY iGetcLump(void)
{
// If ReadLumpSize is 0, don't even check to see if we've gone past the bounds.
if (ReadLumpSize > 0) {
if (ReadLumpPos + 1 > ReadLumpSize) {
ReadLumpPos--;
ilSetError(IL_FILE_READ_ERROR);
return IL_EOF;
}
}
return *((ILubyte*)ReadLump + ReadLumpPos++);
}
ILuint ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number)
{
ILuint TotalBytes = 0, BytesCopied;
ILuint BuffSize = Size * Number;
ILuint NumRead;
if (!UseCache) {
NumRead = ReadProc(Buffer, Size, Number, FileRead);
if (NumRead != Number)
ilSetError(IL_FILE_READ_ERROR);
return NumRead;
}
/*if (Cache == NULL || CacheSize == 0) { // Shouldn't happen, but we check anyway.
return ReadProc(Buffer, Size, Number, FileRead);
}*/
if (BuffSize < CacheSize - CachePos) {
memcpy(Buffer, Cache + CachePos, BuffSize);
CachePos += BuffSize;
CacheBytesRead += BuffSize;
if (Size != 0)
BuffSize /= Size;
return BuffSize;
}
else {
while (TotalBytes < BuffSize) {
// If loop through more than once, after first, CachePos is 0.
if (TotalBytes + CacheSize - CachePos > BuffSize)
BytesCopied = BuffSize - TotalBytes;
else
BytesCopied = CacheSize - CachePos;
memcpy((ILubyte*)Buffer + TotalBytes, Cache + CachePos, BytesCopied);
TotalBytes += BytesCopied;
CachePos += BytesCopied;
if (TotalBytes < BuffSize) {
iPreCache(CacheSize);
}
}
}
// DW: Changed on 12-27-2008. Was causing the position to go too far if the
// cache was smaller than the buffer.
//CacheBytesRead += TotalBytes;
CacheBytesRead = CachePos;
if (Size != 0)
TotalBytes /= Size;
if (TotalBytes != Number)
ilSetError(IL_FILE_READ_ERROR);
return TotalBytes;
}
ILuint ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number)
{
ILuint i, ByteSize = IL_MIN( Size*Number, ReadLumpSize-ReadLumpPos);
for (i = 0; i < ByteSize; i++) {
*((ILubyte*)Buffer + i) = *((ILubyte*)ReadLump + ReadLumpPos + i);
if (ReadLumpSize > 0) { // ReadLumpSize is too large to care about apparently
if (ReadLumpPos + i > ReadLumpSize) {
ReadLumpPos += i;
if (i != Number)
ilSetError(IL_FILE_READ_ERROR);
return i;
}
}
}
ReadLumpPos += i;
if (Size != 0)
i /= Size;
if (i != Number)
ilSetError(IL_FILE_READ_ERROR);
return i;
}
ILboolean iPreCache(ILuint Size)
{
// Reading from a memory lump, so don't cache.
if (iread == iReadLump) {
//iUnCache(); // DW: Removed 06-10-2002.
return IL_TRUE;
}
if (Cache) {
ifree(Cache);
}
if (Size == 0) {
Size = 1;
}
Cache = (ILubyte*)ialloc(Size);
if (Cache == NULL) {
return IL_FALSE;
}
UseCache = IL_FALSE;
CacheStartPos = itell();
CacheSize = iread(Cache, 1, Size);
if (CacheSize != Size)
ilGetError(); // Get rid of the IL_FILE_READ_ERROR.
//2003-09-09: uncommented the following line to prevent
//an infinite loop in ilPreCache()
CacheSize = Size;
CachePos = 0;
UseCache = IL_TRUE;
CacheBytesRead = 0;
return IL_TRUE;
}
void iUnCache()
{
//changed 2003-09-01:
//make iUnCache smart enough to return if
//no cache is used
if (!UseCache)
return;
if (iread == iReadLump)
return;
CacheSize = 0;
CachePos = 0;
if (Cache) {
ifree(Cache);
Cache = NULL;
}
UseCache = IL_FALSE;
iseek(CacheStartPos + CacheBytesRead, IL_SEEK_SET);
return;
}
ILint ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode)
{
if (Mode == IL_SEEK_SET)
Offset += ReadFileStart; // This allows us to use IL_SEEK_SET in the middle of a file.
return SeekRProc(FileRead, Offset, Mode);
}
// Returns 1 on error, 0 on success
ILint ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode)
{
switch (Mode)
{
case IL_SEEK_SET:
if (Offset > (ILint)ReadLumpSize)
return 1;
ReadLumpPos = Offset;
break;
case IL_SEEK_CUR:
if (ReadLumpPos + Offset > ReadLumpSize)
return 1;
ReadLumpPos += Offset;
break;
case IL_SEEK_END:
if (Offset > 0)
return 1;
// Should we use >= instead?
if (abs(Offset) > (ILint)ReadLumpSize) // If ReadLumpSize == 0, too bad
return 1;
ReadLumpPos = ReadLumpSize + Offset;
break;
default:
return 1;
}
return 0;
}
ILuint ILAPIENTRY iTellRFile(void)
{
return TellRProc(FileRead);
}
ILuint ILAPIENTRY iTellRLump(void)
{
return ReadLumpPos;
}
ILHANDLE ILAPIENTRY iGetFile(void)
{
return FileRead;
}
const ILubyte* ILAPIENTRY iGetLump(void) {
return (ILubyte*)ReadLump;
}
// Next 4 functions are the default write functions
ILint ILAPIENTRY iPutcFile(ILubyte Char)
{
return PutcProc(Char, FileWrite);
}
ILint ILAPIENTRY iPutcLump(ILubyte Char)
{
if (WriteLumpPos >= WriteLumpSize)
return IL_EOF; // IL_EOF
*((ILubyte*)(WriteLump) + WriteLumpPos++) = Char;
return Char;
}
ILint ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number)
{
ILuint NumWritten;
NumWritten = WriteProc(Buffer, Size, Number, FileWrite);
if (NumWritten != Number) {
ilSetError(IL_FILE_WRITE_ERROR);
return 0;
}
return NumWritten;
}
ILint ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number)
{
ILuint SizeBytes = Size * Number;
ILuint i = 0;
for (; i < SizeBytes; i++) {
if (WriteLumpSize > 0) {
if (WriteLumpPos + i >= WriteLumpSize) { // Should we use > instead?
ilSetError(IL_FILE_WRITE_ERROR);
WriteLumpPos += i;
return i;
}
}
*((ILubyte*)WriteLump + WriteLumpPos + i) = *((ILubyte*)Buffer + i);
}
WriteLumpPos += SizeBytes;
return SizeBytes;
}
ILint ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode)
{
if (Mode == IL_SEEK_SET)
Offset += WriteFileStart; // This allows us to use IL_SEEK_SET in the middle of a file.
return SeekWProc(FileWrite, Offset, Mode);
}
// Returns 1 on error, 0 on success
ILint ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode)
{
switch (Mode)
{
case IL_SEEK_SET:
if (Offset > (ILint)WriteLumpSize)
return 1;
WriteLumpPos = Offset;
break;
case IL_SEEK_CUR:
if (WriteLumpPos + Offset > WriteLumpSize)
return 1;
WriteLumpPos += Offset;
break;
case IL_SEEK_END:
if (Offset > 0)
return 1;
// Should we use >= instead?
if (abs(Offset) > (ILint)WriteLumpSize) // If WriteLumpSize == 0, too bad
return 1;
WriteLumpPos = WriteLumpSize + Offset;
break;
default:
return 1;
}
return 0;
}
ILuint ILAPIENTRY iTellWFile(void)
{
return TellWProc(FileWrite);
}
ILuint ILAPIENTRY iTellWLump(void)
{
return WriteLumpPos;
}
+472
View File
@@ -0,0 +1,472 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/14/2009
//
// Filename: src-IL/src/il_fits.c
//
// Description: Reads from a Flexible Image Transport System (.fits) file.
// Specifications were found at
// http://www.fileformat.info/format/fits.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_FITS
typedef struct FITSHEAD
{
ILboolean IsSimple;
ILint BitsPixel;
ILint NumAxes; // Number of dimensions / axes
ILint Width;
ILint Height;
ILint Depth;
ILint NumChans;
// Not in the header, but it keeps everything together.
ILenum Type;
ILenum Format;
} FITSHEAD;
enum {
CARD_READ_FAIL = -1,
CARD_END = 1,
CARD_SIMPLE,
CARD_NOT_SIMPLE,
CARD_BITPIX,
CARD_NUMAXES,
CARD_AXIS,
CARD_SKIP
};
ILboolean iIsValidFits(void);
ILboolean iCheckFits(FITSHEAD *Header);
ILboolean iLoadFitsInternal(void);
ILenum GetCardImage(FITSHEAD *Header);
ILboolean GetCardInt(char *Buffer, ILint *Val);
//! Checks if the file specified in FileName is a valid FITS file.
ILboolean ilIsValidFits(ILconst_string FileName)
{
ILHANDLE FitsFile;
ILboolean bFits = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("fits")) && !iCheckExtension(FileName, IL_TEXT("fit"))) {
ilSetError(IL_INVALID_EXTENSION);
return bFits;
}
FitsFile = iopenr(FileName);
if (FitsFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bFits;
}
bFits = ilIsValidFitsF(FitsFile);
icloser(FitsFile);
return bFits;
}
//! Checks if the ILHANDLE contains a valid FITS file at the current position.
ILboolean ilIsValidFitsF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidFits();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid FITS lump.
ILboolean ilIsValidFitsL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidFits();
}
// Internal function used to get the FITS header from the current file.
ILboolean iGetFitsHead(FITSHEAD *Header)
{
ILenum CardKey;
//@TODO: Use something other than memset?
memset(Header, 0, sizeof(Header)); // Clear the header to all 0s first.
do {
CardKey = GetCardImage(Header);
if (CardKey == CARD_END) // End of the header
break;
if (CardKey == CARD_READ_FAIL)
return IL_FALSE;
if (CardKey == CARD_NOT_SIMPLE)
return IL_FALSE;
} while (!ieof());
// The header should never reach the end of the file.
if (ieof())
return IL_FALSE; // Error needed?
// The header must always be a multiple of 2880, so we skip the padding bytes (spaces).
iseek((2880 - (itell() % 2880)) % 2880, IL_SEEK_CUR);
switch (Header->BitsPixel)
{
case 8:
Header->Type = IL_UNSIGNED_BYTE;
break;
case 16:
Header->Type = IL_SHORT;
break;
case 32:
Header->Type = IL_INT;
break;
case -32:
Header->Type = IL_FLOAT;
break;
case -64:
Header->Type = IL_DOUBLE;
break;
default:
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
switch (Header->NumAxes)
{
case 1: // Just a 1D image
Header->Format = IL_LUMINANCE;
Header->Height = 1;
Header->Depth = 1;
Header->NumChans = 1;
break;
case 2: // Assuming it is a 2D image (width+height)
Header->Format = IL_LUMINANCE;
Header->Depth = 1;
Header->NumChans = 1;
break;
case 3:
// We cannot deal with more than 3 channels in an image.
Header->Format = IL_LUMINANCE;
Header->NumChans = 1;
break;
default:
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidFits(void)
{
FITSHEAD Header;
ILuint Pos = itell();
if (!iGetFitsHead(&Header))
return IL_FALSE;
// The length of the header varies, so we just go back to the original position.
iseek(Pos, IL_SEEK_CUR);
return iCheckFits(&Header);
}
// Internal function used to check if the HEADER is a valid FITS header.
ILboolean iCheckFits(FITSHEAD *Header)
{
switch (Header->BitsPixel)
{
case 8: // These are the only values accepted.
case 16:
case 32:
case -32:
case -64:
break;
default:
return IL_FALSE;
}
switch (Header->NumAxes)
{
case 1: // Just a 1D image
case 2: // Assuming it is a 2D image (width+height)
case 3: // 3D image (with depth)
break;
default:
return IL_FALSE;
}
// Possibility that one of these values is returned as <= 0 by atoi, which we cannot use.
if (Header->Width <= 0 || Header->Height <= 0 || Header->Depth <= 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
return IL_TRUE;
}
//! Reads a FITS file
ILboolean ilLoadFits(ILconst_string FileName)
{
ILHANDLE FitsFile;
ILboolean bFits = IL_FALSE;
FitsFile = iopenr(FileName);
if (FitsFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bFits;
}
bFits = ilLoadFitsF(FitsFile);
icloser(FitsFile);
return bFits;
}
//! Reads an already-opened FITS file
ILboolean ilLoadFitsF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadFitsInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a FITS
ILboolean ilLoadFitsL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadFitsInternal();
}
// Internal function used to load the FITS.
ILboolean iLoadFitsInternal(void)
{
FITSHEAD Header;
ILuint i, NumPix;
ILfloat MaxF = 0.0f;
ILdouble MaxD = 0.0f;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetFitsHead(&Header))
return IL_FALSE;
if (!iCheckFits(&Header))
return IL_FALSE;
if (!ilTexImage(Header.Width, Header.Height, Header.Depth, Header.NumChans, Header.Format, Header.Type, NULL))
return IL_FALSE;
/*if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
return IL_FALSE;*/
NumPix = Header.Width * Header.Height * Header.Depth;
//@TODO: Do some checks while reading to see if we have hit the end of the file.
switch (Header.Type)
{
case IL_UNSIGNED_BYTE:
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
return IL_FALSE;
break;
case IL_SHORT:
for (i = 0; i < NumPix; i++) {
((ILshort*)iCurImage->Data)[i] = GetBigShort();
}
break;
case IL_INT:
for (i = 0; i < NumPix; i++) {
((ILint*)iCurImage->Data)[i] = GetBigInt();
}
break;
case IL_FLOAT:
for (i = 0; i < NumPix; i++) {
((ILfloat*)iCurImage->Data)[i] = GetBigFloat();
if (((ILfloat*)iCurImage->Data)[i] > MaxF)
MaxF = ((ILfloat*)iCurImage->Data)[i];
}
// Renormalize to [0..1].
for (i = 0; i < NumPix; i++) {
// Change all negative numbers to 0.
if (((ILfloat*)iCurImage->Data)[i] < 0.0f)
((ILfloat*)iCurImage->Data)[i] = 0.0f;
// Do the renormalization now, dividing by the maximum value.
((ILfloat*)iCurImage->Data)[i] = ((ILfloat*)iCurImage->Data)[i] / MaxF;
}
break;
case IL_DOUBLE:
for (i = 0; i < NumPix; i++) {
((ILdouble*)iCurImage->Data)[i] = GetBigDouble();
if (((ILdouble*)iCurImage->Data)[i] > MaxD)
MaxD = ((ILdouble*)iCurImage->Data)[i];
}
// Renormalize to [0..1].
for (i = 0; i < NumPix; i++) {
// Change all negative numbers to 0.
if (((ILdouble*)iCurImage->Data)[i] < 0.0f)
((ILdouble*)iCurImage->Data)[i] = 0.0f;
// Do the renormalization now, dividing by the maximum value.
((ILdouble*)iCurImage->Data)[i] = ((ILdouble*)iCurImage->Data)[i] / MaxD;
} break;
}
return ilFixImage();
}
//@TODO: NAXISx have to come in order. Check this!
ILenum GetCardImage(FITSHEAD *Header)
{
char Buffer[80];
if (iread(Buffer, 1, 80) != 80) // Each card image is exactly 80 bytes long.
return CARD_READ_FAIL;
//@TODO: Use something other than !strncmp?
if (!strncmp(Buffer, "END ", 4))
return CARD_END;
else if (!strncmp(Buffer, "SIMPLE ", 7)) {
// The true value 'T' is always in the 30th position.
if (Buffer[29] != 'T') {
// We cannot support FITS files that do not correspond to the standard.
Header->IsSimple = IL_FALSE; //@TODO: Does this even need to be set? Should exit loading anyway.
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return CARD_NOT_SIMPLE;
}
Header->IsSimple = IL_TRUE;
return CARD_SIMPLE;
}
else if (!strncmp(Buffer, "BITPIX ", 7)) {
// The specs state that BITPIX has to come after SIMPLE.
if (Header->IsSimple != IL_TRUE) {
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
if (GetCardInt(Buffer, &Header->BitsPixel) != IL_TRUE)
return CARD_READ_FAIL;
//@TODO: Should I do this check from the calling function? Does it really matter?
if (Header->BitsPixel == 0) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return CARD_READ_FAIL;
}
return CARD_BITPIX;
}
// Needs the space after NAXIS so that it does not get this confused with NAXIS1, NAXIS2, etc.
else if (!strncmp(Buffer, "NAXIS ", 6)) {
if (GetCardInt(Buffer, &Header->NumAxes) != IL_TRUE)
return CARD_READ_FAIL;
//@TODO: Should I do this check from the calling function? Does it really matter?
if (Header->NumAxes < 1 || Header->NumAxes > 3) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return CARD_READ_FAIL;
}
return CARD_NUMAXES;
}
else if (!strncmp(Buffer, "NAXIS1 ", 7)) {
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
// First one will always be the width.
if (GetCardInt(Buffer, &Header->Width) != IL_TRUE)
return CARD_READ_FAIL;
return CARD_AXIS;
}
else if (!strncmp(Buffer, "NAXIS2 ", 7)) {
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
// Cannot have a 2nd axis for 0 or 1.
if (Header->NumAxes == 0 || Header->NumAxes == 1) {
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
//@TODO: We are assuming that this is the height right now. Could it just be a
// 1D image with multiple bytes per pixel?
if (GetCardInt(Buffer, &Header->Height) != IL_TRUE)
return CARD_READ_FAIL;
return CARD_AXIS;
}
else if (!strncmp(Buffer, "NAXIS3 ", 7)) {
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
// Cannot have a 3rd axis for 0, 1 and 2.
if (Header->NumAxes < 3) {
ilSetError(IL_INVALID_FILE_HEADER);
return CARD_READ_FAIL;
}
if (GetCardInt(Buffer, &Header->Depth) != IL_TRUE)
return CARD_READ_FAIL;
return CARD_AXIS;
}
return CARD_SKIP; // This is a card that we do not recognize, so skip it.
}
ILboolean GetCardInt(char *Buffer, ILint *Val)
{
ILuint i;
char ValString[22];
if (Buffer[7] != '=' && Buffer[8] != '=')
return IL_FALSE;
for (i = 9; i < 30; i++) {
if (Buffer[i] != ' ' && Buffer[i] != 0) // Right-aligned with ' ' or 0, so skip.
break;
}
if (i == 30) // Did not find the integer in positions 10 - 30.
return IL_FALSE;
//@TODO: Safest way to do this?
memcpy(ValString, &Buffer[i], 30-i);
ValString[30-i] = 0; // Terminate the string.
//@TODO: Check the return somehow?
*Val = atoi(ValString);
return IL_TRUE;
}
#endif//IL_NO_FITS
+101
View File
@@ -0,0 +1,101 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/12/2009
//
// Filename: src-IL/src/il_ftx.c
//
// Description: Reads from a Heavy Metal: FAKK2 (.ftx) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_FTX
ILboolean iLoadFtxInternal(void);
//! Reads a FTX file
ILboolean ilLoadFtx(ILconst_string FileName)
{
ILHANDLE FtxFile;
ILboolean bFtx = IL_FALSE;
FtxFile = iopenr(FileName);
if (FtxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bFtx;
}
bFtx = ilLoadFtxF(FtxFile);
icloser(FtxFile);
return bFtx;
}
//! Reads an already-opened FTX file
ILboolean ilLoadFtxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadFtxInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a FTX
ILboolean ilLoadFtxL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadFtxInternal();
}
// Internal function used to load the FTX.
ILboolean iLoadFtxInternal(void)
{
ILuint Width, Height, HasAlpha;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Width = GetLittleUInt();
Height = GetLittleUInt();
HasAlpha = GetLittleUInt(); // Kind of backwards from what I would think...
//@TODO: Right now, it appears that all images are in RGBA format. See if I can find specs otherwise
// or images that load incorrectly like this.
//if (HasAlpha == 0) { // RGBA format
if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
//}
//else if (HasAlpha == 1) { // RGB format
// if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
// return IL_FALSE;
//}
//else { // Unknown format
// ilSetError(IL_INVALID_FILE_HEADER);
// return IL_FALSE;
//}
// The origin will always be in the upper left.
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
// All we have to do for this format is read the raw, uncompressed data.
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
return IL_FALSE;
return ilFixImage();
}
#endif//IL_NO_FTX
+755
View File
@@ -0,0 +1,755 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_gif.c
//
// Description: Reads from a Graphics Interchange Format (.gif) file.
//
// The LZW decompression code is based on code released to the public domain
// by Javier Arevalo and can be found at
// http://www.programmersheaven.com/zone10/cat452
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_GIF
#include "il_gif.h"
ILenum GifType;
//! Checks if the file specified in FileName is a valid Gif file.
ILboolean ilIsValidGif(ILconst_string FileName)
{
ILHANDLE GifFile;
ILboolean bGif = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("gif"))) {
ilSetError(IL_INVALID_EXTENSION);
return bGif;
}
GifFile = iopenr(FileName);
if (GifFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bGif;
}
bGif = ilIsValidGifF(GifFile);
icloser(GifFile);
return bGif;
}
//! Checks if the ILHANDLE contains a valid Gif file at the current position.
ILboolean ilIsValidGifF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidGif();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid Gif lump.
ILboolean ilIsValidGifL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidGif();
}
// Internal function to get the header and check it.
ILboolean iIsValidGif()
{
char Header[6];
if (iread(Header, 1, 6) != 6)
return IL_FALSE;
iseek(-6, IL_SEEK_CUR);
if (!strnicmp(Header, "GIF87A", 6))
return IL_TRUE;
if (!strnicmp(Header, "GIF89A", 6))
return IL_TRUE;
return IL_FALSE;
}
//! Reads a Gif file
ILboolean ilLoadGif(ILconst_string FileName)
{
ILHANDLE GifFile;
ILboolean bGif = IL_FALSE;
GifFile = iopenr(FileName);
if (GifFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bGif;
}
bGif = ilLoadGifF(GifFile);
icloser(GifFile);
return bGif;
}
//! Reads an already-opened Gif file
ILboolean ilLoadGifF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadGifInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Gif
ILboolean ilLoadGifL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadGifInternal();
}
// Internal function used to load the Gif.
ILboolean iLoadGifInternal()
{
GIFHEAD Header;
ILpal GlobalPal;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
GlobalPal.Palette = NULL;
GlobalPal.PalSize = 0;
//read header
iread(&Header.Sig, 1, 6);
Header.Width = GetLittleUShort();
Header.Height = GetLittleUShort();
Header.ColourInfo = igetc();
Header.Background = igetc();
Header.Aspect = igetc();
if (!strnicmp(Header.Sig, "GIF87A", 6)) {
GifType = GIF87A;
}
else if (!strnicmp(Header.Sig, "GIF89A", 6)) {
GifType = GIF89A;
}
else {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
// Check for a global colour map.
if (Header.ColourInfo & (1 << 7)) {
if (!iGetPalette(Header.ColourInfo, &GlobalPal, IL_FALSE, NULL)) {
return IL_FALSE;
}
}
if (!GetImages(&GlobalPal, &Header))
return IL_FALSE;
if (GlobalPal.Palette && GlobalPal.PalSize)
ifree(GlobalPal.Palette);
GlobalPal.Palette = NULL;
GlobalPal.PalSize = 0;
return ilFixImage();
}
ILboolean iGetPalette(ILubyte Info, ILpal *Pal, ILboolean UsePrevPal, ILimage *PrevImage)
{
ILuint PalSize, PalOffset = 0;
// If we have a local palette and have to use the previous frame as well,
// we have to copy the palette from the previous frame, in addition
// to the data, which we copy in GetImages.
// The ld(palettes bpp - 1) is stored in the lower
// 3 bits of Info (weird gif format ... :) )
PalSize = (1 << ((Info & 0x7) + 1)) * 3;
if (UsePrevPal) {
if (PrevImage == NULL) { // Cannot use the previous palette if it does not exist.
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
PalSize = PalSize + PrevImage->Pal.PalSize;
PalOffset = PrevImage->Pal.PalSize;
}
if (PalSize > 256 * 3) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
Pal->PalSize = PalSize;
Pal->PalType = IL_PAL_RGB24;
//Pal->Palette = (ILubyte*)ialloc(Pal->PalSize);
Pal->Palette = (ILubyte*)ialloc(256 * 3);
if (Pal->Palette == NULL)
return IL_FALSE;
if (UsePrevPal)
memcpy(Pal->Palette, PrevImage->Pal.Palette, PrevImage->Pal.PalSize); // Copy the old palette over.
if (iread(Pal->Palette + PalOffset, 1, Pal->PalSize) != Pal->PalSize) { // Read the new palette.
ifree(Pal->Palette);
Pal->Palette = NULL;
return IL_FALSE;
}
return IL_TRUE;
}
ILboolean GetImages(ILpal *GlobalPal, GIFHEAD *GifHead)
{
IMAGEDESC ImageDesc, OldImageDesc;
GFXCONTROL Gfx;
ILboolean BaseImage = IL_TRUE;
ILimage *Image = iCurImage, *TempImage = NULL, *PrevImage = NULL;
ILuint NumImages = 0, i;
ILint input;
ILuint PalOffset;
OldImageDesc.ImageInfo = 0; // to initialize the data with an harmless value
Gfx.Used = IL_TRUE;
while (!ieof()) {
ILubyte DisposalMethod = 1;
i = itell();
if (!SkipExtensions(&Gfx))
goto error_clean;
i = itell();
if (!Gfx.Used)
DisposalMethod = (Gfx.Packed & 0x1C) >> 2;
//read image descriptor
ImageDesc.Separator = igetc();
if (ImageDesc.Separator != 0x2C) //end of image
break;
ImageDesc.OffX = GetLittleUShort();
ImageDesc.OffY = GetLittleUShort();
ImageDesc.Width = GetLittleUShort();
ImageDesc.Height = GetLittleUShort();
ImageDesc.ImageInfo = igetc();
if (ieof()) {
ilGetError(); // Gets rid of the IL_FILE_READ_ERROR that inevitably results.
break;
}
if (!BaseImage) {
NumImages++;
Image->Next = ilNewImage(iCurImage->Width, iCurImage->Height, 1, 1, 1);
if (Image->Next == NULL)
goto error_clean;
//20040612: DisposalMethod controls how the new images data is to be combined
//with the old image. 0 means that it doesn't matter how they are combined,
//1 means keep the old image, 2 means set to background color, 3 is
//load the image that was in place before the current (this is not implemented
//here! (TODO?))
if (DisposalMethod == 2 || DisposalMethod == 3)
//Note that this is actually wrong, too: If the image has a local
//color table, we should really search for the best fit of the
//background color table and use that index (?). Furthermore,
//we should only memset the part of the image that is not read
//later (if we are sure that no parts of the read image are transparent).
if (!Gfx.Used && Gfx.Packed & 0x1)
memset(Image->Next->Data, Gfx.Transparent, Image->SizeOfData);
else
memset(Image->Next->Data, GifHead->Background, Image->SizeOfData);
else if (DisposalMethod == 1 || DisposalMethod == 0)
memcpy(Image->Next->Data, Image->Data, Image->SizeOfData);
//Interlacing has to be removed after the image was copied (line above)
if (OldImageDesc.ImageInfo & (1 << 6)) { // Image is interlaced.
if (!RemoveInterlace(Image))
goto error_clean;
}
PrevImage = Image;
Image = Image->Next;
Image->Format = IL_COLOUR_INDEX;
Image->Origin = IL_ORIGIN_UPPER_LEFT;
} else {
BaseImage = IL_FALSE;
if (!Gfx.Used && Gfx.Packed & 0x1)
memset(Image->Data, Gfx.Transparent, Image->SizeOfData);
else
memset(Image->Data, GifHead->Background, Image->SizeOfData);
}
Image->OffX = ImageDesc.OffX;
Image->OffY = ImageDesc.OffY;
PalOffset = 0;
// Check to see if the image has its own palette.
if (ImageDesc.ImageInfo & (1 << 7)) {
ILboolean UsePrevPal = IL_FALSE;
if (DisposalMethod == 1 && NumImages != 0) { // Cannot be the first image for this.
PalOffset = PrevImage->Pal.PalSize;
UsePrevPal = IL_TRUE;
}
if (!iGetPalette(ImageDesc.ImageInfo, &Image->Pal, UsePrevPal, PrevImage)) {
goto error_clean;
}
} else {
if (!iCopyPalette(&Image->Pal, GlobalPal)) {
goto error_clean;
}
}
if (!GifGetData(Image, Image->Data + ImageDesc.OffX + ImageDesc.OffY*Image->Width, Image->SizeOfData,
ImageDesc.Width, ImageDesc.Height, Image->Width, PalOffset, &Gfx)) {
memset(Image->Data, 0, Image->SizeOfData); //@TODO: Remove this. For debugging purposes right now.
ilSetError(IL_ILLEGAL_FILE_VALUE);
goto error_clean;
}
// See if there was a valid graphics control extension.
if (!Gfx.Used) {
Gfx.Used = IL_TRUE;
Image->Duration = Gfx.Delay * 10; // We want it in milliseconds.
// See if a transparent colour is defined.
if (Gfx.Packed & 1) {
if (!ConvertTransparent(Image, Gfx.Transparent)) {
goto error_clean;
}
}
}
i = itell();
// Terminates each block.
if((input = igetc()) == IL_EOF)
goto error_clean;
if (input != 0x00)
iseek(-1, IL_SEEK_CUR);
// break;
OldImageDesc = ImageDesc;
}
//Deinterlace last image
if (OldImageDesc.ImageInfo & (1 << 6)) { // Image is interlaced.
if (!RemoveInterlace(Image))
goto error_clean;
}
if (BaseImage) // Was not able to load any images in...
return IL_FALSE;
return IL_TRUE;
error_clean:
Image = iCurImage->Next;
/* while (Image) {
TempImage = Image;
Image = Image->Next;
ilCloseImage(TempImage);
}*/
return IL_FALSE;
}
ILboolean SkipExtensions(GFXCONTROL *Gfx)
{
ILint Code;
ILint Label;
ILint Size;
// DW (06-03-2002): Apparently there can be...
//if (GifType == GIF87A)
// return IL_TRUE; // No extensions in the GIF87a format.
do {
if((Code = igetc()) == IL_EOF)
return IL_FALSE;
if (Code != 0x21) {
iseek(-1, IL_SEEK_CUR);
return IL_TRUE;
}
if((Label = igetc()) == IL_EOF)
return IL_FALSE;
switch (Label)
{
case 0xF9:
Gfx->Size = igetc();
Gfx->Packed = igetc();
Gfx->Delay = GetLittleUShort();
Gfx->Transparent = igetc();
Gfx->Terminator = igetc();
if (ieof())
return IL_FALSE;
Gfx->Used = IL_FALSE;
break;
/*case 0xFE:
break;
case 0x01:
break;*/
default:
do {
if((Size = igetc()) == IL_EOF)
return IL_FALSE;
iseek(Size, IL_SEEK_CUR);
} while (!ieof() && Size != 0);
}
// @TODO: Handle this better.
if (ieof()) {
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
} while (1);
return IL_TRUE;
}
#define MAX_CODES 4096
ILint curr_size, clear, ending, newcodes, top_slot, slot, navail_bytes = 0, nbits_left = 0;
ILubyte b1;
ILubyte byte_buff[257];
ILubyte *pbytes;
ILubyte *stack;
ILubyte *suffix;
ILshort *prefix;
ILboolean success;
ILuint code_mask[13] =
{
0L,
0x0001L, 0x0003L,
0x0007L, 0x000FL,
0x001FL, 0x003FL,
0x007FL, 0x00FFL,
0x01FFL, 0x03FFL,
0x07FFL, 0x0FFFL
};
ILint get_next_code(void) {
ILint i, t;
ILuint ret;
//20050102: Tests for IL_EOF were added because this function
//crashed sometimes if igetc() returned IL_EOF
//(for example "table-add-column-before-active.gif" included in the
//mozilla source package)
if (!nbits_left) {
if (navail_bytes <= 0) {
pbytes = byte_buff;
navail_bytes = igetc();
if(navail_bytes == IL_EOF) {
success = IL_FALSE;
return ending;
}
if (navail_bytes) {
for (i = 0; i < navail_bytes; i++) {
if((t = igetc()) == IL_EOF) {
success = IL_FALSE;
return ending;
}
byte_buff[i] = t;
}
}
}
b1 = *pbytes++;
nbits_left = 8;
navail_bytes--;
}
ret = b1 >> (8 - nbits_left);
while (curr_size > nbits_left) {
if (navail_bytes <= 0) {
pbytes = byte_buff;
navail_bytes = igetc();
if(navail_bytes == IL_EOF) {
success = IL_FALSE;
return ending;
}
if (navail_bytes) {
for (i = 0; i < navail_bytes; i++) {
if((t = igetc()) == IL_EOF) {
success = IL_FALSE;
return ending;
}
byte_buff[i] = t;
}
}
}
b1 = *pbytes++;
ret |= b1 << nbits_left;
nbits_left += 8;
navail_bytes--;
}
nbits_left -= curr_size;
return (ret & code_mask[curr_size]);
}
static void cleanUpGifLoadState()
{
ifree(stack);
ifree(suffix);
ifree(prefix);
}
ILboolean GifGetData(ILimage *Image, ILubyte *Data, ILuint ImageSize, ILuint Width, ILuint Height, ILuint Stride, ILuint PalOffset, GFXCONTROL *Gfx)
{
ILubyte *sp;
ILint code, fc, oc;
ILubyte DisposalMethod = 0;
ILint c, size;
ILuint i = 0, Read = 0, j = 0;
ILubyte *DataPtr = Data;
if (!Gfx->Used)
DisposalMethod = (Gfx->Packed & 0x1C) >> 2;
if((size = igetc()) == IL_EOF)
return IL_FALSE;
if (size < 2 || 9 < size) {
return IL_FALSE;
}
stack = (ILubyte*)ialloc(MAX_CODES + 1);
suffix = (ILubyte*)ialloc(MAX_CODES + 1);
prefix = (ILshort*)ialloc(sizeof(*prefix) * (MAX_CODES + 1));
if (!stack || !suffix || !prefix)
{
cleanUpGifLoadState();
return IL_FALSE;
}
curr_size = size + 1;
top_slot = 1 << curr_size;
clear = 1 << size;
ending = clear + 1;
slot = newcodes = ending + 1;
navail_bytes = nbits_left = 0;
oc = fc = 0;
sp = stack;
while ((c = get_next_code()) != ending && Read < Height) {
if (c == clear)
{
curr_size = size + 1;
slot = newcodes;
top_slot = 1 << curr_size;
while ((c = get_next_code()) == clear);
if (c == ending)
break;
if (c >= slot)
c = 0;
oc = fc = c;
if (DisposalMethod == 1 && !Gfx->Used && Gfx->Transparent == c && (Gfx->Packed & 0x1) != 0)
i++;
else if (i < Width)
DataPtr[i++] = c + PalOffset;
if (i == Width)
{
DataPtr += Stride;
i = 0;
Read += 1;
++j;
if (j >= Height) {
cleanUpGifLoadState();
return IL_FALSE;
}
}
}
else
{
code = c;
//BG-2007-01-10: several fixes for incomplete GIFs
if (code >= slot)
{
code = oc;
if (sp >= stack + MAX_CODES) {
cleanUpGifLoadState();
return IL_FALSE;
}
*sp++ = fc;
}
if (code >= MAX_CODES)
return IL_FALSE;
while (code >= newcodes)
{
if (sp >= stack + MAX_CODES)
{
cleanUpGifLoadState();
return IL_FALSE;
}
*sp++ = suffix[code];
code = prefix[code];
}
if (sp >= stack + MAX_CODES) {
cleanUpGifLoadState();
return IL_FALSE;
}
*sp++ = (ILbyte)code;
if (slot < top_slot)
{
fc = code;
suffix[slot] = fc;
prefix[slot++] = oc;
oc = c;
}
if (slot >= top_slot && curr_size < 12)
{
top_slot <<= 1;
curr_size++;
}
while (sp > stack)
{
sp--;
if (DisposalMethod == 1 && !Gfx->Used && Gfx->Transparent == *sp && (Gfx->Packed & 0x1) != 0)
i++;
else if (i < Width)
DataPtr[i++] = *sp + PalOffset;
if (i == Width)
{
i = 0;
Read += 1;
j = (j+1) % Height;
// Needs to start from Data, not Image->Data.
DataPtr = Data + j * Stride;
}
}
}
}
cleanUpGifLoadState();
return IL_TRUE;
}
/*From the GIF spec:
The rows of an Interlaced images are arranged in the following order:
Group 1 : Every 8th. row, starting with row 0. (Pass 1)
Group 2 : Every 8th. row, starting with row 4. (Pass 2)
Group 3 : Every 4th. row, starting with row 2. (Pass 3)
Group 4 : Every 2nd. row, starting with row 1. (Pass 4)
*/
ILboolean RemoveInterlace(ILimage *image)
{
ILubyte *NewData;
ILuint i, j = 0;
NewData = (ILubyte*)ialloc(image->SizeOfData);
if (NewData == NULL)
return IL_FALSE;
//changed 20041230: images with offsety != 0 were not
//deinterlaced correctly before...
for (i = 0; i < image->OffY; i++, j++) {
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
}
for (i = 0 + image->OffY; i < image->Height; i += 8, j++) {
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
}
for (i = 4 + image->OffY; i < image->Height; i += 8, j++) {
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
}
for (i = 2 + image->OffY; i < image->Height; i += 4, j++) {
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
}
for (i = 1 + image->OffY; i < image->Height; i += 2, j++) {
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
}
ifree(image->Data);
image->Data = NewData;
return IL_TRUE;
}
// Uses the transparent colour index to make an alpha channel.
ILboolean ConvertTransparent(ILimage *Image, ILubyte TransColour)
{
ILubyte *Palette;
ILuint i, j;
if (!Image->Pal.Palette || !Image->Pal.PalSize) {
ilSetError(IL_INTERNAL_ERROR);
return IL_FALSE;
}
Palette = (ILubyte*)ialloc(Image->Pal.PalSize / 3 * 4);
if (Palette == NULL)
return IL_FALSE;
for (i = 0, j = 0; i < Image->Pal.PalSize; i += 3, j += 4) {
Palette[j ] = Image->Pal.Palette[i ];
Palette[j+1] = Image->Pal.Palette[i+1];
Palette[j+2] = Image->Pal.Palette[i+2];
if (j/4 == TransColour)
Palette[j+3] = 0x00;
else
Palette[j+3] = 0xFF;
}
ifree(Image->Pal.Palette);
Image->Pal.Palette = Palette;
Image->Pal.PalSize = Image->Pal.PalSize / 3 * 4;
Image->Pal.PalType = IL_PAL_RGBA32;
return IL_TRUE;
}
#endif //IL_NO_GIF
+659
View File
@@ -0,0 +1,659 @@
//-----------------------------------------------------------------------------
//
// 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
+135
View File
@@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 10/10/2006
//
// Filename: src-IL/src/il_header.c
//
// Description: Generates a C-style header file for the current image.
//
//-----------------------------------------------------------------------------
#ifndef IL_NO_CHEAD
#include "il_internal.h"
// Just a guess...let's see what's purty!
#define MAX_LINE_WIDTH 14
//! Generates a C-style header file for the current image.
ILboolean ilSaveCHeader(ILconst_string FileName, char *InternalName)
{
FILE *HeadFile;
ILuint i = 0, j;
ILimage *TempImage;
const char *Name;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Name = iGetString(IL_CHEAD_HEADER_STRING);
if (Name == NULL)
Name = InternalName;
if (FileName == NULL || Name == NULL ||
ilStrLen(FileName) < 1 || ilCharStrLen(Name) < 1) {
ilSetError(IL_INVALID_VALUE);
return IL_FALSE;
}
if (!iCheckExtension(FileName, IL_TEXT("h"))) {
ilSetError(IL_INVALID_EXTENSION);
return IL_FALSE;
}
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
if (iCurImage->Bpc > 1) {
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
} else {
TempImage = iCurImage;
}
#ifndef _UNICODE
HeadFile = fopen(FileName, "wb");
#else
#ifdef _WIN32
HeadFile = _wfopen(FileName, L"rb");
#else
HeadFile = fopen((char*)FileName, "rb");
#endif
#endif//_UNICODE
if (HeadFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
fprintf(HeadFile, "//#include <il/il.h>\n");
fprintf(HeadFile, "// C Image Header:\n\n\n");
fprintf(HeadFile, "// IMAGE_BPP is in bytes per pixel, *not* bits\n");
fprintf(HeadFile, "#define IMAGE_BPP %d\n",iCurImage->Bpp);
fprintf(HeadFile, "#define IMAGE_WIDTH %d\n", iCurImage->Width);
fprintf(HeadFile, "#define IMAGE_HEIGHT %d\n", iCurImage->Height);
fprintf(HeadFile, "#define IMAGE_DEPTH %d\n\n\n", iCurImage->Depth);
fprintf(HeadFile, "#define IMAGE_TYPE 0x%X\n", iCurImage->Type);
fprintf(HeadFile, "#define IMAGE_FORMAT 0x%X\n\n\n", iCurImage->Format);
fprintf(HeadFile, "ILubyte %s[] = {\n", Name);
for (; i < TempImage->SizeOfData; i += MAX_LINE_WIDTH) {
fprintf(HeadFile, "\t");
for (j = 0; j < MAX_LINE_WIDTH; j++) {
if (i + j >= TempImage->SizeOfData - 1) {
fprintf(HeadFile, "%4d", TempImage->Data[i+j]);
break;
}
else
fprintf(HeadFile, "%4d,", TempImage->Data[i+j]);
}
fprintf(HeadFile, "\n");
}
if (TempImage != iCurImage)
ilCloseImage(TempImage);
fprintf(HeadFile, "};\n");
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE) {
fprintf(HeadFile, "\n\n");
fprintf(HeadFile, "#define IMAGE_PALSIZE %u\n\n", iCurImage->Pal.PalSize);
fprintf(HeadFile, "#define IMAGE_PALTYPE 0x%X\n\n", iCurImage->Pal.PalType);
fprintf(HeadFile, "ILubyte %sPal[] = {\n", Name);
for (i = 0; i < iCurImage->Pal.PalSize; i += MAX_LINE_WIDTH) {
fprintf(HeadFile, "\t");
for (j = 0; j < MAX_LINE_WIDTH; j++) {
if (i + j >= iCurImage->Pal.PalSize - 1) {
fprintf(HeadFile, " %4d", iCurImage->Pal.Palette[i+j]);
break;
}
else
fprintf(HeadFile, " %4d,", iCurImage->Pal.Palette[i+j]);
}
fprintf(HeadFile, "\n");
}
fprintf(HeadFile, "};\n");
}
fclose(HeadFile);
return IL_TRUE;
}
#endif//IL_NO_CHEAD
+362
View File
@@ -0,0 +1,362 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2001-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_icns.c
//
// Description: Reads from a Mac OS X icon (.icns) file.
// Credit for the format of .icns files goes to
// http://www.macdisk.com/maciconen.php3 and
// http://ezix.org/project/wiki/MacOSXIcons
//
//-----------------------------------------------------------------------------
//@TODO: Put ilSetError calls in when errors occur.
//@TODO: Should we clear the alpha channel just in case there isn't one in the file?
//@TODO: Checks on iread
#include "il_internal.h"
#ifndef IL_NO_ICNS
#include "il_icns.h"
#ifndef IL_NO_JP2
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "libjasper.lib")
#else
#pragma comment(lib, "libjasper-d.lib")
#endif
#endif
#endif
#endif//IL_NO_JP2
//! Checks if the file specified in FileName is a valid .icns file.
ILboolean ilIsValidIcns(ILconst_string FileName)
{
ILHANDLE IcnsFile;
ILboolean bIcns = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("icns"))) {
ilSetError(IL_INVALID_EXTENSION);
return bIcns;
}
IcnsFile = iopenr(FileName);
if (IcnsFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIcns;
}
bIcns = ilIsValidIcnsF(IcnsFile);
icloser(IcnsFile);
return bIcns;
}
//! Checks if the ILHANDLE contains a valid .icns file at the current position.
ILboolean ilIsValidIcnsF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidIcns();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .icns lump.
ILboolean ilIsValidIcnsL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidIcns();
}
// Internal function to get the header and check it.
ILboolean iIsValidIcns()
{
ICNSHEAD Header;
iread(Header.Head, 1, 4);
iseek(-4, IL_SEEK_CUR); // Go ahead and restore to previous state
if (strncmp(Header.Head, "icns", 4)) // First 4 bytes have to be 'icns'.
return IL_FALSE;
return IL_TRUE;
}
//! Reads an icon file.
ILboolean ilLoadIcns(ILconst_string FileName)
{
ILHANDLE IcnsFile;
ILboolean bIcns = IL_FALSE;
IcnsFile = iopenr(FileName);
if (IcnsFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIcns;
}
bIcns = ilLoadIcnsF(IcnsFile);
icloser(IcnsFile);
return bIcns;
}
//! Reads an already-opened icon file.
ILboolean ilLoadIcnsF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadIcnsInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains an icon.
ILboolean ilLoadIcnsL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadIcnsInternal();
}
// Internal function used to load the icon.
ILboolean iLoadIcnsInternal()
{
ICNSHEAD Header;
ICNSDATA Entry;
ILimage *Image = NULL;
ILboolean BaseCreated = IL_FALSE;
if (iCurImage == NULL)
{
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
iread(Header.Head, 4, 1);
Header.Size = GetBigInt();
if (strncmp(Header.Head, "icns", 4)) // First 4 bytes have to be 'icns'.
return IL_FALSE;
while ((ILint)itell() < Header.Size && !ieof())
{
iread(Entry.ID, 4, 1);
Entry.Size = GetBigInt();
if (!strncmp(Entry.ID, "it32", 4)) // 128x128 24-bit
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 128, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "t8mk", 4)) // 128x128 alpha mask
{
if (iIcnsReadData(&BaseCreated, IL_TRUE, 128, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "ih32", 4)) // 48x48 24-bit
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 48, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "h8mk", 4)) // 48x48 alpha mask
{
if (iIcnsReadData(&BaseCreated, IL_TRUE, 48, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "il32", 4)) // 32x32 24-bit
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 32, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "l8mk", 4)) // 32x32 alpha mask
{
if (iIcnsReadData(&BaseCreated, IL_TRUE, 32, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "is32", 4)) // 16x16 24-bit
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 16, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "s8mk", 4)) // 16x16 alpha mask
{
if (iIcnsReadData(&BaseCreated, IL_TRUE, 16, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
#ifndef IL_NO_JP2
else if (!strncmp(Entry.ID, "ic09", 4)) // 512x512 JPEG2000 encoded - Uses JasPer
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 512, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
else if (!strncmp(Entry.ID, "ic08", 4)) // 256x256 JPEG2000 encoded - Uses JasPer
{
if (iIcnsReadData(&BaseCreated, IL_FALSE, 256, &Entry, &Image) == IL_FALSE)
goto icns_error;
}
#endif//IL_NO_JP2
else // Not a valid format or one that we can use
{
iseek(Entry.Size - 8, IL_SEEK_CUR);
}
}
return ilFixImage();
icns_error:
return IL_FALSE;
}
ILboolean iIcnsReadData(ILboolean *BaseCreated, ILboolean IsAlpha, ILint Width, ICNSDATA *Entry, ILimage **Image)
{
ILint Position = 0, RLEPos = 0, Channel, i;
ILubyte RLERead, *Data = NULL;
ILimage *TempImage = NULL;
ILboolean ImageAlreadyExists = IL_FALSE;
// The .icns format stores the alpha and RGB as two separate images, so this
// checks to see if one exists for that particular size. Unfortunately,
// there is no guarantee that they are in any particular order.
if (*BaseCreated && iCurImage != NULL)
{
TempImage = iCurImage;
while (TempImage != NULL)
{
if ((ILuint)Width == TempImage->Width)
{
ImageAlreadyExists = IL_TRUE;
break;
}
TempImage = TempImage->Next;
}
}
Data = ialloc(Entry->Size - 8);
if (Data == NULL)
return IL_FALSE;
if (!ImageAlreadyExists)
{
if (!*BaseCreated) // Create base image
{
ilTexImage(Width, Width, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
*Image = iCurImage;
*BaseCreated = IL_TRUE;
}
else // Create next image in list
{
(*Image)->Next = ilNewImage(Width, Width, 1, 4, 1);
*Image = (*Image)->Next;
(*Image)->Format = IL_RGBA;
(*Image)->Origin = IL_ORIGIN_UPPER_LEFT;
}
TempImage = *Image;
}
if (IsAlpha) // Alpha is never compressed.
{
iread(Data, Entry->Size - 8, 1); // Size includes the header
if (Entry->Size - 8 != Width * Width)
{
ifree(Data);
return IL_FALSE;
}
for (i = 0; i < Width * Width; i++)
{
TempImage->Data[(i * 4) + 3] = Data[i];
}
}
else if (Width == 256 || Width == 512) // JPEG2000 encoded - uses JasPer
{
#ifndef IL_NO_JP2
iread(Data, Entry->Size - 8, 1); // Size includes the header
if (ilLoadJp2LInternal(Data, Entry->Size - 8, TempImage) == IL_FALSE)
{
ifree(Data);
ilSetError(IL_LIB_JP2_ERROR);
return IL_TRUE;
}
#else // Cannot handle this size.
ilSetError(IL_LIB_JP2_ERROR); //@TODO: Handle this better...just skip the data.
return IL_FALSE;
#endif//IL_NO_JP2
}
else // RGB data
{
iread(Data, Entry->Size - 8, 1); // Size includes the header
if (Width == 128)
RLEPos += 4; // There are an extra 4 bytes here of zeros.
//@TODO: Should we check to make sure they are all 0?
if (Entry->Size - 8 == Width * Width * 4) // Uncompressed
{
//memcpy(TempImage->Data, Data, Entry->Size);
for (i = 0; i < Width * Width; i++, Position += 4)
{
TempImage->Data[i * 4 + 0] = Data[Position+1];
TempImage->Data[i * 4 + 1] = Data[Position+2];
TempImage->Data[i * 4 + 2] = Data[Position+3];
}
}
else // RLE decoding
{
for (Channel = 0; Channel < 3; Channel++)
{
Position = 0;
while (Position < Width * Width)
{
RLERead = Data[RLEPos];
RLEPos++;
if (RLERead >= 128)
{
for (i = 0; i < RLERead - 125 && (Position + i) < Width * Width; i++)
{
TempImage->Data[Channel + (Position + i) * 4] = Data[RLEPos];
}
RLEPos++;
Position += RLERead - 125;
}
else
{
for (i = 0; i < RLERead + 1 && (Position + i) < Width * Width; i++)
{
TempImage->Data[Channel + (Position + i) * 4] = Data[RLEPos + i];
}
RLEPos += RLERead + 1;
Position += RLERead + 1;
}
}
}
}
}
ifree(Data);
return IL_TRUE;
}
#endif//IL_NO_ICNS
+674
View File
@@ -0,0 +1,674 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2001-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_icon.c
//
// Description: Reads from a Windows icon (.ico) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_ICO
#include "il_icon.h"
#ifndef IL_NO_PNG
#include <png.h>
#endif
//! Reads an icon file.
ILboolean ilLoadIcon(ILconst_string FileName)
{
ILHANDLE IconFile;
ILboolean bIcon = IL_FALSE;
IconFile = iopenr(FileName);
if (IconFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIcon;
}
bIcon = ilLoadIconF(IconFile);
icloser(IconFile);
return bIcon;
}
//! Reads an already-opened icon file.
ILboolean ilLoadIconF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadIconInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains an icon.
ILboolean ilLoadIconL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadIconInternal();
}
// Internal function used to load the icon.
ILboolean iLoadIconInternal()
{
ICODIR IconDir;
ICODIRENTRY *DirEntries = NULL;
ICOIMAGE *IconImages = NULL;
ILimage *Image = NULL;
ILint i;
ILuint Size, PadSize, ANDPadSize, j, k, l, m, x, w, CurAndByte, AndBytes;
ILboolean BaseCreated = IL_FALSE;
ILubyte PNGTest[3];
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
IconDir.Reserved = GetLittleShort();
IconDir.Type = GetLittleShort();
IconDir.Count = GetLittleShort();
if (ieof())
goto file_read_error;
DirEntries = (ICODIRENTRY*)ialloc(sizeof(ICODIRENTRY) * IconDir.Count);
IconImages = (ICOIMAGE*)ialloc(sizeof(ICOIMAGE) * IconDir.Count);
if (DirEntries == NULL || IconImages == NULL) {
ifree(DirEntries);
ifree(IconImages);
return IL_FALSE;
}
// Make it easier for file_read_error.
for (i = 0; i < IconDir.Count; i++)
imemclear(&IconImages[i], sizeof(ICOIMAGE));
for (i = 0; i < IconDir.Count; ++i) {
DirEntries[i].Width = (ILubyte)igetc();
DirEntries[i].Height = (ILubyte)igetc();
DirEntries[i].NumColours = (ILubyte)igetc();
DirEntries[i].Reserved = (ILubyte)igetc();
DirEntries[i].Planes = GetLittleShort();
DirEntries[i].Bpp = GetLittleShort();
DirEntries[i].SizeOfData = GetLittleUInt();
DirEntries[i].Offset = GetLittleUInt();
if (ieof())
goto file_read_error;
}
for (i = 0; i < IconDir.Count; i++) {
iseek(DirEntries[i].Offset, IL_SEEK_SET);
// 08-22-2008: Adding test for compressed PNG data
igetc(); // Skip the first character...seems to vary.
iread(PNGTest, 3, 1);
if (!strnicmp((char*)PNGTest, "PNG", 3)) // Characters 'P', 'N', 'G' for PNG header
{
#ifdef IL_NO_PNG
ilSetError(IL_FORMAT_NOT_SUPPORTED); // Cannot handle these without libpng.
goto file_read_error;
#else
iseek(DirEntries[i].Offset, IL_SEEK_SET);
if (!iLoadIconPNG(&IconImages[i]))
goto file_read_error;
#endif
}
else
{
// Need to go back the 4 bytes that were just read.
iseek(DirEntries[i].Offset, IL_SEEK_SET);
IconImages[i].Head.Size = GetLittleInt();
IconImages[i].Head.Width = GetLittleInt();
IconImages[i].Head.Height = GetLittleInt();
IconImages[i].Head.Planes = GetLittleShort();
IconImages[i].Head.BitCount = GetLittleShort();
IconImages[i].Head.Compression = GetLittleInt();
IconImages[i].Head.SizeImage = GetLittleInt();
IconImages[i].Head.XPixPerMeter = GetLittleInt();
IconImages[i].Head.YPixPerMeter = GetLittleInt();
IconImages[i].Head.ColourUsed = GetLittleInt();
IconImages[i].Head.ColourImportant = GetLittleInt();
if (ieof())
goto file_read_error;
if (IconImages[i].Head.BitCount < 8) {
if (IconImages[i].Head.ColourUsed == 0) {
switch (IconImages[i].Head.BitCount)
{
case 1:
IconImages[i].Head.ColourUsed = 2;
break;
case 4:
IconImages[i].Head.ColourUsed = 16;
break;
}
}
IconImages[i].Pal = (ILubyte*)ialloc(IconImages[i].Head.ColourUsed * 4);
if (IconImages[i].Pal == NULL)
goto file_read_error; // @TODO: Rename the label.
if (iread(IconImages[i].Pal, IconImages[i].Head.ColourUsed * 4, 1) != 1)
goto file_read_error;
}
else if (IconImages[i].Head.BitCount == 8) {
IconImages[i].Pal = (ILubyte*)ialloc(256 * 4);
if (IconImages[i].Pal == NULL)
goto file_read_error;
if (iread(IconImages[i].Pal, 1, 256 * 4) != 256*4)
goto file_read_error;
}
else {
IconImages[i].Pal = NULL;
}
PadSize = (4 - ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
ANDPadSize = (4 - ((IconImages[i].Head.Width + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
Size = ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8 + PadSize)
* (IconImages[i].Head.Height / 2);
IconImages[i].Data = (ILubyte*)ialloc(Size);
if (IconImages[i].Data == NULL)
goto file_read_error;
if (iread(IconImages[i].Data, 1, Size) != Size)
goto file_read_error;
Size = (((IconImages[i].Head.Width + 7) /8) + ANDPadSize) * (IconImages[i].Head.Height / 2);
IconImages[i].AND = (ILubyte*)ialloc(Size);
if (IconImages[i].AND == NULL)
goto file_read_error;
if (iread(IconImages[i].AND, 1, Size) != Size)
goto file_read_error;
}
}
for (i = 0; i < IconDir.Count; i++) {
if (IconImages[i].Head.BitCount != 1 && IconImages[i].Head.BitCount != 4 &&
IconImages[i].Head.BitCount != 8 && IconImages[i].Head.BitCount != 24 &&
IconImages[i].Head.BitCount != 32)
continue;
if (!BaseCreated) {
if (IconImages[i].Head.Size == 0) // PNG compressed icon
ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
else
ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
Image = iCurImage;
BaseCreated = IL_TRUE;
}
else {
if (IconImages[i].Head.Size == 0) // PNG compressed icon
Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, 1);
else
Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, 1);
Image = Image->Next;
Image->Format = IL_BGRA;
}
Image->Type = IL_UNSIGNED_BYTE;
j = 0; k = 0; l = 128; CurAndByte = 0; x = 0;
w = IconImages[i].Head.Width;
PadSize = (4 - ((w*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
ANDPadSize = (4 - ((w + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
AndBytes = (w + 7) / 8;
if (IconImages[i].Head.BitCount == 1) {
for (; j < Image->SizeOfData; k++) {
for (m = 128; m && x < w; m >>= 1) {
Image->Data[j] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4];
Image->Data[j+1] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 1];
Image->Data[j+2] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 2];
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
j += 4;
l >>= 1;
++x;
}
if (l == 0 || x == w) {
l = 128;
CurAndByte++;
if (x == w) {
CurAndByte += ANDPadSize;
k += PadSize;
x = 0;
}
}
}
}
else if (IconImages[i].Head.BitCount == 4) {
for (; j < Image->SizeOfData; j += 8, k++) {
Image->Data[j] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4];
Image->Data[j+1] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 1];
Image->Data[j+2] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 2];
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
l >>= 1;
++x;
if(x < w) {
Image->Data[j+4] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4];
Image->Data[j+5] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 1];
Image->Data[j+6] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 2];
Image->Data[j+7] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
l >>= 1;
++x;
}
else
j -= 4;
if (l == 0 || x == w) {
l = 128;
CurAndByte++;
if (x == w) {
CurAndByte += ANDPadSize;
k += PadSize;
x = 0;
}
}
}
}
else if (IconImages[i].Head.BitCount == 8) {
for (; j < Image->SizeOfData; j += 4, k++) {
Image->Data[j] = IconImages[i].Pal[IconImages[i].Data[k] * 4];
Image->Data[j+1] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 1];
Image->Data[j+2] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 2];
if (IconImages[i].AND == NULL) // PNG Palette
{
Image->Data[j+3] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 3];
}
else
{
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
}
l >>= 1;
++x;
if (l == 0 || x == w) {
l = 128;
CurAndByte++;
if (x == w) {
CurAndByte += ANDPadSize;
k += PadSize;
x = 0;
}
}
}
}
else if (IconImages[i].Head.BitCount == 24) {
for (; j < Image->SizeOfData; j += 4, k += 3) {
Image->Data[j] = IconImages[i].Data[k];
Image->Data[j+1] = IconImages[i].Data[k+1];
Image->Data[j+2] = IconImages[i].Data[k+2];
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
l >>= 1;
++x;
if (l == 0 || x == w) {
l = 128;
CurAndByte++;
if (x == w) {
CurAndByte += ANDPadSize;
k += PadSize;
x = 0;
}
}
}
}
else if (IconImages[i].Head.BitCount == 32) {
for (; j < Image->SizeOfData; j += 4, k += 4) {
Image->Data[j] = IconImages[i].Data[k];
Image->Data[j+1] = IconImages[i].Data[k+1];
Image->Data[j+2] = IconImages[i].Data[k+2];
//If the icon has 4 channels, use 4th channel for alpha...
//(for Windows XP style icons with true alpha channel
Image->Data[j+3] = IconImages[i].Data[k+3];
}
}
}
for (i = 0; i < IconDir.Count; i++) {
ifree(IconImages[i].Pal);
ifree(IconImages[i].Data);
ifree(IconImages[i].AND);
}
ifree(IconImages);
ifree(DirEntries);
return ilFixImage();
file_read_error:
if (IconImages) {
for (i = 0; i < IconDir.Count; i++) {
if (IconImages[i].Pal)
ifree(IconImages[i].Pal);
if (IconImages[i].Data)
ifree(IconImages[i].Data);
if (IconImages[i].AND)
ifree(IconImages[i].AND);
}
ifree(IconImages);
}
if (DirEntries)
ifree(DirEntries);
return IL_FALSE;
}
#ifndef IL_NO_PNG
// 08-22-2008: Copying a lot of this over from il_png.c for the moment.
// @TODO: Make .ico and .png use the same functions.
png_structp ico_png_ptr = NULL;
png_infop ico_info_ptr = NULL;
ILint ico_color_type;
#define GAMMA_CORRECTION 1.0 // Doesn't seem to be doing anything...
ILint ico_readpng_init();
ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent);
void ico_readpng_cleanup();
#endif
ILboolean iLoadIconPNG(ICOIMAGE *Icon)
{
#ifndef IL_NO_PNG
ILint init;
init = ico_readpng_init();
if (init)
return IL_FALSE;
if (!ico_readpng_get_image(Icon, GAMMA_CORRECTION))
return IL_FALSE;
ico_readpng_cleanup();
Icon->Head.Size = 0; // Easiest way to tell that this is a PNG.
// In the normal routine, it will not be 0.
return IL_TRUE;
#else
Icon;
return IL_FALSE;
#endif
}
#ifndef IL_NO_PNG
static void ico_png_read(png_structp png_ptr, png_bytep data, png_size_t length)
{
(void)png_ptr;
iread(data, 1, (ILuint)length);
return;
}
static void ico_png_error_func(png_structp png_ptr, png_const_charp message)
{
message;
ilSetError(IL_LIB_PNG_ERROR);
/*
changed 20040224
From the libpng docs:
"Errors handled through png_error() are fatal, meaning that png_error()
should never return to its caller. Currently, this is handled via
setjmp() and longjmp()"
*/
//return;
longjmp(png_jmpbuf(png_ptr), 1);
}
static void ico_png_warn_func(png_structp png_ptr, png_const_charp message)
{
png_ptr; message;
return;
}
ILint ico_readpng_init()
{
ico_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, ico_png_error_func, ico_png_warn_func);
if (!ico_png_ptr)
return 4; /* out of memory */
ico_info_ptr = png_create_info_struct(ico_png_ptr);
if (!ico_info_ptr) {
png_destroy_read_struct(&ico_png_ptr, NULL, NULL);
return 4; /* out of memory */
}
/* we could create a second info struct here (end_info), but it's only
* useful if we want to keep pre- and post-IDAT chunk info separated
* (mainly for PNG-aware image editors and converters) */
/* setjmp() must be called in every function that calls a PNG-reading
* libpng function */
if (setjmp(png_jmpbuf(ico_png_ptr))) {
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return 2;
}
png_set_read_fn(ico_png_ptr, NULL, ico_png_read);
png_set_error_fn(ico_png_ptr, NULL, ico_png_error_func, ico_png_warn_func);
// png_set_sig_bytes(ico_png_ptr, 8); /* we already read the 8 signature bytes */
png_read_info(ico_png_ptr, ico_info_ptr); /* read all PNG info up to image data */
/* alternatively, could make separate calls to png_get_image_width(),
* etc., but want bit_depth and ico_color_type for later [don't care about
* compression_type and filter_type => NULLs] */
/* OK, that's all we need for now; return happy */
return 0;
}
ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent)
{
png_bytepp row_pointers = NULL;
png_uint_32 width, height; // Changed the type to fix AMD64 bit problems, thanks to Eric Werness
ILdouble screen_gamma = 1.0;
ILuint i, channels;
ILenum format;
png_colorp palette;
ILint num_palette, j, bit_depth;
#if _WIN32 || DJGPP
ILdouble image_gamma;
#endif
display_exponent;
/* setjmp() must be called in every function that calls a PNG-reading
* libpng function */
if (setjmp(png_jmpbuf(ico_png_ptr))) {
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return IL_FALSE;
}
png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
&bit_depth, &ico_color_type, NULL, NULL, NULL);
// Expand low-bit-depth grayscale images to 8 bits
if (ico_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_gray_1_2_4_to_8(ico_png_ptr);
}
// Expand RGB images with transparency to full alpha channels
// so the data will be available as RGBA quartets.
// But don't expand paletted images, since we want alpha palettes!
if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS) && !(png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_PLTE)))
png_set_tRNS_to_alpha(ico_png_ptr);
//refresh information (added 20040224)
png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
&bit_depth, &ico_color_type, NULL, NULL, NULL);
if (bit_depth < 8) { // Expanded earlier for grayscale, now take care of palette and rgb
bit_depth = 8;
png_set_packing(ico_png_ptr);
}
// Perform gamma correction.
// @TODO: Determine if we should call png_set_gamma if image_gamma is 1.0.
#if _WIN32 || DJGPP
screen_gamma = 2.2;
if (png_get_gAMA(ico_png_ptr, ico_info_ptr, &image_gamma))
png_set_gamma(ico_png_ptr, screen_gamma, image_gamma);
#else
screen_gamma = screen_gamma;
#endif
//fix endianess
#ifdef __LITTLE_ENDIAN__
if (bit_depth == 16)
png_set_swap(ico_png_ptr);
#endif
png_read_update_info(ico_png_ptr, ico_info_ptr);
channels = (ILint)png_get_channels(ico_png_ptr, ico_info_ptr);
// added 20040224: update ico_color_type so that it has the correct value
// in iLoadPngInternal (globals rule...)
ico_color_type = png_get_color_type(ico_png_ptr, ico_info_ptr);
// Determine internal format
switch (ico_color_type)
{
case PNG_COLOR_TYPE_PALETTE:
Icon->Head.BitCount = 8;
format = IL_COLOUR_INDEX;
break;
case PNG_COLOR_TYPE_RGB:
Icon->Head.BitCount = 24;
format = IL_RGB;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
Icon->Head.BitCount = 32;
format = IL_RGBA;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return IL_FALSE;
}
if (ico_color_type & PNG_COLOR_MASK_COLOR)
png_set_bgr(ico_png_ptr);
Icon->Head.Width = width;
Icon->Head.Height = height;
Icon->Data = ialloc(width * height * Icon->Head.BitCount / 8);
if (Icon->Data == NULL)
{
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return IL_FALSE;
}
// Copy Palette
if (format == IL_COLOUR_INDEX)
{
int chans;
png_bytep trans = NULL;
int num_trans = -1;
if (!png_get_PLTE(ico_png_ptr, ico_info_ptr, &palette, &num_palette)) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return IL_FALSE;
}
chans = 4;
if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS)) {
png_get_tRNS(ico_png_ptr, ico_info_ptr, &trans, &num_trans, NULL);
}
// @TODO: We may need to keep track of the size of the palette.
Icon->Pal = (ILubyte*)ialloc(num_palette * chans);
for (j = 0; j < num_palette; ++j) {
Icon->Pal[chans*j + 0] = palette[j].blue;
Icon->Pal[chans*j + 1] = palette[j].green;
Icon->Pal[chans*j + 2] = palette[j].red;
if (trans != NULL) {
if (j < num_trans)
Icon->Pal[chans*j + 3] = trans[j];
else
Icon->Pal[chans*j + 3] = 255;
}
}
Icon->AND = NULL; // Transparency information is obtained from libpng.
}
//allocate row pointers
if ((row_pointers = (png_bytepp)ialloc(height * sizeof(png_bytep))) == NULL) {
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
return IL_FALSE;
}
// Set the individual row_pointers to point at the correct offsets
// Needs to be flipped
for (i = 0; i < height; i++)
row_pointers[height - i - 1] = Icon->Data + i * width * Icon->Head.BitCount / 8;
//row_pointers[i] = Icon->Data + i * width * Icon->Head.BitCount / 8;
// Now we can go ahead and just read the whole image
png_read_image(ico_png_ptr, row_pointers);
/* and we're done! (png_read_end() can be omitted if no processing of
* post-IDAT text/time/etc. is desired) */
//png_read_end(ico_png_ptr, NULL);
ifree(row_pointers);
return IL_TRUE;
}
void ico_readpng_cleanup()
{
if (ico_png_ptr && ico_info_ptr) {
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
ico_png_ptr = NULL;
ico_info_ptr = NULL;
}
}
#endif//IL_NO_PNG
#endif//IL_NO_ICO
+479
View File
@@ -0,0 +1,479 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Last modified: 03/0/2009
//
// Filename: src-IL/src/il_iff.c
//
// Description: Reads from an .iff file. Contribution from GAIA:
// http://gaia.fdi.ucm.es/grupo/projects/javy/devzone.html#DevILNotes.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_IFF
// Chunk type, data and functions:
typedef struct _iff_chunk {
ILuint tag;
ILuint start;
ILuint size;
ILuint chunkType;
} iff_chunk;
#define CHUNK_STACK_SIZE (32)
static iff_chunk chunkStack[CHUNK_STACK_SIZE];
static int chunkDepth = -1;
iff_chunk iff_begin_read_chunk();
void iff_end_read_chunk();
char *iff_read_data(int size);
ILboolean iLoadIffInternal(void);
/* Define the IFF tags we are looking for in the file. */
const ILuint IFF_TAG_CIMG = ('C' << 24) | ('I' << 16) | ('M' << 8) | ('G');
const ILuint IFF_TAG_FOR4 = ('F' << 24) | ('O' << 16) | ('R' << 8) | ('4');
const ILuint IFF_TAG_TBHD = ('T' << 24) | ('B' << 16) | ('H' << 8) | ('D');
const ILuint IFF_TAG_TBMP = ('T' << 24) | ('B' << 16) | ('M' << 8) | ('P');
const ILuint IFF_TAG_RGBA = ('R' << 24) | ('G' << 16) | ('B' << 8) | ('A');
const ILuint IFF_TAG_CLPZ = ('C' << 24) | ('L' << 16) | ('P' << 8) | ('Z');
const ILuint IFF_TAG_ESXY = ('E' << 24) | ('S' << 16) | ('X' << 8) | ('Y');
const ILuint IFF_TAG_ZBUF = ('Z' << 24) | ('B' << 16) | ('U' << 8) | ('F');
const ILuint IFF_TAG_BLUR = ('B' << 24) | ('L' << 16) | ('U' << 8) | ('R');
const ILuint IFF_TAG_BLRT = ('B' << 24) | ('L' << 16) | ('R' << 8) | ('T');
const ILuint IFF_TAG_HIST = ('H' << 24) | ('I' << 16) | ('S' << 8) | ('T');
// Flags
#define RGB_FLAG (1)
#define ALPHA_FLAG (2)
#define ZBUFFER_FLAG (4)
// Function for decompress the file.
char *iff_decompress_rle(ILuint numBytes, char *compressedData,
ILuint compressedDataSize,
ILuint *compressedStartIndex);
char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth);
char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
char *compressedData, ILuint compressedDataSize);
//! Reads an IFF file
ILboolean ilLoadIff(const ILstring FileName)
{
ILHANDLE iffFile;
ILboolean ret = IL_FALSE;
iffFile = iopenr(FileName);
if (iffFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return ret;
}
ret = ilLoadIffF(iffFile);
icloser(iffFile);
return ret;
}
//! Reads an already-opened IFF file
ILboolean ilLoadIffF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadIffInternal();
iseek(FirstPos, IL_SEEK_SET);
// Lbm files can have the .iff extension as well, so if Iff-loading failed,
// try to load it as a Lbm.
if (bRet == IL_FALSE)
return ilLoadIlbmF(File);
return bRet;
}
//! Reads from a memory "lump" that contains an IFF
ILboolean ilLoadIffL(const void *Lump, ILuint Size)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputLump(Lump, Size);
FirstPos = itell();
bRet = iLoadIffInternal();
iseek(FirstPos, IL_SEEK_SET);
// Lbm files can have the .iff extension as well, so if Iff-loading failed,
// try to load it as a Lbm.
if (bRet == IL_FALSE)
return ilLoadIlbmL(Lump, Size);
return IL_TRUE;
}
ILboolean iLoadIffInternal(void)
{
iff_chunk chunkInfo;
// -- Header info.
ILuint width, height;
ILuint flags, compress;
ILushort tiles;
ILenum format;
ILubyte bpp;
ILboolean tileImageDataFound;
// -- Initialize the top of the chunk stack.
chunkDepth = -1;
// -- File should begin with a FOR4 chunk of type CIMG
chunkInfo = iff_begin_read_chunk();
if (chunkInfo.chunkType != IFF_TAG_CIMG) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
/*
* Read the image header
* OK, we have a FOR4 of type CIMG, look for the following tags
* FVER
* TBHD bitmap header, definition of size, etc.
* AUTH
* DATE
*/
while (1) {
chunkInfo = iff_begin_read_chunk();
// -- Right now, the only info we need about the image is in TBHD
// -- so search this level until we find it.
if( chunkInfo.tag == IFF_TAG_TBHD ) {
// -- Header chunk found
width = GetBigUInt();
height = GetBigUInt();
GetBigShort(); // -- Don't support
GetBigShort(); // -- Don't support
flags = GetBigUInt();
GetBigShort(); // -- Don't support
tiles = GetBigUShort();
compress = GetBigUInt();
iff_end_read_chunk();
if( compress > 1 ) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
break;
} else
iff_end_read_chunk();
} /* END find TBHD while loop */
if (!(flags & RGB_FLAG)) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
if (flags & ALPHA_FLAG) {
format = IL_RGBA; bpp = 4;
} else {
format = IL_RGB; bpp = 3;
}
if (!ilTexImage(width, height, 1, bpp, format, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
tileImageDataFound = IL_FALSE;
while (!tileImageDataFound) {
ILuint tileImage;
ILuint tileZ;
chunkInfo = iff_begin_read_chunk();
/*
* OK, we have a FOR4 of type TBMP, (embedded FOR4)
* look for the following tags
* RGBA color data, RLE compressed tiles of 32 bbp data
* ZBUF z-buffer data, 32 bit float values
* CLPZ depth map specific, clipping planes, 2 float values
* ESXY depth map specific, eye x-y ratios, 2 float values
* HIST
* VERS
* FOR4 <size> BLUR (twice embedded FOR4)
*/
if (chunkInfo.chunkType != IFF_TAG_TBMP) {
iff_end_read_chunk();
continue;
}
tileImageDataFound = IL_TRUE;
tileImage = 0; // Si no RGBA, tileImage = tiles...
if (flags & ZBUFFER_FLAG)
tileZ = 0;
else
tileZ = tiles;
// Read tiles
while ( (tileImage < tiles) || (tileZ < tiles)) {
char *tileData;
ILushort x1, x2, y1, y2, tile_width, tile_height;
ILuint remainingDataSize;
ILushort tile_area;
ILuint tileCompressed;
chunkInfo = iff_begin_read_chunk();
if ((chunkInfo.tag != IFF_TAG_RGBA) && (chunkInfo.tag != IFF_TAG_ZBUF)) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
x1 = GetBigUShort(); y1 = GetBigUShort();
x2 = GetBigUShort(); y2 = GetBigUShort();
remainingDataSize = chunkInfo.size - 4*sizeof(ILushort);
tile_width = x2 - x1 + 1;
tile_height = y2 - y1 + 1;
tile_area = tile_width * tile_height;
if ((ILint)remainingDataSize >= (tile_width * tile_height * bpp))
tileCompressed = 0;
else
tileCompressed = 1;
if (chunkInfo.tag == IFF_TAG_RGBA) {
if (tileCompressed) {
char *data = iff_read_data(remainingDataSize);
if (data) {
tileData = iff_decompress_tile_rle(tile_width, tile_height,
bpp, data, remainingDataSize);
ifree(data);
}
} else {
tileData = iffReadUncompressedTile(tile_width, tile_height, bpp);
}
if (tileData) {
// Dump RGBA data to our data structure
ILushort i;
ILuint base;
base = bpp*(width * y1 + x1);
for (i = 0; i < tile_height; i++) {
memcpy(&iCurImage->Data[base + bpp*i*width],
&tileData[bpp*i*tile_width],
tile_width*bpp*sizeof(char));
}
ifree(tileData);
tileData = NULL;
iff_end_read_chunk();
tileImage++;
} else
return IL_FALSE;
} else if (chunkInfo.tag == IFF_TAG_ZBUF) {
tileZ++;
iff_end_read_chunk();
}
}
}
//ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); // Why was this here?
return ilFixImage();
}
/*
* IFF Chunking Routines.
*
*/
iff_chunk iff_begin_read_chunk()
{
chunkDepth++;
if (chunkDepth >= CHUNK_STACK_SIZE){
ilSetError(IL_STACK_OVERFLOW);
return chunkStack[0];
}
if (chunkDepth < 0) {
ilSetError(IL_STACK_UNDERFLOW);
return chunkStack[0];
}
chunkStack[chunkDepth].start = itell();
chunkStack[chunkDepth].tag = GetBigInt();
chunkStack[chunkDepth].size = GetBigInt();
if (chunkStack[chunkDepth].tag == IFF_TAG_FOR4) {
// -- We have a form, so read the form type tag as well.
chunkStack[chunkDepth].chunkType = GetBigInt();
} else {
chunkStack[chunkDepth].chunkType = 0;
}
return chunkStack[chunkDepth];
}
void iff_end_read_chunk()
{
ILuint end;
int part;
end = chunkStack[chunkDepth].start + chunkStack[chunkDepth].size + 8;
if (chunkStack[chunkDepth].chunkType != 0) {
end += 4;
}
// Add padding
part = end % 4;
if (part != 0) {
end += 4 - part;
}
iseek(end, IL_SEEK_SET);
chunkDepth--;
}
char * iff_read_data(int size)
{
char *buffer = ialloc(size * sizeof(char));
if (buffer == NULL)
return NULL;
if (iread(buffer, size*sizeof(char), 1) != 1) {
ifree(buffer);
return NULL;
}
return buffer;
}
/*
IFF decompress functions
*/
char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth)
{
char *data = NULL;
char *iniPixel;
char *finPixel;
int i, j;
int tam = width* height * depth * sizeof(char);
data = ialloc(tam);
if (data == NULL)
return NULL;
if (iread(data, tam, 1) != 1) {
ifree(data);
return NULL;
}
iniPixel = data;
for (i = 0; i < tam / depth; i++) {
finPixel = iniPixel + depth;
for (j = 0; j < (depth /2); j++) {
char aux;
aux = *iniPixel;
*(finPixel--) = *iniPixel;
*(iniPixel++) = aux;
}
}
return data;
}
char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
char *compressedData, ILuint compressedDataSize)
{
char *channels[4];
char *data;
int i, k, row, column;
ILuint compressedStart = 0;
// Decompress only in RGBA.
if (depth != 4) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return NULL;
}
for (i = depth-1; i >= 0; --i) {
channels[i] = iff_decompress_rle(width * height, compressedData,
compressedDataSize, &compressedStart);
if (channels[i] == NULL)
return NULL;
}
// Build all the channels from the decompression into an RGBA array.
data = ialloc(width * height * depth * sizeof(char));
if (data == NULL)
return NULL;
for (row = 0; row < height; row++)
for (column = 0; column < width; column++)
for (k = 0; k < depth; k++)
data[depth*(row*width + column) + k] =
channels[k][row*width + column];
ifree(channels[0]); ifree(channels[1]);
ifree(channels[2]); ifree(channels[3]);
return data;
}
char *iff_decompress_rle(ILuint numBytes, char *compressedData,
ILuint compressedDataSize,
ILuint *compressedStartIndex)
{
char *data = ialloc(numBytes * sizeof(char));
unsigned char nextChar, count;
int i;
ILuint byteCount = 0;
if (data == NULL)
return NULL;
memset(data, 0, numBytes*sizeof(char));
while (byteCount < numBytes) {
if (*compressedStartIndex >= compressedDataSize)
break;
nextChar = compressedData[*compressedStartIndex];
(*compressedStartIndex)++;
count = (nextChar & 0x7f) + 1;
if ((byteCount + count) > numBytes) break;
if (nextChar & 0x80) {
// Duplication run
nextChar = compressedData[*compressedStartIndex];
(*compressedStartIndex)++;
// assert ((byteCount + count) <= numBytes);
for (i = 0; i < count; i++) {
data[byteCount]= nextChar;
byteCount++;
}
} else {
// Verbatim run
for (i = 0; i < count; i++) {
data[byteCount] = compressedData[*compressedStartIndex];
(*compressedStartIndex)++;
byteCount++;
}
}
//assert(byteCount <= numBytes);
}
return data;
}
#endif //IL_NO_IFF
+658
View File
@@ -0,0 +1,658 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/08/2009
//
// Filename: src-IL/src/il_ilbm.c
//
// Description: IFF ILBM file (.iff, .ilbm, .lbm) functions
// IFF ILBM loader, ported from SDL_Image library (IMG_lbm.c)
// http://www.libsdl.org/cgi/viewvc.cgi/trunk/SDL_image/IMG_lbm.c?view=markup
//
// Handles Amiga ILBM and PBM images (including .lbm files saved by the PC
// version of dpaint)
// Handles ExtraHalfBright and HAM images.
//
// Adapted from SDL_image by Ben Campbell (http://scumways.com) 2009-02-23
//
//-----------------------------------------------------------------------------
// TODO: sort out the .iff extension confusion: .iff is currently handled by
// Maya IFF/CIMG handler (il_iff.c), but it should defer to this one if
// fileturns out to be an ILBM. I think the best solution would be to
// rename the IFF handler to CIMG, and create a new iff handler to act as
// a front end, passing off to either il_ilbm or il_cimg...
// For now, this handler only handles .lbm and .ilbm extenstions (but
// traditionally, .iff is more common).
#include "il_internal.h"
#ifndef IL_NO_ILBM
#include <stdlib.h>
ILboolean iIsValidIlbm(void);
ILboolean iLoadIlbmInternal(void);
static ILboolean load_ilbm(void);
static int isLBM(void );
ILboolean ilIsValidIlbm(ILconst_string FileName)
{
ILHANDLE f;
ILboolean bIlbm = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("iff")) &&
!iCheckExtension(FileName, IL_TEXT("ilbm")) &&
!iCheckExtension(FileName, IL_TEXT("lbm")) &&
!iCheckExtension(FileName, IL_TEXT("ham")) ) {
ilSetError(IL_INVALID_EXTENSION);
return bIlbm;
}
f = iopenr(FileName);
if (f == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIlbm;
}
bIlbm = ilIsValidIlbmF(f);
icloser(f);
return bIlbm;
}
ILboolean ilIsValidIlbmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidIlbm();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
ILboolean ilIsValidIlbmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidIlbm();
}
ILboolean iIsValidIlbm()
{
return isLBM() ? IL_TRUE:IL_FALSE;
}
// Reads a file
ILboolean ilLoadIlbm(ILconst_string FileName)
{
ILHANDLE IlbmFile;
ILboolean bIlbm = IL_FALSE;
IlbmFile = iopenr(FileName);
if (IlbmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIlbm;
}
bIlbm = ilLoadIlbmF(IlbmFile);
icloser(IlbmFile);
return bIlbm;
}
// Reads an already-opened file
ILboolean ilLoadIlbmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadIlbmInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
// Reads from a memory "lump"
ILboolean ilLoadIlbmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadIlbmInternal();
}
ILboolean iLoadIlbmInternal()
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iIsValidIlbm()) {
ilSetError(IL_INVALID_VALUE);
return IL_FALSE;
}
if (!load_ilbm() )
{
return IL_FALSE;
}
return ilFixImage();
}
/* some defines to allow us to use the SDL_image source in as unmodified form
* as possible, so it'll be easy to diff. Yes, it does look evil, but it's
* really just some local syntactic sugar - most things correspond directly
* to DevIL calls. It's not that bad, honest ;-)
* This will make it _much_ easier to track changes to SDL_Image.
* - BenC
*/
#define Sint8 ILbyte
#define Sint16 ILshort
#define Sint32 ILint
#define Uint8 ILubyte
#define Uint16 ILushort
#define Uint32 ILuint
#define SDL_RWops void
#define SDL_RWtell(s) itell()
#define SDL_RWread(s,ptr,size,nmemb) iread(ptr,size,nmemb)
#define SDL_RWseek(s,offset,whence) iseek(offset, IL_ ## whence)
/* use different function names to avoid any possible symbol contamination
* (user might also be linking with libSDL) */
#define SDL_SwapBE32(i) iSDL_SwapBE32(i)
#define SDL_SwapBE16(s) iSDL_SwapBE16(s)
static Uint16 iSDL_SwapBE16( Uint16 s )
{ Uint16 foo = s; iSwapUShort(&foo); return foo; }
static Uint32 iSDL_SwapBE32( Uint32 i )
{ Uint32 foo = i; iSwapUInt(&foo); return foo; }
/* rest of this file is as unchanged as possible from IMG_lbm.c - BenC */
/***************************************************************************/
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
in December 2002.
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
(http://www.multimania.com/mavati) in December 2003.
Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
Buffer overflow fix in RLE decompression by David Raulo in January 2008.
*/
#define MAXCOLORS 256
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
/* TODO: SDL_Image seems to get away without any struct
* packing... should it be added? */
typedef struct
{
Uint16 w, h; /* width & height of the bitmap in pixels */
Sint16 x, y; /* screen coordinates of the bitmap */
Uint8 planes; /* number of planes of the bitmap */
Uint8 mask; /* mask type ( 0 => no mask ) */
Uint8 tcomp; /* compression type */
Uint8 pad1; /* dummy value, for padding */
Uint16 tcolor; /* transparent color */
Uint8 xAspect, /* pixel aspect ratio */
yAspect;
Sint16 Lpage; /* width of the screen in pixels */
Sint16 Hpage; /* height of the screen in pixels */
} BMHD;
static int isLBM()
{
SDL_RWops* src = 0;
int start;
int is_LBM;
Uint8 magic[4+4+4];
start = SDL_RWtell(src);
is_LBM = 0;
if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
{
if ( !memcmp( magic, "FORM", 4 ) &&
( !memcmp( magic + 8, "PBM ", 4 ) ||
!memcmp( magic + 8, "ILBM", 4 ) ) )
{
is_LBM = 1;
}
}
SDL_RWseek(src, start, SEEK_SET);
return( is_LBM );
}
static ILboolean load_ilbm(void)
{
SDL_RWops* src = 0;
struct { Uint8 r; Uint8 g; Uint8 b; } scratch_pal[MAXCOLORS];
ILenum format; /* IL_RGB (ham or 24bit) or IL_COLOUR_INDEX */
int start;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
Uint32 size, bytesloaded, nbcolors;
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
Uint32 width;
BMHD bmhd;
char *error;
Uint8 flagHAM,flagEHB;
error = NULL;
MiniBuf = NULL;
start = SDL_RWtell(src);
if ( !SDL_RWread( src, id, 4, 1 ) )
{
error="error reading IFF chunk";
goto done;
}
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
{
error="error reading IFF chunk size";
goto done;
}
/* As size is not used here, no need to swap it */
if ( memcmp( id, "FORM", 4 ) != 0 )
{
ilSetError(IL_INVALID_FILE_HEADER);
error="not a IFF file";
goto done;
}
if ( !SDL_RWread( src, id, 4, 1 ) )
{
error="error reading IFF chunk";
goto done;
}
pbm = 0;
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
else if ( memcmp( id, "ILBM", 4 ) )
{
ilSetError(IL_INVALID_FILE_HEADER);
error="not a IFF picture";
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
flagHAM = 0;
flagEHB = 0;
while ( memcmp( id, "BODY", 4 ) != 0 )
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
error="error reading IFF chunk";
goto done;
}
if ( !SDL_RWread( src, &size, 4, 1 ) )
{
error="error reading IFF chunk size";
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
error="error reading BMHD chunk";
goto done;
}
bytesloaded = sizeof( BMHD );
bmhd.w = SDL_SwapBE16( bmhd.w );
bmhd.h = SDL_SwapBE16( bmhd.h );
bmhd.x = SDL_SwapBE16( bmhd.x );
bmhd.y = SDL_SwapBE16( bmhd.y );
bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
bmhd.Lpage = SDL_SwapBE16( bmhd.Lpage );
bmhd.Hpage = SDL_SwapBE16( bmhd.Hpage );
}
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
error="error reading CMAP chunk";
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode */
{
Uint32 viewmodes;
if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
{
error="error reading CAMG chunk";
goto done;
}
bytesloaded = size;
viewmodes = SDL_SwapBE32( viewmodes );
if ( viewmodes & 0x0800 )
flagHAM = 1;
if ( viewmodes & 0x0080 )
flagEHB = 1;
}
if ( memcmp( id, "BODY", 4 ) )
{
if ( size & 1 ) ++size; /* padding ! */
size -= bytesloaded;
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
}
}
/* compute some usefull values, based on the bitmap header */
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
nbplanes = bmhd.planes;
if ( pbm ) /* File format : 'Packed Bitmap' */
{
bytesperline *= 8;
nbplanes = 1;
}
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
ilSetError( IL_OUT_OF_MEMORY );
error="no enough memory for temporary buffer";
goto done;
}
if( bmhd.planes==24 || flagHAM==1 ) {
format = IL_BGR;
} else {
format = IL_COLOUR_INDEX;
}
if( !ilTexImage( width, bmhd.h, 1, (format==IL_COLOUR_INDEX)?1:3, format, IL_UNSIGNED_BYTE, NULL ) )
goto done;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
#if 0 /* No transparent colour support in DevIL? (TODO: confirm) */
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
#endif
/* Update palette informations */
/* There is no palette in 24 bits ILBM file */
if ( nbcolors>0 && flagHAM==0 )
{
int nbrcolorsfinal = 1 << nbplanes;
ptr = &colormap[0];
for ( i=0; i<nbcolors; i++ )
{
scratch_pal[i].r = *ptr++;
scratch_pal[i].g = *ptr++;
scratch_pal[i].b = *ptr++;
}
/* Amiga EHB mode (Extra-Half-Bright) */
/* 6 bitplanes mode with a 32 colors palette */
/* The 32 last colors are the same but divided by 2 */
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
nbcolors = 64;
ptr = &colormap[0];
for ( i=32; i<64; i++ )
{
scratch_pal[i].r = (*ptr++)/2;
scratch_pal[i].g = (*ptr++)/2;
scratch_pal[i].b = (*ptr++)/2;
}
}
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
{
scratch_pal[i].r = scratch_pal[i%nbcolors].r;
scratch_pal[i].g = scratch_pal[i%nbcolors].g;
scratch_pal[i].b = scratch_pal[i%nbcolors].b;
}
if ( !pbm )
ilRegisterPal( scratch_pal, 3*nbrcolorsfinal, IL_PAL_RGB24 );
}
/* Get the bitmap */
for ( h=0; h < bmhd.h; h++ )
{
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
{
ptr = MiniBuf + ( plane * bytesperline );
remainingbytes = bytesperline;
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
{
do
{
if ( !SDL_RWread( src, &count, 1, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
if ( count & 0x80 )
{
count ^= 0xFF;
count += 2; /* now it */
if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) )
{
if( count>remainingbytes)
ilSetError(IL_ILLEGAL_FILE_VALUE );
error="error reading BODY chunk";
goto done;
}
memset( ptr, color, count );
}
else
{
++count;
if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
{
if( count>remainingbytes)
ilSetError(IL_ILLEGAL_FILE_VALUE );
error="error reading BODY chunk";
goto done;
}
}
ptr += count;
remainingbytes -= count;
} while ( remainingbytes > 0 );
}
else
{
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
}
/* One line has been read, store it ! */
ptr = ilGetData();
if ( nbplanes==24 || flagHAM==1 )
ptr += h * width * 3;
else
ptr += h * width;
if ( pbm ) /* File format : 'Packed Bitmap' */
{
memcpy( ptr, MiniBuf, width );
}
else /* We have to un-interlace the bits ! */
{
if ( nbplanes!=24 && flagHAM==0 )
{
size = ( width + 7 ) / 8;
for ( i=0; i < size; i++ )
{
memset( ptr, 0, 8 );
for ( plane=0; plane < nbplanes; plane++ )
{
color = *( MiniBuf + i + ( plane * bytesperline ) );
msk = 0x80;
for ( j=0; j<8; j++ )
{
if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
else ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
msk >>= 1;
}
}
ptr += 8;
}
}
else
{
Uint32 finalcolor = 0;
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
for ( i=0; i<width; i=i+8 )
{
Uint8 maskBit = 0x80;
for ( j=0; j<8; j++ )
{
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
pixelcolor = pixelcolor | maskColor;
maskColor = maskColor<<1;
}
/* HAM : 12 bits RGB image (4 bits per color component) */
/* HAM8 : 18 bits RGB image (6 bits per color component) */
if ( flagHAM )
{
switch( pixelcolor>>(nbplanes-2) )
{
case 0: /* take direct color from palette */
finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
break;
case 1: /* modify only blue component */
finalcolor = finalcolor&0x00FFFF;
finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
break;
case 2: /* modify only red component */
finalcolor = finalcolor&0xFFFF00;
finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
break;
case 3: /* modify only green component */
finalcolor = finalcolor&0xFF00FF;
finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
break;
}
}
else
{
finalcolor = pixelcolor;
}
#if defined( __LITTLE_ENDIAN__ )
{
*ptr++ = (Uint8)(finalcolor>>16);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor);
}
#else
{
*ptr++ = (Uint8)(finalcolor);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor>>16);
}
#endif
maskBit = maskBit>>1;
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
if ( error )
{
/* fprintf(stderr,"il_ilbm.c: '%s'\n",error); */
return IL_FALSE;
}
return IL_TRUE;
}
#endif//IL_NO_ILBM
+271
View File
@@ -0,0 +1,271 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 11/08/2008
//
// Filename: src-IL/src/il_internal.c
//
// Description: Internal stuff for DevIL
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include <string.h>
#include <stdlib.h>
ILimage *iCurImage = NULL;
/* Siigron: added this for Linux... a #define should work, but for some reason
it doesn't (anyone who knows why?) */
#if !_WIN32 || (_WIN32 && __GNUC__) // Cygwin
int stricmp(const char *src1, const char *src2)
{
return strcasecmp(src1, src2);
}
int strnicmp(const char *src1, const char *src2, size_t max)
{
return strncasecmp(src1, src2, max);
}
#elif _WIN32_WCE
int stricmp(const char *src1, const char *src2)
{
return _stricmp(src1, src2);
}
int strnicmp(const char *src1, const char *src2, size_t max)
{
return _strnicmp(src1, src2, max);
}
#endif /* _WIN32 */
#ifdef _WIN32_WCE
char *strdup(const char *src)
{
return _strdup(src);
}
#endif//_WIN32_WCE
#ifdef _UNICODE
int iStrCmp(ILconst_string src1, ILconst_string src2)
{
return wcsicmp(src1, src2);
}
#else
int iStrCmp(ILconst_string src1, ILconst_string src2)
{
return stricmp(src1, src2);
}
#endif
//! Glut's portability.txt says to use this...
ILstring ilStrDup(ILconst_string Str)
{
ILstring copy;
copy = (ILstring)ialloc((ilStrLen(Str) + 1) * sizeof(ILchar));
if (copy == NULL)
return NULL;
iStrCpy(copy, Str);
return copy;
}
// Because MSVC++'s version is too stupid to check for NULL...
ILuint ilStrLen(ILconst_string Str)
{
ILconst_string eos = Str;
if (Str == NULL)
return 0;
while (*eos++);
return((int)(eos - Str - 1));
}
// Because MSVC++'s version is too stupid to check for NULL...
// Passing NULL to strlen will definitely cause a crash.
ILuint ilCharStrLen(const char *Str)
{
const char *eos = Str;
if (Str == NULL)
return 0;
while (*eos++);
return((int)(eos - Str - 1));
}
// Simple function to test if a filename has a given extension, disregarding case
ILboolean iCheckExtension(ILconst_string Arg, ILconst_string Ext)
{
ILboolean PeriodFound = IL_FALSE;
ILint i, Len;
ILstring Argu = (ILstring)Arg;
if (Arg == NULL || Ext == NULL || !ilStrLen(Arg) || !ilStrLen(Ext)) // if not a good filename/extension, exit early
return IL_FALSE;
Len = ilStrLen(Arg);
Argu += Len; // start at the end
for (i = Len; i >= 0; i--) {
if (*Argu == '.') { // try to find a period
PeriodFound = IL_TRUE;
break;
}
Argu--;
}
if (!PeriodFound) // if no period, no extension
return IL_FALSE;
if (!iStrCmp(Argu+1, Ext)) // extension and ext match?
return IL_TRUE;
return IL_FALSE; // if all else fails, return IL_FALSE
}
ILstring iGetExtension(ILconst_string FileName)
{
ILboolean PeriodFound = IL_FALSE;
ILstring Ext = (ILstring)FileName;
ILint i, Len = ilStrLen(FileName);
if (FileName == NULL || !Len) // if not a good filename/extension, exit early
return NULL;
Ext += Len; // start at the end
for (i = Len; i >= 0; i--) {
if (*Ext == '.') { // try to find a period
PeriodFound = IL_TRUE;
break;
}
Ext--;
}
if (!PeriodFound) // if no period, no extension
return NULL;
return Ext+1;
}
// Checks if the file exists
ILboolean iFileExists(ILconst_string FileName)
{
#if (!defined(_UNICODE) || !defined(_WIN32))
FILE *CheckFile = fopen(FileName, "rb");
#else // Windows uses _wfopen instead.
FILE *CheckFile = _wfopen(FileName, L"rb");
#endif//_UNICODE
if (CheckFile) {
fclose(CheckFile);
return IL_TRUE;
}
return IL_FALSE;
}
// Last time I tried, MSVC++'s fgets() was really really screwy
ILbyte *iFgets(char *buffer, ILuint maxlen)
{
ILuint counter = 0;
ILint temp = '\0';
while ((temp = igetc()) && temp != '\n' && temp != IL_EOF && counter < maxlen) {
buffer[counter] = temp;
counter++;
}
buffer[counter] = '\0';
if (temp == IL_EOF && counter == 0) // Only return NULL if no data was "got".
return NULL;
return (ILbyte*)buffer;
}
// A fast integer squareroot, completely accurate for x < 289.
// Taken from http://atoms.org.uk/sqrt/
// There is also a version that is accurate for all integers
// < 2^31, if we should need it
static int table[] = {
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102,
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132,
133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145,
146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157,
158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178,
179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188,
189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197,
198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206,
207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215,
215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223,
224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231,
231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246,
246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253,
253, 254, 254, 255
};
int iSqrt(int x) {
if (x >= 0x10000) {
if (x >= 0x1000000) {
if (x >= 0x10000000) {
if (x >= 0x40000000) {
return (table[x >> 24] << 8);
} else {
return (table[x >> 22] << 7);
}
} else if (x >= 0x4000000) {
return (table[x >> 20] << 6);
} else {
return (table[x >> 18] << 5);
}
} else if (x >= 0x100000) {
if (x >= 0x400000) {
return (table[x >> 16] << 4);
} else {
return (table[x >> 14] << 3);
}
} else if (x >= 0x40000) {
return (table[x >> 12] << 2);
} else {
return (table[x >> 10] << 1);
}
} else if (x >= 0x100) {
if (x >= 0x1000) {
if (x >= 0x4000) {
return (table[x >> 8]);
} else {
return (table[x >> 6] >> 1);
}
} else if (x >= 0x400) {
return (table[x >> 4] >> 2);
} else {
return (table[x >> 2] >> 3);
}
} else if (x >= 0) {
return table[x] >> 4;
}
//hm, x was negative....
return -1;
}
File diff suppressed because it is too large Load Diff
+401
View File
@@ -0,0 +1,401 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/04/2009
//
// Filename: src-IL/src/il_iwi.c
//
// Description: Reads from an Infinity Ward Image (.iwi) file from Call of Duty.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_IWI
#include "il_dds.h"
typedef struct IWIHEAD
{
ILuint Signature;
ILubyte Format;
ILubyte Flags;
ILushort Width;
ILushort Height;
} IWIHEAD;
#define IWI_ARGB8 0x01
#define IWI_RGB8 0x02
#define IWI_ARGB4 0x03
#define IWI_A8 0x04
#define IWI_JPG 0x07
#define IWI_DXT1 0x0B
#define IWI_DXT3 0x0C
#define IWI_DXT5 0x0D
ILboolean iIsValidIwi(void);
ILboolean iCheckIwi(IWIHEAD *Header);
ILboolean iLoadIwiInternal(void);
ILboolean IwiInitMipmaps(ILimage *BaseImage, ILuint *NumMips);
ILboolean IwiReadImage(ILimage *BaseImage, IWIHEAD *Header, ILuint NumMips);
ILenum IwiGetFormat(ILubyte Format, ILubyte *Bpp);
//! Checks if the file specified in FileName is a valid IWI file.
ILboolean ilIsValidIwi(ILconst_string FileName)
{
ILHANDLE IwiFile;
ILboolean bIwi = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("iwi"))) {
ilSetError(IL_INVALID_EXTENSION);
return bIwi;
}
IwiFile = iopenr(FileName);
if (IwiFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIwi;
}
bIwi = ilIsValidIwiF(IwiFile);
icloser(IwiFile);
return bIwi;
}
//! Checks if the ILHANDLE contains a valid IWI file at the current position.
ILboolean ilIsValidIwiF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidIwi();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid IWI lump.
ILboolean ilIsValidIwiL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidIwi();
}
// Internal function used to get the IWI header from the current file.
ILboolean iGetIwiHead(IWIHEAD *Header)
{
Header->Signature = GetLittleUInt();
Header->Format = igetc();
Header->Flags = igetc(); //@TODO: Find out what the flags mean.
Header->Width = GetLittleUShort();
Header->Height = GetLittleUShort();
// @TODO: Find out what is in the rest of the header.
iseek(18, IL_SEEK_CUR);
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidIwi(void)
{
IWIHEAD Header;
ILuint Pos = itell();
if (!iGetIwiHead(&Header))
return IL_FALSE;
// The length of the header varies, so we just go back to the original position.
iseek(Pos, IL_SEEK_CUR);
return iCheckIwi(&Header);
}
// Internal function used to check if the HEADER is a valid IWI header.
ILboolean iCheckIwi(IWIHEAD *Header)
{
if (Header->Signature != 0x06695749 && Header->Signature != 0x05695749) // 'IWi-' (version 6, and version 5 is the second).
return IL_FALSE;
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
// DXT images must have power-of-2 dimensions.
if (Header->Format == IWI_DXT1 || Header->Format == IWI_DXT3 || Header->Format == IWI_DXT5)
if (Header->Width != ilNextPower2(Header->Width) || Header->Height != ilNextPower2(Header->Height))
return IL_FALSE;
// 0x0B, 0x0C and 0x0D are DXT formats.
if (Header->Format != IWI_ARGB4 && Header->Format != IWI_RGB8 && Header->Format != IWI_ARGB8 && Header->Format != IWI_A8
&& Header->Format != IWI_DXT1 && Header->Format != IWI_DXT3 && Header->Format != IWI_DXT5)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a IWI file
ILboolean ilLoadIwi(ILconst_string FileName)
{
ILHANDLE IwiFile;
ILboolean bIwi = IL_FALSE;
IwiFile = iopenr(FileName);
if (IwiFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bIwi;
}
bIwi = ilLoadIwiF(IwiFile);
icloser(IwiFile);
return bIwi;
}
//! Reads an already-opened IWI file
ILboolean ilLoadIwiF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadIwiInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a IWI
ILboolean ilLoadIwiL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadIwiInternal();
}
// Internal function used to load the IWI.
ILboolean iLoadIwiInternal(void)
{
IWIHEAD Header;
ILuint NumMips = 0;
ILboolean HasMipmaps = IL_TRUE;
ILenum Format;
ILubyte Bpp;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
// Read the header and check it.
if (!iGetIwiHead(&Header))
return IL_FALSE;
if (!iCheckIwi(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// From a post by Pointy on http://iwnation.com/forums/index.php?showtopic=27903,
// flags ending with 0x3 have no mipmaps.
HasMipmaps = ((Header.Flags & 0x03) == 0x03) ? IL_FALSE : IL_TRUE;
// Create the image, then create the mipmaps, then finally read the image.
Format = IwiGetFormat(Header.Format, &Bpp);
if (!ilTexImage(Header.Width, Header.Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (HasMipmaps)
if (!IwiInitMipmaps(iCurImage, &NumMips))
return IL_FALSE;
if (!IwiReadImage(iCurImage, &Header, NumMips))
return IL_FALSE;
return ilFixImage();
}
// Helper function to convert IWI formats to DevIL formats and Bpp.
ILenum IwiGetFormat(ILubyte Format, ILubyte *Bpp)
{
switch (Format)
{
case IWI_ARGB8:
*Bpp = 4;
return IL_BGRA;
case IWI_RGB8:
*Bpp = 3;
return IL_BGR;
case IWI_ARGB4:
*Bpp = 4;
return IL_BGRA;
case IWI_A8:
*Bpp = 1;
return IL_ALPHA;
case IWI_DXT1:
*Bpp = 4;
return IL_RGBA;
case IWI_DXT3:
*Bpp = 4;
return IL_RGBA;
case IWI_DXT5:
*Bpp = 4;
return IL_RGBA;
}
return 0; // Will never reach this.
}
// Function to intialize the mipmaps and determine the number of mipmaps.
ILboolean IwiInitMipmaps(ILimage *BaseImage, ILuint *NumMips)
{
ILimage *Image;
ILuint Width, Height, Mipmap;
Image = BaseImage;
Width = BaseImage->Width; Height = BaseImage->Height;
Image->Origin = IL_ORIGIN_UPPER_LEFT;
for (Mipmap = 0; Width != 1 && Height != 1; Mipmap++) {
// 1 is the smallest dimension possible.
Width = (Width >> 1) == 0 ? 1 : (Width >> 1);
Height = (Height >> 1) == 0 ? 1 : (Height >> 1);
Image->Mipmaps = ilNewImageFull(Width, Height, 1, BaseImage->Bpp, BaseImage->Format, BaseImage->Type, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
Image = Image->Mipmaps;
// ilNewImage does not set these.
Image->Format = BaseImage->Format;
Image->Type = BaseImage->Type;
// The origin is in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
}
*NumMips = Mipmap;
return IL_TRUE;
}
ILboolean IwiReadImage(ILimage *BaseImage, IWIHEAD *Header, ILuint NumMips)
{
ILimage *Image;
ILuint SizeOfData;
ILubyte *CompData = NULL;
ILint i, j, k, m;
for (i = NumMips; i >= 0; i--) {
Image = BaseImage;
// Go to the ith mipmap level.
// The mipmaps go from smallest to the largest.
for (j = 0; j < i; j++)
Image = Image->Mipmaps;
switch (Header->Format)
{
case IWI_ARGB8: // These are all
case IWI_RGB8: // uncompressed data,
case IWI_A8: // so just read it.
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
return IL_FALSE;
break;
case IWI_ARGB4: //@TODO: Find some test images for this.
// Data is in ARGB4 format - 4 bits per component.
SizeOfData = Image->Width * Image->Height * 2;
CompData = ialloc(SizeOfData); // Not really compressed - just in ARGB4 format.
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
ifree(CompData);
return IL_FALSE;
}
for (k = 0, m = 0; k < (ILint)Image->SizeOfData; k += 4, m += 2) {
// @TODO: Double the image data into the low and high nibbles for a better range of values.
Image->Data[k+0] = CompData[m] & 0xF0;
Image->Data[k+1] = (CompData[m] & 0x0F) << 4;
Image->Data[k+2] = CompData[m+1] & 0xF0;
Image->Data[k+3] = (CompData[m+1] & 0x0F) << 4;
}
break;
case IWI_DXT1:
// DXT1 data has at least 8 bytes, even for one pixel.
SizeOfData = IL_MAX(Image->Width * Image->Height / 2, 8);
CompData = ialloc(SizeOfData); // Gives a 6:1 compression ratio (or 8:1 for DXT1 with alpha)
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
ifree(CompData);
return IL_FALSE;
}
// Decompress the DXT1 data into Image (ith mipmap).
if (!DecompressDXT1(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
// Keep a copy of the DXTC data if the user wants it.
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = SizeOfData;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT1;
CompData = NULL;
}
break;
case IWI_DXT3:
// DXT3 data has at least 16 bytes, even for one pixel.
SizeOfData = IL_MAX(Image->Width * Image->Height, 16);
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
ifree(CompData);
return IL_FALSE;
}
// Decompress the DXT3 data into Image (ith mipmap).
if (!DecompressDXT3(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
break;
case IWI_DXT5:
// DXT5 data has at least 16 bytes, even for one pixel.
SizeOfData = IL_MAX(Image->Width * Image->Height, 16);
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
ifree(CompData);
return IL_FALSE;
}
// Decompress the DXT5 data into Image (ith mipmap).
if (!DecompressDXT5(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
break;
}
ifree(CompData);
}
return IL_TRUE;
}
#endif//IL_NO_IWI
+823
View File
@@ -0,0 +1,823 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_jp2.c
//
// Description: Jpeg-2000 (.jp2) functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_JP2
#include <jasper/jasper.h>
#include "il_jp2.h"
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "libjasper.lib")
#else
#pragma comment(lib, "libjasper-d.lib")
#endif
#endif
#endif
ILboolean iIsValidJp2(void);
ILboolean JasperInit = IL_FALSE;
//! Checks if the file specified in FileName is a valid .jp2 file.
ILboolean ilIsValidJp2(ILconst_string FileName)
{
ILHANDLE Jp2File;
ILboolean bJp2 = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("jp2")) && !iCheckExtension(FileName, IL_TEXT("jpx")) &&
!iCheckExtension(FileName, IL_TEXT("j2k")) && !iCheckExtension(FileName, IL_TEXT("j2c"))) {
ilSetError(IL_INVALID_EXTENSION);
return bJp2;
}
Jp2File = iopenr(FileName);
if (Jp2File == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bJp2;
}
bJp2 = ilIsValidJp2F(Jp2File);
icloser(Jp2File);
return bJp2;
}
//! Checks if the ILHANDLE contains a valid .jp2 file at the current position.
ILboolean ilIsValidJp2F(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidJp2();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .jp2 lump.
ILboolean ilIsValidJp2L(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidJp2();
}
// Internal function to get the header and check it.
ILboolean iIsValidJp2(void)
{
ILubyte Signature[4];
iseek(4, IL_SEEK_CUR); // Skip the 4 bytes that tell the size of the signature box.
if (iread(Signature, 1, 4) != 4) {
iseek(-4, IL_SEEK_CUR);
return IL_FALSE; // File read error
}
iseek(-8, IL_SEEK_CUR); // Restore to previous state
// Signature is 'jP\040\040' by the specs (or 0x6A502020).
// http://www.jpeg.org/public/fcd15444-6.pdf
if (Signature[0] != 0x6A || Signature[1] != 0x50 ||
Signature[2] != 0x20 || Signature[3] != 0x20)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a Jpeg2000 file.
ILboolean ilLoadJp2(ILconst_string FileName)
{
ILHANDLE Jp2File;
ILboolean bRet;
Jp2File = iopenr(FileName);
if (Jp2File == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
bRet = ilLoadJp2F(Jp2File);
icloser(Jp2File);
return bRet;
}
//! Reads an already-opened Jpeg2000 file.
ILboolean ilLoadJp2F(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
jas_stream_t *Stream;
iSetInputFile(File);
FirstPos = itell();
if (!JasperInit) {
if (jas_init()) {
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
JasperInit = IL_TRUE;
}
Stream = iJp2ReadStream();
if (!Stream)
{
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
bRet = iLoadJp2Internal(Stream, NULL);
// Close the input stream.
jas_stream_close(Stream);
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Jpeg2000 stream.
ILboolean ilLoadJp2L(const void *Lump, ILuint Size)
{
return ilLoadJp2LInternal(Lump, Size, NULL);
}
//! This is separated so that it can be called for other file types, such as .icns.
ILboolean ilLoadJp2LInternal(const void *Lump, ILuint Size, ILimage *Image)
{
ILboolean bRet;
jas_stream_t *Stream;
if (!JasperInit) {
if (jas_init()) {
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
JasperInit = IL_TRUE;
}
Stream = jas_stream_memopen((char*)Lump, Size);
if (!Stream)
{
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
bRet = iLoadJp2Internal(Stream, Image);
// Close the input stream.
jas_stream_close(Stream);
return bRet;
}
// Internal function used to load the Jpeg2000 stream.
ILboolean iLoadJp2Internal(jas_stream_t *Stream, ILimage *Image)
{
jas_image_t *Jp2Image = NULL;
jas_matrix_t *origdata;
ILuint x, y, c, Error;
ILimage *TempImage;
// Decode image
Jp2Image = jas_image_decode(Stream, -1, 0);
if (!Jp2Image)
{
ilSetError(IL_ILLEGAL_FILE_VALUE);
jas_stream_close(Stream);
return IL_FALSE;
}
// JasPer likes to buffer a lot, so it may try buffering past the end
// of the file. iread naturally sets IL_FILE_READ_ERROR if it tries
// reading past the end of the file, but this actually is not an error.
Error = ilGetError();
// Put the error back if it is not IL_FILE_READ_ERROR.
if (Error != IL_FILE_READ_ERROR)
ilSetError(Error);
// We're not supporting anything other than 8 bits/component yet.
if (jas_image_cmptprec(Jp2Image, 0) != 8)
{
jas_image_destroy(Jp2Image);
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
switch (jas_image_numcmpts(Jp2Image))
{
//@TODO: Can we do alpha data? jas_image_cmpttype always returns 0 for this case.
case 1: // Assuming this is luminance data.
if (Image == NULL) {
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
TempImage = iCurImage;
}
else {
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
TempImage = Image;
}
break;
case 2: // Assuming this is luminance-alpha data.
if (Image == NULL) {
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
TempImage = iCurImage;
}
else {
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
TempImage = Image;
}
break;
case 3:
if (Image == NULL) {
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
TempImage = iCurImage;
}
else {
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
TempImage = Image;
}
break;
case 4:
if (Image == NULL) {
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
TempImage = iCurImage;
}
else {
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
TempImage = Image;
}
break;
default:
jas_image_destroy(Jp2Image);
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
// JasPer stores the data channels separately.
// I am assuming RGBA format. Is it possible for other formats to be included?
for (c = 0; c < TempImage->Bpp; c++)
{
origdata = jas_matrix_create(TempImage->Height, TempImage->Width);
if (!origdata)
{
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE; // @TODO: Error
}
// Have to convert data into an intermediate matrix format.
if (jas_image_readcmpt(Jp2Image, c, 0, 0, TempImage->Width, TempImage->Height, origdata))
{
return IL_FALSE;
}
for (y = 0; y < TempImage->Height; y++)
{
for (x = 0; x < TempImage->Width; x++)
{
TempImage->Data[y * TempImage->Width * TempImage->Bpp + x * TempImage->Bpp + c] = origdata->data_[y * origdata->numcols_ + x];
}
}
jas_matrix_destroy(origdata);
}
jas_image_destroy(Jp2Image);
return ilFixImage();
}
static int iJp2_file_read(jas_stream_obj_t *obj, char *buf, int cnt)
{
obj;
return iread(buf, 1, cnt);
}
static int iJp2_file_write(jas_stream_obj_t *obj, char *buf, int cnt)
{
obj;
return iwrite(buf, 1, cnt);
}
static long iJp2_file_seek(jas_stream_obj_t *obj, long offset, int origin)
{
obj;
// We could just pass origin to iseek, but this is probably more portable.
switch (origin)
{
case SEEK_SET:
return iseek(offset, IL_SEEK_SET);
case SEEK_CUR:
return iseek(offset, IL_SEEK_CUR);
case SEEK_END:
return iseek(offset, IL_SEEK_END);
}
return 0; // Failed
}
static int iJp2_file_close(jas_stream_obj_t *obj)
{
obj;
return 0; // We choose when we want to close the file.
}
static jas_stream_ops_t jas_stream_devilops = {
iJp2_file_read,
iJp2_file_write,
iJp2_file_seek,
iJp2_file_close
};
static jas_stream_t *jas_stream_create(void);
static void jas_stream_destroy(jas_stream_t *stream);
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize);
// Modified version of jas_stream_fopen and jas_stream_memopen from jas_stream.c of JasPer
// so that we can use our own file routines.
jas_stream_t *iJp2ReadStream()
{
jas_stream_t *stream;
jas_stream_memobj_t *obj;
if (!(stream = jas_stream_create())) {
return 0;
}
/* A stream associated with a memory buffer is always opened
for both reading and writing in binary mode. */
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_BINARY;
/* We use buffering whether it is from memory or a file. */
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
/* Select the operations for a memory stream. */
stream->ops_ = &jas_stream_devilops;
/* Allocate memory for the underlying memory stream object. */
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
jas_stream_destroy(stream);
return 0;
}
stream->obj_ = (void *) obj;
/* Initialize a few important members of the memory stream object. */
obj->myalloc_ = 0;
obj->buf_ = 0;
// Shouldn't need any of this.
///* If the buffer size specified is nonpositive, then the buffer
//is allocated internally and automatically grown as needed. */
//if (bufsize <= 0) {
// obj->bufsize_ = 1024;
// obj->growable_ = 1;
//} else {
// obj->bufsize_ = bufsize;
// obj->growable_ = 0;
//}
//if (buf) {
// obj->buf_ = (unsigned char *) buf;
//} else {
// obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
// obj->myalloc_ = 1;
//}
//if (!obj->buf_) {
// jas_stream_close(stream);
// return 0;
//}
//if (bufsize > 0 && buf) {
// /* If a buffer was supplied by the caller and its length is positive,
// make the associated buffer data appear in the stream initially. */
// obj->len_ = bufsize;
//} else {
// /* The stream is initially empty. */
// obj->len_ = 0;
//}
//obj->pos_ = 0;
return stream;
}
// The following functions are taken directly from jas_stream.c of JasPer,
// since they are designed to be used within JasPer only.
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
int bufsize)
{
/* If this function is being called, the buffer should not have been
initialized yet. */
assert(!stream->bufbase_);
if (bufmode != JAS_STREAM_UNBUF) {
/* The full- or line-buffered mode is being employed. */
if (!buf) {
/* The caller has not specified a buffer to employ, so allocate
one. */
if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
JAS_STREAM_MAXPUTBACK))) {
stream->bufmode_ |= JAS_STREAM_FREEBUF;
stream->bufsize_ = JAS_STREAM_BUFSIZE;
} else {
/* The buffer allocation has failed. Resort to unbuffered
operation. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
} else {
/* The caller has specified a buffer to employ. */
/* The buffer must be large enough to accommodate maximum
putback. */
assert(bufsize > JAS_STREAM_MAXPUTBACK);
stream->bufbase_ = JAS_CAST(uchar *, buf);
stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
}
} else {
/* The unbuffered mode is being employed. */
/* A buffer should not have been supplied by the caller. */
assert(!buf);
/* Use a trivial one-character buffer. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
stream->ptr_ = stream->bufstart_;
stream->cnt_ = 0;
stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
}
static jas_stream_t *jas_stream_create()
{
jas_stream_t *stream;
if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
return 0;
}
stream->openmode_ = 0;
stream->bufmode_ = 0;
stream->flags_ = 0;
stream->bufbase_ = 0;
stream->bufstart_ = 0;
stream->bufsize_ = 0;
stream->ptr_ = 0;
stream->cnt_ = 0;
stream->ops_ = 0;
stream->obj_ = 0;
stream->rwcnt_ = 0;
stream->rwlimit_ = -1;
return stream;
}
static void jas_stream_destroy(jas_stream_t *stream)
{
/* If the memory for the buffer was allocated with malloc, free
this memory. */
if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
jas_free(stream->bufbase_);
stream->bufbase_ = 0;
}
jas_free(stream);
}
jas_stream_t *iJp2WriteStream()
{
jas_stream_t *stream;
jas_stream_memobj_t *obj;
if (!(stream = jas_stream_create())) {
return 0;
}
/* A stream associated with a memory buffer is always opened
for both reading and writing in binary mode. */
stream->openmode_ = JAS_STREAM_WRITE | JAS_STREAM_BINARY;
/* We use buffering whether it is from memory or a file. */
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
/* Select the operations for a memory stream. */
stream->ops_ = &jas_stream_devilops;
/* Allocate memory for the underlying memory stream object. */
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
jas_stream_destroy(stream);
return 0;
}
stream->obj_ = (void *) obj;
/* Initialize a few important members of the memory stream object. */
obj->myalloc_ = 0;
obj->buf_ = 0;
return stream;
}
//! Writes a Jp2 file
ILboolean ilSaveJp2(const ILstring FileName)
{
ILHANDLE Jp2File;
ILuint Jp2Size;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
Jp2File = iopenw(FileName);
if (Jp2File == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
Jp2Size = ilSaveJp2F(Jp2File);
iclosew(Jp2File);
if (Jp2Size == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Jp2 to an already-opened file
ILuint ilSaveJp2F(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSaveJp2Internal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Jp2 to a memory "lump"
ILuint ilSaveJp2L(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSaveJp2Internal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Function from OpenSceneGraph (originally called getdata in their sources):
// http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
ILint Jp2ConvertData(jas_stream_t *in, jas_image_t *image)
{
int ret;
int numcmpts;
int cmptno;
jas_matrix_t *data[4];
int x;
int y;
int width, height;
width = jas_image_cmptwidth(image, 0);
height = jas_image_cmptheight(image, 0);
numcmpts = jas_image_numcmpts(image);
ret = -1;
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
if (!(data[cmptno] = jas_matrix_create(1, width))) {
goto done;
}
}
for (y = height - 1; y >= 0; --y)
// for (y = 0; y < height; ++y)
{
for (x = 0; x < width; ++x)
{
for (cmptno = 0; cmptno < numcmpts; ++cmptno)
{
// The sample data is unsigned.
int c;
if ((c = jas_stream_getc(in)) == EOF) {
return -1;
}
jas_matrix_set(data[cmptno], 0, x, c);
}
}
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
if (jas_image_writecmpt(image, cmptno, 0, y, width, 1,
data[cmptno])) {
goto done;
}
}
}
jas_stream_flush(in);
ret = 0;
done:
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
if (data[cmptno]) {
jas_matrix_destroy(data[cmptno]);
}
}
return ret;
}
// Internal function used to save the Jp2.
// Since the JasPer documentation is extremely incomplete, I had to look at how OpenSceneGraph uses it:
// http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
//@TODO: Do we need to worry about images with depths > 1?
ILboolean iSaveJp2Internal()
{
jas_image_t *Jp2Image;
jas_image_cmptparm_t cmptparm[4];
jas_stream_t *Mem, *Stream;
ILuint NumChans, i;
ILenum NewFormat, NewType = IL_UNSIGNED_BYTE;
ILimage *TempImage = iCurImage;
if (!JasperInit) {
if (jas_init()) {
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
JasperInit = IL_TRUE;
}
if (iCurImage->Type != IL_UNSIGNED_BYTE) { //@TODO: Support greater than 1 bpc.
NewType = IL_UNSIGNED_BYTE;
}
//@TODO: Do luminance/luminance-alpha/alpha separately.
switch (iCurImage->Format)
{
case IL_LUMINANCE:
NewFormat = IL_LUMINANCE;
NumChans = 1;
break;
case IL_ALPHA:
NewFormat = IL_ALPHA;
NumChans = 1;
break;
case IL_LUMINANCE_ALPHA:
NewFormat = IL_LUMINANCE_ALPHA;
NumChans = 2;
break;
case IL_COLOUR_INDEX: // Assuming the color palette does not have an alpha value.
//@TODO: Check for this in the future.
case IL_RGB:
case IL_BGR:
NewFormat = IL_RGB;
NumChans = 3;
break;
case IL_RGBA:
case IL_BGRA:
NewFormat = IL_RGBA;
NumChans = 4;
break;
}
if (NewType != iCurImage->Type || NewFormat != iCurImage->Format) {
TempImage = iConvertImage(iCurImage, NewFormat, NewType);
if (TempImage == NULL)
return IL_FALSE;
}
// The origin is always in the lower left corner. Flip the buffer if it is not.
if (TempImage->Origin == IL_ORIGIN_UPPER_LEFT)
iFlipBuffer(TempImage->Data, TempImage->Depth, TempImage->Bps, TempImage->Height);
// Have to tell JasPer about each channel. In our case, they all have the same information.
for (i = 0; i < NumChans; i++) {
cmptparm[i].width = iCurImage->Width;
cmptparm[i].height = iCurImage->Height;
cmptparm[i].hstep = 1;
cmptparm[i].vstep = 1;
cmptparm[i].tlx = 0;
cmptparm[i].tly = 0;
cmptparm[i].prec = 8;
cmptparm[i].sgnd = 0; // Unsigned data
}
// Using the unknown color space, since we have not determined the space yet.
// This is done in the following switch statement.
Jp2Image = jas_image_create(NumChans, cmptparm, JAS_CLRSPC_UNKNOWN);
if (Jp2Image == NULL) {
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
switch (NumChans)
{
case 1:
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
if (NewFormat == IL_LUMINANCE)
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
else // IL_ALPHA
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
break;
case 2:
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
break;
case 3:
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
break;
case 4:
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
jas_image_setcmpttype(Jp2Image, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
break;
}
Mem = jas_stream_memopen((char*)TempImage->Data, TempImage->SizeOfData);
if (Mem == NULL) {
jas_image_destroy(Jp2Image);
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
Stream = iJp2WriteStream();
if (Stream == NULL) {
jas_stream_close(Mem);
jas_image_destroy(Jp2Image);
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
// Puts data in the format that JasPer wants it in.
Jp2ConvertData(Mem, Jp2Image);
// Does all of the encoding.
if (jas_image_encode(Jp2Image, Stream, jas_image_strtofmt("jp2"), NULL)) { //@TODO: Do we want to use any options?
jas_stream_close(Mem);
jas_stream_close(Stream);
jas_image_destroy(Jp2Image);
ilSetError(IL_LIB_JP2_ERROR);
return IL_FALSE;
}
jas_stream_flush(Stream); // Do any final writing.
// Close the memory and output streams.
jas_stream_close(Mem);
jas_stream_close(Stream);
// Destroy the JasPer image.
jas_image_destroy(Jp2Image);
// Destroy our temporary image if we used one.
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_TRUE;
}
#endif//IL_NO_JP2
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_lif.c
//
// Description: Reads a Homeworld image.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_LIF
#include "il_lif.h"
//! Checks if the file specified in FileName is a valid Lif file.
ILboolean ilIsValidLif(ILconst_string FileName)
{
ILHANDLE LifFile;
ILboolean bLif = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("lif"))) {
ilSetError(IL_INVALID_EXTENSION);
return bLif;
}
LifFile = iopenr(FileName);
if (LifFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bLif;
}
bLif = ilIsValidLifF(LifFile);
icloser(LifFile);
return bLif;
}
//! Checks if the ILHANDLE contains a valid Lif file at the current position.
ILboolean ilIsValidLifF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidLif();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid Lif lump.
ILboolean ilIsValidLifL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidLif();
}
// Internal function used to get the Lif header from the current file.
ILboolean iGetLifHead(LIF_HEAD *Header)
{
iread(Header->Id, 1, 8);
Header->Version = GetLittleUInt();
Header->Flags = GetLittleUInt();
Header->Width = GetLittleUInt();
Header->Height = GetLittleUInt();
Header->PaletteCRC = GetLittleUInt();
Header->ImageCRC = GetLittleUInt();
Header->PalOffset = GetLittleUInt();
Header->TeamEffect0 = GetLittleUInt();
Header->TeamEffect1 = GetLittleUInt();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidLif()
{
LIF_HEAD Head;
if (!iGetLifHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(LIF_HEAD), IL_SEEK_CUR);
return iCheckLif(&Head);
}
// Internal function used to check if the HEADER is a valid Lif header.
ILboolean iCheckLif(LIF_HEAD *Header)
{
if (Header->Version != 260 || Header->Flags != 50)
return IL_FALSE;
if (stricmp(Header->Id, "Willy 7"))
return IL_FALSE;
return IL_TRUE;
}
//! Reads a .Lif file
ILboolean ilLoadLif(ILconst_string FileName)
{
ILHANDLE LifFile;
ILboolean bLif = IL_FALSE;
LifFile = iopenr(FileName);
if (LifFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bLif;
}
bLif = ilLoadLifF(LifFile);
icloser(LifFile);
return bLif;
}
//! Reads an already-opened .Lif file
ILboolean ilLoadLifF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadLifInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .Lif
ILboolean ilLoadLifL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadLifInternal();
}
ILboolean iLoadLifInternal()
{
LIF_HEAD LifHead;
ILuint i;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetLifHead(&LifHead))
return IL_FALSE;
if (!ilTexImage(LifHead.Width, LifHead.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
iCurImage->Pal.Palette = (ILubyte*)ialloc(1024);
if (iCurImage->Pal.Palette == NULL)
return IL_FALSE;
iCurImage->Pal.PalSize = 1024;
iCurImage->Pal.PalType = IL_PAL_RGBA32;
if (iread(iCurImage->Data, LifHead.Width * LifHead.Height, 1) != 1)
return IL_FALSE;
if (iread(iCurImage->Pal.Palette, 1, 1024) != 1024)
return IL_FALSE;
// Each data offset is offset by -1, so we add one.
for (i = 0; i < iCurImage->SizeOfData; i++) {
iCurImage->Data[i]++;
}
return ilFixImage();
}
#endif//IL_NO_LIF
+30
View File
@@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2002 by Denton Woods
// Last modified: 02/16/2002 <--Y2K Compliant! =]
//
// Filename: src-IL/src/il_main.c
//
// Description: Startup function
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
/* Only needed for MSVC++ unless extended to actually do something =) */
#if defined(_WIN32) && defined(_MSC_VER)
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
hModule; ul_reason_for_call; lpReserved;
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
//ilInit();
}
return TRUE;
}
#endif
+948
View File
@@ -0,0 +1,948 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/24/2009
//
// Filename: src-IL/src/il_manip.c
//
// Description: Image manipulation
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include "il_manip.h"
ILAPI void ILAPIENTRY iFlipBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num)
{
ILubyte *StartPtr, *EndPtr;
ILuint y, d;
const ILuint size = line_num * line_size;
for (d = 0; d < depth; d++) {
StartPtr = buff + d * size;
EndPtr = buff + d * size + size;
for (y = 0; y < (line_num/2); y++) {
EndPtr -= line_size;
iMemSwap(StartPtr, EndPtr, line_size);
StartPtr += line_size;
}
}
}
// Just created for internal use.
ILubyte* iFlipNewBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num)
{
ILubyte *data;
ILubyte *s1, *s2;
ILuint y, d;
const ILuint size = line_num * line_size;
if ((data = (ILubyte*)ialloc(depth*size)) == NULL)
return IL_FALSE;
for (d = 0; d < depth; d++) {
s1 = buff + d * size;
s2 = data + d * size+size;
for (y = 0; y < line_num; y++) {
s2 -= line_size;
memcpy(s2,s1,line_size);
s1 += line_size;
}
}
return data;
}
// Flips an image over its x axis
ILboolean ilFlipImage()
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
iCurImage->Origin = (iCurImage->Origin == IL_ORIGIN_LOWER_LEFT) ?
IL_ORIGIN_UPPER_LEFT : IL_ORIGIN_LOWER_LEFT;
iFlipBuffer(iCurImage->Data,iCurImage->Depth,iCurImage->Bps,iCurImage->Height);
return IL_TRUE;
}
// Just created for internal use.
ILubyte* ILAPIENTRY iGetFlipped(ILimage *img)
{
if (img == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return NULL;
}
return iFlipNewBuffer(img->Data,img->Depth,img->Bps,img->Height);
}
//@JASON New routine created 28/03/2001
//! Mirrors an image over its y axis
ILboolean ILAPIENTRY iMirror() {
ILubyte *Data, *DataPtr, *Temp;
ILuint y, d, PixLine;
ILint x, c;
ILushort *ShortPtr, *TempShort;
ILuint *IntPtr, *TempInt;
ILdouble *DblPtr, *TempDbl;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Data = (ILubyte*)ialloc(iCurImage->SizeOfData);
if (Data == NULL)
return IL_FALSE;
PixLine = iCurImage->Bps / iCurImage->Bpc;
switch (iCurImage->Bpc)
{
case 1:
Temp = iCurImage->Data;
for (d = 0; d < iCurImage->Depth; d++) {
DataPtr = Data + d * iCurImage->SizeOfPlane;
for (y = 0; y < iCurImage->Height; y++) {
for (x = iCurImage->Width - 1; x >= 0; x--) {
for (c = 0; c < iCurImage->Bpp; c++, Temp++) {
DataPtr[y * PixLine + x * iCurImage->Bpp + c] = *Temp;
}
}
}
}
break;
case 2:
TempShort = (ILushort*)iCurImage->Data;
for (d = 0; d < iCurImage->Depth; d++) {
ShortPtr = (ILushort*)(Data + d * iCurImage->SizeOfPlane);
for (y = 0; y < iCurImage->Height; y++) {
for (x = iCurImage->Width - 1; x >= 0; x--) {
for (c = 0; c < iCurImage->Bpp; c++, TempShort++) {
ShortPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempShort;
}
}
}
}
break;
case 4:
TempInt = (ILuint*)iCurImage->Data;
for (d = 0; d < iCurImage->Depth; d++) {
IntPtr = (ILuint*)(Data + d * iCurImage->SizeOfPlane);
for (y = 0; y < iCurImage->Height; y++) {
for (x = iCurImage->Width - 1; x >= 0; x--) {
for (c = 0; c < iCurImage->Bpp; c++, TempInt++) {
IntPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempInt;
}
}
}
}
break;
case 8:
TempDbl = (ILdouble*)iCurImage->Data;
for (d = 0; d < iCurImage->Depth; d++) {
DblPtr = (ILdouble*)(Data + d * iCurImage->SizeOfPlane);
for (y = 0; y < iCurImage->Height; y++) {
for (x = iCurImage->Width - 1; x >= 0; x--) {
for (c = 0; c < iCurImage->Bpp; c++, TempDbl++) {
DblPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempDbl;
}
}
}
}
break;
}
ifree(iCurImage->Data);
iCurImage->Data = Data;
return IL_TRUE;
}
// Should we add type to the parameter list?
// Copies a 1d block of pixels to the buffer pointed to by Data.
ILboolean ilCopyPixels1D(ILuint XOff, ILuint Width, void *Data)
{
ILuint x, c, NewBps, NewOff, PixBpp;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (iCurImage->Width < XOff + Width) {
NewBps = (iCurImage->Width - XOff) * PixBpp;
}
else {
NewBps = Width * PixBpp;
}
NewOff = XOff * PixBpp;
for (x = 0; x < NewBps; x += PixBpp) {
for (c = 0; c < PixBpp; c++) {
Temp[x + c] = TempData[(x + NewOff) + c];
}
}
if (TempData != iCurImage->Data)
ifree(TempData);
return IL_TRUE;
}
// Copies a 2d block of pixels to the buffer pointed to by Data.
ILboolean ilCopyPixels2D(ILuint XOff, ILuint YOff, ILuint Width, ILuint Height, void *Data)
{
ILuint x, y, c, NewBps, DataBps, NewXOff, NewHeight, PixBpp;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (iCurImage->Width < XOff + Width)
NewBps = (iCurImage->Width - XOff) * PixBpp;
else
NewBps = Width * PixBpp;
if (iCurImage->Height < YOff + Height)
NewHeight = iCurImage->Height - YOff;
else
NewHeight = Height;
DataBps = Width * PixBpp;
NewXOff = XOff * PixBpp;
for (y = 0; y < NewHeight; y++) {
for (x = 0; x < NewBps; x += PixBpp) {
for (c = 0; c < PixBpp; c++) {
Temp[y * DataBps + x + c] =
TempData[(y + YOff) * iCurImage->Bps + x + NewXOff + c];
}
}
}
if (TempData != iCurImage->Data)
ifree(TempData);
return IL_TRUE;
}
// Copies a 3d block of pixels to the buffer pointed to by Data.
ILboolean ilCopyPixels3D(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, void *Data)
{
ILuint x, y, z, c, NewBps, DataBps, NewSizePlane, NewH, NewD, NewXOff, PixBpp;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (iCurImage->Width < XOff + Width)
NewBps = (iCurImage->Width - XOff) * PixBpp;
else
NewBps = Width * PixBpp;
if (iCurImage->Height < YOff + Height)
NewH = iCurImage->Height - YOff;
else
NewH = Height;
if (iCurImage->Depth < ZOff + Depth)
NewD = iCurImage->Depth - ZOff;
else
NewD = Depth;
DataBps = Width * PixBpp;
NewSizePlane = NewBps * NewH;
NewXOff = XOff * PixBpp;
for (z = 0; z < NewD; z++) {
for (y = 0; y < NewH; y++) {
for (x = 0; x < NewBps; x += PixBpp) {
for (c = 0; c < PixBpp; c++) {
Temp[z * NewSizePlane + y * DataBps + x + c] =
TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + x + NewXOff + c];
//TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + (x + XOff) * iCurImage->Bpp + c];
}
}
}
}
if (TempData != iCurImage->Data)
ifree(TempData);
return IL_TRUE;
}
ILuint ILAPIENTRY ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data)
{
void *Converted = NULL;
ILubyte *TempBuff = NULL;
ILuint SrcSize, DestSize;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return 0;
}
DestSize = Width * Height * Depth * ilGetBppFormat(Format) * ilGetBpcType(Type);
if (DestSize == 0) {
return DestSize;
}
if (Data == NULL || Format == IL_COLOUR_INDEX) {
ilSetError(IL_INVALID_PARAM);
return 0;
}
SrcSize = Width * Height * Depth * iCurImage->Bpp * iCurImage->Bpc;
if (Format == iCurImage->Format && Type == iCurImage->Type) {
TempBuff = (ILubyte*)Data;
}
else {
TempBuff = (ILubyte*)ialloc(SrcSize);
if (TempBuff == NULL) {
return 0;
}
}
if (YOff + Height <= 1) {
if (!ilCopyPixels1D(XOff, Width, TempBuff)) {
goto failed;
}
}
else if (ZOff + Depth <= 1) {
if (!ilCopyPixels2D(XOff, YOff, Width, Height, TempBuff)) {
goto failed;
}
}
else {
if (!ilCopyPixels3D(XOff, YOff, ZOff, Width, Height, Depth, TempBuff)) {
goto failed;
}
}
if (Format == iCurImage->Format && Type == iCurImage->Type) {
return DestSize;
}
Converted = ilConvertBuffer(SrcSize, iCurImage->Format, Format, iCurImage->Type, Type, &iCurImage->Pal, TempBuff);
if (Converted == NULL)
goto failed;
memcpy(Data, Converted, DestSize);
ifree(Converted);
if (TempBuff != Data)
ifree(TempBuff);
return DestSize;
failed:
if (TempBuff != Data)
ifree(TempBuff);
ifree(Converted);
return 0;
}
ILboolean ilSetPixels1D(ILint XOff, ILuint Width, void *Data)
{
ILuint c, SkipX = 0, PixBpp;
ILint x, NewWidth;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (XOff < 0) {
SkipX = abs(XOff);
XOff = 0;
}
if (iCurImage->Width < XOff + Width) {
NewWidth = iCurImage->Width - XOff;
}
else {
NewWidth = Width;
}
NewWidth -= SkipX;
for (x = 0; x < NewWidth; x++) {
for (c = 0; c < PixBpp; c++) {
TempData[(x + XOff) * PixBpp + c] = Temp[(x + SkipX) * PixBpp + c];
}
}
if (TempData != iCurImage->Data) {
ifree(iCurImage->Data);
iCurImage->Data = TempData;
}
return IL_TRUE;
}
ILboolean ilSetPixels2D(ILint XOff, ILint YOff, ILuint Width, ILuint Height, void *Data)
{
ILuint c, SkipX = 0, SkipY = 0, NewBps, PixBpp;
ILint x, y, NewWidth, NewHeight;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (XOff < 0) {
SkipX = abs(XOff);
XOff = 0;
}
if (YOff < 0) {
SkipY = abs(YOff);
YOff = 0;
}
if (iCurImage->Width < XOff + Width)
NewWidth = iCurImage->Width - XOff;
else
NewWidth = Width;
NewBps = Width * PixBpp;
if (iCurImage->Height < YOff + Height)
NewHeight = iCurImage->Height - YOff;
else
NewHeight = Height;
NewWidth -= SkipX;
NewHeight -= SkipY;
for (y = 0; y < NewHeight; y++) {
for (x = 0; x < NewWidth; x++) {
for (c = 0; c < PixBpp; c++) {
TempData[(y + YOff) * iCurImage->Bps + (x + XOff) * PixBpp + c] =
Temp[(y + SkipY) * NewBps + (x + SkipX) * PixBpp + c];
}
}
}
if (TempData != iCurImage->Data) {
ifree(iCurImage->Data);
iCurImage->Data = TempData;
}
return IL_TRUE;
}
ILboolean ilSetPixels3D(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, void *Data)
{
ILuint SkipX = 0, SkipY = 0, SkipZ = 0, c, NewBps, NewSizePlane, PixBpp;
ILint x, y, z, NewW, NewH, NewD;
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
if (ilIsEnabled(IL_ORIGIN_SET)) {
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
TempData = iGetFlipped(iCurImage);
if (TempData == NULL)
return IL_FALSE;
}
}
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
if (XOff < 0) {
SkipX = abs(XOff);
XOff = 0;
}
if (YOff < 0) {
SkipY = abs(YOff);
YOff = 0;
}
if (ZOff < 0) {
SkipZ = abs(ZOff);
ZOff = 0;
}
if (iCurImage->Width < XOff + Width)
NewW = iCurImage->Width - XOff;
else
NewW = Width;
NewBps = Width * PixBpp;
if (iCurImage->Height < YOff + Height)
NewH = iCurImage->Height - YOff;
else
NewH = Height;
if (iCurImage->Depth < ZOff + Depth)
NewD = iCurImage->Depth - ZOff;
else
NewD = Depth;
NewSizePlane = NewBps * Height;
NewW -= SkipX;
NewH -= SkipY;
NewD -= SkipZ;
for (z = 0; z < NewD; z++) {
for (y = 0; y < NewH; y++) {
for (x = 0; x < NewW; x++) {
for (c = 0; c < PixBpp; c++) {
TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + (x + XOff) * PixBpp + c] =
Temp[(z + SkipZ) * NewSizePlane + (y + SkipY) * NewBps + (x + SkipX) * PixBpp + c];
}
}
}
}
if (TempData != iCurImage->Data) {
ifree(iCurImage->Data);
iCurImage->Data = TempData;
}
return IL_TRUE;
}
void ILAPIENTRY ilSetPixels(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data)
{
void *Converted;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return;
}
if (Data == NULL) {
ilSetError(IL_INVALID_PARAM);
return;
}
if (Format == iCurImage->Format && Type == iCurImage->Type) {
Converted = (void*)Data;
}
else {
Converted = ilConvertBuffer(Width * Height * Depth * ilGetBppFormat(Format) * ilGetBpcType(Type), Format, iCurImage->Format, Type, iCurImage->Type, NULL, Data);
if (!Converted)
return;
}
if (YOff + Height <= 1) {
ilSetPixels1D(XOff, Width, Converted);
}
else if (ZOff + Depth <= 1) {
ilSetPixels2D(XOff, YOff, Width, Height, Converted);
}
else {
ilSetPixels3D(XOff, YOff, ZOff, Width, Height, Depth, Converted);
}
if (Format == iCurImage->Format && Type == iCurImage->Type) {
return;
}
if (Converted != Data)
ifree(Converted);
return;
}
// Ripped from Platinum (Denton's sources)
// This could very well easily be changed to a 128x128 image instead...needed?
//! Creates an ugly 64x64 black and yellow checkerboard image.
ILboolean ILAPIENTRY ilDefaultImage()
{
ILubyte *TempData;
ILubyte Yellow[3] = { 18, 246, 243 };
ILubyte Black[3] = { 0, 0, 0 };
ILubyte *ColorPtr = Yellow; // The start color
ILboolean Color = IL_TRUE;
// Loop Variables
ILint v, w, x, y;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!ilTexImage(64, 64, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
TempData = iCurImage->Data;
for (v = 0; v < 8; v++) {
// We do this because after a "block" line ends, the next row of blocks
// above starts with the ending colour, but the very inner loop switches them.
if (Color) {
Color = IL_FALSE;
ColorPtr = Black;
}
else {
Color = IL_TRUE;
ColorPtr = Yellow;
}
for (w = 0; w < 8; w++) {
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++, TempData += iCurImage->Bpp) {
TempData[0] = ColorPtr[0];
TempData[1] = ColorPtr[1];
TempData[2] = ColorPtr[2];
}
// Switch to alternate between black and yellow
if (Color) {
Color = IL_FALSE;
ColorPtr = Black;
}
else {
Color = IL_TRUE;
ColorPtr = Yellow;
}
}
}
}
return IL_TRUE;
}
ILubyte* ILAPIENTRY ilGetAlpha(ILenum Type)
{
ILimage *TempImage;
ILubyte *Alpha;
ILushort *AlphaShort;
ILuint *AlphaInt;
ILdouble *AlphaDbl;
ILuint i, j, Bpc, Size, AlphaOff;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Bpc = ilGetBpcType(Type);
if (Bpc == 0) {
ilSetError(IL_INVALID_PARAM);
return NULL;
}
if (iCurImage->Type == Type) {
TempImage = iCurImage;
} else {
TempImage = iConvertImage(iCurImage, iCurImage->Format, Type);
if (TempImage == NULL)
return NULL;
}
Size = iCurImage->Width * iCurImage->Height * iCurImage->Depth * TempImage->Bpp;
Alpha = (ILubyte*)ialloc(Size / TempImage->Bpp * Bpc);
if (Alpha == NULL) {
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return NULL;
}
switch (TempImage->Format)
{
case IL_RGB:
case IL_BGR:
case IL_LUMINANCE:
case IL_COLOUR_INDEX: // @TODO: Make IL_COLOUR_INDEX separate.
memset(Alpha, 0xFF, Size / TempImage->Bpp * Bpc);
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return Alpha;
}
// If our format is alpha, just return a copy.
if (TempImage->Format == IL_ALPHA) {
memcpy(Alpha, TempImage->Data, TempImage->SizeOfData);
return Alpha;
}
if (TempImage->Format == IL_LUMINANCE_ALPHA)
AlphaOff = 2;
else
AlphaOff = 4;
switch (TempImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
Alpha[j] = TempImage->Data[i];
break;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
AlphaShort = (ILushort*)Alpha;
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
AlphaShort[j] = ((ILushort*)TempImage->Data)[i];
break;
case IL_INT:
case IL_UNSIGNED_INT:
case IL_FLOAT: // Can throw float in here, because it's the same size.
AlphaInt = (ILuint*)Alpha;
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
AlphaInt[j] = ((ILuint*)TempImage->Data)[i];
break;
case IL_DOUBLE:
AlphaDbl = (ILdouble*)Alpha;
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
AlphaDbl[j] = ((ILdouble*)TempImage->Data)[i];
break;
}
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return Alpha;
}
// sets the Alpha value to a specific value for each pixel in the image
ILboolean ILAPIENTRY ilSetAlpha(ILdouble AlphaValue)
{
ILboolean ret = IL_TRUE;
ILuint i,Size;
ILimage *Image = iCurImage;
ILuint AlphaOff;
if (Image == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
AlphaValue = IL_CLAMP(AlphaValue);
switch (Image->Format)
{
case IL_RGB:
ret = ilConvertImage(IL_RGBA, Image->Type);
case IL_RGBA:
AlphaOff = 4;
break;
case IL_BGR:
ret = ilConvertImage(IL_BGRA, Image->Type);
case IL_BGRA:
AlphaOff = 4;
break;
case IL_LUMINANCE:
ret = ilConvertImage(IL_LUMINANCE_ALPHA, Image->Type);
case IL_LUMINANCE_ALPHA:
AlphaOff = 2;
break;
case IL_ALPHA:
AlphaOff = 1;
case IL_COLOUR_INDEX: //@TODO use palette with alpha
ret = ilConvertImage(IL_RGBA, Image->Type);
AlphaOff = 4;
break;
}
if (ret == IL_FALSE) {
// Error has been set by ilConvertImage.
return IL_FALSE;
}
Size = Image->Width * Image->Height * Image->Depth * Image->Bpp;
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE: {
const ILbyte alpha = (ILubyte)(AlphaValue * IL_MAX_UNSIGNED_BYTE + .5);
for (i = AlphaOff-1; i < Size; i += AlphaOff)
Image->Data[i] = alpha;
break;
}
case IL_SHORT:
case IL_UNSIGNED_SHORT: {
const ILushort alpha = (ILushort)(AlphaValue * IL_MAX_UNSIGNED_SHORT + .5);
for (i = AlphaOff-1; i < Size; i += AlphaOff)
((ILushort*)Image->Data)[i] = alpha;
break;
}
case IL_INT:
case IL_UNSIGNED_INT: {
const ILushort alpha = (ILushort)(AlphaValue * IL_MAX_UNSIGNED_INT + .5);
for (i = AlphaOff-1; i < Size; i += AlphaOff)
((ILuint*)Image->Data)[i] = alpha;
break;
}
case IL_FLOAT: {
const ILfloat alpha = (ILfloat)AlphaValue;
for (i = AlphaOff-1; i < Size; i += AlphaOff)
((ILfloat*)Image->Data)[i] = alpha;
break;
}
case IL_DOUBLE: {
const ILdouble alpha = AlphaValue;
for (i = AlphaOff-1; i < Size; i += AlphaOff)
((ILdouble*)Image->Data)[i] = alpha;
break;
}
}
return IL_TRUE;
}
void ILAPIENTRY ilModAlpha(ILdouble AlphaValue)
{
ILuint AlphaOff = 0;
ILboolean ret = IL_FALSE;
ILuint i,j,Size;
union {
ILubyte alpha_byte;
ILushort alpha_short;
ILuint alpha_int;
ILfloat alpha_float;
ILdouble alpha_double;
} Alpha;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return;
}
switch (iCurImage->Format)
{
case IL_RGB:
ret = ilConvertImage(IL_RGBA,iCurImage->Type);
AlphaOff = 4;
break;
case IL_BGR:
ret = ilConvertImage(IL_BGRA,iCurImage->Type);
AlphaOff = 4;
break;
case IL_LUMINANCE:
ret = ilConvertImage(IL_LUMINANCE_ALPHA,iCurImage->Type);
AlphaOff = 2;
break;
case IL_COLOUR_INDEX:
ret = ilConvertImage(IL_RGBA,iCurImage->Type);
AlphaOff = 4;
break;
}
Size = iCurImage->Width * iCurImage->Height * iCurImage->Depth * iCurImage->Bpp;
if (!ret)
return;
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
Alpha.alpha_byte = (ILubyte)(AlphaValue * 0x000000FF + .5);
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
iCurImage->Data[i] = Alpha.alpha_byte;
break;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
Alpha.alpha_short = (ILushort)(AlphaValue * 0x0000FFFF + .5);
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
((ILushort*)iCurImage->Data)[i] = Alpha.alpha_short;
break;
case IL_INT:
case IL_UNSIGNED_INT:
Alpha.alpha_int = (ILuint)(AlphaValue * 0xFFFFFFFF + .5);
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
((ILuint*)iCurImage->Data)[i] = Alpha.alpha_int;
break;
case IL_FLOAT:
Alpha.alpha_float = (ILfloat)AlphaValue;
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
((ILfloat*)iCurImage->Data)[i] = Alpha.alpha_float;
break;
case IL_DOUBLE:
Alpha.alpha_double = AlphaValue;
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
((ILdouble*)iCurImage->Data)[i] = Alpha.alpha_double;
break;
}
return;
}
//! Clamps data values of unsigned bytes from 16 to 235 for display on an
// NTSC television. Reasoning for this is given at
// http://msdn.microsoft.com/en-us/library/bb174608.aspx.
ILboolean ILAPIENTRY ilClampNTSC(void)
{
ILuint x, y, z, c;
ILuint Offset = 0;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (iCurImage->Type != IL_UNSIGNED_BYTE) // Should we set an error here?
return IL_FALSE;
for (z = 0; z < iCurImage->Depth; z++) {
for (y = 0; y < iCurImage->Height; y++) {
for (x = 0; x < iCurImage->Width; x++) {
for (c = 0; c < iCurImage->Bpp; c++) {
iCurImage->Data[Offset + c] = IL_LIMIT(iCurImage->Data[Offset + c], 16, 235);
}
Offset += iCurImage->Bpp;
}
}
}
return IL_TRUE;
}
+218
View File
@@ -0,0 +1,218 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_mdl.c
//
// Description: Reads a Half-Life model file (.mdl).
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_MDL
#include "il_mdl.h"
ILboolean iLoadMdlInternal(void);
ILboolean iIsValidMdl(void);
//! Checks if the file specified in FileName is a valid MDL file.
ILboolean ilIsValidMdl(ILconst_string FileName)
{
ILHANDLE MdlFile;
ILboolean bMdl = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("mdl"))) {
ilSetError(IL_INVALID_EXTENSION);
return bMdl;
}
MdlFile = iopenr(FileName);
if (MdlFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bMdl;
}
bMdl = ilIsValidMdlF(MdlFile);
icloser(MdlFile);
return bMdl;
}
//! Checks if the ILHANDLE contains a valid MDL file at the current position.
ILboolean ilIsValidMdlF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidMdl();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid MDL lump.
ILboolean ilIsValidMdlL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidMdl();
}
// Internal function to get the header and check it.
ILboolean iIsValidMdl(void)
{
ILuint Id, Version;
Id = GetLittleUInt();
Version = GetLittleUInt();
iseek(-8, IL_SEEK_CUR); // Restore to previous position.
// 0x54534449 == "IDST"
if (Id != 0x54534449 || Version != 10)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a .mdl file
ILboolean ilLoadMdl(ILconst_string FileName)
{
ILHANDLE MdlFile;
ILboolean bMdl = IL_FALSE;
MdlFile = iopenr(FileName);
if (MdlFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bMdl;
}
bMdl = ilLoadMdlF(MdlFile);
icloser(MdlFile);
return bMdl;
}
//! Reads an already-opened .mdl file
ILboolean ilLoadMdlF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadMdlInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .mdl
ILboolean ilLoadMdlL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadMdlInternal();
}
ILboolean iLoadMdlInternal()
{
ILuint Id, Version, NumTex, TexOff, TexDataOff, Position, ImageNum;
ILubyte *TempPal;
TEX_HEAD TexHead;
ILimage *BaseImage=NULL;
ILboolean BaseCreated = IL_FALSE;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Id = GetLittleUInt();
Version = GetLittleUInt();
// 0x54534449 == "IDST"
if (Id != 0x54534449 || Version != 10) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Skips the actual model header.
iseek(172, IL_SEEK_CUR);
NumTex = GetLittleUInt();
TexOff = GetLittleUInt();
TexDataOff = GetLittleUInt();
if (NumTex == 0 || TexOff == 0 || TexDataOff == 0) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
iseek(TexOff, IL_SEEK_SET);
for (ImageNum = 0; ImageNum < NumTex; ImageNum++) {
if (iread(TexHead.Name, 1, 64) != 64)
return IL_FALSE;
TexHead.Flags = GetLittleUInt();
TexHead.Width = GetLittleUInt();
TexHead.Height = GetLittleUInt();
TexHead.Offset = GetLittleUInt();
Position = itell();
if (TexHead.Offset == 0) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
if (!BaseCreated) {
ilTexImage(TexHead.Width, TexHead.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
BaseCreated = IL_TRUE;
BaseImage = iCurImage;
//iCurImage->NumNext = NumTex - 1; // Don't count the first image.
}
else {
//iCurImage->Next = ilNewImage(TexHead.Width, TexHead.Height, 1, 1, 1);
iCurImage = iCurImage->Next;
iCurImage->Format = IL_COLOUR_INDEX;
iCurImage->Type = IL_UNSIGNED_BYTE;
}
TempPal = (ILubyte*)ialloc(768);
if (TempPal == NULL) {
iCurImage = BaseImage;
return IL_FALSE;
}
iCurImage->Pal.Palette = TempPal;
iCurImage->Pal.PalSize = 768;
iCurImage->Pal.PalType = IL_PAL_RGB24;
iseek(TexHead.Offset, IL_SEEK_SET);
if (iread(iCurImage->Data, TexHead.Width * TexHead.Height, 1) != 1)
return IL_FALSE;
if (iread(iCurImage->Pal.Palette, 1, 768) != 768)
return IL_FALSE;
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
}
iseek(Position, IL_SEEK_SET);
}
iCurImage = BaseImage;
return ilFixImage();
}
#endif//IL_NO_MDL
+378
View File
@@ -0,0 +1,378 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_mng.c
//
// Description: Multiple Network Graphics (.mng) functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_MNG
#define MNG_SUPPORT_READ
#define MNG_SUPPORT_WRITE
#define MNG_SUPPORT_DISPLAY
#ifdef _WIN32
//#define MNG_USE_SO
#endif
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "libmng.lib")
#pragma comment(lib, "lcms.lib")
#pragma comment(lib, "libjpeg.lib")
#pragma comment(lib, "zlib.lib")
#else
#pragma comment(lib, "libmng-d.lib")
#pragma comment(lib, "lcms-d.lib")
#pragma comment(lib, "libjpeg-d.lib")
#pragma comment(lib, "zlib-d.lib")
#endif
#endif
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4142) // Redefinition in jmorecfg.h
#endif
#include <libmng.h>
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
//---------------------------------------------------------------------------------------------
// memory allocation; data must be zeroed
//---------------------------------------------------------------------------------------------
mng_ptr MNG_DECL mymngalloc(mng_size_t size)
{
return (mng_ptr)icalloc(1, size);
}
//---------------------------------------------------------------------------------------------
// memory deallocation
//---------------------------------------------------------------------------------------------
void MNG_DECL mymngfree(mng_ptr p, mng_size_t size)
{
ifree(p);
}
//---------------------------------------------------------------------------------------------
// Stream open:
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngopenstream(mng_handle mng)
{
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// Stream open for Writing:
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngopenstreamwrite(mng_handle mng)
{
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// Stream close:
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngclosestream(mng_handle mng)
{
return MNG_TRUE; // We close the file ourself, mng_cleanup doesnt seem to do it...
}
//---------------------------------------------------------------------------------------------
// feed data to the decoder
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngreadstream(mng_handle mng, mng_ptr buffer, mng_size_t size, mng_uint32 *bytesread)
{
// read the requested amount of data from the file
*bytesread = iread(buffer, 1, (ILuint)size);
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// callback for writing data
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngwritedata(mng_handle mng, mng_ptr buffer, mng_size_t size, mng_uint32 *byteswritten)
{
*byteswritten = iwrite(buffer, 1, (ILuint)size);
if (*byteswritten < size) {
ilSetError(IL_FILE_WRITE_ERROR);
return MNG_FALSE;
}
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// the header's been read. set up the display stuff
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngprocessheader(mng_handle mng, mng_uint32 width, mng_uint32 height)
{
ILuint AlphaDepth;
AlphaDepth = mng_get_alphadepth(mng);
if (AlphaDepth == 0) {
ilTexImage(width, height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL);
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
mng_set_canvasstyle(mng, MNG_CANVAS_BGR8);
}
else { // Use alpha channel
ilTexImage(width, height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
mng_set_canvasstyle(mng, MNG_CANVAS_BGRA8);
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// return a row pointer for the decoder to fill
//---------------------------------------------------------------------------------------------
mng_ptr MNG_DECL mymnggetcanvasline(mng_handle mng, mng_uint32 line)
{
return (mng_ptr)(iCurImage->Data + iCurImage->Bps * line);
}
//---------------------------------------------------------------------------------------------
// timer
//---------------------------------------------------------------------------------------------
mng_uint32 MNG_DECL mymnggetticks(mng_handle mng)
{
return 0;
}
//---------------------------------------------------------------------------------------------
// Refresh:
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
{
return MNG_TRUE;
}
//---------------------------------------------------------------------------------------------
// interframe delay callback
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngsettimer(mng_handle mng, mng_uint32 msecs)
{
return MNG_TRUE;
}
// Make this do something different soon!
//---------------------------------------------------------------------------------------------
// Error Callback;
//---------------------------------------------------------------------------------------------
mng_bool MNG_DECL mymngerror(
mng_handle mng, mng_int32 code, mng_int8 severity,
mng_chunkid chunktype, mng_uint32 chunkseq,
mng_int32 extra1, mng_int32 extra2, mng_pchar text
)
{
// error occured;
return MNG_FALSE;
}
ILboolean iLoadMngInternal(void);
// Reads a file
ILboolean ilLoadMng(ILconst_string FileName)
{
ILHANDLE MngFile;
ILboolean bMng = IL_FALSE;
MngFile = iopenr(FileName);
if (MngFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bMng;
}
bMng = ilLoadMngF(MngFile);
icloser(MngFile);
return bMng;
}
// Reads an already-opened file
ILboolean ilLoadMngF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadMngInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
// Reads from a memory "lump"
ILboolean ilLoadMngL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadMngInternal();
}
ILboolean iLoadMngInternal()
{
mng_handle mng;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
mng = mng_initialize(MNG_NULL, mymngalloc, mymngfree, MNG_NULL);
if (mng == MNG_NULL) {
ilSetError(IL_LIB_MNG_ERROR);
return IL_FALSE;
}
// If .mng background is available, use it.
mng_set_usebkgd(mng, MNG_TRUE);
// Set the callbacks.
mng_setcb_errorproc(mng, mymngerror);
mng_setcb_openstream(mng, mymngopenstream);
mng_setcb_closestream(mng, mymngclosestream);
mng_setcb_readdata(mng, (mng_readdata)mymngreadstream);
mng_setcb_gettickcount(mng, mymnggetticks);
mng_setcb_settimer(mng, mymngsettimer);
mng_setcb_processheader(mng, mymngprocessheader);
mng_setcb_getcanvasline(mng, mymnggetcanvasline);
mng_setcb_refresh(mng, mymngrefresh);
mng_read(mng);
mng_display(mng);
return ilFixImage();
}
ILboolean iSaveMngInternal(void);
//! Writes a Mng file
ILboolean ilSaveMng(const ILstring FileName)
{
ILHANDLE MngFile;
ILuint MngSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
MngFile = iopenw(FileName);
if (MngFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
MngSize = ilSaveMngF(MngFile);
iclosew(MngFile);
if (MngSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Mng to an already-opened file
ILuint ilSaveMngF(ILHANDLE File)
{
ILuint Pos = itellw();
iSetOutputFile(File);
if (iSaveMngInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Mng to a memory "lump"
ILuint ilSaveMngL(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSaveMngInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to save the Mng.
ILboolean iSaveMngInternal()
{
//mng_handle mng;
// Not working yet, so just error out.
ilSetError(IL_INVALID_EXTENSION);
return IL_FALSE;
//if (iCurImage == NULL) {
// ilSetError(IL_ILLEGAL_OPERATION);
// return IL_FALSE;
//}
//mng = mng_initialize(MNG_NULL, mymngalloc, mymngfree, MNG_NULL);
//if (mng == MNG_NULL) {
// ilSetError(IL_LIB_MNG_ERROR);
// return IL_FALSE;
//}
//mng_setcb_openstream(mng, mymngopenstreamwrite);
//mng_setcb_closestream(mng, mymngclosestream);
//mng_setcb_writedata(mng, mymngwritedata);
//// Write File:
// mng_create(mng);
//// Check return value.
//mng_putchunk_mhdr(mng, iCurImage->Width, iCurImage->Height, 1000, 3, 1, 3, 0x0047);
//mng_putchunk_basi(mng, iCurImage->Width, iCurImage->Height, 8, MNG_COLORTYPE_RGB, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1);
//mng_putchunk_iend(mng);
//mng_putimgdata_ihdr(mng, iCurImage->Width, iCurImage->Height, MNG_COLORTYPE_RGB, 8, 0, 0, 0, 0, mymnggetcanvasline);
//// Now write file:
//mng_write(mng);
//mng_cleanup(&mng);
//return IL_TRUE;
}
#endif//IL_NO_MNG
+280
View File
@@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/05/2009
//
// Filename: src-IL/src/il_mp3.c
//
// MimeType: Reads from an MPEG-1 Audio Layer 3 (.mp3) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_MP3
typedef struct MP3HEAD
{
char Signature[3];
ILubyte VersionMajor;
ILubyte VersionMinor;
ILubyte Flags;
ILuint Length;
} MP3HEAD;
#define MP3_NONE 0
#define MP3_JPG 1
#define MP3_PNG 2
ILboolean iLoadMp3Internal(void);
ILboolean iIsValidMp3(void);
ILboolean iCheckMp3(MP3HEAD *Header);
ILboolean iLoadJpegInternal(void);
ILboolean iLoadPngInternal(void);
//! Checks if the file specified in FileName is a valid MP3 file.
ILboolean ilIsValidMp3(ILconst_string FileName)
{
ILHANDLE Mp3File;
ILboolean bMp3 = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("mp3"))) {
ilSetError(IL_INVALID_EXTENSION);
return bMp3;
}
Mp3File = iopenr(FileName);
if (Mp3File == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bMp3;
}
bMp3 = ilIsValidMp3F(Mp3File);
icloser(Mp3File);
return bMp3;
}
//! Checks if the ILHANDLE contains a valid MP3 file at the current position.
ILboolean ilIsValidMp3F(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidMp3();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid MP3 lump.
ILboolean ilIsValidMp3L(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidMp3();
}
ILuint GetSynchInt()
{
ILuint SynchInt;
SynchInt = GetBigUInt();
SynchInt = ((SynchInt & 0x7F000000) >> 3) | ((SynchInt & 0x7F0000) >> 2)
| ((SynchInt & 0x7F00) >> 1) | (SynchInt & 0x7F);
return SynchInt;
}
// Internal function used to get the MP3 header from the current file.
ILboolean iGetMp3Head(MP3HEAD *Header)
{
if (iread(Header->Signature, 3, 1) != 1)
return IL_FALSE;
Header->VersionMajor = igetc();
Header->VersionMinor = igetc();
Header->Flags = igetc();
Header->Length = GetSynchInt();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidMp3(void)
{
MP3HEAD Header;
ILuint Pos = itell();
if (!iGetMp3Head(&Header))
return IL_FALSE;
// The length of the header varies, so we just go back to the original position.
iseek(Pos, IL_SEEK_CUR);
return iCheckMp3(&Header);
}
// Internal function used to check if the HEADER is a valid MP3 header.
ILboolean iCheckMp3(MP3HEAD *Header)
{
if (strncmp(Header->Signature, "ID3", 3))
return IL_FALSE;
if (Header->VersionMajor != 3 && Header->VersionMinor != 4)
return IL_FALSE;
return IL_TRUE;
}
ILuint iFindMp3Pic(MP3HEAD *Header)
{
char ID[4];
ILuint FrameSize;
ILubyte TextEncoding;
ILubyte MimeType[65], Description[65];
ILubyte PicType;
ILuint i;
ILuint Type = MP3_NONE;
do {
if (iread(ID, 4, 1) != 1)
return MP3_NONE;
if (Header->VersionMajor == 3)
FrameSize = GetBigUInt();
else
FrameSize = GetSynchInt();
GetBigUShort(); // Skip the flags.
//@TODO: Support multiple APIC entries in an mp3 file.
if (!strncmp(ID, "APIC", 4)) {
//@TODO: Use TextEncoding properly - UTF16 strings starting with FFFE or FEFF.
TextEncoding = igetc();
// Get the MimeType (read until we hit 0).
for (i = 0; i < 65; i++) {
MimeType[i] = igetc();
if (MimeType[i] == 0)
break;
}
// The MimeType must be terminated by 0 in the file by the specs.
if (MimeType[i] != 0)
return MP3_NONE;
if (!strcmp(MimeType, "image/jpeg"))
Type = MP3_JPG;
else if (!strcmp(MimeType, "image/png"))
Type = MP3_PNG;
else
Type = MP3_NONE;
PicType = igetc(); // Whether this is a cover, band logo, etc.
// Skip the description.
for (i = 0; i < 65; i++) {
Description[i] = igetc();
if (Description[i] == 0)
break;
}
if (Description[i] != 0)
return MP3_NONE;
return Type;
}
else {
iseek(FrameSize, IL_SEEK_CUR);
}
//if (!strncmp(MimeType, "
} while (!ieof() && itell() < Header->Length);
return Type;
}
//! Reads a MP3 file
ILboolean ilLoadMp3(ILconst_string FileName)
{
ILHANDLE Mp3File;
ILboolean bMp3 = IL_FALSE;
Mp3File = iopenr(FileName);
if (Mp3File == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bMp3;
}
bMp3 = ilLoadMp3F(Mp3File);
icloser(Mp3File);
return bMp3;
}
//! Reads an already-opened MP3 file
ILboolean ilLoadMp3F(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadMp3Internal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a MP3
ILboolean ilLoadMp3L(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadMp3Internal();
}
// Internal function used to load the MP3.
ILboolean iLoadMp3Internal(void)
{
MP3HEAD Header;
ILuint Type;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetMp3Head(&Header))
return IL_FALSE;
if (!iCheckMp3(&Header))
return IL_FALSE;
Type = iFindMp3Pic(&Header);
switch (Type)
{
#ifndef IL_NO_JPG
case MP3_JPG:
return iLoadJpegInternal();
#endif//IL_NO_JPG
#ifndef IL_NO_PNG
case MP3_PNG:
return iLoadPngInternal();
#endif//IL_NO_PNG
// Either a picture was not found, or the MIME type was not recognized.
default:
ilSetError(IL_INVALID_FILE_HEADER);
}
return IL_FALSE;
}
#endif//IL_NO_MP3
+462
View File
@@ -0,0 +1,462 @@
/* NeuQuant Neural-Net Quantization Algorithm
* ------------------------------------------
*
* Copyright (c) 1994 Anthony Dekker
*
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
* See "Kohonen neural networks for optimal colour quantization"
* in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
* for a discussion of the algorithm.
* See also http://www.acm.org/~dekker/NEUQUANT.HTML
*
* Any party obtaining a copy of these files from the author, directly or
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
* world-wide, paid up, royalty-free, nonexclusive right and license to deal
* in this software and documentation files (the "Software"), including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons who receive
* copies from any such party to do so, with the only requirement being
* that this copyright notice remain intact.
*/
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// by Denton Woods
// Last modified: 01/04/2009
//
// Filename: src-IL/src/il_neuquant.c
//
// Description: Heavily modified by Denton Woods.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
// Function definitions
void initnet(ILubyte *thepic, ILint len, ILint sample);
void unbiasnet();
void inxbuild();
ILubyte inxsearch(ILint b, ILint g, ILint r);
void learn();
// four primes near 500 - assume no image has a length so large
// that it is divisible by all four primes
#define prime1 499
#define prime2 491
#define prime3 487
#define prime4 503
#define minpicturebytes (3*prime4) // minimum size for input image
// Network Definitions
// -------------------
#define netsize 256 // number of colours used
#define maxnetpos (netsizethink-1)
#define netbiasshift 4 // bias for colour values
#define ncycles 100 // no. of learning cycles
// defs for freq and bias
#define intbiasshift 16 // bias for fractions
#define intbias (((ILint) 1)<<intbiasshift)
#define gammashift 10 // gamma = 1024
#define gamma (((ILint) 1)<<gammashift)
#define betashift 10
#define beta (intbias>>betashift)// beta = 1/1024
#define betagamma (intbias<<(gammashift-betashift))
// defs for decreasing radius factor
#define initrad (netsize>>3) // for 256 cols, radius starts
#define radiusbiasshift 6 // at 32.0 biased by 6 bits
#define radiusbias (((ILint) 1)<<radiusbiasshift)
#define initradius (initrad*radiusbias) // and decreases by a
#define radiusdec 30 // factor of 1/30 each cycle
// defs for decreasing alpha factor
#define alphabiasshift 10 // alpha starts at 1.0
#define initalpha (((ILint) 1)<<alphabiasshift)
ILint alphadec; // biased by 10 bits
// radbias and alpharadbias used for radpower calculation
#define radbiasshift 8
#define radbias (((ILint) 1)<<radbiasshift)
#define alpharadbshift (alphabiasshift+radbiasshift)
#define alpharadbias (((ILint) 1)<<alpharadbshift)
// Types and Global Variables
// --------------------------
unsigned char *thepicture; // the input image itself
int lengthcount; // lengthcount = H*W*3
int samplefac; // sampling factor 1..30
typedef int pixel[4]; // BGRc
static pixel network[netsize]; // the network itself
int netindex[256]; // for network lookup - really 256
int bias [netsize]; // bias and freq arrays for learning
int freq [netsize];
int radpower[initrad]; // radpower for precomputation
int netsizethink; // number of colors we want to reduce to, 2-256
// Initialise network in range (0,0,0) to (255,255,255) and set parameters
// -----------------------------------------------------------------------
void initnet(ILubyte *thepic, ILint len, ILint sample)
{
ILint i;
ILint *p;
thepicture = thepic;
lengthcount = len;
samplefac = sample;
for (i=0; i<netsizethink; i++) {
p = network[i];
p[0] = p[1] = p[2] = (i << (netbiasshift+8))/netsize;
freq[i] = intbias/netsizethink; // 1/netsize
bias[i] = 0;
}
return;
}
// Unbias network to give byte values 0..255 and record position i to prepare for sort
// -----------------------------------------------------------------------------------
void unbiasnet()
{
ILint i,j;
for (i=0; i<netsizethink; i++) {
for (j=0; j<3; j++)
network[i][j] >>= netbiasshift;
network[i][3] = i; // record colour no
}
return;
}
// Insertion sort of network and building of netindex[0..255] (to do after unbias)
// -------------------------------------------------------------------------------
void inxbuild()
{
ILint i,j,smallpos,smallval;
ILint *p,*q;
ILint previouscol,startpos;
previouscol = 0;
startpos = 0;
for (i=0; i<netsizethink; i++) {
p = network[i];
smallpos = i;
smallval = p[1]; // index on g
// find smallest in i..netsize-1
for (j=i+1; j<netsizethink; j++) {
q = network[j];
if (q[1] < smallval) { // index on g
smallpos = j;
smallval = q[1]; // index on g
}
}
q = network[smallpos];
// swap p (i) and q (smallpos) entries
if (i != smallpos) {
j = q[0]; q[0] = p[0]; p[0] = j;
j = q[1]; q[1] = p[1]; p[1] = j;
j = q[2]; q[2] = p[2]; p[2] = j;
j = q[3]; q[3] = p[3]; p[3] = j;
}
// smallval entry is now in position i
if (smallval != previouscol) {
netindex[previouscol] = (startpos+i)>>1;
for (j=previouscol+1; j<smallval; j++) netindex[j] = i;
previouscol = smallval;
startpos = i;
}
}
netindex[previouscol] = (startpos+maxnetpos)>>1;
for (j=previouscol+1; j<256; j++) netindex[j] = maxnetpos; // really 256
return;
}
// Search for BGR values 0..255 (after net is unbiased) and return colour index
// ----------------------------------------------------------------------------
ILubyte inxsearch(ILint b, ILint g, ILint r)
{
ILint i,j,dist,a,bestd;
ILint *p;
ILint best;
bestd = 1000; // biggest possible dist is 256*3
best = -1;
i = netindex[g]; // index on g
j = i-1; // start at netindex[g] and work outwards
while ((i<netsizethink) || (j>=0)) {
if (i<netsizethink) {
p = network[i];
dist = p[1] - g; // inx key
if (dist >= bestd) i = netsizethink; // stop iter
else {
i++;
if (dist<0) dist = -dist;
a = p[0] - b; if (a<0) a = -a;
dist += a;
if (dist<bestd) {
a = p[2] - r; if (a<0) a = -a;
dist += a;
if (dist<bestd) {bestd=dist; best=p[3];}
}
}
}
if (j>=0) {
p = network[j];
dist = g - p[1]; // inx key - reverse dif
if (dist >= bestd) j = -1; // stop iter
else {
j--;
if (dist<0) dist = -dist;
a = p[0] - b; if (a<0) a = -a;
dist += a;
if (dist<bestd) {
a = p[2] - r; if (a<0) a = -a;
dist += a;
if (dist<bestd) {bestd=dist; best=p[3];}
}
}
}
}
return (ILubyte)best;
}
// Search for biased BGR values
// ----------------------------
ILint contest(ILint b, ILint g, ILint r)
{
// finds closest neuron (min dist) and updates freq
// finds best neuron (min dist-bias) and returns position
// for frequently chosen neurons, freq[i] is high and bias[i] is negative
// bias[i] = gamma*((1/netsize)-freq[i])
ILint i,dist,a,biasdist,betafreq;
ILint bestpos,bestbiaspos,bestd,bestbiasd;
ILint *p,*f, *n;
bestd = ~(((ILint) 1)<<31);
bestbiasd = bestd;
bestpos = -1;
bestbiaspos = bestpos;
p = bias;
f = freq;
for (i=0; i<netsizethink; i++) {
n = network[i];
dist = n[0] - b; if (dist<0) dist = -dist;
a = n[1] - g; if (a<0) a = -a;
dist += a;
a = n[2] - r; if (a<0) a = -a;
dist += a;
if (dist<bestd) {bestd=dist; bestpos=i;}
biasdist = dist - ((*p)>>(intbiasshift-netbiasshift));
if (biasdist<bestbiasd) {bestbiasd=biasdist; bestbiaspos=i;}
betafreq = (*f >> betashift);
*f++ -= betafreq;
*p++ += (betafreq<<gammashift);
}
freq[bestpos] += beta;
bias[bestpos] -= betagamma;
return(bestbiaspos);
}
// Move neuron i towards biased (b,g,r) by factor alpha
// ----------------------------------------------------
void altersingle(ILint alpha, ILint i, ILint b, ILint g, ILint r)
{
ILint *n;
n = network[i]; // alter hit neuron
*n -= (alpha*(*n - b)) / initalpha;
n++;
*n -= (alpha*(*n - g)) / initalpha;
n++;
*n -= (alpha*(*n - r)) / initalpha;
return;
}
// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
// ---------------------------------------------------------------------------------
void alterneigh(ILint rad, ILint i, ILint b, ILint g, ILint r)
{
ILint j,k,lo,hi,a;
ILint *p, *q;
lo = i-rad; if (lo<-1) lo=-1;
hi = i+rad; if (hi>netsizethink) hi=netsizethink;
j = i+1;
k = i-1;
q = radpower;
while ((j<hi) || (k>lo)) {
a = (*(++q));
if (j<hi) {
p = network[j];
*p -= (a*(*p - b)) / alpharadbias;
p++;
*p -= (a*(*p - g)) / alpharadbias;
p++;
*p -= (a*(*p - r)) / alpharadbias;
j++;
}
if (k>lo) {
p = network[k];
*p -= (a*(*p - b)) / alpharadbias;
p++;
*p -= (a*(*p - g)) / alpharadbias;
p++;
*p -= (a*(*p - r)) / alpharadbias;
k--;
}
}
return;
}
// Main Learning Loop
// ------------------
void learn()
{
ILint i,j,b,g,r;
ILint radius,rad,alpha,step,delta,samplepixels;
ILubyte *p;
ILubyte *lim;
alphadec = 30 + ((samplefac-1)/3);
p = thepicture;
lim = thepicture + lengthcount;
samplepixels = lengthcount/(3*samplefac);
delta = samplepixels/ncycles;
alpha = initalpha;
radius = initradius;
rad = radius >> radiusbiasshift;
if (rad <= 1) rad = 0;
for (i=0; i<rad; i++)
radpower[i] = alpha*(((rad*rad - i*i)*radbias)/(rad*rad));
// beginning 1D learning: initial radius=rad
if ((lengthcount%prime1) != 0) step = 3*prime1;
else {
if ((lengthcount%prime2) !=0) step = 3*prime2;
else {
if ((lengthcount%prime3) !=0) step = 3*prime3;
else step = 3*prime4;
}
}
i = 0;
while (i < samplepixels) {
b = p[0] << netbiasshift;
g = p[1] << netbiasshift;
r = p[2] << netbiasshift;
j = contest(b,g,r);
altersingle(alpha,j,b,g,r);
if (rad) alterneigh(rad,j,b,g,r); // alter neighbours
p += step;
if (p >= lim) p -= lengthcount;
i++;
if (i%delta == 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
if (rad <= 1) rad = 0;
for (j=0; j<rad; j++)
radpower[j] = alpha*(((rad*rad - j*j)*radbias)/(rad*rad));
}
}
// finished 1D learning: final alpha=alpha/initalpha;
return;
}
ILimage *iNeuQuant(ILimage *Image, ILuint NumCols)
{
ILimage *TempImage, *NewImage;
ILuint sample, i, j;
netsizethink=NumCols;
NewImage = iCurImage;
iCurImage = Image;
TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);
iCurImage = NewImage;
sample = ilGetInteger(IL_NEU_QUANT_SAMPLE);
if (TempImage == NULL)
return NULL;
initnet(TempImage->Data, TempImage->SizeOfData, sample);
learn();
unbiasnet();
NewImage = (ILimage*)icalloc(sizeof(ILimage), 1);
if (NewImage == NULL) {
ilCloseImage(TempImage);
return NULL;
}
NewImage->Data = (ILubyte*)ialloc(TempImage->SizeOfData / 3);
if (NewImage->Data == NULL) {
ilCloseImage(TempImage);
ifree(NewImage);
return NULL;
}
ilCopyImageAttr(NewImage, Image);
NewImage->Bpp = 1;
NewImage->Bps = Image->Width;
NewImage->SizeOfPlane = NewImage->Bps * Image->Height;
NewImage->SizeOfData = NewImage->SizeOfPlane;
NewImage->Format = IL_COLOUR_INDEX;
NewImage->Type = IL_UNSIGNED_BYTE;
NewImage->Pal.PalSize = netsizethink * 3;
NewImage->Pal.PalType = IL_PAL_BGR24;
NewImage->Pal.Palette = (ILubyte*)ialloc(256*3);
if (NewImage->Pal.Palette == NULL) {
ilCloseImage(TempImage);
ilCloseImage(NewImage);
return NULL;
}
for (i = 0, j = 0; i < (unsigned)netsizethink; i++, j += 3) {
NewImage->Pal.Palette[j ] = network[i][0];
NewImage->Pal.Palette[j+1] = network[i][1];
NewImage->Pal.Palette[j+2] = network[i][2];
}
inxbuild();
for (i = 0, j = 0; j < TempImage->SizeOfData; i++, j += 3) {
NewImage->Data[i] = inxsearch(
TempImage->Data[j], TempImage->Data[j+1], TempImage->Data[j+2]);
}
ilCloseImage(TempImage);
return NewImage;
}
+227
View File
@@ -0,0 +1,227 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/19/2009
//
// Filename: src-IL/src/il_nvidia.cpp
//
// Description: Implements access to the nVidia Texture Tools library.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include "il_dds.h"
#include "il_manip.h"
#include <limits.h>
#ifdef IL_USE_DXTC_NVIDIA
#include <nvtt/nvtt.h>
#include <nvcore/Memory.h>
using namespace nvtt;
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "nvcore.lib")
#pragma comment(lib, "nvtt.lib")
#else
#pragma comment(lib, "nvcore-d.lib")
#pragma comment(lib, "nvtt-d.lib")
#endif
#endif
#endif
struct ilOutputHandlerMem : public nvtt::OutputHandler
{
ilOutputHandlerMem(ILuint Width, ILuint Height, ILenum DxtType)
{
Width = Width + (4 - (Width % 4)) % 4; // Operates on 4x4 blocks,
Height = Height + (4 - (Height % 4)) % 4; // so gives extra room.
switch (DxtType)
{
case IL_DXT1:
case IL_DXT1A:
Size = Width * Height / 2;
break;
case IL_DXT3:
case IL_DXT5:
Size = Width * Height;
break;
default: // NVTT does not accept DXT2 or DXT4.
// Should error somehow...
break;
}
NewData = (ILubyte*)ialloc(Size);
if (NewData == NULL)
return;
Temp = NewData;
}
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
{
// ignore.
}
virtual bool writeData(const void *data, int size)
{
memcpy(Temp, data, size);
Temp += size;
return true;
}
ILubyte *NewData, *Temp;
ILuint Size;
};
//! Compresses data to a DXT format using nVidia's Texture Tools library.
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
// DxtSize is used to return the size in bytes of the DXTC data returned.
ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
{
if (Data == NULL) { // We cannot operate on a null pointer.
ilSetError(IL_INVALID_PARAM);
return NULL;
}
// The nVidia Texture Tools library does not support volume textures yet.
if (Depth != 1) {
ilSetError(IL_INVALID_PARAM);
return NULL;
}
InputOptions inputOptions;
inputOptions.setTextureLayout(TextureType_2D, Width, Height);
inputOptions.setMipmapData(Data, Width, Height);
inputOptions.setMipmapGeneration(false, -1); //@TODO: Use this in certain cases.
OutputOptions outputOptions;
ilOutputHandlerMem outputHandler(Width, Height, DxtFormat);
outputOptions.setOutputHeader(false);
outputOptions.setOutputHandler(&outputHandler);
if (outputHandler.NewData == NULL)
return NULL;
CompressionOptions compressionOptions;
switch (DxtFormat)
{
case IL_DXT1:
compressionOptions.setFormat(Format_DXT1);
break;
case IL_DXT1A:
compressionOptions.setFormat(Format_DXT1a);
break;
case IL_DXT3:
compressionOptions.setFormat(Format_DXT1);
break;
case IL_DXT5:
compressionOptions.setFormat(Format_DXT5);
break;
default: // Does not support DXT2 or DXT4.
ilSetError(IL_INVALID_PARAM);
break;
}
Compressor compressor;
compressor.process(inputOptions, compressionOptions, outputOptions);
*DxtSize = outputHandler.Size;
return outputHandler.NewData;
}
//
//
// The following is just a repeat of above, but it works generically on file streams or lumps.
// @TODO: Merge these two together.
//
//
struct ilOutputHandlerFile : public nvtt::OutputHandler
{
ilOutputHandlerFile(ILuint Width, ILuint Height, ILenum DxtType)
{
return;
}
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
{
// ignore.
}
virtual bool writeData(const void *data, int size)
{
if (iwrite(data, 1, size) == size)
return true;
return false;
}
};
//! Compresses data to a DXT format using nVidia's Texture Tools library.
// This version is supposed to be completely internal to DevIL.
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
ILuint ilNVidiaCompressDXTFile(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat)
{
ILuint FilePos = itellw();
// The nVidia Texture Tools library does not support volume textures yet.
if (Depth != 1) {
ilSetError(IL_INVALID_PARAM);
return 0;
}
InputOptions inputOptions;
inputOptions.setTextureLayout(TextureType_2D, Width, Height);
inputOptions.setMipmapData(Data, Width, Height);
inputOptions.setMipmapGeneration(false, -1); //@TODO: Use this in certain cases.
OutputOptions outputOptions;
ilOutputHandlerFile outputHandler(Width, Height, DxtFormat);
outputOptions.setOutputHeader(false);
outputOptions.setOutputHandler(&outputHandler);
CompressionOptions compressionOptions;
switch (DxtFormat)
{
case IL_DXT1:
compressionOptions.setFormat(Format_DXT1);
break;
case IL_DXT1A:
compressionOptions.setFormat(Format_DXT1a);
break;
case IL_DXT3:
compressionOptions.setFormat(Format_DXT1);
break;
case IL_DXT5:
compressionOptions.setFormat(Format_DXT5);
break;
default: // Does not support DXT2 or DXT4.
ilSetError(IL_INVALID_PARAM);
break;
}
Compressor compressor;
compressor.process(inputOptions, compressionOptions, outputOptions);
return itellw() - FilePos; // Return the number of characters written.
}
#else
// Let's have this so that the function is always created and exported, even if it does nothing.
ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
{
//@TODO: Do we need to set an error message?
return NULL;
}
#endif//IL_NO_DXTC_NVIDIA
File diff suppressed because it is too large Load Diff
+207
View File
@@ -0,0 +1,207 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_pcd.c
//
// Description: Reads from a Kodak PhotoCD (.pcd) file.
// Note: The code here is sloppy - I had to convert it from Pascal,
// which I've never even attempted to read before...enjoy! =)
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PCD
#include "il_manip.h"
ILboolean iLoadPcdInternal(void);
//! Reads a .pcd file
ILboolean ilLoadPcd(ILconst_string FileName)
{
ILHANDLE PcdFile;
ILboolean bPcd = IL_FALSE;
PcdFile = iopenr(FileName);
if (PcdFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPcd;
}
bPcd = ilLoadPcdF(PcdFile);
icloser(PcdFile);
return bPcd;
}
//! Reads an already-opened .pcd file
ILboolean ilLoadPcdF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPcdInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .pcd file
ILboolean ilLoadPcdL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPcdInternal();
}
void YCbCr2RGB(ILubyte Y, ILubyte Cb, ILubyte Cr, ILubyte *r, ILubyte *g, ILubyte *b)
{
static const ILdouble c11 = 0.0054980*256;
static const ILdouble c12 = 0.0000000*256;
static const ILdouble c13 = 0.0051681*256;
static const ILdouble c21 = 0.0054980*256;
static const ILdouble c22 =-0.0015446*256;
static const ILdouble c23 =-0.0026325*256;
static const ILdouble c31 = 0.0054980*256;
static const ILdouble c32 = 0.0079533*256;
static const ILdouble c33 = 0.0000000*256;
ILint r1, g1, b1;
r1 = (ILint)(c11*Y + c12*(Cb-156) + c13*(Cr-137));
g1 = (ILint)(c21*Y + c22*(Cb-156) + c23*(Cr-137));
b1 = (ILint)(c31*Y + c32*(Cb-156) + c33*(Cr-137));
if (r1 < 0)
*r = 0;
else if (r1 > 255)
*r = 255;
else
*r = r1;
if (g1 < 0)
*g = 0;
else if (g1 > 255)
*g = 255;
else
*g = g1;
if (b1 < 0)
*b = 0;
else if (b1 > 255)
*b = 255;
else
*b = b1;
return;
}
ILboolean iLoadPcdInternal()
{
ILubyte VertOrientation;
ILuint Width, Height, i, Total, x, CurPos = 0;
ILubyte *Y1=NULL, *Y2=NULL, *CbCr=NULL, r = 0, g = 0, b = 0;
ILuint PicNum;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
iseek(72, IL_SEEK_CUR);
if (iread(&VertOrientation, 1, 1) != 1)
return IL_FALSE;
iseek(-72, IL_SEEK_CUR); // Can't rewind
PicNum = iGetInt(IL_PCD_PICNUM);
switch (PicNum)
{
case 0:
iseek(0x02000, IL_SEEK_CUR);
Width = 192;
Height = 128;
break;
case 1:
iseek(0x0b800, IL_SEEK_CUR);
Width = 384;
Height = 256;
break;
case 2:
iseek(0x30000, IL_SEEK_CUR);
Width = 768;
Height = 512;
break;
default:
ilSetError(IL_INVALID_PARAM);
return IL_FALSE;
}
if (itell() == IL_EOF) // Supposed to have data here.
return IL_FALSE;
Y1 = (ILubyte*)ialloc(Width);
Y2 = (ILubyte*)ialloc(Width);
CbCr = (ILubyte*)ialloc(Width);
if (Y1 == NULL || Y2 == NULL || CbCr == NULL) {
ifree(Y1);
ifree(Y2);
ifree(CbCr);
return IL_FALSE;
}
if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
Total = Height >> 1;
for (i = 0; i < Total; i++) {
iread(Y1, 1, Width);
iread(Y2, 1, Width);
if (iread(CbCr, 1, Width) != Width) { // Only really need to check the last one.
ifree(Y1);
ifree(Y2);
ifree(CbCr);
return IL_FALSE;
}
for (x = 0; x < Width; x++) {
YCbCr2RGB(Y1[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
iCurImage->Data[CurPos++] = r;
iCurImage->Data[CurPos++] = g;
iCurImage->Data[CurPos++] = b;
}
for (x = 0; x < Width; x++) {
YCbCr2RGB(Y2[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
iCurImage->Data[CurPos++] = r;
iCurImage->Data[CurPos++] = g;
iCurImage->Data[CurPos++] = b;
}
}
ifree(Y1);
ifree(Y2);
ifree(CbCr);
// Not sure how it is...the documentation is hard to understand
if ((VertOrientation & 0x3F) != 8)
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
else
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return ilFixImage();
}
#endif//IL_NO_PCD
+740
View File
@@ -0,0 +1,740 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_pcx.c
//
// Description: Reads and writes from/to a .pcx file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PCX
#include "il_pcx.h"
#include "il_manip.h"
//! Checks if the file specified in FileName is a valid .pcx file.
ILboolean ilIsValidPcx(ILconst_string FileName)
{
ILHANDLE PcxFile;
ILboolean bPcx = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("pcx"))) {
ilSetError(IL_INVALID_EXTENSION);
return bPcx;
}
PcxFile = iopenr(FileName);
if (PcxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPcx;
}
bPcx = ilIsValidPcxF(PcxFile);
icloser(PcxFile);
return bPcx;
}
//! Checks if the ILHANDLE contains a valid .pcx file at the current position.
ILboolean ilIsValidPcxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidPcx();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .pcx lump.
ILboolean ilIsValidPcxL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidPcx();
}
// Internal function obtain the .pcx header from the current file.
ILboolean iGetPcxHead(PCXHEAD *Head)
{
Head->Manufacturer = igetc();
Head->Version = igetc();
Head->Encoding = igetc();
Head->Bpp = igetc();
Head->Xmin = GetLittleUShort();
Head->Ymin = GetLittleUShort();
Head->Xmax = GetLittleUShort();
Head->Ymax = GetLittleUShort();
Head->HDpi = GetLittleUShort();
Head->VDpi = GetLittleUShort();
iread(Head->ColMap, 1, 48);
Head->Reserved = igetc();
Head->NumPlanes = igetc();
Head->Bps = GetLittleUShort();
Head->PaletteInfo = GetLittleUShort();
Head->HScreenSize = GetLittleUShort();
Head->VScreenSize = GetLittleUShort();
iread(Head->Filler, 1, 54);
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidPcx()
{
PCXHEAD Head;
if (!iGetPcxHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(PCXHEAD), IL_SEEK_CUR);
return iCheckPcx(&Head);
}
// Internal function used to check if the HEADER is a valid .pcx header.
// Should we also do a check on Header->Bpp?
ILboolean iCheckPcx(PCXHEAD *Header)
{
ILuint Test;
// Got rid of the Reserved check, because I've seen some .pcx files with invalid values in it.
if (Header->Manufacturer != 10 || Header->Encoding != 1/* || Header->Reserved != 0*/)
return IL_FALSE;
// Try to support all pcx versions, as they only differ in allowed formats...
// Let's hope it works.
if(Header->Version != 5 && Header->Version != 0 && Header->Version != 2 &&
Header->VDpi != 3 && Header->VDpi != 4)
return IL_FALSE;
// See if the padding size is correct
Test = Header->Xmax - Header->Xmin + 1;
if (Header->Bpp >= 8) {
if (Test & 1) {
if (Header->Bps != Test + 1)
return IL_FALSE;
}
else {
if (Header->Bps != Test) // No padding
return IL_FALSE;
}
}
/* for (i = 0; i < 54; i++) { useless check
if (Header->Filler[i] != 0)
return IL_FALSE;
} */
return IL_TRUE;
}
//! Reads a .pcx file
ILboolean ilLoadPcx(ILconst_string FileName)
{
ILHANDLE PcxFile;
ILboolean bPcx = IL_FALSE;
PcxFile = iopenr(FileName);
if (PcxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPcx;
}
bPcx = ilLoadPcxF(PcxFile);
icloser(PcxFile);
return bPcx;
}
//! Reads an already-opened .pcx file
ILboolean ilLoadPcxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPcxInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .pcx
ILboolean ilLoadPcxL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPcxInternal();
}
// Internal function used to load the .pcx.
ILboolean iLoadPcxInternal()
{
PCXHEAD Header;
ILboolean bPcx = IL_FALSE;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return bPcx;
}
if (!iGetPcxHead(&Header))
return IL_FALSE;
if (!iCheckPcx(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
bPcx = iUncompressPcx(&Header);
if (!bPcx)
return IL_FALSE;
return ilFixImage();
}
// Internal function to uncompress the .pcx (all .pcx files are rle compressed)
ILboolean iUncompressPcx(PCXHEAD *Header)
{
//changed decompression loop 2003-09-01
//From the pcx spec: "There should always
//be a decoding break at the end of each scan line.
//But there will not be a decoding break at the end of
//each plane within each scan line."
//This is now handled correctly (hopefully ;) )
ILubyte ByteHead, Colour, *ScanLine /* For all planes */;
ILuint ScanLineSize;
ILuint c, i, x, y;
if (Header->Bpp < 8) {
/*ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;*/
return iUncompressSmall(Header);
}
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
switch (iCurImage->Bpp)
{
case 1:
iCurImage->Format = IL_COLOUR_INDEX;
iCurImage->Pal.PalType = IL_PAL_RGB24;
iCurImage->Pal.PalSize = 256 * 3; // Need to find out for sure...
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
if (iCurImage->Pal.Palette == NULL) {
return IL_FALSE;
}
break;
//case 2: // No 16-bit images in the pcx format!
case 3:
iCurImage->Format = IL_RGB;
iCurImage->Pal.Palette = NULL;
iCurImage->Pal.PalSize = 0;
iCurImage->Pal.PalType = IL_PAL_NONE;
break;
case 4:
iCurImage->Format = IL_RGBA;
iCurImage->Pal.Palette = NULL;
iCurImage->Pal.PalSize = 0;
iCurImage->Pal.PalType = IL_PAL_NONE;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
ScanLineSize = iCurImage->Bpp*Header->Bps;
ScanLine = (ILubyte*)ialloc(ScanLineSize);
if (ScanLine == NULL) {
return IL_FALSE;
}
//changed 2003-09-01
//having the decoding code twice is error-prone,
//so I made iUnCache() smart enough to grasp
//if iPreCache() wasn't called and call it
//anyways.
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
iPreCache(iCurImage->SizeOfData / 4);
for (y = 0; y < iCurImage->Height; y++) {
x = 0;
//read scanline
while (x < ScanLineSize) {
if (iread(&ByteHead, 1, 1) != 1) {
iUnCache();
goto file_read_error;
}
if ((ByteHead & 0xC0) == 0xC0) {
ByteHead &= 0x3F;
if (iread(&Colour, 1, 1) != 1) {
iUnCache();
goto file_read_error;
}
if (x + ByteHead > ScanLineSize) {
iUnCache();
goto file_read_error;
}
for (i = 0; i < ByteHead; i++) {
ScanLine[x++] = Colour;
}
}
else {
ScanLine[x++] = ByteHead;
}
}
//convert plane-separated scanline into index, rgb or rgba pixels.
//there might be a padding byte at the end of each scanline...
for (x = 0; x < iCurImage->Width; x++) {
for(c = 0; c < iCurImage->Bpp; c++) {
iCurImage->Data[y * iCurImage->Bps + x * iCurImage->Bpp + c] =
ScanLine[x + c * Header->Bps];
}
}
}
iUnCache();
// Read in the palette
if (Header->Version == 5 && iCurImage->Bpp == 1) {
x = itell();
if (iread(&ByteHead, 1, 1) == 0) { // If true, assume that we have a luminance image.
ilGetError(); // Get rid of the IL_FILE_READ_ERROR.
iCurImage->Format = IL_LUMINANCE;
if (iCurImage->Pal.Palette)
ifree(iCurImage->Pal.Palette);
iCurImage->Pal.PalSize = 0;
iCurImage->Pal.PalType = IL_PAL_NONE;
}
else {
if (ByteHead != 12) // Some Quake2 .pcx files don't have this byte for some reason.
iseek(-1, IL_SEEK_CUR);
if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
goto file_read_error;
}
}
ifree(ScanLine);
return IL_TRUE;
file_read_error:
ifree(ScanLine);
//added 2003-09-01
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
ILboolean iUncompressSmall(PCXHEAD *Header)
{
ILuint i = 0, j, k, c, d, x, y, Bps;
ILubyte HeadByte, Colour, Data = 0, *ScanLine;
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
switch (Header->NumPlanes)
{
case 1:
iCurImage->Format = IL_LUMINANCE;
break;
case 4:
iCurImage->Format = IL_COLOUR_INDEX;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
if (Header->NumPlanes == 1 && Header->Bpp == 1) {
for (j = 0; j < iCurImage->Height; j++) {
i = 0; //number of written pixels
while (i < iCurImage->Width) {
if (iread(&HeadByte, 1, 1) != 1)
return IL_FALSE;
if (HeadByte >= 192) {
HeadByte -= 192;
if (iread(&Data, 1, 1) != 1)
return IL_FALSE;
for (c = 0; c < HeadByte; c++) {
k = 128;
for (d = 0; d < 8 && i < iCurImage->Width; d++) {
iCurImage->Data[j * iCurImage->Width + i++] = ((Data & k) != 0 ? 255 : 0);
k >>= 1;
}
}
}
else {
k = 128;
for (c = 0; c < 8 && i < iCurImage->Width; c++) {
iCurImage->Data[j * iCurImage->Width + i++] = ((HeadByte & k) != 0 ? 255 : 0);
k >>= 1;
}
}
}
//if(Data != 0)
//changed 2003-09-01:
//There has to be an even number of bytes per line in a pcx.
//One byte can hold up to 8 bits, so Width/8 bytes
//are needed to hold a 1 bit per pixel image line.
//If Width/8 is even no padding is needed,
//one pad byte has to be read otherwise.
//(let's hope the above is true ;-))
if(!((iCurImage->Width >> 3) & 0x1))
igetc(); // Skip pad byte
}
}
else if (Header->NumPlanes == 4 && Header->Bpp == 1){ // 4-bit images
//changed decoding 2003-09-10 (was buggy)...could need a speedup
Bps = Header->Bps * Header->NumPlanes * 8;
iCurImage->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes).
ScanLine = (ILubyte*)ialloc(Bps);
if (iCurImage->Pal.Palette == NULL || ScanLine == NULL) {
ifree(ScanLine);
ifree(iCurImage->Pal.Palette);
return IL_FALSE;
}
memcpy(iCurImage->Pal.Palette, Header->ColMap, 16 * 3);
iCurImage->Pal.PalSize = 16 * 3;
iCurImage->Pal.PalType = IL_PAL_RGB24;
memset(iCurImage->Data, 0, iCurImage->SizeOfData);
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
iPreCache(iCurImage->SizeOfData / 4);
for (y = 0; y < iCurImage->Height; y++) {
x = 0;
while (x < Bps) {
if (iread(&HeadByte, 1, 1) != 1) {
iUnCache();
ifree(ScanLine);
return IL_FALSE;
}
if ((HeadByte & 0xC0) == 0xC0) {
HeadByte &= 0x3F;
if (iread(&Colour, 1, 1) != 1) {
iUnCache();
ifree(ScanLine);
return IL_FALSE;
}
for (i = 0; i < HeadByte; i++) {
k = 128;
for (j = 0; j < 8 && x < Bps; j++) {
ScanLine[x++] = (Colour & k)?1:0;
k >>= 1;
}
}
}
else {
k = 128;
for (j = 0; j < 8 && x < Bps; j++) {
ScanLine[x++] = (HeadByte & k)?1:0;
k >>= 1;
}
}
}
for (x = 0; x < iCurImage->Width; x++) { // 'Cleverly' ignores the pad bytes. ;)
for(c = 0; c < Header->NumPlanes; c++)
iCurImage->Data[y * iCurImage->Width + x] |= ScanLine[x + c*Header->Bps*8] << c;
}
}
iUnCache();
ifree(ScanLine);
}
else {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
return IL_TRUE;
}
//! Writes a .pcx file
ILboolean ilSavePcx(const ILstring FileName)
{
ILHANDLE PcxFile;
ILuint PcxSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
PcxFile = iopenw(FileName);
if (PcxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
PcxSize = ilSavePcxF(PcxFile);
iclosew(PcxFile);
if (PcxSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a .pcx to an already-opened file
ILuint ilSavePcxF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSavePcxInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a .pcx to a memory "lump"
ILuint ilSavePcxL(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSavePcxInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to save the .pcx.
ILboolean iSavePcxInternal()
{
ILuint i, c, PalSize;
ILpal *TempPal;
ILimage *TempImage = iCurImage;
ILubyte *TempData;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
switch (iCurImage->Format)
{
case IL_LUMINANCE:
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
break;
case IL_BGR:
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
break;
case IL_BGRA:
TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
break;
default:
if (iCurImage->Bpc > 1) {
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
}
}
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
TempData = iGetFlipped(TempImage);
if (TempData == NULL) {
if (TempImage != iCurImage) {
ilCloseImage(TempImage);
}
return IL_FALSE;
}
}
else {
TempData = TempImage->Data;
}
iputc(0xA); // Manufacturer - always 10
iputc(0x5); // Version Number - always 5
iputc(0x1); // Encoding - always 1
iputc(0x8); // Bits per channel
SaveLittleUShort(0); // X Minimum
SaveLittleUShort(0); // Y Minimum
SaveLittleUShort((ILushort)(iCurImage->Width - 1));
SaveLittleUShort((ILushort)(iCurImage->Height - 1));
SaveLittleUShort(0);
SaveLittleUShort(0);
// Useless palette info?
for (i = 0; i < 48; i++) {
iputc(0);
}
iputc(0x0); // Reserved - always 0
iputc(iCurImage->Bpp); // Number of planes - only 1 is supported right now
SaveLittleUShort((ILushort)(iCurImage->Width & 1 ? iCurImage->Width + 1 : iCurImage->Width)); // Bps
SaveLittleUShort(0x1); // Palette type - ignored?
// Mainly filler info
for (i = 0; i < 58; i++) {
iputc(0x0);
}
// Output data
for (i = 0; i < TempImage->Height; i++) {
for (c = 0; c < TempImage->Bpp; c++) {
encLine(TempData + TempImage->Bps * i + c, TempImage->Width, (ILubyte)(TempImage->Bpp - 1));
}
}
// Automatically assuming we have a palette...dangerous!
// Also assuming 3 bpp palette
iputc(0xC); // Pad byte must have this value
// If the current image has a palette, take care of it
if (TempImage->Format == IL_COLOUR_INDEX) {
// If the palette in .pcx format, write it directly
if (TempImage->Pal.PalType == IL_PAL_RGB24) {
iwrite(TempImage->Pal.Palette, 1, TempImage->Pal.PalSize);
}
else {
TempPal = iConvertPal(&TempImage->Pal, IL_PAL_RGB24);
if (TempPal == NULL) {
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
ifree(TempData);
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_FALSE;
}
iwrite(TempPal->Palette, 1, TempPal->PalSize);
ifree(TempPal->Palette);
ifree(TempPal);
}
}
// If the palette is not all 256 colours, we have to pad it.
PalSize = 768 - iCurImage->Pal.PalSize;
for (i = 0; i < PalSize; i++) {
iputc(0x0);
}
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
ifree(TempData);
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_TRUE;
}
// Routine used from ZSoft's pcx documentation
ILuint encput(ILubyte byt, ILubyte cnt)
{
if (cnt) {
if ((cnt == 1) && (0xC0 != (0xC0 & byt))) {
if (IL_EOF == iputc(byt))
return(0); /* disk write error (probably full) */
return(1);
}
else {
if (IL_EOF == iputc((ILubyte)((ILuint)0xC0 | cnt)))
return (0); /* disk write error */
if (IL_EOF == iputc(byt))
return (0); /* disk write error */
return (2);
}
}
return (0);
}
// This subroutine encodes one scanline and writes it to a file.
// It returns number of bytes written into outBuff, 0 if failed.
ILuint encLine(ILubyte *inBuff, ILint inLen, ILubyte Stride)
{
ILubyte _this, last;
ILint srcIndex, i;
ILint total;
ILubyte runCount; // max single runlength is 63
total = 0;
runCount = 1;
last = *(inBuff);
// Find the pixel dimensions of the image by calculating
//[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1].
//Then calculate how many bytes are in a "run"
for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
inBuff += Stride;
_this = *(++inBuff);
if (_this == last) { // There is a "run" in the data, encode it
runCount++;
if (runCount == 63) {
if (! (i = encput(last, runCount)))
return (0);
total += i;
runCount = 0;
}
}
else { // No "run" - _this != last
if (runCount) {
if (! (i = encput(last, runCount)))
return(0);
total += i;
}
last = _this;
runCount = 1;
}
} // endloop
if (runCount) { // finish up
if (! (i = encput(last, runCount)))
return (0);
if (inLen % 2)
iputc(0);
return (total + i);
}
else {
if (inLen % 2)
iputc(0);
}
return (total);
}
#endif//IL_NO_PCX
+426
View File
@@ -0,0 +1,426 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_pic.c
//
// Description: Softimage Pic (.pic) functions
// Lots of this code is taken from Paul Bourke's Softimage Pic code at
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PIC
#include "il_pic.h"
#include "il_manip.h"
#include <string.h>
//! Checks if the file specified in FileName is a valid .pic file.
ILboolean ilIsValidPic(ILconst_string FileName)
{
ILHANDLE PicFile;
ILboolean bPic = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("pic"))) {
ilSetError(IL_INVALID_EXTENSION);
return bPic;
}
PicFile = iopenr(FileName);
if (PicFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPic;
}
bPic = ilIsValidPicF(PicFile);
icloser(PicFile);
return bPic;
}
//! Checks if the ILHANDLE contains a valid .pic file at the current position.
ILboolean ilIsValidPicF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidPic();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .pic lump.
ILboolean ilIsValidPicL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidPic();
}
// Internal function used to get the .pic header from the current file.
ILboolean iGetPicHead(PIC_HEAD *Header)
{
Header->Magic = GetBigInt();
Header->Version = GetBigFloat();
iread(Header->Comment, 1, 80);
iread(Header->Id, 1, 4);
Header->Width = GetBigShort();
Header->Height = GetBigShort();
Header->Ratio = GetBigFloat();
Header->Fields = GetBigShort();
Header->Padding = GetBigShort();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidPic()
{
PIC_HEAD Head;
if (!iGetPicHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(PIC_HEAD), IL_SEEK_CUR); // Go ahead and restore to previous state
return iCheckPic(&Head);
}
// Internal function used to check if the header is a valid .pic header.
ILboolean iCheckPic(PIC_HEAD *Header)
{
if (Header->Magic != 0x5380F634)
return IL_FALSE;
if (strncmp((const char*)Header->Id, "PICT", 4))
return IL_FALSE;
if (Header->Width == 0)
return IL_FALSE;
if (Header->Height == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a .pic file
ILboolean ilLoadPic(ILconst_string FileName)
{
ILHANDLE PicFile;
ILboolean bPic = IL_FALSE;
PicFile = iopenr(FileName);
if (PicFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPic;
}
bPic = ilLoadPicF(PicFile);
icloser(PicFile);
return bPic;
}
//! Reads an already-opened .pic file
ILboolean ilLoadPicF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPicInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .pic
ILboolean ilLoadPicL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPicInternal();
}
// Internal function used to load the .pic
ILboolean iLoadPicInternal()
{
ILuint Alpha = IL_FALSE;
ILubyte Chained;
CHANNEL *Channel = NULL, *Channels = NULL, *Prev;
PIC_HEAD Header;
ILboolean Read;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetPicHead(&Header))
return IL_FALSE;
if (!iCheckPic(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Read channels
do {
if (Channel == NULL) {
Channel = Channels = (CHANNEL*)ialloc(sizeof(CHANNEL));
if (Channels == NULL)
return IL_FALSE;
}
else {
Channels->Next = (CHANNEL*)ialloc(sizeof(CHANNEL));
if (Channels->Next == NULL) {
// Clean up the list before erroring out.
while (Channel) {
Prev = Channel;
Channel = (CHANNEL*)Channel->Next;
ifree(Prev);
}
return IL_FALSE;
}
Channels = (CHANNEL*)Channels->Next;
}
Channels->Next = NULL;
Chained = igetc();
Channels->Size = igetc();
Channels->Type = igetc();
Channels->Chan = igetc();
if (ieof()) {
Read = IL_FALSE;
goto finish;
}
// See if we have an alpha channel in there
if (Channels->Chan & PIC_ALPHA_CHANNEL)
Alpha = IL_TRUE;
} while (Chained);
if (Alpha) { // Has an alpha channel
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
Read = IL_FALSE;
goto finish; // Have to destroy Channels first.
}
}
else { // No alpha channel
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
Read = IL_FALSE;
goto finish; // Have to destroy Channels first.
}
}
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
Read = readScanlines((ILuint*)iCurImage->Data, Header.Width, Header.Height, Channel, Alpha);
finish:
// Destroy channels
while (Channel) {
Prev = Channel;
Channel = (CHANNEL*)Channel->Next;
ifree(Prev);
}
if (Read == IL_FALSE)
return IL_FALSE;
return ilFixImage();
}
ILboolean readScanlines(ILuint *image, ILint width, ILint height, CHANNEL *channel, ILuint alpha)
{
ILint i;
ILuint *scan;
(void)alpha;
for (i = height - 1; i >= 0; i--) {
scan = image + i * width;
if (!readScanline((ILubyte *)scan, width, channel, alpha ? 4 : 3)) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
}
return IL_TRUE;
}
ILuint readScanline(ILubyte *scan, ILint width, CHANNEL *channel, ILint bytes)
{
ILint noCol;
ILint off[4];
ILuint status=0;
while (channel) {
noCol = 0;
if(channel->Chan & PIC_RED_CHANNEL) {
off[noCol] = 0;
noCol++;
}
if(channel->Chan & PIC_GREEN_CHANNEL) {
off[noCol] = 1;
noCol++;
}
if(channel->Chan & PIC_BLUE_CHANNEL) {
off[noCol] = 2;
noCol++;
}
if(channel->Chan & PIC_ALPHA_CHANNEL) {
off[noCol] = 3;
noCol++;
//@TODO: Find out if this is possible.
if (bytes == 3) // Alpha channel in a 24-bit image. Do not know what to do with this.
return 0;
}
switch(channel->Type & 0x0F)
{
case PIC_UNCOMPRESSED:
status = channelReadRaw(scan, width, noCol, off, bytes);
break;
case PIC_PURE_RUN_LENGTH:
status = channelReadPure(scan, width, noCol, off, bytes);
break;
case PIC_MIXED_RUN_LENGTH:
status = channelReadMixed(scan, width, noCol, off, bytes);
break;
}
if (!status)
break;
channel = (CHANNEL*)channel->Next;
}
return status;
}
ILboolean channelReadRaw(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
{
ILint i, j;
for (i = 0; i < width; i++) {
if (ieof())
return IL_FALSE;
for (j = 0; j < noCol; j++)
if (iread(&scan[off[j]], 1, 1) != 1)
return IL_FALSE;
scan += bytes;
}
return IL_TRUE;
}
ILboolean channelReadPure(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
{
ILubyte col[4];
ILint count;
int i, j, k;
for (i = width; i > 0; ) {
count = igetc();
if (count == IL_EOF)
return IL_FALSE;
if (count > width)
count = width;
i -= count;
if (ieof())
return IL_FALSE;
for (j = 0; j < noCol; j++)
if (iread(&col[j], 1, 1) != 1)
return IL_FALSE;
for (k = 0; k < count; k++, scan += bytes) {
for(j = 0; j < noCol; j++)
scan[off[j] + k] = col[j];
}
}
return IL_TRUE;
}
ILboolean channelReadMixed(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
{
ILint count;
int i, j, k;
ILubyte col[4];
for(i = 0; i < width; i += count) {
if (ieof())
return IL_FALSE;
count = igetc();
if (count == IL_EOF)
return IL_FALSE;
if (count >= 128) { // Repeated sequence
if (count == 128) { // Long run
count = GetBigUShort();
if (ieof()) {
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
}
else
count -= 127;
// We've run past...
if ((i + count) > width) {
//fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Repeat) [%d + %d > %d] (NC=%d)\n", i, count, width, noCol);
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
for (j = 0; j < noCol; j++)
if (iread(&col[j], 1, 1) != 1) {
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
for (k = 0; k < count; k++, scan += bytes) {
for (j = 0; j < noCol; j++)
scan[off[j]] = col[j];
}
} else { // Raw sequence
count++;
if ((i + count) > width) {
//fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Raw) [%d + %d > %d] (NC=%d)\n", i, count, width, noCol);
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
for (k = count; k > 0; k--, scan += bytes) {
for (j = 0; j < noCol; j++)
if (iread(&scan[off[j]], 1, 1) != 1) {
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
}
}
}
return IL_TRUE;
}
#endif//IL_NO_PIC
+159
View File
@@ -0,0 +1,159 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_pix.c
//
// Description: Reads from an Alias | Wavefront .pix file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PIX
#include "il_manip.h"
#include "il_endian.h"
#ifdef _MSC_VER
#pragma pack(push, pix_struct, 1)
#endif
typedef struct PIXHEAD
{
ILushort Width;
ILushort Height;
ILushort OffX;
ILushort OffY;
ILushort Bpp;
} IL_PACKSTRUCT PIXHEAD;
#ifdef _MSC_VER
#pragma pack(pop, pix_struct)
#endif
ILboolean iCheckPix(PIXHEAD *Header);
ILboolean iLoadPixInternal(void);
// Internal function used to get the Pix header from the current file.
ILboolean iGetPixHead(PIXHEAD *Header)
{
Header->Width = GetBigUShort();
Header->Height = GetBigUShort();
Header->OffX = GetBigUShort();
Header->OffY = GetBigUShort();
Header->Bpp = GetBigUShort();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidPix()
{
PIXHEAD Head;
if (!iGetPixHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(PIXHEAD), IL_SEEK_CUR);
return iCheckPix(&Head);
}
// Internal function used to check if the HEADER is a valid Pix header.
ILboolean iCheckPix(PIXHEAD *Header)
{
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
if (Header->Bpp != 24)
return IL_FALSE;
//if (Header->OffY != Header->Height)
// return IL_FALSE;
return IL_TRUE;
}
//! Reads a Pix file
ILboolean ilLoadPix(ILconst_string FileName)
{
ILHANDLE PixFile;
ILboolean bPix = IL_FALSE;
PixFile = iopenr(FileName);
if (PixFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPix;
}
bPix = ilLoadPixF(PixFile);
icloser(PixFile);
return bPix;
}
//! Reads an already-opened Pix file
ILboolean ilLoadPixF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPixInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Pix
ILboolean ilLoadPixL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPixInternal();
}
// Internal function used to load the Pix.
ILboolean iLoadPixInternal()
{
PIXHEAD Header;
ILuint i, j;
ILubyte ByteHead, Colour[3];
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetPixHead(&Header))
return IL_FALSE;
if (!iCheckPix(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
for (i = 0; i < iCurImage->SizeOfData; ) {
ByteHead = igetc();
if (iread(Colour, 1, 3) != 3)
return IL_FALSE;
for (j = 0; j < ByteHead; j++) {
iCurImage->Data[i++] = Colour[0];
iCurImage->Data[i++] = Colour[1];
iCurImage->Data[i++] = Colour[2];
}
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return ilFixImage();
}
#endif//IL_NO_PIX
+729
View File
@@ -0,0 +1,729 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_png.c
//
// Description: Portable network graphics file (.png) functions
//
// 20040223 XIX : now may spit out pngs with a transparent index, this is mostly a hack
// but the proper way of doing it would be to change the pal stuff to think in argb rather than rgb
// which is something of a bigger job.
//
//-----------------------------------------------------------------------------
// Most of the comments are left in this file from libpng's excellent example.c
#include "il_internal.h"
#ifndef IL_NO_PNG
#include <png.h>
#include "il_manip.h"
#include <stdlib.h>
#if PNG_LIBPNG_VER < 10200
#warning DevIL was designed with libpng 1.2.0 or higher in mind. Consider upgrading at www.libpng.org.
#endif
#if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "libpng.lib")
#pragma comment(lib, "zlib.lib")
#else
#pragma comment(lib, "libpng-d.lib")
#pragma comment(lib, "zlib-d.lib")
#endif
#endif
#endif
ILboolean iIsValidPng(void);
ILboolean iLoadPngInternal(void);
ILboolean iSavePngInternal(void);
ILint readpng_init(void);
ILboolean readpng_get_image(ILdouble display_exponent);
void readpng_cleanup(void);
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
ILint png_color_type;
#define GAMMA_CORRECTION 1.0 // Doesn't seem to be doing anything...
ILboolean ilIsValidPng(ILconst_string FileName)
{
ILHANDLE PngFile;
ILboolean bPng = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("png"))) {
ilSetError(IL_INVALID_EXTENSION);
return bPng;
}
PngFile = iopenr(FileName);
if (PngFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPng;
}
bPng = ilIsValidPngF(PngFile);
icloser(PngFile);
return bPng;
}
ILboolean ilIsValidPngF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidPng();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
ILboolean ilIsValidPngL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidPng();
}
ILboolean iIsValidPng()
{
ILubyte Signature[8];
ILint Read;
Read = iread(Signature, 1, 8);
iseek(-Read, IL_SEEK_CUR);
return png_check_sig(Signature, 8);
}
// Reads a file
ILboolean ilLoadPng(ILconst_string FileName)
{
ILHANDLE PngFile;
ILboolean bPng = IL_FALSE;
PngFile = iopenr(FileName);
if (PngFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPng;
}
bPng = ilLoadPngF(PngFile);
icloser(PngFile);
return bPng;
}
// Reads an already-opened file
ILboolean ilLoadPngF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPngInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
// Reads from a memory "lump"
ILboolean ilLoadPngL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPngInternal();
}
ILboolean iLoadPngInternal()
{
png_ptr = NULL;
info_ptr = NULL;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iIsValidPng()) {
ilSetError(IL_INVALID_VALUE);
return IL_FALSE;
}
if (readpng_init())
return IL_FALSE;
if (!readpng_get_image(GAMMA_CORRECTION))
return IL_FALSE;
readpng_cleanup();
return ilFixImage();
}
static void png_read(png_structp png_ptr, png_bytep data, png_size_t length)
{
(void)png_ptr;
iread(data, 1, (ILuint)length);
return;
}
static void png_error_func(png_structp png_ptr, png_const_charp message)
{
ilSetError(IL_LIB_PNG_ERROR);
/*
changed 20040224
From the libpng docs:
"Errors handled through png_error() are fatal, meaning that png_error()
should never return to its caller. Currently, this is handled via
setjmp() and longjmp()"
*/
//return;
longjmp(png_jmpbuf(png_ptr), 1);
}
static void png_warn_func(png_structp png_ptr, png_const_charp message)
{
return;
}
ILint readpng_init()
{
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_func, png_warn_func);
if (!png_ptr)
return 4; /* out of memory */
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return 4; /* out of memory */
}
/* we could create a second info struct here (end_info), but it's only
* useful if we want to keep pre- and post-IDAT chunk info separated
* (mainly for PNG-aware image editors and converters) */
/* setjmp() must be called in every function that calls a PNG-reading
* libpng function */
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 2;
}
png_set_read_fn(png_ptr, NULL, png_read);
png_set_error_fn(png_ptr, NULL, png_error_func, png_warn_func);
// png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */
png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
/* alternatively, could make separate calls to png_get_image_width(),
* etc., but want bit_depth and png_color_type for later [don't care about
* compression_type and filter_type => NULLs] */
/* OK, that's all we need for now; return happy */
return 0;
}
/* display_exponent == LUT_exponent * CRT_exponent */
ILboolean readpng_get_image(ILdouble display_exponent)
{
png_bytepp row_pointers = NULL;
png_uint_32 width, height; // Changed the type to fix AMD64 bit problems, thanks to Eric Werness
ILdouble screen_gamma = 1.0;
ILuint i, channels;
ILenum format;
png_colorp palette;
ILint num_palette, j, bit_depth;
#if _WIN32 || DJGPP
ILdouble image_gamma;
#endif
/* setjmp() must be called in every function that calls a PNG-reading
* libpng function */
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return IL_FALSE;
}
png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
&bit_depth, &png_color_type, NULL, NULL, NULL);
// Expand low-bit-depth grayscale images to 8 bits
if (png_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_gray_1_2_4_to_8(png_ptr);
}
// Expand RGB images with transparency to full alpha channels
// so the data will be available as RGBA quartets.
// But don't expand paletted images, since we want alpha palettes!
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) && !(png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)))
png_set_tRNS_to_alpha(png_ptr);
//refresh information (added 20040224)
png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
&bit_depth, &png_color_type, NULL, NULL, NULL);
if (bit_depth < 8) { // Expanded earlier for grayscale, now take care of palette and rgb
bit_depth = 8;
png_set_packing(png_ptr);
}
// Perform gamma correction.
// @TODO: Determine if we should call png_set_gamma if image_gamma is 1.0.
#if _WIN32 || DJGPP
screen_gamma = 2.2;
if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
png_set_gamma(png_ptr, screen_gamma, image_gamma);
#else
screen_gamma = screen_gamma;
#endif
//fix endianess
#ifdef __LITTLE_ENDIAN__
if (bit_depth == 16)
png_set_swap(png_ptr);
#endif
png_read_update_info(png_ptr, info_ptr);
channels = (ILint)png_get_channels(png_ptr, info_ptr);
//added 20040224: update png_color_type so that it has the correct value
//in iLoadPngInternal (globals rule...)
png_color_type = png_get_color_type(png_ptr, info_ptr);
//determine internal format
switch(png_color_type)
{
case PNG_COLOR_TYPE_PALETTE:
format = IL_COLOUR_INDEX;
break;
case PNG_COLOR_TYPE_GRAY:
format = IL_LUMINANCE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
format = IL_LUMINANCE_ALPHA;
break;
case PNG_COLOR_TYPE_RGB:
format = IL_RGB;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
format = IL_RGBA;
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return IL_FALSE;
}
if (!ilTexImage(width, height, 1, (ILubyte)channels, format, ilGetTypeBpc((ILubyte)(bit_depth >> 3)), NULL)) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
//copy palette
if (format == IL_COLOUR_INDEX) {
int chans;
png_bytep trans = NULL;
int num_trans = -1;
if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return IL_FALSE;
}
chans = 3;
iCurImage->Pal.PalType = IL_PAL_RGB24;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
iCurImage->Pal.PalType = IL_PAL_RGBA32;
chans = 4;
}
iCurImage->Pal.PalSize = num_palette * chans;
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
for (j = 0; j < num_palette; ++j) {
iCurImage->Pal.Palette[chans*j + 0] = palette[j].red;
iCurImage->Pal.Palette[chans*j + 1] = palette[j].green;
iCurImage->Pal.Palette[chans*j + 2] = palette[j].blue;
if (trans!=NULL) {
if (j<num_trans)
iCurImage->Pal.Palette[chans*j + 3] = trans[j];
else
iCurImage->Pal.Palette[chans*j + 3] = 255;
}
}
}
//allocate row pointers
if ((row_pointers = (png_bytepp)ialloc(height * sizeof(png_bytep))) == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return IL_FALSE;
}
// Set the individual row_pointers to point at the correct offsets */
for (i = 0; i < height; i++)
row_pointers[i] = iCurImage->Data + i * iCurImage->Bps;
// Now we can go ahead and just read the whole image
png_read_image(png_ptr, row_pointers);
/* and we're done! (png_read_end() can be omitted if no processing of
* post-IDAT text/time/etc. is desired) */
//png_read_end(png_ptr, NULL);
ifree(row_pointers);
return IL_TRUE;
}
void readpng_cleanup()
{
if (png_ptr && info_ptr) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
png_ptr = NULL;
info_ptr = NULL;
}
}
//! Writes a Png file
ILboolean ilSavePng(const ILstring FileName)
{
ILHANDLE PngFile;
ILuint PngSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
PngFile = iopenw(FileName);
if (PngFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
PngSize = ilSavePngF(PngFile);
iclosew(PngFile);
if (PngSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Png to an already-opened file
ILuint ilSavePngF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSavePngInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Png to a memory "lump"
ILuint ilSavePngL(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSavePngInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
void png_write(png_structp png_ptr, png_bytep data, png_size_t length)
{
(void)png_ptr;
iwrite(data, 1, (ILuint)length);
return;
}
void flush_data(png_structp png_ptr)
{
return;
}
// Internal function used to save the Png.
ILboolean iSavePngInternal()
{
png_structp png_ptr;
png_infop info_ptr;
png_text text[4];
ILenum PngType;
ILuint BitDepth, i, j;
ILubyte **RowPtr = NULL;
ILimage *Temp = NULL;
ILpal *TempPal = NULL;
//XIX alpha
ILubyte transpart[1];
ILint trans;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries. REQUIRED.
*/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_func, png_warn_func);
if (png_ptr == NULL) {
ilSetError(IL_LIB_PNG_ERROR);
return IL_FALSE;
}
// Allocate/initialize the image information data. REQUIRED
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
ilSetError(IL_LIB_PNG_ERROR);
goto error_label;
}
/*// Set error handling. REQUIRED if you aren't supplying your own
// error handling functions in the png_create_write_struct() call.
if (setjmp(png_jmpbuf(png_ptr))) {
// If we get here, we had a problem reading the file
png_destroy_write_struct(&png_ptr, &info_ptr);
ilSetError(IL_LIB_PNG_ERROR);
return IL_FALSE;
}*/
// png_init_io(png_ptr, PngFile);
png_set_write_fn(png_ptr, NULL, png_write, flush_data);
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
Temp = iCurImage;
BitDepth = 8;
break;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
Temp = iCurImage;
BitDepth = 16;
break;
case IL_INT:
case IL_UNSIGNED_INT:
Temp = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_SHORT);
if (Temp == NULL) {
png_destroy_write_struct(&png_ptr, &info_ptr);
return IL_FALSE;
}
BitDepth = 16;
break;
default:
ilSetError(IL_INTERNAL_ERROR);
goto error_label;
}
switch (iCurImage->Format)
{
case IL_COLOUR_INDEX:
PngType = PNG_COLOR_TYPE_PALETTE;
break;
case IL_LUMINANCE:
PngType = PNG_COLOR_TYPE_GRAY;
break;
case IL_LUMINANCE_ALPHA: //added 20050328
PngType = PNG_COLOR_TYPE_GRAY_ALPHA;
break;
case IL_RGB:
case IL_BGR:
PngType = PNG_COLOR_TYPE_RGB;
break;
case IL_RGBA:
case IL_BGRA:
PngType = PNG_COLOR_TYPE_RGB_ALPHA;
break;
default:
ilSetError(IL_INTERNAL_ERROR);
goto error_label;
}
// Set the image information here. Width and height are up to 2^31,
// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
// the png_color_type selected. png_color_type is one of PNG_COLOR_TYPE_GRAY,
// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
// or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
// PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
// currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
if (iGetInt(IL_PNG_INTERLACE) == IL_TRUE) {
png_set_IHDR(png_ptr, info_ptr, iCurImage->Width, iCurImage->Height, BitDepth, PngType,
PNG_INTERLACE_ADAM7, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else {
png_set_IHDR(png_ptr, info_ptr, iCurImage->Width, iCurImage->Height, BitDepth, PngType,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
if (iCurImage->Format == IL_COLOUR_INDEX) {
// set the palette if there is one. REQUIRED for indexed-color images.
TempPal = iConvertPal(&iCurImage->Pal, IL_PAL_RGB24);
png_set_PLTE(png_ptr, info_ptr, (png_colorp)TempPal->Palette,
ilGetInteger(IL_PALETTE_NUM_COLS));
//XIX alpha
trans=iGetInt(IL_PNG_ALPHA_INDEX);
if ( trans>=0)
{
transpart[0]=(ILubyte)trans;
png_set_tRNS(png_ptr, info_ptr, transpart, 1, 0);
}
}
/*
// optional significant bit chunk
// if we are dealing with a grayscale image then
sig_bit.gray = true_bit_depth;
// otherwise, if we are dealing with a color image then
sig_bit.red = true_red_bit_depth;
sig_bit.green = true_green_bit_depth;
sig_bit.blue = true_blue_bit_depth;
// if the image has an alpha channel then
sig_bit.alpha = true_alpha_bit_depth;
png_set_sBIT(png_ptr, info_ptr, sig_bit);*/
/* Optional gamma chunk is strongly suggested if you have any guess
* as to the correct gamma of the image.
*/
//png_set_gAMA(png_ptr, info_ptr, gamma);
// Optionally write comments into the image.
imemclear(text, sizeof(png_text) * 4);
text[0].key = "Generated by";
text[0].text = "Generated by the Developer's Image Library (DevIL)";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
text[1].key = "Author";
text[1].text = (char*)iGetString(IL_PNG_AUTHNAME_STRING); // Will not actually be modified!
text[1].compression = PNG_TEXT_COMPRESSION_NONE;
text[2].key = "Description";
text[2].text = iGetString(IL_PNG_DESCRIPTION_STRING);
text[2].compression = PNG_TEXT_COMPRESSION_NONE;
text[3].key = "Title";
text[3].text = iGetString(IL_PNG_TITLE_STRING);
text[3].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png_ptr, info_ptr, text, 3);
// Write the file header information. REQUIRED.
png_write_info(png_ptr, info_ptr);
// Free up our user-defined text.
if (text[1].text)
ifree(text[1].text);
if (text[2].text)
ifree(text[2].text);
if (text[3].text)
ifree(text[3].text);
/* Shift the pixels up to a legal bit depth and fill in
* as appropriate to correctly scale the image.
*/
//png_set_shift(png_ptr, &sig_bit);
/* pack pixels into bytes */
//png_set_packing(png_ptr);
// swap location of alpha bytes from ARGB to RGBA
//png_set_swap_alpha(png_ptr);
// flip BGR pixels to RGB
if (iCurImage->Format == IL_BGR || iCurImage->Format == IL_BGRA)
png_set_bgr(png_ptr);
// swap bytes of 16-bit files to most significant byte first
#ifdef __LITTLE_ENDIAN__
png_set_swap(png_ptr);
#endif//__LITTLE_ENDIAN__
RowPtr = (ILubyte**)ialloc(iCurImage->Height * sizeof(ILubyte*));
if (RowPtr == NULL)
goto error_label;
if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT) {
for (i = 0; i < iCurImage->Height; i++) {
RowPtr[i] = Temp->Data + i * Temp->Bps;
}
}
else {
j = iCurImage->Height - 1;
for (i = 0; i < iCurImage->Height; i++, j--) {
RowPtr[i] = Temp->Data + j * Temp->Bps;
}
}
// Writes the image.
png_write_image(png_ptr, RowPtr);
// It is REQUIRED to call this to finish writing the rest of the file
png_write_end(png_ptr, info_ptr);
// clean up after the write, and ifree any memory allocated
png_destroy_write_struct(&png_ptr, &info_ptr);
ifree(RowPtr);
if (Temp != iCurImage)
ilCloseImage(Temp);
ilClosePal(TempPal);
return IL_TRUE;
error_label:
png_destroy_write_struct(&png_ptr, &info_ptr);
ifree(RowPtr);
if (Temp != iCurImage)
ilCloseImage(Temp);
ilClosePal(TempPal);
return IL_FALSE;
}
#endif//IL_NO_PNG
+698
View File
@@ -0,0 +1,698 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_pnm.c
//
// Description: Reads/writes to/from pbm/pgm/ppm formats (enough slashes? =)
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PNM
#include "il_pnm.h"
#include <limits.h> // for maximum values
#include <ctype.h>
#include "il_manip.h"
#include "il_bits.h"
// According to the ppm specs, it's 70, but PSP
// likes to output longer lines.
#define MAX_BUFFER 180
static ILbyte LineBuffer[MAX_BUFFER];
static ILbyte SmallBuff[MAX_BUFFER];
// Can't read direct bits from a lump yet
ILboolean IsLump = IL_FALSE;
//! Checks if the file specified in FileName is a valid .pnm file.
ILboolean ilIsValidPnm(ILconst_string FileName)
{
ILHANDLE PnmFile;
ILboolean bPnm = IL_FALSE;
if ( !iCheckExtension(FileName, IL_TEXT("pbm"))
&& !iCheckExtension(FileName, IL_TEXT("pgm"))
&& !iCheckExtension(FileName, IL_TEXT("ppm"))
&& !iCheckExtension(FileName, IL_TEXT("pnm"))) {
ilSetError(IL_INVALID_EXTENSION);
return bPnm;
}
PnmFile = iopenr(FileName);
if (PnmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPnm;
}
bPnm = ilIsValidPnmF(PnmFile);
icloser(PnmFile);
return bPnm;
}
//! Checks if the ILHANDLE contains a valid .pnm file at the current position.
ILboolean ilIsValidPnmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidPnm();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid .pnm lump.
ILboolean ilIsValidPnmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidPnm();
}
// Internal function to get the header and check it.
ILboolean iIsValidPnm()
{
char Head[2];
ILint Read;
Read = iread(Head, 1, 2);
iseek(-Read, IL_SEEK_CUR); // Go ahead and restore to previous state
if (Read != 2)
return IL_FALSE;
return iCheckPnm(Head);
}
// Internal function used to check if the HEADER is a valid .pnm header.
ILboolean iCheckPnm(char Header[2])
{
if (Header[0] != 'P')
return IL_FALSE;
switch (Header[1])
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
return IL_TRUE;
}
return IL_FALSE;
}
// Reads a file
ILboolean ilLoadPnm(ILconst_string FileName)
{
ILHANDLE PnmFile;
ILboolean bPnm = IL_FALSE;
PnmFile = iopenr(FileName);
if (PnmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPnm;
}
bPnm = ilLoadPnmF(PnmFile);
icloser(PnmFile);
return bPnm;
}
// Reads an already-opened file
ILboolean ilLoadPnmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPnmInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
// Reads from a memory "lump"
ILboolean ilLoadPnmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPnmInternal();
}
// Load either a pgm or a ppm
ILboolean iLoadPnmInternal()
{
ILimage *PmImage = NULL;
PPMINFO Info;
// ILuint LineInc = 0, SmallInc = 0;
Info.Type = 0;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
// Find out what type of pgm/ppm this is
if (iGetWord(IL_FALSE) == IL_FALSE)
return IL_FALSE;
if (SmallBuff[0] != 'P') {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
switch( SmallBuff[1] ) {
case '1':
Info.Type = IL_PBM_ASCII;
break;
case '2':
Info.Type = IL_PGM_ASCII;
break;
case '3':
Info.Type = IL_PPM_ASCII;
break;
case '4':
Info.Type = IL_PBM_BINARY;
if (IsLump) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
break;
case '5':
Info.Type = IL_PGM_BINARY;
break;
case '6':
Info.Type = IL_PPM_BINARY;
break;
default:
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Retrieve the width and height
if (iGetWord(IL_FALSE) == IL_FALSE)
return IL_FALSE;
Info.Width = atoi((const char*)SmallBuff);
if (Info.Width == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (iGetWord(IL_FALSE) == IL_FALSE)
return IL_FALSE;
Info.Height = atoi((const char*)SmallBuff);
if (Info.Height == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Retrieve the maximum colour component value
if (Info.Type != IL_PBM_ASCII && Info.Type != IL_PBM_BINARY) {
if (iGetWord(IL_TRUE) == IL_FALSE)
return IL_FALSE;
if ((Info.MaxColour = atoi((const char*)SmallBuff)) == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
} else {
Info.MaxColour = 1;
}
if (Info.Type == IL_PBM_ASCII || Info.Type == IL_PBM_BINARY ||
Info.Type == IL_PGM_ASCII || Info.Type == IL_PGM_BINARY) {
if (Info.Type == IL_PGM_ASCII) {
Info.Bpp = Info.MaxColour < 256 ? 1 : 2;
} else {
Info.Bpp = 1;
}
} else {
Info.Bpp = 3;
}
switch (Info.Type) {
case IL_PBM_ASCII:
case IL_PGM_ASCII:
case IL_PPM_ASCII:
PmImage = ilReadAsciiPpm(&Info);
break;
case IL_PBM_BINARY:
PmImage = ilReadBitPbm(&Info);
break;
case IL_PGM_BINARY:
case IL_PPM_BINARY:
PmImage = ilReadBinaryPpm(&Info);
break;
default:
return IL_FALSE;
}
if (PmImage == NULL) {
iCurImage->Format = ilGetFormatBpp(iCurImage->Bpp);
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
// Is this conversion needed? Just 0's and 1's shows up as all black
if (Info.Type == IL_PBM_ASCII) {
PbmMaximize(PmImage);
}
if (Info.MaxColour > 255)
PmImage->Type = IL_UNSIGNED_SHORT;
PmImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (Info.Type == IL_PBM_ASCII || Info.Type == IL_PBM_BINARY ||
Info.Type == IL_PGM_ASCII || Info.Type == IL_PGM_BINARY)
PmImage->Format = IL_LUMINANCE;
else
PmImage->Format = IL_RGB;
PmImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (PmImage == NULL)
return IL_FALSE;
return ilFixImage();
}
ILimage *ilReadAsciiPpm(PPMINFO *Info)
{
ILint LineInc = 0, SmallInc = 0, DataInc = 0, Size;
// ILint BytesRead = 0;
if (Info->MaxColour > 255)
Info->Bpp *= 2;
Size = Info->Width * Info->Height * Info->Bpp;
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (Info->MaxColour > 255)
iCurImage->Type = IL_UNSIGNED_SHORT;
while (DataInc < Size) { // && !feof(File)) {
LineInc = 0;
if (iFgets((char *)LineBuffer, MAX_BUFFER) == NULL) {
//ilSetError(IL_ILLEGAL_FILE_VALUE);
//return NULL;
//return iCurImage;
break;
}
if (LineBuffer[0] == '#') { // Comment
continue;
}
while ((LineBuffer[LineInc] != NUL) && (LineBuffer[LineInc] != '\n')) {
SmallInc = 0;
while (!isalnum(LineBuffer[LineInc])) { // Skip any whitespace
LineInc++;
}
while (isalnum(LineBuffer[LineInc])) {
SmallBuff[SmallInc] = LineBuffer[LineInc];
SmallInc++;
LineInc++;
}
SmallBuff[SmallInc] = NUL;
iCurImage->Data[DataInc] = atoi((const char*)SmallBuff); // Convert from string to colour
// PSP likes to put whitespace at the end of lines...figures. =/
while (!isalnum(LineBuffer[LineInc]) && LineBuffer[LineInc] != NUL) { // Skip any whitespace
LineInc++;
}
// We should set some kind of state flag that enables this
//Image->Data[DataInc] *= (ILubyte)(255 / Info->MaxColour); // Scales to 0-255
if (Info->MaxColour > 255)
DataInc++;
DataInc++;
}
}
// If we read less than what we should have...
if (DataInc < Size) {
//ilCloseImage(iCurImage);
//ilSetCurImage(NULL);
ilSetError(IL_ILLEGAL_FILE_VALUE);
return NULL;
}
return iCurImage;
}
ILimage *ilReadBinaryPpm(PPMINFO *Info)
{
ILuint Size;
Size = Info->Width * Info->Height * Info->Bpp;
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
/* 4/3/2007 Dario Meloni
Here it seems we have eaten too much bytes and it is needed to fix
the starting point
works well on various images
No more need of this workaround. fixed iGetWord
iseek(0,IL_SEEK_END);
ILuint size = itell();
iseek(size-Size,IL_SEEK_SET);
*/
if (iread(iCurImage->Data, 1, Size ) != Size) {
ilCloseImage(iCurImage);
return NULL;
}
return iCurImage;
}
ILimage *ilReadBitPbm(PPMINFO *Info)
{
ILuint m, j, x, CurrByte;
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
x = 0;
for (j = 0; j < iCurImage->SizeOfData;) {
CurrByte = igetc();
for (m = 128; m > 0 && x < Info->Width; m >>= 1, ++x, ++j) {
iCurImage->Data[j] = (CurrByte & m)?255:0;
}
if (x == Info->Width)
x = 0;
}
return iCurImage;
}
ILboolean iGetWord(ILboolean final)
{
ILint WordPos = 0;
ILint Current = 0;
ILboolean Started = IL_FALSE;
ILboolean Looping = IL_TRUE;
if (ieof())
return IL_FALSE;
while (Looping) {
while ((Current = igetc()) != IL_EOF && Current != '\n' && Current != '#' && Current != ' ') {
if (WordPos >= MAX_BUFFER) // We have hit the maximum line length.
return IL_FALSE;
if (!isalnum(Current)) {
if (Started) {
Looping = IL_FALSE;
break;
}
continue;
}
if (Looping)
SmallBuff[WordPos++] = Current;
}
if (Current == IL_EOF)
return IL_FALSE;
SmallBuff[WordPos] = 0; // 08-17-2008 - was NULL, changed to avoid warning
if (final == IL_TRUE)
break;
if (!Looping)
break;
if (Current == '#') { // '#' is a comment...read until end of line
while ((Current = igetc()) != IL_EOF && Current != '\n');
}
// Get rid of any erroneous spaces
while ((Current = igetc()) != IL_EOF) {
if (Current != ' ')
break;
}
iseek(-1, IL_SEEK_CUR);
if (WordPos > 0)
break;
}
if (Current == -1 || WordPos == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
return IL_TRUE;
}
ILstring FName = NULL;
//! Writes a Pnm file
ILboolean ilSavePnm(const ILstring FileName)
{
ILHANDLE PnmFile;
ILuint PnmSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
PnmFile = iopenw(FileName);
if (PnmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
PnmSize = ilSavePnmF(PnmFile);
iclosew(PnmFile);
if (PnmSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Pnm to an already-opened file
ILuint ilSavePnmF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSavePnmInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Pnm to a memory "lump"
ILuint ilSavePnmL(void *Lump, ILuint Size)
{
ILuint Pos;
FName = NULL;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSavePnmInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to save the Pnm.
ILboolean iSavePnmInternal()
{
ILuint Bpp, MaxVal = UCHAR_MAX, i = 0, j, k;
ILenum Type = 0;
ILuint LinePos = 0; // Cannot exceed 70 for pnm's!
ILboolean Binary;
ILimage *TempImage;
ILubyte *TempData;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (iCheckExtension(FName, IL_TEXT("pbm")))
Type = IL_PBM_ASCII;
else if (iCheckExtension(FName, IL_TEXT("pgm")))
Type = IL_PGM_ASCII;
else if (iCheckExtension(FName, IL_TEXT("ppm")))
Type = IL_PPM_ASCII;
else
Type = IL_PPM_ASCII;
/*if (!Type) {
ilSetError(IL_INVALID_EXTENSION);
return IL_FALSE;
}*/
if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION) {
Type += 3;
Binary = IL_TRUE;
}
else {
Binary = IL_FALSE;
}
if (iCurImage->Type == IL_UNSIGNED_BYTE) {
MaxVal = UCHAR_MAX;
}
else if (iCurImage->Type == IL_UNSIGNED_SHORT) {
MaxVal = USHRT_MAX;
}
else {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
if (MaxVal > UCHAR_MAX && Type >= IL_PBM_BINARY) { // binary cannot be higher than 255
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
switch (Type)
{
case IL_PBM_ASCII:
Bpp = 1;
ilprintf("P1\n");
TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
break;
//case IL_PBM_BINARY: // Don't want to mess with saving bits just yet...
//Bpp = 1;
//ilprintf("P4\n");
//break;
case IL_PBM_BINARY:
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
case IL_PGM_ASCII:
Bpp = 1;
ilprintf("P2\n");
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
break;
case IL_PGM_BINARY:
Bpp = 1;
ilprintf("P5\n");
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
break;
case IL_PPM_ASCII:
Bpp = 3;
ilprintf("P3\n");
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
break;
case IL_PPM_BINARY:
Bpp = 3;
ilprintf("P6\n");
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
break;
default:
ilSetError(IL_INTERNAL_ERROR);
return IL_FALSE;
}
if (TempImage == NULL)
return IL_FALSE;
if (Bpp != TempImage->Bpp) {
ilSetError(IL_INVALID_CONVERSION);
return IL_FALSE;
}
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
TempData = iGetFlipped(TempImage);
if (TempData == NULL) {
ilCloseImage(TempImage);
return IL_FALSE;
}
}
else {
TempData = TempImage->Data;
}
ilprintf("%d %d\n", TempImage->Width, TempImage->Height);
if (Type != IL_PBM_BINARY && Type != IL_PBM_ASCII) // not needed for .pbm's (only 0 and 1)
ilprintf("%d\n", MaxVal);
while (i < TempImage->SizeOfPlane) {
for (j = 0; j < Bpp; j++) {
if (Binary) {
if (Type == IL_PBM_BINARY) {
iputc((ILubyte)(TempData[i] > 127 ? 1 : 0));
}
else {
iputc(TempData[i]);
}
}
else {
if (TempImage->Type == IL_UNSIGNED_BYTE)
k = TempData[i];
else // IL_UNSIGNED_SHORT
k = *((ILushort*)TempData + i);
if (Type == IL_PBM_ASCII) {
LinePos += ilprintf("%d ", TempData[i] > 127 ? 1 : 0);
}
else {
LinePos += ilprintf("%d ", TempData[i]);
}
}
if (TempImage->Type == IL_UNSIGNED_SHORT)
i++;
i++;
}
if (LinePos > 65) { // Just a good number =]
ilprintf("\n");
LinePos = 0;
}
}
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT)
ifree(TempData);
ilCloseImage(TempImage);
return IL_TRUE;
}
// Converts a .pbm to something viewable.
void PbmMaximize(ILimage *Image)
{
ILuint i = 0;
for (i = 0; i < Image->SizeOfPlane; i++)
if (Image->Data[i] == 1)
Image->Data[i] = 0xFF;
return;
}
#endif//IL_NO_PNM
+174
View File
@@ -0,0 +1,174 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2002 by Denton Woods
// Last modified: 01/23/2001 <--Y2K Compliant! =]
//
// Filename: src-IL/src/il_profiles.c
//
// Description: Colour profile handler
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_LCMS
#ifdef PACKAGE_NAME
#define IL_PACKAGE_NAME PACKAGE_NAME;
#undef PACKAGE_NAME
#endif
#if (!defined(_WIN32) && !defined(_WIN64))
#define NON_WINDOWS 1
#ifdef LCMS_NODIRINCLUDE
#include <lcms.h>
#else
#include <lcms/lcms.h>
#endif
#else
#if defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "lcms.lib")
#else
#pragma comment(lib, "lcms-d.lib")
#endif
#endif
#endif
#include <lcms.h>
#endif//_WIN32
#ifdef PACKAGE_NAME
#undef PACKAGE_NAME
#endif
#ifdef IL_PACKAGE_NAME
#define PACKAGE_NAME IL_PACKAGE_NAME
#undef IL_PACKAGE_NAME
#endif
#endif//IL_NO_LCMS
ILboolean ILAPIENTRY ilApplyProfile(ILstring InProfile, ILstring OutProfile)
{
#ifndef IL_NO_LCMS
cmsHPROFILE hInProfile, hOutProfile;
cmsHTRANSFORM hTransform;
ILubyte *Temp;
ILint Format=0;
#ifdef _UNICODE
char AnsiName[512];
#endif//_UNICODE
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
switch (iCurImage->Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
switch (iCurImage->Format)
{
case IL_LUMINANCE:
Format = TYPE_GRAY_8;
break;
case IL_RGB:
Format = TYPE_RGB_8;
break;
case IL_BGR:
Format = TYPE_BGR_8;
break;
case IL_RGBA:
Format = TYPE_RGBA_8;
break;
case IL_BGRA:
Format = TYPE_BGRA_8;
break;
default:
ilSetError(IL_INTERNAL_ERROR);
return IL_FALSE;
}
break;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
switch (iCurImage->Format)
{
case IL_LUMINANCE:
Format = TYPE_GRAY_16;
break;
case IL_RGB:
Format = TYPE_RGB_16;
break;
case IL_BGR:
Format = TYPE_BGR_16;
break;
case IL_RGBA:
Format = TYPE_RGBA_16;
break;
case IL_BGRA:
Format = TYPE_BGRA_16;
break;
default:
ilSetError(IL_INTERNAL_ERROR);
return IL_FALSE;
}
break;
// These aren't supported right now.
case IL_INT:
case IL_UNSIGNED_INT:
case IL_FLOAT:
case IL_DOUBLE:
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (InProfile == NULL) {
if (!iCurImage->Profile || !iCurImage->ProfileSize) {
ilSetError(IL_INVALID_PARAM);
return IL_FALSE;
}
hInProfile = iCurImage->Profile;
}
else {
#ifndef _UNICODE
hInProfile = cmsOpenProfileFromFile(InProfile, "r");
#else
wcstombs(AnsiName, InProfile, 512);
hInProfile = cmsOpenProfileFromFile(AnsiName, "r");
#endif//_UNICODE
}
#ifndef _UNICODE
hOutProfile = cmsOpenProfileFromFile(OutProfile, "r");
#else
wcstombs(AnsiName, OutProfile, 512);
hOutProfile = cmsOpenProfileFromFile(AnsiName, "r");
#endif//_UNICODE
hTransform = cmsCreateTransform(hInProfile, Format, hOutProfile, Format, INTENT_PERCEPTUAL, 0);
Temp = (ILubyte*)ialloc(iCurImage->SizeOfData);
if (Temp == NULL) {
return IL_FALSE;
}
cmsDoTransform(hTransform, iCurImage->Data, Temp, iCurImage->SizeOfData / 3);
ifree(iCurImage->Data);
iCurImage->Data = Temp;
cmsDeleteTransform(hTransform);
if (InProfile != NULL)
cmsCloseProfile(hInProfile);
cmsCloseProfile(hOutProfile);
#endif//IL_NO_LCMS
return IL_TRUE;
}
File diff suppressed because it is too large Load Diff
+712
View File
@@ -0,0 +1,712 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_psp.c
//
// Description: Reads a Paint Shop Pro file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include "il_psp.h"
#ifndef IL_NO_PSP
ILubyte PSPSignature[32] = {
0x50, 0x61, 0x69, 0x6E, 0x74, 0x20, 0x53, 0x68, 0x6F, 0x70, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x49,
0x6D, 0x61, 0x67, 0x65, 0x20, 0x46, 0x69, 0x6C, 0x65, 0x0A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00
};
ILubyte GenAttHead[4] = {
0x7E, 0x42, 0x4B, 0x00
};
// Make these global, since they contain most of the image information.
GENATT_CHUNK AttChunk;
PSPHEAD Header;
ILuint NumChannels;
ILubyte **Channels = NULL;
ILubyte *Alpha = NULL;
ILpal Pal;
//! Checks if the file specified in FileName is a valid Psp file.
ILboolean ilIsValidPsp(ILconst_string FileName)
{
ILHANDLE PspFile;
ILboolean bPsp = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("psp"))) {
ilSetError(IL_INVALID_EXTENSION);
return bPsp;
}
PspFile = iopenr(FileName);
if (PspFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPsp;
}
bPsp = ilIsValidPspF(PspFile);
icloser(PspFile);
return bPsp;
}
//! Checks if the ILHANDLE contains a valid Psp file at the current position.
ILboolean ilIsValidPspF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidPsp();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid Psp lump.
ILboolean ilIsValidPspL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidPsp();
}
// Internal function used to get the Psp header from the current file.
ILboolean iGetPspHead()
{
if (iread(Header.FileSig, 1, 32) != 32)
return IL_FALSE;
Header.MajorVersion = GetLittleUShort();
Header.MinorVersion = GetLittleUShort();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidPsp()
{
if (!iGetPspHead())
return IL_FALSE;
iseek(-(ILint)sizeof(PSPHEAD), IL_SEEK_CUR);
return iCheckPsp();
}
// Internal function used to check if the HEADER is a valid Psp header.
ILboolean iCheckPsp()
{
if (stricmp(Header.FileSig, "Paint Shop Pro Image File\n\x1a"))
return IL_FALSE;
if (Header.MajorVersion < 3 || Header.MajorVersion > 5)
return IL_FALSE;
if (Header.MinorVersion != 0)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a PSP file
ILboolean ilLoadPsp(ILconst_string FileName)
{
ILHANDLE PSPFile;
ILboolean bPsp = IL_FALSE;
PSPFile = iopenr(FileName);
if (PSPFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPsp;
}
bPsp = ilLoadPspF(PSPFile);
icloser(PSPFile);
return bPsp;
}
//! Reads an already-opened PSP file
ILboolean ilLoadPspF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPspInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a PSP
ILboolean ilLoadPspL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPspInternal();
}
// Internal function used to load the PSP.
ILboolean iLoadPspInternal()
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Channels = NULL;
Alpha = NULL;
Pal.Palette = NULL;
if (!iGetPspHead())
return IL_FALSE;
if (!iCheckPsp()) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!ReadGenAttributes())
return IL_FALSE;
if (!ParseChunks())
return IL_FALSE;
if (!AssembleImage())
return IL_FALSE;
Cleanup();
return ilFixImage();
}
ILboolean ReadGenAttributes()
{
BLOCKHEAD AttHead;
ILint Padding;
ILuint ChunkLen;
if (iread(&AttHead, sizeof(AttHead), 1) != 1)
return IL_FALSE;
UShort(&AttHead.BlockID);
UInt(&AttHead.BlockLen);
if (AttHead.HeadID[0] != 0x7E || AttHead.HeadID[1] != 0x42 ||
AttHead.HeadID[2] != 0x4B || AttHead.HeadID[3] != 0x00) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (AttHead.BlockID != PSP_IMAGE_BLOCK) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
ChunkLen = GetLittleUInt();
if (Header.MajorVersion != 3)
ChunkLen -= 4;
if (iread(&AttChunk, IL_MIN(sizeof(AttChunk), ChunkLen), 1) != 1)
return IL_FALSE;
// Can have new entries in newer versions of the spec (4.0).
Padding = (ChunkLen) - sizeof(AttChunk);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
// @TODO: Anything but 24 not supported yet...
if (AttChunk.BitDepth != 24 && AttChunk.BitDepth != 8) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// @TODO; Add support for compression...
if (AttChunk.Compression != PSP_COMP_NONE && AttChunk.Compression != PSP_COMP_RLE) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// @TODO: Check more things in the general attributes chunk here.
return IL_TRUE;
}
ILboolean ParseChunks()
{
BLOCKHEAD Block;
ILuint Pos;
do {
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block)) {
ilGetError(); // Get rid of the erroneous IL_FILE_READ_ERROR.
return IL_TRUE;
}
if (Header.MajorVersion == 3)
Block.BlockLen = GetLittleUInt();
else
UInt(&Block.BlockLen);
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
return IL_TRUE;
}
UShort(&Block.BlockID);
UInt(&Block.BlockLen);
Pos = itell();
switch (Block.BlockID)
{
case PSP_LAYER_START_BLOCK:
if (!ReadLayerBlock(Block.BlockLen))
return IL_FALSE;
break;
case PSP_ALPHA_BANK_BLOCK:
if (!ReadAlphaBlock(Block.BlockLen))
return IL_FALSE;
break;
case PSP_COLOR_BLOCK:
if (!ReadPalette(Block.BlockLen))
return IL_FALSE;
break;
// Gets done in the next iseek, so this is now commented out.
//default:
//iseek(Block.BlockLen, IL_SEEK_CUR);
}
// Skip to next block just in case we didn't read the entire block.
iseek(Pos + Block.BlockLen, IL_SEEK_SET);
// @TODO: Do stuff here.
} while (1);
return IL_TRUE;
}
ILboolean ReadLayerBlock(ILuint BlockLen)
{
BLOCKHEAD Block;
LAYERINFO_CHUNK LayerInfo;
LAYERBITMAP_CHUNK Bitmap;
ILuint ChunkSize, Padding, i, j;
ILushort NumChars;
BlockLen;
// Layer sub-block header
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
return IL_FALSE;
if (Header.MajorVersion == 3)
Block.BlockLen = GetLittleUInt();
else
UInt(&Block.BlockLen);
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
return IL_FALSE;
}
if (Block.BlockID != PSP_LAYER_BLOCK)
return IL_FALSE;
if (Header.MajorVersion == 3) {
iseek(256, IL_SEEK_CUR); // We don't care about the name of the layer.
iread(&LayerInfo, sizeof(LayerInfo), 1);
if (iread(&Bitmap, sizeof(Bitmap), 1) != 1)
return IL_FALSE;
}
else { // Header.MajorVersion >= 4
ChunkSize = GetLittleUInt();
NumChars = GetLittleUShort();
iseek(NumChars, IL_SEEK_CUR); // We don't care about the layer's name.
ChunkSize -= (2 + 4 + NumChars);
if (iread(&LayerInfo, IL_MIN(sizeof(LayerInfo), ChunkSize), 1) != 1)
return IL_FALSE;
// Can have new entries in newer versions of the spec (5.0).
Padding = (ChunkSize) - sizeof(LayerInfo);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
ChunkSize = GetLittleUInt();
if (iread(&Bitmap, sizeof(Bitmap), 1) != 1)
return IL_FALSE;
Padding = (ChunkSize - 4) - sizeof(Bitmap);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
}
Channels = (ILubyte**)ialloc(sizeof(ILubyte*) * Bitmap.NumChannels);
if (Channels == NULL) {
return IL_FALSE;
}
NumChannels = Bitmap.NumChannels;
for (i = 0; i < NumChannels; i++) {
Channels[i] = GetChannel();
if (Channels[i] == NULL) {
for (j = 0; j < i; j++)
ifree(Channels[j]);
return IL_FALSE;
}
}
return IL_TRUE;
}
ILboolean ReadAlphaBlock(ILuint BlockLen)
{
BLOCKHEAD Block;
ALPHAINFO_CHUNK AlphaInfo;
ALPHA_CHUNK AlphaChunk;
ILushort NumAlpha, StringSize;
ILuint ChunkSize, Padding;
if (Header.MajorVersion == 3) {
NumAlpha = GetLittleUShort();
}
else {
ChunkSize = GetLittleUInt();
NumAlpha = GetLittleUShort();
Padding = (ChunkSize - 4 - 2);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
}
// Alpha channel header
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
return IL_FALSE;
if (Header.MajorVersion == 3)
Block.BlockLen = GetLittleUInt();
else
UInt(&Block.BlockLen);
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
return IL_FALSE;
}
if (Block.BlockID != PSP_ALPHA_CHANNEL_BLOCK)
return IL_FALSE;
if (Header.MajorVersion >= 4) {
ChunkSize = GetLittleUInt();
StringSize = GetLittleUShort();
iseek(StringSize, IL_SEEK_CUR);
if (iread(&AlphaInfo, sizeof(AlphaInfo), 1) != 1)
return IL_FALSE;
Padding = (ChunkSize - 4 - 2 - StringSize - sizeof(AlphaInfo));
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
ChunkSize = GetLittleUInt();
if (iread(&AlphaChunk, sizeof(AlphaChunk), 1) != 1)
return IL_FALSE;
Padding = (ChunkSize - 4 - sizeof(AlphaChunk));
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
}
else {
iseek(256, IL_SEEK_CUR);
iread(&AlphaInfo, sizeof(AlphaInfo), 1);
if (iread(&AlphaChunk, sizeof(AlphaChunk), 1) != 1)
return IL_FALSE;
}
/*Alpha = (ILubyte*)ialloc(AlphaInfo.AlphaRect.x2 * AlphaInfo.AlphaRect.y2);
if (Alpha == NULL) {
return IL_FALSE;
}*/
Alpha = GetChannel();
if (Alpha == NULL)
return IL_FALSE;
return IL_TRUE;
}
ILubyte *GetChannel()
{
BLOCKHEAD Block;
CHANNEL_CHUNK Channel;
ILubyte *CompData, *Data;
ILuint ChunkSize, Padding;
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
return NULL;
if (Header.MajorVersion == 3)
Block.BlockLen = GetLittleUInt();
else
UInt(&Block.BlockLen);
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return NULL;
}
if (Block.BlockID != PSP_CHANNEL_BLOCK) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return NULL;
}
if (Header.MajorVersion >= 4) {
ChunkSize = GetLittleUInt();
if (iread(&Channel, sizeof(Channel), 1) != 1)
return NULL;
Padding = (ChunkSize - 4) - sizeof(Channel);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
}
else {
if (iread(&Channel, sizeof(Channel), 1) != 1)
return NULL;
}
CompData = (ILubyte*)ialloc(Channel.CompLen);
Data = (ILubyte*)ialloc(AttChunk.Width * AttChunk.Height);
if (CompData == NULL || Data == NULL) {
ifree(Data);
ifree(CompData);
return NULL;
}
if (iread(CompData, 1, Channel.CompLen) != Channel.CompLen) {
ifree(CompData);
ifree(Data);
return NULL;
}
switch (AttChunk.Compression)
{
case PSP_COMP_NONE:
ifree(Data);
return CompData;
break;
case PSP_COMP_RLE:
if (!UncompRLE(CompData, Data, Channel.CompLen)) {
ifree(CompData);
ifree(Data);
return IL_FALSE;
}
break;
default:
ifree(CompData);
ifree(Data);
ilSetError(IL_INVALID_FILE_HEADER);
return NULL;
}
ifree(CompData);
return Data;
}
ILboolean UncompRLE(ILubyte *CompData, ILubyte *Data, ILuint CompLen)
{
ILubyte Run, Colour;
ILint i, /*x, y,*/ Count/*, Total = 0*/;
/*for (y = 0; y < AttChunk.Height; y++) {
for (x = 0, Count = 0; x < AttChunk.Width; ) {
Run = *CompData++;
if (Run > 128) {
Run -= 128;
Colour = *CompData++;
memset(Data, Colour, Run);
Data += Run;
Count += 2;
}
else {
memcpy(Data, CompData, Run);
CompData += Run;
Data += Run;
Count += Run;
}
x += Run;
}
Total += Count;
if (Count % 4) { // Has to be on a 4-byte boundary.
CompData += (4 - (Count % 4)) % 4;
Total += (4 - (Count % 4)) % 4;
}
if (Total >= CompLen)
return IL_FALSE;
}*/
for (i = 0, Count = 0; i < (ILint)CompLen; ) {
Run = *CompData++;
i++;
if (Run > 128) {
Run -= 128;
Colour = *CompData++;
i++;
memset(Data, Colour, Run);
}
else {
memcpy(Data, CompData, Run);
CompData += Run;
i += Run;
}
Data += Run;
Count += Run;
}
return IL_TRUE;
}
ILboolean ReadPalette(ILuint BlockLen)
{
ILuint ChunkSize, PalCount, Padding;
if (Header.MajorVersion >= 4) {
ChunkSize = GetLittleUInt();
PalCount = GetLittleUInt();
Padding = (ChunkSize - 4 - 4);
if (Padding > 0)
iseek(Padding, IL_SEEK_CUR);
}
else {
PalCount = GetLittleUInt();
}
Pal.PalSize = PalCount * 4;
Pal.PalType = IL_PAL_BGRA32;
Pal.Palette = (ILubyte*)ialloc(Pal.PalSize);
if (Pal.Palette == NULL)
return IL_FALSE;
if (iread(Pal.Palette, Pal.PalSize, 1) != 1) {
ifree(Pal.Palette);
return IL_FALSE;
}
return IL_TRUE;
}
ILboolean AssembleImage()
{
ILuint Size, i, j;
Size = AttChunk.Width * AttChunk.Height;
if (NumChannels == 1) {
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
for (i = 0; i < Size; i++) {
iCurImage->Data[i] = Channels[0][i];
}
if (Pal.Palette) {
iCurImage->Format = IL_COLOUR_INDEX;
iCurImage->Pal.PalSize = Pal.PalSize;
iCurImage->Pal.PalType = Pal.PalType;
iCurImage->Pal.Palette = Pal.Palette;
}
}
else {
if (Alpha) {
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
for (i = 0, j = 0; i < Size; i++, j += 4) {
iCurImage->Data[j ] = Channels[0][i];
iCurImage->Data[j+1] = Channels[1][i];
iCurImage->Data[j+2] = Channels[2][i];
iCurImage->Data[j+3] = Alpha[i];
}
}
else if (NumChannels == 4) {
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
for (i = 0, j = 0; i < Size; i++, j += 4) {
iCurImage->Data[j ] = Channels[0][i];
iCurImage->Data[j+1] = Channels[1][i];
iCurImage->Data[j+2] = Channels[2][i];
iCurImage->Data[j+3] = Channels[3][i];
}
}
else if (NumChannels == 3) {
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
for (i = 0, j = 0; i < Size; i++, j += 3) {
iCurImage->Data[j ] = Channels[0][i];
iCurImage->Data[j+1] = Channels[1][i];
iCurImage->Data[j+2] = Channels[2][i];
}
}
else
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return IL_TRUE;
}
ILboolean Cleanup()
{
ILuint i;
if (Channels) {
for (i = 0; i < NumChannels; i++) {
ifree(Channels[i]);
}
ifree(Channels);
}
if (Alpha) {
ifree(Alpha);
}
Channels = NULL;
Alpha = NULL;
Pal.Palette = NULL;
return IL_TRUE;
}
#endif//IL_NO_PSP
+120
View File
@@ -0,0 +1,120 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2002 by Denton Woods
// Last modified: 05/26/2002 <--Y2K Compliant! =]
//
// Filename: src-IL/src/il_pxr.c
//
// Description: Reads from a Pxrar (.pxr) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_PXR
#include "il_manip.h"
#include "il_endian.h"
#ifdef _MSC_VER
#pragma pack(push, pxr_struct, 1)
#endif
typedef struct PIXHEAD
{
ILushort Signature;
ILubyte Reserved1[413];
ILushort Height;
ILushort Width;
ILubyte Reserved2[4];
ILubyte BppInfo;
ILubyte Reserved3[598];
} IL_PACKSTRUCT PIXHEAD;
#ifdef _MSC_VER
#pragma pack(pop, pxr_struct)
#endif
ILboolean iLoadPxrInternal(void);
//! Reads a Pxr file
ILboolean ilLoadPxr(ILconst_string FileName)
{
ILHANDLE PxrFile;
ILboolean bPxr = IL_FALSE;
PxrFile = iopenr(FileName);
if (PxrFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bPxr;
}
bPxr = ilLoadPxrF(PxrFile);
icloser(PxrFile);
return bPxr;
}
//! Reads an already-opened Pxr file
ILboolean ilLoadPxrF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadPxrInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Pxr
ILboolean ilLoadPxrL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadPxrInternal();
}
// Internal function used to load the Pxr.
ILboolean iLoadPxrInternal()
{
ILushort Width, Height;
ILubyte Bpp;
Width = sizeof(PIXHEAD);
iseek(416, IL_SEEK_SET);
Height = GetLittleUShort();
Width = GetLittleUShort();
iseek(424, IL_SEEK_SET);
Bpp = (ILubyte)igetc();
switch (Bpp)
{
case 0x08:
ilTexImage(Width, Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
break;
case 0x0E:
ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
break;
case 0x0F:
ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
break;
default:
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
iseek(1024, IL_SEEK_SET);
iread(iCurImage->Data, 1, iCurImage->SizeOfData);
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return IL_TRUE;
}
#endif//IL_NO_PXR
+643
View File
@@ -0,0 +1,643 @@
//-----------------------------------------------------------------------
// Color Quantization Demo
//
// Author: Roman Podobedov
// Email: romka@ut.ee
// Romka Graphics: www.ut.ee/~romka
//
// Also in this file implemented Wu's Color Quantizer algorithm (v. 2)
// For details see Graphics Gems vol. II, pp. 126-133
//
// Wu's Color Quantizer Algorithm:
// Author: Xiaolin Wu
// Dept. of Computer Science
// Univ. of Western Ontario
// London, Ontario N6A 5B7
// wu@csd.uwo.ca
// http://www.csd.uwo.ca/faculty/wu/
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// by Denton Woods
// Last modified: 01/04/2009
//
// Filename: src-IL/src/il_quantizer.c
//
// Description: Heavily modified by Denton Woods.
//
// 20040223 XIX : Modified so it works better with color requests < 256
// pallete always has memory space for 256 entries
// used so we can quant down to 255 colors then add a transparent color in there.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#define MAXCOLOR 256
#define RED 2
#define GREEN 1
#define BLUE 0
typedef struct Box
{
ILint r0; // min value, exclusive
ILint r1; // max value, inclusive
ILint g0;
ILint g1;
ILint b0;
ILint b1;
ILint vol;
} Box;
/* Histogram is in elements 1..HISTSIZE along each axis,
* element 0 is for base or marginal value
* NB: these must start out 0!
*/
ILfloat gm2[33][33][33];
ILint wt[33][33][33], mr[33][33][33], mg[33][33][33], mb[33][33][33];
ILuint size; //image size
ILint K; //colour look-up table size
ILushort *Qadd;
ILint WindW, WindH, WindD;
ILint i;
ILubyte *buffer;
static ILint Width, Height, Depth, Comp;
/*ILint TotalColors;
ILint a, b;
ILubyte *buf1, *buf2;*/
ILuint n2(ILint s)
{
ILint i;
ILint res;
res = 1;
for (i = 0; i < s; i++) {
res = res*2;
}
return res;
}
// Build 3-D color histogram of counts, r/g/b, c^2
ILboolean Hist3d(ILubyte *Ir, ILubyte *Ig, ILubyte *Ib, ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
{
ILint ind, r, g, b;
ILint inr, ing, inb, table[2560];
ILuint i;
for (i = 0; i < 256; i++)
{
table[i] = i * i;
}
Qadd = (ILushort*)ialloc(sizeof(ILushort) * size);
if (Qadd == NULL)
{
return IL_FALSE;
}
imemclear(Qadd, sizeof(ILushort) * size);
for (i = 0; i < size; i++)
{
r = Ir[i]; g = Ig[i]; b = Ib[i];
inr = (r>>3) + 1;
ing = (g>>3) + 1;
inb = (b>>3) + 1;
Qadd[i] = ind = (inr<<10)+(inr<<6)+inr+(ing<<5)+ing+inb;
//[inr][ing][inb]
vwt[ind]++;
vmr[ind] += r;
vmg[ind] += g;
vmb[ind] += b;
m2[ind] += (ILfloat)(table[r]+table[g]+table[b]);
}
return IL_TRUE;
}
/* At conclusion of the histogram step, we can interpret
* wt[r][g][b] = sum over voxel of P(c)
* mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
* m2[r][g][b] = sum over voxel of c^2*P(c)
* Actually each of these should be divided by 'size' to give the usual
* interpretation of P() as ranging from 0 to 1, but we needn't do that here.
*/
/* We now convert histogram into moments so that we can rapidly calculate
* the sums of the above quantities over any desired Box.
*/
// Compute cumulative moments
void M3d(ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
{
ILushort ind1, ind2;
ILubyte i, r, g, b;
ILint line, line_r, line_g, line_b, area[33], area_r[33], area_g[33], area_b[33];
ILfloat line2, area2[33];
for (r = 1; r <= 32; r++) {
for (i = 0; i <= 32; i++) {
area2[i] = 0.0f;
area[i]=area_r[i]=area_g[i]=area_b[i]=0;
}
for (g = 1; g <= 32; g++) {
line2 = 0.0f;
line = line_r = line_g = line_b = 0;
for (b = 1; b <= 32; b++) {
ind1 = (r<<10) + (r<<6) + r + (g<<5) + g + b; // [r][g][b]
line += vwt[ind1];
line_r += vmr[ind1];
line_g += vmg[ind1];
line_b += vmb[ind1];
line2 += m2[ind1];
area[b] += line;
area_r[b] += line_r;
area_g[b] += line_g;
area_b[b] += line_b;
area2[b] += line2;
ind2 = ind1 - 1089; // [r-1][g][b]
vwt[ind1] = vwt[ind2] + area[b];
vmr[ind1] = vmr[ind2] + area_r[b];
vmg[ind1] = vmg[ind2] + area_g[b];
vmb[ind1] = vmb[ind2] + area_b[b];
m2[ind1] = m2[ind2] + area2[b];
}
}
}
return;
}
// Compute sum over a Box of any given statistic
ILint Vol(Box *cube, ILint mmt[33][33][33])
{
return( mmt[cube->r1][cube->g1][cube->b1]
-mmt[cube->r1][cube->g1][cube->b0]
-mmt[cube->r1][cube->g0][cube->b1]
+mmt[cube->r1][cube->g0][cube->b0]
-mmt[cube->r0][cube->g1][cube->b1]
+mmt[cube->r0][cube->g1][cube->b0]
+mmt[cube->r0][cube->g0][cube->b1]
-mmt[cube->r0][cube->g0][cube->b0] );
}
/* The next two routines allow a slightly more efficient calculation
* of Vol() for a proposed subBox of a given Box. The sum of Top()
* and Bottom() is the Vol() of a subBox split in the given direction
* and with the specified new upper bound.
*/
// Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1
// (depending on dir)
ILint Bottom(Box *cube, ILubyte dir, ILint mmt[33][33][33])
{
switch(dir)
{
case RED:
return( -mmt[cube->r0][cube->g1][cube->b1]
+mmt[cube->r0][cube->g1][cube->b0]
+mmt[cube->r0][cube->g0][cube->b1]
-mmt[cube->r0][cube->g0][cube->b0] );
break;
case GREEN:
return( -mmt[cube->r1][cube->g0][cube->b1]
+mmt[cube->r1][cube->g0][cube->b0]
+mmt[cube->r0][cube->g0][cube->b1]
-mmt[cube->r0][cube->g0][cube->b0] );
break;
case BLUE:
return( -mmt[cube->r1][cube->g1][cube->b0]
+mmt[cube->r1][cube->g0][cube->b0]
+mmt[cube->r0][cube->g1][cube->b0]
-mmt[cube->r0][cube->g0][cube->b0] );
break;
}
return 0;
}
// Compute remainder of Vol(cube, mmt), substituting pos for
// r1, g1, or b1 (depending on dir)
ILint Top(Box *cube, ILubyte dir, ILint pos, ILint mmt[33][33][33])
{
switch (dir)
{
case RED:
return( mmt[pos][cube->g1][cube->b1]
-mmt[pos][cube->g1][cube->b0]
-mmt[pos][cube->g0][cube->b1]
+mmt[pos][cube->g0][cube->b0] );
break;
case GREEN:
return( mmt[cube->r1][pos][cube->b1]
-mmt[cube->r1][pos][cube->b0]
-mmt[cube->r0][pos][cube->b1]
+mmt[cube->r0][pos][cube->b0] );
break;
case BLUE:
return( mmt[cube->r1][cube->g1][pos]
-mmt[cube->r1][cube->g0][pos]
-mmt[cube->r0][cube->g1][pos]
+mmt[cube->r0][cube->g0][pos] );
break;
}
return 0;
}
// Compute the weighted variance of a Box
// NB: as with the raw statistics, this is really the variance * size
ILfloat Var(Box *cube)
{
ILfloat dr, dg, db, xx;
dr = (ILfloat)Vol(cube, mr);
dg = (ILfloat)Vol(cube, mg);
db = (ILfloat)Vol(cube, mb);
xx = gm2[cube->r1][cube->g1][cube->b1]
-gm2[cube->r1][cube->g1][cube->b0]
-gm2[cube->r1][cube->g0][cube->b1]
+gm2[cube->r1][cube->g0][cube->b0]
-gm2[cube->r0][cube->g1][cube->b1]
+gm2[cube->r0][cube->g1][cube->b0]
+gm2[cube->r0][cube->g0][cube->b1]
-gm2[cube->r0][cube->g0][cube->b0];
return xx - (dr*dr+dg*dg+db*db) / (ILfloat)Vol(cube, wt);
}
/* We want to minimize the sum of the variances of two subBoxes.
* The sum(c^2) terms can be ignored since their sum over both subBoxes
* is the same (the sum for the whole Box) no matter where we split.
* The remaining terms have a minus sign in the variance formula,
* so we drop the minus sign and MAXIMIZE the sum of the two terms.
*/
ILfloat Maximize(Box *cube, ILubyte dir, ILint first, ILint last, ILint *cut,
ILint whole_r, ILint whole_g, ILint whole_b, ILint whole_w)
{
ILint half_r, half_g, half_b, half_w;
ILint base_r, base_g, base_b, base_w;
ILint i;
ILfloat temp, max;
base_r = Bottom(cube, dir, mr);
base_g = Bottom(cube, dir, mg);
base_b = Bottom(cube, dir, mb);
base_w = Bottom(cube, dir, wt);
max = 0.0;
*cut = -1;
for (i = first; i < last; ++i) {
half_r = base_r + Top(cube, dir, i, mr);
half_g = base_g + Top(cube, dir, i, mg);
half_b = base_b + Top(cube, dir, i, mb);
half_w = base_w + Top(cube, dir, i, wt);
// Now half_x is sum over lower half of Box, if split at i
if (half_w == 0) { // subBox could be empty of pixels!
continue; // never split into an empty Box
}
else {
temp = ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
(ILfloat)half_b*half_b) / half_w;
}
half_r = whole_r - half_r;
half_g = whole_g - half_g;
half_b = whole_b - half_b;
half_w = whole_w - half_w;
if (half_w == 0) { // subBox could be empty of pixels!
continue; // never split into an empty Box
}
else {
temp += ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
(ILfloat)half_b*half_b) / half_w;
}
if (temp > max) {
max = temp;
*cut = i;
}
}
return max;
}
ILint Cut(Box *set1, Box *set2)
{
ILubyte dir;
ILint cutr, cutg, cutb;
ILfloat maxr, maxg, maxb;
ILint whole_r, whole_g, whole_b, whole_w;
whole_r = Vol(set1, mr);
whole_g = Vol(set1, mg);
whole_b = Vol(set1, mb);
whole_w = Vol(set1, wt);
maxr = Maximize(set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w);
maxg = Maximize(set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w);
maxb = Maximize(set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w);
if ((maxr >= maxg) && (maxr >= maxb)) {
dir = RED;
if (cutr < 0)
return 0; // can't split the Box
}
else if ((maxg >= maxr) && (maxg >= maxb))
dir = GREEN;
else
dir = BLUE;
set2->r1 = set1->r1;
set2->g1 = set1->g1;
set2->b1 = set1->b1;
switch (dir)
{
case RED:
set2->r0 = set1->r1 = cutr;
set2->g0 = set1->g0;
set2->b0 = set1->b0;
break;
case GREEN:
set2->g0 = set1->g1 = cutg;
set2->r0 = set1->r0;
set2->b0 = set1->b0;
break;
case BLUE:
set2->b0 = set1->b1 = cutb;
set2->r0 = set1->r0;
set2->g0 = set1->g0;
break;
}
set1->vol = (set1->r1-set1->r0) * (set1->g1-set1->g0) * (set1->b1-set1->b0);
set2->vol = (set2->r1-set2->r0) * (set2->g1-set2->g0) * (set2->b1-set2->b0);
return 1;
}
void Mark(struct Box *cube, int label, unsigned char *tag)
{
ILint r, g, b;
for (r = cube->r0 + 1; r <= cube->r1; r++) {
for (g = cube->g0 + 1; g <= cube->g1; g++) {
for (b = cube->b0 + 1; b <= cube->b1; b++) {
tag[(r<<10) + (r<<6) + r + (g<<5) + g + b] = label;
}
}
}
return;
}
ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols)
{
Box cube[MAXCOLOR];
ILubyte *tag = NULL;
ILubyte lut_r[MAXCOLOR], lut_g[MAXCOLOR], lut_b[MAXCOLOR];
ILint next;
ILint weight;
ILuint k;
ILfloat vv[MAXCOLOR], temp;
//ILint color_num;
ILubyte *NewData = NULL, *Palette = NULL;
ILimage *TempImage = NULL, *NewImage = NULL;
ILubyte *Ir = NULL, *Ig = NULL, *Ib = NULL;
ILint num_alloced_colors; // number of colors we allocated space for in palette, as NumCols but will not be less than 256
num_alloced_colors=NumCols;
if(num_alloced_colors<256) { num_alloced_colors=256; }
NewImage = iCurImage;
iCurImage = Image;
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
iCurImage = NewImage;
if (TempImage == NULL)
return NULL;
buffer = Image->Data;
WindW = Width = Image->Width;
WindH = Height = Image->Height;
WindD = Depth = Image->Depth;
Comp = Image->Bpp;
Qadd = NULL;
//color_num = ImagePrecalculate(Image);
NewData = (ILubyte*)ialloc(Image->Width * Image->Height * Image->Depth);
Palette = (ILubyte*)ialloc(3 * num_alloced_colors);
if (!NewData || !Palette) {
ifree(NewData);
ifree(Palette);
return NULL;
}
Ir = (ILubyte*)ialloc(Width * Height * Depth);
Ig = (ILubyte*)ialloc(Width * Height * Depth);
Ib = (ILubyte*)ialloc(Width * Height * Depth);
if (!Ir || !Ig || !Ib) {
ifree(Ir);
ifree(Ig);
ifree(Ib);
ifree(NewData);
ifree(Palette);
return NULL;
}
size = Width * Height * Depth;
#ifdef ALTIVEC_GCC
register ILuint v_size = size>>4;
register ILuint pos = 0;
v_size = v_size /3;
register vector unsigned char d0,d1,d2;
register vector unsigned char red[3],blu[3],green[3];
register union{
vector unsigned char vec;
vector unsigned int load;
} mask_1, mask_2, mask_3;
mask_1.load = (vector unsigned int){0xFF0000FF,0x0000FF00,0x00FF0000,0xFF0000FF};
mask_2.load = (vector unsigned int){0x00FF0000,0xFF0000FF,0x0000FF00,0x00FF0000};
mask_2.load = (vector unsigned int){0x0000FF00,0x00FF0000,0xFF0000FF,0x0000FF00};
while( v_size >= 0 ) {
d0 = vec_ld(pos,TempImage->Data);
d1 = vec_ld(pos+16,TempImage->Data);
d2 = vec_ld(pos+32,TempImage->Data);
red[0] = vec_and(d0,mask_1.vec);
green[0] = vec_and(d0,mask_2.vec);
blu[0] = vec_and(d0,mask_3.vec);
red[1] = vec_and(d1,mask_3.vec);
green[1] = vec_and(d1,mask_1.vec);
blu[1] = vec_and(d1,mask_2.vec);
red[2] = vec_and(d2,mask_2.vec);
green[2] = vec_and(d2,mask_3.vec);
blu[2] = vec_and(d2,mask_1.vec);
vec_st(red[0],pos,Ir);
vec_st(red[1],pos+16,Ir);
vec_st(red[2],pos+32,Ir);
vec_st(blu[0],pos,Ib);
vec_st(blu[1],pos+16,Ib);
vec_st(blu[2],pos+32,Ib);
vec_st(green[0],pos,Ig);
vec_st(green[1],pos+16,Ig);
vec_st(green[2],pos+32,Ig);
pos += 48;
}
size -= pos;
#endif
for (k = 0; k < size; k++) {
Ir[k] = TempImage->Data[k * 3];
Ig[k] = TempImage->Data[k * 3 + 1];
Ib[k] = TempImage->Data[k * 3 + 2];
}
#ifdef ALTIVEC_GCC
size = Width * Height * Depth;
#endif
// Set new colors number
K = NumCols;
if (K <= 256) {
// Begin Wu's color quantization algorithm
// May have "leftovers" from a previous run.
imemclear(gm2, 33 * 33 * 33 * sizeof(ILfloat));
imemclear(wt, 33 * 33 * 33 * sizeof(ILint));
imemclear(mr, 33 * 33 * 33 * sizeof(ILint));
imemclear(mg, 33 * 33 * 33 * sizeof(ILint));
imemclear(mb, 33 * 33 * 33 * sizeof(ILint));
if (!Hist3d(Ir, Ig, Ib, (ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2))
goto error_label;
M3d((ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2);
cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
next = 0;
for (i = 1; i < K; ++i) {
if (Cut(&cube[next], &cube[i])) { // volume test ensures we won't try to cut one-cell Box */
vv[next] = (cube[next].vol>1) ? Var(&cube[next]) : 0.0f;
vv[i] = (cube[i].vol>1) ? Var(&cube[i]) : 0.0f;
}
else {
vv[next] = 0.0; // don't try to split this Box again
i--; // didn't create Box i
}
next = 0;
temp = vv[0];
for (k = 1; (ILint)k <= i; ++k) {
if (vv[k] > temp) {
temp = vv[k]; next = k;
}
}
if (temp <= 0.0) {
K = i+1;
// Only got K Boxes
break;
}
}
tag = (ILubyte*)ialloc(33 * 33 * 33 * sizeof(ILubyte));
if (tag == NULL)
goto error_label;
for (k = 0; (ILint)k < K; k++) {
Mark(&cube[k], k, tag);
weight = Vol(&cube[k], wt);
if (weight) {
lut_r[k] = (ILubyte)(Vol(&cube[k], mr) / weight);
lut_g[k] = (ILubyte)(Vol(&cube[k], mg) / weight);
lut_b[k] = (ILubyte)(Vol(&cube[k], mb) / weight);
}
else {
// Bogus Box
lut_r[k] = lut_g[k] = lut_b[k] = 0;
}
}
for (i = 0; i < (ILint)size; i++) {
NewData[i] = tag[Qadd[i]];
}
ifree(tag);
ifree(Qadd);
for (k = 0; k < NumCols; k++) {
Palette[k * 3] = lut_b[k];
Palette[k * 3 + 1] = lut_g[k];
Palette[k * 3 + 2] = lut_r[k];
}
}
else { // If colors more than 256
// Begin Octree quantization
//Quant_Octree(Image->Width, Image->Height, Image->Bpp, buffer2, NewData, Palette, K);
ilSetError(IL_INTERNAL_ERROR); // Can't get much more specific than this.
goto error_label;
}
ifree(Ig);
ifree(Ib);
ifree(Ir);
ilCloseImage(TempImage);
NewImage = (ILimage*)icalloc(sizeof(ILimage), 1);
if (NewImage == NULL) {
return NULL;
}
ilCopyImageAttr(NewImage, Image);
NewImage->Bpp = 1;
NewImage->Bps = Image->Width;
NewImage->SizeOfPlane = NewImage->Bps * Image->Height;
NewImage->SizeOfData = NewImage->SizeOfPlane;
NewImage->Format = IL_COLOUR_INDEX;
NewImage->Type = IL_UNSIGNED_BYTE;
NewImage->Pal.Palette = Palette;
NewImage->Pal.PalSize = 256 * 3;
NewImage->Pal.PalType = IL_PAL_BGR24;
NewImage->Data = NewData;
return NewImage;
error_label:
ifree(NewData);
ifree(Palette);
ifree(Ig);
ifree(Ib);
ifree(Ir);
ifree(tag);
ifree(Qadd);
return NULL;
}
+188
View File
@@ -0,0 +1,188 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_raw.c
//
// Description: "Raw" file functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_RAW
ILboolean iLoadRawInternal(void);
ILboolean iSaveRawInternal(void);
//! Reads a raw file
ILboolean ilLoadRaw(ILconst_string FileName)
{
ILHANDLE RawFile;
ILboolean bRaw = IL_FALSE;
// No need to check for raw
/*if (!iCheckExtension(FileName, "raw")) {
ilSetError(IL_INVALID_EXTENSION);
return bRaw;
}*/
RawFile = iopenr(FileName);
if (RawFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bRaw;
}
bRaw = ilLoadRawF(RawFile);
icloser(RawFile);
return bRaw;
}
//! Reads an already-opened raw file
ILboolean ilLoadRawF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadRawInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a raw memory "lump"
ILboolean ilLoadRawL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadRawInternal();
}
// Internal function to load a raw image
ILboolean iLoadRawInternal()
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
iCurImage->Width = GetLittleUInt();
iCurImage->Height = GetLittleUInt();
iCurImage->Depth = GetLittleUInt();
iCurImage->Bpp = (ILubyte)igetc();
if (iread(&iCurImage->Bpc, 1, 1) != 1)
return IL_FALSE;
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth, iCurImage->Bpp, 0, ilGetTypeBpc(iCurImage->Bpc), NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
// Tries to read the correct amount of data
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) < iCurImage->SizeOfData)
return IL_FALSE;
if (ilIsEnabled(IL_ORIGIN_SET)) {
iCurImage->Origin = ilGetInteger(IL_ORIGIN_MODE);
}
else {
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
}
if (iCurImage->Bpp == 1)
iCurImage->Format = IL_LUMINANCE;
else if (iCurImage->Bpp == 3)
iCurImage->Format = IL_RGB;
else // 4
iCurImage->Format = IL_RGBA;
return ilFixImage();
}
//! Writes a Raw file
ILboolean ilSaveRaw(const ILstring FileName)
{
ILHANDLE RawFile;
ILuint RawSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
RawFile = iopenw(FileName);
if (RawFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
RawSize = ilSaveRawF(RawFile);
iclosew(RawFile);
if (RawSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes Raw to an already-opened file
ILuint ilSaveRawF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSaveRawInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes Raw to a memory "lump"
ILuint ilSaveRawL(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSaveRawInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to load the raw data.
ILboolean iSaveRawInternal()
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
SaveLittleUInt(iCurImage->Width);
SaveLittleUInt(iCurImage->Height);
SaveLittleUInt(iCurImage->Depth);
iputc(iCurImage->Bpp);
iputc(iCurImage->Bpc);
iwrite(iCurImage->Data, 1, iCurImage->SizeOfData);
return IL_TRUE;
}
#endif//IL_NO_RAW
+121
View File
@@ -0,0 +1,121 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/rawdata.c
//
// Description: "Raw" file functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
//#ifndef IL_NO_DATA
#include "il_manip.h"
ILboolean iLoadDataInternal(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp);
//! Reads a raw data file
ILboolean ILAPIENTRY ilLoadData(ILconst_string FileName, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
{
ILHANDLE RawFile;
ILboolean bRaw = IL_FALSE;
// No need to check for raw data
/*if (!iCheckExtension(FileName, "raw")) {
ilSetError(IL_INVALID_EXTENSION);
return bRaw;
}*/
RawFile = iopenr(FileName);
if (RawFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bRaw;
}
bRaw = ilLoadDataF(RawFile, Width, Height, Depth, Bpp);
icloser(RawFile);
return bRaw;
}
//! Reads an already-opened raw data file
ILboolean ILAPIENTRY ilLoadDataF(ILHANDLE File, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadDataInternal(Width, Height, Depth, Bpp);
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a raw data memory "lump"
ILboolean ILAPIENTRY ilLoadDataL(void *Lump, ILuint Size, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
{
iSetInputLump(Lump, Size);
return iLoadDataInternal(Width, Height, Depth, Bpp);
}
// Internal function to load a raw data image
ILboolean iLoadDataInternal(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
{
if (iCurImage == NULL || ((Bpp != 1) && (Bpp != 3) && (Bpp != 4))) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!ilTexImage(Width, Height, Depth, Bpp, 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
// Tries to read the correct amount of data
if (iread(iCurImage->Data, Width * Height * Depth * Bpp, 1) != 1)
return IL_FALSE;
if (iCurImage->Bpp == 1)
iCurImage->Format = IL_LUMINANCE;
else if (iCurImage->Bpp == 3)
iCurImage->Format = IL_RGB;
else // 4
iCurImage->Format = IL_RGBA;
return ilFixImage();
}
//! Save the current image to FileName as raw data
ILboolean ILAPIENTRY ilSaveData(ILconst_string FileName)
{
ILHANDLE DataFile;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
DataFile = iopenr(FileName);
if (DataFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
iwrite(iCurImage->Data, 1, iCurImage->SizeOfData);
icloser(DataFile);
return IL_TRUE;
}
//#endif//IL_NO_DATA
+434
View File
@@ -0,0 +1,434 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 11/07/2008
//
// Filename: src-IL/src/il_register.c
//
// Description: Allows the caller to specify user-defined callback functions
// to open files DevIL does not support, to parse files
// differently, or anything else a person can think up.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#include "il_register.h"
#include <string.h>
// Linked lists of registered formats
iFormatL *LoadProcs = NULL;
iFormatS *SaveProcs = NULL;
ILboolean ILAPIENTRY ilRegisterLoad(ILconst_string Ext, IL_LOADPROC Load) {
iFormatL *TempNode, *NewNode;
TempNode = LoadProcs;
if (TempNode != NULL) {
while (TempNode->Next != NULL) {
TempNode = TempNode->Next;
if (!iStrCmp(TempNode->Ext, Ext)) { // already registered
return IL_TRUE;
}
}
}
NewNode = (iFormatL*)ialloc(sizeof(iFormatL));
if (NewNode == NULL) {
return IL_FALSE;
}
if (LoadProcs == NULL) {
LoadProcs = NewNode;
}
else {
TempNode->Next = NewNode;
}
NewNode->Ext = ilStrDup(Ext);
NewNode->Load = Load;
NewNode->Next = NULL;
return IL_TRUE;
}
ILboolean ILAPIENTRY ilRegisterSave(ILconst_string Ext, IL_SAVEPROC Save)
{
iFormatS *TempNode, *NewNode;
TempNode = SaveProcs;
if (TempNode != NULL) {
while (TempNode->Next != NULL) {
TempNode = TempNode->Next;
if (!iStrCmp(TempNode->Ext, Ext)) { // already registered
return IL_TRUE;
}
}
}
NewNode = (iFormatS*)ialloc(sizeof(iFormatL));
if (NewNode == NULL) {
return IL_FALSE;
}
if (SaveProcs == NULL) {
SaveProcs = NewNode;
}
else {
TempNode->Next = NewNode;
}
NewNode->Ext = ilStrDup(Ext);
NewNode->Save = Save;
NewNode->Next = NULL;
return IL_TRUE;
}
//! Unregisters a load extension - doesn't have to be called.
ILboolean ILAPIENTRY ilRemoveLoad(ILconst_string Ext)
{
iFormatL *TempNode = LoadProcs, *PrevNode = NULL;
while (TempNode != NULL) {
if (!iStrCmp(Ext, TempNode->Ext)) {
if (PrevNode == NULL) { // first node in the list
LoadProcs = TempNode->Next;
ifree((void*)TempNode->Ext);
ifree(TempNode);
}
else {
PrevNode->Next = TempNode->Next;
ifree((void*)TempNode->Ext);
ifree(TempNode);
}
return IL_TRUE;
}
PrevNode = TempNode;
TempNode = TempNode->Next;
}
return IL_FALSE;
}
//! Unregisters a save extension - doesn't have to be called.
ILboolean ILAPIENTRY ilRemoveSave(ILconst_string Ext)
{
iFormatS *TempNode = SaveProcs, *PrevNode = NULL;
while (TempNode != NULL) {
if (!iStrCmp(Ext, TempNode->Ext)) {
if (PrevNode == NULL) { // first node in the list
SaveProcs = TempNode->Next;
ifree((void*)TempNode->Ext);
ifree(TempNode);
}
else {
PrevNode->Next = TempNode->Next;
ifree((void*)TempNode->Ext);
ifree(TempNode);
}
return IL_TRUE;
}
PrevNode = TempNode;
TempNode = TempNode->Next;
}
return IL_FALSE;
}
// Automatically removes all registered formats.
void ilRemoveRegistered()
{
iFormatL *TempNodeL = LoadProcs;
iFormatS *TempNodeS = SaveProcs;
while (LoadProcs != NULL) {
TempNodeL = LoadProcs->Next;
ifree((void*)LoadProcs->Ext);
ifree(LoadProcs);
LoadProcs = TempNodeL;
}
while (SaveProcs != NULL) {
TempNodeS = SaveProcs->Next;
ifree((void*)SaveProcs->Ext);
ifree(SaveProcs);
SaveProcs = TempNodeS;
}
return;
}
ILboolean iRegisterLoad(ILconst_string FileName)
{
iFormatL *TempNode = LoadProcs;
ILstring Ext = iGetExtension(FileName);
ILenum Error;
if (!Ext)
return IL_FALSE;
while (TempNode != NULL) {
if (!iStrCmp(Ext, TempNode->Ext)) {
Error = TempNode->Load(FileName);
if (Error == IL_NO_ERROR || Error == 0) { // 0 and IL_NO_ERROR are both valid.
return IL_TRUE;
}
else {
ilSetError(Error);
return IL_FALSE;
}
}
TempNode = TempNode->Next;
}
return IL_FALSE;
}
ILboolean iRegisterSave(ILconst_string FileName)
{
iFormatS *TempNode = SaveProcs;
ILstring Ext = iGetExtension(FileName);
ILenum Error;
if (!Ext)
return IL_FALSE;
while (TempNode != NULL) {
if (!iStrCmp(Ext, TempNode->Ext)) {
Error = TempNode->Save(FileName);
if (Error == IL_NO_ERROR || Error == 0) { // 0 and IL_NO_ERROR are both valid.
return IL_TRUE;
}
else {
ilSetError(Error);
return IL_FALSE;
}
}
TempNode = TempNode->Next;
}
return IL_FALSE;
}
//
// "Reporting" functions
//
void ILAPIENTRY ilRegisterOrigin(ILenum Origin)
{
switch (Origin)
{
case IL_ORIGIN_LOWER_LEFT:
case IL_ORIGIN_UPPER_LEFT:
iCurImage->Origin = Origin;
break;
default:
ilSetError(IL_INVALID_ENUM);
}
return;
}
void ILAPIENTRY ilRegisterFormat(ILenum Format)
{
switch (Format)
{
case IL_COLOUR_INDEX:
case IL_RGB:
case IL_RGBA:
case IL_BGR:
case IL_BGRA:
case IL_LUMINANCE:
case IL_LUMINANCE_ALPHA:
iCurImage->Format = Format;
break;
default:
ilSetError(IL_INVALID_ENUM);
}
return;
}
ILboolean ILAPIENTRY ilRegisterNumFaces(ILuint Num)
{
ILimage *Next, *Prev;
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
ilCloseImage(iCurImage->Faces); // Close any current mipmaps.
iCurImage->Faces = NULL;
if (Num == 0) // Just gets rid of all the mipmaps.
return IL_TRUE;
iCurImage->Faces = ilNewImage(1, 1, 1, 1, 1);
if (iCurImage->Faces == NULL)
return IL_FALSE;
Next = iCurImage->Faces;
Num--;
while (Num) {
Next->Faces = ilNewImage(1, 1, 1, 1, 1);
if (Next->Faces == NULL) {
// Clean up before we error out.
Prev = iCurImage->Faces;
while (Prev) {
Next = Prev->Faces;
ilCloseImage(Prev);
Prev = Next;
}
return IL_FALSE;
}
Next = Next->Faces;
Num--;
}
return IL_TRUE;
}
ILboolean ILAPIENTRY ilRegisterMipNum(ILuint Num)
{
ILimage *Next, *Prev;
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
ilCloseImage(iCurImage->Mipmaps); // Close any current mipmaps.
iCurImage->Mipmaps = NULL;
if (Num == 0) // Just gets rid of all the mipmaps.
return IL_TRUE;
iCurImage->Mipmaps = ilNewImage(1, 1, 1, 1, 1);
if (iCurImage->Mipmaps == NULL)
return IL_FALSE;
Next = iCurImage->Mipmaps;
Num--;
while (Num) {
Next->Next = ilNewImage(1, 1, 1, 1, 1);
if (Next->Next == NULL) {
// Clean up before we error out.
Prev = iCurImage->Mipmaps;
while (Prev) {
Next = Prev->Next;
ilCloseImage(Prev);
Prev = Next;
}
return IL_FALSE;
}
Next = Next->Next;
Num--;
}
return IL_TRUE;
}
ILboolean ILAPIENTRY ilRegisterNumImages(ILuint Num)
{
ILimage *Next, *Prev;
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
ilCloseImage(iCurImage->Next); // Close any current "next" images.
iCurImage->Next = NULL;
if (Num == 0) // Just gets rid of all the "next" images.
return IL_TRUE;
iCurImage->Next = ilNewImage(1, 1, 1, 1, 1);
if (iCurImage->Next == NULL)
return IL_FALSE;
Next = iCurImage->Next;
Num--;
while (Num) {
Next->Next = ilNewImage(1, 1, 1, 1, 1);
if (Next->Next == NULL) {
// Clean up before we error out.
Prev = iCurImage->Next;
while (Prev) {
Next = Prev->Next;
ilCloseImage(Prev);
Prev = Next;
}
return IL_FALSE;
}
Next = Next->Next;
Num--;
}
return IL_TRUE;
}
void ILAPIENTRY ilRegisterType(ILenum Type)
{
switch (Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
case IL_SHORT:
case IL_UNSIGNED_SHORT:
case IL_INT:
case IL_UNSIGNED_INT:
case IL_FLOAT:
case IL_DOUBLE:
iCurImage->Type = Type;
break;
default:
ilSetError(IL_INVALID_ENUM);
}
return;
}
void ILAPIENTRY ilRegisterPal(void *Pal, ILuint Size, ILenum Type)
{
if (!iCurImage->Pal.Palette || !iCurImage->Pal.PalSize || iCurImage->Pal.PalType != IL_PAL_NONE) {
ifree(iCurImage->Pal.Palette);
}
iCurImage->Pal.PalSize = Size;
iCurImage->Pal.PalType = Type;
iCurImage->Pal.Palette = (ILubyte*)ialloc(Size);
if (iCurImage->Pal.Palette == NULL)
return;
if (Pal != NULL) {
memcpy(iCurImage->Pal.Palette, Pal, Size);
}
else {
ilSetError(IL_INVALID_PARAM);
}
return;
}
ILboolean ILAPIENTRY ilSetDuration(ILuint Duration)
{
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
iCurImage->Duration = Duration;
return IL_TRUE;
}
+153
View File
@@ -0,0 +1,153 @@
//-----------------------------------------------------------------------------
// Description: Functions for run-length encoding
//-----------------------------------------------------------------------------
// RLE code from TrueVision's TGA sample code available as Tgautils.zip at
// ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version
#define IL_RLE_C
#include "il_internal.h"
#include "il_rle.h"
ILboolean ilRleCompressLine(ILubyte *p, ILuint n, ILubyte bpp,
ILubyte *q, ILuint *DestWidth, ILenum CompressMode) {
ILint DiffCount; // pixel count until two identical
ILint SameCount; // number of identical adjacent pixels
ILint RLEBufSize = 0; // count of number of bytes encoded
ILint MaxRun;
const ILint bmp_pad_to_even = 1 - ((ILint)q - *DestWidth) % 2;
switch( CompressMode ) {
case IL_TGACOMP:
MaxRun = TGA_MAX_RUN;
break;
case IL_SGICOMP:
MaxRun = SGI_MAX_RUN;
break;
case IL_BMPCOMP:
MaxRun = BMP_MAX_RUN;
break;
default:
ilSetError(IL_INVALID_PARAM);
return IL_FALSE;
}
while( n > 0 ) {
// Analyze pixels
DiffCount = CountDiffPixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n);
SameCount = CountSamePixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n);
if( CompressMode == IL_BMPCOMP ) {
ILint remaining_data = n - DiffCount - SameCount;
if( remaining_data < 3 ) { // check if the run has gone near the end
// no absolute run can be done
// complete the line adding 0x01 + pixel, for each pixel
while( remaining_data > 0 ) {
*q++ = 0x01;
*q++ = *p++;
remaining_data--;
}
DiffCount = 0;
SameCount = 0;
n = 0;
}
}
if( DiffCount > 0 ) { // create a raw packet (bmp absolute run)
switch(CompressMode) {
case IL_TGACOMP:
*q++ = (ILbyte)(DiffCount - 1);
break;
case IL_BMPCOMP:
*q++ = 0x00; RLEBufSize++;
*q++ = (ILbyte)DiffCount;
break;
case IL_SGICOMP:
*q++ = (ILbyte)(DiffCount | 0x80);
break;
}
n -= DiffCount;
RLEBufSize += (DiffCount * bpp) + 1;
while( DiffCount > 0 ) {
switch(bpp) {
case 4: *q++ = *p++;
case 3: *q++ = *p++;
case 2: *q++ = *p++;
case 1: *q++ = *p++;
}
DiffCount--;
}
if( CompressMode == IL_BMPCOMP ) {
if( (size_t)q % 2 == bmp_pad_to_even ) {
*q++ = 0x00; // insert padding
}
}
}
if( SameCount > 1 ) { // create a RLE packet
switch(CompressMode) {
case IL_TGACOMP:
*q++ = (ILbyte)((SameCount - 1) | 0x80);
break;
case IL_SGICOMP:
case IL_BMPCOMP:
*q++ = (ILbyte)(SameCount);
break;
}
n -= SameCount;
RLEBufSize += bpp + 1;
p += (SameCount - 1) * bpp;
*q++ = *p++;
switch(bpp) {
case 4: *q++ = *p++;
case 3: *q++ = *p++;
case 2: *q++ = *p++;
case 1: *q++ = *p++;
}
}
}
// write line termination code
switch(CompressMode) {
case IL_SGICOMP:
++RLEBufSize;
*q++ = 0;
break;
case IL_BMPCOMP:
*q++ = 0x00; RLEBufSize++;
*q++ = 0x00; RLEBufSize++;
break;
}
*DestWidth = RLEBufSize;
return IL_TRUE;
}
// Compresses an entire image using run-length encoding
ILuint ilRleCompress(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp,
ILubyte *Dest, ILenum CompressMode, ILuint *ScanTable) {
ILuint DestW = 0, i, j, LineLen, Bps = Width * Bpp, SizeOfPlane = Width * Height * Bpp;
if( ScanTable )
imemclear(ScanTable,Depth*Height*sizeof(ILuint));
for( j = 0; j < Depth; j++ ) {
for( i = 0; i < Height; i++ ) {
if( ScanTable )
*ScanTable++ = DestW;
ilRleCompressLine(Data + j * SizeOfPlane + i * Bps, Width, Bpp, Dest + DestW, &LineLen, CompressMode);
DestW += LineLen;
}
}
if( CompressMode == IL_BMPCOMP ) { // add end of image
*(Data+DestW) = 0x00; DestW++;
*(Data+DestW) = 0x01; DestW++;
}
return DestW;
}
+289
View File
@@ -0,0 +1,289 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/15/2009
//
// Filename: src-IL/src/il_rot.c
//
// Description: Reads from a Homeworld 2 - Relic Texture (.rot) file.
//
//-----------------------------------------------------------------------------
// @TODO:
// Note: I am not certain about which is DXT3 and which is DXT5. According to
// http://forums.relicnews.com/showthread.php?t=20512, DXT3 is 1030, and DXT5
// is 1029. However, neither way seems to work quite right for the alpha.
#include "il_internal.h"
#ifndef IL_NO_ROT
#include "il_dds.h"
ILboolean iLoadRotInternal(void);
#define ROT_RGBA32 1024
#define ROT_DXT1 1028
#define ROT_DXT3 1029
#define ROT_DXT5 1030
//! Reads a ROT file
ILboolean ilLoadRot(ILconst_string FileName)
{
ILHANDLE RotFile;
ILboolean bRot = IL_FALSE;
RotFile = iopenr(FileName);
if (RotFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bRot;
}
bRot = ilLoadRotF(RotFile);
icloser(RotFile);
return bRot;
}
//! Reads an already-opened ROT file
ILboolean ilLoadRotF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadRotInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a ROT
ILboolean ilLoadRotL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadRotInternal();
}
// Internal function used to load the ROT.
ILboolean iLoadRotInternal(void)
{
ILubyte Form[4], FormName[4];
ILuint FormLen, Width, Height, Format, Channels, CompSize;
ILuint MipSize, MipLevel, MipWidth, MipHeight;
ILenum FormatIL;
ILimage *Image;
ILboolean BaseCreated = IL_FALSE;
ILubyte *CompData = NULL;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
// The first entry in the file must be 'FORM', 0x20 in a big endian integer and then 'HEAD'.
iread(Form, 1, 4);
FormLen = GetBigUInt();
iread(FormName, 1, 4);
if (strncmp(Form, "FORM", 4) || FormLen != 0x14 || strncmp(FormName, "HEAD", 4)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Next follows the width, height and format in the header.
Width = GetLittleUInt();
Height = GetLittleUInt();
Format = GetLittleUInt();
//@TODO: More formats.
switch (Format)
{
case ROT_RGBA32: // 32-bit RGBA format
Channels = 4;
FormatIL = IL_RGBA;
break;
case ROT_DXT1: // DXT1 (no alpha)
Channels = 4;
FormatIL = IL_RGBA;
break;
case ROT_DXT3: // DXT3
case ROT_DXT5: // DXT5
Channels = 4;
FormatIL = IL_RGBA;
// Allocates the maximum needed (the first width/height given in the file).
CompSize = ((Width + 3) / 4) * ((Height + 3) / 4) * 16;
CompData = ialloc(CompSize);
if (CompData == NULL)
return IL_FALSE;
break;
default:
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (Width == 0 || Height == 0) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
//@TODO: Find out what this is.
GetLittleUInt(); // Skip this for the moment. This appears to be the number of channels.
// Next comes 'FORM', a length and 'MIPS'.
iread(Form, 1, 4);
FormLen = GetBigUInt();
iread(FormName, 1, 4);
//@TODO: Not sure if the FormLen has to be anything specific here.
if (strncmp(Form, "FORM", 4) || strncmp(FormName, "MIPS", 4)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
//@TODO: Can these mipmap levels be in any order? Some things may be easier if the answer is no.
Image = iCurImage;
do {
// Then we have 'FORM' again.
iread(Form, 1, 4);
// This is the size of the mipmap data.
MipSize = GetBigUInt();
iread(FormName, 1, 4);
if (strncmp(Form, "FORM", 4)) {
if (!BaseCreated) { // Our file is malformed.
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// We have reached the end of the mipmap data.
break;
}
if (strncmp(FormName, "MLVL", 4)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Next is the mipmap attributes (level number, width, height and length)
MipLevel = GetLittleUInt();
MipWidth = GetLittleUInt();
MipHeight = GetLittleUInt();
MipSize = GetLittleUInt(); // This is the same as the previous size listed -20 (for attributes).
// Lower level mipmaps cannot be larger than the main image.
if (MipWidth > Width || MipHeight > Height || MipSize > CompSize) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Just create our images here.
if (!BaseCreated) {
if (!ilTexImage(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
BaseCreated = IL_TRUE;
}
else {
Image->Mipmaps = ilNewImageFull(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL);
Image = Image->Mipmaps;
}
switch (Format)
{
case ROT_RGBA32: // 32-bit RGBA format
if (iread(Image->Data, Image->SizeOfData, 1) != 1)
return IL_FALSE;
break;
case ROT_DXT1:
// Allocates the size of the compressed data.
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 8;
if (CompSize != MipSize) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
CompData = ialloc(CompSize);
if (CompData == NULL)
return IL_FALSE;
// Read in the DXT1 data...
if (iread(CompData, CompSize, 1) != 1)
return IL_FALSE;
// ...and decompress it.
if (!DecompressDXT1(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = CompSize;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT1;
CompData = NULL;
}
break;
case ROT_DXT3:
// Allocates the size of the compressed data.
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
if (CompSize != MipSize) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
CompData = ialloc(CompSize);
if (CompData == NULL)
return IL_FALSE;
// Read in the DXT3 data...
if (iread(CompData, MipSize, 1) != 1)
return IL_FALSE;
// ...and decompress it.
if (!DecompressDXT3(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = CompSize;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT3;
CompData = NULL;
}
break;
case ROT_DXT5:
// Allocates the size of the compressed data.
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
if (CompSize != MipSize) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
CompData = ialloc(CompSize);
if (CompData == NULL)
return IL_FALSE;
// Read in the DXT5 data...
if (iread(CompData, MipSize, 1) != 1)
return IL_FALSE;
// ...and decompress it.
if (!DecompressDXT5(Image, CompData)) {
ifree(CompData);
return IL_FALSE;
}
// Keeps a copy
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = CompSize;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT5;
CompData = NULL;
}
break;
}
ifree(CompData); // Free it if it was not saved.
} while (!ieof()); //@TODO: Is there any other condition that should end this?
return ilFixImage();
}
#endif//IL_NO_ROT
+763
View File
@@ -0,0 +1,763 @@
//-----------------------------------------------------------------------------
//
// 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
+185
View File
@@ -0,0 +1,185 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/30/2009
//
// Filename: src-IL/src/il_size.c
//
// Description: Determines the size of output files for lump writing.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
ILuint iTargaSize(void);
ILuint CurPos; // Fake "file" pointer.
ILuint MaxPos;
//! Fake seek function
ILint ILAPIENTRY iSizeSeek(ILint Offset, ILuint Mode)
{
switch (Mode)
{
case IL_SEEK_SET:
CurPos = Offset;
if (CurPos > MaxPos)
MaxPos = CurPos;
break;
case IL_SEEK_CUR:
CurPos = CurPos + Offset;
break;
case IL_SEEK_END:
CurPos = MaxPos + Offset; // Offset should be negative in this case.
break;
default:
ilSetError(IL_INTERNAL_ERROR); // Should never happen!
return -1; // Error code
}
if (CurPos > MaxPos)
MaxPos = CurPos;
return 0; // Code for success
}
ILuint ILAPIENTRY iSizeTell(void)
{
return CurPos;
}
ILint ILAPIENTRY iSizePutc(ILubyte Char)
{
CurPos++;
if (CurPos > MaxPos)
MaxPos = CurPos;
return Char;
}
ILint ILAPIENTRY iSizeWrite(const void *Buffer, ILuint Size, ILuint Number)
{
CurPos += Size * Number;
if (CurPos > MaxPos)
MaxPos = CurPos;
return Number;
}
//@TODO: Do computations for uncompressed formats without going through the
// whole writing process.
//! Returns the size of the memory buffer needed to save the current image into this Type.
// A return value of 0 is an error.
ILuint ilDetermineSize(ILenum Type)
{
MaxPos = CurPos = 0;
iSetOutputFake(); // Sets iputc, iwrite, etc. to functions above.
switch (Type)
{
#ifndef IL_NO_BMP
case IL_BMP:
ilSaveBmpL(NULL, 0);
break;
#endif//IL_NO_BMP
#ifndef IL_NO_DDS
case IL_DDS:
ilSaveDdsL(NULL, 0);
break;
#endif//IL_NO_DDS
#ifndef IL_NO_EXR
case IL_EXR:
ilSaveExrL(NULL, 0);
break;
#endif//IL_NO_EXR
#ifndef IL_NO_HDR
case IL_HDR:
ilSaveHdrL(NULL, 0);
break;
#endif//IL_NO_HDR
#ifndef IL_NO_JP2
case IL_JP2:
ilSaveJp2L(NULL, 0);
break;
#endif//IL_NO_JP2
#ifndef IL_NO_JPG
case IL_JPG:
ilSaveJpegL(NULL, 0);
break;
#endif//IL_NO_JPG
#ifndef IL_NO_PCX
case IL_PCX:
ilSavePcxL(NULL, 0);
break;
#endif//IL_NO_PCX
#ifndef IL_NO_PNG
case IL_PNG:
ilSavePngL(NULL, 0);
break;
#endif//IL_NO_PNG
#ifndef IL_NO_PNM
case IL_PNM:
ilSavePnmL(NULL, 0);
break;
#endif//IL_NO_PNM
#ifndef IL_NO_PSD
case IL_PSD:
ilSavePsdL(NULL, 0);
break;
#endif//IL_NO_PSD
#ifndef IL_NO_RAW
case IL_RAW:
ilSaveRawL(NULL, 0);
break;
#endif//IL_NO_RAW
#ifndef IL_NO_SGI
case IL_SGI:
ilSaveSgiL(NULL, 0);
break;
#endif//IL_NO_SGI
#ifndef IL_NO_TGA
case IL_TGA:
//ilSaveTargaL(NULL, 0);
return iTargaSize();
break;
#endif//IL_NO_TGA
#ifndef IL_NO_TIF
case IL_TIF:
ilSaveTiffL(NULL, 0);
break;
#endif//IL_NO_TIF
#ifndef IL_NO_WBMP
case IL_WBMP:
ilSaveWbmpL(NULL, 0);
break;
#endif//IL_NO_WBMP
default:
// 0 is an error for this.
ilSetError(IL_INVALID_ENUM);
return 0;
}
return MaxPos;
}
+90
View File
@@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/15/2009
//
// Filename: src-IL/src/il_squish.cpp
//
// Description: Implements access to the Squish library.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
/*#include "il_dds.h"
#include "il_manip.h"
#include <limits.h>*/
#ifdef IL_USE_DXTC_SQUISH
#include <squish.h>
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "squish.lib")
#else
#pragma comment(lib, "squish-d.lib")
#endif
#endif
#endif
//! Compresses data to a DXT format using libsquish.
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
// DxtSize is used to return the size in bytes of the DXTC data returned.
ILAPI ILubyte* ILAPIENTRY ilSquishCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
{
ILuint Size; //@TODO: Support larger than 32-bit data?
ILint Flags;
ILubyte *DxtcData;
if (Data == NULL) { // We cannot operate on a null pointer.
ilSetError(IL_INVALID_PARAM);
return NULL;
}
// The nVidia Texture Tools library does not support volume textures yet.
if (Depth != 1) {
ilSetError(IL_INVALID_PARAM);
return NULL;
}
switch (DxtFormat)
{
case IL_DXT1: // Should these two be
case IL_DXT1A: // any different?
Flags = squish::kDxt1;
break;
case IL_DXT3:
Flags = squish::kDxt3;
break;
case IL_DXT5:
Flags = squish::kDxt5;
break;
default: // Does not support DXT2 or DXT4.
ilSetError(IL_INVALID_PARAM);
break;
}
Size = squish::GetStorageRequirements(Width, Height, Flags);
DxtcData = (ILubyte*)ialloc(Size);
if (DxtcData == NULL)
return NULL;
squish::CompressImage(Data, Width, Height, DxtcData, Flags);
*DxtSize = Size;
return DxtcData;
}
#else
// Let's have this so that the function is always created and exported, even if it does nothing.
ILAPI ILubyte* ILAPIENTRY ilSquishCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
{
//@TODO: Do we need to set an error message?
return NULL;
}
#endif//IL_NO_DXTC_SQUISH
+669
View File
@@ -0,0 +1,669 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 12/17/2008
//
// Filename: src-IL/src/il_stack.c
//
// Description: The main image stack
//
//-----------------------------------------------------------------------------
// Credit goes to John Villar (johnny@reliaschev.com) for making the suggestion
// of not letting the user use ILimage structs but instead binding images
// like OpenGL.
#include "il_internal.h"
#include "il_stack.h"
//! Creates Num images and puts their index in Images - similar to glGenTextures().
void ILAPIENTRY ilGenImages(ILsizei Num, ILuint *Images)
{
ILsizei Index = 0;
iFree *TempFree = FreeNames;
if (Num < 1 || Images == NULL) {
ilSetError(IL_INVALID_VALUE);
return;
}
// No images have been generated yet, so create the image stack.
if (ImageStack == NULL)
if (!iEnlargeStack())
return;
do {
if (FreeNames != NULL) { // If any have been deleted, then reuse their image names.
TempFree = (iFree*)FreeNames->Next;
Images[Index] = FreeNames->Name;
ImageStack[FreeNames->Name] = ilNewImage(1, 1, 1, 1, 1);
ifree(FreeNames);
FreeNames = TempFree;
} else {
if (LastUsed >= StackSize)
if (!iEnlargeStack())
return;
Images[Index] = LastUsed;
// Must be all 1's instead of 0's, because some functions would divide by 0.
ImageStack[LastUsed] = ilNewImage(1, 1, 1, 1, 1);
LastUsed++;
}
} while (++Index < Num);
return;
}
ILuint ILAPIENTRY ilGenImage()
{
ILuint i;
ilGenImages(1,&i);
return i;
}
//! Makes Image the current active image - similar to glBindTexture().
void ILAPIENTRY ilBindImage(ILuint Image)
{
if (ImageStack == NULL || StackSize == 0) {
if (!iEnlargeStack()) {
return;
}
}
// If the user requests a high image name.
while (Image >= StackSize) {
if (!iEnlargeStack()) {
return;
}
}
if (ImageStack[Image] == NULL) {
ImageStack[Image] = ilNewImage(1, 1, 1, 1, 1);
if (Image >= LastUsed) // >= ?
LastUsed = Image + 1;
}
iCurImage = ImageStack[Image];
CurName = Image;
ParentImage = IL_TRUE;
return;
}
//! Deletes Num images from the image stack - similar to glDeleteTextures().
void ILAPIENTRY ilDeleteImages(ILsizei Num, const ILuint *Images)
{
iFree *Temp = FreeNames;
ILuint Index = 0;
if (Num < 1) {
//ilSetError(IL_INVALID_VALUE);
return;
}
if (StackSize == 0)
return;
do {
if (Images[Index] > 0 && Images[Index] < LastUsed) { // <= ?
/*if (FreeNames != NULL) { // Terribly inefficient
Temp = FreeNames;
do {
if (Temp->Name == Images[Index]) {
continue; // Sufficient?
}
} while ((Temp = Temp->Next));
}*/
// Already has been deleted or was never used.
if (ImageStack[Images[Index]] == NULL)
continue;
// Find out if current image - if so, set to default image zero.
if (Images[Index] == CurName || Images[Index] == 0) {
iCurImage = ImageStack[0];
CurName = 0;
}
// Should *NOT* be NULL here!
ilCloseImage(ImageStack[Images[Index]]);
ImageStack[Images[Index]] = NULL;
// Add to head of list - works for empty and non-empty lists
Temp = (iFree*)ialloc(sizeof(iFree));
if (!Temp) {
return;
}
Temp->Name = Images[Index];
Temp->Next = FreeNames;
FreeNames = Temp;
}
/*else { // Shouldn't set an error...just continue onward.
ilSetError(IL_ILLEGAL_OPERATION);
}*/
} while (++Index < (ILuint)Num);
}
void ILAPIENTRY ilDeleteImage(const ILuint Num) {
ilDeleteImages(1,&Num);
}
//! Checks if Image is a valid ilGenImages-generated image (like glIsTexture()).
ILboolean ILAPIENTRY ilIsImage(ILuint Image)
{
//iFree *Temp = FreeNames;
if (ImageStack == NULL)
return IL_FALSE;
if (Image >= LastUsed || Image == 0)
return IL_FALSE;
/*do {
if (Temp->Name == Image)
return IL_FALSE;
} while ((Temp = Temp->Next));*/
if (ImageStack[Image] == NULL) // Easier check.
return IL_FALSE;
return IL_TRUE;
}
//! Closes Image and frees all memory associated with it.
ILAPI void ILAPIENTRY ilCloseImage(ILimage *Image)
{
if (Image == NULL)
return;
if (Image->Data != NULL) {
ifree(Image->Data);
Image->Data = NULL;
}
if (Image->Pal.Palette != NULL && Image->Pal.PalSize > 0 && Image->Pal.PalType != IL_PAL_NONE) {
ifree(Image->Pal.Palette);
Image->Pal.Palette = NULL;
}
if (Image->Next != NULL) {
ilCloseImage(Image->Next);
Image->Next = NULL;
}
if (Image->Faces != NULL) {
ilCloseImage(Image->Faces);
Image->Mipmaps = NULL;
}
if (Image->Mipmaps != NULL) {
ilCloseImage(Image->Mipmaps);
Image->Mipmaps = NULL;
}
if (Image->Layers != NULL) {
ilCloseImage(Image->Layers);
Image->Layers = NULL;
}
if (Image->AnimList != NULL && Image->AnimSize != 0) {
ifree(Image->AnimList);
Image->AnimList = NULL;
}
if (Image->Profile != NULL && Image->ProfileSize != 0) {
ifree(Image->Profile);
Image->Profile = NULL;
Image->ProfileSize = 0;
}
if (Image->DxtcData != NULL && Image->DxtcFormat != IL_DXT_NO_COMP) {
ifree(Image->DxtcData);
Image->DxtcData = NULL;
Image->DxtcFormat = IL_DXT_NO_COMP;
Image->DxtcSize = 0;
}
ifree(Image);
Image = NULL;
return;
}
ILAPI ILboolean ILAPIENTRY ilIsValidPal(ILpal *Palette)
{
if (Palette == NULL)
return IL_FALSE;
if (Palette->PalSize == 0 || Palette->Palette == NULL)
return IL_FALSE;
switch (Palette->PalType)
{
case IL_PAL_RGB24:
case IL_PAL_RGB32:
case IL_PAL_RGBA32:
case IL_PAL_BGR24:
case IL_PAL_BGR32:
case IL_PAL_BGRA32:
return IL_TRUE;
}
return IL_FALSE;
}
//! Closes Palette and frees all memory associated with it.
ILAPI void ILAPIENTRY ilClosePal(ILpal *Palette)
{
if (Palette == NULL)
return;
if (!ilIsValidPal(Palette))
return;
ifree(Palette->Palette);
ifree(Palette);
return;
}
ILimage *iGetBaseImage()
{
return ImageStack[ilGetCurName()];
}
//! Sets the current mipmap level
ILboolean ILAPIENTRY ilActiveMipmap(ILuint Number)
{
ILuint Current;
ILimage *iTempImage;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (Number == 0) {
return IL_TRUE;
}
iTempImage = iCurImage;
iCurImage = iCurImage->Mipmaps;
if (iCurImage == NULL) {
iCurImage = iTempImage;
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
for (Current = 1; Current < Number; Current++) {
iCurImage = iCurImage->Mipmaps;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
iCurImage = iTempImage;
return IL_FALSE;
}
}
ParentImage = IL_FALSE;
return IL_TRUE;
}
//! Used for setting the current image if it is an animation.
ILboolean ILAPIENTRY ilActiveImage(ILuint Number)
{
ILuint Current;
ILimage *iTempImage;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (Number == 0) {
return IL_TRUE;
}
iTempImage = iCurImage;
iCurImage = iCurImage->Next;
if (iCurImage == NULL) {
iCurImage = iTempImage;
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Number--; // Skip 0 (parent image)
for (Current = 0; Current < Number; Current++) {
iCurImage = iCurImage->Next;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
iCurImage = iTempImage;
return IL_FALSE;
}
}
ParentImage = IL_FALSE;
return IL_TRUE;
}
//! Used for setting the current face if it is a cubemap.
ILboolean ILAPIENTRY ilActiveFace(ILuint Number)
{
ILuint Current;
ILimage *iTempImage;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (Number == 0) {
return IL_TRUE;
}
iTempImage = iCurImage;
iCurImage = iCurImage->Faces;
if (iCurImage == NULL) {
iCurImage = iTempImage;
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
//Number--; // Skip 0 (parent image)
for (Current = 1; Current < Number; Current++) {
iCurImage = iCurImage->Faces;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
iCurImage = iTempImage;
return IL_FALSE;
}
}
ParentImage = IL_FALSE;
return IL_TRUE;
}
//! Used for setting the current layer if layers exist.
ILboolean ILAPIENTRY ilActiveLayer(ILuint Number)
{
ILuint Current;
ILimage *iTempImage;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (Number == 0) {
return IL_TRUE;
}
iTempImage = iCurImage;
iCurImage = iCurImage->Layers;
if (iCurImage == NULL) {
iCurImage = iTempImage;
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
//Number--; // Skip 0 (parent image)
for (Current = 1; Current < Number; Current++) {
iCurImage = iCurImage->Layers;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
iCurImage = iTempImage;
return IL_FALSE;
}
}
ParentImage = IL_FALSE;
return IL_TRUE;
}
ILuint ILAPIENTRY ilCreateSubImage(ILenum Type, ILuint Num)
{
ILimage *SubImage;
ILuint Count ; // Create one before we go in the loop.
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return 0;
}
if (Num == 0) {
return 0;
}
switch (Type)
{
case IL_SUB_NEXT:
if (iCurImage->Next)
ilCloseImage(iCurImage->Next);
iCurImage->Next = ilNewImage(1, 1, 1, 1, 1);
SubImage = iCurImage->Next;
break;
case IL_SUB_MIPMAP:
if (iCurImage->Mipmaps)
ilCloseImage(iCurImage->Mipmaps);
iCurImage->Mipmaps = ilNewImage(1, 1, 1, 1, 1);
SubImage = iCurImage->Mipmaps;
break;
case IL_SUB_LAYER:
if (iCurImage->Layers)
ilCloseImage(iCurImage->Layers);
iCurImage->Layers = ilNewImage(1, 1, 1, 1, 1);
SubImage = iCurImage->Layers;
break;
default:
ilSetError(IL_INVALID_ENUM);
return IL_FALSE;
}
if (SubImage == NULL) {
return 0;
}
for (Count = 1; Count < Num; Count++) {
SubImage->Next = ilNewImage(1, 1, 1, 1, 1);
SubImage = SubImage->Next;
if (SubImage == NULL)
return Count;
}
return Count;
}
// Returns the current index.
ILAPI ILuint ILAPIENTRY ilGetCurName()
{
if (iCurImage == NULL || ImageStack == NULL || StackSize == 0)
return 0;
return CurName;
}
// Returns the current image.
ILAPI ILimage* ILAPIENTRY ilGetCurImage()
{
return iCurImage;
}
// To be only used when the original image is going to be set back almost immediately.
ILAPI void ILAPIENTRY ilSetCurImage(ILimage *Image)
{
iCurImage = Image;
return;
}
// Completely replaces the current image and the version in the image stack.
ILAPI void ILAPIENTRY ilReplaceCurImage(ILimage *Image)
{
if (iCurImage) {
ilActiveImage(0);
ilCloseImage(iCurImage);
}
ImageStack[ilGetCurName()] = Image;
iCurImage = Image;
ParentImage = IL_TRUE;
return;
}
// Like realloc but sets new memory to 0.
void* ILAPIENTRY ilRecalloc(void *Ptr, ILuint OldSize, ILuint NewSize)
{
void *Temp = ialloc(NewSize);
ILuint CopySize = (OldSize < NewSize) ? OldSize : NewSize;
if (Temp != NULL) {
if (Ptr != NULL) {
memcpy(Temp, Ptr, CopySize);
ifree(Ptr);
}
Ptr = Temp;
if (OldSize < NewSize)
imemclear((ILubyte*)Temp + OldSize, NewSize - OldSize);
}
return Temp;
}
// Internal function to enlarge the image stack by I_STACK_INCREMENT members.
ILboolean iEnlargeStack()
{
// 02-05-2001: Moved from ilGenImages().
// Puts the cleanup function on the exit handler once.
if (!OnExit) {
#ifdef _MEM_DEBUG
AddToAtexit(); // So iFreeMem doesn't get called after unfreed information.
#endif//_MEM_DEBUG
#if (!defined(_WIN32_WCE)) && (!defined(IL_STATIC_LIB))
atexit((void*)ilShutDown);
#endif
OnExit = IL_TRUE;
}
if (!(ImageStack = (ILimage**)ilRecalloc(ImageStack, StackSize * sizeof(ILimage*), (StackSize + I_STACK_INCREMENT) * sizeof(ILimage*)))) {
return IL_FALSE;
}
StackSize += I_STACK_INCREMENT;
return IL_TRUE;
}
static ILboolean IsInit = IL_FALSE;
// ONLY call at startup.
void ILAPIENTRY ilInit()
{
// if it is already initialized skip initialization
if (IsInit == IL_TRUE )
return;
//ilSetMemory(NULL, NULL); Now useless 3/4/2006 (due to modification in il_alloc.c)
ilSetError(IL_NO_ERROR);
ilDefaultStates(); // Set states to their defaults.
// Sets default file-reading callbacks.
ilResetRead();
ilResetWrite();
#if (!defined(_WIN32_WCE)) && (!defined(IL_STATIC_LIB))
atexit((void*)ilRemoveRegistered);
#endif
//_WIN32_WCE
//ilShutDown();
iSetImage0(); // Beware! Clears all existing textures!
iBindImageTemp(); // Go ahead and create the temporary image.
IsInit = IL_TRUE;
return;
}
// Frees any extra memory in the stack.
// - Called on exit
void ILAPIENTRY ilShutDown()
{
// if it is not initialized do not shutdown
iFree* TempFree = (iFree*)FreeNames;
ILuint i;
if (!IsInit)
return;
if (!IsInit) { // Prevent from being called when not initialized.
ilSetError(IL_ILLEGAL_OPERATION);
return;
}
while (TempFree != NULL) {
FreeNames = (iFree*)TempFree->Next;
ifree(TempFree);
TempFree = FreeNames;
}
//for (i = 0; i < LastUsed; i++) {
for (i = 0; i < StackSize; i++) {
if (ImageStack[i] != NULL)
ilCloseImage(ImageStack[i]);
}
if (ImageStack)
ifree(ImageStack);
ImageStack = NULL;
LastUsed = 0;
StackSize = 0;
IsInit = IL_FALSE;
return;
}
// Initializes the image stack's first entry (default image) -- ONLY CALL ONCE!
void iSetImage0()
{
if (ImageStack == NULL)
if (!iEnlargeStack())
return;
LastUsed = 1;
CurName = 0;
ParentImage = IL_TRUE;
if (!ImageStack[0])
ImageStack[0] = ilNewImage(1, 1, 1, 1, 1);
iCurImage = ImageStack[0];
ilDefaultImage();
return;
}
ILAPI void ILAPIENTRY iBindImageTemp()
{
if (ImageStack == NULL || StackSize <= 1)
if (!iEnlargeStack())
return;
if (LastUsed < 2)
LastUsed = 2;
CurName = 1;
ParentImage = IL_TRUE;
if (!ImageStack[1])
ImageStack[1] = ilNewImage(1, 1, 1, 1, 1);
iCurImage = ImageStack[1];
return;
}
File diff suppressed because it is too large Load Diff
+398
View File
@@ -0,0 +1,398 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/06/2009
//
// Filename: src-IL/src/il_sun.c
//
// Description: Reads from a Sun RAS file. Specifications available from
// http://www.fileformat.info/format/sunraster/egff.htm.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_SUN
#include "il_bits.h"
ILboolean iLoadSunInternal(void);
ILboolean iIsValidSun(void);
ILuint iSunGetRle(ILubyte *Data, ILuint Length);
typedef struct SUNHEAD
{
ILuint MagicNumber; // Magic (identification) number
ILuint Width; // Width of image in pixels
ILuint Height; // Height of image in pixels
ILuint Depth; // Number of bits per pixel
ILuint Length; // Size of image data in bytes
ILuint Type; // Type of raster file
ILuint ColorMapType; // Type of color map
ILuint ColorMapLength; // Size of the color map in bytes
} SUNHEAD;
// Data storage types
#define IL_SUN_OLD 0x00
#define IL_SUN_STANDARD 0x01
#define IL_SUN_BYTE_ENC 0x02
#define IL_SUN_RGB 0x03
#define IL_SUN_TIFF 0x04
#define IL_SUN_IFF 0x05
#define IL_SUN_EXPER 0xFFFF // Experimental, not supported.
// Colormap types
#define IL_SUN_NO_MAP 0x00
#define IL_SUN_RGB_MAP 0x01
#define IL_SUN_RAW_MAP 0x02
//! Checks if the file specified in FileName is a valid Sun file.
ILboolean ilIsValidSun(ILconst_string FileName)
{
ILHANDLE SunFile;
ILboolean bSun = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("sun")) && !iCheckExtension(FileName, IL_TEXT("ras")) &&
!iCheckExtension(FileName, IL_TEXT("im1")) && !iCheckExtension(FileName, IL_TEXT("im8")) &&
!iCheckExtension(FileName, IL_TEXT("im24")) && !iCheckExtension(FileName, IL_TEXT("im32")) &&
!iCheckExtension(FileName, IL_TEXT("rs"))) { // Lots of names possible...
ilSetError(IL_INVALID_EXTENSION);
return bSun;
}
SunFile = iopenr(FileName);
if (SunFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bSun;
}
bSun = ilIsValidSunF(SunFile);
icloser(SunFile);
return bSun;
}
//! Checks if the ILHANDLE contains a valid Sun file at the current position.
ILboolean ilIsValidSunF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidSun();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid Sun lump.
ILboolean ilIsValidSunL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidSun();
}
// Internal function used to get the Sun header from the current file.
ILboolean iGetSunHead(SUNHEAD *Header)
{
Header->MagicNumber = GetBigUInt();
Header->Width = GetBigUInt();
Header->Height = GetBigUInt();
Header->Depth = GetBigUInt();
Header->Length = GetBigUInt();
Header->Type = GetBigUInt();
Header->ColorMapType = GetBigUInt();
Header->ColorMapLength = GetBigUInt();
return IL_TRUE;
}
// Internal function used to check if the HEADER is a valid SUN header.
ILboolean iCheckSun(SUNHEAD *Header)
{
if (Header->MagicNumber != 0x59A66A95) // Magic number is always 0x59A66A95.
return IL_FALSE;
if (Header->Width == 0 || Header->Height == 0) // 0 dimensions are meaningless.
return IL_FALSE;
// These are the only valid depths that I know of.
if (Header->Depth != 1 && Header->Depth != 8 && Header->Depth != 24 && Header->Depth != 32)
return IL_FALSE;
if (Header->Type > IL_SUN_RGB) //@TODO: Support further types.
return IL_FALSE;
if (Header->ColorMapType > IL_SUN_RGB_MAP) //@TODO: Find out more about raw map.
return IL_FALSE;
// Color map cannot be 0 if there is a map indicated.
if (Header->ColorMapType > IL_SUN_NO_MAP && Header->ColorMapLength == 0)
return IL_FALSE;
//@TODO: These wouldn't make sense. Are they valid somehow? Find out...
if ((Header->Depth == 1 || Header->Depth == 32) && Header->Type == IL_SUN_BYTE_ENC)
return IL_FALSE;
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidSun()
{
SUNHEAD Head;
if (!iGetSunHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(SUNHEAD), IL_SEEK_CUR);
return iCheckSun(&Head);
}
// Reads a Sun file
ILboolean ilLoadSun(ILconst_string FileName)
{
ILHANDLE SunFile;
ILboolean bSun = IL_FALSE;
SunFile = iopenr(FileName);
if (SunFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bSun;
}
iSetInputFile(SunFile);
bSun = ilLoadSunF(SunFile);
icloser(SunFile);
return bSun;
}
//! Reads an already-opened Sun file
ILboolean ilLoadSunF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadSunInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Sun
ILboolean ilLoadSunL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadSunInternal();
}
ILboolean iLoadSunInternal(void)
{
SUNHEAD Header;
BITFILE *File;
ILuint i, j, Padding, Offset, BytesRead;
ILubyte PaddingData[16];
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
//@TODO: Right now, iGetSunHead cannot fail.
if (!iGetSunHead(&Header) || !iCheckSun(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
switch (Header.Depth)
{
case 1: //@TODO: Find a file to test this on.
File = bfile(iGetFile());
if (File == NULL)
return IL_FALSE;
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
if (Header.ColorMapLength != 0) {
// Data should be an index into the color map, but the color map should only be RGB (6 bytes, 2 entries).
if (Header.ColorMapLength != 6) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
}
iCurImage->Pal.Palette = (ILubyte*)ialloc(6); // Just need 2 entries in the color map.
if (Header.ColorMapLength == 0) { // Create the color map
iCurImage->Pal.Palette[0] = 0x00; // Entry for black
iCurImage->Pal.Palette[1] = 0x00;
iCurImage->Pal.Palette[2] = 0x00;
iCurImage->Pal.Palette[3] = 0xFF; // Entry for white
iCurImage->Pal.Palette[4] = 0xFF;
iCurImage->Pal.Palette[5] = 0xFF;
}
else {
iread(iCurImage->Pal.Palette, 1, 6); // Read in the color map.
}
iCurImage->Pal.PalSize = 6;
iCurImage->Pal.PalType = IL_PAL_RGB24;
Padding = (16 - (iCurImage->Width % 16)) % 16; // Has to be aligned on a 16-bit boundary. The rest is padding.
// Reads the bits
for (i = 0; i < iCurImage->Height; i++) {
bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
//bseek(File, BitPadding, IL_SEEK_CUR); //@TODO: This function does not work correctly.
bread(PaddingData, 1, Padding, File); // Skip padding bits.
}
break;
case 8:
if (Header.ColorMapType == IL_SUN_NO_MAP) { // Greyscale image
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
else { // Colour-mapped image
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Pal.Palette = (ILubyte*)ialloc(Header.ColorMapLength); // Allocate color map.
if (iCurImage->Pal.Palette == NULL)
return IL_FALSE;
if (iread(iCurImage->Pal.Palette, 1, Header.ColorMapLength) != Header.ColorMapLength) { // Read color map.
ilSetError(IL_FILE_READ_ERROR);
return IL_FALSE;
}
iCurImage->Pal.PalSize = Header.ColorMapLength;
iCurImage->Pal.PalType = IL_PAL_RGB24;
}
if (Header.Type != IL_SUN_BYTE_ENC) { // Regular uncompressed image data
Padding = (2 - (iCurImage->Bps % 2)) % 2; // Must be padded on a 16-bit boundary (2 bytes)
for (i = 0; i < Header.Height; i++) {
iread(iCurImage->Data + i * Header.Width, 1, iCurImage->Bps);
if (Padding) // Only possible for padding to be 0 or 1.
igetc();
}
}
else { // RLE image data
for (i = 0; i < iCurImage->Height; i++) {
BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
if (BytesRead % 2) // Each scanline must be aligned on a 2-byte boundary.
igetc(); // Skip padding
}
}
break;
case 24:
if (Header.ColorMapLength > 0) // Ignore any possible colormaps.
iseek(Header.ColorMapLength, IL_SEEK_CUR);
if (Header.Type == IL_SUN_RGB) {
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
else {
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
if (Header.Type != IL_SUN_BYTE_ENC) { // Regular uncompressed image data
Padding = (2 - (iCurImage->Bps % 2)) % 2; // Must be padded on a 16-bit boundary (2 bytes)
for (i = 0; i < Header.Height; i++) {
iread(iCurImage->Data + i * Header.Width * 3, 1, iCurImage->Bps);
if (Padding) // Only possible for padding to be 0 or 1.
igetc();
}
}
else { // RLE image data
for (i = 0; i < iCurImage->Height; i++) {
BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
if (BytesRead % 2) // Each scanline must be aligned on a 2-byte boundary.
igetc(); // Skip padding
}
}
break;
case 32:
if (Header.ColorMapLength > 0) // Ignore any possible colormaps.
iseek(Header.ColorMapLength, IL_SEEK_CUR);
if (Header.Type == IL_SUN_RGB) {
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
else {
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
// There is no padding at the end of each scanline.
Offset = 0;
for (i = 0; i < Header.Height; i++) {
for (j = 0; j < Header.Width; j++) {
igetc(); // There is a pad byte before each pixel.
iCurImage->Data[Offset] = igetc();
iCurImage->Data[Offset+1] = igetc();
iCurImage->Data[Offset+2] = igetc();
}
}
break;
default: // Should have already been checked with iGetSunHead.
return IL_FALSE;
}
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
return ilFixImage();
}
ILuint iSunGetRle(ILubyte *Data, ILuint Length)
{
ILuint i = 0, j;
ILubyte Flag, Value;
ILuint Count;
for (i = 0; i < Length; ) {
Flag = igetc();
if (Flag == 0x80) { // Run follows (or 1 byte of 0x80)
Count = igetc();
if (Count == 0) { // 1 pixel of value (0x80)
*Data = 0x80;
Data++;
i++;
}
else { // Here we have a run.
Value = igetc();
Count++; // Should really be Count+1
for (j = 0; j < Count && i + j < Length; j++, Data++) {
*Data = Value;
}
i += Count;
}
}
else { // 1 byte of this value (cannot be 0x80)
*Data = Flag;
Data++;
i++;
}
}
return i;
}
#endif//IL_NO_SUN
+955
View File
@@ -0,0 +1,955 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_targa.c
//
// Description: Reads from and writes to a Targa (.tga) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_TGA
#include "il_targa.h"
//#include <time.h> // for ilMakeString()
#include <string.h>
#include "il_manip.h"
#include "il_bits.h"
#ifdef DJGPP
#include <dos.h>
#endif
//! Checks if the file specified in FileName is a valid Targa file.
ILboolean ilIsValidTga(ILconst_string FileName)
{
ILHANDLE TargaFile;
ILboolean bTarga = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("tga")) &&
!iCheckExtension(FileName, IL_TEXT("vda")) &&
!iCheckExtension(FileName, IL_TEXT("icb")) &&
!iCheckExtension(FileName, IL_TEXT("vst"))) {
ilSetError(IL_INVALID_EXTENSION);
return bTarga;
}
TargaFile = iopenr(FileName);
if (TargaFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bTarga;
}
bTarga = ilIsValidTgaF(TargaFile);
icloser(TargaFile);
return bTarga;
}
//! Checks if the ILHANDLE contains a valid Targa file at the current position.
ILboolean ilIsValidTgaF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidTarga();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid Targa lump.
ILboolean ilIsValidTgaL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidTarga();
}
// Internal function used to get the Targa header from the current file.
ILboolean iGetTgaHead(TARGAHEAD *Header)
{
Header->IDLen = (ILubyte)igetc();
Header->ColMapPresent = (ILubyte)igetc();
Header->ImageType = (ILubyte)igetc();
Header->FirstEntry = GetLittleShort();
Header->ColMapLen = GetLittleShort();
Header->ColMapEntSize = (ILubyte)igetc();
Header->OriginX = GetLittleShort();
Header->OriginY = GetLittleShort();
Header->Width = GetLittleUShort();
Header->Height = GetLittleUShort();
Header->Bpp = (ILubyte)igetc();
Header->ImageDesc = (ILubyte)igetc();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidTarga()
{
TARGAHEAD Head;
if (!iGetTgaHead(&Head))
return IL_FALSE;
iseek(-(ILint)sizeof(TARGAHEAD), IL_SEEK_CUR);
return iCheckTarga(&Head);
}
// Internal function used to check if the HEADER is a valid Targa header.
ILboolean iCheckTarga(TARGAHEAD *Header)
{
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
if (Header->Bpp != 8 && Header->Bpp != 15 && Header->Bpp != 16
&& Header->Bpp != 24 && Header->Bpp != 32)
return IL_FALSE;
if (Header->ImageDesc & BIT_4) // Supposed to be set to 0
return IL_FALSE;
// check type (added 20040218)
if (Header->ImageType != TGA_NO_DATA
&& Header->ImageType != TGA_COLMAP_UNCOMP
&& Header->ImageType != TGA_UNMAP_UNCOMP
&& Header->ImageType != TGA_BW_UNCOMP
&& Header->ImageType != TGA_COLMAP_COMP
&& Header->ImageType != TGA_UNMAP_COMP
&& Header->ImageType != TGA_BW_COMP)
return IL_FALSE;
// Doesn't work well with the bitshift so change it.
if (Header->Bpp == 15)
Header->Bpp = 16;
return IL_TRUE;
}
//! Reads a Targa file
ILboolean ilLoadTarga(ILconst_string FileName)
{
ILHANDLE TargaFile;
ILboolean bTarga = IL_FALSE;
TargaFile = iopenr(FileName);
if (TargaFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bTarga;
}
bTarga = ilLoadTargaF(TargaFile);
icloser(TargaFile);
return bTarga;
}
//! Reads an already-opened Targa file
ILboolean ilLoadTargaF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadTargaInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a Targa
ILboolean ilLoadTargaL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadTargaInternal();
}
// Internal function used to load the Targa.
ILboolean iLoadTargaInternal()
{
TARGAHEAD Header;
ILboolean bTarga;
ILenum iOrigin;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!iGetTgaHead(&Header))
return IL_FALSE;
if (!iCheckTarga(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
switch (Header.ImageType)
{
case TGA_NO_DATA:
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
case TGA_COLMAP_UNCOMP:
case TGA_COLMAP_COMP:
bTarga = iReadColMapTga(&Header);
break;
case TGA_UNMAP_UNCOMP:
case TGA_UNMAP_COMP:
bTarga = iReadUnmapTga(&Header);
break;
case TGA_BW_UNCOMP:
case TGA_BW_COMP:
bTarga = iReadBwTga(&Header);
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
// @JASON Extra Code to manipulate the image depending on
// the Image Descriptor's origin bits.
iOrigin = Header.ImageDesc & IMAGEDESC_ORIGIN_MASK;
switch (iOrigin)
{
case IMAGEDESC_TOPLEFT:
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
break;
case IMAGEDESC_TOPRIGHT:
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
iMirror();
break;
case IMAGEDESC_BOTLEFT:
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
break;
case IMAGEDESC_BOTRIGHT:
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
iMirror();
break;
}
return ilFixImage();
}
ILboolean iReadColMapTga(TARGAHEAD *Header)
{
char ID[255];
ILuint i;
ILushort Pixel;
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
return IL_FALSE;
if (!ilTexImage(Header->Width, Header->Height, 1, (ILubyte)(Header->Bpp >> 3), 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize)
ifree(iCurImage->Pal.Palette);
iCurImage->Format = IL_COLOUR_INDEX;
iCurImage->Pal.PalSize = Header->ColMapLen * (Header->ColMapEntSize >> 3);
switch (Header->ColMapEntSize)
{
case 16:
iCurImage->Pal.PalType = IL_PAL_BGRA32;
iCurImage->Pal.PalSize = Header->ColMapLen * 4;
break;
case 24:
iCurImage->Pal.PalType = IL_PAL_BGR24;
break;
case 32:
iCurImage->Pal.PalType = IL_PAL_BGRA32;
break;
default:
// Should *never* reach here
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
if (iCurImage->Pal.Palette == NULL) {
return IL_FALSE;
}
// Do we need to do something with FirstEntry? Like maybe:
// iread(Image->Pal + Targa->FirstEntry, 1, Image->Pal.PalSize); ??
if (Header->ColMapEntSize != 16)
{
if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
return IL_FALSE;
}
else {
// 16 bit palette, so we have to break it up.
for (i = 0; i < iCurImage->Pal.PalSize; i += 4)
{
Pixel = GetBigUShort();
if (ieof())
return IL_FALSE;
iCurImage->Pal.Palette[3] = (Pixel & 0x8000) >> 12;
iCurImage->Pal.Palette[0] = (Pixel & 0xFC00) >> 7;
iCurImage->Pal.Palette[1] = (Pixel & 0x03E0) >> 2;
iCurImage->Pal.Palette[2] = (Pixel & 0x001F) << 3;
}
}
if (Header->ImageType == TGA_COLMAP_COMP)
{
if (!iUncompressTgaData(iCurImage))
{
return IL_FALSE;
}
}
else
{
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
{
return IL_FALSE;
}
}
return IL_TRUE;
}
ILboolean iReadUnmapTga(TARGAHEAD *Header)
{
ILubyte Bpp;
char ID[255];
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
return IL_FALSE;
/*if (Header->Bpp == 16)
Bpp = 3;
else*/
Bpp = (ILubyte)(Header->Bpp >> 3);
if (!ilTexImage(Header->Width, Header->Height, 1, Bpp, 0, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
switch (iCurImage->Bpp)
{
case 1:
iCurImage->Format = IL_COLOUR_INDEX; // wtf? How is this possible?
break;
case 2: // 16-bit is not supported directly!
//iCurImage->Format = IL_RGB5_A1;
/*iCurImage->Format = IL_RGBA;
iCurImage->Type = IL_UNSIGNED_SHORT_5_5_5_1_EXT;*/
//iCurImage->Type = IL_UNSIGNED_SHORT_5_6_5_REV;
// Remove?
//ilCloseImage(iCurImage);
//ilSetError(IL_FORMAT_NOT_SUPPORTED);
//return IL_FALSE;
/*iCurImage->Bpp = 4;
iCurImage->Format = IL_BGRA;
iCurImage->Type = IL_UNSIGNED_SHORT_1_5_5_5_REV;*/
iCurImage->Format = IL_BGR;
break;
case 3:
iCurImage->Format = IL_BGR;
break;
case 4:
iCurImage->Format = IL_BGRA;
break;
default:
ilSetError(IL_INVALID_VALUE);
return IL_FALSE;
}
// @TODO: Determine this:
// We assume that no palette is present, but it's possible...
// Should we mess with it or not?
if (Header->ImageType == TGA_UNMAP_COMP) {
if (!iUncompressTgaData(iCurImage)) {
return IL_FALSE;
}
}
else {
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData) {
return IL_FALSE;
}
}
// Go ahead and expand it to 24-bit.
if (Header->Bpp == 16) {
if (!i16BitTarga(iCurImage))
return IL_FALSE;
return IL_TRUE;
}
return IL_TRUE;
}
ILboolean iReadBwTga(TARGAHEAD *Header)
{
char ID[255];
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
return IL_FALSE;
// We assume that no palette is present, but it's possible...
// Should we mess with it or not?
if (!ilTexImage(Header->Width, Header->Height, 1, (ILubyte)(Header->Bpp >> 3), IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL)) {
return IL_FALSE;
}
if (Header->ImageType == TGA_BW_COMP) {
if (!iUncompressTgaData(iCurImage)) {
return IL_FALSE;
}
}
else {
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData) {
return IL_FALSE;
}
}
return IL_TRUE;
}
ILboolean iUncompressTgaData(ILimage *Image)
{
ILuint BytesRead = 0, Size, RunLen, i, ToRead;
ILubyte Header, Color[4];
ILint c;
Size = Image->Width * Image->Height * Image->Depth * Image->Bpp;
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
iPreCache(iCurImage->SizeOfData / 2);
while (BytesRead < Size) {
Header = (ILubyte)igetc();
if (Header & BIT_7) {
ClearBits(Header, BIT_7);
if (iread(Color, 1, Image->Bpp) != Image->Bpp) {
iUnCache();
return IL_FALSE;
}
RunLen = (Header+1) * Image->Bpp;
for (i = 0; i < RunLen; i += Image->Bpp) {
// Read the color in, but we check to make sure that we do not go past the end of the image.
for (c = 0; c < Image->Bpp && BytesRead+i+c < Size; c++) {
Image->Data[BytesRead+i+c] = Color[c];
}
}
BytesRead += RunLen;
}
else {
RunLen = (Header+1) * Image->Bpp;
// We have to check that we do not go past the end of the image data.
if (BytesRead + RunLen > Size)
ToRead = Size - BytesRead;
else
ToRead = RunLen;
if (iread(Image->Data + BytesRead, 1, ToRead) != ToRead) {
iUnCache(); //@TODO: Error needed here?
return IL_FALSE;
}
BytesRead += RunLen;
if (BytesRead + RunLen > Size)
iseek(RunLen - ToRead, IL_SEEK_CUR);
}
}
iUnCache();
return IL_TRUE;
}
// Pretty damn unoptimized
ILboolean i16BitTarga(ILimage *Image)
{
ILushort *Temp1;
ILubyte *Data, *Temp2;
ILuint x, PixSize = Image->Width * Image->Height;
Data = (ILubyte*)ialloc(Image->Width * Image->Height * 3);
Temp1 = (ILushort*)Image->Data;
Temp2 = Data;
if (Data == NULL)
return IL_FALSE;
for (x = 0; x < PixSize; x++) {
*Temp2++ = (*Temp1 & 0x001F) << 3; // Blue
*Temp2++ = (*Temp1 & 0x03E0) >> 2; // Green
*Temp2++ = (*Temp1 & 0x7C00) >> 7; // Red
Temp1++;
/*s = *Temp;
s = SwapShort(s);
a = !!(s & BIT_15);
s = s << 1;
//if (a) {
SetBits(s, BIT_0);
//}
//SetBits(s, BIT_15);
*Temp++ = s;*/
}
if (!ilTexImage(Image->Width, Image->Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, Data)) {
ifree(Data);
return IL_FALSE;
}
ifree(Data);
return IL_TRUE;
}
//! Writes a Targa file
ILboolean ilSaveTarga(const ILstring FileName)
{
ILHANDLE TargaFile;
ILuint TargaSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
TargaFile = iopenw(FileName);
if (TargaFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
TargaSize = ilSaveTargaF(TargaFile);
iclosew(TargaFile);
if (TargaSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a Targa to an already-opened file
ILuint ilSaveTargaF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSaveTargaInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a Targa to a memory "lump"
ILuint ilSaveTargaL(void *Lump, ILuint Size)
{
ILuint Pos = itellw();
iSetOutputLump(Lump, Size);
if (iSaveTargaInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to save the Targa.
ILboolean iSaveTargaInternal()
{
const char *ID = iGetString(IL_TGA_ID_STRING);
const char *AuthName = iGetString(IL_TGA_AUTHNAME_STRING);
const char *AuthComment = iGetString(IL_TGA_AUTHCOMMENT_STRING);
ILubyte IDLen = 0, UsePal, Type, PalEntSize;
ILshort ColMapStart = 0, PalSize;
ILubyte Temp;
ILenum Format;
ILboolean Compress;
ILuint RleLen;
ILubyte *Rle;
ILpal *TempPal = NULL;
ILimage *TempImage = NULL;
ILuint ExtOffset, i;
char *Footer = "TRUEVISION-XFILE.\0";
char *idString = "Developer's Image Library (DevIL)";
ILuint Day, Month, Year, Hour, Minute, Second;
char *TempData;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (iGetInt(IL_TGA_RLE) == IL_TRUE)
Compress = IL_TRUE;
else
Compress = IL_FALSE;
if (ID)
IDLen = (ILubyte)ilCharStrLen(ID);
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE)
UsePal = IL_TRUE;
else
UsePal = IL_FALSE;
iwrite(&IDLen, sizeof(ILubyte), 1);
iwrite(&UsePal, sizeof(ILubyte), 1);
Format = iCurImage->Format;
switch (Format) {
case IL_COLOUR_INDEX:
if (Compress)
Type = 9;
else
Type = 1;
break;
case IL_BGR:
case IL_BGRA:
if (Compress)
Type = 10;
else
Type = 2;
break;
case IL_RGB:
case IL_RGBA:
ilSwapColours();
if (Compress)
Type = 10;
else
Type = 2;
break;
case IL_LUMINANCE:
if (Compress)
Type = 11;
else
Type = 3;
break;
default:
// Should convert the types here...
ilSetError(IL_INVALID_VALUE);
ifree(ID);
ifree(AuthName);
ifree(AuthComment);
return IL_FALSE;
}
iwrite(&Type, sizeof(ILubyte), 1);
SaveLittleShort(ColMapStart);
switch (iCurImage->Pal.PalType)
{
case IL_PAL_NONE:
PalSize = 0;
PalEntSize = 0;
break;
case IL_PAL_BGR24:
PalSize = (ILshort)(iCurImage->Pal.PalSize / 3);
PalEntSize = 24;
TempPal = &iCurImage->Pal;
break;
case IL_PAL_RGB24:
case IL_PAL_RGB32:
case IL_PAL_RGBA32:
case IL_PAL_BGR32:
case IL_PAL_BGRA32:
TempPal = iConvertPal(&iCurImage->Pal, IL_PAL_BGR24);
if (TempPal == NULL)
return IL_FALSE;
PalSize = (ILshort)(TempPal->PalSize / 3);
PalEntSize = 24;
break;
default:
ilSetError(IL_INVALID_VALUE);
ifree(ID);
ifree(AuthName);
ifree(AuthComment);
PalSize = 0;
PalEntSize = 0;
return IL_FALSE;
}
SaveLittleShort(PalSize);
iwrite(&PalEntSize, sizeof(ILubyte), 1);
if (iCurImage->Bpc > 1) {
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
if (TempImage == NULL) {
ifree(ID);
ifree(AuthName);
ifree(AuthComment);
return IL_FALSE;
}
}
else {
TempImage = iCurImage;
}
if (TempImage->Origin != IL_ORIGIN_LOWER_LEFT)
TempData = (char*)iGetFlipped(TempImage);
else
TempData = (char*)TempImage->Data;
// Write out the origin stuff.
Temp = 0;
iwrite(&Temp, sizeof(ILshort), 1);
iwrite(&Temp, sizeof(ILshort), 1);
Temp = iCurImage->Bpp << 3; // Changes to bits per pixel
SaveLittleUShort((ILushort)iCurImage->Width);
SaveLittleUShort((ILushort)iCurImage->Height);
iwrite(&Temp, sizeof(ILubyte), 1);
// Still don't know what exactly this is for...
Temp = 0;
iwrite(&Temp, sizeof(ILubyte), 1);
iwrite(ID, sizeof(char), IDLen);
ifree(ID);
//iwrite(ID, sizeof(ILbyte), IDLen - sizeof(ILuint));
//iwrite(&iCurImage->Depth, sizeof(ILuint), 1);
// Write out the colormap
if (UsePal)
iwrite(TempPal->Palette, sizeof(ILubyte), TempPal->PalSize);
// else do nothing
if (!Compress)
iwrite(TempData, sizeof(ILubyte), TempImage->SizeOfData);
else {
Rle = (ILubyte*)ialloc(TempImage->SizeOfData + TempImage->SizeOfData / 2 + 1); // max
if (Rle == NULL) {
ifree(AuthName);
ifree(AuthComment);
return IL_FALSE;
}
RleLen = ilRleCompress((unsigned char*)TempData, TempImage->Width, TempImage->Height,
TempImage->Depth, TempImage->Bpp, Rle, IL_TGACOMP, NULL);
iwrite(Rle, 1, RleLen);
ifree(Rle);
}
// Write the extension area.
ExtOffset = itellw();
SaveLittleUShort(495); // Number of bytes in the extension area (TGA 2.0 spec)
iwrite(AuthName, 1, ilCharStrLen(AuthName));
ipad(41 - ilCharStrLen(AuthName));
iwrite(AuthComment, 1, ilCharStrLen(AuthComment));
ipad(324 - ilCharStrLen(AuthComment));
ifree(AuthName);
ifree(AuthComment);
// Write time/date
iGetDateTime(&Month, &Day, &Year, &Hour, &Minute, &Second);
SaveLittleUShort((ILushort)Month);
SaveLittleUShort((ILushort)Day);
SaveLittleUShort((ILushort)Year);
SaveLittleUShort((ILushort)Hour);
SaveLittleUShort((ILushort)Minute);
SaveLittleUShort((ILushort)Second);
for (i = 0; i < 6; i++) { // Time created
SaveLittleUShort(0);
}
for (i = 0; i < 41; i++) { // Job name/ID
iputc(0);
}
for (i = 0; i < 3; i++) { // Job time
SaveLittleUShort(0);
}
iwrite(idString, 1, ilCharStrLen(idString)); // Software ID
for (i = 0; i < 41 - ilCharStrLen(idString); i++) {
iputc(0);
}
SaveLittleUShort(IL_VERSION); // Software version
iputc(' '); // Release letter (not beta anymore, so use a space)
SaveLittleUInt(0); // Key colour
SaveLittleUInt(0); // Pixel aspect ratio
SaveLittleUInt(0); // Gamma correction offset
SaveLittleUInt(0); // Colour correction offset
SaveLittleUInt(0); // Postage stamp offset
SaveLittleUInt(0); // Scan line offset
iputc(3); // Attributes type
// Write the footer.
SaveLittleUInt(ExtOffset); // No extension area
SaveLittleUInt(0); // No developer directory
iwrite(Footer, 1, ilCharStrLen(Footer));
if (TempImage->Origin != IL_ORIGIN_LOWER_LEFT) {
ifree(TempData);
}
if (Format == IL_RGB || Format == IL_RGBA) {
ilSwapColours();
}
if (TempPal != &iCurImage->Pal && TempPal != NULL) {
ifree(TempPal->Palette);
ifree(TempPal);
}
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_TRUE;
}
// Only to be called by ilDetermineSize. Returns the buffer size needed to save the
// current image as a Targa file.
ILuint iTargaSize(void)
{
ILuint Size, Bpp;
ILubyte IDLen = 0;
const char *ID = iGetString(IL_TGA_ID_STRING);
const char *AuthName = iGetString(IL_TGA_AUTHNAME_STRING);
const char *AuthComment = iGetString(IL_TGA_AUTHCOMMENT_STRING);
//@TODO: Support color indexed images.
if (iGetInt(IL_TGA_RLE) == IL_TRUE || iCurImage->Format == IL_COLOUR_INDEX) {
// Use the slower method, since we are using compression. We do a "fake" write.
ilSaveTargaL(NULL, 0);
}
if (ID)
IDLen = (ILubyte)ilCharStrLen(ID);
Size = 18 + IDLen; // Header + ID
// Bpp may not be iCurImage->Bpp.
switch (iCurImage->Format)
{
case IL_BGR:
case IL_RGB:
Bpp = 3;
break;
case IL_BGRA:
case IL_RGBA:
Bpp = 4;
break;
case IL_LUMINANCE:
Bpp = 1;
break;
default: //@TODO: Do not know what to do with the others yet.
return 0;
}
Size += iCurImage->Width * iCurImage->Height * Bpp;
Size += 532; // Size of the extension area
return Size;
}
/*// Makes a neat string to go into the id field of the .tga
void iMakeString(char *Str)
{
char *PSG = "Generated by Developer's Image Library: ";
char TimeStr[255];
time_t Time;
struct tm *CurTime;
time(&Time);
#ifdef _WIN32
_tzset();
#endif
CurTime = localtime(&Time);
strftime(TimeStr, 255 - ilCharStrLen(PSG), "%#c (%z)", CurTime);
//strftime(TimeStr, 255 - ilCharStrLen(PSG), "%C (%Z)", CurTime);
sprintf(Str, "%s%s", PSG, TimeStr);
return;
}*/
//changed name to iGetDateTime on 20031221 to fix bug 830196
void iGetDateTime(ILuint *Month, ILuint *Day, ILuint *Yr, ILuint *Hr, ILuint *Min, ILuint *Sec)
{
#ifdef DJGPP
struct date day;
struct time curtime;
gettime(&curtime);
getdate(&day);
*Month = day.da_mon;
*Day = day.da_day;
*Yr = day.da_year;
*Hr = curtime.ti_hour;
*Min = curtime.ti_min;
*Sec = curtime.ti_sec;
return;
#else
#ifdef _WIN32
SYSTEMTIME Time;
GetSystemTime(&Time);
*Month = Time.wMonth;
*Day = Time.wDay;
*Yr = Time.wYear;
*Hr = Time.wHour;
*Min = Time.wMinute;
*Sec = Time.wSecond;
return;
#else
*Month = 0;
*Day = 0;
*Yr = 0;
*Hr = 0;
*Min = 0;
*Sec = 0;
return;
#endif
#endif
}
#endif//IL_NO_TGA
+66
View File
@@ -0,0 +1,66 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/16/2009
//
// Filename: src-IL/src/il_texture.c
//
// Description: Reads from a Medieval II: Total War (by Creative Assembly)
// Texture (.texture) file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_TEXTURE
//! Reads a TEXTURE file
ILboolean ilLoadTexture(ILconst_string FileName)
{
ILHANDLE TextureFile;
ILboolean bTexture = IL_FALSE;
TextureFile = iopenr(FileName);
if (TextureFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bTexture;
}
bTexture = ilLoadTextureF(TextureFile);
icloser(TextureFile);
return bTexture;
}
//! Reads an already-opened TEXTURE file
ILboolean ilLoadTextureF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
// From http://forums.totalwar.org/vb/showthread.php?t=70886, all that needs to be done
// is to strip out the first 48 bytes, and then it is DDS data.
iseek(48, IL_SEEK_CUR);
bRet = ilLoadDdsF(File);
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a TEXTURE
ILboolean ilLoadTextureL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
// From http://forums.totalwar.org/vb/showthread.php?t=70886, all that needs to be done
// is to strip out the first 48 bytes, and then it is DDS data.
iseek(48, IL_SEEK_CUR);
return ilLoadDdsL(Lump, Size);
}
#endif//IL_NO_TEXTURE
File diff suppressed because it is too large Load Diff
+782
View File
@@ -0,0 +1,782 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_tpl.c
//
// Description: Reads from a Gamecube Texture Palette (.tpl).
// Specifications were found at
// http://pabut.homeip.net:8000/yagcd/chap14.html.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_TPL
#include "il_dds.h"
typedef struct TPLHEAD
{
ILuint Magic;
ILuint nTextures;
ILuint HeaderSize;
} TPLHEAD;
// Data formats
#define TPL_I4 0
#define TPL_I8 1
#define TPL_IA4 2
#define TPL_IA8 3
#define TPL_RGB565 4
#define TPL_RGB5A3 5
#define TPL_RGBA8 6
#define TPL_CI4 8
#define TPL_CI8 9
#define TPL_CI14X2 10
#define TPL_CMP 14
// Wrapping
#define TPL_CLAMP 0
#define TPL_REPEAT 1
#define TPL_MIRROR 2
// Palette entries
#define TPL_PAL_IA8 0
#define TPL_PAL_RGB565 1
#define TPL_PAL_RGB5A3 2
ILboolean iIsValidTpl(void);
ILboolean iCheckTpl(TPLHEAD *Header);
ILboolean iLoadTplInternal(void);
ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat);
//! Checks if the file specified in FileName is a valid TPL file.
ILboolean ilIsValidTpl(ILconst_string FileName)
{
ILHANDLE TplFile;
ILboolean bTpl = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("tpl"))) {
ilSetError(IL_INVALID_EXTENSION);
return bTpl;
}
TplFile = iopenr(FileName);
if (TplFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bTpl;
}
bTpl = ilIsValidTplF(TplFile);
icloser(TplFile);
return bTpl;
}
//! Checks if the ILHANDLE contains a valid TPL file at the current position.
ILboolean ilIsValidTplF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidTpl();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid TPL lump.
ILboolean ilIsValidTplL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidTpl();
}
// Internal function used to get the TPL header from the current file.
ILboolean iGetTplHead(TPLHEAD *Header)
{
Header->Magic = GetBigUInt();
Header->nTextures = GetBigUInt();
Header->HeaderSize = GetBigUInt();
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidTpl(void)
{
TPLHEAD Header;
if (!iGetTplHead(&Header))
return IL_FALSE;
iseek(-12, IL_SEEK_CUR);
return iCheckTpl(&Header);
}
// Internal function used to check if the HEADER is a valid TPL header.
ILboolean iCheckTpl(TPLHEAD *Header)
{
// The file signature is 0x0020AF30.
if (Header->Magic != 0x0020AF30)
return IL_FALSE;
// Only valid header size is 0x0C.
if (Header->HeaderSize != 0x0C)
return IL_FALSE;
// We have to have at least 1 texture.
if (Header->nTextures == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a TPL file
ILboolean ilLoadTpl(ILconst_string FileName)
{
ILHANDLE TplFile;
ILboolean bTpl = IL_FALSE;
TplFile = iopenr(FileName);
if (TplFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bTpl;
}
bTpl = ilLoadTplF(TplFile);
icloser(TplFile);
return bTpl;
}
//! Reads an already-opened TPL file
ILboolean ilLoadTplF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadTplInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a TPL
ILboolean ilLoadTplL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadTplInternal();
}
// Internal function used to load the TPL.
ILboolean iLoadTplInternal(void)
{
TPLHEAD Header;
ILimage *Image/*, *BaseImage*/;
ILuint Pos, TexOff, PalOff, DataFormat, Bpp, DataOff, WrapS, WrapT;
ILuint x, y, xBlock, yBlock, i, j, k, n;
ILenum Format;
ILushort Width, Height, ShortPixel;
ILubyte BytePixel, CompData[8];
Color8888 colours[4], *col;
ILushort color_0, color_1;
ILuint bitmask, Select;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
Image = iCurImage; // Top-level image
if (!iGetTplHead(&Header))
return IL_FALSE;
if (!iCheckTpl(&Header)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
// Points to the beginning of the texture header directory.
Pos = itell();
for (n = 0; n < Header.nTextures; n++) {
// Go back to the texture header directory for texture number n+1.
iseek(Pos + n * 8, IL_SEEK_SET);
TexOff = GetBigUInt();
PalOff = GetBigUInt();
// Go to the texture header.
if (iseek(TexOff, IL_SEEK_SET))
return IL_FALSE;
Height = GetBigUShort();
Width = GetBigUShort();
// It looks like files actually have n-1 images, with the nth one having 0 height and width.
if (Width == 0 || Height == 0) {
// If this is our first image, however, we error out.
if (Image == iCurImage) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
// Break out of our for loop and run ilFixImage on the images.
break;
}
DataFormat = GetBigUInt();
TexOff = GetBigUInt();
WrapS = GetBigUInt();
WrapT = GetBigUInt();
if (WrapS == TPL_REPEAT || WrapS == TPL_MIRROR) {
// By the specs, repeated and mirrored textures must have dimensions of power of 2.
if ((Width != ilNextPower2(Width)) || (Height != ilNextPower2(Height))) {
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
}
// Go to the actual texture data.
if (iseek(TexOff, IL_SEEK_SET))
return IL_FALSE;
switch (DataFormat)
{
case TPL_I4:
case TPL_I8:
Format = IL_LUMINANCE;
Bpp = 1;
break;
case TPL_IA4:
case TPL_IA8:
Format = IL_LUMINANCE_ALPHA;
Bpp = 1;
break;
case TPL_RGB565:
Format = IL_RGB;
Bpp = 3;
break;
case TPL_RGB5A3:
Format = IL_RGBA;
Bpp = 4;
break;
case TPL_RGBA8:
Format = IL_RGBA;
Bpp = 4;
break;
case TPL_CI4:
case TPL_CI8:
Format = IL_COLOR_INDEX;
Bpp = 1;
break;
case TPL_CI14X2:
Format = IL_RGBA;
Bpp = 3;
break;
case TPL_CMP:
Format = IL_RGBA;
Bpp = 4;
break;
default:
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
if (Image == iCurImage) { // This is our first image.
if (!ilTexImage(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
}
else {
Image->Next = ilNewImageFull(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL);
if (Image->Next == NULL)
return IL_FALSE;
Image = Image->Next;
}
Image->Origin = IL_ORIGIN_UPPER_LEFT; // Origins are always fixed here.
switch (DataFormat)
{
case TPL_I4:
// 8x8 tiles of 4-bit intensity values
for (y = 0; y < Image->Height; y += 8) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 8; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 8; xBlock += 2) {
BytePixel = igetc();
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
DataOff++;
// We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
DataOff++;
}
}
}
}
break;
case TPL_I8:
// 8x4 tiles of 8-bit intensity values
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 8; xBlock++) {
if ((x + xBlock) >= Image->Width) {
igetc(); // Skip the pad byte.
continue;
}
Image->Data[DataOff] = igetc(); // Luminance value
DataOff++;
}
}
}
}
break;
case TPL_IA4:
// 8x4 tiles of 4-bit intensity and 4-bit alpha values
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 8; xBlock += 2) {
BytePixel = igetc();
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
DataOff += 2;
}
}
}
}
break;
case TPL_IA8:
// 4x4 tiles of 8-bit intensity and 8-bit alpha values
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 4) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4; xBlock += 2) {
if ((x + xBlock) >= Image->Width) {
iseek(2, IL_SEEK_CUR); // Skip the pad bytes.
continue;
}
Image->Data[DataOff] = igetc();
Image->Data[DataOff+1] = igetc();
DataOff += 2;
}
}
}
}
break;
case TPL_RGB565:
// 4x4 tiles of RGB565 data
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 4) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4; xBlock++) {
ShortPixel = GetBigUShort();
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
Image->Data[DataOff+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
Image->Data[DataOff+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
DataOff += 3;
}
}
}
}
break;
case TPL_RGB5A3:
// 4x4 tiles of either RGB5 or RGB4A3 depending on the MSB. 0x80
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 4) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4; xBlock++) {
ShortPixel = GetBigUShort();
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
if (ShortPixel & 0x8000) { // Check MSB.
// We have RGB5.
Image->Data[DataOff] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
Image->Data[DataOff+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
Image->Data[DataOff+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
Image->Data[DataOff+3] = 0xFF; // I am just assuming that it is opaque.
}
else {
// We have RGB4A3.
Image->Data[DataOff] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
Image->Data[DataOff+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
Image->Data[DataOff+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
Image->Data[DataOff+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
}
DataOff += 3;
}
}
}
}
break;
case TPL_RGBA8:
// 4x4 tiles of RGBA data
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 4) {
for (yBlock = 0; yBlock < 4; yBlock++) {
// Skip pad bytes at the bottom of the tile if any.
if ((y + yBlock) >= Image->Height) {
iseek(16, IL_SEEK_CUR); // Entire row of pad bytes skipped
continue;
}
// First it has the AR data.
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4; xBlock++) {
if ((x + xBlock) >= Image->Width) {
iseek(2, IL_SEEK_CUR); // Skip pad bytes.
continue;
}
Image->Data[DataOff+3] = igetc(); // Alpha
Image->Data[DataOff] = igetc(); // Red
DataOff += 3;
}
// Then it has the GB data.
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4 && x + xBlock < Image->Width; xBlock++) {
if ((x + xBlock) >= Image->Width) {
iseek(2, IL_SEEK_CUR); // Skip pad bytes.
continue;
}
Image->Data[DataOff+1] = igetc(); // Green
Image->Data[DataOff+2] = igetc(); // Blue
DataOff += 3;
}
}
}
}
break;
case TPL_CI4:
case TPL_CI8:
case TPL_CI14X2:
// Seek to the palette header.
if (iseek(PalOff, IL_SEEK_SET))
return IL_FALSE;
if (!TplGetIndexImage(Image, TexOff, DataFormat))
return IL_FALSE;
break;
case TPL_CMP:
// S3TC 2x2 blocks of 4x4 tiles. I am assuming that this is DXT1, since it is not specified in the specs.
// Most of this ended up being copied from il_dds.c, from the DecompressDXT1 function.
//@TODO: Make this/that code a bit more modular.
for (y = 0; y < Image->Height; y += 8) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 8 && (y + yBlock) < Image->Height; yBlock += 4) {
for (xBlock = 0; xBlock < 8 && (x + xBlock) < Image->Width; xBlock += 4) {
if (iread(CompData, 1, 8) != 8)
return IL_FALSE; //@TODO: Need to do any cleanup here?
color_0 = *((ILushort*)CompData);
UShort(&color_0);
color_1 = *((ILushort*)(CompData + 2));
UShort(&color_1);
DxtcReadColor(color_0, colours);
DxtcReadColor(color_1, colours + 1);
bitmask = ((ILuint*)CompData)[1];
UInt(&bitmask);
if (color_0 > color_1) {
// Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These 2-bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
//colours[2].a = 0xFF;
colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
colours[3].a = 0xFF;
}
else {
// Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These 2-bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
colours[2].b = (colours[0].b + colours[1].b) / 2;
colours[2].g = (colours[0].g + colours[1].g) / 2;
colours[2].r = (colours[0].r + colours[1].r) / 2;
//colours[2].a = 0xFF;
colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
colours[3].a = 0x00;
}
for (j = 0, k = 0; j < 4; j++) {
for (i = 0; i < 4; i++, k++) {
Select = (bitmask & (0x03 << k*2)) >> k*2;
col = &colours[Select];
if (((x + xBlock + i) < Image->Width) && ((y + yBlock + j) < Image->Height)) {
DataOff = (y + yBlock + j) * Image->Bps + (x + xBlock + i) * Image->Bpp;
Image->Data[DataOff + 0] = col->r;
Image->Data[DataOff + 1] = col->g;
Image->Data[DataOff + 2] = col->b;
Image->Data[DataOff + 3] = col->a;
}
}
}
}
}
}
}
break;
}
}
return ilFixImage();
}
ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat)
{
ILushort NumPal, ShortPixel;
ILubyte LumVal, BytePixel;
ILuint PalFormat, PalOff, PalBpp, DataOff;
ILuint x, y, xBlock, yBlock, i;
NumPal = GetBigUShort();
iseek(2, IL_SEEK_CUR); // Do we need to do anything with the 'unpacked' entry? I see nothing in the specs about it.
PalFormat = GetBigUInt();
// Now we have to find out where the actual palette data is stored.
//@TODO: Do we need to set any errors here?
PalOff = GetBigUInt();
if (iseek(PalOff, IL_SEEK_SET))
return IL_FALSE;
switch (PalFormat)
{
case TPL_PAL_IA8:
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
if (Image->Pal.Palette == NULL)
return IL_FALSE;
Image->Pal.PalType = IL_PAL_RGBA32; //@TODO: Use this format natively.
Image->Pal.PalSize = NumPal * 4;
PalBpp = 4;
for (i = 0; i < NumPal; i++) {
LumVal = igetc();
//@TODO: Do proper conversion of luminance, or support this format natively.
Image->Pal.Palette[i * 4] = LumVal; // Assign the luminance value.
Image->Pal.Palette[i * 4 + 1] = LumVal;
Image->Pal.Palette[i * 4 + 2] = LumVal;
Image->Pal.Palette[i * 4 + 3] = igetc(); // Get alpha value.
}
break;
case TPL_PAL_RGB565:
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 3);
if (Image->Pal.Palette == NULL)
return IL_FALSE;
Image->Pal.PalType = IL_PAL_RGB24;
Image->Pal.PalSize = NumPal * 3;
PalBpp = 3;
for (i = 0; i < NumPal; i++) {
ShortPixel = GetBigUShort();
// This is mostly the same code as in the TPL_RGB565 case.
Image->Pal.Palette[i*3] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
Image->Pal.Palette[i*3+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
Image->Pal.Palette[i*3+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
}
break;
case TPL_PAL_RGB5A3:
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
if (Image->Pal.Palette == NULL)
return IL_FALSE;
Image->Pal.PalType = IL_PAL_RGBA32;
Image->Pal.PalSize = NumPal * 4;
PalBpp = 4;
for (i = 0; i < NumPal; i++) {
ShortPixel = GetBigUShort();
// This is mostly the same code as in the TPL_RGB565 case.
if (ShortPixel & 0x8000) { // Check MSB.
// We have RGB5.
Image->Pal.Palette[i*4] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
Image->Pal.Palette[i*4+3] = 0xFF; // I am just assuming that it is opaque.
}
else {
// We have RGB4A3.
Image->Pal.Palette[i*4] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
Image->Pal.Palette[i*4+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
}
}
break;
default:
ilSetError(IL_ILLEGAL_FILE_VALUE);
return IL_FALSE;
}
// Go back to the texture data.
if (iseek(TexOff, IL_SEEK_SET))
return IL_FALSE;
switch (DataFormat)
{
case TPL_CI4:
// 8x8 tiles of 4-bit color indices
// This is the exact same code as the TPL_I4 case.
for (y = 0; y < Image->Height; y += 8) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 8; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 8; xBlock += 2) {
BytePixel = igetc();
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
DataOff++;
// We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
if ((x + xBlock) >= Image->Width)
continue; // Already read the pad byte.
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
DataOff++;
}
}
}
}
break;
case TPL_CI8:
// 8x4 tiles of 8-bit intensity values
// This is the exact same code as the TPL_I8 case.
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 8) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 8; xBlock++) {
if ((x + xBlock) >= Image->Width) {
igetc(); // Skip the pad byte.
continue;
}
Image->Data[DataOff] = igetc(); // Color index
DataOff++;
}
}
}
}
break;
//@TODO: Convert to more formats than just RGBA.
case TPL_CI14X2:
// 4x4 tiles of 14-bit indices into a palette. Not supported at all in DevIL, since
// it has a huge palette (> 256 colors). Convert to RGBA.
for (y = 0; y < Image->Height; y += 4) {
for (x = 0; x < Image->Width; x += 4) {
for (yBlock = 0; yBlock < 4; yBlock++) {
if ((y + yBlock) >= Image->Height) {
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
continue;
}
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
for (xBlock = 0; xBlock < 4; xBlock++) {
if ((x + xBlock) >= Image->Width) {
GetBigUShort(); // Skip the pad short.
continue;
}
ShortPixel = GetBigUShort();
ShortPixel >>= 2; // Lower 2 bits are padding bits.
Image->Data[DataOff] = Image->Pal.Palette[ShortPixel * PalBpp];
Image->Data[DataOff+1] = Image->Pal.Palette[ShortPixel * PalBpp + 1];
Image->Data[DataOff+2] = Image->Pal.Palette[ShortPixel * PalBpp + 2];
if (PalFormat == TPL_PAL_RGB565)
Image->Data[DataOff+3] = 0xFF;
else
Image->Data[DataOff+3] = Image->Pal.Palette[ShortPixel * PalBpp + 3];
DataOff++;
}
}
}
}
// Get rid of the palette, since we no longer need it.
ifree(Image->Pal.Palette);
Image->Pal.PalType = IL_PAL_NONE;
Image->Pal.PalSize = 0;
break;
}
return IL_TRUE;
}
#endif//IL_NO_TPL
+171
View File
@@ -0,0 +1,171 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 02/04/2009
//
// Filename: src-IL/src/il_utility.c
//
// Description: Utility functions
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
// Returns the bpp of any Format
ILAPI ILubyte ILAPIENTRY ilGetBppFormat(ILenum Format)
{
switch (Format)
{
case IL_COLOUR_INDEX:
case IL_LUMINANCE:
case IL_ALPHA:
return 1;
case IL_LUMINANCE_ALPHA:
return 2;
case IL_RGB:
case IL_BGR:
return 3;
case IL_RGBA:
case IL_BGRA:
return 4;
}
return 0;
}
// Returns the format of any bpp
ILAPI ILenum ILAPIENTRY ilGetFormatBpp(ILubyte Bpp)
{
switch (Bpp)
{
case 1:
return IL_LUMINANCE;
case 2:
return IL_LUMINANCE_ALPHA;
case 3:
return IL_RGB;
case 4:
return IL_RGBA;
}
return 0;
}
// Returns the bpc of any Type
ILAPI ILubyte ILAPIENTRY ilGetBpcType(ILenum Type)
{
switch (Type)
{
case IL_BYTE:
case IL_UNSIGNED_BYTE:
return 1;
case IL_SHORT:
case IL_UNSIGNED_SHORT:
case IL_HALF:
return 2;
case IL_INT:
case IL_UNSIGNED_INT:
case IL_FLOAT:
return 4;
case IL_DOUBLE:
return 8;
}
return 0;
}
// Returns the type matching a bpc
ILAPI ILenum ILAPIENTRY ilGetTypeBpc(ILubyte Bpc)
{
switch (Bpc)
{
case 1:
return IL_UNSIGNED_BYTE;
case 2:
return IL_UNSIGNED_SHORT;
case 4:
return IL_UNSIGNED_INT;
case 8:
return IL_DOUBLE;
}
return 0;
}
// Returns the bpp of any palette type (PalType)
ILAPI ILubyte ILAPIENTRY ilGetBppPal(ILenum PalType)
{
switch (PalType)
{
case IL_PAL_RGB24:
case IL_PAL_BGR24:
return 3;
case IL_PAL_RGB32:
case IL_PAL_RGBA32:
case IL_PAL_BGR32:
case IL_PAL_BGRA32:
return 4;
}
return 0;
}
// Returns the base format of a palette type (PalType)
ILAPI ILenum ILAPIENTRY ilGetPalBaseType(ILenum PalType)
{
switch (PalType)
{
case IL_PAL_RGB24:
return IL_RGB;
case IL_PAL_RGB32:
return IL_RGBA; // Not sure
case IL_PAL_RGBA32:
return IL_RGBA;
case IL_PAL_BGR24:
return IL_BGR;
case IL_PAL_BGR32:
return IL_BGRA; // Not sure
case IL_PAL_BGRA32:
return IL_BGRA;
}
return 0;
}
// Returns the next power of 2 if Num isn't 2^n or returns Num if Num is 2^n
ILAPI ILuint ILAPIENTRY ilNextPower2(ILuint n)
{
ILuint power = 1;
while( power < n ) {
power <<= 1;
}
return power;
}
ILAPI void ILAPIENTRY iMemSwap(ILubyte *s1, ILubyte *s2, const ILuint size)
{
const ILuint block_size = 4096;
const ILuint blocks = size/block_size;
ILuint i;
ILubyte *block = (ILubyte*)ialloc(block_size);
if(block == NULL) return;
for( i = 0; i < blocks; i++ ) {
memcpy(block,s1,block_size);
memcpy(s1,s2,block_size);
memcpy(s2,block,block_size);
s2 += block_size;
s1 += block_size;
}
i = size - i*block_size;
if( i > 0 ) {
memcpy(block,s1,i);
memcpy(s1,s2,i);
memcpy(s2,block,i);
}
ifree(block);
return;
}
+545
View File
@@ -0,0 +1,545 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_utx.cpp
//
// Description: Reads from an Unreal and Unreal Tournament Texture (.utx) file.
// Specifications can be found at
// http://wiki.beyondunreal.com/Legacy:Package_File_Format.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_UTX
#include "il_utx.h"
//! Reads a UTX file
ILboolean ilLoadUtx(ILconst_string FileName)
{
ILHANDLE UtxFile;
ILboolean bUtx = IL_FALSE;
UtxFile = iopenr(FileName);
if (UtxFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bUtx;
}
bUtx = ilLoadUtxF(UtxFile);
icloser(UtxFile);
return bUtx;
}
//! Reads an already-opened UTX file
ILboolean ilLoadUtxF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
try {
bRet = iLoadUtxInternal();
}
catch (bad_alloc &e) {
e;
ilSetError(IL_OUT_OF_MEMORY);
return IL_FALSE;
}
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a UTX
ILboolean ilLoadUtxL(const void *Lump, ILuint Size)
{
try {
iSetInputLump(Lump, Size);
}
catch (bad_alloc &e) {
e;
ilSetError(IL_OUT_OF_MEMORY);
return IL_FALSE;
}
return iLoadUtxInternal();
}
ILboolean GetUtxHead(UTXHEADER &Header)
{
Header.Signature = GetLittleUInt();
Header.Version = GetLittleUShort();
Header.LicenseMode = GetLittleUShort();
Header.Flags = GetLittleUInt();
Header.NameCount = GetLittleUInt();
Header.NameOffset = GetLittleUInt();
Header.ExportCount = GetLittleUInt();
Header.ExportOffset = GetLittleUInt();
Header.ImportCount = GetLittleUInt();
Header.ImportOffset = GetLittleUInt();
return IL_TRUE;
}
ILboolean CheckUtxHead(UTXHEADER &Header)
{
// This signature signifies a UTX file.
if (Header.Signature != 0x9E2A83C1)
return IL_FALSE;
// Unreal uses 61-63, and Unreal Tournament uses 67-69.
if ((Header.Version < 61 || Header.Version > 69))
return IL_FALSE;
return IL_TRUE;
}
// Gets a name variable from the file. Keep in mind that the return value must be freed.
string GetUtxName(UTXHEADER &Header)
{
#define NAME_MAX_LEN 256 //@TODO: Figure out if these can possibly be longer.
char Name[NAME_MAX_LEN];
ILubyte Length = 0;
// New style (Unreal Tournament) name. This has a byte at the beginning telling
// how long the string is (plus terminating 0), followed by the terminating 0.
if (Header.Version >= 64) {
Length = igetc();
if (iread(Name, Length, 1) != 1)
return "";
if (Name[Length-1] != 0)
return "";
return string(Name);
}
// Old style (Unreal) name. This string length is unknown, but it is terminated
// by a 0.
do {
Name[Length++] = igetc();
} while (!ieof() && Name[Length-1] != 0 && Length < NAME_MAX_LEN);
// Never reached the terminating 0.
if (Length == NAME_MAX_LEN && Name[Length-1] != 0)
return "";
return string(Name);
#undef NAME_MAX_LEN
}
bool GetUtxNameTable(vector <UTXENTRYNAME> &NameEntries, UTXHEADER &Header)
{
ILuint NumRead;
// Go to the name table.
iseek(Header.NameOffset, IL_SEEK_SET);
NameEntries.resize(Header.NameCount);
// Read in the name table.
for (NumRead = 0; NumRead < Header.NameCount; NumRead++) {
NameEntries[NumRead].Name = GetUtxName(Header);
if (NameEntries[NumRead].Name == "")
break;
NameEntries[NumRead].Flags = GetLittleUInt();
}
// Did not read all of the entries (most likely GetUtxName failed).
if (NumRead < Header.NameCount) {
ilSetError(IL_INVALID_FILE_HEADER);
return false;
}
return true;
}
// This following code is from http://wiki.beyondunreal.com/Legacy:Package_File_Format/Data_Details.
/// <summary>Reads a compact integer from the FileReader.
/// Bytes read differs, so do not make assumptions about
/// physical data being read from the stream. (If you have
/// to, get the difference of FileReader.BaseStream.Position
/// before and after this is executed.)</summary>
/// <returns>An "uncompacted" signed integer.</returns>
/// <remarks>FileReader is a System.IO.BinaryReader mapped
/// to a file. Also, there may be better ways to implement
/// this, but this is fast, and it works.</remarks>
ILint UtxReadCompactInteger()
{
int output = 0;
ILboolean sign = IL_FALSE;
int i;
ILubyte x;
for(i = 0; i < 5; i++)
{
x = igetc();
// First byte
if(i == 0)
{
// Bit: X0000000
if((x & 0x80) > 0)
sign = IL_TRUE;
// Bits: 00XXXXXX
output |= (x & 0x3F);
// Bit: 0X000000
if((x & 0x40) == 0)
break;
}
// Last byte
else if(i == 4)
{
// Bits: 000XXXXX -- the 0 bits are ignored
// (hits the 32 bit boundary)
output |= (x & 0x1F) << (6 + (3 * 7));
}
// Middle bytes
else
{
// Bits: 0XXXXXXX
output |= (x & 0x7F) << (6 + ((i - 1) * 7));
// Bit: X0000000
if((x & 0x80) == 0)
break;
}
}
// multiply by negative one here, since the first 6+ bits could be 0
if (sign)
output *= -1;
return output;
}
void ChangeObjectReference(ILint *ObjRef, ILboolean *IsImported)
{
if (*ObjRef < 0) {
*IsImported = IL_TRUE;
*ObjRef = -*ObjRef - 1;
}
else if (*ObjRef > 0) {
*IsImported = IL_FALSE;
*ObjRef = *ObjRef - 1; // This is an object reference, so we have to do this conversion.
}
else {
*ObjRef = -1; // "NULL" pointer
}
return;
}
bool GetUtxExportTable(vector <UTXEXPORTTABLE> &ExportTable, UTXHEADER &Header)
{
ILuint i;
// Go to the name table.
iseek(Header.ExportOffset, IL_SEEK_SET);
// Create ExportCount elements in our array.
ExportTable.resize(Header.ExportCount);
for (i = 0; i < Header.ExportCount; i++) {
ExportTable[i].Class = UtxReadCompactInteger();
ExportTable[i].Super = UtxReadCompactInteger();
ExportTable[i].Group = GetLittleUInt();
ExportTable[i].ObjectName = UtxReadCompactInteger();
ExportTable[i].ObjectFlags = GetLittleUInt();
ExportTable[i].SerialSize = UtxReadCompactInteger();
ExportTable[i].SerialOffset = UtxReadCompactInteger();
ChangeObjectReference(&ExportTable[i].Class, &ExportTable[i].ClassImported);
ChangeObjectReference(&ExportTable[i].Super, &ExportTable[i].SuperImported);
ChangeObjectReference(&ExportTable[i].Group, &ExportTable[i].GroupImported);
}
return true;
}
bool GetUtxImportTable(vector <UTXIMPORTTABLE> &ImportTable, UTXHEADER &Header)
{
ILuint i;
// Go to the name table.
iseek(Header.ImportOffset, IL_SEEK_SET);
// Allocate the name table.
ImportTable.resize(Header.ImportCount);
for (i = 0; i < Header.ImportCount; i++) {
ImportTable[i].ClassPackage = UtxReadCompactInteger();
ImportTable[i].ClassName = UtxReadCompactInteger();
ImportTable[i].Package = GetLittleUInt();
ImportTable[i].ObjectName = UtxReadCompactInteger();
ChangeObjectReference(&ImportTable[i].Package, &ImportTable[i].PackageImported);
}
return true;
}
/*void UtxDestroyPalettes(UTXPALETTE *Palettes, ILuint NumPal)
{
ILuint i;
for (i = 0; i < NumPal; i++) {
//ifree(Palettes[i].Name);
ifree(Palettes[i].Pal);
}
ifree(Palettes);
}*/
ILenum UtxFormatToDevIL(ILuint Format)
{
switch (Format)
{
case UTX_P8:
return IL_COLOR_INDEX;
case UTX_DXT1:
return IL_RGBA;
}
return IL_BGRA; // Should never reach here.
}
ILuint UtxFormatToBpp(ILuint Format)
{
switch (Format)
{
case UTX_P8:
return 1;
case UTX_DXT1:
return 4;
}
return 4; // Should never reach here.
}
// Internal function used to load the UTX.
ILboolean iLoadUtxInternal(void)
{
UTXHEADER Header;
vector <UTXENTRYNAME> NameEntries;
vector <UTXEXPORTTABLE> ExportTable;
vector <UTXIMPORTTABLE> ImportTable;
vector <UTXPALETTE> Palettes;
ILimage *Image;
ILuint NumPal = 0, i, j = 0;
ILint Name;
ILubyte Type;
ILint Val;
ILint Size;
ILint Width, Height, PalEntry;
ILboolean BaseCreated = IL_FALSE, HasPal;
ILint Format;
ILubyte *CompData = NULL;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (!GetUtxHead(Header))
return IL_FALSE;
if (!CheckUtxHead(Header))
return IL_FALSE;
// We grab the name table.
if (!GetUtxNameTable(NameEntries, Header))
return IL_FALSE;
// Then we get the export table.
if (!GetUtxExportTable(ExportTable, Header))
return IL_FALSE;
// Then the last table is the import table.
if (!GetUtxImportTable(ImportTable, Header))
return IL_FALSE;
// Find the number of palettes in the export table.
for (i = 0; i < Header.ExportCount; i++) {
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Palette")
NumPal++;
}
Palettes.resize(NumPal);
// Read in all of the palettes.
NumPal = 0;
for (i = 0; i < Header.ExportCount; i++) {
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Palette") {
Palettes[NumPal].Name = i;
iseek(ExportTable[NumPal].SerialOffset, IL_SEEK_SET);
Name = igetc(); // Skip the 2. @TODO: Can there be more in front of the palettes?
Palettes[NumPal].Count = UtxReadCompactInteger();
Palettes[NumPal].Pal = new ILubyte[Palettes[NumPal].Count * 4];
if (iread(Palettes[NumPal].Pal, Palettes[NumPal].Count * 4, 1) != 1)
return IL_FALSE;
NumPal++;
}
}
for (i = 0; i < Header.ExportCount; i++) {
// Find textures in the file.
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Texture") {
iseek(ExportTable[i].SerialOffset, IL_SEEK_SET);
Width = -1; Height = -1; PalEntry = NumPal; HasPal = IL_FALSE; Format = -1;
do {
// Always starts with a comptact integer that gives us an entry into the name table.
Name = UtxReadCompactInteger();
if (NameEntries[Name].Name == "None")
break;
Type = igetc();
Size = (Type & 0x70) >> 4;
if (Type == 0xA2)
igetc(); // Byte is 1 here...
switch (Type & 0x0F)
{
case 1: // Get a single byte.
Val = igetc();
break;
case 2: // Get unsigned integer.
Val = GetLittleUInt();
break;
case 3: // Boolean value is in the info byte.
igetc();
break;
case 4: // Skip flaots for right now.
GetLittleFloat();
break;
case 5:
case 6: // Get a compact integer - an object reference.
Val = UtxReadCompactInteger();
Val--;
break;
case 10:
Val = igetc();
switch (Size)
{
case 0:
iseek(1, IL_SEEK_CUR);
break;
case 1:
iseek(2, IL_SEEK_CUR);
break;
case 2:
iseek(4, IL_SEEK_CUR);
break;
case 3:
iseek(12, IL_SEEK_CUR);
break;
}
break;
default: // Uhm...
break;
}
//@TODO: What should we do if Name >= Header.NameCount?
if ((ILuint)Name < Header.NameCount) { // Don't want to go past the end of our array.
if (NameEntries[Name].Name == "Palette") {
// If it has references to more than one palette, just use the first one.
if (HasPal == IL_FALSE) {
// We go through the palette list here to match names.
for (PalEntry = 0; (ILuint)PalEntry < NumPal; PalEntry++) {
if (Val == Palettes[PalEntry].Name) {
HasPal = IL_TRUE;
break;
}
}
}
}
if (NameEntries[Name].Name == "Format") // Not required for P8 images but can be present.
if (Format == -1)
Format = Val;
if (NameEntries[Name].Name == "USize") // Width of the image
if (Width == -1)
Width = Val;
if (NameEntries[Name].Name == "VSize") // Height of the image
if (Height == -1)
Height = Val;
}
} while (!ieof());
// If the format property is not present, it is a paletted (P8) image.
if (Format == -1)
Format = UTX_P8;
// Just checks for everything being proper. If the format is P8, we check to make sure that a palette was found.
if (Width == -1 || Height == -1 || (PalEntry == NumPal && Format != UTX_DXT1) || (Format != UTX_P8 && Format != UTX_DXT1))
return IL_FALSE;
if (BaseCreated == IL_FALSE) {
BaseCreated = IL_TRUE;
ilTexImage(Width, Height, 1, UtxFormatToBpp(Format), UtxFormatToDevIL(Format), IL_UNSIGNED_BYTE, NULL);
Image = iCurImage;
}
else {
Image->Next = ilNewImageFull(Width, Height, 1, UtxFormatToBpp(Format), UtxFormatToDevIL(Format), IL_UNSIGNED_BYTE, NULL);
if (Image->Next == NULL)
return IL_FALSE;
Image = Image->Next;
}
// Skip the mipmap count, width offset and mipmap size entries.
//@TODO: Implement mipmaps.
iseek(5, IL_SEEK_CUR);
UtxReadCompactInteger();
switch (Format)
{
case UTX_P8:
Image->Pal.PalSize = Palettes[PalEntry].Count * 4;
Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
if (Image->Pal.Palette == NULL)
return IL_FALSE;
memcpy(Image->Pal.Palette, Palettes[PalEntry].Pal, Image->Pal.PalSize);
Image->Pal.PalType = IL_PAL_RGBA32;
if (iread(Image->Data, Image->SizeOfData, 1) != 1)
return IL_FALSE;
break;
case UTX_DXT1:
Image->DxtcSize = IL_MAX(Image->Width * Image->Height / 2, 8);
CompData = (ILubyte*)ialloc(Image->DxtcSize);
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, Image->DxtcSize, 1) != 1) {
ifree(CompData);
return IL_FALSE;
}
// Keep a copy of the DXTC data if the user wants it.
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT1;
CompData = NULL;
}
if (DecompressDXT1(Image, CompData) == IL_FALSE) {
ifree(CompData);
return IL_FALSE;
}
ifree(CompData);
break;
}
Image->Origin = IL_ORIGIN_UPPER_LEFT;
}
}
return ilFixImage();
}
#endif//IL_NO_UTX
+953
View File
@@ -0,0 +1,953 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_vtf.c
//
// Description: Reads from and writes to a Valve Texture Format (.vtf) file.
// These are used in Valve's Source games. VTF specs available
// from http://developer.valvesoftware.com/wiki/VTF.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_VTF
#include "il_vtf.h"
#include "il_dds.h"
//@TODO: Get rid of these globals.
//static VTFHEAD Head;
//! Checks if the file specified in FileName is a valid VTF file.
ILboolean ilIsValidVtf(ILconst_string FileName)
{
ILHANDLE VtfFile;
ILboolean bVtf = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("vtf"))) {
ilSetError(IL_INVALID_EXTENSION);
return bVtf;
}
VtfFile = iopenr(FileName);
if (VtfFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bVtf;
}
bVtf = ilIsValidVtfF(VtfFile);
icloser(VtfFile);
return bVtf;
}
//! Checks if the ILHANDLE contains a valid VTF file at the current position.
ILboolean ilIsValidVtfF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidVtf();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid VTF lump.
ILboolean ilIsValidVtfL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidVtf();
}
// Internal function used to get the VTF header from the current file.
ILboolean iGetVtfHead(VTFHEAD *Header)
{
iread(Header->Signature, 1, 4);
Header->Version[0] = GetLittleUInt();
Header->Version[1] = GetLittleUInt();
Header->HeaderSize = GetLittleUInt();
Header->Width = GetLittleUShort();
Header->Height = GetLittleUShort();
Header->Flags = GetLittleUInt();
Header->Frames = GetLittleUShort();
Header->FirstFrame = GetLittleUShort();
iseek(4, IL_SEEK_CUR); // Padding
Header->Reflectivity[0] = GetLittleFloat();
Header->Reflectivity[1] = GetLittleFloat();
Header->Reflectivity[2] = GetLittleFloat();
iseek(4, IL_SEEK_CUR); // Padding
Header->BumpmapScale = GetLittleFloat();
Header->HighResImageFormat = GetLittleUInt();
Header->MipmapCount = (ILubyte)igetc();
Header->LowResImageFormat = GetLittleInt();
Header->LowResImageWidth = (ILubyte)igetc();
Header->LowResImageHeight = (ILubyte)igetc();
//@TODO: This is a hack for the moment.
if (Header->HeaderSize == 64) {
Header->Depth = igetc();
if (Header->Depth == 0)
Header->Depth = 1;
}
else {
Header->Depth = GetLittleUShort();
iseek(Header->HeaderSize - sizeof(VTFHEAD), IL_SEEK_CUR);
}
return IL_TRUE;
}
// Internal function to get the header and check it.
ILboolean iIsValidVtf(void)
{
VTFHEAD Header;
if (!iGetVtfHead(&Header))
return IL_FALSE;
iseek(-(ILint)sizeof(VTFHEAD), IL_SEEK_CUR);
return iCheckVtf(&Header);
}
//@TODO: Add more checks.
// Should we check for Frames, MipmapCount and Depth != 0?
// Internal function used to check if the HEADER is a valid VTF header.
ILboolean iCheckVtf(VTFHEAD *Header)
{
// The file signature is "VTF\0".
if ((Header->Signature[0] != 'V') || (Header->Signature[1] != 'T') || (Header->Signature[2] != 'F')
|| (Header->Signature[3] != 0))
return IL_FALSE;
// Are there other versions available yet?
if (Header->Version[0] != 7)
return IL_FALSE;
// We have 7.0 through 7.4 as of 12/27/2008.
if (Header->Version[1] > 4)
return IL_FALSE;
// May change in future version of the specifications.
// 80 is through version 7.2, and 96/104 are through 7.4.
// This must be 16-byte aligned, but something is outputting headers with 104.
if ((Header->HeaderSize != 80) && (Header->HeaderSize != 96) && (Header->HeaderSize != 104)
&& (Header->HeaderSize != 64))
return IL_FALSE;
// 0 is an invalid dimension
if (Header->Width == 0 || Header->Height == 0)
return IL_FALSE;
// Width and Height must be powers of 2.
if ((ilNextPower2(Header->Width) != Header->Width) || (ilNextPower2(Header->Height) != Header->Height))
return IL_FALSE;
// It looks like width and height of zero are valid - i.e. no low res image.
if (Header->LowResImageWidth != 0 && Header->LowResImageHeight != 0) {
if ((ilNextPower2(Header->LowResImageWidth) != Header->LowResImageWidth)
|| (ilNextPower2(Header->LowResImageHeight) != Header->LowResImageHeight))
return IL_FALSE;
}
// In addition, the LowResImage has to have dimensions no greater than 16.
if ((Header->LowResImageWidth > 16) || (Header->LowResImageHeight > 16))
//|| (Header->LowResImageWidth == 0) || (Header->LowResImageHeight == 0))
// It looks like width and height of zero are valid.
return IL_FALSE;
// And the LowResImage has to have dimensions less than or equal to the main image.
if ((Header->LowResImageWidth > Header->Width) || (Header->LowResImageHeight > Header->Height))
return IL_FALSE;
// The LowResImage must be in DXT1 format, or if it does not exist, it is denoted by all bits set.
if (Header->LowResImageFormat != IMAGE_FORMAT_DXT1 && Header->LowResImageFormat != 0xFFFFFFFF)
return IL_FALSE;
return IL_TRUE;
}
//! Reads a VTF file
ILboolean ilLoadVtf(ILconst_string FileName)
{
ILHANDLE VtfFile;
ILboolean bVtf = IL_FALSE;
VtfFile = iopenr(FileName);
if (VtfFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bVtf;
}
bVtf = ilLoadVtfF(VtfFile);
icloser(VtfFile);
return bVtf;
}
//! Reads an already-opened VTF file
ILboolean ilLoadVtfF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadVtfInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a VTF
ILboolean ilLoadVtfL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadVtfInternal();
}
// Internal function used to load the VTF.
ILboolean iLoadVtfInternal(void)
{
ILboolean bVtf = IL_TRUE;
ILimage *Image, *BaseImage;
ILenum Format, Type;
ILint Frame, Face, Mipmap;
ILuint SizeOfData, Channels, k;
ILubyte *CompData = NULL, SwapVal, *Data16Bit, *Temp, NumFaces;
VTFHEAD Head;
ILuint CurName;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
CurName = ilGetCurName();
if (!iGetVtfHead(&Head))
return IL_FALSE;
if (!iCheckVtf(&Head)) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (Head.Flags & TEXTUREFLAGS_ENVMAP) {
// If we have a spherical map in addition to the 6 sides of the cubemap, FirstFrame's bits
// are all set. The only place I found out about this was VTFLib.
NumFaces = Head.FirstFrame == 0xFFFF ? 6 : 7;
}
else
NumFaces = 1; // This is not an environmental map.
// Skip the low resolution image. This is just a thumbnail.
// The block size is 8, and the compression ratio is 6:1.
SizeOfData = IL_MAX(Head.LowResImageWidth * Head.LowResImageHeight / 2, 8);
if (Head.LowResImageWidth == 0 && Head.LowResImageHeight == 0)
SizeOfData = 0; // No low resolution image present.
iseek(SizeOfData, IL_SEEK_CUR);
//@TODO: Make this a helper function that set channels, bpc and format.
switch (Head.HighResImageFormat)
{
case IMAGE_FORMAT_DXT1: //@TODO: Should we make DXT1 channels = 3?
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
case IMAGE_FORMAT_DXT3:
case IMAGE_FORMAT_DXT5:
Channels = 4;
Format = IL_RGBA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGR888:
case IMAGE_FORMAT_BGR888_BLUESCREEN:
Channels = 3;
Format = IL_BGR;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGRA8888:
Channels = 4;
Format = IL_BGRA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGRX8888:
Channels = 3;
Format = IL_BGR;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_RGB888:
case IMAGE_FORMAT_RGB888_BLUESCREEN:
Channels = 3;
Format = IL_RGB;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_RGBA8888:
Channels = 4;
Format = IL_RGBA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_RGBA16161616: // 16-bit shorts
Channels = 4;
Format = IL_RGBA;
Type = IL_UNSIGNED_SHORT;
break;
case IMAGE_FORMAT_RGBA16161616F: // 16-bit floats
Channels = 4;
Format = IL_RGBA;
Type = IL_FLOAT;
break;
case IMAGE_FORMAT_I8: // 8-bit luminance data
Channels = 1;
Format = IL_LUMINANCE;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_IA88: // 8-bit luminance and alpha data
Channels = 2;
Format = IL_LUMINANCE_ALPHA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_A8: // 8-bit alpha data
Channels = 1;
Format = IL_ALPHA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_ARGB8888:
Channels = 4;
Format = IL_BGRA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_ABGR8888:
Channels = 4;
Format = IL_RGBA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_RGB565:
Channels = 3;
Format = IL_RGB;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGR565:
Channels = 3;
Format = IL_BGR;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGRA5551:
Channels = 4;
Format = IL_BGRA;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGRX5551: // Unused alpha channel
Channels = 3;
Format = IL_BGR;
Type = IL_UNSIGNED_BYTE;
break;
case IMAGE_FORMAT_BGRA4444:
Channels = 4;
Format = IL_BGRA;
Type = IL_UNSIGNED_BYTE;
break;
default:
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
if (!ilTexImage(Head.Width, Head.Height, Head.Depth, Channels, Format, Type, NULL))
return IL_FALSE;
// The origin should be in the upper left.
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
// Create any mipmaps.
VtfInitFacesMipmaps(iCurImage, NumFaces, &Head);
// Create our animation chain
BaseImage = Image = iCurImage; // Top-level image
for (Frame = 1; Frame < Head.Frames; Frame++) {
Image->Next = ilNewImageFull(Head.Width, Head.Height, Head.Depth, Channels, Format, Type, NULL);
if (Image->Next == NULL)
return IL_FALSE;
Image = Image->Next;
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
// Create our faces and mipmaps for each frame.
VtfInitFacesMipmaps(Image, NumFaces, &Head);
}
// We want to put the smallest mipmap at the end, but it is first in the file, so we count backwards.
for (Mipmap = Head.MipmapCount - 1; Mipmap >= 0; Mipmap--) {
// Frames are in the normal order.
for (Frame = 0; Frame < Head.Frames; Frame++) {
// @TODO: Cubemap faces are always in the same order?
for (Face = 0; Face < NumFaces; Face++) {
//@TODO: Would probably be quicker to do the linked list traversal manually here.
ilBindImage(CurName);
ilActiveImage(Frame);
ilActiveFace(Face);
ilActiveMipmap(Mipmap);
Image = iCurImage;
switch (Head.HighResImageFormat)
{
// DXT1 compression
case IMAGE_FORMAT_DXT1:
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
// The block size is 8.
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth / 2, 8);
CompData = ialloc(SizeOfData); // Gives a 6:1 compression ratio (or 8:1 for DXT1 with alpha)
if (CompData == NULL)
return IL_FALSE;
iread(CompData, 1, SizeOfData);
// Keep a copy of the DXTC data if the user wants it.
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = SizeOfData;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT5;
CompData = NULL;
}
bVtf = DecompressDXT1(Image, CompData);
break;
// DXT3 compression
case IMAGE_FORMAT_DXT3:
// The block size is 16.
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth, 16);
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
if (CompData == NULL)
return IL_FALSE;
iread(CompData, 1, SizeOfData);
// Keep a copy of the DXTC data if the user wants it.
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = SizeOfData;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT3;
CompData = NULL;
}
bVtf = DecompressDXT3(Image, CompData);
break;
// DXT5 compression
case IMAGE_FORMAT_DXT5:
// The block size is 16.
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth, 16);
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
if (CompData == NULL)
return IL_FALSE;
iread(CompData, 1, SizeOfData);
// Keep a copy of the DXTC data if the user wants it.
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
Image->DxtcSize = SizeOfData;
Image->DxtcData = CompData;
Image->DxtcFormat = IL_DXT5;
CompData = NULL;
}
bVtf = DecompressDXT5(Image, CompData);
break;
// Uncompressed BGR(A) data (24-bit and 32-bit)
case IMAGE_FORMAT_BGR888:
case IMAGE_FORMAT_BGRA8888:
// Uncompressed RGB(A) data (24-bit and 32-bit)
case IMAGE_FORMAT_RGB888:
case IMAGE_FORMAT_RGBA8888:
// Uncompressed 16-bit shorts
case IMAGE_FORMAT_RGBA16161616:
// Luminance data only
case IMAGE_FORMAT_I8:
// Luminance and alpha data
case IMAGE_FORMAT_IA88:
// Alpha data only
case IMAGE_FORMAT_A8:
// We will ignore the part about the bluescreen right now.
// I could not find any information about it.
case IMAGE_FORMAT_RGB888_BLUESCREEN:
case IMAGE_FORMAT_BGR888_BLUESCREEN:
// Just copy the data over - no compression.
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
bVtf = IL_FALSE;
else
bVtf = IL_TRUE;
break;
// Uncompressed 24-bit data with an unused alpha channel (we discard it)
case IMAGE_FORMAT_BGRX8888:
SizeOfData = Image->Width * Image->Height * Image->Depth * 3;
Temp = CompData = ialloc(SizeOfData / 3 * 4); // Not compressed data
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData / 3 * 4) != SizeOfData / 3 * 4) {
bVtf = IL_FALSE;
break;
}
for (k = 0; k < SizeOfData; k += 3) {
Image->Data[k] = Temp[0];
Image->Data[k+1] = Temp[1];
Image->Data[k+2] = Temp[2];
Temp += 4;
}
break;
// Uncompressed 16-bit floats (must be converted to 32-bit)
case IMAGE_FORMAT_RGBA16161616F:
SizeOfData = Image->Width * Image->Height * Image->Depth * Image->Bpp * 2;
CompData = ialloc(SizeOfData); // Not compressed data
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
bVtf = IL_FALSE;
break;
}
bVtf = iConvFloat16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData, SizeOfData / 2);
break;
// Uncompressed 32-bit ARGB and ABGR data. DevIL does not handle this
// internally, so we have to swap values.
case IMAGE_FORMAT_ARGB8888:
case IMAGE_FORMAT_ABGR8888:
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData) {
bVtf = IL_FALSE;
break;
}
else {
bVtf = IL_TRUE;
}
// Swap the data
for (k = 0; k < Image->SizeOfData; k += 4) {
SwapVal = Image->Data[k];
Image->Data[k] = Image->Data[k+3];
Image->Data[k+3] = SwapVal;
SwapVal = Image->Data[k+1];
Image->Data[k+1] = Image->Data[k+2];
Image->Data[k+2] = SwapVal;
}
break;
// Uncompressed 16-bit RGB and BGR data. We have to expand this to 24-bit, since
// DevIL does not handle this internally.
// The data is in the file as: gggbbbbb rrrrrrggg
case IMAGE_FORMAT_RGB565:
case IMAGE_FORMAT_BGR565:
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
bVtf = IL_FALSE;
break;
}
for (k = 0; k < Image->SizeOfData; k += 3) {
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
Image->Data[k+1] = ((Data16Bit[1] & 0x07) << 5) | ((Data16Bit[0] & 0xE0) >> 3);
Image->Data[k+2] = Data16Bit[1] & 0xF8;
Data16Bit += 2;
}
break;
// Uncompressed 16-bit BGRA data (1-bit alpha). We have to expand this to 32-bit,
// since DevIL does not handle this internally.
// Something seems strange with this one, but this is how VTFEdit outputs.
// The data is in the file as: gggbbbbb arrrrrgg
case IMAGE_FORMAT_BGRA5551:
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
bVtf = IL_FALSE;
break;
}
for (k = 0; k < Image->SizeOfData; k += 4) {
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
Image->Data[k+1] = ((Data16Bit[0] & 0xE0) >> 2) | ((Data16Bit[1] & 0x03) << 6);
Image->Data[k+2] = (Data16Bit[1] & 0x7C) << 1;
// 1-bit alpha is either off or on.
Image->Data[k+3] = ((Data16Bit[0] & 0x80) == 0x80) ? 0xFF : 0x00;
Data16Bit += 2;
}
break;
// Same as above, but the alpha channel is unused.
case IMAGE_FORMAT_BGRX5551:
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
bVtf = IL_FALSE;
break;
}
for (k = 0; k < Image->SizeOfData; k += 3) {
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
Image->Data[k+1] = ((Data16Bit[0] & 0xE0) >> 2) | ((Data16Bit[1] & 0x03) << 6);
Image->Data[k+2] = (Data16Bit[1] & 0x7C) << 1;
Data16Bit += 2;
}
break;
// Data is reduced to a 4-bits per channel format.
case IMAGE_FORMAT_BGRA4444:
SizeOfData = Image->Width * Image->Height * Image->Depth * 4;
Temp = CompData = ialloc(SizeOfData / 2); // Not compressed data
if (CompData == NULL)
return IL_FALSE;
if (iread(CompData, 1, SizeOfData / 2) != SizeOfData / 2) {
bVtf = IL_FALSE;
break;
}
for (k = 0; k < SizeOfData; k += 4) {
// We double the data here.
Image->Data[k] = (Temp[0] & 0x0F) << 4 | (Temp[0] & 0x0F);
Image->Data[k+1] = (Temp[0] & 0xF0) >> 4 | (Temp[0] & 0xF0);
Image->Data[k+2] = (Temp[1] & 0x0F) << 4 | (Temp[1] & 0x0F);
Image->Data[k+3] = (Temp[1] & 0xF0) >> 4 | (Temp[1] & 0xF0);
Temp += 2;
}
break;
}
ifree(CompData);
CompData = NULL;
if (bVtf == IL_FALSE) //@TODO: Do we need to do any cleanup here?
return IL_FALSE;
}
}
}
ilBindImage(CurName); // Set to parent image first.
return ilFixImage();
}
ILuint GetFaceFlag(ILuint FaceNum)
{
switch (FaceNum)
{
case 0:
return IL_CUBEMAP_POSITIVEX;
case 1:
return IL_CUBEMAP_NEGATIVEX;
case 2:
return IL_CUBEMAP_POSITIVEY;
case 3:
return IL_CUBEMAP_NEGATIVEY;
case 4:
return IL_CUBEMAP_POSITIVEZ;
case 5:
return IL_CUBEMAP_NEGATIVEZ;
case 6:
return IL_SPHEREMAP;
}
return IL_SPHEREMAP; // Should never reach here!
}
ILboolean VtfInitFacesMipmaps(ILimage *BaseImage, ILuint NumFaces, VTFHEAD *Header)
{
ILimage *Image;
ILuint Face;
// Initialize mipmaps under the base image.
VtfInitMipmaps(BaseImage, Header);
Image = BaseImage;
// We have an environment map.
if (NumFaces != 1) {
Image->CubeFlags = IL_CUBEMAP_POSITIVEX;
}
for (Face = 1; Face < NumFaces; Face++) {
Image->Faces = ilNewImageFull(Image->Width, Image->Height, Image->Depth, Image->Bpp, Image->Format, Image->Type, NULL);
if (Image->Faces == NULL)
return IL_FALSE;
Image = Image->Faces;
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
// Set the flags that tell which face this is.
Image->CubeFlags = GetFaceFlag(Face);
// Now we can initialize the mipmaps under each face.
VtfInitMipmaps(Image, Header);
}
return IL_TRUE;
}
ILboolean VtfInitMipmaps(ILimage *BaseImage, VTFHEAD *Header)
{
ILimage *Image;
ILuint Width, Height, Depth, Mipmap;
Image = BaseImage;
Width = BaseImage->Width; Height = BaseImage->Height; Depth = BaseImage->Depth;
for (Mipmap = 1; Mipmap < Header->MipmapCount; Mipmap++) {
// 1 is the smallest dimension possible.
Width = (Width >> 1) == 0 ? 1 : (Width >> 1);
Height = (Height >> 1) == 0 ? 1 : (Height >> 1);
Depth = (Depth >> 1) == 0 ? 1 : (Depth >> 1);
Image->Mipmaps = ilNewImageFull(Width, Height, Depth, BaseImage->Bpp, BaseImage->Format, BaseImage->Type, NULL);
if (Image->Mipmaps == NULL)
return IL_FALSE;
Image = Image->Mipmaps;
// ilNewImage does not set these.
Image->Format = BaseImage->Format;
Image->Type = BaseImage->Type;
// The origin should be in the upper left.
Image->Origin = IL_ORIGIN_UPPER_LEFT;
}
return IL_TRUE;
}
ILboolean CheckDimensions()
{
if ((ilNextPower2(iCurImage->Width) != iCurImage->Width) || (ilNextPower2(iCurImage->Height) != iCurImage->Height)) {
ilSetError(IL_BAD_DIMENSIONS);
return IL_FALSE;
}
return IL_TRUE;
}
//! Writes a Vtf file
ILboolean ilSaveVtf(const ILstring FileName)
{
ILHANDLE VtfFile;
ILuint VtfSize;
if (!CheckDimensions())
return IL_FALSE;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
VtfFile = iopenw(FileName);
if (VtfFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
VtfSize = ilSaveVtfF(VtfFile);
iclosew(VtfFile);
if (VtfSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a .vtf to an already-opened file
ILuint ilSaveVtfF(ILHANDLE File)
{
ILuint Pos;
if (!CheckDimensions())
return 0;
iSetOutputFile(File);
Pos = itellw();
if (iSaveVtfInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a .vtf to a memory "lump"
ILuint ilSaveVtfL(void *Lump, ILuint Size)
{
ILuint Pos;
if (!CheckDimensions())
return 0;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSaveVtfInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// Internal function used to save the Vtf.
ILboolean iSaveVtfInternal()
{
ILimage *TempImage = iCurImage;
ILubyte *TempData, *CompData;
ILuint Format, i, CompSize;
ILenum Compression;
// Find out if the user has specified to use DXT compression.
Compression = ilGetInteger(IL_VTF_COMP);
//@TODO: Other formats
if (Compression == IL_DXT_NO_COMP) {
switch (TempImage->Format)
{
case IL_RGB:
Format = IMAGE_FORMAT_RGB888;
break;
case IL_RGBA:
Format = IMAGE_FORMAT_RGBA8888;
break;
case IL_BGR:
Format = IMAGE_FORMAT_BGR888;
break;
case IL_BGRA:
Format = IMAGE_FORMAT_BGRA8888;
break;
case IL_LUMINANCE:
Format = IMAGE_FORMAT_I8;
break;
case IL_ALPHA:
Format = IMAGE_FORMAT_A8;
break;
case IL_LUMINANCE_ALPHA:
Format = IMAGE_FORMAT_IA88;
break;
//case IL_COLOUR_INDEX:
default:
Format = IMAGE_FORMAT_BGRA8888;
TempImage = iConvertImage(iCurImage, IL_BGRA, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
}
//@TODO: When we have the half format available internally, also use IMAGE_FORMAT_RGBA16161616F.
if (TempImage->Format == IL_RGBA && TempImage->Type == IL_UNSIGNED_SHORT) {
Format = IMAGE_FORMAT_RGBA16161616;
}
else if (TempImage->Type != IL_UNSIGNED_BYTE) { //@TODO: Any possibility for shorts, etc. to be used?
TempImage = iConvertImage(iCurImage, Format, IL_UNSIGNED_BYTE);
if (TempImage == NULL)
return IL_FALSE;
}
}
else { // We are using DXT compression.
switch (Compression)
{
case IL_DXT1:
Format = IMAGE_FORMAT_DXT1_ONEBITALPHA;//IMAGE_FORMAT_DXT1;
break;
case IL_DXT3:
Format = IMAGE_FORMAT_DXT3;
break;
case IL_DXT5:
Format = IMAGE_FORMAT_DXT5;
break;
default: // Should never reach this point.
ilSetError(IL_INTERNAL_ERROR);
Format = IMAGE_FORMAT_DXT5;
}
}
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
TempData = iGetFlipped(TempImage);
if (TempData == NULL) {
ilCloseImage(TempImage);
return IL_FALSE;
}
} else {
TempData = TempImage->Data;
}
// Write the file signature.
iwrite("VTF", 1, 4);
// Write the file version - currently using 7.2 specs.
SaveLittleUInt(7);
SaveLittleUInt(2);
// Write the header size.
SaveLittleUInt(80);
// Now we write the width and height of the image.
SaveLittleUShort(TempImage->Width);
SaveLittleUShort(TempImage->Height);
//@TODO: This is supposed to be the flags used. What should we use here? Let users specify?
SaveLittleUInt(0);
// Number of frames in the animation. - @TODO: Change to use animations.
SaveLittleUShort(1);
// First frame in the animation
SaveLittleUShort(0);
// Padding
SaveLittleUInt(0);
// Reflectivity (3 floats) - @TODO: Use what values? User specified?
SaveLittleFloat(0.0f);
SaveLittleFloat(0.0f);
SaveLittleFloat(0.0f);
// Padding
SaveLittleUInt(0);
// Bumpmap scale
SaveLittleFloat(0.0f);
// Image format
SaveLittleUInt(Format);
// Mipmap count - @TODO: Use mipmaps
iputc(1);
// Low resolution image format - @TODO: Create low resolution image.
SaveLittleUInt(0xFFFFFFFF);
// Low resolution image width and height
iputc(0);
iputc(0);
// Depth of the image - @TODO: Support for volumetric images.
SaveLittleUShort(1);
// Write final padding for the header (out to 80 bytes).
for (i = 0; i < 15; i++) {
iputc(0);
}
if (Compression == IL_DXT_NO_COMP) {
// We just write the image data directly.
if (iwrite(TempImage->Data, TempImage->SizeOfData, 1) != 1)
return IL_FALSE;
}
else { // Do DXT compression here and write.
// We have to find out how much we are writing first.
CompSize = ilGetDXTCData(NULL, 0, Compression);
if (CompSize == 0) {
ilSetError(IL_INTERNAL_ERROR);
if (TempData != TempImage->Data)
ifree(TempData);
return IL_FALSE;
}
CompData = (ILubyte*)ialloc(CompSize);
if (CompData == NULL) {
if (TempData != TempImage->Data)
ifree(TempData);
return IL_FALSE;
}
// DXT compress the data.
CompSize = ilGetDXTCData(CompData, CompSize, Compression);
if (CompSize == 0) {
ilSetError(IL_INTERNAL_ERROR);
if (TempData != TempImage->Data)
ifree(TempData);
return IL_FALSE;
}
// Finally write the data.
if (iwrite(CompData, CompSize, 1) != 1) {
ifree(CompData);
if (TempData != TempImage->Data)
ifree(TempData);
return IL_FALSE;
}
}
if (TempData != TempImage->Data)
ifree(TempData);
if (TempImage != iCurImage)
ilCloseImage(TempImage);
return IL_TRUE;
}
#endif//IL_NO_VTF
+169
View File
@@ -0,0 +1,169 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_wal.c
//
// Description: Loads a Quake .wal texture.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_WAL
#include "il_manip.h"
#include "il_q2pal.h"
typedef struct WALHEAD
{
ILbyte FileName[32]; // Image name
ILuint Width; // Width of first image
ILuint Height; // Height of first image
ILuint Offsets[4]; // Offsets to image data
ILbyte AnimName[32]; // Name of next frame
ILuint Flags; // ??
ILuint Contents; // ??
ILuint Value; // ??
} WALHEAD;
ILboolean iLoadWalInternal(void);
//! Reads a .wal file
ILboolean ilLoadWal(ILconst_string FileName)
{
ILHANDLE WalFile;
ILboolean bWal = IL_FALSE;
WalFile = iopenr(FileName);
if (WalFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bWal;
}
bWal = ilLoadWalF(WalFile);
icloser(WalFile);
return bWal;
}
//! Reads an already-opened .wal file
ILboolean ilLoadWalF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadWalInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .wal file
ILboolean ilLoadWalL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadWalInternal();
}
ILboolean iLoadWalInternal()
{
WALHEAD Header;
ILimage *Mipmaps[3], *CurImage;
ILuint i, NewW, NewH;
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
CurImage = iCurImage;
// Read header
iread(&Header.FileName, 1, 32);
Header.Width = GetLittleUInt();
Header.Height = GetLittleUInt();
for (i = 0; i < 4; i++)
Header.Offsets[i] = GetLittleUInt();
iread(Header.AnimName, 1, 32);
Header.Flags = GetLittleUInt();
Header.Contents = GetLittleUInt();
Header.Value = GetLittleUInt();
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
for (i = 0; i < 3; i++) {
Mipmaps[i] = (ILimage*)icalloc(sizeof(ILimage), 1);
if (Mipmaps[i] == NULL)
goto cleanup_error;
Mipmaps[i]->Pal.Palette = (ILubyte*)ialloc(768);
if (Mipmaps[i]->Pal.Palette == NULL)
goto cleanup_error;
memcpy(Mipmaps[i]->Pal.Palette, ilDefaultQ2Pal, 768);
Mipmaps[i]->Pal.PalType = IL_PAL_RGB24;
}
NewW = Header.Width;
NewH = Header.Height;
for (i = 0; i < 3; i++) {
NewW /= 2;
NewH /= 2;
iCurImage = Mipmaps[i];
if (!ilTexImage(NewW, NewH, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
goto cleanup_error;
// Don't set until now so ilTexImage won't get rid of the palette.
Mipmaps[i]->Pal.PalSize = 768;
Mipmaps[i]->Origin = IL_ORIGIN_UPPER_LEFT;
}
iCurImage = CurImage;
ilCloseImage(iCurImage->Mipmaps);
iCurImage->Mipmaps = Mipmaps[0];
Mipmaps[0]->Mipmaps = Mipmaps[1];
Mipmaps[1]->Mipmaps = Mipmaps[2];
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE)
ifree(iCurImage->Pal.Palette);
iCurImage->Pal.Palette = (ILubyte*)ialloc(768);
if (iCurImage->Pal.Palette == NULL)
goto cleanup_error;
iCurImage->Pal.PalSize = 768;
iCurImage->Pal.PalType = IL_PAL_RGB24;
memcpy(iCurImage->Pal.Palette, ilDefaultQ2Pal, 768);
iseek(Header.Offsets[0], IL_SEEK_SET);
if (iread(iCurImage->Data, Header.Width * Header.Height, 1) != 1)
goto cleanup_error;
for (i = 0; i < 3; i++) {
iseek(Header.Offsets[i+1], IL_SEEK_SET);
if (iread(Mipmaps[i]->Data, Mipmaps[i]->Width * Mipmaps[i]->Height, 1) != 1)
goto cleanup_error;
}
// Fixes all images, even mipmaps.
return ilFixImage();
cleanup_error:
for (i = 0; i < 3; i++) {
ilCloseImage(Mipmaps[i]);
}
return IL_FALSE;
}
#endif//IL_NO_WAL
+274
View File
@@ -0,0 +1,274 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 03/07/2009
//
// Filename: src-IL/src/il_wbmp.c
//
// Description: Reads from a Wireless Bitmap (.wbmp) file. Specs available from
// http://www.ibm.com/developerworks/wireless/library/wi-wbmp/
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_WBMP
#include "il_bits.h"
ILboolean iLoadWbmpInternal(void);
ILuint WbmpGetMultibyte(void);
ILboolean iSaveWbmpInternal(void);
// Reads a .wbmp file
ILboolean ilLoadWbmp(ILconst_string FileName)
{
ILHANDLE WbmpFile;
ILboolean bWbmp = IL_FALSE;
WbmpFile = iopenr(FileName);
if (WbmpFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bWbmp;
}
iSetInputFile(WbmpFile);
bWbmp = ilLoadWbmpF(WbmpFile);
icloser(WbmpFile);
return bWbmp;
}
//! Reads an already-opened .wbmp file
ILboolean ilLoadWbmpF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadWbmpInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a .wbmp
ILboolean ilLoadWbmpL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadWbmpInternal();
}
ILboolean iLoadWbmpInternal(void)
{
ILuint Width, Height, BitPadding, i;
BITFILE *File;
ILubyte Padding[8];
if (iCurImage == NULL) {
ilSetError(IL_ILLEGAL_OPERATION);
return IL_FALSE;
}
if (igetc() != 0 || igetc() != 0) { // The first two bytes have to be 0 (the "header")
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
Width = WbmpGetMultibyte(); // Next follows the width and height.
Height = WbmpGetMultibyte();
if (Width == 0 || Height == 0) { // Must have at least some height and width.
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
if (!ilTexImage(Width, Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
return IL_FALSE;
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; // Always has origin in the upper left.
BitPadding = (8 - (Width % 8)) % 8; // Has to be aligned on a byte boundary. The rest is padding.
File = bfile(iGetFile());
if (File == NULL)
return IL_FALSE; //@TODO: Error?
//@TODO: Do this without bread? Would be faster, since we would not have to do
// the second loop.
// Reads the bits
for (i = 0; i < iCurImage->Height; i++) {
bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
//bseek(File, BitPadding, IL_SEEK_CUR); //@TODO: This function does not work correctly.
bread(Padding, 1, BitPadding, File); // Skip padding bits.
}
// Converts bit value of 1 to white and leaves 0 at 0 (2-colour images only).
for (i = 0; i < iCurImage->SizeOfData; i++) {
if (iCurImage->Data[i] == 1)
iCurImage->Data[i] = 0xFF; // White
}
bclose(File);
return IL_TRUE;
}
ILuint WbmpGetMultibyte()
{
ILuint Val = 0, i;
ILubyte Cur;
for (i = 0; i < 5; i++) { // Should not be more than 5 bytes.
Cur = igetc();
Val = (Val << 7) | (Cur & 0x7F); // Drop the MSB of Cur.
if (!(Cur & 0x80)) { // Check the MSB and break if 0.
break;
}
}
return Val;
}
ILboolean WbmpPutMultibyte(ILuint Val)
{
ILint i, NumBytes = 0;
ILuint MultiVal = Val;
do {
MultiVal >>= 7;
NumBytes++;
} while (MultiVal != 0);
for (i = NumBytes - 1; i >= 0; i--) {
MultiVal = (Val >> (i * 7)) & 0x7F;
if (i != 0)
MultiVal |= 0x80;
iputc(MultiVal);
}
return IL_TRUE;
}
//! Writes a Wbmp file
ILboolean ilSaveWbmp(const ILstring FileName)
{
ILHANDLE WbmpFile;
ILuint WbmpSize;
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
if (iFileExists(FileName)) {
ilSetError(IL_FILE_ALREADY_EXISTS);
return IL_FALSE;
}
}
WbmpFile = iopenw(FileName);
if (WbmpFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return IL_FALSE;
}
WbmpSize = ilSaveWbmpF(WbmpFile);
iclosew(WbmpFile);
if (WbmpSize == 0)
return IL_FALSE;
return IL_TRUE;
}
//! Writes a .wbmp to an already-opened file
ILuint ilSaveWbmpF(ILHANDLE File)
{
ILuint Pos;
iSetOutputFile(File);
Pos = itellw();
if (iSaveWbmpInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
//! Writes a .wbmp to a memory "lump"
ILuint ilSaveWbmpL(void *Lump, ILuint Size)
{
ILuint Pos;
iSetOutputLump(Lump, Size);
Pos = itellw();
if (iSaveWbmpInternal() == IL_FALSE)
return 0; // Error occurred
return itellw() - Pos; // Return the number of bytes written.
}
// In il_quantizer.c
ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols);
// In il_neuquant.c
ILimage *iNeuQuant(ILimage *Image, ILuint NumCols);
// Internal function used to save the Wbmp.
ILboolean iSaveWbmpInternal()
{
ILimage *TempImage = NULL;
ILuint i, j;
ILint k;
ILubyte Val;
ILubyte *TempData;
iputc(0); // First two header values
iputc(0); // must be 0.
WbmpPutMultibyte(iCurImage->Width); // Write the width
WbmpPutMultibyte(iCurImage->Height); // and the height.
//TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
if (iGetInt(IL_QUANTIZATION_MODE) == IL_NEU_QUANT)
TempImage = iNeuQuant(iCurImage, 2);
else // Assume IL_WU_QUANT otherwise.
TempImage = iQuantizeImage(iCurImage, 2);
if (TempImage == NULL)
return IL_FALSE;
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
TempData = iGetFlipped(TempImage);
if (TempData == NULL) {
ilCloseImage(TempImage);
return IL_FALSE;
}
} else {
TempData = TempImage->Data;
}
for (i = 0; i < TempImage->Height; i++) {
for (j = 0; j < TempImage->Width; j += 8) {
Val = 0;
for (k = 0; k < 8; k++) {
if (j + k < TempImage->Width) {
//Val |= ((TempData[TempImage->Width * i + j + k] > 0x7F) ? (0x80 >> k) : 0x00);
Val |= ((TempData[TempImage->Width * i + j + k] == 1) ? (0x80 >> k) : 0x00);
}
}
iputc(Val);
}
}
if (TempData != TempImage->Data)
ifree(TempData);
ilCloseImage(TempImage);
return IL_TRUE;
}
#endif//IL_NO_WBMP
+429
View File
@@ -0,0 +1,429 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Last modified: 02/09/2009
//
// Filename: src-IL/src/il_wdp.c
//
// Description: Reads a Microsoft HD Photo (.wdp or .hdp)
// Based very much on the Microsoft HD Photo Device Porting Kit 1.0
// available at
// http://www.microsoft.com/downloads/details.aspx?FamilyID=285eeffd-d86c-48c3-ab93-3abd5ee7f1ce&displaylang=en.
//
// Note: The license that the Device Porting Kit is under is not very clear.
// Commentary on the license can be found at http://en.wikipedia.org/wiki/HD_Photo.
// Lots of this code is taken from the examples in the DPK and from code
// within the DPK itself. For this reason, this file is not under the LGPL
// license, unlike the rest of DevIL.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_WDP
#include <WMPGlue.h>
#include "il_wdp.h"
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifndef _DEBUG
#pragma comment(lib, "wmplib.lib")
#else
#pragma comment(lib, "wmplib-d.lib")
#endif
#endif
#endif
//! Reads a WDP file
ILboolean ilLoadWdp(ILconst_string FileName)
{
ILHANDLE WdpFile;
ILboolean bWdp = IL_FALSE;
WdpFile = iopenr(FileName);
if (WdpFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bWdp;
}
bWdp = ilLoadWdpF(WdpFile);
icloser(WdpFile);
return bWdp;
}
//! Reads an already-opened WDP file
ILboolean ilLoadWdpF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadWdpInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains a WDP
ILboolean ilLoadWdpL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadWdpInternal();
}
//@TODO: Put in ilPKImageEncode_WritePixels_DevIL?
ERR WriteDevILHeader(PKImageEncode* pIE)
{
struct WMPStream* pS = pIE->pStream;
if (IsEqualGUID(&GUID_PKPixelFormat24bppRGB, &pIE->guidPixFormat) || IsEqualGUID(&GUID_PKPixelFormat24bppBGR, &pIE->guidPixFormat))
{
pIE->cbPixel = 3;
}
else if (IsEqualGUID(&GUID_PKPixelFormat32bppBGRA, &pIE->guidPixFormat)
|| IsEqualGUID(&GUID_PKPixelFormat32bppBGR, &pIE->guidPixFormat)
|| IsEqualGUID(&GUID_PKPixelFormat32bppPBGRA, &pIE->guidPixFormat))
{
pIE->cbPixel = 4;
}
else if (IsEqualGUID(&GUID_PKPixelFormat8bppGray, &pIE->guidPixFormat))
{
pIE->cbPixel = 1;
}
else if (IsEqualGUID(&GUID_PKPixelFormat16bppGray, &pIE->guidPixFormat))
{
pIE->cbPixel = 2;
}
else if (IsEqualGUID(&GUID_PKPixelFormat128bppRGBAFloat, &pIE->guidPixFormat))
{
pIE->cbPixel = 16;//4;
}
pIE->offPixel = pIE->offStart;
pIE->fHeaderDone = !IL_FALSE;
return WMP_errSuccess;
}
ERR ilPKImageEncode_WritePixels_DevIL(PKImageEncode* pIE, U32 cLine, U8* pbPixel, U32 cbStride)
{
ERR err = WMP_errSuccess;
struct WMPStream* pS = pIE->pStream;
size_t cbLineM = 0, cbLineS = 0;
I32 i = 0;
static U8 pPadding[4] = {0};
// header
if (!pIE->fHeaderDone)
{
// WriteBMPHeader() also inits this object
Call(WriteDevILHeader(pIE));
}
// body
// calculate line size in memory and in stream
cbLineM = pIE->cbPixel * pIE->uWidth;
cbLineS = (cbLineM + 3) / 4 * 4;
//FailIf(pRect->X < 0 || pID->uWidth <= pRect->X, WMP_errInvalidParameter);
//FailIf(pRect->Y < 0 || pID->uHeight <= pRect->Y, WMP_errInvalidParameter);
//FailIf(pRect->Width < 0 || pID->uWidth < pRect->X + pRect->Width, WMP_errInvalidParameter);
//FailIf(pRect->Height < 0 || pID->uHeight < pRect->Y + pRect->Height, WMP_errInvalidParameter);
FailIf(cbStride < cbLineM, WMP_errInvalidParameter);
for (i = cLine - 1; 0 <= i; --i)
{
size_t offM = cbStride * i;
size_t offS = cbLineS * (pIE->uHeight - (pIE->idxCurrentLine + i + 1));
Call(pS->SetPos(pS, pIE->offPixel + offS));
Call(pS->Write(pS, pbPixel + offM, cbLineM));
}
Call(pS->Write(pS, pPadding, (cbLineS - cbLineM)));
pIE->idxCurrentLine += cLine;
Cleanup:
return err;
}
ERR PKImageEncode_Create_DevIL(
PKImageEncode** ppIE)
{
ERR err = WMP_errSuccess;
PKImageEncode* pIE = NULL;
Call(PKImageEncode_Create(ppIE));
pIE = *ppIE;
pIE->WritePixels = ilPKImageEncode_WritePixels_DevIL;
Cleanup:
return err;
}
ERR iWmpDecAppCreateEncoderFromExt(
PKCodecFactory* pCFactory,
const char* szExt,
PKImageEncode** ppIE)
{
ERR err = WMP_errSuccess;
const PKIID* pIID = NULL;
// get encod PKIID
Call(GetImageEncodeIID(szExt, &pIID));
// Create encoder
//Call(PKCodecFactory_CreateCodec(pIID, ppIE));
Call(PKImageEncode_Create_DevIL(ppIE));
Cleanup:
return err;
}
ERR iCloseWS_File(struct WMPStream** ppWS)
{
ERR err = WMP_errSuccess;
/*struct WMPStream* pWS = *ppWS;
fclose(pWS->state.file.pFile);
Call(WMPFree((void**)ppWS));
Cleanup:*/
return err;
}
Bool iEOSWS_File(struct WMPStream* pWS)
{
//return feof(pWS->state.file.pFile);
return ieof();
}
ERR iReadWS_File(struct WMPStream* pWS, void* pv, size_t cb)
{
// For some reason, the WDP images load just fine, but it tries to read too much,
// so IL_FILE_READ_ERROR is set. So we get rid of the error.
if (iread(pv, 1, (ILuint)cb) != cb)
ilGetError();
return WMP_errSuccess;
}
ERR iWriteWS_File(struct WMPStream* pWS, const void* pv, size_t cb)
{
ERR err = WMP_errSuccess;
if (0 != cb) {
FailIf(1 != iwrite(pv, (ILuint)cb, 1), WMP_errFileIO);
}
Cleanup:
return err;
}
ERR iSetPosWS_File(struct WMPStream* pWS, size_t offPos)
{
ERR err = WMP_errSuccess;
//FailIf(0 != fseek(pWS->state.file.pFile, (long)offPos, SEEK_SET), WMP_errFileIO);
FailIf(0 != iseek((ILuint)offPos, IL_SEEK_SET), WMP_errFileIO);
Cleanup:
return err;
}
ERR iGetPosWS_File(struct WMPStream* pWS, size_t* poffPos)
{
ERR err = WMP_errSuccess;
long lOff = 0;
//FailIf(-1 == (lOff = ftell(pWS->state.file.pFile)), WMP_errFileIO);
lOff = itell();
*poffPos = (size_t)lOff;
Cleanup:
return err;
}
ERR ilCreateWS_File(struct WMPStream** ppWS, const char* szFilename, const char* szMode)
{
ERR err = WMP_errSuccess;
struct WMPStream* pWS = NULL;
*ppWS = icalloc(1, sizeof(**ppWS));
if (*ppWS == NULL)
return WMP_errOutOfMemory;
pWS = *ppWS;
pWS->Close = iCloseWS_File;
pWS->EOS = iEOSWS_File;
pWS->Read = iReadWS_File;
pWS->Write = iWriteWS_File;
//pWS->GetLine = GetLineWS_File;
pWS->SetPos = iSetPosWS_File;
pWS->GetPos = iGetPosWS_File;
//pWS->state.file.pFile = fopen(szFilename, szMode);
pWS->state.file.pFile = NULL;
//FailIf(NULL == pWS->state.file.pFile, WMP_errFileIO);
Cleanup:
return err;
}
ERR ilPKCodecFactory_CreateDecoderFromFile(PKImageDecode** ppDecoder)
{
ERR err = WMP_errSuccess;
char *pExt = ".wdp"; // We are loading a WDP file, so we have to tell the library that with this extension.
PKIID* pIID = NULL;
struct WMPStream* pStream = NULL;
PKImageDecode* pDecoder = NULL;
// get decode PKIID
Call(GetImageDecodeIID(pExt, &pIID));
// create stream
Call(ilCreateWS_File(&pStream, NULL, "rb"));
// Create decoder
Call(PKCodecFactory_CreateCodec(pIID, ppDecoder));
pDecoder = *ppDecoder;
// attach stream to decoder
Call(pDecoder->Initialize(pDecoder, pStream));
pDecoder->fStreamOwner = !0;
Cleanup:
return err;
}
ERR ilPKCreateFactory(PKFactory** ppFactory, U32 uVersion)
{
ERR err = WMP_errSuccess;
PKFactory* pFactory = NULL;
Call(PKAlloc(ppFactory, sizeof(**ppFactory)));
pFactory = *ppFactory;
pFactory->CreateStream = PKCreateFactory_CreateStream;
pFactory->CreateStreamFromFilename = ilCreateWS_File;
pFactory->CreateStreamFromMemory = CreateWS_Memory;
pFactory->Release = PKCreateFactory_Release;
Cleanup:
return err;
}
ILboolean iLoadWdpInternal(/*ILconst_string FileName*/)
{
ERR err = WMP_errSuccess;
PKFactory* pFactory = NULL;
PKCodecFactory* pCodecFactory = NULL;
PKImageDecode* pDecoder = NULL;
PKPixelInfo PI;
PKPixelFormatGUID guidPixFormat;
PKFormatConverter* pConverter = NULL;
U32 cFrame = 0, i = 0;
PKRect Rect;
struct WMPStream* pEncodeStream = NULL;
PKImageEncode* pEncoder = NULL;
//Call(PKCreateFactory(&pFactory, PK_SDK_VERSION));
//Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
//Call(pCodecFactory->CreateDecoderFromFile(FileName, &pDecoder));
Call(ilPKCreateFactory(&pFactory, PK_SDK_VERSION));
Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
Call(ilPKCodecFactory_CreateDecoderFromFile(&pDecoder));
//guidPixFormat = GUID_PKPixelFormat24bppRGB;
guidPixFormat = GUID_PKPixelFormat32bppBGRA;
//guidPixFormat = GUID_PKPixelFormat8bppGray;
//guidPixFormat = GUID_PKPixelFormat16bppGray;
// Color transcoding
if (IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat16bppGray)){ // ** => Y transcoding
pDecoder->guidPixFormat = guidPixFormat;
pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY;
}
else if(IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK){ // CMYK = > RGB
pDecoder->WMP.wmiI.cfColorFormat = CF_RGB;
pDecoder->guidPixFormat = guidPixFormat;
pDecoder->WMP.wmiI.bRGB = 1; //RGB
}
PI.pGUIDPixFmt = &guidPixFormat;
PixelFormatLookup(&PI, LOOKUP_FORWARD);
pDecoder->WMP.wmiSCP.bfBitstreamFormat = 0;
pDecoder->WMP.wmiSCP.uAlphaMode = 0;
pDecoder->WMP.wmiSCP.sbSubband = SB_ALL;
pDecoder->WMP.bIgnoreOverlap = FALSE;
pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat;
pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth;
pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
//==== Validate thumbnail decode parameters =====
pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth;
pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight;
pDecoder->WMP.wmiI.bSkipFlexbits = FALSE;
pCodecFactory->CreateFormatConverter(&pConverter);
pConverter->Initialize(pConverter, pDecoder, NULL, guidPixFormat);
// Right now, we are just assuming one frame.
// @TODO: Deal with multiple frames.
//pDecoder->GetFrameCount(pDecoder, &cFrame);
//pDecoder->SelectFrame(pDecoder, 1);
if (!ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
goto Cleanup;
//ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, Data);
pFactory->CreateStreamFromMemory(&pEncodeStream, iCurImage->Data, iCurImage->SizeOfData);
iWmpDecAppCreateEncoderFromExt(pCodecFactory, ".wdp", &pEncoder);
pEncoder->Initialize(pEncoder, pEncodeStream, ".wdp", 0);
pEncoder->pStream->GetPos(pEncoder->pStream, &pEncoder->offStart);
// Set the region that we want to be the whole image.
Rect.X = 0; Rect.Y = 0; Rect.Height = pDecoder->uHeight; Rect.Width = pDecoder->uWidth;
pEncoder->SetPixelFormat(pEncoder, guidPixFormat);
pEncoder->SetSize(pEncoder, Rect.Width, Rect.Height);
pEncoder->WriteSource = PKImageEncode_Transcode;
pEncoder->WriteSource(pEncoder, pConverter, &Rect);
Cleanup:
// Release everything all at the end.
PKImageDecode_Release(&pDecoder);
if (pEncoder)
PKImageEncode_Release(&pEncoder);
PKCreateCodecFactory_Release(&pCodecFactory);
PKCreateFactory_Release(&pFactory);
PKFormatConverter_Release(&pConverter);
if (err != WMP_errSuccess)
return IL_FALSE;
return IL_TRUE;
}
#endif//IL_NO_WDP
+655
View File
@@ -0,0 +1,655 @@
//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2009 by Denton Woods
// Last modified: 01/04/2009
//
// Filename: src-IL/src/il_xpm.c
//
// Description: Reads from an .xpm file.
//
//-----------------------------------------------------------------------------
#include "il_internal.h"
#ifndef IL_NO_XPM
#include <ctype.h>
//If this is defined, only xpm files with 1 char/pixel
//can be loaded. They load somewhat faster then, though
//(not much).
//#define XPM_DONT_USE_HASHTABLE
ILboolean iIsValidXpm(void);
ILboolean iLoadXpmInternal(void);
ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen);
//! Checks if the file specified in FileName is a valid XPM file.
ILboolean ilIsValidXpm(ILconst_string FileName)
{
ILHANDLE XpmFile;
ILboolean bXpm = IL_FALSE;
if (!iCheckExtension(FileName, IL_TEXT("xpm"))) {
ilSetError(IL_INVALID_EXTENSION);
return bXpm;
}
XpmFile = iopenr(FileName);
if (XpmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bXpm;
}
bXpm = ilIsValidXpmF(XpmFile);
icloser(XpmFile);
return bXpm;
}
//! Checks if the ILHANDLE contains a valid XPM file at the current position.
ILboolean ilIsValidXpmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iIsValidXpm();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Checks if Lump is a valid XPM lump.
ILboolean ilIsValidXpmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iIsValidXpm();
}
// Internal function to get the header and check it.
ILboolean iIsValidXpm(void)
{
ILubyte Buffer[10];
ILuint Pos = itell();
XpmGetsInternal(Buffer, 10);
iseek(Pos, IL_SEEK_SET); // Restore position
if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */")))
return IL_FALSE;
return IL_TRUE;
}
// Reads an .xpm file
ILboolean ilLoadXpm(ILconst_string FileName)
{
ILHANDLE XpmFile;
ILboolean bXpm = IL_FALSE;
XpmFile = iopenr(FileName);
if (XpmFile == NULL) {
ilSetError(IL_COULD_NOT_OPEN_FILE);
return bXpm;
}
iSetInputFile(XpmFile);
bXpm = ilLoadXpmF(XpmFile);
icloser(XpmFile);
return bXpm;
}
//! Reads an already-opened .xpm file
ILboolean ilLoadXpmF(ILHANDLE File)
{
ILuint FirstPos;
ILboolean bRet;
iSetInputFile(File);
FirstPos = itell();
bRet = iLoadXpmInternal();
iseek(FirstPos, IL_SEEK_SET);
return bRet;
}
//! Reads from a memory "lump" that contains an .xpm
ILboolean ilLoadXpmL(const void *Lump, ILuint Size)
{
iSetInputLump(Lump, Size);
return iLoadXpmInternal();
}
typedef ILubyte XpmPixel[4];
#define XPM_MAX_CHAR_PER_PIXEL 2
#ifndef XPM_DONT_USE_HASHTABLE
//The following hash table code was inspired by the xpm
//loading code of xv, one of the best image viewers of X11
//For xpm files with more than one character/pixel, it is
//impractical to use a simple lookup table for the
//character-to-color mapping (because the table requires
//2^(chars/pixel) entries, this is quite big).
//Because of that, a hash table is used for the mapping.
//The hash table has 257 entries, and collisions are
//resolved by chaining.
//257 is the smallest prime > 256
#define XPM_HASH_LEN 257
typedef struct XPMHASHENTRY
{
ILubyte ColourName[XPM_MAX_CHAR_PER_PIXEL];
XpmPixel ColourValue;
struct XPMHASHENTRY *Next;
} XPMHASHENTRY;
static ILuint XpmHash(const ILubyte* name, int len)
{
ILint i, sum;
for (sum = i = 0; i < len; ++i)
sum += name[i];
return sum % XPM_HASH_LEN;
}
XPMHASHENTRY** XpmCreateHashTable()
{
XPMHASHENTRY** Table =
(XPMHASHENTRY**)ialloc(XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
if (Table != NULL)
memset(Table, 0, XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
return Table;
}
void XpmDestroyHashTable(XPMHASHENTRY **Table)
{
ILint i;
XPMHASHENTRY* Entry;
for (i = 0; i < XPM_HASH_LEN; ++i) {
while (Table[i] != NULL) {
Entry = Table[i]->Next;
ifree(Table[i]);
Table[i] = Entry;
}
}
ifree(Table);
}
void XpmInsertEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
{
XPMHASHENTRY* NewEntry;
ILuint Index;
Index = XpmHash(Name, Len);
NewEntry = (XPMHASHENTRY*)ialloc(sizeof(XPMHASHENTRY));
if (NewEntry != NULL) {
NewEntry->Next = Table[Index];
memcpy(NewEntry->ColourName, Name, Len);
memcpy(NewEntry->ColourValue, Colour, sizeof(Colour));
Table[Index] = NewEntry;
}
}
void XpmGetEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
{
XPMHASHENTRY* Entry;
ILuint Index;
Index = XpmHash(Name, Len);
Entry = Table[Index];
while (Entry != NULL && strncmp((char*)(Entry->ColourName), (char*)Name, Len) != 0)
Entry = Entry->Next;
if (Entry != NULL)
memcpy(Colour, Entry->ColourValue, sizeof(Colour));
}
#endif //XPM_DONT_USE_HASHTABLE
ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen)
{
ILint i = 0, Current;
if (ieof())
return IL_EOF;
while ((Current = igetc()) != IL_EOF && i < MaxLen - 1) {
if (Current == IL_EOF)
return 0;
if (Current == '\n') //unix line ending
break;
if (Current == '\r') { //dos/mac line ending
Current = igetc();
if (Current == '\n') //dos line ending
break;
if (Current == IL_EOF)
break;
Buffer[i++] = (ILubyte)Current;
continue;
}
Buffer[i++] = (ILubyte)Current;
}
Buffer[i++] = 0;
return i;
}
ILint XpmGets(ILubyte *Buffer, ILint MaxLen)
{
ILint Size, i, j;
ILboolean NotComment = IL_FALSE, InsideComment = IL_FALSE;
do {
Size = XpmGetsInternal(Buffer, MaxLen);
if (Size == IL_EOF)
return IL_EOF;
//skip leading whitespace (sometimes there's whitespace
//before a comment or before the pixel data)
for(i = 0; i < Size && isspace(Buffer[i]); ++i) ;
Size = Size - i;
for(j = 0; j < Size; ++j)
Buffer[j] = Buffer[j + i];
if (Size == 0)
continue;
if (Buffer[0] == '/' && Buffer[1] == '*') {
for (i = 2; i < Size; i++) {
if (Buffer[i] == '*' && Buffer[i+1] == '/') {
break;
}
}
if (i >= Size)
InsideComment = IL_TRUE;
}
else if (InsideComment) {
for (i = 0; i < Size; i++) {
if (Buffer[i] == '*' && Buffer[i+1] == '/') {
break;
}
}
if (i < Size)
InsideComment = IL_FALSE;
}
else {
NotComment = IL_TRUE;
}
} while (!NotComment);
return Size;
}
ILint XpmGetInt(ILubyte *Buffer, ILint Size, ILint *Position)
{
char Buff[1024];
ILint i, j;
ILboolean IsInNum = IL_FALSE;
for (i = *Position, j = 0; i < Size; i++) {
if (isdigit(Buffer[i])) {
IsInNum = IL_TRUE;
Buff[j++] = Buffer[i];
}
else {
if (IsInNum) {
Buff[j] = 0;
*Position = i;
return atoi(Buff);
}
}
}
return -1;
}
ILboolean XpmPredefCol(char *Buff, XpmPixel *Colour)
{
ILint len;
ILint val = 128;
if (!stricmp(Buff, "none")) {
(*Colour)[0] = 0;
(*Colour)[1] = 0;
(*Colour)[2] = 0;
(*Colour)[3] = 0;
return IL_TRUE;
}
(*Colour)[3] = 255;
if (!stricmp(Buff, "black")) {
(*Colour)[0] = 0;
(*Colour)[1] = 0;
(*Colour)[2] = 0;
return IL_TRUE;
}
if (!stricmp(Buff, "white")) {
(*Colour)[0] = 255;
(*Colour)[1] = 255;
(*Colour)[2] = 255;
return IL_TRUE;
}
if (!stricmp(Buff, "red")) {
(*Colour)[0] = 255;
(*Colour)[1] = 0;
(*Colour)[2] = 0;
return IL_TRUE;
}
if (!stricmp(Buff, "green")) {
(*Colour)[0] = 0;
(*Colour)[1] = 255;
(*Colour)[2] = 0;
return IL_TRUE;
}
if (!stricmp(Buff, "blue")) {
(*Colour)[0] = 0;
(*Colour)[1] = 0;
(*Colour)[2] = 255;
return IL_TRUE;
}
if (!stricmp(Buff, "yellow")) {
(*Colour)[0] = 255;
(*Colour)[1] = 255;
(*Colour)[2] = 0;
return IL_TRUE;
}
if (!stricmp(Buff, "cyan")) {
(*Colour)[0] = 0;
(*Colour)[1] = 255;
(*Colour)[2] = 255;
return IL_TRUE;
}
if (!stricmp(Buff, "gray")) {
(*Colour)[0] = 128;
(*Colour)[1] = 128;
(*Colour)[2] = 128;
return IL_TRUE;
}
//check for grayXXX codes (added 20040218)
len = ilCharStrLen(Buff);
if (len >= 4) {
if (Buff[0] == 'g' || Buff[0] == 'G'
|| Buff[1] == 'r' || Buff[1] == 'R'
|| Buff[2] == 'a' || Buff[2] == 'A'
|| Buff[3] == 'y' || Buff[3] == 'Y') {
if (isdigit(Buff[4])) { // isdigit returns false on '\0'
val = Buff[4] - '0';
if (isdigit(Buff[5])) {
val = val*10 + Buff[5] - '0';
if (isdigit(Buff[6]))
val = val*10 + Buff[6] - '0';
}
val = (255*val)/100;
}
(*Colour)[0] = (ILubyte)val;
(*Colour)[1] = (ILubyte)val;
(*Colour)[2] = (ILubyte)val;
return IL_TRUE;
}
}
// Unknown colour string, so use black
// (changed 20040218)
(*Colour)[0] = 0;
(*Colour)[1] = 0;
(*Colour)[2] = 0;
return IL_FALSE;
}
#ifndef XPM_DONT_USE_HASHTABLE
ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XPMHASHENTRY **Table)
#else
ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XpmPixel* Colours)
#endif
{
ILint i = 0, j, strLen = 0;
ILubyte ColBuff[3];
char Buff[1024];
XpmPixel Colour;
ILubyte Name[XPM_MAX_CHAR_PER_PIXEL];
for ( ; i < Size; i++) {
if (Buffer[i] == '\"')
break;
}
i++; // Skip the quotes.
if (i >= Size)
return IL_FALSE;
// Get the characters.
for (j = 0; j < Len; ++j) {
Name[j] = Buffer[i++];
}
// Skip to the colour definition.
for ( ; i < Size; i++) {
if (Buffer[i] == 'c')
break;
}
i++; // Skip the 'c'.
if (i >= Size || Buffer[i] != ' ') { // no 'c' found...assume black
#ifndef XPM_DONT_USE_HASHTABLE
memset(Colour, 0, sizeof(Colour));
Colour[3] = 255;
XpmInsertEntry(Table, Name, Len, Colour);
#else
memset(Colours[Name[0]], 0, sizeof(Colour));
Colours[Name[0]][3] = 255;
#endif
return IL_TRUE;
}
for ( ; i < Size; i++) {
if (Buffer[i] != ' ')
break;
}
if (i >= Size)
return IL_FALSE;
if (Buffer[i] == '#') {
// colour string may 4 digits/color or 1 digit/color
// (added 20040218) TODO: is isxdigit() ANSI???
++i;
while (i + strLen < Size && isxdigit(Buffer[i + strLen]))
++strLen;
for (j = 0; j < 3; j++) {
if (strLen >= 10) { // 4 digits
ColBuff[0] = Buffer[i + j*4];
ColBuff[1] = Buffer[i + j*4 + 1];
}
else if (strLen >= 8) { // 3 digits
ColBuff[0] = Buffer[i + j*3];
ColBuff[1] = Buffer[i + j*3 + 1];
}
else if (strLen >= 6) { // 2 digits
ColBuff[0] = Buffer[i + j*2];
ColBuff[1] = Buffer[i + j*2 + 1];
}
else if(j < strLen) { // 1 digit, strLen >= 1
ColBuff[0] = Buffer[i + j];
ColBuff[1] = 0;
}
ColBuff[2] = 0; // add terminating '\0' char
Colour[j] = (ILubyte)strtol((char*)ColBuff, NULL, 16);
}
Colour[3] = 255; // Full alpha.
}
else {
for (j = 0; i < Size; i++) {
if (!isalnum(Buffer[i]))
break;
Buff[j++] = Buffer[i];
}
Buff[j] = 0;
if (i >= Size)
return IL_FALSE;
if (!XpmPredefCol(Buff, &Colour))
return IL_FALSE;
}
#ifndef XPM_DONT_USE_HASHTABLE
XpmInsertEntry(Table, Name, Len, Colour);
#else
memcpy(Colours[Name[0]], Colour, sizeof(Colour));
#endif
return IL_TRUE;
}
ILboolean iLoadXpmInternal()
{
#define BUFFER_SIZE 2000
ILubyte Buffer[BUFFER_SIZE], *Data;
ILint Size, Pos, Width, Height, NumColours, i, x, y;
ILint CharsPerPixel;
#ifndef XPM_DONT_USE_HASHTABLE
XPMHASHENTRY **HashTable;
#else
XpmPixel *Colours;
ILint Offset;
#endif
Size = XpmGetsInternal(Buffer, BUFFER_SIZE);
if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */"))) {
ilSetError(IL_INVALID_FILE_HEADER);
return IL_FALSE;
}
Size = XpmGets(Buffer, BUFFER_SIZE);
// @TODO: Actually check the variable name here.
Size = XpmGets(Buffer, BUFFER_SIZE);
Pos = 0;
Width = XpmGetInt(Buffer, Size, &Pos);
Height = XpmGetInt(Buffer, Size, &Pos);
NumColours = XpmGetInt(Buffer, Size, &Pos);
CharsPerPixel = XpmGetInt(Buffer, Size, &Pos);
#ifdef XPM_DONT_USE_HASHTABLE
if (CharsPerPixel != 1) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
#endif
if (CharsPerPixel > XPM_MAX_CHAR_PER_PIXEL
|| Width*CharsPerPixel > BUFFER_SIZE) {
ilSetError(IL_FORMAT_NOT_SUPPORTED);
return IL_FALSE;
}
#ifndef XPM_DONT_USE_HASHTABLE
HashTable = XpmCreateHashTable();
if (HashTable == NULL)
return IL_FALSE;
#else
Colours = ialloc(256 * sizeof(XpmPixel));
if (Colours == NULL)
return IL_FALSE;
#endif
for (i = 0; i < NumColours; i++) {
Size = XpmGets(Buffer, BUFFER_SIZE);
#ifndef XPM_DONT_USE_HASHTABLE
if (!XpmGetColour(Buffer, Size, CharsPerPixel, HashTable)) {
XpmDestroyHashTable(HashTable);
#else
if (!XpmGetColour(Buffer, Size, CharsPerPixel, Colours)) {
ifree(Colours);
#endif
return IL_FALSE;
}
}
if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
#ifndef XPM_DONT_USE_HASHTABLE
XpmDestroyHashTable(HashTable);
#else
ifree(Colours);
#endif
return IL_FALSE;
}
Data = iCurImage->Data;
for (y = 0; y < Height; y++) {
Size = XpmGets(Buffer, BUFFER_SIZE);
for (x = 0; x < Width; x++) {
#ifndef XPM_DONT_USE_HASHTABLE
XpmGetEntry(HashTable, &Buffer[1 + x*CharsPerPixel], CharsPerPixel, &Data[(x << 2)]);
#else
Offset = (x << 2);
Data[Offset + 0] = Colours[Buffer[x + 1]][0];
Data[Offset + 1] = Colours[Buffer[x + 1]][1];
Data[Offset + 2] = Colours[Buffer[x + 1]][2];
Data[Offset + 3] = Colours[Buffer[x + 1]][3];
#endif
}
Data += iCurImage->Bps;
}
//added 20040218
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
#ifndef XPM_DONT_USE_HASHTABLE
XpmDestroyHashTable(HashTable);
#else
ifree(Colours);
#endif
return IL_TRUE;
#undef BUFFER_SIZE
}
#endif//IL_NO_XPM