位圖是描述圖像的最簡單直觀的一種方式,把圖像橫向分爲等間距的W列,縱向分爲等間距的H列,於是這個圖像大小被定義爲分辨率W*H。位圖分爲單色圖和彩色圖,區分方法是圖片的一個像素點可以用多少種顏色表示。現在這裏介紹的位圖是作爲GDI對象來介紹的,後面會在位圖專題中介紹位圖。
在MFC中CBitmap類封裝了位圖對象及其基本操作,可以使用多種方式來創建位圖對象。
1) 在內存中創建位圖對象
BOOL CreateBitmap(
int nWidth, //位圖寬度
int nHeight, //位圖高度
UINT nPlanes, //指定目標設備的位面數
UINT nBitcount, //顏色位圖
const void* lpBits //位圖數據
);
當前內存中已存在位圖數據,需要構造CBitmap對象便於管理位圖,此時就可以簡單地調用CreateBitmap即可。
2) 根據BITMAP結構在內存中創建位圖對象
BOOL CreateBitmapIndirect(
LPBITMAP lpBitmap //指向BITMAP結構
);
CreateBitmapIndirect與CreateBitmap類似,都是在內存中直接創建位圖對象。而CreateBitmapIndirect通過BITMAP結構指定待創建位圖對象的參數信息。BITMAP結構定義如下:
typedef struct tagBITMAP
{
LONG bmType; //位圖類型。對於邏輯位圖,必須爲0
LONG bmWidth; //位圖寬度,必須大於0
LONG bmHeight; //位圖高度,必須大於0
LONG bmWidthBytes; //位圖數據中一行有幾個字節
WORD bmPlanes; //指定目標設備的位面數
WORD bmBitsPixel; //指定每個像素的位數
LPVOID bmBits; //位圖數據
} BITMAP;
3) 創建與指定設備上下文兼容的位圖對象
BOOL CreateCompatibleBitmap(
CDC* pDC, //目標DC
int nWidth, //位圖寬度
int nHeight //位圖高度
);
4) 從應用程序資源中加載位圖對象,有兩種形式,可以根據資源名或資源ID加載。
BOOL LoadBitmap(
LPCTSTR lpszResourceName //位圖資源名,絕對路徑
);
BOOL LoadBitmap(
UINT nIDResource //位圖資源ID
);
示例:使用GDI對象CBitmap顯示位圖
1) 導入位圖資源。通過加載位圖資源的方式,加載8個位圖資源,資源ID爲默認ID。
2) 定義繪圖結構和變量
struct my_Bitmap{
CRect rect; //圖形顯示區域
CBitmap bmp; //位圖
};
成員變量:my_Bitmap m_my_Bitmap[8];
3) 初始化繪圖區域
void CSDITestView::InitRectBitmap()
{
//加載的圖片大小是128*128
CRect rect(0,0,128,128);
for (int i=0;i<8;i++)
{
if (i<4)
{
//第一行圖形
CRect rect;
rect.left=20+i*160;
rect.top=20;
rect.right=100+i*160;
rect.bottom=148;
m_my_Bitmap[i].rect.CopyRect(rect);
}
else
{
//第二行圖形
CRect rect;
rect.left=20+(i-4)*160;
rect.top=168;
rect.right=100+(i-4)*160;
rect.bottom=296;
m_my_Bitmap[i].rect.CopyRect(rect);
}
}
}
4) 初始化繪圖信息
void CSDITestView::InitBitmap()
{
m_my_Bitmap[0].bmp.LoadBitmapW(IDB_BITMAP1);
m_my_Bitmap[1].bmp.LoadBitmapW(IDB_BITMAP2);
m_my_Bitmap[2].bmp.LoadBitmapW(IDB_BITMAP3);
m_my_Bitmap[3].bmp.LoadBitmapW(IDB_BITMAP4);
m_my_Bitmap[4].bmp.LoadBitmapW(IDB_BITMAP5);
m_my_Bitmap[5].bmp.LoadBitmapW(IDB_BITMAP6);
m_my_Bitmap[6].bmp.LoadBitmapW(IDB_BITMAP7);
m_my_Bitmap[7].bmp.LoadBitmapW(IDB_BITMAP8);
}
5) 具體繪圖過程。在OnDraw函數中添加下面的代碼:
//採用GDI CBitmap繪圖 S
CRect WndRect;
GetWindowRect(&WndRect);
ScreenToClient(&WndRect);
CClientDC cdc(this);
CDC mdc,TempDc;
BITMAP BmpInfo;
CBitmap ClientBmp,*pOldBmp;
//創建與設備DC兼容的內存DC
mdc.CreateCompatibleDC(&cdc);
TempDc.CreateCompatibleDC(&cdc);
//創建與設備DC兼容的位圖對象
ClientBmp.CreateCompatibleBitmap(&cdc,WndRect.right,WndRect.bottom);
mdc.SelectObject(&ClientBmp);
//依次把位圖貼到內存DC
for (int i=0;i<8;i++)
{
TempDc.SelectObject(&m_my_Bitmap[i].bmp);
m_my_Bitmap[i].bmp.GetBitmap(&BmpInfo);
mdc.TransparentBlt(m_my_Bitmap[i].rect.left,m_my_Bitmap[i].rect.top,BmpInfo.bmWidth,BmpInfo.bmHeight,&TempDc,0,0,BmpInfo.bmWidth,BmpInfo.bmHeight,RGB(255,255,255));
}
//把內存DC貼到設備DC上
cdc.BitBlt(0,0,WndRect.right,WndRect.bottom,&mdc,0,0,SRCCOPY);
//環境清理
ClientBmp.DeleteObject();
mdc.DeleteDC();
//採用GDI CBitmap繪圖 E
6) 運行結果如圖4-4-1所示:
圖4-4-1 使用GDI對象CBitmap顯示圖片
其實,不僅僅對於位圖操作需要先寫到內存DC後寫到設備DC,幾乎所有繪圖過程都應該遵循這個原理。不止是爲了防止抖動,也爲了提升效率。當然,如果有特殊的需求的話,那就另當別論了。