BMP文件格式詳解(BMP file format)
BMP文件格式,又稱爲Bitmap(位圖)或是DIB(Device-Independent Device,設備無關位圖),是Windows系統中普遍使用的圖像文件格式。因爲它能夠不做任何變換地保存圖像像素域的數據,所以成爲咱們取得RAW數據的重要來源。Windows的圖形用戶界面(graphical user interfaces)也在它的內建圖像子系統GDI中對BMP格式提供了支持。html
下面以Notepad++爲分析工具,結合Windows的位圖數據結構對BMP文件格式進行一個深度的剖析。數組
BMP文件的數據按照從文件頭開始的前後順序分爲四個部分:數據結構
Ø bmp文件頭(bmp file header):提供文件的格式、大小等信息ide
Ø 位圖信息頭(bitmap information):提供圖像數據的尺寸、位平面數、壓縮方式、顏色索引等信息工具
Ø 調色板(color palette):可選,如使用索引來表示圖像,調色板就是索引與其對應的顏色的映射表佈局
Ø 位圖數據(bitmap data):就是圖像數據啦^_^.net
下面結合Windows結構體的定義,經過一個表來分析這四個部分。3d
咱們通常見到的圖像以24位圖像爲主,即R、G、B三種顏色各用8個bit來表示,這樣的圖像咱們稱爲真彩色,這種狀況下是不須要調色板的,也就是所位圖信息頭後面緊跟的就是位圖數據了。所以,咱們經常見到有這樣一種說法:位圖文件從文件頭開始偏移54個字節就是位圖數據了,這其實說的是24或32位圖的狀況。這也就解釋了咱們按照這種程序寫出來的程序爲何對某些位圖文件沒用了。orm
下面針對一幅特定的圖像進行分析,來看看在位圖文件中這四個數據段的排布以及組成。htm
咱們使用的圖像顯示以下:
這是一幅16位的位圖文件,所以它是含有調色板的。
在拉出圖像數據進行分析以前,咱們首先進行幾個約定:
1. 在BMP文件中,若是一個數據須要用幾個字節來表示的話,那麼該數據的存放字節順序爲「低地址村存放低位數據,高地址存放高位數據」。如數據0x1756在內存中的存儲順序爲:
這種存儲方式稱爲小端方式(little endian) , 與之相反的是大端方式(big endian)。對二者的使用狀況有興趣的能夠深究一下,其中仍是有學問的。
2. 如下全部分析均以字節爲序號單位進行。
下面咱們對從文件中拉出來的數據進行剖析:
1、bmp文件頭
Windows爲bmp文件頭定義了以下結構體:
typedef struct tagBITMAPFILEHEADER
{
UINT16 bfType;
DWORD bfSize;
UINT16 bfReserved1;
UINT16 bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
其中:
對照文件數據咱們看到:
1-2 :424dh = 'BM',表示這是Windows支持的位圖格式。有不少聲稱開頭兩個字節必須爲'BM'纔是位圖文件,從上表來看應爲開頭兩個字節必須爲'BM'纔是Windows位圖文件。
3-5 :00010436h = 66614 B = 65.05 kB,經過查詢文件屬性發現一致。
6-9 :這是兩個保留段,爲0。
A-D:00000436h = 1078。即從文件頭到位圖數據需偏移1078字節。咱們稍後將驗證這個數據。
共有14個字節。
2、位圖信息頭
一樣地,Windows爲位圖信息頭定義了以下結構體:
代碼
對照數據文件:
0E-11:00000028h = 40,這就是說我這個位圖信息頭的大小爲40個字節。前面咱們已經說過位圖信息頭通常有40個字節,既然是這樣,爲何這裏還要給一個字段來講明呢?這裏涉及到一些歷史,其實位圖信息頭本來有不少大小的版本的。咱們看一下下表:
出於兼容性的考慮,大多數應用使用了舊版的位圖信息頭來保存文件。而 OS/2 已通過時了,所以如今最經常使用的格式就僅有V3 header了。所以,咱們在前面說位圖信息頭的大小爲40字節。
12-15:00000100h = 256,圖像寬爲255像素,與文件屬性一致。
16-19:00000100h = 256,圖像高爲255像素,與文件屬性一致。這是一個正數,說明圖像數據是從圖像左下角到右上角排列的。
1A-1B:0001h, 該值總爲1。
1C-1D:0008h = 8, 表示每一個像素佔8個比特,即該圖像共有256種顏色。
1E-21:00000000h,BI_RGB, 說明本圖像不壓縮。
22-25:00000000h,圖像的大小,由於使用BI_RGB,因此設置爲0。
26-29:00000000h,水平分辨率,缺省。
2A-2D:00000000h,垂直分辨率,缺省。
2E-31:00000100h = 256,說明本位圖實際使用的顏色索引數爲256,與1C-ID獲得的結論一致。
32-35:00000100h = 256,說明本位圖重要的顏色索引數爲256,與前面獲得的結論一致。
3、調色板
下面的數據就是調色板了。前面也已經提過,調色板實際上是一張映射表,標識顏色索引號與其表明的顏色的對應關係。它在文件中的佈局就像一個二維數組palette[N][4],其中N表示總的顏色索引數,每行的四個元素分別表示該索引對應的B、G、R和Alpha的值,每一個份量佔一個字節。如不設透明通道時,Alpha爲0。由於前面知道,本圖有256個顏色索引,所以N = 256。索引號就是所在行的行號,對應的顏色就是所在行的四個元素。這裏截取一些數據來講明:
索引:(藍,綠,紅,Alpha)
0號:(fe,fa,fd,00)
1號:(fd,f3,fc,00)
2號:(f4,f3,fc,00)
3號:(fc,f2,f4,00)
4號:(f6,f2,f2,00)
5號:(fb,f9,f6,00) 等等。
一共有256種顏色,每一個顏色佔用4個字節,就是一共1024個字節,再加上前面的文件信息頭和位圖信息頭的54個字節加起來一共是1078個字節。也就是說在位圖數據出現以前一共有1078個字節,與咱們在文件信息頭獲得的信息:文件頭到文圖數據區的偏移爲1078個字節一致!
4、位圖數據
下面就是位圖數據了,每一個像素佔一個字節,取得這個字節後,以該字節爲索引查詢相應的顏色,並顯示到相應的顯示設備上就能夠了。
注意:因爲位圖信息頭中的圖像高度是正數,因此位圖數據在文件中的排列順序是從左下角到右上角,以行爲主序排列的。
也即咱們見到的第一個像素60是圖像最左下角的數據,第二我的像素60爲圖像最後一行第二列的數據,…一直到最後一行的最後一列數據,後面緊接的是倒數第二行的第一列的數據,依此類推。
若是圖像是24位或是32位數據的位圖的話,位圖數據區就不是索引而是實際的像素值了。下面說明一下,此時位圖數據區的每一個像素的RGB顏色陣列排布:
24位RGB按照BGR的順序來存儲每一個像素的各顏色通道的值,一個像素的全部顏色份量值都存完後才存下一個下一個像素,不進行交織存儲。
32位數據按照BGRA的順序存儲,其他與24位位圖的方式同樣。
像素的排布規則與前述一致。
對齊規則
講完了像素的排列規則以及各像素的顏色份量的排列規則,最後咱們談談數據的對齊規則。咱們知道Windows默認的掃描的最小單位是4字節,若是數據對齊知足這個值的話對於數據的獲取速度等都是有很大的增益的。所以,BMP圖像順應了這個要求,要求每行的數據的長度必須是4的倍數,若是不夠須要進行比特填充(以0填充),這樣能夠達到按行的快速存取。這時,位圖數據區的大小就未必是 圖片寬×每像素字節數×圖片高 能表示的了,由於每行可能還須要進行比特填充。
填充後的每行的字節數爲:
,其中BPP(Bits Per Pixel)爲每像素的比特數。
在程序中,咱們能夠表示爲:
int iLineByteCnt = (((m_iImageWidth * m_iBitsPerPixel) + 31) >> 5) << 2;
這樣,位圖數據區的大小爲:
m_iImageDataSize = iLineByteCnt * m_iImageHeight;
咱們在掃描完一行數據後,也可能接下來的數據並非下一行的數據,可能須要跳過一段填充數據:
skip = 4 - ((m_iImageWidth * m_iBitsPerPixel)>>3) & 3;
5、拾遺
至此,咱們經過分析一個具體的位圖文件例子詳細地剖析了位圖文件的組成。須要注意的是:咱們講的主要是PC機上的位圖文件的構成,對於嵌入式平臺,可能在調色板數據段與PC機的不一樣。如在嵌入式平臺上常見的16位r5g6b5位圖實際上採用的掩模的方式而不是索引的方式來表示圖像。此時,在調色板數據段共有四個部分,每一個部分爲四個字節,實際表示的是彩色版規範。即:
第一個部分是紅色份量的掩模
第二個部分是綠色份量的掩模
第三個部分是藍色份量的掩模
第四個部分是Alpha份量的掩模(缺省爲0)
典型的調色板規範在文件中的順序爲爲:
00F8 0000 E007 0000 1F00 0000 0000 0000
其中
00F8 0000爲FB00h=1111100000000000(二進制),是藍紅份量的掩碼。
E007 0000爲 07E0h=0000011111100000(二進制),是綠色份量的掩碼。
1F00 0000爲001Fh=0000000000011111(二進制),是藍色份量的掩碼。
0000 0000設置爲0。
將掩碼跟像素值進行「與」運算再進行移位操做就能夠獲得各色份量值。看看掩碼,就能夠明白事實上在每一個像素值的兩個字節16位中,按從高到低取五、六、5位分別就是r、g、b份量值。取出份量值後把r、g、b值分別乘以八、四、8就能夠補齊每一個份量爲一個字節,再把這三個字節按BGR組合,放入存儲器,就能夠轉換爲24位標準BMP格式了。
這樣咱們假設在位圖數據區有一個像素的數據在文件中表示爲02 F1。這個數據實際上應爲F102:
r = (F102 AND F800) >> 8 = F0h = 240
g= (F102 AND 07E0)>> 3 = 20h = 32
b=(F102 AND 001F) << 3 = 10h =16
至此咱們就能夠顯示了。(本文結束)
參考資源:
1. wiki百科 bmp file format
http://en.wikipedia.org/wiki/BMP_file_format
2. gwwgle的專欄 BMP格式詳解 http://blog.csdn.net/gwwgle/archive/2009/11/06/4775396.aspx
3. 匿名 BMP格式圖像文件詳析http://www.thethirdmedia.com/pc/200407/20040722117029.shtm
4. Singler的專欄位圖文件(BMP)格式分析以及程序實現http://blog.csdn.net/yyfzy/archive/2006/06/10/785945.aspx
轉自:http://www.cnblogs.com/Matrix_Yao/archive/2009/12/02/1615295.html
【FILE HEADER 實例圖解】14 bytes
typedef struct {
/* type : Magic identifier,通常爲BM(0x42,0x4d) */
unsigned short int type;
unsigned int size;/* File size in bytes,所有的檔案大小 */
unsigned short int reserved1, reserved2; /* 保留位 */
unsigned int offset;/* Offset to image data, bytes */
} FILEHEADER;
type:2 bytes,通常都是'B' (0x42)、'M' (0x4D)
size:4 bytes,記錄該BMP檔的大小,0x436 = 1078 bytes
reserved1:保留位,2 bytes
reserved2:保留位,2 bytes
offset:4 bytes,0x36 = 54 bytes
【INFO HEADER 實例圖解】40 bytes
typedef struct {
unsigned int size;/* Info Header size in bytes */
int width,height;/* Width and height of image */
unsigned short int planes;/* Number of colour planes */
unsigned short int bits; /* Bits per pixel */
unsigned int compression; /* Compression type */
unsigned int imagesize; /* Image size in bytes */
int xresolution,yresolution; /* Pixels per meter */
unsigned int ncolours; /* Number of colours */
unsigned int importantcolours; /* Important colours */
} INFOHEADER;
size:4 bytes,0x28 = 40 bytes,表示Info Header的大長度總共 40 bytes
width:4 bytes,0x10 = 16,圖像寬度爲16 pixel
height:4 bytes,0x10 = 16,圖像高度爲16 pixel
planes:2 bytes,0x01 = 1,位元面數爲1
bits:2 bytes,0x20 = 32,每個pixel須要32bits
compression:4 bytes,0表明不壓縮
imagesize:4 bytes,0x400 = 1024 bytes,點陣圖資料大小爲1024 bytes
xresolution:4 bytes,水平解析度
yresolution:4 bytes,垂直解析度
ncolours:4 bytes,點陣圖使用的調色板顏色數
importantcolours:4 bytes,重要的顏色數
【RAW DATA 實例圖解】
剛剛的File Header共14bytes,Info Header爲40bytes,「imagesize」 = 1024 bytes,因此「14 + 40 + 1024 = 1078」, 即等於File Header中「size」的大小。下面我只提取部分的資料,反正所有的檔案,減去Header檔54位元組,剩下的就是點陣圖的資料。
在Info Header中的「bits」爲32 bits,故四個位元組一組,若24 bits,則三個位元組一組,例子中的長寬各爲16,以「Z」字型來看,一列則爲16組,即16 X 4 = 64 bytes。注意的是,圖中是以A、B、C ~ …的讀取順序來解說,但實際上程序所讀取到的一般回是反過來的,即… ~ C、B、A。另外,下圖是以「BGRA」排列。