📄 pluginbmp.cpp
字号:
// ==========================================================// 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)//// This file is part of FreeImage 2//// 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 <assert.h>#include "thirdparty/common/FreeImage/Source/FreeImage.h"#include "thirdparty/common/FreeImage/Source/Utilities.h"// ----------------------------------------------------------// Constants + headers// ----------------------------------------------------------const int RLE_COMMAND = 0;const int RLE_ENDOFLINE = 0;const int RLE_ENDOFBITMAP = 1;const int RLE_DELTA = 2;#define BI_RGB 0L#define BI_RLE8 1L#define BI_RLE4 2L#define BI_BITFIELDS 3L// ----------------------------------------------------------#ifdef WIN32#pragma pack(push, 1)#else#pragma pack(1)#endiftypedef 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; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER;typedef struct tagRGBTRIPLE { BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed; } RGBTRIPLE; #ifdef WIN32#pragma pack(pop)#else#pragma pack(4)#endif// ==========================================================// Plugin Interface// ==========================================================static int s_format_id;// ==========================================================// Internal functions// ==========================================================static FIBITMAP *LoadWindowsBMP(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { FIBITMAP *dib; try { // load the info header BITMAPINFOHEADER bih; io.read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); // keep some general information about the bitmap int used_colors = bih.biClrUsed; int width = bih.biWidth; int height = bih.biHeight; int bit_count = bih.biBitCount; int compression = bih.biCompression; int pitch = CalculatePitch(CalculateLine(width, bit_count)); switch (bit_count) { case 1 : case 4 : case 8 : { if ((used_colors <= 0) || (used_colors > CalculateUsedColors(bit_count))) used_colors = CalculateUsedColors(bit_count); // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette dib = freeimage.allocate_proc(width, height, bit_count, 0, 0, 0); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; // load the palette io.read_proc(freeimage.get_palette_proc(dib), used_colors * sizeof(RGBQUAD), 1, handle); // 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 * sizeof(RGBQUAD)))) io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); // read the pixel data switch (compression) { case BI_RGB : if (height > 0) { io.read_proc((void *)freeimage.get_bits_proc(dib), height * pitch, 1, handle); } else { for (int c = 0; c < abs(height); ++c) { io.read_proc((void *)freeimage.get_scanline_proc(dib, height - c - 1), pitch, 1, handle); } } return dib; case BI_RLE4 : { BYTE status_byte = 0; BYTE second_byte = 0; int scanline = 0; int bits = 0; BOOL low_nibble = FALSE; for (;;) { io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_COMMAND : io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_ENDOFLINE : bits = 0; scanline++; low_nibble = FALSE; break; case RLE_ENDOFBITMAP : return (FIBITMAP *)dib; case RLE_DELTA : { // read the delta values BYTE delta_x; BYTE delta_y; io.read_proc(&delta_x, sizeof(BYTE), 1, handle); io.read_proc(&delta_y, sizeof(BYTE), 1, handle); // apply them bits += delta_x / 2; scanline += delta_y; break; } default : io.read_proc(&second_byte, sizeof(BYTE), 1, handle); BYTE *sline = freeimage.get_scanline_proc(dib, scanline); for (int i = 0; i < status_byte; i++) { if (low_nibble) { *(sline + bits) |= LOWNIBBLE(second_byte); if (i != status_byte - 1) io.read_proc(&second_byte, sizeof(BYTE), 1, handle); bits++; } else { *(sline + bits) |= HINIBBLE(second_byte); } low_nibble = !low_nibble; } if (((status_byte / 2) & 1 )== 1) io.read_proc(&second_byte, sizeof(BYTE), 1, handle); break; }; break; default : { BYTE *sline = freeimage.get_scanline_proc(dib, scanline); io.read_proc(&second_byte, sizeof(BYTE), 1, handle); for (unsigned i = 0; i < status_byte; i++) { if (low_nibble) { *(sline + bits) |= LOWNIBBLE(second_byte); bits++; } else { *(sline + bits) |= HINIBBLE(second_byte); } low_nibble = !low_nibble; } } break; }; } break; } case BI_RLE8 : { BYTE status_byte = 0; BYTE second_byte = 0; int scanline = 0; int bits = 0; for (;;) { io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_COMMAND : io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_ENDOFLINE : bits = 0; scanline++; break; case RLE_ENDOFBITMAP : return (FIBITMAP *)dib; case RLE_DELTA : { // read the delta values BYTE delta_x; BYTE delta_y; io.read_proc(&delta_x, sizeof(BYTE), 1, handle); io.read_proc(&delta_y, sizeof(BYTE), 1, handle); // apply them bits += delta_x; scanline += delta_y; break; } default : io.read_proc((void *)(freeimage.get_scanline_proc(dib, scanline) + bits), sizeof(BYTE) * status_byte, 1, handle); // align run length to even number of bytes if ((status_byte & 1) == 1) io.read_proc(&second_byte, sizeof(BYTE), 1, handle); bits += status_byte; break; }; break; default : BYTE *sline = freeimage.get_scanline_proc(dib, scanline); io.read_proc(&second_byte, sizeof(BYTE), 1, handle); for (unsigned i = 0; i < status_byte; i++) { *(sline + bits) = second_byte; bits++; } break; }; } break; } default : throw "compression type not supported"; } break; } case 16 : { if (bih.biCompression == BI_BITFIELDS) { DWORD bitfields[3]; io.read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); dib = freeimage.allocate_proc(width, height, bit_count, bitfields[2], bitfields[1], bitfields[0]); } else { dib = freeimage.allocate_proc(width, height, bit_count, 0x1F, 0x3E0, 0x7C00); } if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); return dib; } case 24 : case 32 : { if (bih.biCompression == BI_BITFIELDS) { throw "bitfields in 32-bit BMPs are currently unsupported"; } else { dib = freeimage.allocate_proc(width, height, bit_count, 0xFF, 0xFF00, 0xFF0000); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; // Skip over the optional palette // A 24 or 32 bit DIB may contain a palette for faster color reduction if (pInfoHeader->biClrUsed > 0) io.seek_proc(handle, pInfoHeader->biClrUsed * sizeof(RGBQUAD), SEEK_CUR); // read in the bitmap bits io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); // check if the bitmap contains transparency, if so enable it in the header freeimage.set_transparent_proc(dib, (freeimage.get_color_type_proc(dib) == FIC_RGBALPHA)); return dib; } } } } catch(const char *message) { freeimage.output_message_proc(s_format_id, message); } return NULL;}static FIBITMAP *LoadOS22XBMP(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { FIBITMAP *dib = NULL; try { // load the info header BITMAPINFOHEADER bih; io.read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); // keep some general information about the bitmap int used_colors = bih.biClrUsed; int width = bih.biWidth; int height = bih.biHeight; int bit_count = bih.biBitCount; int compression = bih.biCompression; int pitch = CalculatePitch(CalculateLine(width, bit_count)); switch (bit_count) { case 1 : case 4 : case 8 : { if ((used_colors <= 0) || (used_colors > CalculateUsedColors(bit_count))) used_colors = CalculateUsedColors(bit_count); // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette dib = freeimage.allocate_proc(width, height, bit_count, 0, 0, 0); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; // load the palette io.seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET); RGBQUAD *pal = freeimage.get_palette_proc(dib); for (int count = 0; count < used_colors; count++) { RGBTRIPLE triple; io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); pal[count].rgbRed = triple.rgbtRed; pal[count].rgbGreen = triple.rgbtGreen; pal[count].rgbBlue = triple.rgbtBlue; } // 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 : if (height > 0) { io.read_proc((void *)freeimage.get_bits_proc(dib), height * pitch, 1, handle); } else { for (int c = 0; c < abs(height); ++c) { io.read_proc((void *)freeimage.get_scanline_proc(dib, height - c - 1), pitch, 1, handle); } } return dib; case BI_RLE4 : { BYTE status_byte = 0; BYTE second_byte = 0; int scanline = 0; int bits = 0; BOOL low_nibble = FALSE; for (;;) { io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_COMMAND : io.read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_ENDOFLINE : bits = 0; scanline++; low_nibble = FALSE; break; case RLE_ENDOFBITMAP : return (FIBITMAP *)dib; case RLE_DELTA : { // read the delta values BYTE delta_x; BYTE delta_y; io.read_proc(&delta_x, sizeof(BYTE), 1, handle); io.read_proc(&delta_y, sizeof(BYTE), 1, handle); // apply them bits += delta_x / 2; scanline += delta_y; break; } default :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -