diff options
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginRAS.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/PluginRAS.cpp | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginRAS.cpp b/plugins/AdvaImg/src/FreeImage/PluginRAS.cpp new file mode 100644 index 0000000000..08fc0c9e17 --- /dev/null +++ b/plugins/AdvaImg/src/FreeImage/PluginRAS.cpp @@ -0,0 +1,512 @@ +// ========================================================== +// Sun rasterfile Loader +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// +// 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 tagSUNHEADER { + DWORD magic; // Magic number + DWORD width; // Image width in pixels + DWORD height; // Image height in pixels + DWORD depth; // Depth (1, 8, 24 or 32 bits) of each pixel + DWORD length; // Image length (in bytes) + DWORD type; // Format of file (see RT_* below) + DWORD maptype; // Type of colormap (see RMT_* below) + DWORD maplength; // Length of colormap (in bytes) +} SUNHEADER; + +#ifdef _WIN32 +#pragma pack(pop) +#else +#pragma pack() +#endif + +// ---------------------------------------------------------- + +// Following the header is the colormap, for maplength bytes (unless maplength is zero), +// then the image. Each row of the image is rounded to 2 bytes. + +#define RAS_MAGIC 0x59A66A95 // Magic number for Sun rasterfiles + +// Sun supported type's + +#define RT_OLD 0 // Old format (raw image in 68000 byte order) +#define RT_STANDARD 1 // Raw image in 68000 byte order +#define RT_BYTE_ENCODED 2 // Run-length encoding of bytes +#define RT_FORMAT_RGB 3 // XRGB or RGB instead of XBGR or BGR +#define RT_FORMAT_TIFF 4 // TIFF <-> standard rasterfile +#define RT_FORMAT_IFF 5 // IFF (TAAC format) <-> standard rasterfile + +#define RT_EXPERIMENTAL 0xffff // Reserved for testing + +// These are the possible colormap types. +// if it's in RGB format, the map is made up of three byte arrays +// (red, green, then blue) that are each 1/3 of the colormap length. + +#define RMT_NONE 0 // maplength is expected to be 0 +#define RMT_EQUAL_RGB 1 // red[maplength/3], green[maplength/3], blue[maplength/3] +#define RMT_RAW 2 // Raw colormap +#define RESC 128 // Run-length encoding escape character + +// ----- NOTES ----- +// Each line of the image is rounded out to a multiple of 16 bits. +// This corresponds to the rounding convention used by the memory pixrect +// package (/usr/include/pixrect/memvar.h) of the SunWindows system. +// The ras_encoding field (always set to 0 by Sun's supported software) +// was renamed to ras_length in release 2.0. As a result, rasterfiles +// of type 0 generated by the old software claim to have 0 length; for +// compatibility, code reading rasterfiles must be prepared to compute the +// TRUE length from the width, height, and depth fields. + +// ========================================================== +// Internal functions +// ========================================================== + +static void +ReadData(FreeImageIO *io, fi_handle handle, BYTE *buf, DWORD length, BOOL rle) { + // Read either Run-Length Encoded or normal image data + + static BYTE repchar, remaining= 0; + + if (rle) { + // Run-length encoded read + + while(length--) { + if (remaining) { + remaining--; + *(buf++)= repchar; + } else { + io->read_proc(&repchar, 1, 1, handle); + + if (repchar == RESC) { + io->read_proc(&remaining, 1, 1, handle); + + if (remaining == 0) { + *(buf++)= RESC; + } else { + io->read_proc(&repchar, 1, 1, handle); + + *(buf++)= repchar; + } + } else { + *(buf++)= repchar; + } + } + } + } else { + // Normal read + + io->read_proc(buf, length, 1, handle); + } +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "RAS"; +} + +static const char * DLL_CALLCONV +Description() { + return "Sun Raster Image"; +} + +static const char * DLL_CALLCONV +Extension() { + return "ras"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/x-cmu-raster"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO *io, fi_handle handle) { + BYTE ras_signature[] = { 0x59, 0xA6, 0x6A, 0x95 }; + BYTE signature[4] = { 0, 0, 0, 0 }; + + io->read_proc(signature, 1, sizeof(ras_signature), handle); + + return (memcmp(ras_signature, signature, sizeof(ras_signature)) == 0); +} + +static BOOL DLL_CALLCONV +SupportsExportDepth(int depth) { + return FALSE; +} + +static BOOL DLL_CALLCONV +SupportsExportType(FREE_IMAGE_TYPE type) { + return FALSE; +} + +static BOOL DLL_CALLCONV +SupportsNoPixels() { + return TRUE; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { + SUNHEADER header; // Sun file header + WORD linelength; // Length of raster line in bytes + WORD fill; // Number of fill bytes per raster line + BOOL rle; // TRUE if RLE file + BOOL isRGB; // TRUE if file type is RT_FORMAT_RGB + BYTE fillchar; + + FIBITMAP *dib = NULL; + BYTE *bits; // Pointer to dib data + WORD x, y; + + if (!handle) { + return NULL; + } + + BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; + + try { + // Read SUN raster header + + io->read_proc(&header, sizeof(SUNHEADER), 1, handle); + +#ifndef FREEIMAGE_BIGENDIAN + // SUN rasterfiles are big endian only + + SwapLong(&header.magic); + SwapLong(&header.width); + SwapLong(&header.height); + SwapLong(&header.depth); + SwapLong(&header.length); + SwapLong(&header.type); + SwapLong(&header.maptype); + SwapLong(&header.maplength); +#endif + + // Verify SUN identifier + + if (header.magic != RAS_MAGIC) { + throw FI_MSG_ERROR_MAGIC_NUMBER; + } + + // Allocate a new DIB + + switch(header.depth) { + case 1: + case 8: + dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth); + break; + + case 24: + dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + break; + + case 32: + dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + break; + } + + if (dib == NULL) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + // Check the file format + + rle = FALSE; + isRGB = FALSE; + + switch(header.type) { + case RT_OLD: + case RT_STANDARD: + case RT_FORMAT_TIFF: // I don't even know what these format are... + case RT_FORMAT_IFF: //The TIFF and IFF format types indicate that the raster + //file was originally converted from either of these file formats. + //so lets at least try to process them as RT_STANDARD + break; + + case RT_BYTE_ENCODED: + rle = TRUE; + break; + + case RT_FORMAT_RGB: + isRGB = TRUE; + break; + + default: + throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; + } + + // set up the colormap if needed + + switch(header.maptype) { + case RMT_NONE : + { + if (header.depth < 24) { + // Create linear color ramp + + RGBQUAD *pal = FreeImage_GetPalette(dib); + + int numcolors = 1 << header.depth; + + for (int i = 0; i < numcolors; i++) { + pal[i].rgbRed = (BYTE)((255 * i) / (numcolors - 1)); + pal[i].rgbGreen = (BYTE)((255 * i) / (numcolors - 1)); + pal[i].rgbBlue = (BYTE)((255 * i) / (numcolors - 1)); + } + } + + break; + } + + case RMT_EQUAL_RGB: + { + BYTE *r, *g, *b; + + // Read SUN raster colormap + + int numcolors = 1 << header.depth; + if ((DWORD)(3 * numcolors) > header.maplength) { + // some RAS may have less colors than the full palette + numcolors = header.maplength / 3; + } else { + throw "Invalid palette"; + } + + r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE)); + g = r + numcolors; + b = g + numcolors; + + RGBQUAD *pal = FreeImage_GetPalette(dib); + + io->read_proc(r, 3 * numcolors, 1, handle); + + for (int i = 0; i < numcolors; i++) { + pal[i].rgbRed = r[i]; + pal[i].rgbGreen = g[i]; + pal[i].rgbBlue = b[i]; + } + + free(r); + break; + } + + case RMT_RAW: + { + BYTE *colormap; + + // Read (skip) SUN raster colormap. + + colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE)); + + io->read_proc(colormap, header.maplength, 1, handle); + + free(colormap); + break; + } + } + + if(header_only) { + // header only mode + return dib; + } + + // Calculate the line + pitch + // Each row is multiple of 16 bits (2 bytes). + + if (header.depth == 1) { + linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0)); + } else { + linelength = (WORD)header.width; + } + + fill = (linelength % 2) ? 1 : 0; + + unsigned pitch = FreeImage_GetPitch(dib); + + // Read the image data + + switch(header.depth) { + case 1: + case 8: + { + bits = FreeImage_GetBits(dib) + (header.height - 1) * pitch; + + for (y = 0; y < header.height; y++) { + ReadData(io, handle, bits, linelength, rle); + + bits -= pitch; + + if (fill) { + ReadData(io, handle, &fillchar, fill, rle); + } + } + + break; + } + + case 24: + { + BYTE *buf, *bp; + + buf = (BYTE*)malloc(header.width * 3); + + for (y = 0; y < header.height; y++) { + bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch; + + ReadData(io, handle, buf, header.width * 3, rle); + + bp = buf; + + if (isRGB) { + for (x = 0; x < header.width; x++) { + bits[FI_RGBA_RED] = *(bp++); // red + bits[FI_RGBA_GREEN] = *(bp++); // green + bits[FI_RGBA_BLUE] = *(bp++); // blue + + bits += 3; + } + } else { + for (x = 0; x < header.width; x++) { + bits[FI_RGBA_RED] = *(bp + 2); // red + bits[FI_RGBA_GREEN] = *(bp + 1);// green + bits[FI_RGBA_BLUE] = *bp; // blue + + bits += 3; bp += 3; + } + } + + if (fill) { + ReadData(io, handle, &fillchar, fill, rle); + } + } + + free(buf); + break; + } + + case 32: + { + BYTE *buf, *bp; + + buf = (BYTE*)malloc(header.width * 4); + + for (y = 0; y < header.height; y++) { + bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch; + + ReadData(io, handle, buf, header.width * 4, rle); + + bp = buf; + + if (isRGB) { + for (x = 0; x < header.width; x++) { + bits[FI_RGBA_ALPHA] = *(bp++); // alpha + bits[FI_RGBA_RED] = *(bp++); // red + bits[FI_RGBA_GREEN] = *(bp++); // green + bits[FI_RGBA_BLUE] = *(bp++); // blue + + bits += 4; + } + } + else { + for (x = 0; x < header.width; x++) { + bits[FI_RGBA_RED] = *(bp + 3); // red + bits[FI_RGBA_GREEN] = *(bp + 2); // green + bits[FI_RGBA_BLUE] = *(bp + 1); // blue + bits[FI_RGBA_ALPHA] = *bp; // alpha + + bits += 4; + bp += 4; + } + } + + if (fill) { + ReadData(io, handle, &fillchar, fill, rle); + } + } + + free(buf); + break; + } + } + + return dib; + + } catch (const char *text) { + if(dib) { + FreeImage_Unload(dib); + } + FreeImage_OutputMessageProc(s_format_id, text); + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitRAS(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; + plugin->supports_no_pixels_proc = SupportsNoPixels; +} |