4.2位圖的顯示 Visual C++ MFC中沒有提供一個(gè)專門的類來處理DIB位圖,因此,,為了方便地使用位圖文件,,我們有必要派生一個(gè)CDib類。類的源代碼如下: (1) CDib類的聲明
// DIB.h:類CDib聲明頭文件 #ifndef __DIB_H__ #define __DIB_H__ #include <wingdi.h> class CDib { public: CDib(); ~CDib();
BOOL Load( const char * ); BOOL Save( const char * ); BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY); BOOL SetPalette( CDC * );
private: CPalette m_Palette; unsigned char *m_pDib, *m_pDibBits; DWORD m_dwDibSize; BITMAPINFOHEADER *m_pBIH; RGBQUAD *m_pPalette; int m_nPaletteEntries; }; #endif
|
(2) CDib類的實(shí)現(xiàn)
// DIB.cpp:類CDib實(shí)現(xiàn)文件 #include "stdafx.h" #include "DIB.h"
CDib::CDib() { m_pDib = NULL; }
CDib::~CDib() { // 如果位圖已經(jīng)被加載,,釋放內(nèi)存 if (m_pDib != NULL) delete []m_pDib; } |
下面這個(gè)函數(shù)非常重要,,其功能為加載位圖,類似于CBitmap類的LoadBitmap函數(shù):
BOOL CDib::Load(const char *pszFilename) { CFile cf;
// 打開位圖文件 if (!cf.Open(pszFilename, CFile::modeRead)) return (FALSE);
// 獲得位圖文件大小,,并減去BITMAPFILEHEADER的長度 DWORD dwDibSize; dwDibSize = cf.GetLength() - sizeof(BITMAPFILEHEADER);
// 為DIB位圖分配內(nèi)存 unsigned char *pDib; pDib = new unsigned char[dwDibSize]; if (pDib == NULL) return (FALSE);
BITMAPFILEHEADER BFH;
// 讀取位圖文件數(shù)據(jù) try { // 文件格式是否正確有效 if ( cf.Read(&BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) || BFH.bfType != ’MB’ || cf.Read(pDib, dwDibSize) != dwDibSize) { delete []pDib; return (FALSE); } } catch (CFileException *e) { e->Delete(); delete []pDib; return (FALSE); }
// delete先前加載的位圖 if (m_pDib != NULL) delete m_pDib;
// 將臨時(shí)Dib數(shù)據(jù)指針和Dib大小變量賦給類成員變量 m_pDib = pDib; m_dwDibSize = dwDibSize;
// 為相應(yīng)類成員變量賦BITMAPINFOHEADER和調(diào)色板指針 m_pBIH = (BITMAPINFOHEADER*)m_pDib; m_pPalette = (RGBQUAD*) &m_pDib[sizeof(BITMAPINFOHEADER)];
// 計(jì)算調(diào)色板中實(shí)際顏色數(shù)量 m_nPaletteEntries = 1 << m_pBIH->biBitCount; if (m_pBIH->biBitCount > 8) m_nPaletteEntries = 0; else if (m_pBIH->biClrUsed != 0) m_nPaletteEntries = m_pBIH->biClrUsed;
// 為相應(yīng)類成員變量賦image data指針 m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)];
// delete先前的調(diào)色板 if (m_Palette.GetSafeHandle() != NULL) m_Palette.DeleteObject();
// 如果位圖中存在調(diào)色板,,創(chuàng)建LOGPALETTE 及CPalette if (m_nPaletteEntries != 0) { LOGPALETTE *pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries *sizeof(PALETTEENTRY)];
if (pLogPal != NULL) { pLogPal->palVersion = 0x300; pLogPal->palNumEntries = m_nPaletteEntries;
for (int i = 0; i < m_nPaletteEntries; i++) { pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed; pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen; pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue; }
//創(chuàng)建CPalette并釋放LOGPALETTE的內(nèi)存 m_Palette.CreatePalette(pLogPal); delete []pLogPal; } }
return (TRUE); }
//函數(shù)功能:保存位圖入BMP文件 BOOL CDib::Save(const char *pszFilename) { if (m_pDib == NULL) return (FALSE);
CFile cf; if (!cf.Open(pszFilename, CFile::modeCreate | CFile::modeWrite)) return (FALSE);
try { BITMAPFILEHEADER BFH; memset(&BFH, 0, sizeof(BITMAPFILEHEADER)); BFH.bfType = ’MB’; BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize; BFH.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_nPaletteEntries *sizeof(RGBQUAD);
cf.Write(&BFH, sizeof(BITMAPFILEHEADER)); cf.Write(m_pDib, m_dwDibSize); } catch (CFileException *e) { e->Delete(); return (FALSE); } return (TRUE); } |
下面這個(gè)函數(shù)也非常重要,其功能為在pDC指向的CDC中繪制位圖,,起點(diǎn)坐標(biāo)為(nX,nY),,繪制寬度和高度為nWidth、nHeight,,最后一個(gè)參數(shù)是光柵模式:
BOOL CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode) { if (m_pDib == NULL) return (FALSE);
// 獲取位圖寬度和高度賦值 if (nWidth == - 1) nWidth = m_pBIH->biWidth; if (nHeight == - 1) nHeight = m_pBIH->biHeight;
// 繪制位圖 StretchDIBits(pDC->m_hDC, nX, nY, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO*)m_pBIH, BI_RGB, mode);
return (TRUE); }
//函數(shù)功能:設(shè)置調(diào)色板 BOOL CDib::SetPalette(CDC *pDC) { if (m_pDib == NULL) return (FALSE);
// 檢查當(dāng)前是否有一個(gè)調(diào)色板句柄,,對于大于256色的位圖,為NULL if (m_Palette.GetSafeHandle() == NULL) return (TRUE);
// 選擇調(diào)色板,,接著實(shí)施之,,最后恢復(fù)老的調(diào)色板 CPalette *pOldPalette; pOldPalette = pDC->SelectPalette(&m_Palette, FALSE); pDC->RealizePalette(); pDC->SelectPalette(pOldPalette, FALSE);
return (TRUE); } |
從整個(gè)CDib類的代碼中我們可以看出,DIB位圖的顯示需遵循如下步驟: ?。?)讀取位圖,,本類中使用pDib = new unsigned char[dwDibSize]為位圖中的信息分配內(nèi)存,另一種方法是調(diào)用API函數(shù)CreateDIBSection,,譬如:
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS, (LPVOID*) &m_lpDIBits, NULL, 0); |
m_hBitmap定義為:
?。?)根據(jù)讀取的位圖信息,計(jì)算出調(diào)色板大小,,然后創(chuàng)建調(diào)色板,; (3)調(diào)用CDib::SetPalette( CDC *pDC )設(shè)置調(diào)色板,,需要用到CDC::SelectPalette及CDC::RealizePalette兩個(gè)函數(shù),; (4)調(diào)用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)函數(shù)繪制位圖,。在此函數(shù)中,,真正發(fā)揮顯示位圖作用的是對StretchDIBits API函數(shù)的調(diào)用。StretchDIBits函數(shù)具有縮放功能,其最后一個(gè)參數(shù)也是光柵操作的模式,。 下面給出DIB位圖的打開及顯示并在其中加入天極網(wǎng)logo的函數(shù)源代碼,。"DIB位圖"父菜單下"打開"子菜單的單擊事件消息處理函數(shù)為(其功能為打開位圖并顯示之):
void CBitMapExampleDlg::OnOpendibpic() { // 彈出文件對話框,讓用戶選擇位圖文件 CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL,"位圖文件(*.BMP)|*.bmp;*.BMP|"); if (IDOK == fileDialog.DoModal()) { // 加載位圖并顯示之 CDib dib; if (dib.Load(fileDialog.GetPathName())) { CClientDC dc(this); dib.SetPalette(&dc); dib.Draw(&dc); } } } |
"DIB位圖"父菜單下"標(biāo)記"子菜單的單擊事件消息處理函數(shù)為(其功能為給位圖加上天極網(wǎng)logo):
void CBitMapExampleDlg::OnMarkDibpic() { // 彈出文件對話框,,讓用戶選擇標(biāo)記logo CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL, "標(biāo)記位圖文件(*.BMP)|*.bmp;*.BMP|"); if (IDOK == fileDialog.DoModal()) { // 加載標(biāo)記logo位圖并與目標(biāo)位圖相與 CDib dib; if (dib.Load(fileDialog.GetPathName())) { CClientDC dc(this); dib.SetPalette(&dc); dib.Draw(&dc, 0, 0, - 1, - 1, SRCAND); } } } |
圖4顯示了DIB位圖加載天極網(wǎng)logo后的效果,,要好于圖3中加天極網(wǎng)logo后的DDB位圖。圖4顯示的是真彩色位圖相互與的結(jié)果,,而圖3中的圖像顏色被減少了,。
圖4 在DIB位圖中加入天極網(wǎng)logo
|
5. 結(jié)束語
本文介紹了位圖及調(diào)色板的概念,并講解了DDB位圖與DIB位圖的區(qū)別,。在此基礎(chǔ)上,,本文以實(shí)例講解了DDB位圖和DIB位圖的操作方式。DDB位圖的處理相對比較簡單,,對于DIB位圖,,我們需要定義一個(gè)MFC所沒有的新類CDib,它屏蔽位圖信息的讀取及調(diào)色板創(chuàng)建的技術(shù)細(xì)節(jié),,應(yīng)用程序可以方便地使用之,。 本文中的所有程序在Visual C++6.0及Windows XP平臺上調(diào)試通過。
|