基於VC6.0的控制檯作圖--顯示點陣圖(bmp)
文章目錄
GDI是什麼?
前面,我們利用windows的圖形裝置介面實現了在控制檯視窗中作圖和動畫。其中,連結了gdi32.lib
庫,也就是使用了GDI(圖形裝置介面)。
GDI在全稱是Graphics Device Interface,是圖形顯示與實際物理裝置之間的橋樑。GDI使得使用者無需關心具體裝置的細節,而只需在一個虛擬的環境(即邏輯裝置)中進行操作。
GDI函式大致可分類為:
- 裝置上下文函式(如GetDC、CreateDC、DeleteDC)
- 畫線函式(如LineTo、Polyline、Arc)
- 填充畫圖函式(如Ellipse、FillRect、Pie)
- 畫圖屬性函式(如SetBkColor、SetBkMode、SetTextColor)
- 文字、字型函式(如TextOut、GetFontData)
- 點陣圖函式(如SetPixel、BitBlt、StretchBlt)
- 座標函式(如DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)
- 對映函式(如SetMapMode、SetWindowExtEx、SetViewportExtEx)
- 元檔案函式(如PlayMetaFile、SetWinMetaFileBits)
- 區域函式(如FillRgn、FrameRgn、InvertRgn)
- 路徑函式(如BeginPath、EndPath、StrokeAndFillPath)
- 裁剪函式(如SelectClipRgn、SelectClipPath)
用LoadImage
讀取點陣圖bmp檔案
從點陣圖檔案路徑讀取bmp檔案函式LoadImage
:
LoadImage:可以載入點陣圖、圖示、游標多種影象資料,既可以從資源檢視中載入,也可以從磁碟中直接載入。函式
HANDLE LoadImage( HINSTANCE hinst, LPCTSTR lpszName, UINT uType, // 型別:點陣圖、圖示、游標 int cxDesired, //x座標位置 int cyDesired,//y座標位置 UINT fuLoad );
例如:
HBITMAP hbmpBack = (HBITMAP) ::LoadImage (
NULL,
".\\xxxx.bmp",
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
將點陣圖選入記憶體相容區
設當前控制檯視窗的控制代碼為hWnd
,則對應的HDC是裝置描述表控制代碼用:
HDC hdc = GetDC(hWnd);
來獲得。通過hdc
可建立對應的記憶體相容區hdcMem
:
//依據螢幕顯示DC建立記憶體DC裝置描述表控制代碼
HDC hdcMem = CreateCompatibleDC(hdc);
設hdcMem為記憶體DC裝置描述表控制代碼,用SelectObject函式可將點陣圖控制代碼hbmpBack
放到hdcMem中。
SelectObject(hdcMem,hbmpBack);
SelectObject函式選擇一物件到指定的裝置上下文環境中,該新物件替換先前的相同型別的物件。
為了儲存舊的點陣圖控制代碼(以備恢復現場),通常用:
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hdcMem,hbmpBack);
將記憶體相容區拷貝到螢幕區
Windows不允許直接將點陣圖繪製到需要顯示的視窗DC(裝置上下文)上,只能將點陣圖先放入相容的裝置上下文中(相容DC),然後將相容上下文的內容拷貝到裝置上下文中,才能實現點陣圖的繪製。
使用BitBlt或者StretchBlt兩個API,可實現將相容DC(源DC)中的內容拷貝目標DC(需要顯示的DC)中。他們的區別是,BitBlt不能進行點陣圖的縮放功能,而Stretch能實現縮放。
【BitBlt】函式
BOOL BitBlt(
HDC hdcDest, // 目標DC控制代碼
int nXDest, int nYDest, int nWidth, int nHeight, // 目標區域
HDC hdcSrc, // 源DC控制代碼
int nXSrc, int nYSrc, //源區域的左上角
DWORD dwRop // 操作的方式,一般為SRCCOPY(拷貝)
);
【StretchBlt】函式
BOOL StretchBlt(
HDC hdcDest, //目標DC的控制代碼
int xDest, int yDest, int wDest, int hDest, //目標DC的區域
HDC hdcSrc, //源DC的控制代碼
int xSrc, int ySrc, int wSrc, __in int hSrc, //源DC的區域
DWORD rop //操作標誌,一般為SRCCOPY,意思為拷貝
);
恢復現場
作圖完成後,應恢復現場。
將現在的點陣圖控制代碼選出臨時記憶體DC,也就是將我們原來的點陣圖控制代碼選入記憶體DC中。這裡為什麼需要選出來?如果不選出來,當前的點陣圖控制代碼還在記憶體DC中,使用DeleteDC後將會同時刪除現在使用的點陣圖控制代碼。
::SelectObject(hdcMem, hOldBmp);
銷燬臨時的記憶體DC
::DeleteDC(hdcMem);
例項 ( showbmp.cpp)
VC6.0 wtclablogo.bmp
為436*80 的24位點陣圖。例項中演示了BitBlt
和StretchBlt
的用法。
#include<windows.h>
#include<stdio.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
int main(int argc,char *argv[])
{
HDC hdc = GetDC(GetConsoleWindow ());//HDC是裝置描述表控制代碼(獲取螢幕顯示DC)
HBITMAP hbmpBack = (HBITMAP) LoadImage (NULL,
("wtclablogo.bmp"),
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem,hbmpBack);
system("cls");
BitBlt(hdc,200,300,800,600,hdcMem,0,0,SRCCOPY);
SetStretchBltMode(hdc,HALFTONE);
StretchBlt(hdc,20,50,180,40,hdcMem,0,0,436,80,SRCCOPY);
//恢復
SelectObject(hdcMem, hOldBmp);
DeleteDC(hdcMem);
return 0;
}
編譯:(或直接在VC6 整合環境中編譯。將圖片wtclablogo.bmp
放在exe檔案同一目錄下)
cl.exe showbmp.cpp
編譯和執行截圖:
最簡程式碼(15行):
#include<windows.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
void main(int argc,char *argv[])
{
HDC hdc = GetDC(GetConsoleWindow ());//HDC是裝置描述表控制代碼(獲取螢幕顯示DC)
HBITMAP hbmpBack = (HBITMAP) LoadImage (NULL,"wtclablogo.bmp",IMAGE_BITMAP,0, 0,
LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
HDC hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem,hbmpBack);
system("cls");
BitBlt(hdc,200,300,800,600,hdcMem,0,0,SRCCOPY);
StretchBlt(hdc,20,50,180,40,hdcMem,0,0,436,80,SRCCOPY);
}
進一步的改進方向
顯然,通過命令列傳參,就可實現在控制檯視窗顯示指定檔名的bmp圖片了。但GDI 只能顯示bmp, icon, cursor, animated cursor等圖形檔案,而我們常常要顯示jpg, png等更多格式的圖片,此時GDI就無能為力了。GDI是20年前的技術。
windows2000之後,GDI就升級為更強大的GDIplus(GDI+)了。通過GDI+ 技術可以顯示更多格式的圖片。
【注1】在使用StretchBlt拉伸影象時,可用SetStretchBltMode來提高顯示質量。
SetStretchBltMode(hdc,HALFTONE);
【注2】也可用TransparentBlt來實現伸縮。TransparentBlt可處理透明特性。TransparentBlt可以根據目標dc的矩形大小和原dc矩形大小比例對點陣圖進行伸縮處理,可設定掩碼色,也就是實現透明貼圖 ,該函式為系統API函式。如:
TransparentBlt(hdc,20,50,180,40,hdcMem,0,0,436,80,SRCCOPY);
注意,使用TransparentBlt需加入Msimg32.lib
庫。否則編譯會出錯。
#pragma comment(lib,"Msimg32.lib")
使用TransparentBlt的原始碼如下:
#include<windows.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"Msimg32.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
void main(int argc,char *argv[])
{
HDC hdc = GetDC(GetConsoleWindow ());//HDC是裝置描述表控制代碼(獲取螢幕顯示DC)
HBITMAP hbmpBack = (HBITMAP) LoadImage (NULL,"wtclablogo.bmp",IMAGE_BITMAP,0, 0,
LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
HDC hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem,hbmpBack);
system("cls");
BitBlt(hdc,200,300,800,600,hdcMem,0,0,SRCCOPY);
TransparentBlt(hdc,20,50,180,40,hdcMem,0,0,436,80,SRCCOPY);
}
此外,以上程式繪圖只繪一次,視窗變化後繪圖將被擦除,為了能不斷重繪重新整理,可採用while迴圈(for(;;)等價
)和sleep函式,以使每隔一定時間能自動重新整理。程式中,退出while迴圈的方法是:按ESC鍵(採用kbhit()
檢測)或Ctrl+C。程式碼如此下:
#include<windows.h>
#include<conio.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"Msimg32.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
void main(int argc,char *argv[])
{
for(;;){
HDC hdc = GetDC(GetConsoleWindow ());//HDC是裝置描述表控制代碼(獲取螢幕顯示DC)
HBITMAP hbmpBack = (HBITMAP) LoadImage (NULL,"wtclablogo.bmp",IMAGE_BITMAP,0, 0,
LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
HDC hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem,hbmpBack);
system("cls");
BitBlt(hdc,200,300,800,600,hdcMem,0,0,SRCCOPY);
TransparentBlt(hdc,20,50,180,40,hdcMem,0,0,436,80,SRCCOPY);
Sleep(100);
if (kbhit())//檢查是否有按鍵按下
{
if (_getch() == 0x1b)break;//若按下ESC鍵跳出迴圈
}
}
}
效果如下: