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 )