VS2010下用GDIplus(GDI+)在控制檯視窗顯示多種格式的圖片(一)
文章目錄
GDI和GDI+
GDI是Graphics Device Interface的縮寫,含義是圖形裝置介面,它的主要任務是負責系統與繪圖程式之間的資訊交換,處理所有Windows程式的圖形輸出。利用GDI所提供的眾多函式就可以方便的在螢幕、印表機及其它輸出裝置上輸出圖形,文字等操作。GDI的使程式設計師無需要關心硬體裝置及裝置驅動,就可以將應用程式的輸出轉化為硬體裝置上的輸出,實現了程式開發者與硬體裝置的隔離,大大方便了開發工作。
GDI+ (Graphics Device Interface plus)是2000年後windows發展出來的新技術。GDI+ 是一組通過C++類實現的應用程式程式設計介面。GDI+是以前版本GDI的繼承者,出於相容性考慮,Windows XP仍然支援以前版本的GDI,但是在開發新應用程式的時候,開發人員為了滿足圖形輸出需要應該使用GDI+,因為GDI+對以前的Windows版本中GDI進行了優化,並添加了許多新的功能。
作為圖形裝置介面的GDI+使得應用程式開發人員在輸出螢幕和印表機資訊的時候無需考慮具體顯示裝置的細節,他們只需呼叫GDI+庫輸出的類的一些方法即可完成圖形操作,真正的繪圖工作由這些方法交給特定的裝置驅動程式來完成,GDI+使得圖形硬體和應用程式相互隔離.從而使開發人員編寫裝置無關的應用程式變得非常容易。
1998年誕生的 VC++6.0 支援GDI程式設計。但預設不支援GDI+。需要使用者安裝新的windows SDK才行。但VC 2010 版直接支援GDI+ 程式設計。
GDI只支援bmp等少數影象格式讀取,GID+ 支援大多數常見影象格式(如jpg,png, tif,gif等等)。為了方便讀取多種格式的影象檔案並顯示,下面的實驗以VS2010為開發平臺,講解如何利用GDI+ 來讀取影象檔案,並顯示在控制檯視窗中。(關於如何利用MFC在新建視窗或對話方塊視窗中應用GDI+的文章很多了,本文就不涉及)。
【注】VS2010 綠色版參見:
VS2010 綠色版下載
GDIplus 的引入和使用方法
引入GDI+庫
使用GDI+,需引入gdiplus.h
並連結gdiplus.lib
庫。GDI+的函式在名字空間Gdiplus
中,也要以using namespace Gdiplus;
引入。否則需在GDI+函式前加上Gdiplus::
字首。
#include<gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
//#define ULONG_PTR ULONG
using namespace Gdiplus;
【注】:在VC6中編譯,如出現ULONG_PTR ULONG
未定義,可加上
#define ULONG_PTR ULONG
因為GDI+是WIndows Platform SDK不是MFC的一部分,而ULONG_PTR在SDK中的定義與MFC中的定義相沖突,所以,會出現此問題。
使用GDI+ 讀取影象檔案
然後,在主程式中用GdiplusStartup
函式啟動GDI+ :
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
通過FromFile
開啟影象檔案。
Image* pImage = Image::FromFile(L"wtclablogo.png");
也可這樣:
Image* pImage = new Image(L"testfile.jpg");
其中,L"testfile.jpg"
是將字串轉為寬字元的。因為Image類只接受寬字串WCHAR
。
【注】從字串char *
到寬字串型別WCHAR
還可用如下函式來轉換。
WCHAR * charToWCHAR(char *s) {
int w_nlen = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
WCHAR *ret;
ret = (WCHAR*)malloc(sizeof(WCHAR)*w_nlen);
memset(ret, 0, sizeof(ret));
MultiByteToWideChar(CP_ACP, 0, s, -1, ret, w_nlen);
return ret;
}
例如,要從main函式的命令列引數中讀取檔名(設在argv[1]
中),需做如下轉換:
WCHAR * filename;
filename =charToWCHAR(argv[1]);
Image* pImage = new Image(filename);
獲取顯示區繪圖控制代碼hdc
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
main(){
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
}
建立GDI+ 繪圖對像
構建Graphics
物件,並繫結在顯示區hdc
上。(這裡沒有用雙緩衝)
Graphics graphics(hdc);
通過GDI+ 繪圖對像的DrawImag
方法將影象顯示出來
最後,通過Graphics
物件的DrawImage
方法在螢幕上作圖。其中,用pImage->GetWidth()和pImage->GetHeight()
可取出影象的寬和高(畫素數)。
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth(), pImage->GetHeight());
關閉GDI+
程式執行的最後可關閉GDI+ (在控制檯視窗程式中,不關閉就退出也可)
GdiplusShutdown( m_gdiplusToken );
最簡例項程式碼(25行)
本例讀取了png圖片,並以2倍放大後顯示。
#include<Windows.h>
#include<stdio.h>
#include<gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
using namespace Gdiplus;
int main() {
Gdiplus::GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
Image* pImage = Image::FromFile(L"wtclablogo.png");
if ((pImage==NULL)||(pImage->GetLastStatus()!=Ok))
{
if (pImage)
{
printf("無法開啟圖片");
delete pImage;
pImage = NULL;
}
return FALSE;
}
Graphics graphics(hdc);
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
return 0;
}
以上程式碼在VS2010和VC++6(補充了GDI+)的整合環境中下都可編譯。執行結果如下:
從執行結果看,wtclablogo.png
圖片中透明部分也正確顯示了。
【注】對於gif格式這種以多幀構成的影象,要在VS2010版中自帶的GDI+才支援分幀解析。所以以下讀取gif影象的實驗都要在VS2010中編譯完成。
為了使影象顯示後能重繪重新整理,可用while迴圈(Ctrl+C退出)結合Sleep函式來實現,如前一篇檔案所述。
while(TRUE){
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
Sleep(100);
}
完整程式碼:
#include<Windows.h>
#include<stdio.h>
#include<gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
using namespace Gdiplus;
int main() {
Gdiplus::GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
Image* pImage = Image::FromFile(L"wtclablogo.png");
if (!pImage) {
printf("無法開啟圖片");
return -1;
}
Graphics graphics(hdc);
while(TRUE){
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
Sleep(100);
}
GdiplusShutdown( m_gdiplusToken );//關閉GDI+,可略此句
return 0;
}