1.基本概念

  GDI在Windows中定義為Graphics Device Interface,即圖形設備接口,是Windows API(Application Programming Interface)的一個重要組成部分。它是Windows圖形顯示程序與實際物理設備之間的橋梁,GDI使得用戶無需關心具體設備的細節,而只需在一個虛擬的環境(即邏輯設備)中進行操作。它的橋梁作用體現在:

  (1)用戶通過調用GDI函數將邏輯空間的操作轉化為具體針對設備驅動程序的調用。

  為實現圖形設備無關性,Windows 的繪圖操作在一個設備描述表上進行。用戶擁有自己的"邏輯坐標"系統,它獨立于實際的物理設備,與"設備坐標"相對應。開發Windows應用程序時,程序員關心的是邏輯坐標,我們在邏輯坐標系上繪圖,利用GDI將邏輯窗口映射到物理設備上。

  (2)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)等。

  GDI雖然使程序員得到了一定程度的解脫,但是其編程方式仍很麻煩。譬如,顯示一張位圖,程序員需要進行"裝入位圖―讀取位圖文件頭信息―啟用設備場景―調色板變換"等一連串操作。而有了GDI+,這些問題便迎刃而解了。

  顧名思義,GDI+是GDI的增強版。它是微軟在Windows 2000以后操作系統中提供的新接口,其通過一套部署為托管代碼的類來展現,這套類被稱為GDI+的"托管類接口"。GDI+主要提供了以下三類服務:

  (1) 二維矢量圖形:GDI+提供了存儲圖形基元自身信息的類(或結構體)、存儲圖形基元繪制方式信息的類以及實際進行繪制的類;

  (2) 圖像處理:大多數圖片都難以劃定為直線和曲線的集合,無法使用二維矢量圖形方式進行處理。因此,GDI+為我們提供了Bitmap、Image等類,它們可用于顯示、操作和保存BMP、JPG、GIF等圖像格式。

  (3) 文字顯示:GDI+支持使用各種字體、字號和樣式來顯示文本。

  GDI接口是基于函數的,而GDI+是基于C++類的對象化的應用程序編程接口,因此使用起來比GDI要方便。

  2.例程簡述

  單擊此處下載本文例程源代碼。

  本文后續的講解都基于這樣的一個例子工程(例程的開發環境為Visual C++6.0,操作系統為Windows XP),它是一個基于對話框的MFC應用程序,包括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:基數樣條

  單擊事件:在窗口演示GDI+的基數樣條函數功能

  (ⅲ)ID:IDM_Transformation_Matrix caption:變形和矩陣對象

  單擊事件:在窗口演示GDI+的變形和矩陣對象功能

  (ⅳ)ID:IDM_Scalable_Region caption:可伸縮區域

  單擊事件:在窗口演示GDI+的可伸縮區域功能

  (ⅴ)ID:IDM_IMAGE caption:圖像

  單擊事件:在窗口演示GDI+的多種圖像格式支持功能

  (ⅵ)ID:IDM_Alpha_Blend caption:Alpha混合

  單擊事件:在窗口演示GDI+的Alpha混合功能

  (ⅶ)ID:IDM_TEXT caption:文本

  單擊事件:在窗口演示GDI+的強大文本輸出能力

  后續篇章將集中在對上述菜單單擊事件消息處理函數的講解,下面的代碼是整個對話框類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"菜單下的"畫線"子菜單單擊事件消息處理函數的代碼如下:

void CGdiexampleDlg::OnGdiDrawLine()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //邏輯坐標與設備坐標變換
 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);
 //創建繪制正旋曲線的pen并將其選入設備上下文
 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));
 }
 //創建繪制x軸的pen并將其選入設備上下文
 CPen penx(PS_SOLID, 1, RGB(0, 0, 255));
 dc.SelectObject(penx.GetSafeHandle());
 //繪制X軸
 dc.MoveTo(0, 0);
 dc.LineTo(rect.right, 0);
 //恢復原先的pen
 dc.SelectObject(oldObject);
}

  單擊這個按鈕,會出現如圖1所示的效果,我們來對此進行解讀。

WindowsGDI和GDI+編程實例全剖析(2)
圖1 繪制正旋曲線

  前文提到,GDI編程需進行設備坐標和邏輯坐標的轉化。而屏幕上的設備坐標通常會按客戶坐標給出,客戶坐標依賴于窗口的客戶區域,其起始位置位于客戶區域的左上角。為示區別,圖2給出了設備坐標和用戶邏輯坐標的示例。

WindowsGDI和GDI+編程實例全剖析(2)
圖2 設備坐標與邏輯坐標

  設備坐標與邏輯坐標的轉換關系如下:

WindowsGDI和GDI+編程實例全剖析(2)
WindowsGDI和GDI+編程實例全剖析(2)

  公式中的<Xvorg, Yvorg>是設備空間中視口的原點,而< Xworg, Yworg >是邏輯空間中窗口的原點。 Xwext/Xvext和Ywext/Yvext分別是窗口與視口水平和垂直范圍的比例。

  因此,經過程序中的dc.SetWindowOrg (0,0) 和dc.SetViewportOrg (0,rect.bottom/2)語句我們設置了視口和窗口的原點;而經過程序中的dc.SetWindowExt (rect.right,rect.bottom) 和dc.SetViewportExt (rect.right,-rect.bottom) 語句我們設置了視口和窗口的范圍。由于視口和窗口的縱坐標方向相反,設置視口的垂直范圍為負值。這樣我們得到了一個邏輯坐標原點為客戶區水平方向最左邊和垂直方向居中的坐標系,我們在這個坐標系上直接繪制正旋曲線,不需要再理睬Windows對話框客戶區坐標了。

  void CGdiexampleDlg::OnGdiDrawLine()函數中未指定邏輯設備和物理設備的映射模式,則為缺省的MM_TEXT。在這種模式下,一個邏輯單位對應于一個像素點。映射模式是GDI中的一個重要概念,其它的映射模式還有MM_LOENGLlSH、MM_HIENGLISH、MM_LOMETRIC和MM_HIMETRIC等。我們可以通過如下語句指定映射模式為MM_TEXT:

dc.SetMapMode(MM_TEXT);

  值得一提的是,從上述代碼可以看出:在GDI編程中,幾乎所有的操作都圍繞設備上下文dc展開。的確,這正是GDI編程的特點!設備上下文是Windows 使用的一種結構,所有GDI操作前都需取得特定設備的上下文,函數中的CClientDC dc (this) 語句完成這一功能。

  歸納可得,利用GDI進行圖形、圖像處理的一般操作步驟為:

  1. 取得指定窗口的DC;

  2. 確定使用的坐標系及映射方式;

  3. 進行圖形、圖像或文字處理;

  4. 釋放所使用的DC。

  4.GDI+編程

  "GDI+"菜單下的"畫線"子菜單單擊事件消息處理函數的代碼如下:

void CGdiexampleDlg::OnGdipDrawLine()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //邏輯坐標與設備坐標變換
 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);

 //創建Graphics對象
 Graphics graphics(dc);
 //創建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支持包。在微軟官方網站下載時需認證Windows為正版,我們可從這個地址下載:http://www.codeguru.com/code/legacy/gdi/GDIPlus.zip。一個完整的GDI+支持包至少包括如下文件:

  (1)頭文件:gdiplus.h

  (2)動態鏈接庫的.lib文件:gdiplus.lib

  (3)動態鏈接庫的.dll文件:gdiplus.dll

  少了(1)、(2)程序不能編譯,少了(3)程序能以共享DLL的方式編譯但是不能運行,運行時找不到.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+必須先進行GDI+的初始化,我們在CWinApp派生類的InitInstance函數中進行此項工作是最好的:

///////////////////////////////////////
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的環境
 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){}

 //關閉gdiplus的環境
 GdiplusShutdown(gdiplusToken);

 return FALSE;
}


  單擊"GDI+"菜單下的"畫線"子菜單,也會出現如圖1所示的效果。觀察void CGdiexampleDlg::OnGdipDrawLine() 函數,我們發現用GDI+進行圖形、圖像操作的步驟為:

  (1)創建 Graphics 對象:Graphics 對象表示GDI+繪圖表面,是用于創建圖形圖像的對象;

  (2)使用 Graphics 對象繪制線條和形狀、呈現文本或顯示與操作圖像。

  Graphics 對象是GDI+的核心,GDI中設備上下文dc和Graphics 對象的作用相似,但在GDI中使用的是基于句柄的編程模式,而GDI+中使用的則是基于對象的編程模式。Graphics封裝了GDI+ 繪圖面,而且此類無法被繼承,它的所有成員函數都不是虛函數。

  下面,我們來逐個用實際代碼實現GDI+的新增功能,這些新增功能包括:漸變的畫刷(Gradient Brushes)、基數樣條函數(Cardinal Splines)、持久的路徑對象(Persistent Path Objects)、變形和矩陣對象(Transformations &Matrix Object)、可伸縮區域(Scalable Regions)、Alpha混合(Alpha Blending)和豐富的圖像格式支持等。

漸變的畫刷

  GDI+提供了用于填充圖形、路徑和區域的線性漸變畫刷和路徑漸變畫刷。

  線性漸變畫刷使用漸變顏色來填充圖形。

  當用路徑漸變畫刷填充圖形時,可指定從圖形的一部分移至另一部分時畫刷顏色的變化方式。例如,我們可以只指定圖形的中心顏色和邊緣顏色,當畫刷從圖形中間向外邊緣移動時,畫刷會逐漸從中心顏色變化到邊緣顏色。

void CGdiexampleDlg::OnGradientBrush()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 CRect rect;
 GetClientRect(&rect);
 //創建Graphics對象
 Graphics graphics(dc);
 //創建漸變畫刷
 LinearGradientBrush lgb(Point(0, 0), Point(rect.right, rect.bottom), Color::Blue, Color::Green);
 //填充
 graphics.FillRectangle(&lgb, 0, 0, rect.right, rect.bottom);
}

  本程序使用線性漸變畫刷,當畫刷從客戶區左上角移向客戶區右下角的過程中,顏色逐漸由藍色轉變為綠色。

WindowsGDI和GDI+編程實例全剖析(3)
圖3 GDI+漸變畫刷

  基數樣條函數

  GDI+支持基數樣條,基數樣條指的是一連串單獨的曲線,這些曲線連接起來形成一條較大的曲線。樣條由點(Point結構體)的數組指定,并通過該數組中的每一個點。基數樣條平滑地穿過數組中的每一個點(不出現尖角),因此比用直線連接創建的路徑精確。

void CGdiexampleDlg::OnCardinalSpline()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建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]);
 }
 //利用基數樣條畫線
 graphics.DrawCurve(&Pen(Color::Red, 3), points, 5);
}

  圖4演示了直接連線和經過基數樣條平滑擬合后的線條的對比,后者的曲線(Curve)沒有尖角。這個工作我們在中學的數學課上把離散的點連接成曲線時做過。

WindowsGDI和GDI+編程實例全剖析(3)
圖4 GDI+基數樣條

?

持久的路徑對象

  在GDI中,路徑隸屬于一個設備上下文,一旦設備環境指針超過它的生存期,路徑也會被刪除。利用GDI+,可以創建并維護與Graphics對象分開的GraphicsPath 對象,它不依賴于Graphics對象的生存期。

  變形和矩陣對象

  GDI+提供了Matrix對象,它是一種可以使變形(旋轉、平移、縮放等) 簡易靈活的強大工具,Matrix對象需與要被變形的對象聯合使用。對于GraphicsPath類,我們可以使用其成員函數Transform接收Matrix參數用于變形。

void CGdiexampleDlg::OnTransformationMatrix()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建Graphics對象
 Graphics graphics(dc);
 GraphicsPath path;
 path.AddRectangle(Rect(250, 20, 70, 70));
 graphics.DrawPath(&Pen(Color::Black, 1), &path); // 在應用變形矩陣之前繪制矩形
 // 路徑變形
 Matrix matrix1, matrix2;

 matrix1.Rotate(45.0f); //旋轉順時針45度
 path.Transform(&matrix1); //應用變形
 graphics.DrawPath(&Pen(Color::Red, 3), &path);

 matrix2.Scale(1.0f, 0.5f); //轉化成為平行四邊形法則
 path.Transform(&matrix2); //應用變形
 graphics.DrawPath(&Pen(Color::Blue, 3), &path);
}

  圖5演示了正方形經過旋轉和拉伸之后的效果:黑色的為原始圖形,紅色的為旋轉45度之后的圖形,藍色的為經過拉伸為平行四邊形后的圖形。

WindowsGDI和GDI+編程實例全剖析(4)
圖5 GDI+變形和矩陣對象

  可伸縮區域

  GDI+通過對區域(Region)的支持極大地擴展了GDI。在GDI 中,區域存儲在設備坐標中,可應用于區域的唯一變形是平移。但是在GDI +中,區域存儲在全局坐標(世界坐標)中,可對區域利用變形矩陣進行變形(旋轉、平移、縮放等)。

void CGdiexampleDlg::OnScalableRegion()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建Graphics對象
 Graphics graphics(dc);
 //創建GraphicsPath
 GraphicsPath path;
 path.AddLine(100, 100, 150, 150);
 path.AddLine(50, 150, 150, 150);
 path.AddLine(50, 150, 100, 100);
 //創建Region
 Region region(&path);
 //填充區域
 graphics.FillRegion(&SolidBrush(Color::Blue), &region);
 //區域變形
 Matrix matrix;
 matrix.Rotate(10.0f); //旋轉順時針20度
 matrix.Scale(1.0f, 0.3f); //拉伸
 region.Transform(&matrix); //應用變形
 //填充變形后的區域
 graphics.FillRegion(&SolidBrush(Color::Green), &region);
}

  上述程序中以藍色填充一個三角形區域,接著將此區域旋轉和拉伸,再次顯示,其效果如圖6。

WindowsGDI和GDI+編程實例全剖析(4)
圖6 GDI+區域變形

豐富的圖像格式支持

  GDI +提供了Image、Bitmap 和Metafile 類,方便用戶進行圖像格式的加載、操作和保存。GDI+支持的圖像格式有BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、EMF等,幾乎涵蓋了所有的常用圖像格式。

void CGdiexampleDlg::OnImage()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建Graphics對象
 Graphics graphics(dc);
 Image image(L "d:\1.jpg");
 //在矩形區域內顯示jpg圖像
 Point destPoints1[3] =
 {
  Point(10, 10), Point(220, 10), Point(10, 290)
 };
 graphics.DrawImage(&image, destPoints1, 3);
 //在平行四邊形區域內顯示jpg圖像
 Point destPoints2[3] =
 {
  Point(230, 10), Point(440, 10), Point(270, 290)
 };
 graphics.DrawImage(&image, destPoints2, 3);
}

  上述程序將D盤根目錄下文件名為"1.jpg"的jpg圖像以矩陣和平行四邊形兩種方式顯示,效果如圖7。

WindowsGDI和GDI+編程實例全剖析(5)
圖7 GDI+多種圖像格式支持

  由此我們可以看出,GDI+在圖像顯示和操作方面的確比GDI簡單許多。回憶我們在《Visual C++中DDB與DIB位圖編程全攻略》一文中所介紹的用GDI顯示位圖的方式,其與GDI+圖像處理的難易程度真是有天壤之別。

Alpha混合

  Alpha允許將兩個物體混合起來顯示,在3D氣氛和場景渲染等方面有廣泛應用。它能"霧化"圖像,使得一個圖像著色在另一個半透明的圖像上,呈現一種朦朧美。我們知道,一個像素可用R,G,B三個維度來表示,我們可以再加上第4個即:Alpha維度(channel),表征透明程度。

void CGdiexampleDlg::OnAlphaBlend()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建Graphics對象
 Graphics graphics(dc);
 //創建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);
 //在矩形區域內顯示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);
 //在平行四邊形區域內顯示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"的圖像與之進行混合,其效果如圖8。

WindowsGDI和GDI+編程實例全剖析(6)
圖8 GDI+ Alpha混合

  為了能進行Alpha混合,我們需要使用ImageAttributes類和ColorMatrix矩陣,ImageAttributes可以進行顏色、灰度等調整從而達到控制圖像著色方式的目的。ColorMatrix是ImageAttributes類大多數函數的參數,它包含了Alpha、Red、Green、Blue維度的值,以及另一維w,順序為RGBaw。

  CGdiexampleDlg::OnAlphaBlend()函數中ColorMatrix的實例ClrMatrix中元素(4,4)的值為0.5,表示Alpha度的值為0.5(即半透明)。在ColorMatrix中,元素(5,5)的值恒定為1.0。我們把ClrMatrix的元素(0,0)修改為0.0,即使得圖像2.jpg的紅色維度全不顯示,再看效果,為圖9。列位讀者,我們以前在豪杰超級解霸中調整R,G,B值從而控制圖像輸出顏色的時候,調的就是這個東東!圖9的效果很像破舊彩色電視機,紅色電子槍"嗝"了。剛大學畢業時,俺那個叫窮啊,就買了這么個電視機,還看得很爽,真是往事不堪回首!

WindowsGDI和GDI+編程實例全剖析(6)
圖9 GDI+中的ColorMatrix

強大的文字輸出

  GDI+擁有極其強大的文字輸出處理能力,輸出文字的顏色、字體、填充方式都可以直接作為Graphics類DrawString成員函數的參數進行設置,其功能遠勝過GDI設備上下文的TextOut函數。

void CGdiexampleDlg::OnText()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 //創建Graphics對象
 Graphics graphics(dc);
 //創建20號"楷體"字體
 FontFamily fontFamily1(L "楷體_GB2312"); // 定義"楷體"字樣
 Font font1(&fontFamily1, 20, FontStyleRegular, UnitPoint);
 //定義輸出UNICODE字符串
 WCHAR string[256];
 wcscpy(string, L "天極網的讀者朋友,您好!");
 //以藍色畫刷和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));
 //以線性漸變畫刷和創建的20號"楷體"顯示字符串
 graphics.DrawString(string, (INT)wcslen(string), &font1, PointF(30, 50),&linGrBrush);
 //創建20號"華文行楷"字體
 FontFamily fontFamily2(L "華文行楷"); // 定義"楷體"字樣
 Font font2(&fontFamily2, 20, FontStyleRegular, UnitPoint);
 //以線性漸變畫刷和20號"華文行楷"顯示字符串
 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 90),&linGrBrush);
 //以圖像創建畫刷
 Image image(L "d:\3.jpg");
 TextureBrush tBrush(&image);
 //以圖像畫刷和20號"華文行楷"顯示字符串
 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 130),&tBrush);
 //創建25號"華文中宋"字體
 FontFamily fontFamily3(L "華文中宋"); // 定義"楷體"字樣
 Font font3(&fontFamily2, 25, FontStyleRegular, UnitPoint);
 //以圖像畫刷和20號"華文行楷"顯示字符串
 graphics.DrawString(string, (INT)wcslen(string), &font3, PointF(30, 170),&tBrush);
}

  上述代碼的執行效果如圖10所示,字體、顏色和填充都很豐富!