Alien-FreeImage

 view release on metacpan or  search on metacpan

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

			return FALSE;
		}
	} else {
		int positiveHeight = abs(height);
		for (int c = 0; c < positiveHeight; ++c) {
			count = io->read_proc((void *)FreeImage_GetScanLine(dib, positiveHeight - c - 1), pitch, 1, handle);
			if(count != 1) {
				return FALSE;
			}
		}
	}

	// swap as needed
#ifdef FREEIMAGE_BIGENDIAN
	if (bit_count == 16) {
		for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
			WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y);
			for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
				SwapShort(pixel);
				pixel++;
			}
		}
	}
#endif
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
	if (bit_count == 24 || bit_count == 32) {
		for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
			BYTE *pixel = FreeImage_GetScanLine(dib, y);
			for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
				INPLACESWAP(pixel[0], pixel[2]);
				pixel += (bit_count >> 3);
			}
		}
	}
#endif

	return TRUE;
}

/**
Load image pixels for 4-bit RLE compressed dib
@param io FreeImage IO
@param handle FreeImage IO handle
@param width Image width
@param height Image height
@param dib Image to be loaded 
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL 
LoadPixelDataRLE4(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
	int status_byte = 0;
	BYTE second_byte = 0;
	int bits = 0;

	BYTE *pixels = NULL;	// temporary 8-bit buffer

	try {
		height = abs(height);

		pixels = (BYTE*)malloc(width * height * sizeof(BYTE));
		if(!pixels) throw(1);
		memset(pixels, 0, width * height * sizeof(BYTE));

		BYTE *q = pixels;
		BYTE *end = pixels + height * width;

		for (int scanline = 0; scanline < height; ) {
			if (q < pixels || q  >= end) {
				break;
			}
			if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
				throw(1);
			}
			if (status_byte != 0)	{
				status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
				// Encoded mode
				if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
					throw(1);
				}
				for (int i = 0; i < status_byte; i++)	{
					*q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
				}
				bits += status_byte;
			}
			else {
				// Escape mode
				if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
					throw(1);
				}
				switch (status_byte) {
					case RLE_ENDOFLINE:
					{
						// End of line
						bits = 0;
						scanline++;
						q = pixels + scanline*width;
					}
					break;

					case RLE_ENDOFBITMAP:
						// End of bitmap
						q = end;
						break;

					case RLE_DELTA:
					{
						// read the delta values

						BYTE delta_x = 0;
						BYTE delta_y = 0;

						if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
							throw(1);
						}
						if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
							throw(1);
						}

						// apply them

						bits += delta_x;
						scanline += delta_y;
						q = pixels + scanline*width+bits;
					}
					break;

					default:
					{
						// Absolute mode
						status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
						for (int i = 0; i < status_byte; i++) {
							if ((i & 0x01) == 0) {
								if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
									throw(1);
								}
							}
							*q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
						}
						bits += status_byte;
						// Read pad byte
						if (((status_byte & 0x03) == 1) || ((status_byte & 0x03) == 2)) {
							BYTE padding = 0;
							if(io->read_proc(&padding, sizeof(BYTE), 1, handle) != 1) {
								throw(1);
							}
						}
					}
					break;
				}
			}
		}
		
		{
			// Convert to 4-bit
			for(int y = 0; y < height; y++) {
				const BYTE *src = (BYTE*)pixels + y * width;
				BYTE *dst = FreeImage_GetScanLine(dib, y);

				BOOL hinibble = TRUE;

				for (int cols = 0; cols < width; cols++){
					if (hinibble) {
						dst[cols >> 1] = (src[cols] << 4);
					} else {
						dst[cols >> 1] |= src[cols];
					}

					hinibble = !hinibble;
				}
			}
		}

		free(pixels);

		return TRUE;

	} catch(int) {
		if(pixels) free(pixels);
		return FALSE;
	}
}

/**
Load image pixels for 8-bit RLE compressed dib
@param io FreeImage IO
@param handle FreeImage IO handle
@param width Image width
@param height Image height
@param dib Image to be loaded 
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL 
LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
	BYTE status_byte = 0;
	BYTE second_byte = 0;
	int scanline = 0;
	int bits = 0;

	for (;;) {
		if( io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
			return FALSE;
		}

		switch (status_byte) {

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

				int count = MIN((int)status_byte, width - bits);

				BYTE *sline = FreeImage_GetScanLine(dib, scanline);

				if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
					return FALSE;
				}

				for (int i = 0; i < count; i++) {
					*(sline + bits) = second_byte;

					bits++;					
				}

				break;
			}
		}
	}
}

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

static FIBITMAP *
LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset, int type) {
	FIBITMAP *dib = NULL;

	try {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		// load the info header

		BITMAPINFOHEADER bih;

		io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
		SwapInfoHeader(&bih);
#endif

		// keep some general information about the bitmap

		unsigned used_colors	= bih.biClrUsed;
		int width				= bih.biWidth;
		int height				= bih.biHeight;		// WARNING: height can be < 0 => check each call using 'height' as a parameter
		unsigned bit_count		= bih.biBitCount;
		unsigned compression	= bih.biCompression;
		unsigned pitch			= CalculatePitch(CalculateLine(width, bit_count));

		switch (bit_count) {
			case 1 :
			case 4 :
			case 8 :
			{
				if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) {
					used_colors = CalculateUsedPaletteEntries(bit_count);
				}
				
				// allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette

				dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}

				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);

				// seek to the end of the header (depending on the BMP header version)
				// type == sizeof(BITMAPVxINFOHEADER)
				switch(type) {
					case 40:	// sizeof(BITMAPINFOHEADER) - all Windows versions since Windows 3.0
						break;
					case 52:	// sizeof(BITMAPV2INFOHEADER) (undocumented)
					case 56:	// sizeof(BITMAPV3INFOHEADER) (undocumented)
					case 108:	// sizeof(BITMAPV4HEADER) - all Windows versions since Windows 95/NT4 (not supported)
					case 124:	// sizeof(BITMAPV5HEADER) - Windows 98/2000 and newer (not supported)
						io->seek_proc(handle, (long)(type - sizeof(BITMAPINFOHEADER)), SEEK_CUR);
						break;
				}
				
				// load the palette

				io->read_proc(FreeImage_GetPalette(dib), used_colors * sizeof(RGBQUAD), 1, handle);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
				RGBQUAD *pal = FreeImage_GetPalette(dib);
				for(int i = 0; i < used_colors; i++) {
					INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue);
				}
#endif

				if(header_only) {
					// header only mode
					return dib;
				}

				// seek to the actual pixel data.
				// this is needed because sometimes the palette is larger than the entries it contains predicts
				io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);

				// read the pixel data

				switch (compression) {
					case BI_RGB :
						if( LoadPixelData(io, handle, dib, height, pitch, bit_count) ) {
							return dib;
						} else {
							throw "Error encountered while decoding BMP data";
						}
						break;

					case BI_RLE4 :
						if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
							return dib;
						} else {
							throw "Error encountered while decoding RLE4 BMP data";
						}
						break;

					case BI_RLE8 :
						if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
							return dib;
						} else {
							throw "Error encountered while decoding RLE8 BMP data";
						}
						break;

					default :
						throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
				}
			}
			break; // 1-, 4-, 8-bit

			case 16 :
			{
				int use_bitfields = 0;
				if (bih.biCompression == BI_BITFIELDS) use_bitfields = 3;
				else if (bih.biCompression == BI_ALPHABITFIELDS) use_bitfields = 4;
				else if (type == 52) use_bitfields = 3;
				else if (type >= 56) use_bitfields = 4;
				
				if (use_bitfields > 0) {
 					DWORD bitfields[4];
					io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
				} else {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
				}

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;						
				}

				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);

				if(header_only) {
					// header only mode
					return dib;
				}
				
				// seek to the actual pixel data
				io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);

				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				return dib;
			}
			break; // 16-bit

			case 24 :
			case 32 :
			{
				int use_bitfields = 0;
				if (bih.biCompression == BI_BITFIELDS) use_bitfields = 3;
				else if (bih.biCompression == BI_ALPHABITFIELDS) use_bitfields = 4;
				else if (type == 52) use_bitfields = 3;
				else if (type >= 56) use_bitfields = 4;

 				if (use_bitfields > 0) {
					DWORD bitfields[4];
					io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
				} else {
					if( bit_count == 32 ) {
						dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					}
				}

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}

				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);

				if(header_only) {
					// header only mode
					return dib;
				}

				// Skip over the optional palette 
				// A 24 or 32 bit DIB may contain a palette for faster color reduction
				// i.e. you can have (FreeImage_GetColorsUsed(dib) > 0)

				// seek to the actual pixel data
				io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);

				// read in the bitmap bits
				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				// check if the bitmap contains transparency, if so enable it in the header

				FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));

				return dib;
			}
			break; // 24-, 32-bit
		}
	} catch(const char *message) {
		if(dib) {
			FreeImage_Unload(dib);
		}
		if(message) {
			FreeImage_OutputMessageProc(s_format_id, message);
		}
	}

	return NULL;
}

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

static FIBITMAP *
LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
	FIBITMAP *dib = NULL;

	try {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		// load the info header

		BITMAPINFOHEADER bih;

		io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
		SwapInfoHeader(&bih);
#endif

		// keep some general information about the bitmap

		unsigned used_colors	= bih.biClrUsed;
		int width				= bih.biWidth;
		int height				= bih.biHeight;		// WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
		unsigned bit_count		= bih.biBitCount;
		unsigned compression	= bih.biCompression;
		unsigned pitch			= CalculatePitch(CalculateLine(width, bit_count));
		
		switch (bit_count) {
			case 1 :
			case 4 :
			case 8 :
			{
				if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
					used_colors = CalculateUsedPaletteEntries(bit_count);
					
				// allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette

				dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}

				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
				
				// load the palette
				// note that it may contain RGB or RGBA values : we will calculate this
				unsigned pal_size = (bitmap_bits_offset - sizeof(BITMAPFILEHEADER) - bih.biSize) / used_colors; 

				io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET);

				RGBQUAD *pal = FreeImage_GetPalette(dib);

				if(pal_size == 4) {
					for (unsigned count = 0; count < used_colors; count++) {
						FILE_BGRA bgra;

						io->read_proc(&bgra, sizeof(FILE_BGRA), 1, handle);
						
						pal[count].rgbRed	= bgra.r;
						pal[count].rgbGreen = bgra.g;
						pal[count].rgbBlue	= bgra.b;
					} 
				} else if(pal_size == 3) {
					for (unsigned count = 0; count < used_colors; count++) {
						FILE_BGR bgr;

						io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
						
						pal[count].rgbRed	= bgr.r;
						pal[count].rgbGreen = bgr.g;
						pal[count].rgbBlue	= bgr.b;
					} 
				}
				
				if(header_only) {
					// header only mode
					return dib;
				}

				// seek to the actual pixel data.
				// this is needed because sometimes the palette is larger than the entries it contains predicts

				if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
					io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
				}

				// read the pixel data

				switch (compression) {
					case BI_RGB :
						// load pixel data 
						LoadPixelData(io, handle, dib, height, pitch, bit_count);						
						return dib;

					case BI_RLE4 :
						if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
							return dib;
						} else {
							throw "Error encountered while decoding RLE4 BMP data";
						}
						break;

					case BI_RLE8 :
						if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
							return dib;
						} else {
							throw "Error encountered while decoding RLE8 BMP data";
						}
						break;

					default :		
						throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
				}	
			}

			case 16 :
			{
				if (bih.biCompression == 3) {
					DWORD bitfields[3];

					io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);

					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
				} else {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
				}

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}

				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);

				if(header_only) {
					// header only mode
					return dib;
				}

				if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
					io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
				}

				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				return dib;
			}

			case 24 :
			case 32 :
			{
				if( bit_count == 32 ) {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				} else {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				}

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}
				
				// set resolution information
				FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
				FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);

				if(header_only) {
					// header only mode
					return dib;
				}

				// Skip over the optional palette 
				// A 24 or 32 bit DIB may contain a palette for faster color reduction

				if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
					io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
				}
				
				// read in the bitmap bits
				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				// check if the bitmap contains transparency, if so enable it in the header

				FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));

				return dib;
			}
		}
	} catch(const char *message) {
		if(dib)
			FreeImage_Unload(dib);

		FreeImage_OutputMessageProc(s_format_id, message);
	}

	return NULL;
}

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

static FIBITMAP *
LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
	FIBITMAP *dib = NULL;

	try {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		BITMAPINFOOS2_1X_HEADER bios2_1x;

		io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
		SwapOS21XHeader(&bios2_1x);
#endif
		// keep some general information about the bitmap

		unsigned used_colors = 0;
		unsigned width		= bios2_1x.biWidth;
		unsigned height		= bios2_1x.biHeight;	// WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
		unsigned bit_count	= bios2_1x.biBitCount;
		unsigned pitch		= CalculatePitch(CalculateLine(width, bit_count));
		
		switch (bit_count) {
			case 1 :
			case 4 :
			case 8 :
			{
				used_colors = CalculateUsedPaletteEntries(bit_count);
				
				// allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette

				dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;
				}

				// set resolution information to default values (72 dpi in english units)
				FreeImage_SetDotsPerMeterX(dib, 2835);
				FreeImage_SetDotsPerMeterY(dib, 2835);
				
				// load the palette

				RGBQUAD *pal = FreeImage_GetPalette(dib);

				for (unsigned count = 0; count < used_colors; count++) {
					FILE_BGR bgr;

					io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
					
					pal[count].rgbRed	= bgr.r;
					pal[count].rgbGreen = bgr.g;
					pal[count].rgbBlue	= bgr.b;
				}
				
				if(header_only) {
					// header only mode
					return dib;
				}

				// Skip over the optional palette 
				// A 24 or 32 bit DIB may contain a palette for faster color reduction

				io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
				
				// read the pixel data

				// load pixel data 
				LoadPixelData(io, handle, dib, height, pitch, bit_count);
						
				return dib;
			}

			case 16 :
			{
				dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;						
				}

				// set resolution information to default values (72 dpi in english units)
				FreeImage_SetDotsPerMeterX(dib, 2835);
				FreeImage_SetDotsPerMeterY(dib, 2835);

				if(header_only) {
					// header only mode
					return dib;
				}

				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				return dib;
			}

			case 24 :
			case 32 :
			{
				if( bit_count == 32 ) {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				} else {
					dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				}

				if (dib == NULL) {
					throw FI_MSG_ERROR_DIB_MEMORY;						
				}

				// set resolution information to default values (72 dpi in english units)
				FreeImage_SetDotsPerMeterX(dib, 2835);
				FreeImage_SetDotsPerMeterY(dib, 2835);

				if(header_only) {
					// header only mode
					return dib;
				}

				// Skip over the optional palette 
				// A 24 or 32 bit DIB may contain a palette for faster color reduction

				// load pixel data and swap as needed if OS is Big Endian
				LoadPixelData(io, handle, dib, height, pitch, bit_count);

				// check if the bitmap contains transparency, if so enable it in the header

				FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));

				return dib;
			}
		}
	} catch(const char *message) {	
		if(dib)
			FreeImage_Unload(dib);

		FreeImage_OutputMessageProc(s_format_id, message);
	}

	return NULL;
}

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

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

static const char * DLL_CALLCONV
Description() {
	return "Windows or OS/2 Bitmap";
}

static const char * DLL_CALLCONV
Extension() {
	return "bmp";
}

static const char * DLL_CALLCONV
RegExpr() {
	return "^BM";
}

static const char * DLL_CALLCONV
MimeType() {



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