BMP 文件格式解析
BMP 文件由文件頭、位圖信息頭、顏色信息和圖形數據四部分組成。
位圖文件頭(14個字節) | 位圖信息頭(40個字節) | 顏色信息 | 圖形數據 |
---|
- 文件頭與信息頭一共是 54 字節
- RGB 數據部分:
RGB24 文件存儲的順序是 RGB, RGB, RGB ...... RGB
BMP 文件 RGB 數據存儲的順序是 BGR, BGR, BGR ... BGR
位圖文件頭
位圖文件頭分 4 部分,共 14 字節
名稱 | 佔用空間 | 內容 | 示例數據 |
---|---|---|---|
bfType | 2字節 | 標識,就是“BM” | BM |
bfSize | 4字節 | 整個 BMP 文件的大小 | 0x000C0036(786486) |
bfReserved1 | 2字節 | 保留字 | 0 |
bfReserved2 | 2字節 | 保留字 | 0 |
bfOffBits | 4字節 | 偏移數,即位圖文件頭+位圖信息頭+調色板的大小 | 0x36(54) |
位圖信息頭
位圖信息頭共 40 字節
名稱 | 佔用空間 | 內容 | 示例數據 |
---|---|---|---|
biSize | 4字節 | 位圖信息頭的大小,爲40 | 0x28(40) |
biWidth | 4字節 | 位圖的寬度,單位是像素 | 0x200(512) |
biHeight | 4字節 | 位圖的高度,單位是像素 | 0x200(512) |
biPlanes | 2字節 | 固定值1 | 1 |
biBitCount | 2字節 | 每個像素的位數 1-黑白圖,4-16色,8-256色,24-真彩色,32-帶 alpha 通道 | 0x18(24) |
biCompression | 4字節 | 壓縮方式,BI_RGB(0)爲不壓縮 | 0 |
biSizeImage | 4字節 | 位圖全部像素佔用的字節數,BI_RGB時可設爲0 | 0x0C |
biXPelsPerMeter | 4字節 | 水平分辨率(像素/米) | 0 |
biYPelsPerMeter | 4字節 | 垂直分辨率(像素/米) | 0 |
biClrUsed | 4字節 | 位圖使用的顏色數 如果爲0,則顏色數爲2的biBitCount次方 | 0 |
biClrImportant | 4字節 | 重要的顏色數,0代表所有顏色都重要 | 0 |
將 RGB24 像素點數據轉成 BMP 格式圖片
轉換代碼:
#include <stdio.h>
#include <stdlib.h>
// 彩虹的七種顏色
u_int32_t rainbowColors[] = {
0XFF0000, // 紅
0XFFA500, // 橙
0XFFFF00, // 黃
0X00FF00, // 綠
0X007FFF, // 青
0X0000FF, // 藍
0X8B00FF // 紫
};
/*bmp file header*/
typedef struct {
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BitmapFileHeader;
/*bmp info header*/
typedef struct {
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BitmapInfoHeader;
void writeRGBToBmp(char *filename, int width, int height) {
FILE *bitmapFile = fopen(filename, "wb");
if(!bitmapFile) {
printf("Could not write file \n");
return;
}
uint16_t bfType = 0x4d42;
BitmapFileHeader fileHeader;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfSize = 2 + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + width*height*3;
fileHeader.bfOffBits = 0x36;
BitmapInfoHeader infoHeader;
infoHeader.biSize = sizeof(BitmapInfoHeader);
infoHeader.biWidth = width;
infoHeader.biHeight = height;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biSizeImage = 0;
infoHeader.biCompression = 0;
infoHeader.biXPelsPerMeter = 5000;
infoHeader.biYPelsPerMeter = 5000;
infoHeader.biClrUsed = 0;
infoHeader.biClrImportant = 0;
fwrite(&bfType, sizeof(bfType), 1, bitmapFile);
fwrite(&fileHeader, sizeof(fileHeader), 1, bitmapFile);
fwrite(&infoHeader, sizeof(infoHeader), 1, bitmapFile);
// 寫入圖像數據
for (int i = 0; i < width; ++i) {
// 當前顏色
u_int32_t currentColor = rainbowColors[0];
if(i < 100) {
currentColor = rainbowColors[0];
} else if(i < 200) {
currentColor = rainbowColors[1];
} else if(i < 300) {
currentColor = rainbowColors[2];
} else if(i < 400) {
currentColor = rainbowColors[3];
} else if(i < 500) {
currentColor = rainbowColors[4];
} else if(i < 600) {
currentColor = rainbowColors[5];
} else if(i < 700) {
currentColor = rainbowColors[6];
}
// 當前顏色 R 分量
u_int8_t R = (currentColor & 0xFF0000) >> 16;
// 當前顏色 G 分量
u_int8_t G = (currentColor & 0x00FF00) >> 8;
// 當前顏色 B 分量
u_int8_t B = currentColor & 0x0000FF;
for (int j = 0; j < height; ++j) {
// 按 BGR 順序寫入一個像素 RGB24 到文件中
fwrite(&B, 1, 1, bitmapFile);
fwrite(&G, 1, 1, bitmapFile);
fwrite(&R, 1, 1, bitmapFile);
}
}
// 關閉文件
fclose(bitmapFile);
}
int main() {
writeRGBToBmp("/Users/staff/Desktop/rainbow-700x700.bmp", 700, 700);
return 0;
}
檢查生成的 BMP 圖片
Congratulations! 圖片查看軟件識別出我們的 BMP 圖片了,預覽正常!
BUT!好像哪裏不對勁?!我們的彩虹倒過來了!
彩虹的顏色,從上到下應該是:
紅 -> 橙 -> 黃 -> 綠 -> 青 -> 藍 -> 紫
這張圖是:
紫 -> 藍 -> 青 -> 綠 -> 黃 -> 橙 -> 紅
處理圖片倒立問題
BitmapInfoHeader 中的 biHeight 字段,
biHeight 爲正,位圖自底向頂掃描,
biHeight 爲負,位圖自頂向底掃描。
如果這個值的設置和原始位圖文件掃描方式不符,則圖像顯示可能會顛倒。
<br/>
將上面的轉換代碼中,BitmapInfoHeader 部分:
// infoHeader.biHeight = height;
infoHeader.biHeight = -height;
Congratulations!
成功用像素點拼出了一張 “真正” 的圖片!
代碼:
參考資料:
non-dword-aligned-pixel-to-dword-aligned-bitmap
generate-bmp-file-from-array-of-rgb-values
內容有誤?聯繫作者: