位圖文件結構及平滑縮放

BMP位圖文件結構及平滑縮放

----  
用普通方法顯示BMP位圖,佔內存大,速度慢,在圖形縮小時,失真嚴重,在低顏色位數的設備上顯示高顏色位數的圖形時失真大。本文采用視頻函數顯示BMP位圖,可以消除以上的缺點。


----  
一、BMP文件結構


----   1.   BMP
文件組成


----   BMP
文件由文件頭、位圖信息頭、顏色信息和圖形數據四部分組成。


----   2.   BMP
文件頭


----   BMP
文件頭數據結構含有BMP文件的類型、文件大小和位圖起始位置等信息。


----  
其結構定義如下
:

typedef   struct   tagBITMAPFILEHEADER
{
WORDbfType;   //  
位圖文件的類型,必須爲
BM
DWORD   bfSize;   //  
位圖文件的大小,以字節爲單位

WORDbfReserved1;   //  
位圖文件保留字,必須爲
0
WORDbfReserved2;   //  
位圖文件保留字,必須爲
0
DWORD   bfOffBits;   //  
位圖數據的起始位置,以相對於位圖

//  
文件頭的偏移量表示,以字節爲單位

}   BITMAPFILEHEADER;

----   3.  
位圖信息頭
----

BMP
位圖信息頭數據用於說明位圖的尺寸等信息。

typedef   struct   tagBITMAPINFOHEADER{
DWORD   biSize;     //  
本結構所佔用字節數

LONG    biWidth;    //  
位圖的寬度,以像素爲單位

LONG    biHeight;    //  
位圖的高度,以像素爲單位

WORD   biPlanes;     //  
目標設備的級別,必須爲
1
WORD   biBitCount;  //  
每個像素所需位數,1(雙色), 4(16)8(256)24(真彩色)DWORD   biCompression;   //   位圖壓縮類型,必須是0(不壓縮),1(BI_RLE8壓縮類型)  

(BI_RLE4壓縮類型)之一                                                                                    
DWORD   biSizeImage;   //  
位圖的大小,以字節爲單位
LONGbiXPelsPerMeter;   //  
位圖水平分辨率,每米像素數

LONGbiYPelsPerMeter;   //  
位圖垂直分辨率,每米像素數

DWORD   biClrUsed;//  
位圖實際使用的顏色表中的顏色數

DWORD   biClrImportant;//  
位圖顯示過程中重要的顏色數

}   BITMAPINFOHEADER;

----   4.  
顏色表

----  
顏色表用於說明位圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結構,定義一種顏色。RGBQUAD結構的定義如下
:

typedef   struct   tagRGBQUAD   {
BYTErgbBlue;//  
藍色的亮度(值範圍爲
0-255)
BYTErgbGreen;   //  
綠色的亮度(值範圍爲
0-255)
BYTErgbRed;   //  
紅色的亮度(值範圍爲
0-255)
BYTErgbReserved;//  
保留,必須爲
0
}   RGBQUAD;
顏色表中RGBQUAD結構數據的個數有biBitCount來確定
:
biBitCount=1,4,8時,分別有2,16,256個表項
;
biBitCount=24時,沒有顏色表項。

位圖信息頭和顏色表組成位圖信息,BITMAPINFO結構定義如下
:
typedef   struct   tagBITMAPINFO   {
BITMAPINFOHEADER   bmiHeader;   //  
位圖信息頭

RGBQUAD   bmiColors[1];   //  
顏色表

}   BITMAPINFO;

----   5.  
位圖數據

----  
位圖數據記錄了位圖的每一個像素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。位圖的一個像素值所佔的字節數
:

biBitCount=1時,8個像素佔1個字節
;
biBitCount=4時,2個像素佔1個字節
;
biBitCount=8時,1個像素佔1個字節
;
biBitCount=24,1個像素佔3個字節
;
Windows
規定一個掃描行所佔的字節數必須是

4
的倍數(即以long爲單位),不足的以0填充,

一個掃描行所佔的字節數計算方法
:
DataSizePerLine=   (biWidth*   biBitCount+31)/8;  
//  
一個掃描行所佔的字節數

DataSizePerLine=   DataSizePerLine/4*4;   //  
字節數必須是4的倍數

位圖數據的大小(不壓縮情況下
):
DataSize=   DataSizePerLine*   biHeight;


----  
二、BMP位圖一般顯示方法

----   1.  
申請內存空間用於存放位圖文件


----   GlobalAlloc(GHND
FileLength);

----   2.  
位圖文件讀入所申請內存空間中


----   LoadFileToMemory(   mpBitsSrc
mFileName);

----   3.  
OnPaint等函數中用創建顯示用位圖


----  
CreateDIBitmap()創建顯示用位圖,用CreateCompatibleDC()創建兼容
DC,

----  
SelectBitmap()選擇顯示位圖。


----   4.  
BitBltStretchBlt等函數顯示位圖


----   5.  
DeleteObject()刪除所創建的位圖


----  
以上方法的缺點是:   1)顯示速度慢;   2)   內存佔用大;   3)   位圖在縮小顯示時圖形失真大,(可通過安裝字體平滑軟件來解決);   4)   在低顏色位數的設備上(256顯示模式)顯示高顏色位數的圖形(如真彩色)失真嚴重。


----  
三、BMP位圖縮放顯示


----  
DrawDib視頻函數來顯示位圖,內存佔用少,速度快,而且還可以對圖形進行淡化(Dithering)處理。淡化處理是一種圖形算法,可以用來在一個支持比圖像所用顏色要少的設備上顯示彩色圖像。BMP位圖顯示方法如下
:

----   1.  
打開視頻函數DrawDibOpen(),一般放在在構造函數中


----   2.  
申請內存空間用於存放位圖文件

----   GlobalAlloc(GHND
FileLength);

----   3.  
位圖文件讀入所申請內存空間中


----   LoadFileToMemory(mpBitsSrc
mFileName);

----   4.  
OnPaint等函數中用DrawDibRealize()DrawDibDraw()顯示位圖


----   5.  
關閉視頻函數DrawDibClose(),一般放在在析構函數中

----  
以上方法的優點是:   1)顯示速度快;   2)   內存佔用少;   3)   縮放顯示時圖形失真小,4)   在低顏色位數的設備上顯示高顏色位數的圖形時失真小;   5)   通過直接處理位圖數據,可以製作簡單動畫。

----  
四、CViewBimap類編程要點


----   1.  
CViewBimap類中添加視頻函數等成員


HDRAWDIB   m_hDrawDib;   //  
視頻函數

HANDLEmhBitsSrc;   //  
位圖文件句柄(內存
)
LPSTR   mpBitsSrc;   //  
位圖文件地址(內存
)
BITMAPINFOHEADER   *mpBitmapInfo;   //  
位圖信息頭



----   2.  
CViewBimap類構造函數中添加打開視頻函數

----   m_hDrawDib=   DrawDibOpen();

----   3.  
CViewBimap類析構函數中添加關閉視頻函數


if(   m_hDrawDib   !=   NULL)
{
DrawDibClose(   m_hDrawDib);
m_hDrawDib   =   NULL;
}


----   4.  
CViewBimap類圖形顯示函數OnPaint中添加
GraphicDraw()
voidCViewBitmap::OnPaint()
{
CPaintDC   dc(this);   //   device   context   for   painting
GraphicDraw(   );
}

voidCViewBitmap::GraphicDraw(   void   )
{
CClientDC   dc(this);   //   device   context   for   painting
BITMAPFILEHEADER   *pBitmapFileHeader;
ULONG   bfoffBits=   0;
CPoint   Wid;

//  
圖形文件名有效
  (=0   BMP)
if(   mBitmapFileType   <   ID_BITMAP_BMP   )   return;

//  
圖形文件名有效
  (=0   BMP)
//  
準備顯示真彩位圖

pBitmapFileHeader=   (BITMAPFILEHEADER   *)   mpBitsSrc;
bfoffBits=   pBitmapFileHeader-> bfOffBits;

//  
使用普通函數顯示位圖


if(   m_hDrawDib   ==   NULL   ||   mDispMethod   ==   0)
{
HBITMAP   hBitmap=::CreateDIBitmap(dc.m_hDC,
mpBitmapInfo,   CBM_INIT,   mpBitsSrc+bfoffBits,
(LPBITMAPINFO)   mpBitmapInfo,DIB_RGB_COLORS);  
//  
建立位圖

HDC   hMemDC=::CreateCompatibleDC(dc.m_hDC);//  
建立內存

HBITMAP   hBitmapOld=   SelectBitmap(hMemDC,   hBitmap);   //  
選擇對象

//  
成員CRect   mDispR用於指示圖形顯示區域的大小
.
//  
成員CPoint   mPos用於指示圖形顯示起始位置座標
.
if(   mPos.x   >   (mpBitmapInfo-   > biWidth   -   mDispR.Width()   ))
mPos.x=   mpBitmapInfo-> biWidth   -   mDispR.Width()   ;
if(   mPos.y   >   (mpBitmapInfo-   > biHeight-   mDispR.Height()))
mPos.y=   mpBitmapInfo-   > biHeight-   mDispR.Height();
if(   mPos.x   <   0   )   mPos.x=   0;
if(   mPos.y   <   0   )   mPos.y=   0;

if(   mFullViewTog   ==   0)
{
//  
顯示真彩位圖

::BitBlt(dc.m_hDC,0,0,   mDispR.Width(),   mDispR.Height(),
hMemDC,mPos.x,mPos.y,   SRCCOPY);
}   else   {
::StretchBlt(dc.m_hDC,0,0,   mDispR.Width(),   mDispR.Height(),
hMemDC,0,0,   mpBitmapInfo-   > biWidth,   mpBitmapInfo-
> biHeight,   SRCCOPY);
}
//  
結束顯示真彩位圖

::DeleteObject(SelectObject(hMemDC,hBitmapOld));  
//  
     

}   else   {

//  
使用視頻函數顯示位圖


if(   mPos.x   >   (mpBitmapInfo-   > biWidth   -   mDispR.Width()   ))
mPos.x=   mpBitmapInfo-   > biWidth   -   mDispR.Width()   ;
if(   mPos.y   >   (mpBitmapInfo-   > biHeight-   mDispR.Height()))
mPos.y=   mpBitmapInfo-   > biHeight-   mDispR.Height();
if(   mPos.x   <   0   )   mPos.x=   0;
if(   mPos.y   <   0   )   mPos.y=   0;

//  
顯示真彩位圖

DrawDibRealize(   m_hDrawDib,   dc.GetSafeHdc(),   TRUE);

if(   mFullViewTog   ==   0)
{
Wid.x=   mDispR.Width();
Wid.y=   mDispR.Height();
//   1:1  
顯示時,   不能大於圖形大小

if(   Wid.x   >   mpBitmapInfo-   > biWidth   )
Wid.x   =   mpBitmapInfo-   > biWidth;
if(   Wid.y   >   mpBitmapInfo-   > biHeight)
Wid.y   =   mpBitmapInfo-   > biHeight;

DrawDibDraw(m_hDrawDib, dc.GetSafeHdc()
,   0,   0,   Wid.x,   Wid.y,
mpBitmapInfo,   (LPVOID)   (mpBitsSrc+bfoffBits),
mPos.x,   mPos.y,   Wid.x,   Wid.y,   DDF_BACKGROUNDPAL);
}   else   {
DrawDibDraw(   m_hDrawDib,   dc.GetSafeHdc(),
0,   0,   mDispR.Width(),   mDispR.Height(),
mpBitmapInfo,   (LPVOID)   (mpBitsSrc+bfoffBits),
0,   0,   mpBitmapInfo-   > biWidth,   mpBitmapInfo-   > biHeight,
DDF_BACKGROUNDPAL);
}
}
return;
}


----  
五、使用CViewBimap類顯示BMP位圖


----   1.  
Visual   C++5.0中新建一個名稱爲mymap工程文件,類型爲MFC   AppWizard[exe]。在編譯運行通過後,在WorkSpace(如被關閉,Alt_0打開)點擊ResourceView,點擊Menu左側的+符號展開Menu條目,雙擊IDR_MAINFRAME條目,進入菜單資源編輯,在 '“查看(V)”下拉式菜單(英文版爲View下拉式菜單)的尾部添加“ViewBitmap”條目,其IDID_VIEW_BITMAP

----   2.  
Visual   C++5.0中點擊下拉式菜單Project-   > Add   To   project-   > Files...,將Bitmap0.hBitmap0.cpp添加到工程文件中。

----   3.  
Visual   C++5.0中按Ctrl_W進入MFC   ClassWizard,選擇類名稱爲CMainFrame,ObjectIDs:   ID_VIEW_BITMAPMessages選擇Command,然後點擊Add   Fucction按鈕

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章