Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginSGI.cpp view on Meta::CPAN
static const char * DLL_CALLCONV
Format() {
return "SGI";
}
static const char * DLL_CALLCONV
Description() {
return "SGI Image Format";
}
static const char * DLL_CALLCONV
Extension() {
return "sgi,rgb,rgba,bw";
}
static const char * DLL_CALLCONV
RegExpr() {
return NULL;
}
static const char * DLL_CALLCONV
MimeType() {
return "image/x-sgi";
}
static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {
BYTE sgi_signature[2] = { 0x01, 0xDA };
BYTE signature[2] = { 0, 0 };
io->read_proc(signature, 1, sizeof(sgi_signature), handle);
return (memcmp(sgi_signature, signature, sizeof(sgi_signature)) == 0);
}
static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
return FALSE;
}
static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type) {
return FALSE;
}
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
int width = 0, height = 0, zsize = 0;
int i, dim;
int bitcount;
SGIHeader sgiHeader;
RLEStatus my_rle_status;
FIBITMAP *dib = NULL;
LONG *pRowIndex = NULL;
try {
// read the header
memset(&sgiHeader, 0, sizeof(SGIHeader));
if(io->read_proc(&sgiHeader, 1, sizeof(SGIHeader), handle) < sizeof(SGIHeader)) {
throw SGI_LESS_THAN_HEADER_LENGTH;
}
#ifndef FREEIMAGE_BIGENDIAN
SwapHeader(&sgiHeader);
#endif
if(sgiHeader.magic != 474) {
throw FI_MSG_ERROR_MAGIC_NUMBER;
}
BOOL bIsRLE = (sgiHeader.storage == 1) ? TRUE : FALSE;
// check for unsupported image types
if (sgiHeader.bpc != 1) {
// Expected one byte per color component
throw SGI_16_BIT_COMPONENTS_NOT_SUPPORTED;
}
if (sgiHeader.colormap != 0) {
// Indexed or dithered images not supported
throw SGI_COLORMAPS_NOT_SUPPORTED;
}
// get the width & height
dim = sgiHeader.dimension;
width = sgiHeader.xsize;
if (dim < 3) {
zsize = 1;
} else {
zsize = sgiHeader.zsize;
}
if (dim < 2) {
height = 1;
} else {
height = sgiHeader.ysize;
}
if(bIsRLE) {
// read the Offset Tables
int index_len = height * zsize;
pRowIndex = (LONG*)malloc(index_len * sizeof(LONG));
if(!pRowIndex) {
throw FI_MSG_ERROR_MEMORY;
}
if ((unsigned)index_len != io->read_proc(pRowIndex, sizeof(LONG), index_len, handle)) {
throw SGI_EOF_IN_RLE_INDEX;
}
#ifndef FREEIMAGE_BIGENDIAN
// Fix byte order in index
for (i = 0; i < index_len; i++) {
SwapLong((DWORD*)&pRowIndex[i]);
}
#endif
// Discard row size index
for (i = 0; i < (int)(index_len * sizeof(LONG)); i++) {
BYTE packed = 0;
if( io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1 ) {
throw SGI_EOF_IN_RLE_INDEX;
}
}
}
switch(zsize) {
case 1:
bitcount = 8;
break;
case 2:
//Grayscale+Alpha. Need to fake RGBA
bitcount = 32;
break;
case 3:
bitcount = 24;
break;
case 4:
bitcount = 32;
break;
default:
throw SGI_INVALID_CHANNEL_COUNT;
}
dib = FreeImage_Allocate(width, height, bitcount);
if(!dib) {
throw FI_MSG_ERROR_DIB_MEMORY;
}
if (bitcount == 8) {
// 8-bit SGI files are grayscale images, so we'll generate
// a grayscale palette.
RGBQUAD *pclrs = FreeImage_GetPalette(dib);
for (i = 0; i < 256; i++) {
pclrs[i].rgbRed = (BYTE)i;
pclrs[i].rgbGreen = (BYTE)i;
pclrs[i].rgbBlue = (BYTE)i;
pclrs[i].rgbReserved = 0;
}
}
// decode the image
memset(&my_rle_status, 0, sizeof(RLEStatus));
int ns = FreeImage_GetPitch(dib);
BYTE *pStartRow = FreeImage_GetScanLine(dib, 0);
int offset_table[] = { 2, 1, 0, 3 };
int numChannels = zsize;
if (zsize < 3) {
offset_table[0] = 0;
}
if (zsize == 2)
{
//This is how faked grayscale+alpha works.
//First channel goes into first
//second channel goes into alpha (4th channel)
//Two channels are left empty and will be copied later
offset_table[1] = 3;
numChannels = 4;
}
LONG *pri = pRowIndex;
for (i = 0; i < zsize; i++) {
BYTE *pRow = pStartRow + offset_table[i];
for (int j = 0; j < height; j++, pRow += ns, pri++) {
BYTE *p = pRow;
if (bIsRLE) {
my_rle_status.cnt = 0;
io->seek_proc(handle, *pri, SEEK_SET);
}
for (int k = 0; k < width; k++, p += numChannels) {
int ch;
BYTE packed = 0;
if (bIsRLE) {
ch = get_rlechar(io, handle, &my_rle_status);
packed = (BYTE)ch;
}
else {
ch = io->read_proc(&packed, sizeof(BYTE), 1, handle);
}
if (ch == EOF) {
throw SGI_EOF_IN_IMAGE_DATA;
}
*p = packed;
}
}
}
if (zsize == 2)
{
BYTE *pRow = pStartRow;
//If faking RGBA from grayscale + alpha, copy first channel to second and third
for (int i=0; i<height; i++, pRow += ns)
{
BYTE *pPixel = pRow;
for (int j=0; j<width; j++)
{
pPixel[2] = pPixel[1] = pPixel[0];
pPixel += 4;
}
}
}
if(pRowIndex)
free(pRowIndex);
return dib;
} catch(const char *text) {
if(pRowIndex) free(pRowIndex);
if(dib) FreeImage_Unload(dib);
FreeImage_OutputMessageProc(s_format_id, text);
return NULL;
}
}
// ==========================================================
// Init
// ==========================================================
void DLL_CALLCONV
InitSGI(Plugin *plugin, int format_id) {
s_format_id = format_id;
plugin->format_proc = Format;
plugin->description_proc = Description;
plugin->extension_proc = Extension;
plugin->regexpr_proc = RegExpr;
plugin->open_proc = NULL;
plugin->close_proc = NULL;
plugin->pagecount_proc = NULL;
plugin->pagecapability_proc = NULL;
plugin->load_proc = Load;
plugin->save_proc = NULL;
plugin->validate_proc = Validate;
plugin->mime_proc = MimeType;
plugin->supports_export_bpp_proc = SupportsExportDepth;
plugin->supports_export_type_proc = SupportsExportType;
plugin->supports_icc_profiles_proc = NULL;
}
( run in 0.807 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )