PageRenderTime 63ms CodeModel.GetById 32ms app.highlight 25ms RepoModel.GetById 2ms app.codeStats 0ms

/src/FreeImage/Source/FreeImage/PluginIFF.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 459 lines | 313 code | 86 blank | 60 comment | 68 complexity | f0d889cc10874e5739557471e6695c83 MD5 | raw file
  1// ==========================================================
  2// Deluxe Paint Loader
  3//
  4// Design and implementation by
  5// - Floris van den Berg (flvdberg@wxs.nl)
  6// - Mark Sibly (marksibly@blitzbasic.com)
  7// - Aaron Shumate (trek@startreker.com)
  8// - Hervé Drolon (drolon@infonie.fr)
  9//
 10// This file is part of FreeImage 3
 11//
 12// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 13// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 14// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 15// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 16// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 17// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 18// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 19// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 20// THIS DISCLAIMER.
 21//
 22// Use at your own risk!
 23// ==========================================================
 24
 25#include "FreeImage.h"
 26#include "Utilities.h"
 27
 28// ----------------------------------------------------------
 29//  Internal typedefs and structures
 30// ----------------------------------------------------------
 31
 32#ifdef _WIN32
 33#pragma pack(push, 1)
 34#else
 35#pragma pack(1)
 36#endif
 37
 38typedef struct {
 39    WORD w, h;                    /* raster width & height in pixels */
 40    WORD x, y;                    /* position for this image */
 41    BYTE nPlanes;                 /* # source bitplanes */
 42    BYTE masking;                 /* masking technique */
 43    BYTE compression;             /* compression algorithm */
 44    BYTE pad1;                    /* UNUSED.  For consistency, put 0 here.*/
 45    WORD transparentColor;        /* transparent "color number" */
 46    BYTE xAspect, yAspect;        /* aspect ratio, a rational number x/y */
 47    WORD pageWidth, pageHeight;   /* source "page" size in pixels */
 48} BMHD;
 49
 50#ifdef _WIN32
 51#pragma pack(pop)
 52#else
 53#pragma pack()
 54#endif
 55
 56#ifndef FREEIMAGE_BIGENDIAN
 57static void
 58SwapHeader(BMHD *header) {
 59	SwapShort(&header->w);
 60	SwapShort(&header->h);
 61	SwapShort(&header->x);
 62	SwapShort(&header->y);
 63	SwapShort(&header->transparentColor);
 64	SwapShort(&header->pageWidth);
 65	SwapShort(&header->pageHeight);
 66}
 67#endif
 68
 69// ----------------------------------------------------------
 70
 71/* IFF chunk IDs */
 72
 73typedef DWORD IFF_ID;
 74
 75#define MAKE_ID(a, b, c, d)         ((IFF_ID)(a)<<24 | (IFF_ID)(b)<<16 | (IFF_ID)(c)<<8 | (IFF_ID)(d))
 76
 77#define ID_FORM     MAKE_ID('F', 'O', 'R', 'M')     /* EA IFF 85 group identifier */
 78#define ID_CAT      MAKE_ID('C', 'A', 'T', ' ')     /* EA IFF 85 group identifier */
 79#define ID_LIST     MAKE_ID('L', 'I', 'S', 'T')     /* EA IFF 85 group identifier */
 80#define ID_PROP     MAKE_ID('P', 'R', 'O', 'P')     /* EA IFF 85 group identifier */
 81#define ID_END      MAKE_ID('E', 'N', 'D', ' ')     /* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3 page 376) */
 82
 83#define ID_ILBM     MAKE_ID('I', 'L', 'B', 'M')     /* EA IFF 85 raster bitmap form */
 84#define ID_DEEP     MAKE_ID('D', 'E', 'E', 'P')     /* Chunky pixel image files (Used in TV Paint) */
 85#define ID_RGB8     MAKE_ID('R', 'G', 'B', '8')     /* RGB image forms, Turbo Silver (Impulse) */
 86#define ID_RGBN     MAKE_ID('R', 'G', 'B', 'N')     /* RGB image forms, Turbo Silver (Impulse) */
 87#define ID_PBM      MAKE_ID('P', 'B', 'M', ' ')     /* 256-color chunky format (DPaint 2 ?) */
 88#define ID_ACBM     MAKE_ID('A', 'C', 'B', 'M')     /* Amiga Contiguous Bitmap (AmigaBasic) */
 89/* generic */
 90#define ID_FVER     MAKE_ID('F', 'V', 'E', 'R')     /* AmigaOS version string */
 91#define ID_JUNK     MAKE_ID('J', 'U', 'N', 'K')     /* always ignore this chunk */
 92#define ID_ANNO     MAKE_ID('A', 'N', 'N', 'O')     /* EA IFF 85 Generic Annotation chunk */
 93#define ID_AUTH     MAKE_ID('A', 'U', 'T', 'H')     /* EA IFF 85 Generic Author chunk */
 94#define ID_CHRS     MAKE_ID('C', 'H', 'R', 'S')     /* EA IFF 85 Generic character string chunk */
 95#define ID_NAME     MAKE_ID('N', 'A', 'M', 'E')     /* EA IFF 85 Generic Name of art, music, etc. chunk */
 96#define ID_TEXT     MAKE_ID('T', 'E', 'X', 'T')     /* EA IFF 85 Generic unformatted ASCII text chunk */
 97#define ID_copy     MAKE_ID('(', 'c', ')', ' ')     /* EA IFF 85 Generic Copyright text chunk */
 98/* ILBM chunks */
 99#define ID_BMHD     MAKE_ID('B', 'M', 'H', 'D')     /* ILBM BitmapHeader */
100#define ID_CMAP     MAKE_ID('C', 'M', 'A', 'P')     /* ILBM 8bit RGB colormap */
101#define ID_GRAB     MAKE_ID('G', 'R', 'A', 'B')     /* ILBM "hotspot" coordiantes */
102#define ID_DEST     MAKE_ID('D', 'E', 'S', 'T')     /* ILBM destination image info */
103#define ID_SPRT     MAKE_ID('S', 'P', 'R', 'T')     /* ILBM sprite identifier */
104#define ID_CAMG     MAKE_ID('C', 'A', 'M', 'G')     /* Amiga viewportmodes */
105#define ID_BODY     MAKE_ID('B', 'O', 'D', 'Y')     /* ILBM image data */
106#define ID_CRNG     MAKE_ID('C', 'R', 'N', 'G')     /* color cycling */
107#define ID_CCRT     MAKE_ID('C', 'C', 'R', 'T')     /* color cycling */
108#define ID_CLUT     MAKE_ID('C', 'L', 'U', 'T')     /* Color Lookup Table chunk */
109#define ID_DPI      MAKE_ID('D', 'P', 'I', ' ')     /* Dots per inch chunk */
110#define ID_DPPV     MAKE_ID('D', 'P', 'P', 'V')     /* DPaint perspective chunk (EA) */
111#define ID_DRNG     MAKE_ID('D', 'R', 'N', 'G')     /* DPaint IV enhanced color cycle chunk (EA) */
112#define ID_EPSF     MAKE_ID('E', 'P', 'S', 'F')     /* Encapsulated Postscript chunk */
113#define ID_CMYK     MAKE_ID('C', 'M', 'Y', 'K')     /* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
114#define ID_CNAM     MAKE_ID('C', 'N', 'A', 'M')     /* Color naming chunk (Soft-Logik) */
115#define ID_PCHG     MAKE_ID('P', 'C', 'H', 'G')     /* Line by line palette control information (Sebastiano Vigna) */
116#define ID_PRVW     MAKE_ID('P', 'R', 'V', 'W')     /* A mini duplicate ILBM used for preview (Gary Bonham) */
117#define ID_XBMI     MAKE_ID('X', 'B', 'M', 'I')     /* eXtended BitMap Information (Soft-Logik) */
118#define ID_CTBL     MAKE_ID('C', 'T', 'B', 'L')     /* Newtek Dynamic Ham color chunk */
119#define ID_DYCP     MAKE_ID('D', 'Y', 'C', 'P')     /* Newtek Dynamic Ham chunk */
120#define ID_SHAM     MAKE_ID('S', 'H', 'A', 'M')     /* Sliced HAM color chunk */
121#define ID_ABIT     MAKE_ID('A', 'B', 'I', 'T')     /* ACBM body chunk */
122#define ID_DCOL     MAKE_ID('D', 'C', 'O', 'L')     /* unofficial direct color */
123
124// ==========================================================
125// Plugin Interface
126// ==========================================================
127
128static int s_format_id;
129
130// ==========================================================
131// Plugin Implementation
132// ==========================================================
133
134static const char * DLL_CALLCONV
135Format() {
136	return "IFF";
137}
138
139static const char * DLL_CALLCONV
140Description() {
141	return "IFF Interleaved Bitmap";
142}
143
144static const char * DLL_CALLCONV
145Extension() {
146	return "iff,lbm";
147}
148
149static const char * DLL_CALLCONV
150RegExpr() {
151	return NULL;
152}
153
154static const char * DLL_CALLCONV
155MimeType() {
156	return "image/x-iff";
157}
158
159static BOOL DLL_CALLCONV
160Validate(FreeImageIO *io, fi_handle handle) {
161	DWORD type = 0;
162
163	// read chunk type
164	io->read_proc(&type, 4, 1, handle);
165#ifndef FREEIMAGE_BIGENDIAN
166	SwapLong(&type);
167#endif
168
169	if(type != ID_FORM)
170		return FALSE;
171		
172	// skip 4 bytes
173	io->read_proc(&type, 4, 1, handle);
174
175	// read chunk type
176	io->read_proc(&type, 4, 1, handle);
177#ifndef FREEIMAGE_BIGENDIAN
178	SwapLong(&type);
179#endif
180
181	// File format : ID_PBM = Packed Bitmap, ID_ILBM = Interleaved Bitmap
182	return (type == ID_ILBM) || (type == ID_PBM);
183}
184
185
186static BOOL DLL_CALLCONV
187SupportsExportDepth(int depth) {
188	return FALSE;
189}
190
191static BOOL DLL_CALLCONV 
192SupportsExportType(FREE_IMAGE_TYPE type) {
193	return FALSE;
194}
195
196// ----------------------------------------------------------
197
198static FIBITMAP * DLL_CALLCONV
199Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
200	if (handle != NULL) {
201		FIBITMAP *dib = NULL;
202
203		DWORD type, size;
204
205		io->read_proc(&type, 4, 1, handle);
206#ifndef FREEIMAGE_BIGENDIAN
207		SwapLong(&type);
208#endif
209
210		if(type != ID_FORM)
211			return NULL;
212
213		io->read_proc(&size, 4, 1, handle);
214#ifndef FREEIMAGE_BIGENDIAN
215		SwapLong(&size);
216#endif
217
218		io->read_proc(&type, 4, 1, handle);
219#ifndef FREEIMAGE_BIGENDIAN
220		SwapLong(&type);
221#endif
222
223		if((type != ID_ILBM) && (type != ID_PBM))
224			return NULL;
225
226		size -= 4;
227
228		unsigned width = 0, height = 0, planes = 0, depth = 0, comp = 0;
229
230		while (size) {
231			DWORD ch_type,ch_size;
232
233			io->read_proc(&ch_type, 4, 1, handle);
234#ifndef FREEIMAGE_BIGENDIAN
235			SwapLong(&ch_type);
236#endif
237
238			io->read_proc(&ch_size,4,1,handle );
239#ifndef FREEIMAGE_BIGENDIAN
240			SwapLong(&ch_size);
241#endif
242
243			unsigned ch_end = io->tell_proc(handle) + ch_size;
244
245			if (ch_type == ID_BMHD) {			// Bitmap Header
246				if (dib)
247					FreeImage_Unload(dib);
248
249				BMHD bmhd;
250
251				io->read_proc(&bmhd, sizeof(bmhd), 1, handle);
252#ifndef FREEIMAGE_BIGENDIAN
253				SwapHeader(&bmhd);
254#endif
255
256				width = bmhd.w;
257				height = bmhd.h;
258				planes = bmhd.nPlanes;
259				comp = bmhd.compression;
260
261				if(bmhd.masking & 1)
262					planes++;	// there is a mask ( 'stencil' )
263
264				if (planes > 8 && planes != 24)
265					return NULL;
266
267				depth = planes > 8 ? 24 : 8;
268
269				if( depth == 24 ) {
270					dib = FreeImage_Allocate(width, height, depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
271				} else {
272					dib = FreeImage_Allocate(width, height, depth);
273				}
274			} else if (ch_type == ID_CMAP) {	// Palette (Color Map)
275				if (!dib)
276					return NULL;
277
278				RGBQUAD *pal = FreeImage_GetPalette(dib);
279				if(pal != NULL) {
280					unsigned palette_entries = MIN((unsigned)ch_size / 3, FreeImage_GetColorsUsed(dib));
281					for (unsigned k = 0; k < palette_entries; k++) {					
282						io->read_proc(&pal[k].rgbRed, 1, 1, handle );
283						io->read_proc(&pal[k].rgbGreen, 1, 1, handle );
284						io->read_proc(&pal[k].rgbBlue, 1, 1, handle );
285					}
286				}
287			} else if (ch_type == ID_BODY) {
288				if (!dib)
289					return NULL;
290
291				if (type == ID_PBM) {
292					// NON INTERLACED (LBM)
293
294					unsigned line = FreeImage_GetLine(dib) + 1 & ~1;
295					
296					for (unsigned i = 0; i < FreeImage_GetHeight(dib); i++) {
297						BYTE *bits = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1);
298
299						if (comp == 1) {
300							// use RLE compression
301
302							DWORD number_of_bytes_written = 0;
303							BYTE rle_count;
304							BYTE byte;
305
306							while (number_of_bytes_written < line) {
307								io->read_proc(&rle_count, 1, 1, handle);
308
309								if (rle_count < 128) {
310									for (int k = 0; k < rle_count + 1; k++) {
311										io->read_proc(&byte, 1, 1, handle);
312
313										bits[number_of_bytes_written++] += byte;
314									}
315								} else if (rle_count > 128) {
316									io->read_proc(&byte, 1, 1, handle);
317
318									for (int k = 0; k < 257 - rle_count; k++) {
319										bits[number_of_bytes_written++] += byte;
320									}
321								}
322							}
323						} else {
324							// don't use compression
325
326							io->read_proc(bits, line, 1, handle);
327						}
328					}
329
330					return dib;
331				} else {
332					// INTERLACED (ILBM)
333
334					unsigned pixel_size = depth/8;
335					unsigned n_width=(width+15)&~15;
336					unsigned plane_size = n_width/8;
337					unsigned src_size = plane_size * planes;
338					BYTE *src = (BYTE*)malloc(src_size);
339					BYTE *dest = FreeImage_GetBits(dib);
340
341					dest += FreeImage_GetPitch(dib) * height;
342
343					for (unsigned y = 0; y < height; y++) {
344						dest -= FreeImage_GetPitch(dib);
345
346						// read all planes in one hit,
347						// 'coz PSP compresses across planes...
348
349						if (comp) {
350							// unpacker algorithm
351
352							for(unsigned x = 0; x < src_size;) {
353								// read the next source byte into t
354								signed char t = 0;
355								io->read_proc(&t, 1, 1, handle);
356								
357								if (t >= 0) {
358									// t = [0..127] => copy the next t+1 bytes literally
359									unsigned size_to_read = t + 1;
360
361									if((size_to_read + x) > src_size) {
362										// sanity check for buffer overruns 
363										size_to_read = src_size - x;
364										io->read_proc(src + x, size_to_read, 1, handle);
365										x += (t + 1);
366									} else {
367										io->read_proc(src + x, size_to_read, 1, handle);
368										x += size_to_read;
369									}
370								} else if (t != -128) {
371									// t = [-1..-127]  => replicate the next byte -t+1 times
372									BYTE b = 0;
373									io->read_proc(&b, 1, 1, handle);
374									unsigned size_to_copy = (unsigned)(-(int)t + 1);
375
376									if((size_to_copy + x) > src_size) {
377										// sanity check for buffer overruns 
378										size_to_copy = src_size - x;
379										memset(src + x, b, size_to_copy);
380										x += (unsigned)(-(int)t + 1);
381									} else {
382										memset(src + x, b, size_to_copy);
383										x += size_to_copy;
384									}
385								}
386								// t = -128 => noop
387							}
388						} else {
389							io->read_proc(src, src_size, 1, handle);
390						}
391
392						// lazy planar->chunky...
393
394						for (unsigned x = 0; x < width; x++) {
395							for (unsigned n = 0; n < planes; n++) {
396								BYTE bit = (BYTE)( src[n * plane_size + (x / 8)] >> ((x^7) & 7) );
397
398								dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7);
399							}
400						}
401
402#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
403						if (depth == 24) {
404							for (unsigned x = 0; x < width; ++x){
405								INPLACESWAP(dest[x * 3], dest[x * 3 + 2]);
406							}
407						}
408#endif
409					}
410
411					free(src);
412
413					return dib;
414				}
415			}
416
417			// Every odd-length chunk is followed by a 0 pad byte.  This pad
418			//  byte is not counted in ch_size.
419			if (ch_size & 1) {
420				ch_size++;
421				ch_end++;
422			}
423
424			io->seek_proc(handle, ch_end - io->tell_proc(handle), SEEK_CUR);
425
426			size -= ch_size + 8;
427		}
428
429		if (dib)
430			FreeImage_Unload(dib);
431	}
432
433	return 0;
434}
435
436// ==========================================================
437//   Init
438// ==========================================================
439
440void DLL_CALLCONV
441InitIFF(Plugin *plugin, int format_id) {
442	s_format_id = format_id;
443
444	plugin->format_proc = Format;
445	plugin->description_proc = Description;
446	plugin->extension_proc = Extension;
447	plugin->regexpr_proc = RegExpr;
448	plugin->open_proc = NULL;
449	plugin->close_proc = NULL;
450	plugin->pagecount_proc = NULL;
451	plugin->pagecapability_proc = NULL;
452	plugin->load_proc = Load;
453	plugin->save_proc = NULL;
454	plugin->validate_proc = Validate;
455	plugin->mime_proc = MimeType;
456	plugin->supports_export_bpp_proc = SupportsExportDepth;
457	plugin->supports_export_type_proc = SupportsExportType;
458	plugin->supports_icc_profiles_proc = NULL;
459}