1. 程式人生 > >基於VC6.0的控制檯作圖--顯示點陣圖(bmp)

基於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位點陣圖。例項中演示了BitBltStretchBlt的用法。

#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鍵跳出迴圈
		}
	}
}

效果如下:

在這裡插入圖片描述