PageRenderTime 42ms CodeModel.GetById 14ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImage/PluginRAS.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 512 lines | 326 code | 115 blank | 71 comment | 41 complexity | adbe794f1c7fc3d69d6667dd89bc6509 MD5 | raw file
  1// ==========================================================
  2// Sun rasterfile Loader
  3//
  4// Design and implementation by 
  5// - Hervé Drolon (drolon@infonie.fr)
  6//
  7// This file is part of FreeImage 3
  8//
  9// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 10// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 11// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 12// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 13// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 14// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 15// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 16// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 17// THIS DISCLAIMER.
 18//
 19// Use at your own risk!
 20// ==========================================================
 21
 22#include "FreeImage.h"
 23#include "Utilities.h"
 24
 25// ----------------------------------------------------------
 26//   Constants + headers
 27// ----------------------------------------------------------
 28
 29#ifdef _WIN32
 30#pragma pack(push, 1)
 31#else
 32#pragma pack(1)
 33#endif
 34
 35typedef struct tagSUNHEADER {
 36	DWORD magic;		// Magic number
 37	DWORD width;		// Image width in pixels
 38	DWORD height;		// Image height in pixels
 39	DWORD depth;		// Depth (1, 8, 24 or 32 bits) of each pixel
 40	DWORD length;		// Image length (in bytes)
 41	DWORD type;			// Format of file (see RT_* below)
 42	DWORD maptype;		// Type of colormap (see RMT_* below)
 43	DWORD maplength;	// Length of colormap (in bytes)
 44} SUNHEADER;
 45
 46#ifdef _WIN32
 47#pragma pack(pop)
 48#else
 49#pragma pack()
 50#endif
 51
 52// ----------------------------------------------------------
 53
 54// Following the header is the colormap, for maplength bytes (unless maplength is zero),
 55// then the image. Each row of the image is rounded to 2 bytes.
 56
 57#define RAS_MAGIC 0x59A66A95 // Magic number for Sun rasterfiles
 58
 59// Sun supported type's
 60
 61#define RT_OLD			0	// Old format (raw image in 68000 byte order)
 62#define RT_STANDARD		1	// Raw image in 68000 byte order
 63#define RT_BYTE_ENCODED	2	// Run-length encoding of bytes 
 64#define RT_FORMAT_RGB	3	// XRGB or RGB instead of XBGR or BGR
 65#define RT_FORMAT_TIFF	4	// TIFF <-> standard rasterfile
 66#define RT_FORMAT_IFF	5	// IFF (TAAC format) <-> standard rasterfile
 67
 68#define RT_EXPERIMENTAL 0xffff	// Reserved for testing
 69
 70// These are the possible colormap types.
 71// if it's in RGB format, the map is made up of three byte arrays
 72// (red, green, then blue) that are each 1/3 of the colormap length.
 73
 74#define RMT_NONE		0	// maplength is expected to be 0
 75#define RMT_EQUAL_RGB	1	// red[maplength/3], green[maplength/3], blue[maplength/3]
 76#define RMT_RAW			2	// Raw colormap
 77#define RESC			128 // Run-length encoding escape character
 78
 79// ----- NOTES -----
 80// Each line of the image is rounded out to a multiple of 16 bits.
 81// This corresponds to the rounding convention used by the memory pixrect
 82// package (/usr/include/pixrect/memvar.h) of the SunWindows system.
 83// The ras_encoding field (always set to 0 by Sun's supported software)
 84// was renamed to ras_length in release 2.0.  As a result, rasterfiles
 85// of type 0 generated by the old software claim to have 0 length; for
 86// compatibility, code reading rasterfiles must be prepared to compute the
 87// TRUE length from the width, height, and depth fields.
 88
 89// ==========================================================
 90// Internal functions
 91// ==========================================================
 92
 93static void
 94ReadData(FreeImageIO *io, fi_handle handle, BYTE *buf, DWORD length, BOOL rle) {
 95	// Read either Run-Length Encoded or normal image data
 96
 97	static BYTE repchar, remaining= 0;
 98
 99	if (rle) {
100		// Run-length encoded read
101
102		while(length--) {
103			if (remaining) {
104				remaining--;
105				*(buf++)= repchar;
106			} else {
107				io->read_proc(&repchar, 1, 1, handle);
108
109				if (repchar == RESC) {
110					io->read_proc(&remaining, 1, 1, handle);
111
112					if (remaining == 0) {
113						*(buf++)= RESC;
114					} else {
115						io->read_proc(&repchar, 1, 1, handle);
116
117						*(buf++)= repchar;
118					}
119				} else {
120					*(buf++)= repchar;
121				}
122			}
123		}
124	} else {
125		// Normal read
126	
127		io->read_proc(buf, length, 1, handle);
128	}
129}
130
131// ==========================================================
132// Plugin Interface
133// ==========================================================
134
135static int s_format_id;
136
137// ==========================================================
138// Plugin Implementation
139// ==========================================================
140
141static const char * DLL_CALLCONV
142Format() {
143	return "RAS";
144}
145
146static const char * DLL_CALLCONV
147Description() {
148	return "Sun Raster Image";
149}
150
151static const char * DLL_CALLCONV
152Extension() {
153	return "ras";
154}
155
156static const char * DLL_CALLCONV
157RegExpr() {
158	return NULL;
159}
160
161static const char * DLL_CALLCONV
162MimeType() {
163	return "image/x-cmu-raster";
164}
165
166static BOOL DLL_CALLCONV
167Validate(FreeImageIO *io, fi_handle handle) {
168	BYTE ras_signature[] = { 0x59, 0xA6, 0x6A, 0x95 };
169	BYTE signature[4] = { 0, 0, 0, 0 };
170
171	io->read_proc(signature, 1, sizeof(ras_signature), handle);
172
173	return (memcmp(ras_signature, signature, sizeof(ras_signature)) == 0);
174}
175
176static BOOL DLL_CALLCONV
177SupportsExportDepth(int depth) {
178	return FALSE;
179}
180
181static BOOL DLL_CALLCONV 
182SupportsExportType(FREE_IMAGE_TYPE type) {
183	return FALSE;
184}
185
186static BOOL DLL_CALLCONV
187SupportsNoPixels() {
188	return TRUE;
189}
190
191// ----------------------------------------------------------
192
193static FIBITMAP * DLL_CALLCONV
194Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
195	SUNHEADER header;	// Sun file header
196	WORD linelength;	// Length of raster line in bytes
197	WORD fill;			// Number of fill bytes per raster line
198	BOOL rle;			// TRUE if RLE file
199	BOOL isRGB;			// TRUE if file type is RT_FORMAT_RGB
200	BYTE fillchar;
201
202	FIBITMAP *dib = NULL;
203	BYTE *bits;			// Pointer to dib data
204	WORD x, y;
205
206	if(!handle) {
207		return NULL;
208	}
209
210	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
211
212	try {
213		// Read SUN raster header
214
215		io->read_proc(&header, sizeof(SUNHEADER), 1, handle);
216
217#ifndef FREEIMAGE_BIGENDIAN
218		// SUN rasterfiles are big endian only
219
220		SwapLong(&header.magic);
221		SwapLong(&header.width);
222		SwapLong(&header.height);
223		SwapLong(&header.depth);
224		SwapLong(&header.length);
225		SwapLong(&header.type);
226		SwapLong(&header.maptype);
227		SwapLong(&header.maplength);
228#endif
229
230		// Verify SUN identifier
231
232		if (header.magic != RAS_MAGIC) {
233			throw FI_MSG_ERROR_MAGIC_NUMBER;
234		}
235
236		// Allocate a new DIB
237
238		switch(header.depth) {
239			case 1:
240			case 8:
241				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth);
242				break;
243
244			case 24:
245				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
246				break;
247
248			case 32:
249				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
250				break;
251		}
252
253		if (dib == NULL) {
254			throw FI_MSG_ERROR_DIB_MEMORY;
255		}
256
257		// Check the file format
258
259		rle = FALSE;
260		isRGB = FALSE;
261
262		switch(header.type) {
263			case RT_OLD:
264			case RT_STANDARD:
265			case RT_FORMAT_TIFF: // I don't even know what these format are...
266			case RT_FORMAT_IFF: //The TIFF and IFF format types indicate that the raster
267				//file was originally converted from either of these file formats.
268				//so lets at least try to process them as RT_STANDARD
269				break;
270
271			case RT_BYTE_ENCODED:
272				rle = TRUE;
273				break;
274
275			case RT_FORMAT_RGB:
276				isRGB = TRUE;
277				break;
278
279			default:
280				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
281		}
282
283		// set up the colormap if needed
284
285		switch(header.maptype) {
286			case RMT_NONE :
287			{				
288				if (header.depth < 24) {
289					// Create linear color ramp
290
291					RGBQUAD *pal = FreeImage_GetPalette(dib);
292
293					int numcolors = 1 << header.depth;
294
295					for (int i = 0; i < numcolors; i++) {
296						pal[i].rgbRed	= (BYTE)((255 * i) / (numcolors - 1));
297						pal[i].rgbGreen = (BYTE)((255 * i) / (numcolors - 1));
298						pal[i].rgbBlue	= (BYTE)((255 * i) / (numcolors - 1));
299					}
300				}
301
302				break;
303			}
304
305			case RMT_EQUAL_RGB:
306			{
307				BYTE *r, *g, *b;
308
309				// Read SUN raster colormap
310
311				int numcolors = 1 << header.depth;
312				if((DWORD)(3 * numcolors) > header.maplength) {
313					// some RAS may have less colors than the full palette
314					numcolors = header.maplength / 3;
315				} else {
316					throw "Invalid palette";
317				}
318
319				r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE));
320				g = r + numcolors;
321				b = g + numcolors;
322
323				RGBQUAD *pal = FreeImage_GetPalette(dib);
324
325				io->read_proc(r, 3 * numcolors, 1, handle);
326
327				for (int i = 0; i < numcolors; i++) {
328					pal[i].rgbRed	= r[i];
329					pal[i].rgbGreen = g[i];
330					pal[i].rgbBlue	= b[i];
331				}
332
333				free(r);
334				break;
335			}
336
337			case RMT_RAW:
338			{
339				BYTE *colormap;
340
341				// Read (skip) SUN raster colormap.
342
343				colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE));
344
345				io->read_proc(colormap, header.maplength, 1, handle);
346
347				free(colormap);
348				break;
349			}
350		}
351
352		if(header_only) {
353			// header only mode
354			return dib;
355		}
356
357		// Calculate the line + pitch
358		// Each row is multiple of 16 bits (2 bytes).
359
360		if (header.depth == 1) {
361			linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0));
362		} else {
363			linelength = (WORD)header.width;
364		}
365
366		fill = (linelength % 2) ? 1 : 0;
367
368		unsigned pitch = FreeImage_GetPitch(dib);
369
370		// Read the image data
371		
372		switch(header.depth) {
373			case 1:
374			case 8:
375			{
376				bits = FreeImage_GetBits(dib) + (header.height - 1) * pitch;
377
378				for (y = 0; y < header.height; y++) {
379					ReadData(io, handle, bits, linelength, rle);
380
381					bits -= pitch;
382
383					if (fill) {
384						ReadData(io, handle, &fillchar, fill, rle);
385					}
386				}
387
388				break;
389			}
390
391			case 24:
392			{
393				BYTE *buf, *bp;
394
395				buf = (BYTE*)malloc(header.width * 3);
396
397				for (y = 0; y < header.height; y++) {
398					bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
399
400					ReadData(io, handle, buf, header.width * 3, rle);
401
402					bp = buf;
403
404					if (isRGB) {
405						for (x = 0; x < header.width; x++) {
406							bits[FI_RGBA_RED] = *(bp++);	// red
407							bits[FI_RGBA_GREEN] = *(bp++);	// green
408							bits[FI_RGBA_BLUE] = *(bp++);	// blue
409
410							bits += 3;
411						}
412					} else {
413						for (x = 0; x < header.width; x++) {
414							bits[FI_RGBA_RED] = *(bp + 2);	// red
415							bits[FI_RGBA_GREEN] = *(bp + 1);// green
416							bits[FI_RGBA_BLUE] = *bp;       // blue
417
418							bits += 3; bp += 3;
419						}
420					}
421
422					if (fill) {
423						ReadData(io, handle, &fillchar, fill, rle);
424					}
425				}
426
427				free(buf);
428				break;
429			}
430
431			case 32:
432			{
433				BYTE *buf, *bp;
434
435				buf = (BYTE*)malloc(header.width * 4);
436
437				for (y = 0; y < header.height; y++) {
438					bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
439
440					ReadData(io, handle, buf, header.width * 4, rle);
441
442					bp = buf;
443
444					if (isRGB) {
445						for (x = 0; x < header.width; x++) {
446							bits[FI_RGBA_ALPHA] = *(bp++);	// alpha
447							bits[FI_RGBA_RED] = *(bp++);	// red
448							bits[FI_RGBA_GREEN] = *(bp++);	// green
449							bits[FI_RGBA_BLUE] = *(bp++);	// blue
450
451							bits += 4;
452						}
453					}
454					else {
455						for (x = 0; x < header.width; x++) {
456							bits[FI_RGBA_RED] = *(bp + 3);	// red
457							bits[FI_RGBA_GREEN] = *(bp + 2); // green
458							bits[FI_RGBA_BLUE] = *(bp + 1);	// blue
459							bits[FI_RGBA_ALPHA] = *bp;		// alpha
460
461							bits += 4;
462							bp += 4;
463						}
464					}
465
466					if (fill) {
467						ReadData(io, handle, &fillchar, fill, rle);
468					}
469				}
470
471				free(buf);
472				break;
473			}
474		}
475		
476		return dib;
477
478	} catch (const char *text) {
479		if(dib) {
480			FreeImage_Unload(dib);
481		}
482		FreeImage_OutputMessageProc(s_format_id, text);
483	}
484
485	return NULL;
486}
487
488// ==========================================================
489//   Init
490// ==========================================================
491
492void DLL_CALLCONV
493InitRAS(Plugin *plugin, int format_id) {
494	s_format_id = format_id;
495
496	plugin->format_proc = Format;
497	plugin->description_proc = Description;
498	plugin->extension_proc = Extension;
499	plugin->regexpr_proc = RegExpr;
500	plugin->open_proc = NULL;
501	plugin->close_proc = NULL;
502	plugin->pagecount_proc = NULL;
503	plugin->pagecapability_proc = NULL;
504	plugin->load_proc = Load;
505	plugin->save_proc = NULL;
506	plugin->validate_proc = Validate;
507	plugin->mime_proc = MimeType;
508	plugin->supports_export_bpp_proc = SupportsExportDepth;
509	plugin->supports_export_type_proc = SupportsExportType;
510	plugin->supports_icc_profiles_proc = NULL;
511	plugin->supports_no_pixels_proc = SupportsNoPixels;
512}