BMP文件格式,,又稱為Bitmap(位圖)或是DIB(Device-Independent Device,,設(shè)備無關(guān)位圖),是Windows系統(tǒng)中廣泛使用的圖像文件格式,。由于它可以不作任何變換地保存圖像像素域的數(shù)據(jù),,因此成為我們?nèi)〉?/span>RAW數(shù)據(jù)的重要來源。Windows的圖形用戶界面(graphical user interfaces)也在它的內(nèi)建圖像子系統(tǒng)GDI中對BMP格式提供了支持,。 下面以Notepad++為分析工具,,結(jié)合Windows的位圖數(shù)據(jù)結(jié)構(gòu)對BMP文件格式進(jìn)行一個深度的剖析。 BMP文件的數(shù)據(jù)按照從文件頭開始的先后順序分為四個部分: Ø bmp文件頭(bmp file header):提供文件的格式,、大小等信息 Ø 位圖信息頭(bitmap information):提供圖像數(shù)據(jù)的尺寸,、位平面數(shù)、壓縮方式,、顏色索引等信息 Ø 調(diào)色板(color palette):可選,,如使用索引來表示圖像,,調(diào)色板就是索引與其對應(yīng)的顏色的映射表 Ø 位圖數(shù)據(jù)(bitmap data):就是圖像數(shù)據(jù)啦^_^ 下面結(jié)合Windows結(jié)構(gòu)體的定義,通過一個表來分析這四個部分,。 我們一般見到的圖像以24位圖像為主,,即R、G,、B三種顏色各用8個bit來表示,,這樣的圖像我們稱為真彩色,這種情況下是不需要調(diào)色板的,,也就是所位圖信息頭后面緊跟的就是位圖數(shù)據(jù)了,。因此,我們常常見到有這樣一種說法:位圖文件從文件頭開始偏移54個字節(jié)就是位圖數(shù)據(jù)了,,這其實(shí)說的是24或32位圖的情況,。這也就解釋了我們按照這種程序?qū)懗鰜淼某绦驗(yàn)槭裁磳δ承┪粓D文件沒用了。 下面針對一幅特定的圖像進(jìn)行分析,,來看看在位圖文件中這四個數(shù)據(jù)段的排布以及組成,。 我們使用的圖像顯示如下:
這是一幅16位的位圖文件,因此它是含有調(diào)色板的,。 在拉出圖像數(shù)據(jù)進(jìn)行分析之前,,我們首先進(jìn)行幾個約定: 1. 在BMP文件中,如果一個數(shù)據(jù)需要用幾個字節(jié)來表示的話,,那么該數(shù)據(jù)的存放字節(jié)順序?yàn)?#8220;低地址村存放低位數(shù)據(jù),,高地址存放高位數(shù)據(jù)”。如數(shù)據(jù)0x1756在內(nèi)存中的存儲順序?yàn)椋?/span>
這種存儲方式稱為小端方式(little endian) , 與之相反的是大端方式(big endian),。對兩者的使用情況有興趣的可以深究一下,,其中還是有學(xué)問的。 2. 以下所有分析均以字節(jié)為序號單位進(jìn)行,。 下面我們對從文件中拉出來的數(shù)據(jù)進(jìn)行剖析:
一,、bmp文件頭
typedef struct tagBITMAPFILEHEADER
{ UINT16 bfType; DWORD bfSize; UINT16 bfReserved1; UINT16 bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;
其中:
對照文件數(shù)據(jù)我們看到:
1-2 :424dh = 'BM',表示這是Windows支持的位圖格式。有很多聲稱開頭兩個字節(jié)必須為'BM'才是位圖文件,,從上表來看應(yīng)為開頭兩個字節(jié)必須為'BM'才是Windows位圖文件,。 3-5 :00010436h = 66614 B = 65.05 kB,通過查詢文件屬性發(fā)現(xiàn)一致,。 6-9 :這是兩個保留段,,為0。 A-D:00000436h = 1078,。即從文件頭到位圖數(shù)據(jù)需偏移1078字節(jié),。我們稍后將驗(yàn)證這個數(shù)據(jù)。 共有14個字節(jié)。 二,、位圖信息頭 代碼
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個字節(jié)。前面我們已經(jīng)說過位圖信息頭一般有40個字節(jié),,既然是這樣,,為什么這里還要給一個字段來說明呢?這里涉及到一些歷史,其實(shí)位圖信息頭原本有很多大小的版本的,。我們看一下下表: 12-15:00000100h = 256,,圖像寬為255像素,,與文件屬性一致。 16-19:00000100h = 256,,圖像高為255像素,,與文件屬性一致。這是一個正數(shù),,說明圖像數(shù)據(jù)是從圖像左下角到右上角排列的,。 1E-21:00000000h,BI_RGB,, 說明本圖像不壓縮。 22-25:00000000h,,圖像的大小,,因?yàn)槭褂?/span>BI_RGB,所以設(shè)置為0,。 26-29:00000000h,,水平分辨率,缺省,。 2E-31:00000100h = 256,說明本位圖實(shí)際使用的顏色索引數(shù)為256,,與 32-35:00000100h = 256,說明本位圖重要的顏色索引數(shù)為256,與前面得到的結(jié)論一致,。 三,、調(diào)色板
索引:(藍(lán),,綠,,紅,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個字節(jié),,就是一共1024個字節(jié),再加上前面的文件信息頭和位圖信息頭的54個字節(jié)加起來一共是1078個字節(jié),。也就是說在位圖數(shù)據(jù)出現(xiàn)之前一共有1078個字節(jié),,與我們在文件信息頭得到的信息:文件頭到文圖數(shù)據(jù)區(qū)的偏移為1078個字節(jié)一致! 四,、位圖數(shù)據(jù) 下面就是位圖數(shù)據(jù)了,,每個像素占一個字節(jié),取得這個字節(jié)后,,以該字節(jié)為索引查詢相應(yīng)的顏色,,并顯示到相應(yīng)的顯示設(shè)備上就可以了。 注意:由于位圖信息頭中的圖像高度是正數(shù),,所以位圖數(shù)據(jù)在文件中的排列順序是從左下角到右上角,,以行為主序排列的。
也即我們見到的第一個像素60是圖像最左下角的數(shù)據(jù),,第二個人像素60為圖像最后一行第二列的數(shù)據(jù),,…一直到最后一行的最后一列數(shù)據(jù),后面緊接的是倒數(shù)第二行的第一列的數(shù)據(jù),,依此類推,。 如果圖像是24位或是32位數(shù)據(jù)的位圖的話,位圖數(shù)據(jù)區(qū)就不是索引而是實(shí)際的像素值了,。下面說明一下,,此時位圖數(shù)據(jù)區(qū)的每個像素的RGB顏色陣列排布: 24位RGB按照BGR的順序來存儲每個像素的各顏色通道的值,一個像素的所有顏色分量值都存完后才存下一個下一個像素,,不進(jìn)行交織存儲,。 32位數(shù)據(jù)按照BGRA的順序存儲,其余與24位位圖的方式一樣,。 像素的排布規(guī)則與前述一致,。 對齊規(guī)則 講完了像素的排列規(guī)則以及各像素的顏色分量的排列規(guī)則,最后我們談?wù)剶?shù)據(jù)的對齊規(guī)則,。我們知道Windows默認(rèn)的掃描的最小單位是4字節(jié),如果數(shù)據(jù)對齊滿足這個值的話對于數(shù)據(jù)的獲取速度等都是有很大的增益的,。因此,,BMP圖像順應(yīng)了這個要求,要求每行的數(shù)據(jù)的長度必須是4的倍數(shù),,如果不夠需要進(jìn)行比特填充(以0填充),,這樣可以達(dá)到按行的快速存取。這時,位圖數(shù)據(jù)區(qū)的大小就未必是 圖片寬×每像素字節(jié)數(shù)×圖片高 能表示的了,,因?yàn)槊啃锌赡苓€需要進(jìn)行比特填充,。 填充后的每行的字節(jié)數(shù)為: ,其中BPP(Bits Per Pixel)為每像素的比特?cái)?shù),。 在程序中,,我們可以表示為: int iLineByteCnt = (((m_iImageWidth * m_iBitsPerPixel) + 31) >> 5) << 2; 這樣,位圖數(shù)據(jù)區(qū)的大小為: m_iImageDataSize = iLineByteCnt * m_iImageHeight; 我們在掃描完一行數(shù)據(jù)后,,也可能接下來的數(shù)據(jù)并不是下一行的數(shù)據(jù),,可能需要跳過一段填充數(shù)據(jù): skip = 4 - ((m_iImageWidth * m_iBitsPerPixel)>>3) & 3; 五、拾遺 至此,,我們通過分析一個具體的位圖文件例子詳細(xì)地剖析了位圖文件的組成,。需要注意的是:我們講的主要是PC機(jī)上的位圖文件的構(gòu)成,對于嵌入式平臺,,可能在調(diào)色板數(shù)據(jù)段與PC機(jī)的不同,。如在嵌入式平臺上常見的16位r 第一個部分是紅色分量的掩模 第二個部分是綠色分量的掩模 第三個部分是藍(lán)色分量的掩模 第四個部分是Alpha分量的掩模(缺省為0) 典型的調(diào)色板規(guī)范在文件中的順序?yàn)闉椋?/span> 其中 將掩碼跟像素值進(jìn)行“與”運(yùn)算再進(jìn)行移位操作就可以得到各色分量值??纯囱诖a,,就可以明白事實(shí)上在每個像素值的兩個字節(jié)16位中,按從高到低取5,、6,、5位分別就是r、g,、b分量值,。取出分量值后把r、g,、b值分別乘以8,、4,、8就可以補(bǔ)齊每個分量為一個字節(jié),再把這三個字節(jié)按BGR組合,,放入存儲器,,就可以轉(zhuǎn)換為24位標(biāo)準(zhǔn)BMP格式了。 這樣我們假設(shè)在位圖數(shù)據(jù)區(qū)有一個像素的數(shù)據(jù)在文件中表示為 r = (F102 AND F800) >> 8 = F0h = 240 g= (F102 AND 07E0)>> 3 = 20h = 32 至此我們就可以顯示了,。(本文結(jié)束) 參考資源: 1. wiki百科 bmp file format http://en./wiki/BMP_file_format 2. gwwgle的專欄 BMP格式詳解 http://blog.csdn.net/gwwgle/archive/2009/11/06/4775396.aspx 3. 匿名 BMP格式圖像文件詳析http://www./pc/200407/20040722117029.shtm 4. Singler的專欄位圖文件(BMP)格式分析以及程序?qū)崿F(xiàn)http://blog.csdn.net/yyfzy/archive/2006/06/10/785945.aspx |
|