weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評(píng)論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          位圖文件讀寫綜述

          作者:吉林大學(xué) 胡卓瑋一、位圖文件結(jié)構(gòu)
          1. 位圖文件頭
          2. 位圖信息
            2.1 位圖信息頭
            2.2 顏色表
          3. 位圖數(shù)據(jù)

          二、位圖文件讀寫操作

          1. 類的聲明
          2. 位圖的讀取
          3. 位圖讀取過程中的調(diào)色板的創(chuàng)建和調(diào)用
          4. 位圖的顯示
          5. 位圖的存儲(chǔ)
          6. 新位圖的創(chuàng)建
          7. 其它問題

          三、CFG_DIB的使用


          下載本文配套代碼


          關(guān)于位圖文件操作的資料很多。為了方便開發(fā)人員的工作,寫下本文,介紹了位圖文件結(jié)構(gòu),在此基礎(chǔ)之上設(shè)計(jì)了通用類CFG_DIB,用于進(jìn)行位圖文件的讀寫操作。

          一、位圖文件結(jié)構(gòu)

          位圖文件由三部分組成:文件頭 + 位圖信息 + 位圖像素?cái)?shù)據(jù)

          1、位圖文件頭。位圖文件頭主要用于識(shí)別位圖文件。以下是位圖文件頭結(jié)構(gòu)的定義:

          typedef struct tagBITMAPFILEHEADER { // bmfh 
              WORD    bfType; 
              DWORD   bfSize; 
              WORD    bfReserved1; 
              WORD    bfReserved2; 
              DWORD   bfOffBits; 
          } BITMAPFILEHEADER;
          其中的bfType值應(yīng)該是“BM”(0x4d42),標(biāo)志該文件是位圖文件。bfSize的值是位圖文件的大小。
          2、位圖信息中所記錄的值用于分配內(nèi)存,設(shè)置調(diào)色板信息,讀取像素值等。
          以下是位圖信息結(jié)構(gòu)的定義:

          typedef struct tagBITMAPINFO {
              BITMAPINFOHEADER    bmiHeader;
              RGBQUAD             bmiColors[1];
          } BITMAPINFO;
          
          可見位圖信息也是由兩部分組成的:位圖信息頭 + 顏色表



          2.1位圖信息頭。位圖信息頭包含了單個(gè)像素所用字節(jié)數(shù)以及描述顏色的格式,此外還包括位圖的寬度、高度、目標(biāo)設(shè)備的位平面數(shù)、圖像的壓縮格式。以下是位圖信息頭結(jié)構(gòu)的定義:
          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; 
          
          下表是對(duì)結(jié)構(gòu)體當(dāng)中各個(gè)成員的說明:
          結(jié)構(gòu)成員
          說 明
          biSize結(jié)構(gòu)BITMAPINFOHEADER的字節(jié)數(shù),即sizeof(BITMAPINFOHEADER)*
          biWidth
          以像素為單位的圖像寬度*
          biHeight
          以像素為單位的圖像長(zhǎng)度*
          biplanes
          目標(biāo)設(shè)備的位平面數(shù)
          biBitCount
          每個(gè)像素的位數(shù)*(1)
          biCompression
          圖像的壓縮格式(這個(gè)值幾乎總是為0)
          biSizeImage
          以字節(jié)為單位的圖像數(shù)據(jù)的大小(對(duì)BI_RGB壓縮方式而言)
          biXPelsPermeter
          水平方向上的每米的像素個(gè)數(shù)
          biYpelsPerMeter
          垂直方向上的每米的像素個(gè)數(shù)
          biClrused
          調(diào)色板中實(shí)際使用的顏色數(shù)(2)
          biClrImportant
          現(xiàn)實(shí)位圖時(shí)必須的顏色數(shù)(3)

          說明:*是需要加以注意的部分,因?yàn)樗鼈兪俏覀冊(cè)谶M(jìn)行位圖操作時(shí)經(jīng)常參考的變量
          (1)對(duì)于每個(gè)像素的字節(jié)數(shù),分別有一下意義:
          0,用在JPEG格式中
          1,單色圖,調(diào)色板中含有兩種顏色,也就是我們通常說的黑白圖片
          4,16色圖
          8,256色圖,通常說的灰度圖
          16,64K圖,一般沒有調(diào)色板,圖像數(shù)據(jù)中每?jī)蓚€(gè)字節(jié)表示一個(gè)像素,5個(gè)或6個(gè)位表示一個(gè)RGB分量
          24,16M真彩色圖,一般沒有調(diào)色板,圖像數(shù)據(jù)中每3個(gè)字節(jié)表示一個(gè)像素,每個(gè)字節(jié)表示一個(gè)RGB分量
          32,4G真彩色,一般沒有調(diào)色板,每4個(gè)字節(jié)表示一個(gè)像素,相對(duì)24位真彩圖而言,加入了一個(gè)透明度,即RGBA模式

          (2)這個(gè)值通常為0,表示使用biBitCount確定的全部顏色,例外是使用的顏色樹木小于制定的顏色深度的顏色數(shù)目的最大值。

          (3)這個(gè)值通常為0,表示所有的顏色都是必需的

          2.2顏色表。顏色表一般是針對(duì)16位一下的圖像而設(shè)置的,對(duì)于16位和16位以上的圖像,由于其位圖像素?cái)?shù)據(jù)中直接對(duì)對(duì)應(yīng)像素的RGB(A)顏色進(jìn)行描述,因而省卻了調(diào)色板。而對(duì)于16位一下的圖像,由于其位圖像素?cái)?shù)據(jù)中記錄的只是調(diào)色板索引值,因而需要根據(jù)這個(gè)索引到調(diào)色板去取得相應(yīng)的RGB(A)顏色。顏色表的作用就是創(chuàng)建調(diào)色板。

          下圖是帶調(diào)色板和不帶調(diào)色板的位圖的簡(jiǎn)單示意圖

          圖1 帶調(diào)色板和不帶調(diào)色板位圖之間的區(qū)別

          顏色表是由顏色表項(xiàng)組成的,顏色表項(xiàng)結(jié)構(gòu)的定義如下:

          typedef struct tagRGBQUAD { // rgbq 
              BYTE    rgbBlue; 
              BYTE    rgbGreen; 
              BYTE    rgbRed; 
              BYTE    rgbReserved; 
          } RGBQUAD;
          其中需要注意的問題是,RGBQUAD結(jié)構(gòu)中的顏色順序是BGR,而不是平常的RGB。

          3、位圖數(shù)據(jù)。最后,在位圖文件頭、位圖信息頭、位圖顏色表之后,便是位圖的主體部分:位圖數(shù)據(jù)。根據(jù)不同的位圖,位圖數(shù)據(jù)所占據(jù)的字節(jié)數(shù)也是不同的,比如,對(duì)于8位位圖,每個(gè)字節(jié)代表了一個(gè)像素,對(duì)于16位位圖,每?jī)蓚€(gè)字節(jié)代表了一個(gè)像素,對(duì)于24位位圖,每三個(gè)字節(jié)代表了一個(gè)像素,對(duì)于32位位圖,每四個(gè)字節(jié)代表了一個(gè)像素。

          二、位圖文件讀寫操作

          認(rèn)識(shí)了位圖文件的結(jié)構(gòu)以后,對(duì)特定位圖文件進(jìn)行讀寫操作就顯得簡(jiǎn)單了。本文附帶的源代碼中包含了一個(gè)能夠方便進(jìn)行位圖讀寫操作的C++類。以下給出該類的使用參考,對(duì)于實(shí)現(xiàn)代碼中的關(guān)鍵部分做出了講解。

          1、類的聲明

          class CFG_DIB : public CObject  
          {
          public:
          	//默認(rèn)構(gòu)造函數(shù)
          	CFG_DIB();
          	//構(gòu)造函數(shù),根據(jù)圖象寬和高,以及記錄每個(gè)象素所需字節(jié)數(shù)來初始化
          	CFG_DIB(int width, int height, int nBitCounts);
          	virtual ~CFG_DIB();
          
          public:
          	HBITMAP m_hBitmap;
          	LPBYTE m_lpDIBits;					//DIB位的起始位置
          	LPBITMAPINFOHEADER m_lpBMPHdr;		//BITMAPINFOHEADER信息
          	LPVOID m_lpvColorTable;				//顏色表信息
          	HPALETTE m_hPalette;				//條調(diào)色板
          
          private:
          	DWORD m_dwImageSize;				//非BITMAPINFOHEADER或BITMAPFILEHEADER的位
          	int m_nColorEntries;				//顏色表項(xiàng)的個(gè)數(shù)
          
          //顯示參數(shù)
          public:
          	CPoint m_Dest;						//目的矩形域的左上角坐標(biāo)
          	CSize m_DestSize;					//顯示矩形的寬度和高度
          	CPoint m_Src;						//原矩形左下角坐標(biāo)
          	CSize m_SrcSize;					//原矩形寬度和高度
          
          public:
          	void InitDestroy();							//初始化變量
          	void ComputePaletteSize(int nBitCounts);	//計(jì)算調(diào)色板大小
          	void ComputeImage();						//計(jì)算圖象大小
          
          	//從BMP文件中讀入DIB信息
          	BOOL ReadFile(CFile* pFile);
          	//從BMP文件中讀入DIB信息,與ReadFile不同的是使用CreateSection創(chuàng)建位圖位
          	BOOL ReadSection(CFile* pFile, CDC* pDC = NULL);
          	//將DIB寫入文件,保存成BMP圖片格式
          	BOOL WriteFile(CFile* pFile);
          	//創(chuàng)建新的位圖文件,根據(jù)參數(shù)width,height,nBitCounts分配內(nèi)存空間
          	BOOL NewFile(int width, int height, int nBitCounts);
          	//關(guān)閉位圖文件
          	BOOL CloseFile();
          
          	//顯示位圖
          	BOOL Display(CDC* pDC);
          
          	HBITMAP CreateBitmap(CDC* pDC);				//用DIB創(chuàng)建DDB
          	HBITMAP CreateSection(CDC* pDC = NULL);		//創(chuàng)建位圖位數(shù)據(jù),即象素?cái)?shù)據(jù)
          	//如果DIB沒有顏色表,可以用邏輯調(diào)色板
          	BOOL SetLogPalette(CDC* pDC);
          	//如果DIB有顏色表,可以創(chuàng)建系統(tǒng)調(diào)色板
          	BOOL SetWinPalette();
          	//把DIB對(duì)象的邏輯調(diào)色板選進(jìn)設(shè)備環(huán)境里,然后實(shí)現(xiàn)調(diào)色板
          	UINT UseLogPalette(CDC* pDC);
          
          	//得到BitmapInfoHeader的大小,包含顏色表數(shù)據(jù)
          	int GetHeaderSize()
          	{
          		return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;
          	}
          	//得到圖像的高度
          	int GetHeight()
          	{
          		if(m_lpBMPHdr == NULL) return 0;
          		return m_lpBMPHdr->biHeight;
          	}
          	//得到圖像的寬度
          	int GetWidth()
          	{
          		if(m_lpBMPHdr == NULL) return 0;
          		return m_lpBMPHdr->biWidth;
          	}
          	//得到圖像的大小
          	int GetImageSize()
          	{
          		return m_dwImageSize;
          	}
          	long GetLineBit();		//得到一行的象素?cái)?shù)
          };
          2、位圖的讀取。
          CFG_DIB提供了兩個(gè)從位圖文件讀取位圖數(shù)據(jù)的方法:ReadFile和ReadSection,二者不同之處,前者使用動(dòng)態(tài)分配內(nèi)存的方法初始化存儲(chǔ)位位圖數(shù)據(jù)的指針,后者則使用API函數(shù),根據(jù)位圖信息初始化存儲(chǔ)位圖數(shù)據(jù)的指針。

          方法1
          m_lpDIBits = (LPBYTE) new char[m_dwImageSize];
          方法2
          m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), 
                   (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
                   (LPVOID*) &m_lpDIBits, NULL, 0);
          3、位圖讀取過程中的調(diào)色板的創(chuàng)建和調(diào)用。
          關(guān)于調(diào)色板的詳細(xì)情況,本文不作詳細(xì)介紹,只是對(duì)讀取位圖的過程中需要調(diào)用的對(duì)調(diào)色板進(jìn)行操作的相關(guān)函數(shù)進(jìn)行說明。

          讀取文件的過程中,計(jì)算出調(diào)色板大小,然后調(diào)用創(chuàng)建調(diào)色板函數(shù):

          ComputePaletteSize(m_lpBMPHdr->biBitCount);
          SetWinPalette();
          在顯示位圖之前,設(shè)置調(diào)色板:
          if(m_hPalette != NULL) {
               ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
          }
          4、位圖的顯示。
          位圖的顯示還是調(diào)用Windows的API函數(shù)來進(jìn)行,需要傳遞的參數(shù)包括當(dāng)前位圖信息頭,位圖數(shù)據(jù)等:
          ::StretchDIBits(pDC->GetSafeHdc(), m_Dest.x, m_Dest.y,
                                       m_DestSize.cx, m_DestSize.cy,
                                       m_Src.x, m_Src.y,
                                       m_SrcSize.cx, m_SrcSize.cy,
                                       m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr, 
                                       DIB_RGB_COLORS, SRCCOPY);
          其中的m_Dest,m_DestSize,m_Src,m_SrcSize分別代表了圖像在當(dāng)前設(shè)備上顯示的左上角坐標(biāo)和范圍以及需要顯示的源圖像的左下角坐標(biāo)和范圍。此處需要說明的是,位圖數(shù)據(jù)的字節(jié)數(shù)組是從圖像的最下面一行開始逐行想上存儲(chǔ)的,所以用戶在選取源位圖的現(xiàn)實(shí)范圍的時(shí)候需要特別注意!
          m_Dest,m_DestSize,m_Src,m_SrcSize需要在現(xiàn)實(shí)之前設(shè)置好。

          5、位圖的存儲(chǔ)。位圖的存儲(chǔ)用WriteFile實(shí)現(xiàn)。
          6、新位圖的創(chuàng)建。新位圖的創(chuàng)建由NewFile實(shí)現(xiàn)。需要的參數(shù)是位圖的寬度、高度、以及位圖像素占用的位數(shù)。
          7、其它問題。存取位圖數(shù)據(jù)的字節(jié)數(shù)組有個(gè)問題需要引起開發(fā)人員的注意:字節(jié)數(shù)組中每個(gè)掃描行的字節(jié)數(shù)必需是4的倍數(shù),如果不足要用0補(bǔ)齊。
          以下是處理的辦法:
          DWORD dwBytes = ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
          if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32) {
               dwBytes++;
          }
          dwBytes *= 4;
          m_dwImageSize = dwBytes * m_lpBMPHdr->biHeight;
          這段代碼按照要求算出了用于記錄圖像數(shù)據(jù)的字節(jié)數(shù)組的大小。

          三、CFG_DIB的使用

          以下是CFG_DIB的使用示例代碼。

          #include "fg_dib.h"
          
          CFG_DIB m_fgdib;
          
          //new file
          m_fgdib.NewFile(width, height, nbitnum);
          
          //open file
          CFile* pf;
          pf = new CFile;
          pf->Open(sFileName, CFile::modeRead);
          m_fgdib.ReadFile(pf);
          pf->Close();
          delete pf;
          
          //draw BMP
          m_fgdib.m_Dest.x = 0;
          m_fgdib.m_Dest.y = 0;
          m_fgdib.m_DestSize.cx = m_fgdib.GetWidth();
          m_fgdib.m_DestSize.cy = m_fgdib.GetHeight();
          m_fgdib.m_Src.x = 0;
          m_fgdib.m_Src.y = 0;
          m_fgdib.m_SrcSize.cx = m_fgdib.GetWidth();
          m_fgdib.m_SrcSize.cy = m_fgdib.GetHeight();
          CDC* pDC = GetDC();
          m_fgdib.Display(pDC);
          
          //close BMP
          m_fgdib.CloseFile();

          如果您在閱讀文章和使用代碼過程中遇到的問題,請(qǐng)與作者聯(lián)系:

          吉林省長(zhǎng)春市西民主大街6號(hào)地球探測(cè)科學(xué)與技術(shù)學(xué)院2001級(jí)碩士研究生(130026)
          歡迎訪問作者的主頁:Forevergis.6to23.com

          from: http://www.vckbase.com/document/viewdoc/?id=674

          posted on 2006-07-30 21:22 weidagang2046 閱讀(229) 評(píng)論(0)  編輯  收藏 所屬分類: Windows

          主站蜘蛛池模板: 岫岩| 凤城市| 调兵山市| 顺平县| 河池市| 清流县| 元谋县| 武城县| 安图县| 吴忠市| 内乡县| 曲松县| 锦州市| 永吉县| 盐边县| 阜新市| 怀来县| 灵寿县| 清远市| 望城县| 沐川县| 于都县| 高安市| 图们市| 安达市| 康平县| 北辰区| 北川| 江永县| 南乐县| 青浦区| 三台县| 麻阳| 五华县| 任丘市| 长垣县| 河北区| 武义县| 鹤峰县| 昌吉市| 五寨县|