Visual C++中DDB與DIB位圖編程全攻略
來源: 天極網
1. 基本概念
先來用通俗的語句講解位圖和調色板的概念。
我們知道,自然界中的所有顏色都可以由紅、綠、藍(R,G,B)三基色組合而成。針對含有紅、綠、藍色成分的多少,可以對其分別分成0~255個等級,而紅、綠、藍的不同組合共有256×256×256種,因此約能表示1600萬種顏色。對于人眼而言,這已經是"真彩色"了。
對每個像素進行了(R,G,B)量化的圖像就是位圖,其在計算機中對應文件的擴展名一般為.bmp。既然用R,G,B的量化值就可以直接記錄一張位圖的所有像素,那我們需要調色板干什么呢?
首先,我們可以計算完全利用(R,G,B)組合來存儲一個800×600的位圖所需要的空間為:
800×600×3 = 1440000(字節(jié))= 1.37M(字節(jié))
驚人的大!因此,調色板橫空出世了,它的功能在于緩解位圖文件存儲空間過大的問題。
假設一個位圖為16色,其像素總數為800×600。我們只需要用4個bit就可以存儲這個位圖的每個像素在16種顏色中所處的等級,然后調色板提供了這16種等級對應的(R,G,B)值,這樣,存儲這個16色位圖只需要:
800×600×4/8 = 240000(字節(jié))= 0.22 M(字節(jié))
額外的存儲R,G,B表的開銷(即調色板Palette,也稱為顏色查找表LUT)僅僅為16×3=48字節(jié)。
存儲空間被大為減少!
常見的位圖有單色、16色、256色、16位及24位真彩色5種,對于前三者(即不大于256色)都可以調色板方式進行存儲,而對16位及24位真彩色以調色板進行存儲是不劃算的,它們直接按照R,G,B分量進行存儲。
在此基礎上我們來分析DDB位圖(Device-dependent bitmap,與設備相關的位圖)與DIB位圖(Device-independent bitmap,與設備無關的位圖)的概念以及二者的區(qū)別。
DDB依賴于具體設備,它只能存在于內存中(視頻內存或系統(tǒng)內存),其顏色模式必須與特定的輸出設備相一致,使用系統(tǒng)調色板。一般只能載入色彩較簡單的DDB位圖,對于顏色較豐富的位圖,需使用DIB才能長期保存。
DIB不依賴于具體設備,可以用來永久性地保存圖象。DIB一般是以*.BMP文件的形式保存在磁盤中的,有時也會保存在*.DIB文件中。 DIB位圖的特點是將顏色信息儲存在位圖文件自身的顏色表中,應用程序要根據此顏色表為DIB創(chuàng)建邏輯調色板。因此,在輸出一幅DIB位圖之前,程序應該將其邏輯調色板選入到相關的設備上下文并實現到系統(tǒng)調色板中。
2. 例程簡述
本文后續(xù)的講解都基于這樣的一個例子工程,它是一個基于對話框的MFC應用程序,包括2個父菜單:
(1) DDB位圖
DDB位圖父菜單又包括兩個子菜單:
a. ID:IDM_LOADDDBPIC caption:加載
單擊事件:加載資源中的DDB位圖并顯示之
b. ID:IDM_MARK_DDBPIC caption:標記
單擊事件:在DIB位圖中透明地添加天極網logo
(2) DIB位圖
DIB位圖父菜單又包括兩個子菜單:
a. ID:IDM_OPENDIBPIC caption:打開
單擊事件:彈出文件對話框,打開.bmp位圖文件,并顯示
b. ID:IDM_MARK_DIBPIC caption:標記
單擊事件:在DIB位圖中透明地添加天極網logo
工程中還包含下列位圖資源:
(1)IDB_LOADED_BITMAP:要加載的位圖資源
(2)IDB_YESKY_BITMAP:天極網logo
后續(xù)篇章將集中在對4個子菜單單擊事件消息處理函數的講解,下面的代碼是整個對話框類CBitMapExampleDlg的消息映射:
BEGIN_MESSAGE_MAP(CBitMapExampleDlg, CDialog)
//{{AFX_MSG_MAP(CBitMapExampleDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_COMMAND(IDM_LOADDDBPIC, OnLoadddbpic)
ON_COMMAND(IDM_MARK_DDBPIC, OnMarkDdbpic)
ON_COMMAND(IDM_OPENDIBPIC, OnOpendibpic)
ON_COMMAND(IDM_MARK_DIBPIC,OnMarkDibpic) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
?
3. DDB位圖編程
先看DDB加載按鈕的單擊事件代碼:
void CBitMapExampleDlg::OnLoadddbpic()
{
1: CBitmap bmpDraw;
2: bmpDraw.LoadBitmap( IDB_LOADED_BITMAP );//裝入要加載的DDB位圖
3: BITMAP bmpInfo;
4: bmpDraw.GetBitmap( &bmpInfo ); //獲取要加載DDB位圖的尺寸
5: CDC memDC;//定義一個兼容DC
6: CClientDC dc( this );
7: memDC.CreateCompatibleDC( &dc );//創(chuàng)建兼容DC
8: CBitmap* pbmpOld = memDC.SelectObject( &bmpDraw );//保存原有DDB,并選入新DDB入DC
9: dc.BitBlt( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCCOPY );
10: memDC.SelectObject( pbmpOld );//選入原DDB
}
上述代碼將產生如圖1所示的效果,位圖被安置在對話框(0,0)坐標開始的位置上。
圖1 加載DDB位圖資源
?
我們來逐行解析上述代碼是怎樣產生圖1的效果的。
第1、2行定義了一個CBitmap對象,并調用其成員函數LoadBitmap加載工程中的位圖資源IDB_LOADED_BITMAP。第3、4行定義了BITMAP結構體的實例并調用CBitmap的成員函數GetBitmap獲得位圖信息,BITMAP結構體定義在頭文件中,其形式為:
/* Bitmap Header Definition */
typedef struct tagBITMAP
{
LONG bmType; //必需為0
LONG bmWidth; //位圖的寬度(以像素為單位)
LONG bmHeight; //位圖的高度(以像素為單位)
LONG bmWidthBytes; //每一掃描行所需的字節(jié)數,應是偶數
WORD bmPlanes; //色平面數
WORD bmBitsPixel; //色平面的顏色位數
LPVOID bmBits; //指向存儲像素陣列的數組
} BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP;
第5~8行的作用是:構建一個CDC對象,調用CDC::CreateCompatibleDC創(chuàng)建一個兼容的內存設備上下文,接著調用CDC::SelectObject將DDB選入內存設備上下文中。
第9行調用函數CDC::BitBlt繪制位圖,CDC::BitBlt的原型為:
CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int xSrc, int ySrc, DWORD dwRop)
CDC::BitBlt執(zhí)行的操作為將源DC中位圖復制到目的DC中。其中前四個參數為目的區(qū)域的坐標(x,y)及長度和寬度(Width, nHeight),第五個參數是源DC指針,接下來的參數是源DC中的起始坐標,最后一個參數為光柵操作的類型。
第10行調用CDC::SelectObject把原來的DDB選入到內存設備上下文中并使新DDB脫離出來。
與CDC::BitBlt對應的還有另一個函數CDC::StretchBlt,它具有縮放功能,其原型為:
BOOL CDC::StretchBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int
xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop);
該函數把位圖從源矩形拷貝到目的矩形中,如果源和目的矩形尺寸不同,那么將縮放位圖的功能以適應目的矩形的大小。函數的大部分參數與BitBlt的相同,但多了兩個參數nSrcWidth和nSrcHeight用來指定源矩形的寬和高。
如果我們將函數CBitMapExampleDlg::OnLoadddbpic() 中的第9行改為:
CRect clientRect;
GetClientRect(&clientRect); //獲得對話框窗口的大小
dc.StretchBlt(0, 0, clientRect.right, clientRect.bottom, &memDC, 0, 0,
bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);
則單擊加載按鈕后的對話框如圖2所示,位圖被拉伸至整個對話框的范圍。
圖2 拉伸位圖
CDC::BitBlt和dc.StretchBlt函數中的dwRop參數較為有用,它定義光柵操作的類型。請看"DDB位圖"父菜單下"標記"子菜單單擊事件的消息處理函數代碼:
void CBitMapExampleDlg::OnMarkDdbpic()
{
CBitmap bmpDraw;
bmpDraw.LoadBitmap(IDB_YESKY_BITMAP); //裝入天極網logo DDB位圖資源
BITMAP bmpInfo;
bmpDraw.GetBitmap(&bmpInfo); //獲取天極網logo位圖的尺寸
CDC memDC; //定義一個兼容DC
CClientDC dc(this);
memDC.CreateCompatibleDC(&dc); //創(chuàng)建DC
CBitmap *pbmpOld = memDC.SelectObject(&bmpDraw);
//保存原有DDB,并選入天極網logo位圖入DC
dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND);
memDC.SelectObject(pbmpOld); //選入原DDB
}
單擊該按鈕后,將產生如圖3的效果,天極網的logo被透明地添加到了位圖中!
圖3 在DDB位圖中加入天極網logo
能產生這個效果的原因在于我們在代碼行:
dc.BitBlt ( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND );
中使用了參數SRCAND(不同于先前代碼中SRCCOPY,它僅僅意味著復制源位圖到目的位圖),它的含義為源和目的間進行AND操作。我們不知道天極網的編輯同志是怎么為文章中的圖片加logo的,有可能他們就使用了具有自動AND功能的圖像加logo批處理軟件。的確,我們可以利用例程中的原理寫一個批處理軟件,一次對一堆圖片自動添加logo。
參數dwRop除了可以為SRCAND和SRCCOPY外,還可以有如下取值:
BLACKNESS:輸出區(qū)域為黑色
DSTINVERT:反轉目的位圖
MERGECOPY:用與操作把圖案(Pattern)與源位圖融合起來
MERGEPAINT:用或操作把反轉的源位圖與目的位圖融合起來
NOTSRCCOPY:把源位圖反轉然后拷貝到目的地
NOTSRCERASE:用或操作融合源和目的位圖,然后再反轉
PATCOPY:把圖案拷貝到目的位圖中
PATINVERT:用異或操作把圖案與目的位圖相融合
PATPAINT:用或操作融合圖案和反轉的源位圖,然后用或操作把結果與目的位圖融合
SRCERASE:先反轉目的位圖,再用與操作將其與源位圖融合
SRCINVERT:用異或操作融合源位圖和目的位圖
SRCPAINT:用或操作融合源位圖和目的位圖
WHITENESS:輸出區(qū)域為白色
合理利用這些取值將幫助我們制作出特定要求的圖像處理軟件。
從上述實例我們可以看出,在VC中使用CBitmap類,必須將位圖放入工程的資源中,并使用類 CBitmap的成員函數LoadBitmap加載之,再通過CDC類的成員函數BitBlt進行DC拷貝等操作達到顯示的目的。CBitmap有顯示的不足:
(1) 位圖需要放入工程資源中,這將導致工程的可執(zhí)行文件變大;
(2) 因為位圖需放入工程資源中,而資源中不能無窮無盡地包含位圖,應用程序無法自適應地選取其它位圖,能使用的位圖十分有限的;
(3) 類CBitmap只是DDB位圖操作API的封裝,不能獨立于平臺。
DIB位圖則可以解決上述問題,其特點是以.BMP位圖文件格式存儲獨立于平臺的圖像數據,下面我們來詳細分析。
4. DIB位圖編程
4.1位圖文件格式
先來分析DIB位圖文件的格式。位圖文件分為四部分:
(1)位圖文件頭BITMAPFILEHEADER
位圖文件頭BITMAPFILEHEADER是一個結構體,長度為14字節(jié),定義為:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; //文件類型,必須是0x424D,即字符串"BM"
DWORD bfSize; //文件大小,包括BITMAPFILEHEADER的14個字節(jié)
WORD bfReserved1; //保留字
WORD bfReserved2; //保留字
DWORD bfOffBits; //從文件頭到實際的位圖數據的偏移字節(jié)數
} BITMAPFILEHEADER;
(2)位圖信息頭BITMAPINFOHEADER
位圖信息頭BITMAPINFOHEADER也是一個結構體,長度為40字節(jié),定義為:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; //本結構的長度,為40
LONG biWidth; //圖象的寬度,單位是象素
LONG biHeight; //圖象的高度,單位是象素
WORD biPlanes; //必須是1
WORD biBitCount;
//表示顏色時要用到的位數,1(單色), 4(16色), 8(256色), 24(真彩色)
DWORD biCompression;
//指定位圖是否壓縮,有效的值為BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS等,BI_RGB表示不壓縮
DWORD biSizeImage;
//實際的位圖數據占用的字節(jié)數,即 biSizeImage=biWidth’ × biHeight,biWidth’是biWidth 按照4的整倍數調整后的結果
LONG biXPelsPerMeter; //目標設備的水平分辨率,單位是每米的象素個數
LONG biYPelsPerMeter; //目標設備的垂直分辨率,單位是每米的象素個數
DWORD biClrUsed; //位圖實際用到的顏色數,0表示顏色數為2biBitCount
DWORD biClrImportant; //位圖中重要的顏色數,0表示所有顏色都重要
} BITMAPINFOHEADER;
(3)調色板Palette
調色板Palette針對的是需要調色板的位圖,即單色、16色和256色位圖。對于不以調色板方式存儲的位圖,則無此項信息。調色板是一個數組,共有biClrUsed個元素(如果該值為0,則有2biBitCount個元素)。數組中每個元素是一個RGBQUAD結構體,長度為4個字節(jié),定義為:
typedef struct tagRGBQUAD
{
BYTE rgbBlue; //藍色分量
BYTE rgbGreen; //綠色分量
BYTE rgbRed; //紅色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
(4)實際的位圖數據ImageDate
對于用到調色板的位圖,實際的圖象數據ImageDate為該象素的顏色在調色板中的索引值;對于真彩色圖,圖象數據則為實際的R、G、B值:
a.單色位圖:用1bit就可以表示象素的顏色索引值;
b.16色位圖:用4bit可以表示象素的顏色索引值;
c. 256色位圖:1個字節(jié)表示1個象素的顏色索引值;
d.真彩色:3個字節(jié)表示1個象素的顏色R,G,B值。
此外,位圖數據每一行的字節(jié)數必須為4的整倍數,如果不是,則需要補齊。奇怪的是,位圖文件中的數據是從下到上(而不是從上到下)、從左到右方式存儲的。
4.2位圖的顯示
Visual C++ MFC中沒有提供一個專門的類來處理DIB位圖,因此,為了方便地使用位圖文件,我們有必要派生一個CDib類。類的源代碼如下:
(1) CDib類的聲明
// DIB.h:類CDib聲明頭文件
#ifndef __DIB_H__
#define __DIB_H__
#include
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類的實現
// DIB.cpp:類CDib實現文件
#include "stdafx.h"
#include "DIB.h"
CDib::CDib()
{
m_pDib = NULL;
}
CDib::~CDib()
{
// 如果位圖已經被加載,釋放內存
if (m_pDib != NULL)
delete []m_pDib;
}
下面這個函數非常重要,其功能為加載位圖,類似于CBitmap類的LoadBitmap函數:
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位圖分配內存
unsigned char *pDib;
pDib = new unsigned char[dwDibSize];
if (pDib == NULL)
return (FALSE);
BITMAPFILEHEADER BFH;
// 讀取位圖文件數據
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;
// 將臨時Dib數據指針和Dib大小變量賦給類成員變量
m_pDib = pDib;
m_dwDibSize = dwDibSize;
// 為相應類成員變量賦BITMAPINFOHEADER和調色板指針
m_pBIH = (BITMAPINFOHEADER*)m_pDib;
m_pPalette = (RGBQUAD*) &m_pDib[sizeof(BITMAPINFOHEADER)];
// 計算調色板中實際顏色數量
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;
// 為相應類成員變量賦image data指針
m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)];
// delete先前的調色板
if (m_Palette.GetSafeHandle() != NULL)
m_Palette.DeleteObject();
// 如果位圖中存在調色板,創(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的內存
m_Palette.CreatePalette(pLogPal);
delete []pLogPal;
}
}
return (TRUE);
}
//函數功能:保存位圖入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);
}
下面這個函數也非常重要,其功能為在pDC指向的CDC中繪制位圖,起點坐標為(nX,nY),繪制寬度和高度為nWidth、nHeight,最后一個參數是光柵模式:
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);
}
//函數功能:設置調色板
BOOL CDib::SetPalette(CDC *pDC)
{
if (m_pDib == NULL)
return (FALSE);
// 檢查當前是否有一個調色板句柄,對于大于256色的位圖,為NULL
if (m_Palette.GetSafeHandle() == NULL)
return (TRUE);
// 選擇調色板,接著實施之,最后恢復老的調色板
CPalette *pOldPalette;
pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
pDC->RealizePalette();
pDC->SelectPalette(pOldPalette, FALSE);
return (TRUE);
}
從整個CDib類的代碼中我們可以看出,DIB位圖的顯示需遵循如下步驟:
(1)讀取位圖,本類中使用pDib = new unsigned char[dwDibSize]為位圖中的信息分配內存,另一種方法是調用API函數CreateDIBSection,譬如:
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);
m_hBitmap定義為:
HBITMAP m_hBitmap;
(2)根據讀取的位圖信息,計算出調色板大小,然后創(chuàng)建調色板;
(3)調用CDib::SetPalette( CDC *pDC )設置調色板,需要用到CDC::SelectPalette及CDC::RealizePalette兩個函數;
(4)調用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)函數繪制位圖。在此函數中,真正發(fā)揮顯示位圖作用的是對StretchDIBits API函數的調用。StretchDIBits函數具有縮放功能,其最后一個參數也是光柵操作的模式。
下面給出DIB位圖的打開及顯示并在其中加入天極網logo的函數源代碼。"DIB位圖"父菜單下"打開"子菜單的單擊事件消息處理函數為(其功能為打開位圖并顯示之):
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位圖"父菜單下"標記"子菜單的單擊事件消息處理函數為(其功能為給位圖加上天極網logo):
void CBitMapExampleDlg::OnMarkDibpic()
{
// 彈出文件對話框,讓用戶選擇標記logo
CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL, "標記位圖文件(*.BMP)|*.bmp;*.BMP|");
if (IDOK == fileDialog.DoModal())
{
// 加載標記logo位圖并與目標位圖相與
CDib dib;
if (dib.Load(fileDialog.GetPathName()))
{
CClientDC dc(this);
dib.SetPalette(&dc);
dib.Draw(&dc, 0, 0, - 1, - 1, SRCAND);
}
}
}
圖4顯示了DIB位圖加載天極網logo后的效果,要好于圖3中加天極網logo后的DDB位圖。圖4顯示的是真彩色位圖相互與的結果,而圖3中的圖像顏色被減少了。
圖4 在DIB位圖中加入天極網logo
5. 結束語
本文介紹了位圖及調色板的概念,并講解了DDB位圖與DIB位圖的區(qū)別。在此基礎上,本文以實例講解了DDB位圖和DIB位圖的操作方式。DDB位圖的處理相對比較簡單,對于DIB位圖,我們需要定義一個MFC所沒有的新類CDib,它屏蔽位圖信息的讀取及調色板創(chuàng)建的技術細節(jié),應用程序可以方便地使用之。
本文中的所有程序在Visual C++6.0及Windows XP平臺上調試通過。?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1518334