最近工作中用到一些解析bmp圖檔格式的工作,作為一種最簡單的圖檔格式,bmp簡單易于了解,但
是就是占用空間太大。在開發過程中,需要有幾點需要注意,特此記錄一下。
位圖格式 BMP是bitmap的縮寫形式,bitmap顧名思義,就是位圖也即Windows位圖。它一般由4部分組成:檔案頭資訊塊、圖像描述資訊塊、顔色表(在真彩色模式無顔色表)和圖像資料區組成。在系統中以BMP為擴充名儲存。
打開Windows的畫圖程式,在儲存圖像時,可以看到三個選項:2色位圖(黑白)、16色位圖、256色位圖和24位位圖。
現在講解BMP的4個組成部分:
1.檔案頭資訊塊
0000-0001 :檔案辨別,為字母ASCII碼“BM”。
0002-0005 :檔案大小。
0006-0009 :保留,每位元組以“00”填寫。
000A-000D :記錄圖像資料區的起始位置。各位元組的資訊含義依次為:檔案頭資訊塊大小,圖像描述資訊塊的大小,圖像顔色表的大小,保留(為01)。
2.圖像描述資訊塊
000E-0011:圖像描述資訊塊的大小,常為28H。
0012-0015:圖像寬度。
0016-0019:圖像高度。
001A-001B:圖像的plane總數(恒為1)。
001C-001D:記錄像素的位數,很重要的數值,圖像的顔色數由該值決定。
001E-0021:資料壓縮方式(數值位0:不壓縮;1:8位壓縮;2:4位壓縮)。
0022-0025:圖像區資料的大小。
0026-0029:水準每米有多少像素,在裝置無關位圖(.DIB)中,每位元組以00H填寫。 這個在手機中填寫手機的像素值即可
002A-002D:垂直每米有多少像素,在裝置無關位圖(.DIB)中,每位元組以00H填寫。這個在手機中填寫手機的像素值即可
002E-0031:此圖像所用的顔色數,如值為0,表示所有顔色一樣重要。
3.顔色表
顔色表的大小根據所使用的顔色模式而定:2×××像為8位元組;16×××像位64位元組;256×××像為1024位元組。其中,每4位元組表示一種顔色,并以B(藍色)、G(綠色)、R(紅色)、alpha(32位位圖的透明度值,一般不需要)。即首先4位元組表示顔色号0的顔色,接下來表示顔色号1的顔色,依此類推。
4.圖像資料區
顔色表接下來位是位圖檔案的圖像資料區,在此部分記錄着每點像素對應的顔色号,其記錄方式也随顔色模式而定,既2×××像每點占1位;16×××像每點占4位;256×××像每點占8位;真彩×××像每點占24位。是以,整個資料區的大小也會随之變化。究其規律而言,可的出如下計算公式:圖像資料資訊大小=(圖像寬度*圖像高度*記錄像素的位數)/8。 然而,未壓縮的圖像資訊區的大小。除了真彩色模式外,其餘的均大于或等于資料資訊的大小。這是為什麼呢?原因有兩個:
1. BMP檔案記錄一行圖像是以位元組為機關的。是以,就不存在一個位元組中的資料位資訊表示的點在不同的兩行中。也就是說,設顯示模式位16色,在每個位元組配置設定兩個點資訊時,如果圖像的寬度位奇數,那麼最後一個像素點的資訊将獨占一個位元組,這個位元組的後4位将沒有意義。接下來的一個位元組将開始記錄下一行的資訊。
這點很重要,即便是32位或者24位的圖檔有時候也要補位的,也就是每行一定是4的倍數,同時bmp整個圖檔的大小也一定要是4的倍數,而補位的原則是行在行尾,圖在圖尾。也就是說,bmp按照行來進行描述,行是bmp圖檔的一個基本機關,這一行的位元組數如果不是4的倍數的話,那麼就一定要将這一行在最後補齊成4的倍數,雖然這一行大小的變化會影響到整體位圖的大小,但是最後位圖的補齊并沒有在這裡計算。
位圖最後的大小有時候需要補齊,有時候不需要補齊,這點不影響最後的圖檔顯示效果,也就是說實際的圖檔的大小(不包含頭部 54位元組的資訊)這個可以是4的倍數也可以不是,補齊的資料當然也放在實際資料的最後,這點其實是不影響實際的解析函數對正确關鍵資料的提取的。是以關鍵資料的提取其實是對行補齊的操作。
2. 為了顯示的友善,除了真彩色外,其他的每中顔色模式的行位元組數要用資料“00”補齊為4的整數倍。如果顯示模式為16色,當圖像寬為19時,存儲時每行則要補充4-(19/2+1)%4=2個位元組(加1是因為裡面有一個像素點要獨占了一位元組)。如果顯示模式為256色,當圖像寬為19時,每行也要補充4-19%4=1個位元組。
bmp檔案大體上分成四個部分。
位圖檔案頭BITMAPFILEHEADER 、位圖資訊頭BITMAPINFOHEADER 、調色闆Palette 、實際的位圖資料ImageDate
第一部分為位圖檔案頭BITMAPFILEHEADER,是一個結構,其定義如下:
typedef unsigned char BYTE
typedef unsigned short WORD
typedef unsigned long DWORD
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //類型名,必須是0x424D,即字元串“BM”,
DWORD bfSize; //檔案大小
WORD bfReserved1; //保留字,不考慮
WORD bfReserved2; //保留字,同上
DWORD bfOffBits; //實際位圖資料的偏移位元組數,即前三個部分長度之和
} BITMAPFILEHEADER;
第二部分為位圖資訊頭BITMAPINFOHEADER,也是一個結構,其定義如下:
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //指定此結構體的長度,為40
LONG biWidth; //位圖寬
LONG biHeight; //位圖高
WORD biPlanes; //平面數,為1
WORD biBitCount //采用顔色位數,可以是1,2,4,8,16,24,新的可以是32
DWORD biCompression; //壓縮方式,可以是0,1,2,其中0表示不壓縮
DWORD biSizeImage; //實際位圖資料占用的位元組數
LONG biXPelsPerMeter; //X方向分辨率
LONG biYPelsPerMeter; //Y方向分辨率
DWORD biClrUsed; //使用的顔色數,如果為0,則表示預設值(2^顔色位數)
DWORD biClrImportant; //重要顔色數,如果為0,則表示所有顔色都是重要的
} BITMAPINFOHEADER;
第三部分為調色闆Palette,當然,這裡是對那些需要調色闆的位圖檔案而言的。24位和32位是不需要調色闆的。
typedef struct tagRGBQUAD {
BYTE rgbBlue; //該顔色的藍色分量
BYTE rgbGreen; //該顔色的綠色分量
BYTE rgbRed; //該顔色的紅色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
第四部分就是實際的圖象資料了。對于用到調色闆的位圖,圖象資料就是該象素顔在調色闆中的索引值。對于真彩×××,圖象資料就是實際的R、G、B值。對于2色位圖,用1位就可以表示該象素的顔色(一般0表示黑,1表示白),是以一個位元組可以表示8個象素。對于16色位圖,用4位可以表示一個象素的顔色,是以一個位元組可以表示2個象素。對于256色位圖,一個位元組剛好可以表示1個象素。對于真彩×××,三個位元組才能表示1個象素。要注意兩點: (1) 每一行的位元組數必須是4的整倍數,如果不是,則需要補齊。 (2) 一般來說,.bMP檔案的資料從下到上,從左到右的。也就是說,從檔案中最先讀到的是圖象最下面一行的左邊第一個象素,然後是左邊第二個象素……接下來是倒數第二行左邊第一個象素,左邊第二個象素……依次類推 ,最後得到的是最上面一行的最右一個象素。