1.基本概念
GDI在Windows中定義為Graphics Device Interface,即圖形設(shè)備接口,是Windows API(Application Programming Interface)的一個重要組成部分。它是Windows圖形顯示程序與實(shí)際物理設(shè)備之間的橋梁,GDI使得用戶無需關(guān)心具體設(shè)備的細(xì)節(jié),而只需在一個虛擬的環(huán)境(即邏輯設(shè)備)中進(jìn)行操作。它的橋梁作用體現(xiàn)在:
(1)用戶通過調(diào)用GDI函數(shù)將邏輯空間的操作轉(zhuǎn)化為具體針對設(shè)備驅(qū)動程序的調(diào)用。
為實(shí)現(xiàn)圖形設(shè)備無關(guān)性,Windows 的繪圖操作在一個設(shè)備描述表上進(jìn)行。用戶擁有自己的"邏輯坐標(biāo)"系統(tǒng),它獨(dú)立于實(shí)際的物理設(shè)備,與"設(shè)備坐標(biāo)"相對應(yīng)。開發(fā)Windows應(yīng)用程序時,程序員關(guān)心的是邏輯坐標(biāo),我們在邏輯坐標(biāo)系上繪圖,利用GDI將邏輯窗口映射到物理設(shè)備上。
(2)GDI能檢測具體設(shè)備的能力,并依據(jù)具體的設(shè)備以最優(yōu)方式驅(qū)動這些設(shè)備,完成真實(shí)的顯示。
GDI函數(shù)大致可分類為:設(shè)備上下文函數(shù)(如GetDC、CreateDC、DeleteDC)、 畫線函數(shù)(如LineTo、Polyline、Arc)、填充畫圖函數(shù)(如Ellipse、FillRect、Pie)、畫圖屬性函數(shù)(如SetBkColor、SetBkMode、SetTextColor)、文本、字體函數(shù)(如TextOut、GetFontData)、位圖函數(shù)(如SetPixel、BitBlt、StretchBlt)、坐標(biāo)函數(shù)(如DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)、映射函數(shù)(如SetMapMode、SetWindowExtEx、SetViewportExtEx)、元文件函數(shù)(如PlayMetaFile、SetWinMetaFileBits)、區(qū)域函數(shù)(如FillRgn、FrameRgn、InvertRgn)、路徑函數(shù)(如BeginPath、EndPath、StrokeAndFillPath)、裁剪函數(shù)(如SelectClipRgn、SelectClipPath)等。
GDI雖然使程序員得到了一定程度的解脫,但是其編程方式仍很麻煩。譬如,顯示一張位圖,程序員需要進(jìn)行"裝入位圖―讀取位圖文件頭信息―啟用設(shè)備場景―調(diào)色板變換"等一連串操作。而有了GDI+,這些問題便迎刃而解了。
顧名思義,GDI+是GDI的增強(qiáng)版。它是微軟在Windows 2000以后操作系統(tǒng)中提供的新接口,其通過一套部署為托管代碼的類來展現(xiàn),這套類被稱為GDI+的"托管類接口"。GDI+主要提供了以下三類服務(wù):
(1) 二維矢量圖形:GDI+提供了存儲圖形基元自身信息的類(或結(jié)構(gòu)體)、存儲圖形基元繪制方式信息的類以及實(shí)際進(jìn)行繪制的類;
(2) 圖像處理:大多數(shù)圖片都難以劃定為直線和曲線的集合,無法使用二維矢量圖形方式進(jìn)行處理。因此,GDI+為我們提供了Bitmap、Image等類,它們可用于顯示、操作和保存BMP、JPG、GIF等圖像格式。
(3) 文字顯示:GDI+支持使用各種字體、字號和樣式來顯示文本。
GDI接口是基于函數(shù)的,而GDI+是基于C++類的對象化的應(yīng)用程序編程接口,因此使用起來比GDI要方便。
2.例程簡述 單擊此處下載本文例程源代碼。
本文后續(xù)的講解都基于這樣的一個例子工程(例程的開發(fā)環(huán)境為Visual C++6.0,操作系統(tǒng)為Windows XP),它是一個基于對話框的MFC應(yīng)用程序,包括2個父菜單:
(1) GDI
GDI父菜單下包括一個子菜單:
ID:IDM_GDI_DRAW_LINE caption:畫線
單擊事件:在窗口繪制正旋曲線
(2) GDI+
DIB位圖父菜單下包括兩個子菜單:
a. ID:IDM_GDIP_DRAW_LINE caption:畫線
單擊事件:在窗口繪制正旋曲線
b. caption:新增功能,其下又包括下列子菜單:
(ⅰ)ID:IDM_Gradient_Brush caption:漸變畫刷
單擊事件:在窗口演示GDI+的漸變畫刷功能
(ⅱ)ID:IDM_Cardinal_Spline caption:基數(shù)樣條
單擊事件:在窗口演示GDI+的基數(shù)樣條函數(shù)功能
(ⅲ)ID:IDM_Transformation_Matrix caption:變形和矩陣對象
單擊事件:在窗口演示GDI+的變形和矩陣對象功能
(ⅳ)ID:IDM_Scalable_Region caption:可伸縮區(qū)域
單擊事件:在窗口演示GDI+的可伸縮區(qū)域功能
(ⅴ)ID:IDM_IMAGE caption:圖像
單擊事件:在窗口演示GDI+的多種圖像格式支持功能
(ⅵ)ID:IDM_Alpha_Blend caption:Alpha混合
單擊事件:在窗口演示GDI+的Alpha混合功能
(ⅶ)ID:IDM_TEXT caption:文本
單擊事件:在窗口演示GDI+的強(qiáng)大文本輸出能力
后續(xù)篇章將集中在對上述菜單單擊事件消息處理函數(shù)的講解,下面的代碼是整個對話框類CGdiexampleDlg的消息映射:
BEGIN_MESSAGE_MAP(CGdiexampleDlg, CDialog) //{{AFX_MSG_MAP(CGdiexampleDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_COMMAND(IDM_GDI_DRAW_LINE, OnGdiDrawLine) ON_COMMAND(IDM_GDIP_DRAW_LINE, OnGdipDrawLine) ON_COMMAND(IDM_Gradient_Brush, OnGradientBrush) ON_COMMAND(IDM_Cardinal_Spline, OnCardinalSpline) ON_COMMAND(IDM_Transformation_Matrix, OnTransformationMatrix) ON_COMMAND(IDM_Scalable_Region, OnScalableRegion) ON_COMMAND(IDM_IMAGE, OnImage) ON_COMMAND(IDM_Alpha_Blend, OnAlphaBlend) ON_COMMAND(IDM_TEXT, OnText) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
3.GDI編程
"GDI"菜單下的"畫線"子菜單單擊事件消息處理函數(shù)的代碼如下:
void CGdiexampleDlg::OnGdiDrawLine() { // TODO: Add your command handler code here CClientDC dc(this); //邏輯坐標(biāo)與設(shè)備坐標(biāo)變換 CRect rect; GetClientRect(&rect); dc.SetMapMode(MM_ANISOTROPIC); dc.SetWindowOrg(0, 0); dc.SetWindowExt(rect.right, rect.bottom); dc.SetViewportOrg(0, rect.bottom / 2); dc.SetViewportExt(rect.right, - rect.bottom); //創(chuàng)建繪制正旋曲線的pen并將其選入設(shè)備上下文 CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); HGDIOBJ oldObject = dc.SelectObject(pen.GetSafeHandle()); //繪制正旋曲線 dc.MoveTo(0, 0); for (int i = 0; i < rect.right; i++) { dc.LineTo(i, 100 *sin(2 *(i / (rect.right / 5.0)) *PI)); } //創(chuàng)建繪制x軸的pen并將其選入設(shè)備上下文 CPen penx(PS_SOLID, 1, RGB(0, 0, 255)); dc.SelectObject(penx.GetSafeHandle()); //繪制X軸 dc.MoveTo(0, 0); dc.LineTo(rect.right, 0); //恢復(fù)原先的pen dc.SelectObject(oldObject); } |
單擊這個按鈕,會出現(xiàn)如圖1所示的效果,我們來對此進(jìn)行解讀。
 圖1 繪制正旋曲線 |
前文提到,GDI編程需進(jìn)行設(shè)備坐標(biāo)和邏輯坐標(biāo)的轉(zhuǎn)化。而屏幕上的設(shè)備坐標(biāo)通常會按客戶坐標(biāo)給出,客戶坐標(biāo)依賴于窗口的客戶區(qū)域,其起始位置位于客戶區(qū)域的左上角。為示區(qū)別,圖2給出了設(shè)備坐標(biāo)和用戶邏輯坐標(biāo)的示例。
 圖2 設(shè)備坐標(biāo)與邏輯坐標(biāo) |
設(shè)備坐標(biāo)與邏輯坐標(biāo)的轉(zhuǎn)換關(guān)系如下:


公式中的<Xvorg, Yvorg>是設(shè)備空間中視口的原點(diǎn),而< Xworg, Yworg >是邏輯空間中窗口的原點(diǎn)。 Xwext/Xvext和Ywext/Yvext分別是窗口與視口水平和垂直范圍的比例。
因此,經(jīng)過程序中的dc.SetWindowOrg (0,0) 和dc.SetViewportOrg (0,rect.bottom/2)語句我們設(shè)置了視口和窗口的原點(diǎn);而經(jīng)過程序中的dc.SetWindowExt (rect.right,rect.bottom) 和dc.SetViewportExt (rect.right,-rect.bottom) 語句我們設(shè)置了視口和窗口的范圍。由于視口和窗口的縱坐標(biāo)方向相反,設(shè)置視口的垂直范圍為負(fù)值。這樣我們得到了一個邏輯坐標(biāo)原點(diǎn)為客戶區(qū)水平方向最左邊和垂直方向居中的坐標(biāo)系,我們在這個坐標(biāo)系上直接繪制正旋曲線,不需要再理睬Windows對話框客戶區(qū)坐標(biāo)了。
void CGdiexampleDlg::OnGdiDrawLine()函數(shù)中未指定邏輯設(shè)備和物理設(shè)備的映射模式,則為缺省的MM_TEXT。在這種模式下,一個邏輯單位對應(yīng)于一個像素點(diǎn)。映射模式是GDI中的一個重要概念,其它的映射模式還有MM_LOENGLlSH、MM_HIENGLISH、MM_LOMETRIC和MM_HIMETRIC等。我們可以通過如下語句指定映射模式為MM_TEXT:
值得一提的是,從上述代碼可以看出:在GDI編程中,幾乎所有的操作都圍繞設(shè)備上下文dc展開。的確,這正是GDI編程的特點(diǎn)!設(shè)備上下文是Windows 使用的一種結(jié)構(gòu),所有GDI操作前都需取得特定設(shè)備的上下文,函數(shù)中的CClientDC dc (this) 語句完成這一功能。
歸納可得,利用GDI進(jìn)行圖形、圖像處理的一般操作步驟為:
1. 取得指定窗口的DC;
2. 確定使用的坐標(biāo)系及映射方式;
3. 進(jìn)行圖形、圖像或文字處理;
4. 釋放所使用的DC。
4.GDI+編程
"GDI+"菜單下的"畫線"子菜單單擊事件消息處理函數(shù)的代碼如下:
void CGdiexampleDlg::OnGdipDrawLine() { // TODO: Add your command handler code here CClientDC dc(this); //邏輯坐標(biāo)與設(shè)備坐標(biāo)變換 CRect rect; GetClientRect(&rect); dc.SetMapMode(MM_ANISOTROPIC); dc.SetWindowOrg(0, 0); dc.SetWindowExt(rect.right, rect.bottom); dc.SetViewportOrg(0, rect.bottom / 2); dc.SetViewportExt(rect.right, - rect.bottom);
//創(chuàng)建Graphics對象 Graphics graphics(dc); //創(chuàng)建pen Pen myPen(Color::Red); myPen.SetWidth(1); //畫正旋曲線 for (int i = 0; i < rect.right; i++) { graphics.DrawLine(&myPen, i, 100 *sin(2 *(i / (rect.right / 5.0)) *PI), i + 1, 100 *sin(2 *((i + 1) / (rect.right / 5.0)) *PI)); } //畫X軸 myPen.SetColor(Color::Blue); graphics.DrawLine(&myPen, 0, 0, rect.right, 0); } |
由于我們使用的是Visual C++6.0而非VS.Net,我們需要下載微軟的GDIPLUS支持包。在微軟官方網(wǎng)站下載時需認(rèn)證Windows為正版,我們可從這個地址下載:http://www.codeguru.com/code/legacy/gdi/GDIPlus.zip。一個完整的GDI+支持包至少包括如下文件:
(1)頭文件:gdiplus.h
(2)動態(tài)鏈接庫的.lib文件:gdiplus.lib
(3)動態(tài)鏈接庫的.dll文件:gdiplus.dll
少了(1)、(2)程序不能編譯,少了(3)程序能以共享DLL的方式編譯但是不能運(yùn)行,運(yùn)行時找不到.dll文件。
為使得Visual C++6.0支持GDI+,我們需要在使用GDI+對象的文件的開頭添加如下代碼:
#define UNICODE #ifndef ULONG_PTR #define ULONG_PTR unsigned long* #endif #include "c:\gdiplus\includes\gdiplus.h" using namespace Gdiplus; #pragma comment(lib, "c:\gdiplus\lib\gdiplus.lib") |
在Visual C++中使用GDI+必須先進(jìn)行GDI+的初始化,我們在CWinApp派生類的InitInstance函數(shù)中進(jìn)行此項(xiàng)工作是最好的:
/////////////////////////////////////// CGdiexampleApp initialization
BOOL CGdiexampleApp::InitInstance() { AfxEnableControlContainer();
// Standard initialization
#ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif
//初始化gdiplus的環(huán)境 GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; // 初始化GDI+. GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
CGdiexampleDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK){} else if (nResponse == IDCANCEL){}
//關(guān)閉gdiplus的環(huán)境 GdiplusShutdown(gdiplusToken);
return FALSE; } |
單擊"GDI+"菜單下的"畫線"子菜單,也會出現(xiàn)如圖1所示的效果。觀察void CGdiexampleDlg::OnGdipDrawLine() 函數(shù),我們發(fā)現(xiàn)用GDI+進(jìn)行圖形、圖像操作的步驟為:
(1)創(chuàng)建 Graphics 對象:Graphics 對象表示GDI+繪圖表面,是用于創(chuàng)建圖形圖像的對象;
(2)使用 Graphics 對象繪制線條和形狀、呈現(xiàn)文本或顯示與操作圖像。
Graphics 對象是GDI+的核心,GDI中設(shè)備上下文dc和Graphics 對象的作用相似,但在GDI中使用的是基于句柄的編程模式,而GDI+中使用的則是基于對象的編程模式。Graphics封裝了GDI+ 繪圖面,而且此類無法被繼承,它的所有成員函數(shù)都不是虛函數(shù)。
下面,我們來逐個用實(shí)際代碼實(shí)現(xiàn)GDI+的新增功能,這些新增功能包括:漸變的畫刷(Gradient Brushes)、基數(shù)樣條函數(shù)(Cardinal Splines)、持久的路徑對象(Persistent Path Objects)、變形和矩陣對象(Transformations &Matrix Object)、可伸縮區(qū)域(Scalable Regions)、Alpha混合(Alpha Blending)和豐富的圖像格式支持等。
漸變的畫刷
GDI+提供了用于填充圖形、路徑和區(qū)域的線性漸變畫刷和路徑漸變畫刷。
線性漸變畫刷使用漸變顏色來填充圖形。
當(dāng)用路徑漸變畫刷填充圖形時,可指定從圖形的一部分移至另一部分時畫刷顏色的變化方式。例如,我們可以只指定圖形的中心顏色和邊緣顏色,當(dāng)畫刷從圖形中間向外邊緣移動時,畫刷會逐漸從中心顏色變化到邊緣顏色。
void CGdiexampleDlg::OnGradientBrush() { // TODO: Add your command handler code here CClientDC dc(this); CRect rect; GetClientRect(&rect); //創(chuàng)建Graphics對象 Graphics graphics(dc); //創(chuàng)建漸變畫刷 LinearGradientBrush lgb(Point(0, 0), Point(rect.right, rect.bottom), Color::Blue, Color::Green); //填充 graphics.FillRectangle(&lgb, 0, 0, rect.right, rect.bottom); } |
本程序使用線性漸變畫刷,當(dāng)畫刷從客戶區(qū)左上角移向客戶區(qū)右下角的過程中,顏色逐漸由藍(lán)色轉(zhuǎn)變?yōu)榫G色。
 圖3 GDI+漸變畫刷 |
基數(shù)樣條函數(shù) GDI+支持基數(shù)樣條,基數(shù)樣條指的是一連串單獨(dú)的曲線,這些曲線連接起來形成一條較大的曲線。樣條由點(diǎn)(Point結(jié)構(gòu)體)的數(shù)組指定,并通過該數(shù)組中的每一個點(diǎn)?;鶖?shù)樣條平滑地穿過數(shù)組中的每一個點(diǎn)(不出現(xiàn)尖角),因此比用直線連接創(chuàng)建的路徑精確。
void CGdiexampleDlg::OnCardinalSpline() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); Point points[] = { Point(0, 0), Point(100, 200), Point(200, 0), Point(300, 200), Point(400, 00) }; //直接畫線 for (int i = 0; i < 4; i++) { graphics.DrawLine(&Pen(Color::Blue, 3), points[i], points[i + 1]); } //利用基數(shù)樣條畫線 graphics.DrawCurve(&Pen(Color::Red, 3), points, 5); } |
圖4演示了直接連線和經(jīng)過基數(shù)樣條平滑擬合后的線條的對比,后者的曲線(Curve)沒有尖角。這個工作我們在中學(xué)的數(shù)學(xué)課上把離散的點(diǎn)連接成曲線時做過。
 圖4 GDI+基數(shù)樣條 |
?
持久的路徑對象
在GDI中,路徑隸屬于一個設(shè)備上下文,一旦設(shè)備環(huán)境指針超過它的生存期,路徑也會被刪除。利用GDI+,可以創(chuàng)建并維護(hù)與Graphics對象分開的GraphicsPath 對象,它不依賴于Graphics對象的生存期。
變形和矩陣對象
GDI+提供了Matrix對象,它是一種可以使變形(旋轉(zhuǎn)、平移、縮放等) 簡易靈活的強(qiáng)大工具,Matrix對象需與要被變形的對象聯(lián)合使用。對于GraphicsPath類,我們可以使用其成員函數(shù)Transform接收Matrix參數(shù)用于變形。
void CGdiexampleDlg::OnTransformationMatrix() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); GraphicsPath path; path.AddRectangle(Rect(250, 20, 70, 70)); graphics.DrawPath(&Pen(Color::Black, 1), &path); // 在應(yīng)用變形矩陣之前繪制矩形 // 路徑變形 Matrix matrix1, matrix2;
matrix1.Rotate(45.0f); //旋轉(zhuǎn)順時針45度 path.Transform(&matrix1); //應(yīng)用變形 graphics.DrawPath(&Pen(Color::Red, 3), &path);
matrix2.Scale(1.0f, 0.5f); //轉(zhuǎn)化成為平行四邊形法則 path.Transform(&matrix2); //應(yīng)用變形 graphics.DrawPath(&Pen(Color::Blue, 3), &path); } |
圖5演示了正方形經(jīng)過旋轉(zhuǎn)和拉伸之后的效果:黑色的為原始圖形,紅色的為旋轉(zhuǎn)45度之后的圖形,藍(lán)色的為經(jīng)過拉伸為平行四邊形后的圖形。
 圖5 GDI+變形和矩陣對象 |
可伸縮區(qū)域
GDI+通過對區(qū)域(Region)的支持極大地擴(kuò)展了GDI。在GDI 中,區(qū)域存儲在設(shè)備坐標(biāo)中,可應(yīng)用于區(qū)域的唯一變形是平移。但是在GDI +中,區(qū)域存儲在全局坐標(biāo)(世界坐標(biāo))中,可對區(qū)域利用變形矩陣進(jìn)行變形(旋轉(zhuǎn)、平移、縮放等)。
void CGdiexampleDlg::OnScalableRegion() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); //創(chuàng)建GraphicsPath GraphicsPath path; path.AddLine(100, 100, 150, 150); path.AddLine(50, 150, 150, 150); path.AddLine(50, 150, 100, 100); //創(chuàng)建Region Region region(&path); //填充區(qū)域 graphics.FillRegion(&SolidBrush(Color::Blue), ®ion); //區(qū)域變形 Matrix matrix; matrix.Rotate(10.0f); //旋轉(zhuǎn)順時針20度 matrix.Scale(1.0f, 0.3f); //拉伸 region.Transform(&matrix); //應(yīng)用變形 //填充變形后的區(qū)域 graphics.FillRegion(&SolidBrush(Color::Green), ®ion); } |
上述程序中以藍(lán)色填充一個三角形區(qū)域,接著將此區(qū)域旋轉(zhuǎn)和拉伸,再次顯示,其效果如圖6。
 圖6 GDI+區(qū)域變形 |
豐富的圖像格式支持
GDI +提供了Image、Bitmap 和Metafile 類,方便用戶進(jìn)行圖像格式的加載、操作和保存。GDI+支持的圖像格式有BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、EMF等,幾乎涵蓋了所有的常用圖像格式。
void CGdiexampleDlg::OnImage() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); Image image(L "d:\1.jpg"); //在矩形區(qū)域內(nèi)顯示jpg圖像 Point destPoints1[3] = { Point(10, 10), Point(220, 10), Point(10, 290) }; graphics.DrawImage(&image, destPoints1, 3); //在平行四邊形區(qū)域內(nèi)顯示jpg圖像 Point destPoints2[3] = { Point(230, 10), Point(440, 10), Point(270, 290) }; graphics.DrawImage(&image, destPoints2, 3); } |
上述程序?qū)盤根目錄下文件名為"1.jpg"的jpg圖像以矩陣和平行四邊形兩種方式顯示,效果如圖7。
 圖7 GDI+多種圖像格式支持 |
由此我們可以看出,GDI+在圖像顯示和操作方面的確比GDI簡單許多?;貞浳覀冊凇禫isual C++中DDB與DIB位圖編程全攻略》一文中所介紹的用GDI顯示位圖的方式,其與GDI+圖像處理的難易程度真是有天壤之別。
Alpha混合
Alpha允許將兩個物體混合起來顯示,在3D氣氛和場景渲染等方面有廣泛應(yīng)用。它能"霧化"圖像,使得一個圖像著色在另一個半透明的圖像上,呈現(xiàn)一種朦朧美。我們知道,一個像素可用R,G,B三個維度來表示,我們可以再加上第4個即:Alpha維度(channel),表征透明程度。
void CGdiexampleDlg::OnAlphaBlend() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); //創(chuàng)建ColorMatrix ColorMatrix ClrMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; //將ColorMatrix賦給ImageAttributes ImageAttributes ImgAttr; ImgAttr.SetColorMatrix(&ClrMatrix, ColorMatrixFlagsDefault,ColorAdjustTypeBitmap); //在矩形區(qū)域內(nèi)顯示jpg圖像 Image img1(L "d:\1.jpg"); Point destPoints1[3] = { Point(10, 10), Point(220, 10), Point(10, 290) }; graphics.DrawImage(&img1, destPoints1, 3); //Alpha混合 Image img2(L "d:\2.jpg"); int width, height; width = img2.GetWidth(); height = img2.GetHeight(); graphics.DrawImage(&img2, RectF(10, 10, 210, 280), 0, 0, width, height,UnitPixel, &ImgAttr); //在平行四邊形區(qū)域內(nèi)顯示jpg圖像 Point destPoints2[3] = { Point(230, 10), Point(440, 10), Point(270, 290) }; graphics.DrawImage(&img1, destPoints2, 3); //Alpha混合 graphics.DrawImage(&img2, destPoints2, 3, 0, 0, width, height, UnitPixel,&ImgAttr); } |
上述程序中將D盤根目錄下文件名為"1.jpg"的圖像以矩陣和平行四邊形兩種方式顯示,然后將文件名為為"2.jpg"的圖像與之進(jìn)行混合,其效果如圖8。
 圖8 GDI+ Alpha混合 |
為了能進(jìn)行Alpha混合,我們需要使用ImageAttributes類和ColorMatrix矩陣,ImageAttributes可以進(jìn)行顏色、灰度等調(diào)整從而達(dá)到控制圖像著色方式的目的。ColorMatrix是ImageAttributes類大多數(shù)函數(shù)的參數(shù),它包含了Alpha、Red、Green、Blue維度的值,以及另一維w,順序?yàn)镽GBaw。
CGdiexampleDlg::OnAlphaBlend()函數(shù)中ColorMatrix的實(shí)例ClrMatrix中元素(4,4)的值為0.5,表示Alpha度的值為0.5(即半透明)。在ColorMatrix中,元素(5,5)的值恒定為1.0。我們把ClrMatrix的元素(0,0)修改為0.0,即使得圖像2.jpg的紅色維度全不顯示,再看效果,為圖9。列位讀者,我們以前在豪杰超級解霸中調(diào)整R,G,B值從而控制圖像輸出顏色的時候,調(diào)的就是這個東東!圖9的效果很像破舊彩色電視機(jī),紅色電子槍"嗝"了。剛大學(xué)畢業(yè)時,俺那個叫窮啊,就買了這么個電視機(jī),還看得很爽,真是往事不堪回首!
 圖9 GDI+中的ColorMatrix |
強(qiáng)大的文字輸出
GDI+擁有極其強(qiáng)大的文字輸出處理能力,輸出文字的顏色、字體、填充方式都可以直接作為Graphics類DrawString成員函數(shù)的參數(shù)進(jìn)行設(shè)置,其功能遠(yuǎn)勝過GDI設(shè)備上下文的TextOut函數(shù)。
void CGdiexampleDlg::OnText() { // TODO: Add your command handler code here CClientDC dc(this); //創(chuàng)建Graphics對象 Graphics graphics(dc); //創(chuàng)建20號"楷體"字體 FontFamily fontFamily1(L "楷體_GB2312"); // 定義"楷體"字樣 Font font1(&fontFamily1, 20, FontStyleRegular, UnitPoint); //定義輸出UNICODE字符串 WCHAR string[256]; wcscpy(string, L "天極網(wǎng)的讀者朋友,您好!"); //以藍(lán)色畫刷和20號"楷體"顯示字符串 graphics.DrawString(string, (INT)wcslen(string), &font1, PointF(30, 10),&SolidBrush(Color::Blue)); //定義字符串顯示畫刷 LinearGradientBrush linGrBrush(Point(30, 50), Point(100, 50), Color(255, 255,0, 0), Color(255, 0, 0, 255)); //以線性漸變畫刷和創(chuàng)建的20號"楷體"顯示字符串 graphics.DrawString(string, (INT)wcslen(string), &font1, PointF(30, 50),&linGrBrush); //創(chuàng)建20號"華文行楷"字體 FontFamily fontFamily2(L "華文行楷"); // 定義"楷體"字樣 Font font2(&fontFamily2, 20, FontStyleRegular, UnitPoint); //以線性漸變畫刷和20號"華文行楷"顯示字符串 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 90),&linGrBrush); //以圖像創(chuàng)建畫刷 Image image(L "d:\3.jpg"); TextureBrush tBrush(&image); //以圖像畫刷和20號"華文行楷"顯示字符串 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 130),&tBrush); //創(chuàng)建25號"華文中宋"字體 FontFamily fontFamily3(L "華文中宋"); // 定義"楷體"字樣 Font font3(&fontFamily2, 25, FontStyleRegular, UnitPoint); //以圖像畫刷和20號"華文行楷"顯示字符串 graphics.DrawString(string, (INT)wcslen(string), &font3, PointF(30, 170),&tBrush); } |
上述代碼的執(zhí)行效果如圖10所示,字體、顏色和填充都很豐富!