複製鏈接
請複製以下鏈接發送給好友

BMP格式

鎖定
BMP是英文Bitmap位圖)的簡寫,它是Windows操作系統中的標準圖像文件格式,能夠被多種Windows應用程序所支持。隨着Windows操作系統的流行與豐富的Windows應用程序的開發,BMP位圖格式理所當然地被廣泛應用。這種格式的特點是包含的圖像信息較豐富,幾乎不進行壓縮,但由此導致了它與生俱來的缺點--佔用磁盤空間過大。所以,BMP在單機上比較流行。
中文名
位圖圖像
外文名
BMP(Bitmap)
優    點
圖像信息較豐富,幾乎不進行壓縮
缺    點
佔用磁盤空間過大

BMP格式格式分析

簡介
BMP(Bitmap-File)圖形文件是Windows採用的圖形文件格式,在Windows環境下運行的所有圖像處理軟件都支持BMP圖像文件格式。Windows系統內部各圖像繪製操作都是以BMP為基礎的。Windows 3.0以前的BMP圖文件格式與顯示設備有關,因此把這種BMP圖像文件格式稱為設備相關位圖DDB(device-dependent bitmap)文件格式。Windows 3.0以後的BMP圖像文件與顯示設備無關,因此把這種BMP像文件格式稱為設備無關位圖DIB(device-independent bitmap)格式(注:Windows 3.0以後,在系統中仍然存在DDB位圖,像BitBlt這種函數就是基於DDB位圖的,只不過如果你想將圖像以BMP格式保存到磁盤文件中時,微軟極力推薦你以DIB格式保存),目的是為了讓Windows能夠在任何類型的顯示設備上顯示所存儲的圖像。BMP位圖文件默認的文件擴展名是BMP或者bmp(有時它也會以.DIB或.RLE作擴展名)。
1.2 文件結構
位圖文件可看成由4個部分組成:位圖文件頭(bitmap-file header)、位圖信息頭(bitmap-information header)、彩色表(color table)和定義位圖的字節(位圖數據,即圖像數據,Data Bits 或Data Body)陣列,它具有如下所示的形式。
位圖文件的組成
結構名稱  符 號
位圖文件頭 (bitmap-file header) BITMAPFILEHEADER bmfh
位圖信息頭 (bitmap-information header) BITMAPINFOHEADER bmih
彩色表  (color table) RGBQUAD aColors()
圖像數據陣列字節 BYTE aBitmapBits()
位圖文件結構可綜合在表6-01中。
表01位圖文件結構內容摘要
偏移量 域的名稱  大小  內容
圖像文件頭
0000h 文件標識 2 bytes 兩字節的內容用來識別位圖的類型:
‘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系統並沒有被普及開,所以在編程時,你只需判斷第一個標識“BM”就行。
0002h File Size 1 dword 用字節表示的整個文件的大小
0006h Reserved 1 dword 保留,必須設置為0
000Ah Bitmap Data Offset 1 dword 從文件開始到位圖數據開始之間的數據(bitmap data)之間的偏移量
圖像信息頭
000Eh Bitmap Header Size 1 dword位圖信息頭(Bitmap Info Header)的長度,用來描述位圖的顏色、壓縮方法等。下面的長度表示:
28h - Windows 3.1x,95,NT,…
0Ch - OS/2 1.x
F0h - OS/2 2.x
注:在Windows95、98、2000等操作系統中,位圖信息頭的長度並不一定是28h,因為微軟已經制定出了新的BMP文件格式,其中的信息頭結構變化比較大,長度加長。所以最好不要直接使用常數28h,而是應該從具體的文件中讀取這個值。這樣才能確保程序的兼容性。
0012h Width 1 dword位圖的寬度,以像素為單位
0016h Height 1 dword位圖的高度,以像素為單位
001Ah Planes 1 word位圖的位面數(注:該值將總是1)
001Ch Bits Per Pixel 1 word 每個像素的位數
1 - 單色位圖(實際上可有兩種顏色,缺省情況下是黑色和白色。你可以自己定義這兩種顏色)
4 - 16 色位圖
8 - 256 色位圖
16 - 16bit 高彩色位圖
24 - 24bit真彩色位圖
32 - 32bit 增強型真彩色位圖
001Eh Compression 1 dword 壓縮説明:
0 - 不壓縮 (使用BI_RGB表示)
1 - RLE 8-使用8位RLE壓縮方式(用BI_RLE8表示)
2 - RLE 4-使用4位RLE壓縮方式(用BI_RLE4表示)
3 - Bitfields-位域存放方式(用BI_BITFIELDS表示)
0022h Bitmap Data Size 1 dword 用字節數表示的位圖數據的大小。該數必須是4的倍數
0026h HResolution 1 dword 用像素/米表示的水平分辨率
002Ah VResolution 1 dword 用像素/米表示的垂直分辨率
002Eh Colors 1 dword位圖使用的顏色數。如8-比特/像素表示為100h或者 256.
0032h Important Colors 1 dword 指定重要的顏色數。當該域的值等於顏色數時(或者等於0時),表示所有顏色都一樣重要
調色板數據 根據BMP版本的不同而不同 Palette N * 4 byte 調色板規範。對於調色板中的每個表項,這4個字節用下述方法來描述RGB的值:1字節用於藍色分量
1字節用於綠色分量
1字節用於紅色分量
1字節用於填充符(設置為0)
圖像數據 根據BMP版本及調色板尺寸的不同而不同 Bitmap Data xxx bytes 該域的大小取決於壓縮方法及圖像的尺寸和圖像的位深度,它包含所有的位圖數據字節,這些數據可能是彩色調色板的索引號,也可能是實際的RGB值,這將根據圖像信息頭中的位深度值來決定。

BMP格式構件詳解

編輯 播報
位圖文件頭
位圖文件頭包含有關於文件類型、文件大小、存放位置等信息,在Windows 3.0以上版本的位圖文件中用BITMAPFILEHEADER結構來定義:
typedef struct tagBITMAPFILEHEADER {
/* bmfh */
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
}BITMAPFILEHEADER;
其中:
bfType
説明文件的類型.(該值必需是0x4D42,也就是字符'BM'。我們不需要判斷OS/2的位圖標識,這麼做看來似乎已經沒有什麼意義了,而且如果要支持OS/2的位圖,程序將變得很繁瑣。所以,在此只建議你檢察'BM'標識)
注意:查ascii表'B': 0x42,'M': 0x4d, bfType為兩個字節,'B'為low字節,'M'為high字節, 所以bfType=0x4D42,而不是0x424D,但注意(這裏採用了小端模式,詳見大小端模式)
bfSize
説明文件的大小,用字節為單位
bfReserved1
保留,必須設置為0
bfReserved2
保留,必須設置為0
bfOffBits
説明從文件頭開始到實際的圖像數據之間的字節的偏移量。這個參數是非常有用的,因為位圖信息頭和調色板的長度會根據不同情況而變化,所以你可以用這個偏移值迅速的從文件中讀取到位數據。
位圖信息
位圖信息用BITMAPINFO結構來定義,它由位圖信息頭(bitmap-information header)和彩色表(color table)組成,前者用BITMAPINFOHEADER結構定義,後者用RGBQUAD結構定義。BITMAPINFO結構具有如下形式:
typedef struct tagBITMAPINFO {
/* bmi */
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
其中:
bmiHeader
説明BITMAPINFOHEADER結構,其中包含了有關位圖的尺寸及位格式等信息
bmiColors
説明彩色表RGBQUAD結構的陣列,其中包含索引圖像的真實RGB值。
BITMAPINFOHEADER結構包含有位圖文件的大小、壓縮類型和顏色格式,其結構定義為:
typedef struct tagBITMAPINFOHEADER {
/* bmih */
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
其中:
biSize
説明BITMAPINFOHEADER結構所需要的字數。注:這個值並不一定是BITMAPINFOHEADER結構的尺寸,它也可能是sizeof(BITMAPV4HEADER)的值,或是sizeof(BITMAPV5HEADER)的值。這要根據該位圖文件的格式版本來決定,不過,就現在的情況來看,絕大多數的BMP圖像都是BITMAPINFOHEADER結構的(可能是後兩者太新的緣故吧:-)。
biWidth
説明圖像的寬度,以像素為單位
biHeight
説明圖像的高度,以像素為單位。注:這個值除了用於描述圖像的高度之外,它還有另一個用處,就是指明該圖像是倒向的位圖,還是正向的位圖。如果該值是一個正數,説明圖像是倒向的,如果該值是一個負數,則説明圖像是正向的。大多數的BMP文件都是倒向的位圖,也就是時,高度值是一個正數。(注:當高度值是一個負數時(正向圖像),圖像將不能被壓縮(也就是説biCompression成員將不能是BI_RLE8或BI_RLE4)。
biPlanes
為目標設備説明位面數,其值將總是被設為1
biBitCount
説明比特數/像素,其值為1、4、8、16、24、或32
biCompression
説明圖像數據壓縮的類型。其值可以是下述值之一:
BI_RGB:沒有壓縮;
BI_RLE8:每個像素8比特的RLE壓縮編碼,壓縮格式由2字節組成(重複像素計數和顏色索引);
BI_RLE4:每個像素4比特的RLE壓縮編碼,壓縮格式由2字節組成
BI_BITFIELDS:每個像素的比特由指定的掩碼決定。
biSizeImage
説明圖像的大小,以字節為單位。當用BI_RGB格式時,可設置為0
biXPelsPerMeter
説明水平分辨率,用像素/米表示
biYPelsPerMeter
説明垂直分辨率,用像素/米表示
biClrUsed
説明位圖實際使用的彩色表中的顏色索引數(設為0的話,則説明使用所有調色板項)
biClrImportant
説明對圖像顯示有重要影響的顏色索引的數目,如果是0,表示都重要。
現就BITMAPINFOHEADER結構作如下説明:
彩色表定位
應用程序可使用存儲在biSize成員中的信息來查找在BITMAPINFO結構中的彩色表,如下所示:
pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo->bmiHeader.biSize))
biBitCount
biBitCount=1 表示位圖最多有兩種顏色,缺省情況下是黑色和白色,你也可以自己定義這兩種顏色。圖像信息頭裝調色板中將有兩個調色板項,稱為索引0和索引1。圖像數據陣列中的每一位表示一個像素。如果一個位是0,顯示時就使用索引0的RGB值,如果位是1,則使用索引1的RGB值。
biBitCount=4 表示位圖最多有16種顏色。每個像素用4位表示,並用這4位作為彩色表的表項來查找該像素的顏色。例如,如果位圖中的第一個字節為0x1F,它表示有兩個像素,第一像素的顏色就在彩色表的第2表項中查找,而第二個像素的顏色就在彩色表的第16表項中查找。此時,調色板中缺省情況下會有16個RGB項。對應於索引0到索引15。
biBitCount=8 表示位圖最多有256種顏色。每個像素用8位表示,並用這8位作為彩色表的表項來查找該像素的顏色。例如,如果位圖中的第一個字節為0x1F,這個像素的顏色就在彩色表的第32表項中查找。此時,缺省情況下,調色板中會有256個RGB項,對應於索引0到索引255。
biBitCount=16 表示位圖最多有65536種顏色。每個色素用16位(2個字節)表示。這種格式叫作高彩色,或叫增強型16位色,或64K色。它的情況比較複雜,當biCompression成員的值是BI_RGB時,它沒有調色板。16位中,最低的5位表示藍色分量,中間的5位表示綠色分量,高的5位表示紅色分量,一共佔用了15位,最高的一位保留,設為0。這種格式也被稱作555 16位位圖。如果biCompression成員的值是BI_BITFIELDS,那麼情況就複雜了,首先是原來調色板的位置被三個DWORD變量佔據,稱為紅、綠、藍掩碼。分別用於描述紅、綠、藍分量在16位中所佔的位置。在Windows 95(或98)中,系統可接受兩種格式的位域:555和565,在555格式下,紅、綠、藍的掩碼分別是:0x7C00、0x03E0、0x001F,而在565格式下,它們則分別為:0xF800、0x07E0、0x001F。你在讀取一個像素之後,可以分別用掩碼“與”上像素值,從而提取出想要的顏色分量(當然還要再經過適當的左右移操作)。在NT系統中,則沒有格式限制,只不過要求掩碼之間不能有重疊。(注:這種格式的圖像使用起來是比較麻煩的,不過因為它的顯示效果接近於真彩,而圖像數據又比真彩圖像小的多,所以,它更多的被用於遊戲軟件)。
biBitCount=24 表示位圖最多有1670萬種顏色。這種位圖沒有調色板(bmiColors成員尺寸為0),在位數組中,每3個字節代表一個像素,分別對應於顏色R、G、B。
biBitCount=32 表示位圖最多有4294967296(2的32次方)種顏色。這種位圖的結構與16位位圖結構非常類似,當biCompression成員的值是BI_RGB時,它也沒有調色板,32位中有24位用於存放RGB值,順序是:最高位—保留,紅8位、綠8位、藍8位。這種格式也被成為888 32位圖。如果 biCompression成員的值是BI_BITFIELDS時,原來調色板的位置將被三個DWORD變量佔據,成為紅、綠、藍掩碼,分別用於描述紅、綠、藍分量在32位中所佔的位置。在Windows 95/Windows 98中,系統只接受888格式,也就是説三個掩碼的值將只能是:0xFF0000、0xFF00、0xFF。而在NT系統中,你只要注意使掩碼之間不產生重疊就行。(注:這種圖像格式比較規整,因為它是DWORD對齊的,所以在內存中進行圖像處理時可進行彙編級的代碼優化(簡單))。

BMP格式簡介

編輯 播報
如今Windows(3.x以及95,98,NT)系列已經成為絕大多數用户使用的操作系統,它比DOS成功的一個重要因素是它可視化的漂亮界面。那麼Windows是如何顯示圖像的呢?這就要談到位圖(bitmap)。
我們知道,普通的顯示器屏幕是由許許多多點構成的,我們稱之為像素。顯示時採用掃描的方法:電子槍每次從左到右掃描一行,為每個像素着色,然後從上到下這樣掃描若干行,就掃過了一屏。為了防止閃爍,每秒要重複上述過程幾十次。例如我們常説的屏幕分辨率為640×480,刷新頻率為70Hz,意思是説每行要掃描640個像素,一共有480行,每秒重複掃描屏幕70次。
我們稱這種顯示器為位映像設備。所謂位映像,就是指一個二維的像素矩陣,而位圖就是採用位映像方法顯示和存儲的圖像。舉個例子,圖1.1是一幅普通的黑白位圖,圖1.2是被放大後的圖,圖中每個方格代表了一個像素。我們可以看到:整個骷髏就是由這樣一些黑點和白點組成的。
圖1.1 骷髏
圖1.2 放大後的骷髏位圖
那麼,彩色圖是怎麼回事呢?
我們先來説説三元色RGB概念。
我們知道,自然界中的所有顏色都可以由紅、綠、藍(R,G,B)組合而成。有的顏色含有紅色成分多一些,如深紅;有的含有紅色成分少一些,如淺紅。針對含有紅色成分的多少,可以分成0到255共256個等級,0級表示不含紅色成分;255級表示含有100%的紅色成分。同樣,綠色和藍色也被分成256級。這種分級概念稱為量化。
這樣,根據紅、綠、藍各種不同的組合我們就能表示出256×256×256,約1600萬種顏色。這麼多顏色對於我們人眼來説已經足夠豐富了。
表1.1 常見顏色的RGB組合值
顏色
R
G
B
255
0
0
0
0
255
0
255
0
255
255
0
255
0
255
0
255
255
255
255
255
0
0
0
128
128
128
你大概已經明白了,當一幅圖中每個像素賦予不同的RGB值時,能呈現出五彩繽紛的顏色了,這樣就形成了彩色圖。的確是這樣的,但實際上的做法還有些差別。
讓我們來看看下面的例子。
有一個長寬各為200個像素,顏色數為16色的彩色圖,每一個像素都用R、G、B三個分量表示。因為每個分量有256個級別,要用8位(bit),即一個字節(byte)來表示,所以每個像素需要用3個字節。整個圖像要用200×200×3,約120k字節,這可不是一個小數目,但是我們用下面的方法,就能省的多。
因為是一個16色圖,也就是説這幅圖中最多隻有16種顏色,我們可以用一個表:表中的每一行記錄一種顏色的R、G、B值。這樣當我們表示一個像素的顏色時,只需要指出該顏色是在第幾行,即該顏色在表中的索引值。舉個例子,如果表的第0行為255,0,0(紅色),那麼當某個像素為紅色時,只需要標明0即可。
讓我們再來計算一下:16種狀態可以用4位(bit)表示,所以一個像素要用半個字節。整個圖像要用200×200×0.5,約20k字節,再加上表佔用的字節為3×16=48字節.整個佔用的字節數約為前面的1/6,省很多吧?
這張R、G、B的表,就是我們常説的調色板(Palette),另一種叫法是顏色查找表LUT(Look Up Table),似乎更確切一些。Windows位圖中便用到了調色板技術。其實不光是Windows位圖,許多圖像文件格式如pcx、tif、gif等都用到了。所以很好地掌握調色板的概念是十分有用的。
有一種圖,它的顏色數高達256×256×256種,也就是説包含我們上述提到的R、G、B顏色表示方法中所有的顏色,這種圖叫做真彩色圖(true color)。真彩色圖並不是説一幅圖包含了所有的顏色,而是説它具有顯示所有顏色的能力,即最多可以包含所有的顏色。表示真彩色圖時,每個像素直接用R、G、B三個分量字節表示,而不採用調色板技術。原因很明顯:如果用調色板,表示一個像素也要用24位,這是因為每種顏色的索引要用24位(因為總共有2種顏色,即調色板有2行),和直接用R,G,B三個分量表示用的字節數一樣,不但沒有任何便宜,還要加上一個256×256×256×3個字節的大調色板。所以真彩色圖直接用R、G、B三個分量表示,它又叫做24位色圖。

BMP格式顏色陣列

編輯 播報
有關RGB三色空間我想大家都很熟悉,這裏我想説的是在Windows下,RGB顏色陣列存儲的格式其實BGR。也就是説,對於24位的RGB位圖像素數據格式是:
藍色B值
綠色G值
紅色R值
對於32位的RGB位圖像素數據格式是:
藍色B值
綠色G值
紅色R值
透明通道A值
透明通道也稱Alpha通道,該值是該像素點的透明屬性,取值在0(全透明)到255(不透明)之間。對於24位的圖像來説,因為沒有Alpha通道,故整個圖像都不透明。

BMP格式加載文件

編輯 播報
加載文件的目的是要得到圖片屬性,以及RGB數據,然後可以將其繪製在DC上(GDI),或是生成紋理對象(3D:OpenGL/Direct3D)。這兩種用途在數據處理上有點區別,我們主要按前一種用法講,在和3D有不同的地方,我們再提出來。
加載代碼
//Load the file header
BITMAPFILEHEADER header;
memset(&header,0,sizeof(header));
inf.read((char*)&header,sizeof(header));
if(header.bfType != 0x4D42)
return false;
位圖信息
//Load the image information header
BITMAPINFOHEADER infoheader;
memset(&infoheader,0,sizeof(infoheader));
inf.read((char*)&infoheader,sizeof(infoheader));
m_iImageWidth = infoheader.biWidth;
m_iImageHeight = infoheader.biHeight;
m_iBitsPerPixel = infoheader.biBitCount;
這裏我們得到了3各重要的圖形屬性:寬,高,以及每個像素顏色所佔用的位數。
行對齊
由於Windows在進行行掃描的時候最小的單位為4個字節,所以當
圖片寬 X 每個像素的字節數 != 4的整數倍
時要在每行的後面補上缺少的字節,以0填充(一般來説當圖像寬度為2的冪時不需要對齊)。位圖文件裏的數據在寫入的時候已經進行了行對齊,也就是説加載的時候不需要再做行對齊。但是這樣一來圖片數據的長度就不是:寬 X 高 X 每個像素的字節數了,我們需要通過下面的方法計算正確的數據長度:
//Calculate the image data size
int iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel/8) + 3) >> 2) << 2;
m_iImageDataSize = iLineByteCnt * m_iImageHeight;
圖片數據
對於24位和32位的位圖文件,位圖數據的偏移量為sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是説我們可以直接讀取圖像數據了。
if(m_pImageData) delete []m_pImageData;
m_pImageData = new unsigned char[m_iImageDataSize];
inf.read((char*)m_pImageData,m_iImageDataSize);
如果你足夠細心,就會發現內存m_pImageData裏的數據的確是BGR格式,可以用個純藍色或者是純紅色的圖片測試一下。
繪製
好了,數據和屬性我們都有了,就可以拿來隨便用了,就和吃饅頭一樣,愛粘白糖粘白糖,愛粘紅糖粘紅糖。下面是我的GDI繪製代碼,僅作參考。
void CImage::DrawImage(HDC hdc,int iLeft,int iTop,int iWidth,int iHeight)
{
if(!hdc || m_pImageData == NULL)
return;
BITMAPINFO bmi;
memset(&bmi,0,sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth = m_iImageWidth;
bmi.bmiHeader.biHeight = m_iImageHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = m_iBitsPerPixel;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = m_iImageDataSize;
StretchDIBits(hdc,iLeft,iTop,iWidth,iHeight,
0,0,m_iImageWidth,m_iImageHeight,
m_pImageData,&bmi,DIB_RGB_COLORS,SRCCOPY);
}
不同之處
如果你是想用剛才我們得到的數據生成紋理對象,那麼你還要請出下面的問題。
首先,用來生成紋理的數據不需要對齊,也就是説不能在每行的後面加上對齊的字節。當然在OpenGL裏要求紋理圖片的尺寸為2的冪,所以這個問題實際上不存在;
其次,我們得到的圖形數據格式是BGR(BGRA),所以在生成紋理的時候,需指定格式為GL_BGR_EXT(GL_BGRA_EXT);否則需要做BGR-RGB(BGRA-RGBA)的轉化。