Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginPICT.cpp  view on Meta::CPAN

	WORD y;
};

struct MacPattern // Klaube
{
	BYTE pix[64];
};

// ----------------------------------------------------------

static void 
ReadRect( FreeImageIO *io, fi_handle handle, MacRect* rect ) {
	rect->top = Read16( io, handle );
	rect->left = Read16( io, handle );
	rect->bottom = Read16( io, handle );
	rect->right = Read16( io, handle );
}

static void 
ReadPixmap( FreeImageIO *io, fi_handle handle, MacpixMap* pPixMap ) {
	pPixMap->version = Read16( io, handle );
	pPixMap->packType = Read16( io, handle );
	pPixMap->packSize = Read32( io, handle );
	pPixMap->hRes = Read16( io, handle );
	Read16( io, handle );
	pPixMap->vRes = Read16( io, handle );
	Read16( io, handle );
	pPixMap->pixelType = Read16( io, handle );
	pPixMap->pixelSize = Read16( io, handle );
	pPixMap->cmpCount = Read16( io, handle );
	pPixMap->cmpSize = Read16( io, handle );
	pPixMap->planeBytes = Read32( io, handle );
	pPixMap->pmTable = Read32( io, handle );
	pPixMap->pmReserved = Read32( io, handle );
}

/**
Reads a mac color table into a bitmap palette.
*/
static void 
ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pPal ) {
	LONG        ctSeed;
	WORD        ctFlags;
	WORD        val;
	int         i;
	
	ctSeed = Read32( io, handle );
	ctFlags = Read16( io, handle );
	WORD numColors = Read16( io, handle )+1;
	*pNumColors = numColors;
	
	for (i = 0; i < numColors; i++) {
		val = Read16( io, handle );
		if (ctFlags & 0x8000) {
			// The indicies in a device colour table are bogus and
			// usually == 0, so I assume we allocate up the list of
			// colours in order.
			val = (WORD)i;
		}
		if (val >= numColors) {
			throw "pixel value greater than color table size.";
		}
		// Mac colour tables contain 16-bit values for R, G, and B...
		pPal[val].rgbRed = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
		pPal[val].rgbGreen = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
		pPal[val].rgbBlue = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
	}
}

/**
skips unneeded packbits.
pixelSize == Source bits per pixel.
*/
static void 
SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int pixelSize ) {
	int    i;
	WORD   pixwidth;           // bytes per row when uncompressed.
	
	int height = bounds->bottom - bounds->top;
	int width = bounds->right - bounds->left;
	
	// High bit of rowBytes is flag.
	if (pixelSize <= 8) {
		rowBytes &= 0x7fff;
	}
	pixwidth = (WORD)width;
	
	if (pixelSize == 16) {
		pixwidth *= 2;
	}
	if (rowBytes == 0) {
		rowBytes = pixwidth;
	}
	if (rowBytes < 8) {
		io->seek_proc( handle, rowBytes*height, SEEK_CUR );
	}
	else {
		for (i = 0; i < height; i++) {
			int lineLen;            // length of source line in bytes.
			if (rowBytes > 250) {
				lineLen = Read16( io, handle );
			} else {
				lineLen = Read8( io, handle );
			}
			io->seek_proc( handle, lineLen, SEEK_CUR );
		}
	}
}

/**
Skip polygon or region
*/
static void 
SkipPolyOrRegion( FreeImageIO *io, fi_handle handle ) {
	WORD len = Read16( io, handle ) - 2;
	io->seek_proc(handle, len, SEEK_CUR);	
}

/**
Width in bytes for 8 bpp or less.
Width in pixels for 16 bpp.
Expands Width units to 32-bit pixel data.
*/
static void 
expandBuf( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) { 
	switch (bpp) {
		case 16:
			for ( int i=0; i<width; i++) {
				WORD src = Read16( io, handle );
				dst[ FI_RGBA_BLUE ] = (src & 31)*8;				// Blue
				dst[ FI_RGBA_GREEN ] = ((src >> 5) & 31)*8;		// Green
				dst[ FI_RGBA_RED ] = ((src >> 10) & 31)*8;		// Red
				dst[ FI_RGBA_ALPHA ] = 0xFF;					// Alpha
				dst += 4;
			}
			break;
		default:
			throw "Bad bits per pixel in expandBuf.";
	}
}

/**
Expands Width units to 8-bit pixel data.
Max. 8 bpp source format.
*/
static void 
expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst )
{
	switch (bpp) {
		case 8:
			io->read_proc( dst, width, 1, handle );
			break;
		case 4:
			for (int i = 0; i < width; i++) {
				WORD src = Read8( io, handle );
				*dst = (src >> 4) & 15;
				*(dst+1) = (src & 15);
				dst += 2;
			}
			if (width & 1) { // Odd Width?
				WORD src = Read8( io, handle );
				*dst = (src >> 4) & 15;
				dst++;
			}
			break;
		case 2:
			for (int i = 0; i < width; i++) {
				WORD src = Read8( io, handle );
				*dst = (src >> 6) & 3;
				*(dst+1) = (src >> 4) & 3;
				*(dst+2) = (src >> 2) & 3;
				*(dst+3) = (src & 3);
				dst += 4;
			}
			if (width & 3)  { // Check for leftover pixels
				for (int i = 6; i > 8 - (width & 3) * 2; i -= 2) {
					WORD src = Read8( io, handle );
					*dst = (src >> i) & 3;
					dst++;
				}
			}
			break;
		case 1:
			for (int i = 0; i < width; i++) {
				WORD src = Read8( io, handle );
				*dst = (src >> 7) & 1;
				*(dst+1) = (src >> 6) & 1;
				*(dst+2) = (src >> 5) & 1;
				*(dst+3) = (src >> 4) & 1;
				*(dst+4) = (src >> 3) & 1;
				*(dst+5) = (src >> 2) & 1;
				*(dst+6) = (src >> 1) & 1;
				*(dst+7) = (src  & 1);
				dst += 8;
			}
			if (width & 7) {  // Check for leftover pixels
				for (int i = 7; i > (8-width & 7); i--) {
					WORD src = Read8( io, handle );
					*dst = (src >> i) & 1;
					dst++;
				}
			}
			break;
		default:
			throw "Bad bits per pixel in expandBuf8.";
	}
}

static BYTE* 
UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) {	

	if (rowBytes < 8) { // Ah-ha!  The bits aren't actually packed.  This will be easy.
		io->read_proc( pLineBuf, rowBytes, 1, handle );
	}
	else {
		BYTE* pCurPixel = pLineBuf;
		
		// Unpack RLE. The data is packed bytewise.
		for (int j = 0; j < srcBytes; )	{
			BYTE FlagCounter = Read8( io, handle );
			if (FlagCounter & 0x80) {
				if (FlagCounter == 0x80) {
					// Special case: repeat value of 0.
					// Apple says ignore.
					j++;
				} else { 
					// Packed data.
					int len = ((FlagCounter ^ 255) & 255) + 2;					
					BYTE p = Read8( io, handle );
					memset( pCurPixel, p, len);
					pCurPixel += len;
					j += 2;
				}
			}
			else { 
				// Unpacked data
				int len = (FlagCounter & 255) + 1;
				io->read_proc( pCurPixel, len, 1, handle );
				pCurPixel += len;
				j += len + 1;
			}
		}
	}
	
	return pLineBuf;
}

/**
This routine decompresses BitsRects with a packType of 4 (and 32 bits per pixel). 
In this format, each line is separated into 8-bit-bitplanes and then compressed via RLE. 
To decode, the routine decompresses each line & then juggles the bytes around to get pixel-oriented data.
NumBitPlanes == 3 if RGB, 4 if RGBA
*/
static void 
Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int numPlanes ) {
	int height = bounds->bottom - bounds->top;
	int width = bounds->right - bounds->left;
	
	if (rowBytes == 0) {
		rowBytes = (WORD)( width * 4 );
	}
	
	BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes
	if ( pLineBuf )	{
		try	{
			for ( int i = 0; i < height; i++ ) { 
				// for each line do...
				int linelen;            // length of source line in bytes.
				if (rowBytes > 250) {
					linelen = Read16( io, handle );
				} else {
					linelen = Read8( io, handle);
				}
				
				BYTE* pBuf = UnpackPictRow( io, handle, pLineBuf, width, rowBytes, linelen );
				
				// Convert plane-oriented data into pixel-oriented data &
				// copy into destination bitmap.
				BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
				
				if ( numPlanes == 3 ) {
					for ( int j = 0; j < width; j++ ) { 
						// For each pixel in line...
						dst[ FI_RGBA_BLUE ] = (*(pBuf+width*2));     // Blue
						dst[ FI_RGBA_GREEN ] = (*(pBuf+width));       // Green
						dst[ FI_RGBA_RED ] = (*pBuf);             // Red
						dst[ FI_RGBA_ALPHA ] = (0xFF);
						dst += 4;
						pBuf++;
					}
				} else {
					for ( int j = 0; j < width; j++ ) { 
						// For each pixel in line...
						dst[ FI_RGBA_BLUE ] = (*(pBuf+width*3));     // Blue
						dst[ FI_RGBA_GREEN ] = (*(pBuf+width*2));     // Green
						dst[ FI_RGBA_RED ] = (*(pBuf+width));       // Red
						dst[ FI_RGBA_ALPHA ] = (*pBuf);
						dst += 4;
						pBuf++;
					}
				}
			}
		}
		catch( ... ) {
			free( pLineBuf );
			throw;
		}
	}
	free( pLineBuf );
}

/**
Decompression routine for 8 bpp. 
rowBytes is the number of bytes each source row would take if it were uncompressed.
This _isn't_ equal to the number of pixels in the row - it seems apple pads the data to a word boundary and then compresses it. 
Of course, we have to decompress the excess data and then throw it away.
*/
static void 
Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes ) {	
	int height = bounds->bottom - bounds->top;
	int width = bounds->right - bounds->left;
	
	// High bit of rowBytes is flag.
	rowBytes &= 0x7fff;
	
	if (rowBytes == 0) {
		rowBytes = (WORD)width;
	}
	
	for ( int i = 0; i < height; i++ ) {
		int linelen;            // length of source line in bytes.
		if (rowBytes > 250) {
			linelen = Read16( io, handle );
		} else {
			linelen = Read8( io, handle );
		}
		BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);				
		dst = UnpackPictRow( io, handle, dst, width, rowBytes, linelen );
	}
}

/**
Decompression routine for everything but 8 & 32 bpp. 
This routine is slower than the two routines above since it has to deal with a lot of special cases :-(.
It's also a bit chaotic because of these special cases...
unpack8bits is basically a dumber version of unpackbits.
pixelSize == Source bits per pixel.
*/
static void 
UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int pixelSize ) {
	WORD   pixwidth;           // bytes per row when uncompressed.
	int    pkpixsize;
	int    PixelPerRLEUnit;

	char outputMessage[ outputMessageSize ] = "";
	
	int height = bounds->bottom - bounds->top;
	int width = bounds->right - bounds->left;
	
	// High bit of rowBytes is flag.
	if (pixelSize <= 8) {
		rowBytes &= 0x7fff;
	}
	
	pixwidth = (WORD)width;
	pkpixsize = 1;          // RLE unit: one byte for everything...
	if (pixelSize == 16) {    // ...except 16 bpp.
		pkpixsize = 2;
		pixwidth *= 2;
	}
	
	if (rowBytes == 0) {
		rowBytes = pixwidth;
	}
	
	{
		// I allocate the temporary line buffer here. I allocate too
		// much memory to compensate for sloppy (& hence fast) decompression.
		switch (pixelSize) {
			case 1:
				PixelPerRLEUnit = 8;
				break;
			case 2:
				PixelPerRLEUnit = 4;
				break;
			case 4:
				PixelPerRLEUnit = 2;
				break;
			case 8:
				PixelPerRLEUnit = 1;
				break;
			case 16:
				PixelPerRLEUnit = 1;
				break;
			default:
				sprintf( outputMessage, "Illegal bpp value in unpackbits: %d\n", pixelSize );
				throw outputMessage;
		}
		
		if (rowBytes < 8) { 
			// ah-ha!  The bits aren't actually packed.  This will be easy.
			for ( int i = 0; i < height; i++ ) {
				BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
				if (pixelSize == 16) {
					expandBuf( io, handle, width, pixelSize, dst );
				} else {
					expandBuf8( io, handle, width, pixelSize, dst );
				}
			}
		}
		else {
			for ( int i = 0; i < height; i++ ) { 
				// For each line do...
				int    linelen;            // length of source line in bytes.
				if (rowBytes > 250) {
					linelen = Read16( io, handle );
				} else {
					linelen = Read8( io, handle );
				}
				
				BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
				BYTE FlagCounter;
				
				// Unpack RLE. The data is packed bytewise - except for
				// 16 bpp data, which is packed per pixel :-(.
				for ( int j = 0; j < linelen; ) {
					FlagCounter = Read8( io, handle );
					if (FlagCounter & 0x80) {
						if (FlagCounter == 0x80) {
							// Special case: repeat value of 0.
							// Apple says ignore.
							j++;
						}
						else { 
							// Packed data.
							int len = ((FlagCounter ^ 255) & 255) + 2;
							
							// This is slow for some formats...
							if (pixelSize == 16) {
								expandBuf( io, handle, 1, pixelSize, dst );
								for ( int k = 1; k < len; k++ ) { 
									// Repeat the pixel len times.
									memcpy( dst+(k*4*PixelPerRLEUnit), dst,	4*PixelPerRLEUnit);
								}
								dst += len*4*PixelPerRLEUnit;
							}
							else {
								expandBuf8( io, handle, 1, pixelSize, dst );
								for ( int k = 1; k < len; k++ ) { 
									// Repeat the expanded byte len times.
									memcpy( dst+(k*PixelPerRLEUnit), dst, PixelPerRLEUnit);
								}
								dst += len*PixelPerRLEUnit;
							}
							j += pkpixsize + 1;
						}
					}
					else { 
						// Unpacked data
						int len = (FlagCounter & 255) + 1;
						if (pixelSize == 16) {
							expandBuf( io, handle, len, pixelSize, dst );
							dst += len*4*PixelPerRLEUnit;
						}
						else {
							expandBuf8( io, handle, len, pixelSize, dst );
							dst += len*PixelPerRLEUnit;
						}
						j += ( len * pkpixsize ) + 1;
					}
				}
			}
		}
	}
}

static void 
DecodeOp9a( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacpixMap* pixMap ) {
	// Do the actual unpacking.
	switch ( pixMap->pixelSize ) {
		case 32:
			Unpack32Bits( io, handle, dib, &pixMap->Bounds, 0, pixMap->cmpCount );
			break;
		case 8:
			Unpack8Bits( io, handle, dib, &pixMap->Bounds, 0 );
			break;
		default:
			UnpackBits( io, handle, dib, &pixMap->Bounds, 0, pixMap->pixelSize );
	}
}

static void 
DecodeBitmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacRect* bounds, WORD rowBytes ) {
	WORD mode = Read16( io, handle );
	
	if ( isRegion ) {
		SkipPolyOrRegion( io, handle );
	}
	
	RGBQUAD* pal = FreeImage_GetPalette( dib );
	if ( !pal ) {
		throw "No palette for bitmap!";
	}
	
	for (int i = 0; i < 2; i++) {
		unsigned char val = i ? 0xFF : 0x0;
		pal[i].rgbRed = val;
		pal[i].rgbGreen = val;
		pal[i].rgbBlue = val;
	}
	
	UnpackBits( io, handle, dib, bounds, rowBytes, 1 );
}

static void 
DecodePixmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacpixMap* pixMap, WORD rowBytes ) {
	// Read mac colour table into windows palette.
	WORD numColors;    // Palette size.
	RGBQUAD ct[256];
	
	ReadColorTable( io, handle, &numColors, ct );
	if ( FreeImage_GetBPP( dib ) == 8 ) {
		RGBQUAD* pal = FreeImage_GetPalette( dib );
		if ( !pal ) {
			throw "No palette for bitmap!";
		}
		
		for (int i = 0; i < numColors; i++) {
			pal[i].rgbRed = ct[ i ].rgbRed;
			pal[i].rgbGreen = ct[ i ].rgbGreen;
			pal[i].rgbBlue = ct[ i ].rgbBlue;
		}
	}
	
	// Ignore source & destination rectangle as well as transfer mode.
	MacRect tempRect;
	ReadRect( io, handle, &tempRect );
	ReadRect( io, handle, &tempRect );
	WORD mode = Read16( io, handle );
	
	if ( isRegion) {
		SkipPolyOrRegion( io, handle );
	}
	
	switch ( pixMap->pixelSize ) {
		case 32:
			Unpack32Bits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->cmpCount );
			break;
		case 8:
			Unpack8Bits( io, handle, dib, &pixMap->Bounds, rowBytes );
			break;
		default:
			UnpackBits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->pixelSize );
	}
}

// ==========================================================
// Plugin Implementation
// ==========================================================

static const char * DLL_CALLCONV
Format() {
	return "PICT";
}

static const char * DLL_CALLCONV
Description() {
	return "Macintosh PICT";
}

static const char * DLL_CALLCONV
Extension() {
	return "pct,pict,pic";
}

static const char * DLL_CALLCONV
MimeType() {
	return "image/x-pict";
}

static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {
	if(io->seek_proc(handle, 522, SEEK_SET) == 0) {
		BYTE pict_signature[] = { 0x00, 0x11, 0x02, 0xFF, 0x0C, 0X00 };
		BYTE signature[6];

		if(io->read_proc(signature, 1, sizeof(pict_signature), handle)) {
			// v1.0 files have 0x11 (version operator) followed by 0x01 (version number)
			// v2.0 files have 0x0011 (version operator) followed by 0x02ff (version number)
			//   and additionally 0x0c00 as a header opcode
			// Currently, we are only supporting v2.0
			return (memcmp(pict_signature, signature, sizeof(pict_signature)) == 0);
		} else {
			return FALSE;
		}
	}

	return FALSE;
}

static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
	return FALSE;
}

static BOOL DLL_CALLCONV 
SupportsExportType(FREE_IMAGE_TYPE type) {
	return FALSE;
}

static BOOL DLL_CALLCONV
SupportsICCProfiles() {
	return FALSE;
}

/**
This plugin decodes macintosh PICT files with 1,2,4,8,16 and 32 bits per pixel as well as PICT/JPEG. 
If an alpha channel is present in a 32-bit-PICT, it is decoded as well. 
The PICT format is a general picture file format and can contain a lot of other elements besides bitmaps. 
These elements are ignored.	
*/
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	char outputMessage[ outputMessageSize ] = "";
	FIBITMAP* dib = NULL;
	try {		
		// Skip empty 512 byte header.
		if ( !io->seek_proc(handle, 512, SEEK_CUR) == 0 )
			return NULL;
		
		// Read PICT header
		Read16( io, handle ); // Skip version 1 picture size
		
		MacRect frame;
		ReadRect( io, handle, &frame );

		BYTE b = 0;
		while ((b = Read8(io, handle)) == 0);
		if ( b != 0x11 ) {
			throw "invalid header: version number missing.";
		}
		
		int version = Read8( io, handle );
		if ( version == 2 && Read8( io, handle ) != 0xff ) {
			throw "invalid header: illegal version number.";
		}
		
		enum PICTType {none, op9a, jpeg, pixmap, bitmap};
		PICTType pictType = none;
		
		MacRect bounds;
		MacpixMap pixMap;
		int hRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
		int vRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
		WORD rowBytes = 0;
		BOOL isRegion = FALSE;
		BOOL done = FALSE;
		long currentPos = 0;

		while ( !done ) {
			WORD opcode = 0;

			// get the current stream position (used to avoid infinite loops)
			currentPos = io->tell_proc(handle);
			
			if ((version == 1) || ((io->tell_proc( handle ) % 2) != 0)) {
				// align to word for version 2
				opcode = Read8( io, handle );
			}
			if (version == 2) {
				opcode = Read16( io, handle );
			}
			
			if (opcode == 0xFF || opcode == 0xFFFF) {
				done = TRUE;
				throw "PICT contained only vector data!";
			}
			else if (opcode < 0xa2)	{				
				switch (opcode)	{
					case 0x01:
					{
						// skip clipping rectangle
						MacRect clipRect;
						WORD len = Read16( io, handle );

						if (len == 0x000a) { 
							/* null rgn */
							ReadRect( io, handle, &clipRect );
						} else {
							io->seek_proc(handle, len - 2, SEEK_CUR);
						}
						break;
					}						
					case 0x12:
					case 0x13:
					case 0x14:
					{
						// skip pattern definition
						WORD       patType;
						WORD       rowBytes;
						MacpixMap  p;
						WORD       numColors;
						
						patType = Read16( io, handle );
						
						switch( patType ) {
							case 2:
								io->seek_proc(handle, 8, SEEK_CUR);
								io->seek_proc(handle, 5, SEEK_CUR);
								break;
							case 1:
							{
								io->seek_proc(handle, 8, SEEK_CUR);
								rowBytes = Read16( io, handle );
								ReadRect( io, handle, &p.Bounds );
								ReadPixmap( io, handle, &p);
								
								RGBQUAD ct[256];
								ReadColorTable(io, handle, &numColors, ct );
								SkipBits( io, handle, &p.Bounds, rowBytes, p.pixelSize );
								break;
							}
							default:
								throw "Unknown pattern type.";
						}
						
						break;
					}
					case 0x70:
					case 0x71:
					case 0x72:
					case 0x73:
					case 0x74:
					case 0x75:
					case 0x76:
					case 0x77:
					{
						SkipPolyOrRegion( io, handle );
						break;
					}
					case 0x90:
					case 0x98:
					{
						// Bitmap/pixmap data clipped by a rectangle.
						rowBytes = Read16( io, handle );    // Bytes per row in source when uncompressed.						
						isRegion = FALSE;
						
						if ( rowBytes & 0x8000) {
							pictType = pixmap;
						} else {
							pictType = bitmap;
						}
						done = TRUE;
						break;
					}
					case 0x91:
					case 0x99:
					{
						// Bitmap/pixmap data clipped by a region.
						rowBytes = Read16( io, handle );    // Bytes per row in source when uncompressed.						
						isRegion = TRUE;
						
						if ( rowBytes & 0x8000) {
							pictType = pixmap;
						} else {
							pictType = bitmap;						
						}
						done = TRUE;
						break;
					}
					case 0x9a:
					{
						// DirectBitsRect.
						Read32( io, handle );           // Skip fake len and fake EOF.
						Read16( io, handle );			// bogus row bytes.
						
						// Read in the PixMap fields.
						ReadRect( io, handle, &pixMap.Bounds );
						ReadPixmap( io, handle, &pixMap );
						
						// Ignore source & destination rectangle as well as transfer mode.
						MacRect dummy;
						ReadRect( io, handle, &dummy );
						ReadRect( io, handle, &dummy );

src/Source/FreeImage/PluginPICT.cpp  view on Meta::CPAN

						WORD len;
						
						type = Read16( io, handle );
						len = Read16( io, handle);
						if (len > 0) {
							io->seek_proc(handle, len, SEEK_CUR);
						}
						break;
					}
					default:
						// No function => skip to next opcode
						if (optable[opcode].len == WORD_LEN) {
							WORD len = Read16( io, handle );
							io->seek_proc(handle, len, SEEK_CUR);
						} else {
							io->seek_proc(handle, optable[opcode].len, SEEK_CUR);
						}
						break;
				}
			}
			else if (opcode == 0xc00) {
				// version 2 header (26 bytes)
				WORD minorVersion = Read16( io, handle );	// always FFFE (-2) for extended version 2
				Read16( io, handle );						// reserved
				hRes = Read32( io, handle );				// original horizontal resolution in pixels/inch
				vRes = Read32( io, handle );				// original horizontal resolution in pixels/inch
				MacRect dummy;
				ReadRect( io, handle, &dummy );				// frame bounds at original resolution
				Read32( io, handle );						// reserved
			}
			else if (opcode == 0x8200) {
				// jpeg
				long opLen = Read32( io, handle );
				BOOL found = FALSE;
				int i = 0;
				
				// skip to JPEG header.
				while ( !found && i < opLen ) {
//					io->seek_proc( handle, 24, SEEK_CUR );
//					MacRect dummy;
//					ReadRect( io, handle, &dummy );
//					io->seek_proc( handle, 122, SEEK_CUR );
//					found = TRUE;
					BYTE data[ 2 ];
					if( io->read_proc( data, 2, 1, handle ) ) {
						io->seek_proc( handle, -2, SEEK_CUR );
						
						if ( data[0] == 0xFF && data[1] == 0xD8 ) {
							found = TRUE;
						} else {
							Read8( io, handle );
							i++;
						}
					}
				}
				
				if ( found ) {
					// Pass the data to the JPEG decoder.
					pictType = jpeg;
				} else {
					throw "PICT file contains unrecognized quicktime data.";
				}
				done = TRUE;
			}
			else if (opcode >= 0xa2 && opcode <= 0xaf) {
				// reserved
				WORD len = Read16( io, handle );
				io->seek_proc(handle, len, SEEK_CUR);
			}
			else if ((opcode >= 0xb0 && opcode <= 0xcf) || (opcode >= 0x8000 && opcode <= 0x80ff)) {
				// just a reserved opcode, no data
			}
			else if ((opcode >= 0xd0 && opcode <= 0xfe) || opcode >= 8100) {
				// reserved
				LONG len = Read32( io, handle );
				io->seek_proc(handle, len, SEEK_CUR);
			}
			else if (opcode >= 0x100 && opcode <= 0x7fff) {
				// reserved
				io->seek_proc(handle, ((opcode >> 7) & 255), SEEK_CUR);				
			}
			else {
				sprintf( outputMessage, "Can't handle opcode %x.\n", opcode );
				throw outputMessage;
			}

			if(currentPos == io->tell_proc(handle)) {
				// we probaly reached the end of file as we can no longer move forward ... 
				throw "Invalid PICT file";
			}
		}
				
		switch ( pictType )	{
			case op9a:
			{
				bounds = pixMap.Bounds;
				int width = bounds.right - bounds.left;
				int height = bounds.bottom - bounds.top;
				
				if ( pixMap.pixelSize > 8 ) {
					dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				} else {
					dib = FreeImage_Allocate( width, height, 8);
				}
				hRes = pixMap.hRes << 16;
				vRes = pixMap.vRes << 16;				
				break;
			}	
				
			case jpeg:
			{
				dib = FreeImage_LoadFromHandle( FIF_JPEG, io, handle );					
				break;
			}

			case pixmap:
			{
				// Decode version 2 pixmap
				ReadRect( io, handle, &pixMap.Bounds );
				ReadPixmap( io, handle, &pixMap );
				
				bounds = pixMap.Bounds;
				int width = bounds.right - bounds.left;
				int height = bounds.bottom - bounds.top;

				if ( pixMap.pixelSize > 8 ) {
					dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				} else {
					dib = FreeImage_Allocate( width, height, 8);
				}
				hRes = pixMap.hRes << 16;
				vRes = pixMap.vRes << 16;				
				break;
			}
				
			case bitmap:
			{
				// Decode version 1 bitmap: 1 bpp.
				MacRect srcRect;
				MacRect dstRect;
				WORD width;        // Width in pixels
				WORD height;       // Height in pixels
				
				ReadRect( io, handle, &bounds );
				ReadRect( io, handle, &srcRect );
				ReadRect( io, handle, &dstRect );
				
				width = bounds.right - bounds.left;
				height = bounds.bottom - bounds.top;
				
				dib = FreeImage_Allocate(width, height, 8);
				break;
			}			
		}		
		
		if ( dib ) {
			// need to convert resolution figures from fixed point, pixels/inch
			// to floating point, pixels/meter.			
			float hres_ppm = hRes * ((float)39.4 / (float)65536.0);
			float vres_ppm = vRes * ((float)39.4 / (float)65536.0);		
			
			FreeImage_SetDotsPerMeterX( dib, (LONG)hres_ppm );
			FreeImage_SetDotsPerMeterY( dib, (LONG)vres_ppm );			
			
			switch( pictType ) {
				case op9a:
					DecodeOp9a( io, handle, dib, &pixMap );
					break;
				case jpeg:
					// Already decoded if the embedded format was valid.
					break;
				case pixmap:
					DecodePixmap( io, handle, dib, isRegion, &pixMap, rowBytes );
					break;
				case bitmap:
					DecodeBitmap( io, handle, dib, isRegion, &bounds, rowBytes );
					break;
				default:
					throw "invalid pict type";
			}			
		}
		
		return dib;
	} 
	catch(const char *message) {
		FreeImage_Unload( dib );
		FreeImage_OutputMessageProc(s_format_id, message);
	}

	return NULL;
}

// ==========================================================
//   Init
// ==========================================================

void DLL_CALLCONV
InitPICT(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 = NULL;
	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 = SupportsICCProfiles;
}



( run in 0.612 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )