diff options
Diffstat (limited to 'plugins/FreeImage/src/FreeImage/PluginRAS.cpp')
| -rw-r--r-- | plugins/FreeImage/src/FreeImage/PluginRAS.cpp | 512 | 
1 files changed, 512 insertions, 0 deletions
diff --git a/plugins/FreeImage/src/FreeImage/PluginRAS.cpp b/plugins/FreeImage/src/FreeImage/PluginRAS.cpp new file mode 100644 index 0000000000..08fc0c9e17 --- /dev/null +++ b/plugins/FreeImage/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; +}  | 
