『Bitmap』圖檔之副檔名使用『.bmp』它非常簡單易讀,記得在2005年學DirextX時寫圖檔分析器就是它.缺點不支持壓縮.8Bit(256色)支持RLF壓縮但只有色彩單調時才有效果否則文檔更大. 不要以為256色已經淘汰,通過更換調色板的顏色可以快速更換顏色依然大有用處.渲染演示程式下載:
BMP文檔由四部分組成:
『Bitmap』文檔結構 |
簡介 |
FILE_HEADER file; |
圖檔的頭部 |
INFO_HEADER info; |
圖檔的信息 |
PALETTEENTRY palette[256]; |
調色板只用於256色.
16Bit、24Bit、32Bit均無調色板 |
PBYTE buffer; |
圖像數據
要在OpenGL中渲染像素『Pixel』要倒轉排成RGB/RGBA順序 |
FILE_HEADER文檔結構 |
簡介 |
WORD type; |
‘MB’ 0x4d42 BMP文檔標記
用於判斷是否BMP文檔 |
DWORD size; |
文檔大小,判斷文檔是否完整 |
WORD reserved1; |
保留 |
WORD reserved2; |
保留 |
DWORD OffBits; |
圖像數據的偏移量(文檔的頭部) |
INFO_HEADER圖檔信息頭部 |
簡介 |
DWORD size; |
圖檔信息頭部的大小 |
LONG width; |
圖檔寬度像素『Pixel』 |
LONG height; |
圖檔高度像素『Pixel』 |
WORD planes; |
平面量,總為1 |
WORD bitCount; |
位圖像素尺寸:
8Bit(256色)支持RLF壓縮
16BIT(分為RGB555與RGB565), 24BIT, 32BIT |
DWORD compression; |
壓縮類型:
0 = RGB
0 = RGB555 0x0RRRRRGGGGGBBBBB
3 = RGB565 0xRRRRRGGGGGGBBBBB
1 = RLE8 (run length encoding)壓縮
2 = RLE4 |
DWORD sizeImage; |
圖檔數據所占空間,若使用RLE壓縮為壓縮後的大細 |
LONG XPelsPerMeter; |
X軸每米像素 |
LONG YPelsPerMeter; |
Y軸每米像素 |
DWORD ClrUsed; |
圖像顏色量 |
DWORD ClrImportant; |
圖像重要顏色量 |
PALETTEENTRY調色板 |
簡介 |
BYTE red; |
紅色 |
BYTE green; |
綠色 |
BYTE blue; |
藍色 |
BYTE flags |
只用於DirectDraw
PC_EXPLICIT:映射到硬件
PC_NOCOLLAPSE:不要映射
PC_RESERVED:保留 |
載入BMP位圖C代碼
bool Load_Bitmap(BITMAP_FILE_PTR bitmap,PBYTE data,int size)
{
int index;
int line_size;// 圖像每行所占的字節數
int pixel_size ;// 像素大小
PBYTE image;
int width ;// 圖寬
int height;// 圖高
// 讀取頭部數據
memcpy(&bitmap->header, data, sizeof(BITMAP_FILE_HEADER));
// 判斷是否是位圖文件
if (bitmap->header.type != BITMAP_ID)
return false;//出錯返回
// 讀取位圖信息的頭部
memcpy(&bitmap->info, data + sizeof(BITMAP_FILE_HEADER), sizeof(BITMAP_INFO_HEADER));
if (bitmap->info.sizeImage == 0)
{
bitmap->info.sizeImage = size – sizeof(BITMAP_FILE_HEADER) – sizeof(BITMAP_INFO_HEADER);
if (bitmap->info.bitCount == 8)
bitmap->info.sizeImage = bitmap->info.sizeImage – MAX_COLORS_PALETTE * sizeof(BITMAP_PALETTEENTRY);
}
//定位圖像數據
image = data + size – (int)bitmap->info.sizeImage;// 相對於文件尾
line_size = bitmap->info.sizeImage / bitmap->info.height;// 圖像每行所占的字節數
pixel_size = bitmap->info.bitCount / 8;// 像素大小
width = bitmap->info.width;// 圖寬
height = abs(bitmap->info.height);// 圖高
// 讀取位圖8或16,32位圖
if (bitmap->info.bitCount == 8)
{ // 讀取位圖的調色板
PBYTE palette = data + sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER);
// RGBQUAD結構與PALETTEENTRY結構的順序調轉了
for (index = 0; index < MAX_COLORS_PALETTE; index++)
{//掉轉紅色和綠色
bitmap->palette[index].red = palette[index * 4 + 2];
bitmap->palette[index].green = palette[index * 4 + 1];
bitmap->palette[index].blue = palette[index * 4 + 0];
bitmap->palette[index].flags = PC_NOCOLLAPSE;
}
//根據位圖影像的大小生請空間
bitmap->buffer = (UCHAR *)malloc(abs(bitmap->info.width * bitmap->info.height * 3));
if (bitmap->buffer == NULL)
return false;//出錯返回
PBYTE buffer = NULL;
if (bitmap->info.compression == BITMAP_COMPRESSION_RLE8)
{
buffer = (PBYTE)malloc(abs(bitmap->info.width * bitmap->info.height));
Load_RLE8_Bitmap(buffer, image, bitmap->info.sizeImage, bitmap->info.width);// RLE解碼
image = buffer;
}
// 現在將索引值值轉為24BIT
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
index = y * width + x;
int color = image[index];
bitmap->buffer[index * 3 + 0] = bitmap->palette[color].red;
bitmap->buffer[index * 3 + 1] = bitmap->palette[color].green;
bitmap->buffer[index * 3 + 2] = bitmap->palette[color].blue;
}
}
if (bitmap->info.compression == BITMAP_COMPRESSION_RLE8)
free(buffer);
//最後將位圖位數變為24位
bitmap->info.bitCount = 24;
}
else
if (bitmap->info.bitCount == 16)// 讀取16位圖
{ // 以24BIT分配記憶體空間
bitmap->buffer = (UCHAR *)malloc(abs(bitmap->info.width * bitmap->info.height * 3));
if (bitmap->buffer == NULL)
return false;//出錯返回
if (bitmap->info.compression == 3)
{// RGB565
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{// 現在將各個16位RGB值轉為32位值
index = y * line_size + x * 2;
WORD color = (image[index + 1] << 8) | image[index + 0];
UCHAR red = ((color >> 11) & 0x1f);
UCHAR green = ((color >> 5) & 0x3f);
UCHAR blue = (color & 0x1f);
index = y * width + x;
bitmap->buffer[index * 3 + 0] = (red << 3);
bitmap->buffer[index * 3 + 1] = (green << 2);
bitmap->buffer[index * 3 + 2] = (blue << 3);
}
}
}
else
{// RGB555
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
index = y * line_size + x * 2;
WORD color = (image[index + 1] << 8) | image[index + 0];
UCHAR red = (((color) >> 10) & 0x1f);
UCHAR green = (((color) >> 5) & 0x1f);
UCHAR blue = ((color) & 0x1f);
index = y * width + x;
bitmap->buffer[index * 3 + 0] = (red << 3);
bitmap->buffer[index * 3 + 1] = (green << 3);
bitmap->buffer[index * 3 + 2] = (blue << 3);
}
}
}
//最後將位16BIT變為24BIT
bitmap->info.bitCount = 24;
}
else
if (bitmap->info.bitCount == 24)// 讀取24BIT圖檔
{ // 根據位圖影像的大小申請空間
bitmap->buffer = (UCHAR *)malloc(bitmap->info.sizeImage);
if (bitmap->buffer == NULL)// 申請內存空間失敗
return false;//出錯返回
// 讀取圖像
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{// 轉換GL_RGB模式
index = y * line_size + x * 3;
bitmap->buffer[index + 0] = image[index + 2];//逐個像素地拷貝
bitmap->buffer[index + 1] = image[index + 1];
bitmap->buffer[index + 2] = image[index + 0];
}
}
}
else
if (bitmap->info.bitCount == 32)// 處理32BIT圖檔
{ // 根據位圖影像的大小申請空間
bitmap->buffer = (UCHAR *)malloc(bitmap->info.sizeImage);
if (bitmap->buffer == NULL)//若不能申請空間
return false;//出錯退出
// 像素轉為BGRA 32Bit肯定是4字節對齊
for (index = 0; index < (int)bitmap->info.sizeImage-4; index=index+4)
{
bitmap->buffer[index + 0] = image[index + 2];//逐個像素地拷貝
bitmap->buffer[index + 1] = image[index + 1];
bitmap->buffer[index + 2] = image[index + 0];
bitmap->buffer[index + 3] = image[index + 3];
}
}
else
{
return false;//嚴重文提
}
if (bitmap->info.height < 0)// height為負時表示圖片顛倒
Flip_Bitmap(bitmap->buffer, bitmap->info.width*(bitmap->info.bitCount / 8), bitmap->info.height);
bitmap->info.height = abs(bitmap->info.height);
return true;
}
將顛倒的BMP文件翻轉過來
bool Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
UCHAR *buffer; //用於臨時保存位圖數據.
int index; //循環計數
//分配單行空間
buffer = (UCHAR )malloc(bytes_per_lineheight);
if (buffer == NULL)
return false;
// 單行拷貝
memcpy(buffer, image, bytes_per_line*height);
// 垂直顛倒圖片
for (index = 0; index < height; index++)
memcpy(&image[((height – 1) – index)bytes_per_line], &buffer[indexbytes_per_line], bytes_per_line);
//釋放空間
free(buffer);
return true;//返回
}
你必須登入才能發表留言。