文章屬於轉載:http://zya20050621.blog.163.com/blog/static/64714325201022933455895/
看過很過講BMP文件格式的博客,這篇文章寫的很給力,大讚一把!
BMP文件格式,又稱爲Bitmap(位圖)或是DIB(Device-Independent Device,設備無關位圖),是Windows系統中廣泛使用的圖像文件格式。由於它可以不作任何變換地保存圖像像素域的數據,因此成爲我們取得RAW數據的重要來源。Windows的圖形用戶界面(graphical user interfaces)也在它的內建圖像子系統GDI中對BMP格式提供了支持。
下面以Notepad++爲分析工具,結合Windows的位圖數據結構對BMP文件格式進行一個深度的剖析。
BMP文件的數據按照從文件頭開始的先後順序分爲四個部分:
1、bmp文件頭(bmp file header):提供文件的格式、大小等信息
2、位圖信息頭(bitmap information):提供圖像數據的尺寸、位平面數、壓縮方式、顏色索引等信息
3、調色板(color palette):可選,如使用索引來表示圖像,調色板就是索引與其對應的顏色的映射表
4、位圖數據(bitmap data):就是圖像數據啦^_^
下面結合Windows結構體的定義,通過一個表來分析這四個部分。
我們一般見到的圖像以24位圖像爲主,即R、G、B三種顏色各用8個bit來表示,這樣的圖像我們稱爲真彩色,這種情況下是不需要調色板的,也就是所位圖信息頭後面緊跟的就是位圖數據了。因此,我們常常見到有這樣一種說法:位圖文件從文件頭開始偏移54個字節就是位圖數據了,這其實說的是24或32位圖的情況。這也就解釋了我們按照這種程序寫出來的程序爲什麼對某些位圖文件沒用了。
下面針對一幅特定的圖像進行分析,來看看在位圖文件中這四個數據段的排布以及組成。
我們使用的圖像顯示如下:
這是一幅16位的位圖文件,因此它是含有調色板的。
在拉出圖像數據進行分析之前,我們首先進行幾個約定:
1、在BMP文件中,如果一個數據需要用幾個字節來表示的話,那麼該數據的存放字節順序爲“低地址村存放低位數據,高地址存放高位數據”。如數據0x1756在內存中的存儲順序爲:
這種存儲方式稱爲小端方式(little endian) , 與之相反的是大端方式(big endian)。對兩者的使用情況有興趣的可以深究一下,其中還是有學問的。
2、以下所有分析均以字節爲序號單位進行。
下面我們對從文件中拉出來的數據進行剖析:
一、bmp文件頭
Windows爲bmp文件頭定義瞭如下結構體:
此處說明一下面要用到的數據類型的長度:
UINT16 16bit
WORD 16bit
DWORD 32bit
LONG 32bit
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個字節。
二、位圖信息頭
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
對照數據文件:
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,與前面得到的結論一致。
三、調色板
下面的數據就是調色板了。前面也已經提過,調色板其實是一張映射表,標識顏色索引號與其代表的顏色的對應關係。它在文件中的佈局就像一個二維數組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個字節一致!
四、位圖數據
下面就是位圖數據了,每個像素佔一個字節,取得這個字節後,以該字節爲索引查詢相應的顏色,並顯示到相應的顯示設備上就可以了。
注意:由於位圖信息頭中的圖像高度是正數,所以位圖數據在文件中的排列順序是從左下角到右上角,以行爲主序排列的。
也即我們見到的第一個像素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;
五、拾遺
至此,我們通過分析一個具體的位圖文件例子詳細地剖析了位圖文件的組成。需要注意的是:我們講的主要是PC機上的位圖文件的構成,對於嵌入式平臺,可能在調色板數據段與PC機的不同。如在嵌入式平臺上常見的16位r5g6b5位圖實際上採用的掩模的方式而不是索引的方式來表示圖像。此時,在調色板數據段共有四個部分,每個部分爲四個字節,實際表示的是彩色版規範。即:
第一個部分是紅色分量的掩模
第二個部分是綠色分量的掩模
第三個部分是藍色分量的掩模
第四個部分是Alpha分量的掩模(缺省爲0)
典型的調色板規範在文件中的順序爲爲:
00F8 0000 E007 0000 1F00 0000 0000 0000
其中
00F8 0000爲FB00h=1111100000000000(二進制),是藍紅分量的掩碼。
將掩碼跟像素值進行“與”運算再進行移位操作就可以得到各色分量值。看看掩碼,就可以明白事實上在每個像素值的兩個字節16位中,按從高到低取5、6、5位分別就是r、g、b分量值。取出分量值後把r、g、b值分別乘以8、4、8就可以補齊每個分量爲一個字節,再把這三個字節按BGR組合,放入存儲器,就可以轉換爲24位標準BMP格式了。
這樣我們假設在位圖數據區有一個像素的數據在文件中表示爲02 F1。這個數據實際上應爲F102:
r = (F102 AND F800) >> 8 = F0h = 240
g= (F102 AND 07E0)>> 3 = 20h = 32
至此我們就可以顯示了。(本文結束)
參考資源:
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