BMP文件結(jié)構(gòu)的探索._第1頁(yè)
BMP文件結(jié)構(gòu)的探索._第2頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、BMP 文件結(jié)構(gòu)的探索 WhatIf 2004-9-10 一、文件格式 Bmp 文件是非常常用的位圖文件,無(wú)論是游戲還是其他都被廣泛使用。針對(duì) bmp 文件的處理也有一堆 現(xiàn)成的 api進(jìn)行調(diào)用,然而文件內(nèi)部究竟怎樣,如何自己來(lái)解析這樣的文件呢?為了消除無(wú)聊,我用了幾 天時(shí)間來(lái)研究了一下,同時(shí)作為學(xué)習(xí)筆記,進(jìn)行記錄。 首先,整個(gè) bmp文件的內(nèi)容可以分為 3到 4塊。之所以分為 3到 4 塊而不是固定的值,是因?yàn)?,?duì)于 bmp來(lái)說(shuō)可能存在調(diào)色板或者一些掩碼。具體稍候討論。 第一塊是 bmp的文件頭用于描述整個(gè) bmp文件的情況。結(jié)構(gòu)如下: typedef struct tagBITMAPFIL

2、EHEADER WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; BITMAPFILEHEADER, *PBITMAPFILEHEADER; 這些信息相當(dāng)有用,如果你想直接來(lái)解析 bmp 文件。第一個(gè) bfType用于表示文件類型,如果它是 bmp 文件,那么它這個(gè)位置的值一定是 ”BM ”也就是 0 x4D42。第二個(gè) bfSize表示整個(gè)文件的字節(jié)數(shù)。 第三 第四個(gè) 則保留,目前無(wú)意義,最后一個(gè)相當(dāng)重要,表示,位圖的數(shù)據(jù)信息離文件頭的偏移量,以字節(jié)為單 位。 第二塊是位圖信息頭,即

3、 BITMAPINFOHEADER ,用于描述整個(gè)位圖文件的情況。以下挑重要的數(shù) 據(jù)進(jìn)行解釋 typedef struct tagBITMAPINFOHEADER DWORD biSize; / 表示本結(jié)構(gòu)的大小 LONG biWidth; / 位圖的寬度 LONG biHeight; / 位圖的高度 WORD biPlanes; / 永遠(yuǎn)為 1 ,由于沒有用過(guò)所以 沒做研究 附 msdn解釋 / Specifies the number of planes for the target device. This value must be set to 1. WORD biBitCount;

4、/ 位圖的位數(shù) 分為 1 4 8 16 24 32 本文沒對(duì) 1 4進(jìn)行研究 DWORD biCompression; / 本以為壓縮類型,但是卻另外有作用,稍候解釋 DWORD biSizeImage; / 表示位圖數(shù)據(jù)區(qū)域的大小以字節(jié)為單位 LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; BITMAPINFOHEADER, *PBITMAPINFOHEADER; 第三塊就是調(diào)色板信息或者掩碼部分, 如果是 8位位圖 則存放調(diào)色板;16與 32位 位圖則存放 RGB 顏色的掩

5、碼,這些掩碼以 DWOR大小來(lái)存放。 最后一塊就是位圖的數(shù)據(jù)實(shí)體。 以上文件信息可以在任意一篇 bmp 文件結(jié)構(gòu)的文章中找到描述,所以本文只是稍微帶過(guò)。二、4 字節(jié)對(duì)其問(wèn)題 關(guān)于數(shù)據(jù)讀取。Bmp文件有個(gè)重要特性,那就是對(duì)于數(shù)據(jù)區(qū)域而言,每行的數(shù)據(jù)它必須湊滿 4 字節(jié), 如果沒有滿,則用冗余的數(shù)據(jù)來(lái)補(bǔ)齊。這個(gè)特性直接影響到我們讀取位圖數(shù)據(jù)的方法,因?yàn)樵谖覀兛磥?lái) (x,y )的數(shù)據(jù)應(yīng)該在 y*width+x 這樣的位置上 但是因?yàn)闀?huì)有冗余信息 那么必須將 width 用 width 該行 的冗余量來(lái)處理,而由于位圖文件有不同的位數(shù),所以這樣的計(jì)算也不盡相同。 下面列出計(jì)算偏移量的一般公式。 首先將

6、位圖信息讀入一個(gè) UCHAR勺 buffer 中: 8 位: int pitch; if (width%4=0) pitch=width; else pitch=width+4-width%4; index=buffery*pitch+x; 因?yàn)?8 位位圖的數(shù)據(jù)區(qū)域存放的是調(diào)色板索引值,所以只需讀取這 個(gè) index 16 位 int pitch=width+width%2; buffer(y*pitch+x)*2 buffer(i*pitch+j)*2 1 兩個(gè) UCHAF內(nèi),存放的是(x,y)處的顏色信息 24 位 int pitch=width%4; buffer(y*width+x)

7、*3+y*pitch; buffer(y*width+x)*3+y*pitch+1; buffer(y*width+x)*3+y*pitch+2; 32 位 由于一個(gè)象素就是 4字節(jié) 所以無(wú)需補(bǔ)齊 雖然計(jì)算比較繁瑣,但是這些計(jì)算是必須的,否則當(dāng)你的位圖每行的象素?cái)?shù)不是 4 的倍數(shù),那么 y*width+x 帶給你的是一個(gè)扭曲的圖片, 當(dāng)然如果你想做這樣的旋轉(zhuǎn), 也不錯(cuò)啊, 至少我因?yàn)橐婚_始沒有考 慮(不知道這個(gè)特性) 讓一個(gè)每行象素少 1字節(jié)的 16位圖片變成了扭曲的菱形。 三、有了數(shù)據(jù)分離 RG分量。 由于我的測(cè)試代碼用了 GDI,所以我必須講得到的某一個(gè)點(diǎn)的值 分離成 24位模式下的 RG

8、B離,這不 是一件容易的工作。位圖麻煩的地方之一就是他的格式太多,所以我們還是要分格式再討論。 8 位 通過(guò)第二部分提到的操作我們得到了一個(gè) index,這個(gè)值的范圍是 0255 共 256個(gè)正好是調(diào)色板的 顏色數(shù)量。 在 8位 bmp圖片中 數(shù)據(jù)信息前 256個(gè) RGBQUAD大小開始就是調(diào)色板的信息。不過(guò)如果要組織成調(diào)色板 還要一定的轉(zhuǎn)換 因?yàn)槔锩媸?RGBQUAD息 r b兩個(gè)與調(diào)色板中的順序是顛倒的。因?yàn)槲也恍枰{(diào)色板設(shè)置 所以我字節(jié)讀取到 RGBQUAD組中,并且通過(guò)下面的表達(dá)式獲取 RGBt: UCHAR r=quadindex.rgbRed; UCHAR g=quadindex.

9、rgbGreen; UCHAR b=quadindex.rgbBlue; 16 位 這是最麻煩的一個(gè)。因?yàn)樵谔幚頃r(shí)有 555 565 兩種格式的區(qū)別,而且還有所謂壓縮類型的區(qū)別。 之前的 bitmapinfoheader 里面提到一個(gè) biCompression 現(xiàn)在我們分兩種情況討論: BI_RGB 和 BI_BITFIELDS 當(dāng)他等于 BI_RGB 寸只有 555這種格式,所以可以放心大膽的進(jìn)行如下的數(shù)據(jù)分離: UCHAR b=buffer(i*pitch+j)*2&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j

10、)*25); UCHAR r=(buffer(i*pitch+j)*2+13; 希望不要被這個(gè)表達(dá)式折磨的眼花繚亂,我想既然你在看這篇文章,你就有能力閱讀這樣的代碼,否 則只能說(shuō)你還沒有到閱讀這方面的地步,需要去學(xué)習(xí)基礎(chǔ)的語(yǔ)法了。 有一點(diǎn)值得提醒的是由于有較多的位操作 ,所以在處理的時(shí)候在前一次操作的上面加上一對(duì)括號(hào), 我就曾經(jīng)因?yàn)闆]有加而導(dǎo)致出現(xiàn)誤差,另外雖然 buffer 中一個(gè)元素代表的是一個(gè) UCHARf 旦是右移操作會(huì)自 動(dòng)增長(zhǎng)為兩字節(jié) 所以需要在進(jìn)行一次與操作截取低位的 1字節(jié)數(shù)據(jù)。 現(xiàn)在討論 BI_BITFIELDS。 這個(gè)模式下 既可以有 555 也可以有 565 。 555

11、格式 x rrrrr gggggbbbbb 565 格式 rrrrr ggggggbbbbb 顯然不同的格式處理不同,所以我們要首先判斷處到底屬于那種格式。 Bitmapinfoheader 的 biCompression 為 BI_BITFIELDS 時(shí),在位圖數(shù)據(jù)區(qū)域前存在一個(gè) RGB掩碼的描述 是 3個(gè) DWORD,我們只需要讀取其中的 R或者 G的掩碼,來(lái)判斷是那種格式。 以紅色掩碼為例 0111110000000000 的時(shí)候就是 555格式 1111100000000000 就是 565格式。 以下是 565格式時(shí)的數(shù)據(jù)分離: UCHAR b=buffer(i*pitch+j)*2

12、&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+12)+(buffer(i*pitch+j)*25); UCHAR r=buffer(i*pitch+j)*2+13; 現(xiàn)在我們得到了 RG各自的分量,但是還有一個(gè)新的問(wèn)題,那就是由于兩字節(jié)表示了 3 個(gè)顏色 555下 每個(gè)顏色最多到 Ox仆 565格式下最大的綠色分量也就 0 x3F。所以我們需要一個(gè)轉(zhuǎn)換 color=color*255/ 最大 顏色數(shù) 即可 如 565下 RGB(r*0 xFF/0 x1F,g*0 xFF/0 x3F,b*0 xFF/0 x1F) 24 位 UCHAR b=buffer(i*w

13、idth+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; 四、剩余的問(wèn)題 當(dāng)數(shù)據(jù)取到了,顏色也分離出來(lái)了 ,但是可能你繪出的位圖是倒轉(zhuǎn)的,這是因?yàn)橛行┪粓D的確是翻 轉(zhuǎn)的。通過(guò) bitmapinfoheader 的 biHeight 可以判斷是正常還是翻轉(zhuǎn),當(dāng)

14、biHeight0 的時(shí)候顛倒,它小于 0 的時(shí)候正常,不過(guò)測(cè)試寫到現(xiàn)在看到的文件都是顛倒過(guò)來(lái)的 五、相關(guān)測(cè)試代碼: 采用 MFC目的只是實(shí)現(xiàn)自行解析位圖文件 void CBmpTestView:OnDraw(CDC* pDC) CBmpTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: 在此處為本機(jī)數(shù)據(jù)添加繪制代碼 if (filename=) return ; FILE *fp=fopen(filename,r); if (fp=NULL) pDC-TextOut(100,200,no file found); return

15、 ; BITMAPFILEHEADER fileheader; BITMAPINFO info; fread(&fileheader, sizeof (fileheader),1,fp); if (fileheader.bfType!=0 x4D42) pDC-TextOut(100,200, 無(wú)位圖文件 請(qǐng)選擇位圖文件 ); fclose(fp); return ; fread(&info.bmiHeader, sizeof (BITMAPINFOHEADER),1,fp); long width=info.bmiHeader.biWidth; long height=inf

16、o.bmiHeader.biHeight; UCHAR *buffer= newUCHARinfo.bmiHeader.biSizeImage; fseek(fp,fileheader.bfOffBits,0); fread(buffer,info.bmiHeader.biSizeImage,1,fp); if (info.bmiHeader.biBitCount=8) int pitch; if (width%4=0) pitch=width; else pitch=width+4-width%4; RGBQUAD quad256; fseek(fp,fileheader.bfOffBits

17、- sizeof (RGBQUAD)*256,0); fread(quad, sizeof (RGBQUAD)*256,1,fp); if (height0) /height0 表示圖片顛倒 for (int i=0;iheight;i+) for (int j=0;jSetPixel(j,height-i,RGB(r,g,b); else for (int i=0;i0-height;i+) for (int j=0;jSetPixel(j,i,RGB(r,g,b); else if (info.bmiHeader.biBitCount=16) int pitch=width+width%2

18、; if (height0) /height0 表示圖片顛倒 if (info.bmiHeader.biCompression=BI_RGB) / 該模式只有 555 for (int i=0;iheight;i+) for ( int j=0;jwidth;j+) /5 5 5 格式 UCHAR b=buffer(i*pitch+j)*2&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB

19、(r*0 xFF)/0 x1F,(g*0 xFF)/0 x1F,(b*0 xFF)/0 x1F); else if (info.bmiHeader.biCompression=BI_BITFIELDS) /該模式在 bitmapinfoheader 之后存在 RGBS碼 每個(gè)掩碼 1 DWORD fseek(fp,fileheader.bfOffBits- sizeof (DWORD )*3,0); DWORD rMask; fread(&rMask, sizeof (DWORD ),1,fp); if (rMask=0 x7C00) / 5 5 5 格式 MessageBeep(0)

20、; for ( int i=0;iheight;i+) for (int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB(r*0 xFF)/0 x1F,(g*0 xFF)/0 x1F,(b*0 xFF)/0 x1F); else if (rMask=0 xF800) /5 6 5 格式 for ( in

21、t i=0;iheight;i+) for (int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+12)+(buffer(i*pitch+j)*25); UCHAR r=buffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB(r*0 xFF/0 x1F,g*0 xFF/0 x3F,b*0 xFF/0 x1F); else if (info.bmiHeader.biCompression=BI_RGB) / 該模式只有 555

22、for (int i=0;i0-height;i+) for ( int j=0;jwidth;j+) /5 5 5 格式 UCHAR b=buffer(i*pitch+j)*2&0 x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,i,RGB(r*0 xFF)/0 x1F,(g*0 xFF)/0 x1F,(b*0 xFF)/0 x1F); else if (info.bmiHeader.biCompression=BI_BITFIELDS) /該模式在 bitmapinfoheader 之后存在 RGBS碼 每個(gè)掩碼 1 DWORD ITLXO03R*(+II9 一 d*D上 n q u qorAA( L vvL+

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論