Alien-FreeImage

 view release on metacpan or  search on metacpan

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

// 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"

// ==========================================================
// Plugin Interface
// ==========================================================
static int s_format_id;

static const int outputMessageSize = 256;

// ==========================================================
// Internal functions
// ==========================================================

static BYTE
Read8(FreeImageIO *io, fi_handle handle) {
	BYTE i = 0;
	io->read_proc(&i, 1, 1, handle);
	return i;
}

static WORD
Read16(FreeImageIO *io, fi_handle handle) {
	// reads a two-byte big-endian integer from the given file and returns its value.
	// assumes unsigned.
	
	unsigned hi = Read8(io, handle);
	unsigned lo = Read8(io, handle);
	return (WORD)(lo + (hi << 8));
}

static unsigned
Read32(FreeImageIO *io, fi_handle handle) {
	// reads a four-byte big-endian integer from the given file and returns its value.
	// assumes unsigned.
	
	unsigned b3 = Read8(io, handle);
	unsigned b2 = Read8(io, handle);
	unsigned b1 = Read8(io, handle);
	unsigned b0 = Read8(io, handle);
	return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
}

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

struct OpDef
{
	const char * name;
	int    len;
	const char * description;
};

// for reserved opcodes
#define res(length) { "reserved", (length), "reserved for Apple use" }
#define RGB_LEN 6
#define WORD_LEN -1
#define NA 0

static OpDef optable[] =
{
/* 0x00 */  { "NOP",               0, "nop" },
/* 0x01 */  { "Clip",             NA, "clip" },
/* 0x02 */  { "BkPat",             8, "background pattern" },
/* 0x03 */  { "TxFont",            2, "text font (word)" },
/* 0x04 */  { "TxFace",            1, "text face (byte)" },
/* 0x05 */  { "TxMode",            2, "text mode (word)" },
/* 0x06 */  { "SpExtra",           4, "space extra (fixed point)" },
/* 0x07 */  { "PnSize",            4, "pen size (point)" },
/* 0x08 */  { "PnMode",            2, "pen mode (word)" },
/* 0x09 */  { "PnPat",             8, "pen pattern" },
/* 0x0a */  { "FillPat",           8, "fill pattern" },
/* 0x0b */  { "OvSize",            4, "oval size (point)" },
/* 0x0c */  { "Origin",            4, "dh, dv (word)" },
/* 0x0d */  { "TxSize",            2, "text size (word)" },
/* 0x0e */  { "FgColor",           4, "foreground color (longword)" },
/* 0x0f */  { "BkColor",           4, "background color (longword)" },
/* 0x10 */  { "TxRatio",           8, "numerator (point), denominator (point)" },
/* 0x11 */  { "Version",           1, "version (byte)" },
/* 0x12 */  { "BkPixPat",         NA, "color background pattern" },
/* 0x13 */  { "PnPixPat",         NA, "color pen pattern" },
/* 0x14 */  { "FillPixPat",       NA, "color fill pattern" },
/* 0x15 */  { "PnLocHFrac",        2, "fractional pen position" },
/* 0x16 */  { "ChExtra",           2, "extra for each character" },
/* 0x17 */  res(0),
/* 0x18 */  res(0),
/* 0x19 */  res(0),
/* 0x1a */  { "RGBFgCol",    RGB_LEN, "RGB foreColor" },
/* 0x1b */  { "RGBBkCol",    RGB_LEN, "RGB backColor" },
/* 0x1c */  { "HiliteMode",        0, "hilite mode flag" },
/* 0x1d */  { "HiliteColor", RGB_LEN, "RGB hilite color" },
/* 0x1e */  { "DefHilite",         0, "Use default hilite color" },
/* 0x1f */  { "OpColor",           6, "RGB OpColor for arithmetic modes" },
/* 0x20 */  { "Line",              8, "pnLoc (point), newPt (point)" },
/* 0x21 */  { "LineFrom",          4, "newPt (point)" },
/* 0x22 */  { "ShortLine",         6, "pnLoc (point, dh, dv (-128 .. 127))" },
/* 0x23 */  { "ShortLineFrom",     2, "dh, dv (-128 .. 127)" },
/* 0x24 */  res(WORD_LEN),
/* 0x25 */  res(WORD_LEN),
/* 0x26 */  res(WORD_LEN),
/* 0x27 */  res(WORD_LEN),
/* 0x28 */  { "LongText",         NA, "txLoc (point), count (0..255), text" },
/* 0x29 */  { "DHText",           NA, "dh (0..255), count (0..255), text" },
/* 0x2a */  { "DVText",           NA, "dv (0..255), count (0..255), text" },
/* 0x2b */  { "DHDVText",         NA, "dh, dv (0..255), count (0..255), text" },
/* 0x2c */  res(WORD_LEN),
/* 0x2d */  res(WORD_LEN),
/* 0x2e */  res(WORD_LEN),
/* 0x2f */  res(WORD_LEN),
/* 0x30 */  { "frameRect",         8, "rect" },
/* 0x31 */  { "paintRect",         8, "rect" },
/* 0x32 */  { "eraseRect",         8, "rect" },
/* 0x33 */  { "invertRect",        8, "rect" },
/* 0x34 */  { "fillRect",          8, "rect" },
/* 0x35 */  res(8),

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

*/
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;
			}

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


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;
					}
				}
			}
		}
	}



( run in 1.346 second using v1.01-cache-2.11-cpan-119454b85a5 )