diff options
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginBMP.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/PluginBMP.cpp | 1494 |
1 files changed, 0 insertions, 1494 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp b/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp deleted file mode 100644 index 13206f7b71..0000000000 --- a/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp +++ /dev/null @@ -1,1494 +0,0 @@ -// ========================================================== -// BMP Loader and Writer -// -// Design and implementation by -// - Floris van den Berg (flvdberg@wxs.nl) -// - Markus Loibl (markus.loibl@epost.de) -// - Martin Weber (martweb@gmx.net) -// - Hervé Drolon (drolon@infonie.fr) -// - Michal Novotny (michal@etc.cz) -// -// This file is part of FreeImage 3 -// -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY -// 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" - -// ---------------------------------------------------------- -// Constants + headers -// ---------------------------------------------------------- - -static const BYTE RLE_COMMAND = 0; -static const BYTE RLE_ENDOFLINE = 0; -static const BYTE RLE_ENDOFBITMAP = 1; -static const BYTE RLE_DELTA = 2; - -static const BYTE BI_RGB = 0; // compression: none -static const BYTE BI_RLE8 = 1; // compression: RLE 8-bit/pixel -static const BYTE BI_RLE4 = 2; // compression: RLE 4-bit/pixel -static const BYTE BI_BITFIELDS = 3; // compression: Bit field or Huffman 1D compression for BITMAPCOREHEADER2 -static const BYTE BI_JPEG = 4; // compression: JPEG or RLE-24 compression for BITMAPCOREHEADER2 -static const BYTE BI_PNG = 5; // compression: PNG -static const BYTE BI_ALPHABITFIELDS = 6; // compression: Bit field (this value is valid in Windows CE .NET 4.0 and later) - -// ---------------------------------------------------------- - -#ifdef _WIN32 -#pragma pack(push, 1) -#else -#pragma pack(1) -#endif - -typedef struct tagBITMAPCOREHEADER { - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCnt; -} BITMAPCOREHEADER, *PBITMAPCOREHEADER; - -typedef struct tagBITMAPINFOOS2_1X_HEADER { - DWORD biSize; - WORD biWidth; - WORD biHeight; - WORD biPlanes; - WORD biBitCount; -} BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER; - -typedef struct tagBITMAPFILEHEADER { - WORD bfType; //! The file type - DWORD bfSize; //! The size, in bytes, of the bitmap file - WORD bfReserved1; //! Reserved; must be zero - WORD bfReserved2; //! Reserved; must be zero - DWORD bfOffBits; //! The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits -} BITMAPFILEHEADER, *PBITMAPFILEHEADER; - -#ifdef _WIN32 -#pragma pack(pop) -#else -#pragma pack() -#endif - -// ========================================================== -// Plugin Interface -// ========================================================== - -static int s_format_id; - -// ========================================================== -// Internal functions -// ========================================================== - -#ifdef FREEIMAGE_BIGENDIAN -static void -SwapInfoHeader(BITMAPINFOHEADER *header) { - SwapLong(&header->biSize); - SwapLong((DWORD *)&header->biWidth); - SwapLong((DWORD *)&header->biHeight); - SwapShort(&header->biPlanes); - SwapShort(&header->biBitCount); - SwapLong(&header->biCompression); - SwapLong(&header->biSizeImage); - SwapLong((DWORD *)&header->biXPelsPerMeter); - SwapLong((DWORD *)&header->biYPelsPerMeter); - SwapLong(&header->biClrUsed); - SwapLong(&header->biClrImportant); -} - -static void -SwapCoreHeader(BITMAPCOREHEADER *header) { - SwapLong(&header->bcSize); - SwapShort(&header->bcWidth); - SwapShort(&header->bcHeight); - SwapShort(&header->bcPlanes); - SwapShort(&header->bcBitCnt); -} - -static void -SwapOS21XHeader(BITMAPINFOOS2_1X_HEADER *header) { - SwapLong(&header->biSize); - SwapShort(&header->biWidth); - SwapShort(&header->biHeight); - SwapShort(&header->biPlanes); - SwapShort(&header->biBitCount); -} - -static void -SwapFileHeader(BITMAPFILEHEADER *header) { - SwapShort(&header->bfType); - SwapLong(&header->bfSize); - SwapShort(&header->bfReserved1); - SwapShort(&header->bfReserved2); - SwapLong(&header->bfOffBits); -} -#endif - -// -------------------------------------------------------------------------- - -/** -Load uncompressed image pixels for 1-, 4-, 8-, 16-, 24- and 32-bit dib -@param io FreeImage IO -@param handle FreeImage IO handle -@param dib Image to be loaded -@param height Image height -@param pitch Image pitch -@param bit_count Image bit-depth (1-, 4-, 8-, 16-, 24- or 32-bit) -@return Returns TRUE if successful, returns FALSE otherwise -*/ -static BOOL -LoadPixelData(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int height, unsigned pitch, unsigned bit_count) { - unsigned count = 0; - - // Load pixel data - // NB: height can be < 0 for BMP data - if (height > 0) { - count = io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle); - if(count != 1) { - 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) { - case RLE_COMMAND : - if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) { - return FALSE; - } - - switch (status_byte) { - case RLE_ENDOFLINE : - bits = 0; - scanline++; - break; - - case RLE_ENDOFBITMAP : - return TRUE; - - 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) { - return FALSE; - } - if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) { - return FALSE; - } - - // apply them - - bits += delta_x; - scanline += delta_y; - - break; - } - - default : - { - if(scanline >= abs(height)) { - return TRUE; - } - - int count = MIN((int)status_byte, width - bits); - - BYTE *sline = FreeImage_GetScanLine(dib, scanline); - - if(io->read_proc((void *)(sline + bits), sizeof(BYTE) * count, 1, handle) != 1) { - return FALSE; - } - - // align run length to even number of bytes - - if ((status_byte & 1) == 1) { - if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) { - return FALSE; - } - } - - bits += status_byte; - - break; - } - } - - break; - - default : - { - if(scanline >= abs(height)) { - return TRUE; - } - - 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() { - return "image/bmp"; -} - -static BOOL DLL_CALLCONV -Validate(FreeImageIO *io, fi_handle handle) { - BYTE bmp_signature1[] = { 0x42, 0x4D }; - BYTE bmp_signature2[] = { 0x42, 0x41 }; - BYTE signature[2] = { 0, 0 }; - - io->read_proc(signature, 1, sizeof(bmp_signature1), handle); - - if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0) - return TRUE; - - if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0) - return TRUE; - - return FALSE; -} - -static BOOL DLL_CALLCONV -SupportsExportDepth(int depth) { - return ( - (depth == 1) || - (depth == 4) || - (depth == 8) || - (depth == 16) || - (depth == 24) || - (depth == 32) - ); -} - -static BOOL DLL_CALLCONV -SupportsExportType(FREE_IMAGE_TYPE type) { - return (type == FIT_BITMAP) ? TRUE : FALSE; -} - -static BOOL DLL_CALLCONV -SupportsNoPixels() { - return TRUE; -} - -// ---------------------------------------------------------- - -static FIBITMAP * DLL_CALLCONV -Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { - if (handle != NULL) { - BITMAPFILEHEADER bitmapfileheader; - DWORD type = 0; - - // we use this offset value to make seemingly absolute seeks relative in the file - - long offset_in_file = io->tell_proc(handle); - - // read the fileheader - - io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle); -#ifdef FREEIMAGE_BIGENDIAN - SwapFileHeader(&bitmapfileheader); -#endif - - // check the signature - - if((bitmapfileheader.bfType != 0x4D42) && (bitmapfileheader.bfType != 0x4142)) { - FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER); - return NULL; - } - - // read the first byte of the infoheader - - io->read_proc(&type, sizeof(DWORD), 1, handle); - io->seek_proc(handle, 0 - (long)sizeof(DWORD), SEEK_CUR); -#ifdef FREEIMAGE_BIGENDIAN - SwapLong(&type); -#endif - - // call the appropriate load function for the found bitmap type - - switch(type) { - case 12: - // OS/2 and also all Windows versions since Windows 3.0 - return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); - - case 64: - // OS/2 - return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); - - case 40: // BITMAPINFOHEADER - all Windows versions since Windows 3.0 - case 52: // BITMAPV2INFOHEADER (undocumented, partially supported) - case 56: // BITMAPV3INFOHEADER (undocumented, partially supported) - case 108: // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (partially supported) - case 124: // BITMAPV5HEADER - Windows 98/2000 and newer (partially supported) - return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits, type); - - default: - break; - } - - FreeImage_OutputMessageProc(s_format_id, "unknown bmp subtype with id %d", type); - } - - return NULL; -} - -// ---------------------------------------------------------- - -/** -Encode a 8-bit source buffer into a 8-bit target buffer using a RLE compression algorithm. -The size of the target buffer must be equal to the size of the source buffer. -On return, the function will return the real size of the target buffer, which should be less that or equal to the source buffer size. -@param target 8-bit Target buffer -@param source 8-bit Source buffer -@param size Source/Target input buffer size -@return Returns the target buffer size -*/ -static int -RLEEncodeLine(BYTE *target, BYTE *source, int size) { - BYTE buffer[256]; - int buffer_size = 0; - int target_pos = 0; - - for (int i = 0; i < size; ++i) { - if ((i < size - 1) && (source[i] == source[i + 1])) { - // find a solid block of same bytes - - int j = i + 1; - int jmax = 254 + i; - - while ((j < size - 1) && (j < jmax) && (source[j] == source[j + 1])) - ++j; - - // if the block is larger than 3 bytes, use it - // else put the data into the larger pool - - if (((j - i) + 1) > 3) { - // don't forget to write what we already have in the buffer - - switch(buffer_size) { - case 0 : - break; - - case RLE_DELTA : - target[target_pos++] = 1; - target[target_pos++] = buffer[0]; - target[target_pos++] = 1; - target[target_pos++] = buffer[1]; - break; - - case RLE_ENDOFBITMAP : - target[target_pos++] = (BYTE)buffer_size; - target[target_pos++] = buffer[0]; - break; - - default : - target[target_pos++] = RLE_COMMAND; - target[target_pos++] = (BYTE)buffer_size; - memcpy(target + target_pos, buffer, buffer_size); - - // prepare for next run - - target_pos += buffer_size; - - if ((buffer_size & 1) == 1) - target_pos++; - - break; - } - - // write the continuous data - - target[target_pos++] = (BYTE)((j - i) + 1); - target[target_pos++] = source[i]; - - buffer_size = 0; - } else { - for (int k = 0; k < (j - i) + 1; ++k) { - buffer[buffer_size++] = source[i + k]; - - if (buffer_size == 254) { - // write what we have - - target[target_pos++] = RLE_COMMAND; - target[target_pos++] = (BYTE)buffer_size; - memcpy(target + target_pos, buffer, buffer_size); - - // prepare for next run - - target_pos += buffer_size; - buffer_size = 0; - } - } - } - - i = j; - } else { - buffer[buffer_size++] = source[i]; - } - - // write the buffer if it's full - - if (buffer_size == 254) { - target[target_pos++] = RLE_COMMAND; - target[target_pos++] = (BYTE)buffer_size; - memcpy(target + target_pos, buffer, buffer_size); - - // prepare for next run - - target_pos += buffer_size; - buffer_size = 0; - } - } - - // write the last bytes - - switch(buffer_size) { - case 0 : - break; - - case RLE_DELTA : - target[target_pos++] = 1; - target[target_pos++] = buffer[0]; - target[target_pos++] = 1; - target[target_pos++] = buffer[1]; - break; - - case RLE_ENDOFBITMAP : - target[target_pos++] = (BYTE)buffer_size; - target[target_pos++] = buffer[0]; - break; - - default : - target[target_pos++] = RLE_COMMAND; - target[target_pos++] = (BYTE)buffer_size; - memcpy(target + target_pos, buffer, buffer_size); - - // prepare for next run - - target_pos += buffer_size; - - if ((buffer_size & 1) == 1) - target_pos++; - - break; - } - - // write the END_OF_LINE marker - - target[target_pos++] = RLE_COMMAND; - target[target_pos++] = RLE_ENDOFLINE; - - // return the written size - - return target_pos; -} - -static BOOL DLL_CALLCONV -Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { - if ((dib != NULL) && (handle != NULL)) { - // write the file header - - BITMAPFILEHEADER bitmapfileheader; - bitmapfileheader.bfType = 0x4D42; - bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD); - bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib); - bitmapfileheader.bfReserved1 = 0; - bitmapfileheader.bfReserved2 = 0; - - // take care of the bit fields data of any - - bool bit_fields = (FreeImage_GetBPP(dib) == 16); - - if (bit_fields) { - bitmapfileheader.bfSize += 3 * sizeof(DWORD); - bitmapfileheader.bfOffBits += 3 * sizeof(DWORD); - } - -#ifdef FREEIMAGE_BIGENDIAN - SwapFileHeader(&bitmapfileheader); -#endif - if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) - return FALSE; - - // update the bitmap info header - - BITMAPINFOHEADER bih; - memcpy(&bih, FreeImage_GetInfoHeader(dib), sizeof(BITMAPINFOHEADER)); - - if (bit_fields) - bih.biCompression = BI_BITFIELDS; - else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE)) - bih.biCompression = BI_RLE8; - else - bih.biCompression = BI_RGB; - - // write the bitmap info header - -#ifdef FREEIMAGE_BIGENDIAN - SwapInfoHeader(&bih); -#endif - if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) - return FALSE; - - // write the bit fields when we are dealing with a 16 bit BMP - - if (bit_fields) { - DWORD d; - - d = FreeImage_GetRedMask(dib); - - if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) - return FALSE; - - d = FreeImage_GetGreenMask(dib); - - if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) - return FALSE; - - d = FreeImage_GetBlueMask(dib); - - if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) - return FALSE; - } - - // write the palette - - if (FreeImage_GetPalette(dib) != NULL) { - RGBQUAD *pal = FreeImage_GetPalette(dib); - FILE_BGRA bgra; - for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) { - bgra.b = pal[i].rgbBlue; - bgra.g = pal[i].rgbGreen; - bgra.r = pal[i].rgbRed; - bgra.a = pal[i].rgbReserved; - if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) - return FALSE; - } - } - - // write the bitmap data... if RLE compression is enable, use it - - unsigned bpp = FreeImage_GetBPP(dib); - if ((bpp == 8) && (flags & BMP_SAVE_RLE)) { - BYTE *buffer = (BYTE*)malloc(FreeImage_GetPitch(dib) * 2 * sizeof(BYTE)); - - for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) { - int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib)); - - if (io->write_proc(buffer, size, 1, handle) != 1) { - free(buffer); - return FALSE; - } - } - - buffer[0] = RLE_COMMAND; - buffer[1] = RLE_ENDOFBITMAP; - - if (io->write_proc(buffer, 2, 1, handle) != 1) { - free(buffer); - return FALSE; - } - - free(buffer); -#ifdef FREEIMAGE_BIGENDIAN - } else if (bpp == 16) { - int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(WORD); - WORD pad = 0; - WORD pixel; - for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { - BYTE *line = FreeImage_GetScanLine(dib, y); - for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { - pixel = ((WORD *)line)[x]; - SwapShort(&pixel); - if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1) - return FALSE; - } - if(padding != 0) { - if(io->write_proc(&pad, padding, 1, handle) != 1) { - return FALSE; - } - } - } -#endif -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB - } else if (bpp == 24) { - int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(FILE_BGR); - DWORD pad = 0; - FILE_BGR bgr; - for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { - BYTE *line = FreeImage_GetScanLine(dib, y); - for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { - RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x; - bgr.b = triple->rgbtBlue; - bgr.g = triple->rgbtGreen; - bgr.r = triple->rgbtRed; - if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1) - return FALSE; - } - if(padding != 0) { - if(io->write_proc(&pad, padding, 1, handle) != 1) { - return FALSE; - } - } - } - } else if (bpp == 32) { - FILE_BGRA bgra; - for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { - BYTE *line = FreeImage_GetScanLine(dib, y); - for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { - RGBQUAD *quad = ((RGBQUAD *)line)+x; - bgra.b = quad->rgbBlue; - bgra.g = quad->rgbGreen; - bgra.r = quad->rgbRed; - bgra.a = quad->rgbReserved; - if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) - return FALSE; - } - } -#endif - } else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) { - return FALSE; - } - - return TRUE; - } else { - return FALSE; - } -} - -// ========================================================== -// Init -// ========================================================== - -void DLL_CALLCONV -InitBMP(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 = RegExpr; - plugin->open_proc = NULL; - plugin->close_proc = NULL; - plugin->pagecount_proc = NULL; - plugin->pagecapability_proc = NULL; - plugin->load_proc = Load; - plugin->save_proc = Save; - 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 = NULL; // not implemented yet; - plugin->supports_no_pixels_proc = SupportsNoPixels; -} |