BMP文件格式秸妥,又稱為Bitmap(位圖)或是DIB(Device-Independent Device,設(shè)備無關(guān)位圖),是Windows系統(tǒng)中廣泛使用的圖像文件格式访诱。由于它可以不作任何變換地保存圖像像素域的數(shù)據(jù),因此成為我們?nèi)〉肦AW數(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ù)了创倔,這其實說的是24或32位圖的情況。這也就解釋了我們按照這種程序?qū)懗鰜淼某绦驗槭裁磳δ承┪粓D文件沒用了焚碌。
下面針對一幅特定的圖像進(jìn)行分析畦攘,來看看在位圖文件中這四個數(shù)據(jù)段的排布以及組成。
我們使用的圖像顯示如下:
這是一幅16位的位圖文件十电,因此它是含有調(diào)色板的知押。
在拉出圖像數(shù)據(jù)進(jìn)行分析之前,我們首先進(jìn)行幾個約定:
- 在BMP文件中摆出,如果一個數(shù)據(jù)需要用幾個字節(jié)來表示的話朗徊,那么該數(shù)據(jù)的存放字節(jié)順序為“低地址村存放低位數(shù)據(jù),高地址存放高位數(shù)據(jù)”偎漫。如數(shù)據(jù)0x1756在內(nèi)存中的存儲順序為:
這種存儲方式稱為小端方式(little endian) , 與之相反的是大端方式(big endian)爷恳。對兩者的使用情況有興趣的可以深究一下,其中還是有學(xué)問的象踊。 - 以下所有分析均以字節(jié)為序號單位進(jìn)行温亲。
下面我們對從文件中拉出來的數(shù)據(jù)進(jìn)行剖析:
一、bmp****文件頭Windows為bmp文件頭定義了如下結(jié)構(gòu)體:
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é)鬓照。我們稍后將驗證這個數(shù)據(jù)。
共有14個字節(jié)孤紧。
二豺裆、位圖信息頭同樣地,Windows為位圖信息頭定義了如下結(jié)構(gòu)體:
**
對照數(shù)據(jù)文件: **
0E-11:00000028h = 40,這就是說我這個位圖信息頭的大小為40個字節(jié)号显。前面我們已經(jīng)說過位圖信息頭一般有40個字節(jié)臭猜,既然是這樣,為什么這里還要給一個字段來說明呢押蚤?這里涉及到一些歷史,其實位圖信息頭原本有很多大小的版本的蔑歌。我們看一下下表:
出于兼容性的考慮,大多數(shù)應(yīng)用使用了舊版的位圖信息頭來保存文件活喊。而 OS/2 已經(jīng)過時了,因此現(xiàn)在最常用的格式就僅有V3 header了丐膝。因此量愧,我們在前面說位圖信息頭的大小為40字節(jié)钾菊。
12-15:00000100h = 256,圖像寬為255像素偎肃,與文件屬性一致煞烫。
16-19:00000100h = 256,圖像高為255像素累颂,與文件屬性一致滞详。這是一個正數(shù),說明圖像數(shù)據(jù)是從圖像左下角到右上角排列的紊馏。
1A-1B:0001h, 該值總為1料饥。
1C-1D:0008h = 8, 表示每個像素占8個比特,即該圖像共有256種顏色朱监。
1E-21:00000000h岸啡,BI_RGB, 說明本圖像不壓縮赫编。
22-25:00000000h巡蘸,圖像的大小,因為使用BI_RGB擂送,所以設(shè)置為0悦荒。
26-29:00000000h,水平分辨率嘹吨,缺省搬味。
2A-2D:00000000h,垂直分辨率,缺省碰纬。
2E-31:00000100h = 256,說明本位圖實際使用的顏色索引數(shù)為256产还,與1C-ID得到的結(jié)論一致。
32-35:00000100h = 256,說明本位圖重要的顏色索引數(shù)為256嘀趟,與前面得到的結(jié)論一致脐区。
三、調(diào)色板下面的數(shù)據(jù)就是調(diào)色板了她按。前面也已經(jīng)提過牛隅,調(diào)色板其實是一張映射表,標(biāo)識顏色索引號與其代表的顏色的對應(yīng)關(guān)系酌泰。它在文件中的布局就像一個二維數(shù)組palette[N][4],其中N表示總的顏色索引數(shù)媒佣,每行的四個元素分別表示該索引對應(yīng)的B、G陵刹、R和Alpha的值默伍,每個分量占一個字節(jié)。如不設(shè)透明通道時衰琐,Alpha為0也糊。因為前面知道,本圖有256個顏色索引羡宙,因此N = 256狸剃。索引號就是所在行的行號,對應(yīng)的顏色就是所在行的四個元素狗热。這里截取一些數(shù)據(jù)來說明:
索引:(藍(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ù)據(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ù)×圖片高 能表示的了含衔,因為每行可能還需要進(jìn)行比特填充。
填充后的每行的字節(jié)數(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位r5g6b5位圖實際上采用的掩模的方式而不是索引的方式來表示圖像汁果。此時涡拘,在調(diào)色板數(shù)據(jù)段共有四個部分,每個部分為四個字節(jié)据德,實際表示的是彩色版規(guī)范鳄乏。即:
第一個部分是紅色分量的掩模
第二個部分是綠色分量的掩模
第三個部分是藍(lán)色分量的掩模
第四個部分是Alpha分量的掩模(缺省為0)
典型的調(diào)色板規(guī)范在文件中的順序為為:
00F8 0000 E007 0000 1F00 0000 0000 0000
其中
00F8 0000為FB00h=1111100000000000(二進(jìn)制),是藍(lán)紅分量的掩碼棘利。 E007 0000為 07E0h=0000011111100000(二進(jìn)制)橱野,是綠色分量的掩碼。 1F00 0000為001Fh=0000000000011111(二進(jìn)制)善玫,是藍(lán)色分量的掩碼水援。 0000 0000設(shè)置為0。
將掩碼跟像素值進(jìn)行“與”運(yùn)算再進(jìn)行移位操作就可以得到各色分量值茅郎∥显看看掩碼,就可以明白事實上在每個像素值的兩個字節(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ù)在文件中表示為02 F1跛梗。這個數(shù)據(jù)實際上應(yīng)為F102:
r = (F102 AND F800) >> 8 = F0h = 240
g= (F102 AND 07E0)>> 3 = 20h = 32 b=(F102 AND 001F) << 3 = 10h =16
至此我們就可以顯示了。(本文結(jié)束)
參考資源:
*wiki百科 bmp file format*
http://en.wikipedia.org/wiki/BMP_file_format
*gwwgle的專欄 BMP格式詳解* [http://blog.csdn.net/gwwgle/archive/2009/11/06/4775396.aspx](http://blog.csdn.net/gwwgle/archive/2009/11/06/4775396.aspx)
*匿名 BMP格式圖像文件詳析*[http://www.thethirdmedia.com/pc/200407/20040722117029.shtm](http://www.thethirdmedia.com/pc/200407/20040722117029.shtm)
*Singler的專欄位圖文件(BMP)格式分析以及程序?qū)崿F(xiàn)*[http://blog.csdn.net/yyfzy/archive/2006/06/10/785945.aspx](http://blog.csdn.net/yyfzy/archive/2006/06/10/785945.aspx)
轉(zhuǎn)自: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,位元面數(shù)為1
bits:2 bytes双炕,0x20 = 32狞悲,每個pixel需要32bits
compression:4 bytes,0代表不壓縮
imagesize:4 bytes妇斤,0x400 = 1024 bytes,點(diǎn)陣圖資料大小為1024 bytes
xresolution:4 bytes丹拯,水平解析度
yresolution:4 bytes站超,垂直解析度
ncolours:4 bytes,點(diǎn)陣圖使用的調(diào)色板顏色數(shù)
importantcolours:4 bytes乖酬,重要的顏色數(shù)
【RAW DATA 實例圖解****】
剛剛的File Header共14bytes死相,Info Header為40bytes,「imagesize」 = 1024 bytes咬像,所以「14 + 40 + 1024 = 1078」算撮, 即等于File Header中「size」的大小生宛。下面我只提取部分的資料,反正全部的檔案肮柜,減去Header檔54位元組陷舅,剩下的就是點(diǎn)陣圖的資料。
在Info Header中的「bits」為32 bits审洞,故四個位元組一組莱睁,若24 bits,則三個位元組一組芒澜,例子中的長寬各為16仰剿,以「Z」字型來看,一列則為16組痴晦,即16 X 4 = 64 bytes南吮。注意的是,圖中是以A誊酌、B旨袒、C ~ …的讀取順序來解說,但實際上程序所讀取到的通呈醴回是反過來的砚尽,即… ~ C、B辉词、A必孤。另外,下圖是以「BGRA」排列瑞躺。
轉(zhuǎn)自:http://blog.csdn.net/o_sun_o/article/details/8351037