*******************************************
《簡介》
點陣圖(bitmap)格式是 Windows 採用的圖像檔案儲存格式,在 Windows 環境下運行的所有圖像處理軟件都支持這種格式。Windows 3.0 以前的 BMP 格式與顯示設備有關,因此稱為設備相關點陣圖(Device-Dependent Bitmap, DDB)格式。Windows 3.0 以後的 BMP 格式則與顯示設備無關(Device-Independent Bitmap, DIB),目的是為了讓 Windows 能夠在任何類型的顯示設備上顯示點陣圖檔案。點陣圖檔案的預設副檔名是 BMP 或 bmp。
*******************************************
《點陣圖檔案結構》
點陣圖檔案由四個部份組成:
- Bitmap File Header
- Bitmap Info Header
- Color Table (Palette)
- Bitmap Array
Note: 以下欄位資料皆為 little-endian!
Little-Endian 的意思是:若某個欄位值為 0x1234,當你將BMP檔案用 UltraEdit 之類的純文字編輯器打開時,則你看到的值會是 0x3412,這是 Intel 制定的儲存方式,把值小的位元組(0x34)存在前面;詳情可參考 Big Endian 和 Little Endian 架構的說明
| Shift | Name | Size (bytes) | Content | |
| Bitmap File Header | 0000h | Identifier (ID) | 2 | 'BM'【註1】 |
| 0002h | File Size | 4 | 整個點陣圖檔案的大小(單位:byte) | |
| 0006h | Reserved | 4 | 保留欄位 | |
| 000Ah | Bitmap Data Offset | 4 | 點陣圖資料開始之前的偏移量(單位:byte) | |
| Bitmap Info Header | 000Eh | Bitmap Header Size | 4 | Bitmap Info Header 的長度【註2】 |
| 0012h | Width | 4 | 點陣圖的寬度,以像素(pixel)為單位 | |
| 0016h | Height | 4 | 點陣圖的高度,以像素(pixel)為單位【註3】 | |
| 001Ah | Planes | 2 | 點陣圖的位元圖層數【註4】 | |
| 001Ch | Bits Per Pixel | 2 | 每個像素的位元數 1:單色點陣圖(使用 2 色調色盤) 4:4 位元點陣圖(使用 16 色調色盤) 8:8 位元點陣圖(使用 256 色調色盤) 16:16 位元高彩點陣圖(不一定使用調色盤) 24:24 位元全彩點陣圖(不使用調色盤) 32:32 位元全彩點陣圖(不一定使用調色盤) 【註5】 | |
| 001Eh | Compression | 4 | 壓縮方式【註6】: 0:未壓縮 1:RLE 8-bit/pixel 2:RLE 4-bit/pixel 3:Bitfields | |
| 0022h | Bitmap Data Size | 4 | 點陣圖資料的大小(單位:byte)【註7】。 | |
| 0026h | H-Resolution | 4 | 水平解析度(單位:像素/公尺)【註8】 | |
| 002Ah | V-Resolution | 4 | 垂直解析度(單位:像素/公尺) | |
| 002Eh | Used Colors | 4 | 點陣圖使用的調色盤顏色數【註9】 | |
| 0032h | Important Colors | 4 | 重要的顏色數【註10】 | |
| Palette | 0036h | Palette | N*4 | 調色盤資料。 每個索引值指定一種顏色:0x00RRGGBB 其中最高位元組保留為零 |
| Bitmap Array | - | Bitmap Data | - | 點陣圖資料【註11】 |
【註1】此欄原本有多種識別碼,用來識別點陣圖的類型:
'BM' - Windows 3.1x, 95, NT, ...
'BA' - OS/2 Bitmap Array
'CI' - OS/2 Color Icon
'CP' - OS/2 Color Pointer
'IC' - OS/2 Icon
'PT' - OS/2 Pointer
不過既然 OS/2 並不普及,目前皆在 Windows 上作業,因此 ID 全都是 'BM'。
【註2】此欄原本有多種數值,依作業系統種類而定:
28h - Windows 3.1x, 95, NT, ...
0Ch - OS/2 1.x
F0h - OS/2 2.x
以目前 Windows 常用的點陣圖來說,此欄位數值通常是 28h。
但因為微軟已經制定出了新的點陣圖格式,其中的 Bitmap Info Header 結構變化較大,長度加長,所以最好不要直接使用常數 28h,而是應該從實際檔案中讀取這個數值,才能確保程式相容性。
【註3】高度可能為負值,負值表示掃瞄方向由上而下。
但若高度是負值時,此點陣圖將不能被壓縮!(也就是說 Compression 欄位總是為 0)
【註5】16 及 32 位元點陣圖是否使用調色盤必須由 Compression 欄位的數值決定,
請參考 Bitfields 的解說。
【註6】點陣圖壓縮方式有以下四種:BI_RGB,BI_RLE8,BI_RLE4,以及BI_BITFIELDS。
- None (BI_RGB)
表示此點陣圖資料沒有壓縮,不使用調色盤。
- RLE 8bpp (BI_RLE8)
每個像素為 8 bit 的 RLE 壓縮編碼(Run-Length Encoding)(總共可使用 256 色)。
有「編碼模式」(Encoded Mode)和「絕對模式」(Absolute Mode)兩種方法,
可在同一幅圖檔中的任何地方交錯使用。
「編碼模式」:由兩個位元組(byte)組成。
第一個位元組指定 "Length"(使用相同顏色的像素數目),
第二個位元組指定 "Run"(此像素使用的調色盤索引)。
若第一個位元組為零,則表示特殊意義:
0x0000 - 表示此列結束
0x0001 - 表示此點陣圖檔案結束
0x0002 - 表示其後的兩位元組分別表示
下個像素位置與目前像素位置的水平/垂直偏移量。
0x000x - 表示絕對模式。
「絕對模式」:第一個位元組為 0x00,第二個位元組為 0x03 ~ 0xFF 之間的數值。
其中第二個位元組表示後續資料的長度(單位為 byte),
後續資料的每個位元組都表示單一像素的調色盤索引值。
每一模式的編碼長度都必須與字邊界對齊(word-aligned),也就是 2 的倍數。
使用「編碼模式」時,由於每組編碼皆為兩個位元組,所以毋需多加處理;
但是使用「絕對模式」時,則必須在最後補上適當的 0x00 以使資料長度對齊 2 的倍數。
下面是一個 BI_RLE8 的例子:
03 01 05 02 00 03 00 01 02 00 02 01 00 02 05 01 02 03 00 00 09 02 00 01
這些資料可解讀為:
壓縮資料 解壓縮之後的資料 03 01 01 01 01 05 02 02 02 02 02 02 00 03 00 01 02 00 00 01 02(最後的 00 是為了 word-aligned 才補上的) 02 01 01 01 00 02 05 01 從目前位置右移 5 像素之後,向下移一列 02 03 03 03 00 00 此列結束 09 02 02 02 02 02 02 02 02 02 02 00 01 此點陣圖結束 上述資料的圖形如下:
- RLE 4bpp (BI_RLE4)
每個像素為 4-bit 的 RLE 壓縮編碼(總共可使用 16 色)。
同樣也有「編碼模式」與「絕對模式」,且可以在同一圖檔中任何地方使用任一模式。
「編碼模式」:由兩個位元組組成。
第一個位元組指定像素數目,
第二個位元組包含兩個調色盤索引:
第一個像素使用高 4 位元的索引值、
第二個像素使用低 4 位元的索引值、
第三個像素又使用高 4 位元的索引值,以此類推。
若第一個位元組為零,則表示特殊意義:
0x0000 - 表示此列結束
0x0001 - 表示此點陣圖檔案結束
0x0002 - 表示其後的兩位元組分別表示
下個像素位置與目前像素位置的水平/垂直偏移量。
0x000x - 表示絕對模式。
「絕對模式」:第一個位元組為 0x00,第二個位元組表示後續資料的長度(單位為 byte)。
後續資料的每個位元組都含有兩個調色盤索引值(高 4 及低 4 位元),
每個索引值對應一個像素。
每一模式的編碼長度仍然必須與字邊界對齊(word-aligned)。
使用「編碼模式」時,由於每組編碼皆為兩個位元組,所以毋需多加處理;
但是使用「絕對模式」時,則必須在最後補上適當的 0 以使資料長度對齊 2 的倍數。
下面是一個 BI_RLE4 的例子:
03 11 05 02 00 05 01 23 10 00 02 22 00 02 05 01 02 13 00 00 09 10 00 01
這些資料可解讀為:
壓縮資料 解壓縮之後的資料 03 11 1 1 1 05 02 0 2 0 2 0 00 05 01 23 10 00 0 1 2 3 1(最後的 0 00 是為了 word-aligned 才補上的) 02 22 2 2 00 02 05 01 從目前位置右移 5 像素之後,向下移一列 02 13 1 3 00 00 此列結束 09 10 1 0 1 0 1 0 1 0 1 00 01 此點陣圖結束 上述資料的圖形如下:
- Bitfileds (BI_BITFIELDS)
只有當「Bit Per Pixel」欄位的數值為 16 或 32 時,才會使用 BI_BITFIELDS 這種格式。
使用 BI_BITFIELDS 時,點陣圖檔中原本的調色盤位置會被三個 DWORD 佔據,
分別代表 R、G、B 三個顏色分量的遮罩(mask)。
例如:- Bit_Per_Pixel = 16, Compression = BI_RGB(無壓縮),
則每個像素的 16 位元之中:
最低 5 位元表示藍色分量,
中間 5 位元表示綠色分量,
接著的高 5 位元則是紅色分量,
最高的 1 位元保留不使用。
此格式即為 RGB555 格式。
- Bit_Per_Pixel = 16, Compression = BI_BITFIELDS,
紅、綠、藍的 mask 分別為 0xF800, 0x07E0, 0x001F,
則每個像素的 16 位元之中:
最低 5 位元表示藍色分量,
中間 6 位元表示綠色分量,
最高 5 位元則是紅色分量,
此格式即為 RGB565 格式。
- Bit_Per_Pixel = 16, Compression = BI_RGB(無壓縮),
【註7】若沒有壓縮(Compression 欄位為 0),則此欄數值可設為 0。
(我發現許多繪圖軟體根本不看此欄數值,隨便填寫也無所謂,圖檔仍可正常開啟)
【註8】若要換算為 dpi,則將此欄數值要除以39.37(吋/公尺)
例如,此欄數值若為 2834 (pixels per meter),
則 2834 ÷ 39.37 = 72 (pixels per inch) = 72 dpi
【註9】此欄表示圖檔實際使用的顏色數目,若數值為 0,表示使用所有調色盤顏色。
如果此欄數值並非「可用顏色的最大值」或者「零」,則需注意調色盤尺寸的計算。
例如,在 4 bpp bitmap 中,調色盤預設尺寸應是 16*4 bytes,
但若 Used Color 欄位數值並非 16 或 0,則調色盤尺寸應是 Used_Color_Number * 4 (bytes)。
【註10】當此欄的值等於「顏色數」或者為 0 時,表示所有顏色都一樣重要。
【註11】緊跟在調色盤之後的就是點陣圖資料陣列。
每一掃描列的長度取決於圖檔的寬度及顏色深度(Color Depth),
但是每一掃描列的長度必需是 4 byte 的倍數(DWORD-aligned)!
正常的點陣圖掃描列是由底向上儲存的:
陣列中的第一個 byte 表示全圖左下角的像素,而最後一個 byte 則表示全圖右上角的像素。
但如果是正向掃描(Height 欄位為負值),則掃描方向則是由上而下。
推薦上專欄
訓練日誌



這篇對我實在有用..
終於搞定 16bit RGB565 了.
很棒的整理
比我在其他網站看到的 BMP file format 解釋詳盡多了,借我收錄一下,感謝您的分享!
雖然花了很久才達到目標
但是如果沒了這篇
真的不知如何下手
真是謝謝你啦^^
正在嘗試SetDIBitsToDevice囧
感謝你的整理
因為這篇完整的介紹才讓我順利解決影像處理的作業
大感謝
非常有幫助。
不過,可否請問版大如果bitmap的深度只有1bit(黑白圖檔), 那麼讀取點陣圖陣列的方式會有所不同嗎?
digital transfer bmp
想請問大大你知要怎麼把01digital 訊號寫成.bmp的file嗎?請問一個問題
因為最近在研究bmp的東西.因此有緣拜訪這個網站,感謝大大的無私分享,讓我受益良多.可是我有一個小問題.就是我在小畫家開一個圖檔,然後存成24位元點陣圖檔(*.bmp),他的格式裡面就沒有Palette,如果用有palteet的方法去解會有問題.請問大大有關這一類型的檔案我們要怎麼樣去區隔他呢?感恩喔.感謝
感謝大大的回應.我剛剛再檢查一遍.發現是我會錯意,24是沒有調色盤的.感謝大大的指正.還有可以再請教一個問題嗎.請問大大你有聽過EMSBMP這種格式嗎?再問一個問題..^^"
在RLE解壓縮的時候,會有一個位移的指令(0x0002),我想請問在位移的之間的顏色要填什麼呢?index=0的顏色還是有背景顏色呢?以小貓的範例來看,看起來像是先把整個buffer填成index=0的顏色後再來decode,請問是這樣嗎.感恩..^^關於Palette
您好, 我正在把一個received 16-bit bitmap data加上一個header. But I find difficulty to write the "palette part". I'm not sure how to write that part. I tried to add "00 F8 00 00 E0 07 00 00 1F 00 00 00" before the "bitmap array" part. However, the whole pic filtered in yellow. 請問Palette part 怎樣寫才對? 急問. 謝謝!再問一下....
很興奮你這麼快就給我回覆了!!!1. 其實也不清楚是否就這樣就可以把 (0x000000F8,0x0000E007,0x00001F00) 直接加到data和header之間, 但就姑且一試, 結果現在仍未做得到
2. 現在的offset應該是指到對的位置...有check過
3. compression..我用的是c328r camera module, user manual說應該是rgb565的,
所以就用了bitfield, 但bits per pixel就不太清楚該如何定下...可否賜教?
4. 不好意思...因為對著一堆16位數子有點時間了,希望可以問一下...
5. 我們也抱歉...其實你提供的資料真的很有用, 也幫了我們不少, 謝謝你!!!!!^^
謝謝您...
解說的好清楚...最近工作上需要,將YUV420的格式轉成RGB565,想要將RGB565做成bmp檔案,以方便直接在PC上show出來。
運氣真好,一google馬上就連到這兒來,目前RGB555及RGB565已可正常運作。
非常感謝您。:)
感謝你
感謝你的熱心發表, 讓我工作順利許多.可否請教一下, 為何我256 色的BMP 檔中, 純紅是的值0xFC 而不是0xE0呢(RRRGGGBB)?
感謝
解釋得很詳細,幫助很多,謝謝 :)請問關於bmp
請問我用C語言的fopen去開啟bmp檔作處理,處理完後要如何存成另一個檔案的bmp檔呢?關於BMP圖檔
我也是認為fwrite,不過測試後發現了一個很奇怪的問題,我是用BCB寫的,程式碼如下:int main(int argc, char* argv[])
{
unsigned char *temp1;
FILE *fp,*fp2 ;
//int i,j,k,x = 50,y = 60,m,n;
int width = 0,height = 0;
int counter_1,i,j;
fp=fopen("c:\\111.bmp","rb");
fseek(fp,18,0);
fread(&width,sizeof(width),1,fp);
fseek(fp,22,0);
fread(&height,sizeof(height),1,fp);
fseek(fp,0,0); //bmp content
printf("width is %d\n",width);
printf("height is %d\n",height);
temp1 = new unsigned char[height*width*3+54];
counter_1=fread(temp1,sizeof(unsigned char),height*width*3+54,fp);
fclose(fp);
fp2 = fopen("c:\\test.bmp","wb");
counter_1=fwrite(temp1,sizeof(unsigned char),height*width*3+54,fp2);
fclose(fp2);
free(temp1);
getch();
return 0;
}
我用小畫家隨便畫張圖後,檔名取為111.bmp放在C:\底下,然後執行完此程式後會出現test.bmp,可是他圖片用小畫家開啟右上角會多出一條黑線,用windows picture and fax viewer開啟會出現繪圖失敗??
關於BMP圖檔
抱歉,給你帶來困擾,我只是學生,剛好看到這邊有講bmp的東西,所以想問問我碰到的問題,謝謝您的回答,謝謝關於BMP圖檔
至於你說的魔術數字我是想說一張bmp的大小應該是height*width*3 (RGB) 再加上標頭檔54,所以才會出現這個數字的,不過不知道為什麼這個數字會和size有差?這個 BMP 的解說真是詳盡
您的 BMP 解說真是詳盡,被布蘭登同學找到後,以饗同好。我相信這個 2006 年的資料,應該還可以在下一世紀繼續流傳。本篇迴響權限: 開放所有人迴響