BMP檔案結構的探索(轉貼)

2021-09-30 08:17:59 字數 3786 閱讀 3551

bmp檔案結構的探索**貼)

2008-06-09 17:46:59

一、檔案格式

bmp檔案是非常常用的位**件,無論是遊戲還是其他都被廣泛使用。針對bmp檔案的處理也有一堆現成的api進行呼叫,然而檔案內部究竟怎樣,如何自己來解析這樣的檔案呢?為了消除無聊,我用了幾天時間來研究了一下,同時作為學習筆記,進行記錄。

首先,整個bmp檔案的內容可以分為3到4塊。之所以分為3到4塊而不是固定的值,是因為,對於bmp來說可能存在調色盤或者一些掩碼。具體稍候討論。

第一塊是bmp的檔案頭用於描述整個bmp檔案的情況。結構如下:

typedef struct tagbitmapfileheader bitmapfileheader, *pbitmapfileheader;

這些資訊相當有用,如果你想直接來解析bmp檔案。第乙個bftype用於表示檔案型別,如果它是bmp檔案,那麼它這個位置的值一定是」bm」 也就是0x4d42。第二個bfsize表示整個檔案的位元組數。第三第四個則保留,目前無意義,最後乙個相當重要,表示,點陣圖的資料資訊離檔案頭的偏移量,以位元組為單位。

第二塊是點陣圖資訊頭,即bitmapinfoheader,用於描述整個位**件的情況。以下挑重要的資料進行解釋

typedef struct tagbitmapinfoheader bitmapinfoheader, *pbitmapinfoheader;

第三塊就是調色盤資訊或者掩碼部分,如果是8位位圖則存放調色盤 ;16 與32位位圖則存放rgb顏色的掩碼,這些掩碼以dword大小來存放。

最後一塊就是點陣圖的資料實體。

二、4位元組對其問題

關於資料讀取。bmp檔案有個重要特性,那就是對於資料區域而言,每行的資料它必須湊滿4位元組,如果沒有滿,則用冗餘的資料來補齊。這個特性直接影響到我們讀取位圖資料的方法,因為在我們看來(x,y)的資料應該在 y*width+x這樣的位置上 但是因為會有冗餘資訊那麼必須將width用width+該行的冗餘量來處理,而由於位**件有不同的位數,所以這樣的計算也不盡相同。

下面列出計算偏移量的一般公式。

首先將位圖資訊讀入乙個uchar 的buffer中 :

8位:int pitch;

if(width%4==0)else

index=buffer[y*pitch+x]; 因為8位位圖的資料區域存放的是調色盤索引值,所以只需讀取這個index

16位int pitch=width+width%2;

buffer[(y*pitch+x)*2]

buffer[(i*pitch+j)*2+1]

兩個uchar內,存放的是(x,y)處的顏色資訊

24位int pitch=width%4;

buffer[(y*width+x)*3+y*pitch];

buffer[(y*width+x)*3+y*pitch+1];

buffer[(y*width+x)*3+y*pitch+2];

32位由於乙個象素就是4位元組 所以無需補齊

雖然計算比較繁瑣,但是這些計算是必須的,否則當你的點陣圖每行的象素數不是4的倍數,那麼y*width+x帶給你的是乙個扭曲的,當然如果你想做這樣的旋轉,也不錯啊,至少我因為一開始沒有考慮(不知道這個特性)讓乙個每行象素少1位元組的16位變成了扭曲的菱形。

三、有了資料分離rgb分量。

由於我的測試**用了gdi,所以我必須講得到的某乙個點的值分離成 24位模式下的rgb分離,這不是一件容易的工作。位圖麻煩的地方之一就是他的格式太多,所以我們還是要分格式再討論。

8位通過第二部分提到的操作我們得到了乙個index,這個值的範圍是0~255 一共256個 正好是調色盤的顏色數量。

在8位bmp中資料資訊前256個rgbquad的大小開始就是調色盤的資訊。不過如果要組織成調色盤還要一定的轉換因為裡面是rgbquad資訊 r b 兩個與調色盤中的順序是顛倒的。因為我不需要調色盤設定所以我位元組讀取到rgbquad陣列中,並且通過下面的表示式獲取rgb值:

uchar r=quad[index].rgbred;

uchar g=quad[index].rgbgreen;

uchar b=quad[index].rgbblue;

16位這是最麻煩的乙個。因為在處理時有555 565 兩種格式的區別,而且還有所謂壓縮型別的區別。

之前的bitmapinfoheader裡面提到乙個bicompression

現在我們分兩種情況討論:bi_rgb和bi_bitfields

當他等於bi_rgb時 只有555 這種格式,所以可以放心大膽的進行如下的資料分離:

uchar b=buffer[(i*pitch+j)*2]&0x1f;

uchar g=(((buffer[(i*pitch+j)*2+1]<<6)&0xff)>>3)+(buffer[(i*pitch+j)*2]>>5);

uchar r=(buffer[(i*pitch+j)*2+1]<<1)>>3;

希望不要被這個表示式折磨的眼花繚亂,我想既然你在看這篇文章,你就有能力閱讀這樣的**,否則只能說你還沒有到閱讀這方面的地步,需要去學習基礎的語法了。

有一點值得提醒的是由於有較多的位操作,所以在處理的時候在前一次操作的上面加上一對括號,我就曾經因為沒有加而導致出現誤差,另外雖然buffer中乙個元素代表的是乙個uchar 但是右移操作會自動增長為兩位元組所以需要在進行一次與操作擷取低位的1位元組資料。

現在討論bi_bitfields。

這個模式下 既可以有555 也可以有565 。

555 格式 xrrrrr

ggggg

bbbbb

565 格式 rrrrr

gggggg

bbbbb

顯然不同的格式處理不同,所以我們要首先判斷處到底屬於那種格式。

bitmapinfoheader的bicompression為bi_bitfields時,在位圖資料區域前存在乙個rgb掩碼的描述是3個dword值,我們只需要讀取其中的r或者g的掩碼,來判斷是那種格式。

以紅色掩碼為例 0111110000000000的時候就是555格式 1111100000000000就是565格式。

以下是565格式時的資料分離:

uchar b=buffer[(i*pitch+j)*2]&0x1f;

uchar g=(((buffer[(i*pitch+j)*2+1]<<5)&0xff)>>2)+(buffer[(i*pitch+j)*2]>>5);

uchar r=buffer[(i*pitch+j)*2+1]>>3;

現在我們得到了rgb各自的分量,但是還有乙個新的問題,那就是由於兩位元組表示了3個顏色 555下每個顏色最多到0x1f 565格式下最大的綠色分量也就0x3f。所以我們需要乙個轉換 color=color*255/最大顏色數 即可

如565下rgb(r*0xff/0x1f,g*0xff/0x3f,b*0xff/0x1f)

24位uchar b=buffer[(i*width+j)*3+realpitch];

uchar g=buffer[(i*width+j)*3+1+realpitch];

uchar r=buffer[(i*width+j)*3+2+realpitch];

32位uchar b=buffer[(i*width+j)*4];

uchar g=buffer[(i*width+j)*4+1];

uchar r=buffer[(i*width+j)*4+2];

四、剩餘的問題

當資料取到了,顏色也分離出來了,但是可能你繪出的點陣圖是倒轉的,這是因為有些位圖的確是翻轉的。通過bitmapinfoheader的biheight可以判斷是正常還是翻轉,當biheight>0的時候顛倒,它小於0的時候正常,不過測試寫到現在看到的檔案都是顛倒過來的。

BMP檔案結構的探索

一 檔案格式 bmp檔案是非常常用的位 件,無論是遊戲還是其他都被廣泛使用。針對bmp檔案的處理也有一堆現成的api進行呼叫,然而檔案內部究竟怎樣,如何自己來解析這樣的檔案呢?為了消除無聊,我用了幾天時間來研究了一下,同時作為學習筆記,進行記錄。首先,整個bmp檔案的內容可以分為3到4塊。之所以分為...

BMP檔案結構

1.bmp檔案組成 bmp檔案由檔案頭 位圖資訊頭 顏色資訊和圖形資料四部分組成。2.bmp檔案頭 bmp檔案頭資料結構含有bmp檔案的型別 檔案大小和點陣圖起始位置等資訊。其結構定義如下 typedef struct tagbitmapfileheader bitmapfileheader 3.位...

BMP檔案結構

1.bmp檔案組成 bmp檔案由檔案頭 位圖資訊頭 顏色資訊和圖形資料四部分組成。2.bmp檔案頭 bmp檔案頭資料結構含有bmp檔案的型別 檔案大小和點陣圖起始位置等資訊。其結構定義如下 typedef struct tagbitmapfileheader bitmapfileheader 3.位...