summaryrefslogtreecommitdiff
path: root/plugins/FreeImage/Source/FreeImage/PluginSGI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/FreeImage/Source/FreeImage/PluginSGI.cpp')
-rw-r--r--plugins/FreeImage/Source/FreeImage/PluginSGI.cpp850
1 files changed, 425 insertions, 425 deletions
diff --git a/plugins/FreeImage/Source/FreeImage/PluginSGI.cpp b/plugins/FreeImage/Source/FreeImage/PluginSGI.cpp
index 38ac293b78..0fd162b1d4 100644
--- a/plugins/FreeImage/Source/FreeImage/PluginSGI.cpp
+++ b/plugins/FreeImage/Source/FreeImage/PluginSGI.cpp
@@ -1,425 +1,425 @@
-// ==========================================================
-// SGI Loader
-//
-// Design and implementation by
-// - Sherman Wilcox
-// - Noam Gat
-//
-// References :
-// ------------
-// - The SGI Image File Format, Version 1.0
-// http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
-// - SGI RGB Image Format
-// http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/
-//
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#include "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// Constants + headers
-// ----------------------------------------------------------
-
-#ifdef _WIN32
-#pragma pack(push, 1)
-#else
-#pragma pack(1)
-#endif
-
-typedef struct tagSGIHeader {
- /** IRIS image file magic number. This should be decimal 474. */
- WORD magic;
- /** Storage format: 0 for uncompressed, 1 for RLE compression. */
- BYTE storage;
- /** Number of bytes per pixel channel. Legally 1 or 2. */
- BYTE bpc;
- /**
- Number of dimensions. Legally 1, 2, or 3.
- 1 means a single row, XSIZE long
- 2 means a single 2D image
- 3 means multiple 2D images
- */
- WORD dimension;
- /** X size in pixels */
- WORD xsize;
- /** Y size in pixels */
- WORD ysize;
- /**
- Number of channels.
- 1 indicates greyscale
- 3 indicates RGB
- 4 indicates RGB and Alpha
- */
- WORD zsize;
- /** Minimum pixel value. This is the lowest pixel value in the image.*/
- LONG pixmin;
- /** Maximum pixel value. This is the highest pixel value in the image.*/
- LONG pixmax;
- /** Ignored. Normally set to 0. */
- char dummy[4];
- /** Image name. Must be null terminated, therefore at most 79 bytes. */
- char imagename[80];
- /**
- Colormap ID.
- 0 - normal mode
- 1 - dithered, 3 mits for red and green, 2 for blue, obsolete
- 2 - index colour, obsolete
- 3 - not an image but a colourmap
- */
- LONG colormap;
- /** Ignored. Should be set to 0, makes the header 512 bytes. */
- char reserved[404];
-} SGIHeader;
-
-typedef struct tagRLEStatus {
- int cnt;
- int val;
-} RLEStatus;
-
-#ifdef _WIN32
-#pragma pack(pop)
-#else
-#pragma pack()
-#endif
-
-static const char *SGI_LESS_THAN_HEADER_LENGTH = "Incorrect header size";
-static const char *SGI_16_BIT_COMPONENTS_NOT_SUPPORTED = "No 16 bit support";
-static const char *SGI_COLORMAPS_NOT_SUPPORTED = "No colormap support";
-static const char *SGI_EOF_IN_RLE_INDEX = "EOF in run length encoding";
-static const char *SGI_EOF_IN_IMAGE_DATA = "EOF in image data";
-static const char *SGI_INVALID_CHANNEL_COUNT = "Invalid channel count";
-
-// ==========================================================
-// Plugin Interface
-// ==========================================================
-
-static int s_format_id;
-
-// ==========================================================
-// Plugin Implementation
-// ==========================================================
-
-#ifndef FREEIMAGE_BIGENDIAN
-static void
-SwapHeader(SGIHeader *header) {
- SwapShort(&header->magic);
- SwapShort(&header->dimension);
- SwapShort(&header->xsize);
- SwapShort(&header->ysize);
- SwapShort(&header->zsize);
- SwapLong((DWORD*)&header->pixmin);
- SwapLong((DWORD*)&header->pixmax);
- SwapLong((DWORD*)&header->colormap);
-}
-#endif
-
-static int
-get_rlechar(FreeImageIO *io, fi_handle handle, RLEStatus *pstatus) {
- if (!pstatus->cnt) {
- int cnt = 0;
- while (0 == cnt) {
- BYTE packed = 0;
- if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
- return EOF;
- }
- cnt = packed;
- }
- if (cnt == EOF) {
- return EOF;
- }
- pstatus->cnt = cnt & 0x7F;
- if (cnt & 0x80) {
- pstatus->val = -1;
- } else {
- BYTE packed = 0;
- if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
- return EOF;
- }
- pstatus->val = packed;
- }
- }
- pstatus->cnt--;
- if (pstatus->val == -1) {
- BYTE packed = 0;
- if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
- return EOF;
- }
- return packed;
- }
- else {
- return pstatus->val;
- }
-}
-
-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";
-}
-
-static const char * DLL_CALLCONV
-RegExpr() {
- return NULL;
-}
-
-static const char * DLL_CALLCONV
-MimeType() {
- return "image/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;
-}
-
+// ==========================================================
+// SGI Loader
+//
+// Design and implementation by
+// - Sherman Wilcox
+// - Noam Gat
+//
+// References :
+// ------------
+// - The SGI Image File Format, Version 1.0
+// http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
+// - SGI RGB Image Format
+// http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/
+//
+//
+// This file is part of FreeImage 3
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#include "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// Constants + headers
+// ----------------------------------------------------------
+
+#ifdef _WIN32
+#pragma pack(push, 1)
+#else
+#pragma pack(1)
+#endif
+
+typedef struct tagSGIHeader {
+ /** IRIS image file magic number. This should be decimal 474. */
+ WORD magic;
+ /** Storage format: 0 for uncompressed, 1 for RLE compression. */
+ BYTE storage;
+ /** Number of bytes per pixel channel. Legally 1 or 2. */
+ BYTE bpc;
+ /**
+ Number of dimensions. Legally 1, 2, or 3.
+ 1 means a single row, XSIZE long
+ 2 means a single 2D image
+ 3 means multiple 2D images
+ */
+ WORD dimension;
+ /** X size in pixels */
+ WORD xsize;
+ /** Y size in pixels */
+ WORD ysize;
+ /**
+ Number of channels.
+ 1 indicates greyscale
+ 3 indicates RGB
+ 4 indicates RGB and Alpha
+ */
+ WORD zsize;
+ /** Minimum pixel value. This is the lowest pixel value in the image.*/
+ LONG pixmin;
+ /** Maximum pixel value. This is the highest pixel value in the image.*/
+ LONG pixmax;
+ /** Ignored. Normally set to 0. */
+ char dummy[4];
+ /** Image name. Must be null terminated, therefore at most 79 bytes. */
+ char imagename[80];
+ /**
+ Colormap ID.
+ 0 - normal mode
+ 1 - dithered, 3 mits for red and green, 2 for blue, obsolete
+ 2 - index colour, obsolete
+ 3 - not an image but a colourmap
+ */
+ LONG colormap;
+ /** Ignored. Should be set to 0, makes the header 512 bytes. */
+ char reserved[404];
+} SGIHeader;
+
+typedef struct tagRLEStatus {
+ int cnt;
+ int val;
+} RLEStatus;
+
+#ifdef _WIN32
+#pragma pack(pop)
+#else
+#pragma pack()
+#endif
+
+static const char *SGI_LESS_THAN_HEADER_LENGTH = "Incorrect header size";
+static const char *SGI_16_BIT_COMPONENTS_NOT_SUPPORTED = "No 16 bit support";
+static const char *SGI_COLORMAPS_NOT_SUPPORTED = "No colormap support";
+static const char *SGI_EOF_IN_RLE_INDEX = "EOF in run length encoding";
+static const char *SGI_EOF_IN_IMAGE_DATA = "EOF in image data";
+static const char *SGI_INVALID_CHANNEL_COUNT = "Invalid channel count";
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+#ifndef FREEIMAGE_BIGENDIAN
+static void
+SwapHeader(SGIHeader *header) {
+ SwapShort(&header->magic);
+ SwapShort(&header->dimension);
+ SwapShort(&header->xsize);
+ SwapShort(&header->ysize);
+ SwapShort(&header->zsize);
+ SwapLong((DWORD*)&header->pixmin);
+ SwapLong((DWORD*)&header->pixmax);
+ SwapLong((DWORD*)&header->colormap);
+}
+#endif
+
+static int
+get_rlechar(FreeImageIO *io, fi_handle handle, RLEStatus *pstatus) {
+ if (!pstatus->cnt) {
+ int cnt = 0;
+ while (0 == cnt) {
+ BYTE packed = 0;
+ if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
+ return EOF;
+ }
+ cnt = packed;
+ }
+ if (cnt == EOF) {
+ return EOF;
+ }
+ pstatus->cnt = cnt & 0x7F;
+ if (cnt & 0x80) {
+ pstatus->val = -1;
+ } else {
+ BYTE packed = 0;
+ if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
+ return EOF;
+ }
+ pstatus->val = packed;
+ }
+ }
+ pstatus->cnt--;
+ if (pstatus->val == -1) {
+ BYTE packed = 0;
+ if(io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1) {
+ return EOF;
+ }
+ return packed;
+ }
+ else {
+ return pstatus->val;
+ }
+}
+
+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";
+}
+
+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;
+}
+