天天看點

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

原作者:孫濤 整理

http://blog.csdn.net/suntaoznz

GDI+介紹

Microsoft® Windows® GDI+ 是Windows XP 或者Windows Server 2003 作業系統的子系統。它負責在螢幕和列印機上顯示資訊。GDI+ 是一個應用程式程式設計接口,它是一個C++ 類。

如同它的名字暗示一樣,GDI+ 是Windows 圖形裝置接口(GDI)的繼承者, 這個圖形裝置接口包括早期的Windows版本。 Windows XP 或者 Windows Server 2003 為了支援以前的應用程式還支援GDI,但是新的應用程式開發人員應該去使用GDI+ 去作他們的圖像處理工作。因為GDI+對GDI的很多性能進行了優化,同時還提供了其他的一些特性。

一個圖形裝置接口,例如GDI+, 允許應用程式開發人員在列印機或螢幕上顯示資訊,而不用去考慮顯示裝置的具體細節。應用程式開發人員調用GDI+ classes 提供的方法(methods),這些方法将依次傳到指定的裝置驅動程式上。 GDI+ 讓應用程式與圖形硬體分離開,并且它可以開發人員建立獨立于裝置的應用程式。

1. GDI+的三個部分

--------------------------------------------------------------------------------

  • 2D矢量圖 (2-D vector graphics)
  • 圖像 (Imaging)
  • 印刷格式 (Typography)

2D矢量圖 2-D vector graphics

矢量圖形包括坐标系統中的系列點指定的繪圖基元(例如,直線、曲線和圖形)。例如,直線可通過它的兩個端點來指定,而矩形可通過确定其左上角位置的點并給出其寬度和高度的一對數字來指定。簡單路徑可由通過直線連接配接的點的數組來指定。貝塞爾樣條是由四個控制點指定的複雜曲線。

GDI+ 提供了存儲基元自身相關資訊的類(和結構)、存儲基元繪制方式相關資訊的類,以及實際進行繪制的類。例如,Rectangle 結構存儲矩形的位置和尺寸;Pen 類存儲有關線條顔色、線條粗細和線型的資訊;而 Graphics 類具有用于繪制直線、矩形、路徑和其他圖形的方法。還有幾種 Brush 類,它們存儲有關如何使用顔色或圖案來填充封閉圖形和路徑的資訊。

您可以在圖元檔案中記錄矢量圖像(圖形指令的序列)。GDI+ 提供了 Metafile 類,可用于記錄、顯示和儲存圖元檔案。MetafileHeader 和 MetaHeader 類允許您檢查圖元檔案頭中存儲的資料。

圖像處理(Imaging)

某些種類的圖檔很難或者根本無法用矢量圖形技術來顯示。例如,工具欄按鈕上的圖檔和顯示為圖示的圖檔就難以指定為直線和曲線的集合。擁擠的棒球運動場的高分辨率數字照片會更難以使用矢量技術來制作。這種類型的圖像可存儲為位圖,即代表螢幕上單個點顔色的數字數組。GDI+ 提供了 Bitmap 類,可用于顯示、操作和儲存位圖。

版式

版式關系到使用各種字型、字号和樣式來顯示文本。GDI+ 為這種複雜任務提供了大量的支援。GDI+ 中的新功能之一是子像素消除鋸齒,它可以使文本在 LCD 螢幕上呈現時顯得比較平滑。

2. 基于類的接口結構

--------------------------------------------------------------------------------

GDI+ 的托管類接口包含大約 60 個類、50 個枚舉和 8 個結構。Graphics 類是 GDI+ 的核心功能,它是實際繪制直線、曲線、圖形、圖像和文本的類。

許多類與 Graphics 類一起使用。例如,Graphics.DrawLine 方法接收 Pen 對象,該對象中存有所要繪制的線條的屬性(顔色、寬度、虛線線型和外觀)。Graphics.FillRectangle 方法可以接收指向 LinearGradientBrush 對象(它使用 Graphics 對象以漸變色填充矩形)的指針。Font 和 StringFormat 對象影響 Graphics 對象繪制文本的方式。Matrix 對象存儲并操作 Graphics 對象的全局變形,該對象用于旋轉、縮放和翻轉圖像。

GDI+ 為組織圖形資料提供了幾種結構(例如,Rectangle、Point 和 Size)。而且,某些類的主要作用是結構化資料類型。例如,BitmapData 類是 Bitmap 類的助手,而 PathData 類是 GraphicsPath 類的助手。

GDI+ 定義了幾種枚舉,它們是相關常量的集合。例如,LineJoin 枚舉包含元素 Bevel、Miter 和 Round,它們指定可用于連接配接兩個線條的樣式。

GDI+ 提供了少量不依附于任何類的函數。比如GdiplusStartup 和 GdiplusShutdown函數。 在你要調用GDI+前,必須先調用GdiplusStartup 。當你使用完GDI+後,你必須調用GdiplusShutdown 。

GDI+的新增特性?

--------------------------------------------------------------------------------

Microsoft® Windows® GDI+ 是不同于GDI的。首先, GDI+ 通過提供新的一些性能,在GDI的上進行擴充。比如gradient brushes 和alpha blending. 其次,程式設計的模式已經重新修改了,并且圖形程式設計更容易更靈活。

1. 新特性

--------------------------------------------------------------------------------

下面将介紹Microsoft® Windows® GDI+的幾個新的特性。

漸變畫筆(Gradient Brushes)

通過提供用于填充圖形、路徑和區域的線性漸變畫筆和路徑漸變畫筆,GDI+ 擴充了 GDI 的功能。漸變畫筆還可用于繪制直線、曲線和路徑。線性漸變畫筆可用于使用顔色來填充圖形,畫筆在圖形中移動時,顔色會逐漸改變。例如,假定您通過指定圖形左邊為藍色、右邊為綠色建立了一個水準漸變畫筆。當您用水準漸變畫筆填充該圖形時,随着畫筆從圖形的左邊移至右邊,顔色就會由藍色逐漸變為綠色。用類似方法定義的垂直漸變畫筆填充的圖形,顔色從上到下變化。下面的插圖顯示了用水準漸變畫筆填充的橢圓和用斜式漸變畫筆填充的區域。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

用路徑漸變畫筆填充圖形時,可選擇不同的方法來指定當您從圖形的一部分至另一部分移動畫筆時顔色的變化方式。一種選擇是指定中心顔色和邊緣顔色,以使在您從圖形中間向外邊緣移動畫筆時,像素逐漸從一種顔色變化到另一種顔色。下面的插圖顯示了用路徑漸變畫筆填充的路徑(該路徑是用一對貝塞爾樣條建立的)。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

基數樣條(Cardinal Splines)

GDI+ 支援在 GDI 中不支援的基數樣條。基數樣條是一連串單獨的曲線,這些曲線連接配接起來形成一條較大的曲線。樣條由點的數組指定,并通過該數組中的每一個點。基數樣條平滑地(沒有銳角)通過數組中的每一個點,是以,比通過連接配接直線建立的路徑更精準。下面的插圖顯示了兩個路徑,一個以基數樣條的形式建立,另一個通過連接配接直線建立。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

獨立的路徑對象

在 GDI 中,路徑屬于裝置上下文,并且會在繪制時被毀壞。利用 GDI+,繪圖由 Graphics 對象執行,而您可以建立并維護幾個與 Graphics 對象分開的 GraphicsPath 對象。繪圖操作不會破壞 GraphicsPath 對象,是以您可以多次使用同一個 GraphicsPath 對象來繪制路徑。

變形和矩陣對象

GDI+ 提供了 Matrix 對象,它是一種可以使變形(旋轉、平移,等等)簡易靈活的強大工具。矩陣對象與所變形對象聯合使用。例如,GraphicsPath 對象具有 Transform 方法,此方法接收 Matrix 對象作為參數。單一的 3×3 矩陣可存儲一種變形或一個變形序列。下面的插圖顯示了一個路徑在執行兩種變形前後的情況。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

縮放區域

GDI+ 通過對區域的支援極大地擴充了 GDI。在 GDI 中,區域存儲在裝置坐标中,而且,可應用于區域的唯一變形是平移。GDI+ 在全局坐标中存儲區域,且允許區域發生任何可存儲在變形矩陣中的變形(例如縮放)。下面的插圖顯示一個區域在執行三種變形(縮放、旋轉和平移)前後的情況。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

Alpha 混合

請注意,在上圖中,您可以在變形區域(用藍色陰影畫筆填充)中看到未變形區域(用紅色填充)。這是由 GDI+ 支援的 alpha 混合實作的。使用 alpha 混合,您可以指定填充顔色的透明度。透明色與背景色相混合 —填充色越透明,背景色的透出程度就越高。下面的插圖顯示四個用相同顔色(紅色)填充、但透明層次不同的橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

對多圖像格式的支援

BMP 、Graphics Interchange Format (GIF) 、JPEG 、Exif 、PNG 、TIFF 、ICON 、WMF

EMF。

2.程式設計模式的變化

--------------------------------------------------------------------------------

以下章節描述了使用 GDI+ 程式設計與使用 GDI 程式設計的幾點不同之處。

裝置上下文、句柄和圖形對象

如果您使用過 GDI(Windows 的以前版本中包括的圖形裝置接口)編寫程式,就會熟悉裝置上下文的知識。裝置上下文是 Windows 使用的一種結構,用于存儲與特殊顯示裝置的功能和指定如何在該裝置上繪制項目的屬性相關的資訊。用于視訊顯示的裝置上下文還與顯示的特定視窗關聯。首先,您獲得一個裝置上下文的句柄 (HDC),然後将該句柄作為參數傳遞至實際進行繪制的 GDI 函數。您還可将此句柄作為參數傳遞給擷取或設定裝置上下文屬性的 GDI 函數。

使用 GDI+,您不需要再使用句柄或裝置上下文,而是隻需建立一個 Graphics 對象,然後以您熟悉的面向對象樣式 myGraphicsObject.DrawLine(parameters) 調用其方法。正如裝置上下文位于 GDI 的核心,Graphics 對象也位于 GDI+ 的核心。裝置上下文和 Graphics 對象的作用相似,但在使用裝置上下文 (GDI) 的、基于句柄的程式設計模式和使用 Graphics 對象 (GDI+) 的、面向對象的程式設計模型之間存在一些基本的差異。

Graphics 對象(像裝置上下文一樣)與螢幕上的特定視窗關聯,并具有指定如何繪制項目的屬性(例如,SmoothingMode 和 TextRenderingHint)。但是,Graphics 對象不受鋼筆、畫筆、路徑、圖像或字型的限制,這與裝置上下文不同。例如,使用裝置上下文繪制線條之前,必須先調用 SelectObject 以使鋼筆對象和裝置上下文關聯。這是指将鋼筆選入裝置上下文中。在裝置上下文中繪制的所有線條均使用該鋼筆,直到您選擇另一支不同的鋼筆為止。在 GDI+ 中,将 Pen 對象作為參數傳遞給 Graphics 類的 DrawLine 方法。您可以在一系列 DrawLine 調用的每個調用中使用不同的 Pen 對象,而不必使給定的 Pen 對象與 Graphics 對象關聯。

繪制線條的兩種方法

下面每個示例都在位置 (20, 10) 和位置 (200, 100) 之間繪制了一條寬為 3 的紅色線條。第一個示例調用 GDI,第二個示例通過托管類接口調用 GDI+。

使用 GDI 繪制線條

要使用 GDI 繪制線條,需要兩個對象:裝置上下文和鋼筆。通過調用 BeginPaint,可以獲得裝置上下文句柄;通過調用 CreatePen,則可以獲得鋼筆句柄。下一步,調用 SelectObject 以将鋼筆選入裝置上下文。調用 MoveToEx,将鋼筆位置設在 (20, 10),然後調用 LineTo,在鋼筆位置與位置 (200, 100) 之間繪制一條線條。請注意,MoveToEx 和 LineTo 均将 hdc(裝置上下文的句柄)作為參數接收。

HDC          hdc;

           
PAINTSTRUCT  ps;

           
HPEN         hPen;

           
...

           
hdc = BeginPaint(hWnd, &ps);

           
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

           
SelectObject(hdc, hPen);

           
MoveToEx(hdc, 20, 10, NULL);

           
LineTo(hdc, 200, 100);

           
EndPaint(hWnd, &ps);

           

使用 GDI+ 和托管類接口繪制線條

用GDI+的C++類接口來畫線,你需要一個Graphics 對象和一個Pen 對象。你不要去獲得這些對象的句柄。你去建立一個Graphics 對象和一個Pen 對象。調用Graphics 對象的Graphics::DrawLine 方法。Graphics::DrawLine 方法的第一個參數,就是指向你的Pen 對象的指針。

HDC          hdc;

           
PAINTSTRUCT  ps;

           
Pen*         myPen;

           
Graphics*    myGraphics;

           
hdc = BeginPaint(hWnd, &ps);

           
myPen = new Pen(Color(255, 255, 0, 0), 3);

           
myGraphics = new Graphics(hdc);

           
myGraphics->DrawLine(myPen, 20, 10, 200, 100);

           
delete myGraphics;

           
delete myPen;

           
EndPaint(hWnd, &ps);

           

作為參數的鋼筆、畫筆、路徑、圖像和字型

前面的示例顯示:建立和維護 Pen 對象可以與提供繪制方法的 Graphics 對象分開。建立和維護 Brush、GraphicsPath、Image 和 Font 對象也可以與 Graphics 對象分開。Graphics 類提供的許多繪制方法都将 Brush、GraphicsPath、Image 或 Font 對象作為參數接收。例如,Brush 對象作為參數傳遞至 FillRectangle 方法,GraphicsPath 對象作為參數傳遞至 DrawPath 方法。同樣,Image 和 Font 對象傳遞至 DrawImage 和 DrawString 方法。這與 GDI 不同,在 GDI 中,需要将畫筆、路徑、圖像或字型選入裝置上下文,然後将裝置上下文的句柄作為參數傳遞至繪制函數。

方法重載

許多 GDI+ 方法都是重載的,即,若幹方法共享同一名稱,卻有不同的參數清單。例如,Graphics 類的 DrawLine 方法來自下清單單:

Status DrawLine(IN const Pen* pen,

           
IN REAL x1,

           
IN REAL y1,

           
IN REAL x2,

           
IN REAL y2);

           
Status DrawLine(IN const Pen* pen,

           
IN const PointF& pt1,

           
IN const PointF& pt2);

           
Status DrawLine(IN const Pen* pen,

           
IN INT x1,

           
IN INT y1,

           
IN INT x2,

           
IN INT y2);
				
           
Status DrawLine(IN const Pen* pen,

           
IN const Point& pt1,

           
IN const Point& pt2);

           

以上四種 DrawLine 變體均接收 Pen 對象、起點坐标和終點坐标。前兩種變體将坐标作為浮點數接收,而後兩種變體将坐标作為整數接收。第一種和第三種變體将坐标作為四個單個數字的清單接收,而第二種和第四種變體則将坐标作為一對 Point(或 PointF)對象接收。

無目前位置

請注意,前面所述的 DrawLine 方法中顯示:線條的起點和終點均被作為參數接收。這與 GDI 方案不同,在 GDI 中,調用 MoveToEx(hdc, x1, y1, NULL) 來設定目前鋼筆位置之後,再調用 LineTo(hdc, x2, y2) 以繪制一條從 (x1, y1) 到 (x2, y2) 的線條。GDI+ 從總體上已經放棄了目前位置的概念。

繪制和填充的不同方法

論及繪制輪廓和填充圖形内部時,GDI+ 要比 GDI 更靈活。GDI 有一個 Rectangle 函數,可一步完成繪制輪廓和填充矩形内部。輪廓由目前標明的鋼筆繪制,而内部則由目前標明的畫筆來填充。

hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));

           
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

           
SelectObject(hdc, hBrush);

           
SelectObject(hdc, hPen);

           
Rectangle(hdc, 100, 50, 200, 80);

           

GDI+ 使用不同的方法來繪制輪廓和填充矩形内部。Graphics 類的 DrawRectangle 方法将 Pen 對象作為其參數之一,而 FillRectangle 方法将 Brush 對象作為其參數之一。

HatchBrush* myHatchBrush = new HatchBrush(

           
HatchStyleCross,

           
Color(255, 0, 255, 0),

           
Color(255, 0, 0, 255));

           
Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);

           
myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);

           
myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);
				
           

請注意,GDI+ 中的 FillRectangle 和 DrawRectangle 方法接收指定矩形左邊緣、上邊緣、寬和高的參數。這與 GDI 的 Rectangle 函數不同,Rectangle 函數接收指定矩形左邊緣、右邊緣、上邊緣和下邊緣的參數。另請注意,GDI+ 中 Color 類的 FromArgb 方法有四個參數。後三個參數是常見的紅色、綠色和藍色值。第一個參數是 alpha 值,它指定所繪制顔色與背景顔色的混合程度。

構造區域

GDI 提供幾種用于建立區域的函數:CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn 和 CreatePolyPolygonRgn。您或許希望 GDI+ 中的 Region 類也有類似的構造函數,将矩形、橢圓、圓角矩形和多邊形作為參數接收,但事實并非如此。GDI+ 中的 Region 類提供一個接收 Rectangle 對象的構造函數和另一個接收 GraphicsPath 對象的構造函數。如果您想基于橢圓、圓角矩形或多邊形構造區域,可以通過建立一個 GraphicsPath 對象(例如包含橢圓的對象),然後将其傳遞至 Region 構造函數來輕松實作。

GDI+ 通過組合圖形和路徑,使得構成複雜區域十分簡單。Region 類具有 Union 和 Intersect 方法,可用于擴充具有路徑的現有區域或其他區域。GDI+ 方案一個很好的功能就是 GraphicsPath 對象在作為參數傳遞至 Region 構造函數時不會被破壞(在 GDI 中,可以使用 PathToRegion 函數将路徑轉換為區域,但在此過程中,路徑将被破壞)。另外,GraphicsPath 對象在作為參數傳遞給 Union 或 Intersect 方法時也不會被破壞,是以,在一些單獨的區域中,您可以将給定的路徑作為構造塊使用。此過程如下面的示例所示。假定 onePath 是一個已初始化的 GraphicsPath 對象(簡單或複雜)。

Region  region1(rect1);

           
Region  region2(rect2);

           
region1.Union(onePath);

           
region2.Intersect(onePath);

           

直線、曲線和圖形

--------------------------------------------------------------------------------

GDI+ 的矢量圖形部分用于繪制直線、曲線,并用于繪制和填充圖形。

1. 矢量圖形概述

--------------------------------------------------------------------------------

GDI+ 在坐标系統中繪制直線、矩形和其他圖形。您可以從各種各樣的坐标系統中選擇,但預設坐标系統的原點是在左上角,并且 x 軸指向右邊,y 軸指向下邊。預設坐标系統的度量機關是像素。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

計算機螢幕是在一個點的矩形數組上建立其顯示,這些點被稱為圖檔元素或像素。各台螢幕螢幕上顯示的像素數量都是不同的,并且使用者通常在一定程度上可以配置單獨一台螢幕上顯示的像素數量。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

在使用 GDI+ 繪制直線、矩形或曲線時,要提供有關要繪制的項目的某些關鍵資訊。例如,您可以通過提供兩個點來指定一條直線,而且您可以通過提供一個點、高度和寬度來指定一個矩形。GDI+ 與顯示驅動程式軟體一同工作來确定要顯示直線、矩形或曲線必須打開哪些像素。下面的插圖顯示了已打開的用于顯示從點 (4, 2) 到點 (12, 8) 的直線的像素。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

在實踐中,人們發現某些基本構造塊對于建立二維圖檔尤其有用。下面列出了全部由 GDI+ 支援的這些構造塊:

  • 矩形
  • 橢圓
  • 弧線
  • 多邊形
  • 基數樣條
  • 貝塞爾樣條

GDI+ 中的 Graphics 類提供了以下用于繪制前面清單中項目的方法:DrawLine、DrawRectangle、DrawEllipse、DrawPolygon、DrawArc、DrawCurve(用于基數樣條)和 DrawBezier。這些方法中的每一種都是重載的,即每種方法都支援幾個不同的參數清單。例如,DrawLine 方法的一個變體接收一個 Pen 對象和四個整數,而 DrawLine 方法的另一個變體接收一個 Pen 對象和兩個 Point 對象。

繪制線條、矩形和貝塞爾樣條的方法具有可在單個調用中繪制多個項目的複數同伴方法:DrawLines、DrawRectangles 和 DrawBeziers。DrawCurve 方法也有一個同伴方法 DrawClosedCurve,它能夠通過連接配接曲線的終點和起點來關閉該曲線。

Graphics 類的所有繪制方法與 Pen 對象共同工作。要進行繪制,必須至少建立兩個對象:一個 Graphics 對象和一個 Pen 對象。Pen 對象存儲要繪制項目的屬性,例如,線寬和顔色。Pen 對象作為參數之一傳遞到繪制方法。例如,如下面的示例所示,DrawRectangle 方法的一個變體接收一個 Pen 對象和四個整數,該示例繪制一個寬 100、高 50 且左上角位于 (20, 10) 的矩形:

myGraphics.DrawRectangle(&myPen, 20, 10, 100, 50);

           

2. 鋼筆、直線和矩形

--------------------------------------------------------------------------------

要使用 GDI+ 繪制直線,需要建立 Graphics 對象和 Pen 對象。Graphics 對象提供能實際進行繪制的方法,Pen 對象存儲屬性,例如,線條顔色、寬度和線型。要繪制直線,可調用 Graphics 對象的 DrawLine 方法。Pen 對象作為參數之一傳遞到 DrawLine 方法。下面的示例繪制了一條從點 (4, 2) 到點 (12, 6) 的直線:

myGraphics.DrawLine(&myPen, 4, 2, 12, 6);

           

DrawLine 是 Graphics 類的重載方法,是以您有幾種方法可以給它提供參數。例如,您可以構造兩個 Point 對象并把它們作為參數傳遞給 DrawLine 方法:

Point myStartPoint(4, 2);

           
Point myEndPoint(12, 6);

           
myGraphics.DrawLine(&myPen, myStartPoint, myEndPoint);
					
           

您在構造 Pen 對象時可以指定某些屬性。例如,一種 Pen 構造函數允許您指定顔色和寬度。下面的示例繪制了一條從 (0, 0) 到 (60, 30) 寬度為 2 的藍線:

Pen myPen(Color(255, 0, 0, 255), 2);

           
myGraphics.DrawLine(&myPen, 0, 0, 60, 30);

           

Pen 對象也公開屬性,例如 DashStyle 可用于指定直線的特性。下面的示例繪制了一條從 (100, 50) 到 (300, 80) 的點劃線:

myPen.SetDashStyle(DashStyleDash);

           
myGraphics.DrawLine(&myPen, 100, 50, 300, 80);
				
           

您可以利用 Pen 對象的屬性來為直線設定更多屬性。StartCap 和 EndCap 屬性指定線條兩端的外觀;兩端可以是平的、正方形的、圓形的、三角形的或自定義形狀。LineJoin 屬性可用于指定連接配接的線互相間是斜接的(連接配接時形成銳角)、斜切的、圓形的還是截斷的。下面的插圖顯示了具有不同的線帽和連接配接類型的直線。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

利用 GDI+ 繪制矩形與繪制直線類似。要繪制矩形,需要有 Graphics 對象和 Pen 對象。Graphics 對象提供了 DrawRectangle 方法,Pen 對象存儲屬性,例如,線寬和顔色。Pen 對象作為參數之一傳遞到 DrawRectangle 方法。下面的示例繪制了一個矩形,其左上角位于 (100, 50),寬度為 80,高度為 40:

myGraphics.DrawRectangle(&myPen, 100, 50, 80, 40);

           

DrawRectangle 是 Graphics 類的重載方法,是以您有幾種方法為它提供參數。例如,您可以構造一個 Rectangle 對象并将該 Rectangle 對象作為參數傳遞到 DrawRectangle 方法:

Rect myRect(100, 50, 80, 40);

           
myGraphics.DrawRectangle(&myPen, myRect);

           

Rectangle 對象具有用于處理和收集矩形相關資訊的方法和屬性。例如,Inflate 和 Offset 方法可改變該矩形的大小和位置。IntersectsWith 方法可顯示矩形是否與另一給定的矩形相交,Contains 方法可顯示一個給定的點是否在該矩形内。

3.橢圓和弧線

--------------------------------------------------------------------------------

橢圓由其邊框指定。下面的插圖顯示了一個橢圓,以及它的邊框。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

要繪制橢圓,需要有 Graphics 對象和 Pen 對象。Graphics 對象提供 DrawEllipse 方法,而 Pen 對象存儲用于呈現橢圓的線條屬性,例如,寬度和顔色。Pen 對象作為參數之一傳遞到 DrawEllipse 方法。傳遞到 DrawEllipse 方法的其餘參數指定橢圓的邊框。下面的示例繪制了一個橢圓;邊框的寬度為 80,高度為 40,左上角位于 (100, 50):

myGraphics.DrawEllipse(&myPen, 100, 50, 160, 80);

           

DrawEllipse 是 Graphics 類的重載方法,是以您有幾種方法可為它提供參數。例如,您可以構造 Rectangle 對象并将 Rectangle 對象作為參數傳遞到 DrawEllipse 方法:

Rect myRect(100, 50, 160, 80);

           
myGraphics.DrawEllipse(&myPen, myRect);

           

弧線是橢圓的一部分。要繪制弧線,可調用 Graphics 類的 DrawArc 方法。除了 DrawArc 需要有起始角度和仰角以外,DrawArc 方法的參數與 DrawEllipse 方法的參數相同。下面的示例繪制了一個起始角為 30 度、仰角為 180 度的弧線:

myGraphics.DrawArc(&myPen, 100, 50, 160, 80, 30, 180);

           

下面的插圖顯示了弧線、橢圓和邊框。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

4.多邊形

--------------------------------------------------------------------------------

多邊形是有三條或更多直邊的閉合圖形。例如,三角形是有三條邊的多邊形,矩形是有四條邊的多邊形,五邊形是有五條邊的多邊形。下面的插圖顯示了幾個多邊形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

要繪制多邊形,需要有 Graphics 對象、Pen 對象和 Point(或 PointF)對象的數組。Graphics 對象提供了 DrawPolygon 方法。Pen 對象存儲用于呈現多邊形的線條屬性,例如,寬度和顔色,Point 對象的數組存儲将由直線連接配接的點。Pen 對象和 Point 對象的數組作為參數傳遞到 DrawPolygon 方法。下面的示例繪制了一個三條邊的多邊形。請注意,myPointArray 中隻有三個點:(0, 0)、(50, 30) 和 (30, 60)。DrawPolygon 方法通過繪制一條從 (30, 60) 回到起始點 (0, 0) 的線來自動閉合該多邊形。

Point myPointArray[] =

           
{Point(0, 0), Point(50, 30), Point(30, 60)};

           
myGraphics.DrawPolygon(&myPen, myPointArray, 3);

           

下面的插圖顯示了該多邊形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

5. 基數樣條

--------------------------------------------------------------------------------

基數樣條是一連串單獨的曲線,這些曲線連接配接起來形成一條較大的曲線。樣條由點的數組和張力參數指定。基數樣條平滑地經過數組中的每個點;曲線的陡度上沒有尖角和突然的變化。下面的插圖顯示了一組點和經過這一組點中每一點的基數樣條。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

實體樣條是一塊薄木片或其他有彈性的物質。在數學樣條出現之前,設計者利用實體樣條繪制曲線。設計者把樣條放置在一張紙上并錨定到一組給定的點上。然後設計者就可以用鉛筆沿着樣條繪制出一條曲線。一組給定的點可以産生各種各樣的曲線,這取決于實體樣條的屬性。例如,極不易彎曲的樣條與非常有彈性的樣條産生的曲線是不同的。

數學樣條的公式基于彈性棒條的屬性,是以數學樣條産生的曲線與實體樣條曾産生的曲線是相同的。正如不同張力的實體樣條通過一組給定的點将産生不同的曲線一樣,張力參數值不同的數學樣條在一組給定的點上将産生不同的曲線。下面的插圖顯示了經過同一組點的四個基數樣條。每個樣條都顯示了張力。請注意,0 張力對應于無限的實體張力,強制曲線在點與點之間采用最短的路線(直線)。張力為 1 對應于沒有實體張力,使樣條采用最小完全彎曲的路徑。張力值大于 1 的曲線就像壓縮的彈簧,被擠壓着采用較長的路徑。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

請注意,上面插圖中的四個樣條共享同一條起始點處的切線。該切線是從起始點到沿着曲線的下一點繪制的一條線。同樣,在結束點處共享的切線是從結束點到沿着曲線的上一點繪制的一條線。

要繪制基數樣條,需要有 Graphics 對象、Pen 對象和 Point 對象的數組。Graphics 提供繪制樣條的 DrawCurve 方法,Pen 對象存儲樣條的屬性,例如,線寬和顔色。Point 對象數組存儲曲線将要經過的點。下面的示例繪制了一個經過 myPointArray 中的點的基數樣條。第三個參數是張力。

myGraphics.DrawCurve(&myPen, myPointArray, 3, 1.5f);

           

6. 貝塞爾樣條

--------------------------------------------------------------------------------

貝塞爾樣條是由四個點指定的曲線:兩個終點(p1 和 p2)和兩個控制點(c1 和 c2)。曲線開始于 p1,結束于 p2。該曲線不經過控制點,但是控制點的作用像磁鐵一樣,在某些方向上拉拽曲線并影響曲線彎曲的方式。下面的插圖顯示了一個貝塞爾曲線及其終點和控制點。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

請注意,該曲線開始于 p1 并向控制點 c1 移動。該曲線 p1 處的切線是從 p1 到 c1 繪制的線。另外請注意,終結點 p2 處的切線是從 c2 到 p2 繪制的線。

若要繪制貝塞爾樣條,需要 Graphics 對象和 Pen 對象。Graphics 對象提供 DrawBezier 方法,Pen 對象存儲用于呈現曲線的線條屬性,例如,寬度和顔色。Pen 對象作為參數之一傳遞給 DrawBezier 方法。傳遞到 DrawBezier 方法的其餘參數是終結點和控制點。下面的示例繪制了一個貝塞爾樣條,起始點為 (0, 0),控制點為 (40, 20) 和 (80, 150),結束點為 (100, 10):

myGraphics.DrawBezier(&myPen, 0, 0, 40, 20, 80, 150, 100, 10);

           

下面的插圖顯示了曲線、控制點和兩條切線。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

貝塞爾樣條最初是由皮埃爾·貝塞爾開發的,用于汽車工業設計中。許多類型的計算機輔助設計都證明了它們十分有用,它們也用于定義字型的輪廓。貝塞爾樣條可生成各種各樣的形狀,下面的插圖顯示了其中的一些。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

7. 路徑

--------------------------------------------------------------------------------

路徑是通過組合直線、矩形和簡單的曲線而形成的。請回憶一下矢量圖形概述,以下基本構造塊已被證明對于繪制圖檔是非常有用的:

  • 矩形
  • 橢圓
  • 弧線
  • 多邊形
  • 基數樣條
  • 貝塞爾樣條

在 GDI+ 中,GraphicsPath 對象允許您将這些構造塊序列收集到一個單獨單元中。一個對 Graphics 類的 DrawPath 方法的調用,可以繪制出整個序列的直線、矩形、多邊形和曲線。下面的插圖顯示了通過結合一條直線、一個弧形、一個貝塞爾樣條和一個基數樣條而建立的路徑。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

GraphicsPath 類提供了以下用于建立待繪制項目序列的方法:AddLine、AddRectangle、AddEllipse、AddArc、AddPolygon、AddCurve(用于基數樣條)和 AddBezier。這些方法中的每一種都是重載的,即每種方法都支援幾個不同的參數清單。例如,AddLine 方法的一個變體接收四個整數,而 AddLine 方法的另一個變體接收兩個 Point 對象。

向一個路徑添加直線、矩形和貝塞爾樣條的方法有複數同伴方法(在單個調用中向路徑添加若幹個項目):AddLines、AddRectangles 和 AddBeziers。AddCurve 和 AddArc 方法也有同伴方法 AddClosedCurve 和 AddPie,它們可向路徑添加閉合的曲線或扇形。

要繪制路徑,需要有 Graphics 對象、Pen 對象和 GraphicsPath 對象。Graphics 對象提供 DrawPath 方法,Pen 對象存儲用于呈現路徑的線條屬性,例如,寬度和顔色。GraphicsPath 對象存儲構成路徑的直線和曲順序列。Pen 對象和 GraphicsPath 對象作為參數傳遞到 DrawPath 方法。下面的示例繪制了由直線、橢圓和貝塞爾樣條組成的路徑:

myGraphicsPath.AddLine(0, 0, 30, 20);

           
myGraphicsPath.AddEllipse(20, 20, 20, 40);

           
myGraphicsPath.AddBezier(30, 60, 70, 60, 50, 30, 100, 10);

           
myGraphics.DrawPath(&myPen, &myGraphicsPath);

           

下面的插圖顯示了該路徑。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

除了向路徑添加直線、矩形和曲線外,還可以向路徑添加路徑。這就允許您合并現有的路徑來形成大型複雜路徑。

myGraphicsPath.AddPath(&graphicsPath1, FALSE);

           
myGraphicsPath.AddPath(&graphicsPath2, TRUE);

           

您還可以把其他兩個項目加入路徑:字元串和扇形。扇形是橢圓内的一部分。下面的示例用弧形、基數樣條、字元串和扇形建立了路徑:

myGraphicsPath.AddArc(0, 0, 30, 20, -90, 180);

           
myGraphicsPath.AddCurve(myPointArray, 3);

           
myGraphicsPath.AddString(L"a string in a path", 18, &myFontFamily, 
					
           
0, 24, myPointF, &myStringFormat);

           
myGraphicsPath.AddPie(230, 10, 40, 40, 40, 110);

           
myGraphics.DrawPath(&myPen, &myGraphicsPath);
				
           

下面的插圖顯示了該路徑。請注意,不必連接配接路徑;弧形、基數樣條、字元串和扇形都是分開的。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

8. 畫筆和填充的形狀

--------------------------------------------------------------------------------

閉合的形狀(例如,矩形或橢圓)由輪廓和内部組成。輪廓用鋼筆繪制,内部用畫筆填充。GDI+ 提供了幾種用于填充閉合形狀内部的畫筆類:SolidBrush、HatchBrush、TextureBrush 和 GradientBrush。所有這些類都是從 Brush 類繼承的。下面的插圖顯示了用實心畫筆填充的矩形和用陰影畫筆填充的橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

實心畫筆

要填充閉合圖形,需要有 Graphics 對象和 Brush 對象。Graphics 對象提供 FillRectangle 和 FillEllipse 這樣的方法,Brush 對象存儲填充的屬性,例如,顔色和圖案。Brush 對象作為參數之一傳遞到填充方法。下面的示例用純紅色填充橢圓:

SolidBrush mySolidBrush(Color(255, 255, 0, 0));

           
myGraphics.FillEllipse(&mySolidBrush, 0, 0, 60, 40);

           

請注意,在前面的示例中,畫筆是從 Brush 繼承的 SolidBrush 類型。

陰影畫筆

用陰影畫筆填充圖形時,要指定前景色、背景色和陰影樣式。前景色是陰影的顔色。

HatchBrush myHatchBrush(

           
HatchStyleVertical, 

           
Color(255, 0, 0, 255),

           
Color(255, 0, 255, 0)); 
				
           

GDI+ 提供了 50 多種陰影樣式;下面插圖中顯示的三種樣式分别是水準的、前置對角的和交叉的。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

紋理畫筆

有了紋理畫筆,您就可以用位圖中存儲的圖案來填充圖形。例如,假定下面的圖檔存儲在名為 MyTexture.bmp 的磁盤檔案中。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

下面的示例通過重複存儲在 MyTexture.bmp 中的圖檔來填充橢圓:

Image myImage(L"MyTexture.bmp");

           
TextureBrush myTextureBrush(&myImage);

           
myGraphics.FillEllipse(&myTextureBrush, 0, 0, 100, 50);

           

下面的插圖顯示已填充的橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

漸變畫筆

GDI+ 提供兩種漸變畫筆:線性和路徑。您可以使用線性漸變畫筆來用顔色(在您橫向、縱向或斜向移過圖形時會逐漸變化的顔色)填充圖形。下面的示例用水準漸變畫筆填充一個橢圓,當您從橢圓的左邊緣向右邊緣移動時畫筆顔色會由藍變綠:

LinearGradientBrush myLinearGradientBrush(

           
myRect,

           
Color(255, 0, 0, 255),

           
Color(255, 0, 255, 0),

           
LinearGradientModeHorizontal);

           
myGraphics.FillEllipse(&myLinearGradientBrush, myRect); 
				
           

下面的插圖顯示已填充的橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

路徑漸變畫筆可配置為當您從圖形中心向邊緣移動時顔色随之改變。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

路徑漸變畫筆非常靈活。用于填充下面插圖中三角形的漸變畫筆,顔色從中心由紅色開始到頂點逐漸變為三種不同的顔色。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

9. 打開的曲線和閉合的曲線

--------------------------------------------------------------------------------

下面的插圖顯示了兩條曲線:一條打開的和一條閉合的。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

閉合的曲線具有内部,是以可以用畫筆填充。GDI+ 中的 Graphics 類提供了以下用于填充閉合圖形和曲線的方法:FillRectangle、FillEllipse、FillPie、FillPolygon、FillClosedCurve、FillPath 和 FillRegion。每當調用其中某種方法時,都必須将一種特定的畫筆類型(SolidBrush、HatchBrush、TextureBrush、LinearGradientBrush 或 PathGradientBrush)作為參數傳遞。

FillPie 方法是 DrawArc 方法的伴侶。正如 DrawArc 方法繪制橢圓輪廓的一部分,FillPie 方法填充橢圓内部的一部分。下面的示例繪制了一個弧形并填充橢圓内部的相應部分:

SolidBrush mySolidBrush(Color(255, 255, 0, 0));

           
myGraphics.FillEllipse(&mySolidBrush, 0, 0, 60, 40);

           

下面的插圖顯示了該弧形和填充後的扇形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

FillClosedCurve 方法是 DrawClosedCurve 方法的伴侶。這兩種方法都通過連接配接結束點和起始點來自動閉合曲線。下面的示例繪制了一條經過 (0, 0)、(60, 20) 和 (40, 50) 的曲線。然後,該曲線通過連接配接 (40, 50) 至起始點 (0, 0) 自動閉合,并且用一種純色填充内部。

Point myPointArray[] =

           
{Point(10, 10), Point(60, 20),Point(40, 50)};

           
myGraphics.DrawClosedCurve(&myPen, myPointArray, 3);

           
myGraphics.FillClosedCurve(&mySolidBrush, myPointArray, 3, FillModeAlternate)

           

FillPath 方法填充了路徑的不同部分的内部。如果路徑的某一部分不構成封閉的曲線或圖形,FillPath 方法會在填充該部分之前先自動将其閉合。下面的示例繪制并填充一個路徑,該路徑由弧形、基數樣條、字元串和扇形組成:

myGraphics.FillPath(&mySolidBrush, &myGraphicsPath);

           
myGraphics.DrawPath(&myPen, &myGraphicsPath);

           

下面的插圖顯示了有純色填充和沒有純色填充的路徑。請注意,通過利用 DrawPath 方法,字元串内的文本是空心的,而不是實心的。FillPath 方法可用于繪制字元串中字元的内部。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

10. 區域

---------------------------------------------------------------------

區域是輸出裝置顯示區域的一部分。區域可以是簡單的(單個矩形)或複雜的(多邊形和閉合曲線的組合)。下面的插圖顯示了兩個區域:一個利用矩形構造,另一個利用路徑構造。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

區域常用于剪輯和命中檢測。剪輯需要将繪制限制到顯示區域的一個特定區域,通常是需要更新的部分。命中檢測需要通過檢查來确定按下滑鼠按鈕時光标是否在螢幕的特定區域中。

您可以從矩形或路徑中構造區域。您也可以通過合并現有的區域來建立複雜區域。Region 類提供了以下合并區域的方法:Intersect、Union、Xor、Exclude 和 Complement。

兩個區域的交集是同時屬于兩個區域的所有點的集合。并集是屬于一個或另一個或兩個區域的所有點的集合。區域的補集是不在該區域的所有點的集合。下面的插圖顯示了前面插圖中兩個區域的交集和并集。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

适用于一對區域的 Xor 方法可生成一個區域,其中包含屬于一個區域或另一個區域但不同時屬于兩個區域的所有點。适用于一對區域的 Exclude 方法可生成了一個區域,其中包含在第一個區域中而不在第二個區域中的所有點。下面的插圖顯示了通過将 Xor 和 Exclude 方法應用于該主題開始處的兩個區域而産生的區域。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

要填充區域,需要有 Graphics 對象、Brush 對象和 Region 對象。Graphics 對象提供 FillRegion 方法,Brush 對象存儲填充的屬性,例如,顔色或圖案。下面的示例用純色填充區域:

myGraphics.FillRegion(&mySolidBrush, &myRegion);

           

11. 剪輯

---------------------------------------------------------------------

剪輯需要把繪制限制到一個特定的矩形或區域。下面的插圖顯示了剪輯到心形區域的字元串"Hello"。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

區域可從路徑構造,路徑可包含字元串的輪廓,是以您可以剪輯空心效果的文字。下面的插圖顯示了剪輯到文本字元串内部的一組同心橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

要利用剪輯繪制,可建立 Graphics 對象,設定其 Clip 屬性,然後調用同一個 Graphics 對象的繪制方法:

Region myRegion(Rect(20, 30, 100, 50));

           
myGraphics.DrawRectangle(&myPen, 20, 30, 100, 50);  

           
myGraphics.SetClip(&myRegion, CombineModeReplace);

           
myGraphics.DrawLine(&myPen, 0, 0, 200, 200);

           

12.拉平路徑

---------------------------------------------------------------------

GraphicsPath 對象存儲一系列直線和貝塞爾樣條。您可以将若幹種類型的曲線(橢圓、弧形和基數樣條)添至路徑,但在存儲到路徑中之前,各種曲線都會轉化為貝塞爾樣條。拉平路徑包含将路徑中的各條貝塞爾樣條轉化為一連串直線。

要拉平路徑,可調用 GraphicsPath 對象的 Flatten 方法。Flatten 方法接收拉平參數,該參數指定拉平的路徑和原始路徑之間的最大距離。下面的插圖顯示了路徑(拉平之前和拉平之後)。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

13. 用直線和曲線消除鋸齒

---------------------------------------------------------------------

在使用 GDI+ 繪制直線時,要提供直線的起始點和結束點,但不需要提供有關線上單個像素的任何資訊。GDI+ 與顯示驅動程式軟體共同工作,可确定在特定顯示裝置上顯示直線要打開哪些像素。

請注意從點 (4,2) 到點 (16,10) 的紅色直線。假定坐标系統的原點位于左上角且度量機關是像素。另外假定 x 坐标軸指向右邊、y 坐标軸指向下邊。下面的插圖顯示了在多顔色背景下繪制的紅線的放大視圖。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

請注意,用來呈現該線的紅色像素是不透明的。直線中沒有部分透明的像素。這種類型的直線看上去帶有鋸齒,有點像樓梯。這種用樓梯狀來表示直線的技術被稱為鋸齒化;樓梯是理論直線的一個别名。

一項更為複雜的呈現直線的技術需要使用部分透明的像素和不透明的像素。像素被設為純紅色或紅色和背景色的混合色(取決于它們和直線的接近程度)。這種呈現方式被稱為消除鋸齒,它可以生成視覺上更感平滑的直線。下面的插圖顯示了如何混合特定的像素和背景來生成消除鋸齒的直線。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

消除鋸齒(平滑化)也可應用于曲線。下面的插圖顯示了平滑橢圓的放大視圖。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

下面的插圖顯示了實際大小的同一個橢圓,一次沒有使用消除鋸齒,另一次使用了消除鋸齒。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

要繪制使用消除鋸齒的直線和曲線,可建立 Graphics 對象,并将其 SmoothingMode 屬性設為 SmoothingMode.AntiAlias 或 SmoothingMode.HighQuality。然後調用同一個 Graphics 對象的某種繪制方法。

myGraphics.SetSmoothingMode(SmoothingModeAntiAlias);

           
myGraphics.DrawLine(&myPen, 0, 0, 12, 8);

           

圖像、位圖和圖元檔案

--------------------------------------------------------------------------------

Image 類是抽象基類,它提供了處理光栅圖像(位圖)和矢量圖像(圖元檔案)的方法。Bitmap 類和 Metafile 類都從 Image 類繼承。Bitmap 類提供了用于加載、儲存和處理光栅圖像的其他方法,因而擴充了 Image 類的功能。Metafile 類提供了用于記錄和檢查矢量圖像的其他方法,因而擴充了 Image 類的功能。

1. 位圖類型

位圖是位的數組,它指定了像素矩陣中各像素的顔色。專用于單個像素的位數決定了可配置設定到該像素的顔色數。例如,如果用 4 位來呈現每個像素,那麼一個給定的像素就可以配置設定到 16 (2^4 = 16) 種顔色中的一種。下表中的幾個示例顯示了可配置設定到由給定位數代表的像素的顔色數量。

每像素的位數 一個像素可配置設定到的顔色數量
1 2^1 = 2
2 2^2 = 4
4 2^4 = 16
8 2^8 = 256
16 2^16 = 65536
24 2^24 = 16, 777, 216

存儲位圖的磁盤檔案通常包含一個或多個資訊塊,資訊塊中存儲了如每像素位數、每行的像素數以及數組中的行數等資訊。這樣一個檔案也可能包含顔色表(有時稱為調色闆)。顔色表将位圖中的數值映射到特定的顔色。下面的插圖顯示了一幅放大的圖像以及它的位圖和顔色表。每個像素用一個 4 位數表示,那麼顔色表中有 2^4 = 16 種顔色。表中的每種顔色用一個 24 位數表示:8 位用于紅色,8 位用于綠色,8 位用于藍色。數字以十六進制(基 16)形式顯示:A = 10,B = 11,C = 12,D = 13,E = 14,F = 15。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

請看位于該圖像第 3 行、第 5 列的像素。位圖中相應的數值為 1。顔色表告訴我們 1 表示紅色,是以該像素是紅色的。該位圖最上面一行中所有的項都是 3。顔色表告知我們 3 表示藍色,是以該圖像最上面一行中的所有像素都是藍色。

注意   一些位圖以上下颠倒的格式存儲;位圖首行中的數值對應于圖像最下面一行的像素。

在顔色表中存儲索引的位圖被稱為"調色闆索引"位圖。有些位圖不需要顔色表。例如,如果位圖使用每像素 24 位的格式,那麼該位圖就可以将顔色本身(而不是索引)存儲到顔色表中。下面的插圖顯示了一個直接存儲顔色(24 位/像素)而不使用顔色表的位圖。該插圖也顯示了相應圖像的放大視圖。在位圖中,FFFFFF 表示白色,FF0000 表示紅色,00FF00 表示綠色,0000FF 表示藍色。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

圖形檔案格式

用于在磁盤檔案中存儲位圖的标準格式有許多種。GDI+ 支援下面段落中描述的圖形檔案格式。

BMP

BMP 是 Windows 使用的一種标準格式,用于儲存設備無關和應用程式無關的圖像。一個給定 BMP 檔案的每像素位數值(1、4、8、15、24、32 或 64)在檔案頭中指定。每像素 24 位的 BMP 檔案是通用的。BMP 檔案通常不壓縮,是以不太适合通過 Internet 傳輸。

可交換圖像檔案格式 (GIF)

GIF 是一種用于在 Web 頁中顯示圖像的通用格式。GIF 檔案适用于畫線、有純色塊的圖檔和在顔色之間有清晰邊界的圖檔。GIF 檔案是壓縮的,但是在壓縮過程中沒有資訊丢失;解壓縮的圖像與原始圖像完全一樣。GIF 檔案中的一種顔色可以被指定為透明,這樣,圖像将具有顯示它的任何 Web 頁的背景色。在單個檔案中存儲一系列 GIF 圖像可以形成一個動畫 GIF。GIF 檔案每像素最多能存儲 8 位,是以它們隻限于使用 256 種顔色。

聯合攝影專家組 (JPEG)

JPEG 是一種适應于自然景觀(如掃描的照片)的壓縮方案。一些資訊會在壓縮過程中丢失,但是這些丢失人眼是察覺不到的。JPEG 檔案每像素存儲 24 位,是以它們能夠顯示超過 16,000,000 種顔色。JPEG 檔案不支援透明或動畫。

JPEG 圖像中的壓縮級别是可以控制的,但是較高的壓縮級别(較小的檔案)會導緻丢失更多的資訊。對于一幅以 20:1 壓縮比生成的圖像,人眼難以把它和原始圖像差別開來。下面的插圖顯示了一幅 BMP 圖像和用這幅 BMP 圖像壓縮而得的兩幅 JPEG 圖像。第一幅 JPEG 的壓縮比是 4:1,第二幅 JPEG 的壓縮比是 8:1。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

JPEG 壓縮不适用于線條圖形、純色塊和清晰邊界。下面的插圖顯示了一幅 BMP 圖像,以及兩幅 JPEG 圖像和一幅 GIF 圖像。JPEG 和 GIF 圖像從 BMP 圖像壓縮而得。GIF 的壓縮比是 4:1,較小 JPEG 的壓縮比是 4:1,較大 JPEG 的壓縮比是 8:3。請注意,GIF 圖像沿線條保持着清晰的邊界,但 JPEG 圖像的邊界處則有些模糊。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

JPEG 是一種壓縮方案,不是一種檔案格式。"JPEG 檔案交換格式 (JFIF)"是一種檔案格式,常用于存儲和傳輸已根據 JPEG 方案壓縮的圖像。Web 浏覽器顯示的 JFIF 檔案使用 .jpg 擴充名。

可交換圖像檔案 (EXIF)

EXIF 是一種适用于數位相機拍攝的照片的檔案格式。EXIF 檔案中含有根據 JPEG 規格壓縮的圖像。EXIF 檔案中還包含了有關照片的資訊(拍攝日期、快門速度、曝光時間,等等)和相機資訊(制造商、型号,等等)。

可移植網絡圖形 (PNG)

PNG 格式不但保留了許多 GIF 格式的優點,還提供了超出 GIF 的功能。像 GIF 檔案一樣,PNG 檔案在壓縮時也不損失資訊。PNG 檔案能以每像素 8、24 或 48 位來存儲顔色,并以每像素 1、2、4、8 或 16 位來存儲灰階。相比之下,GIF 檔案隻能使用每像素 1、2、4 或 8 位。PNG 檔案還可為每個像素存儲一個 alpha 值,該值指定了該像素顔色與背景顔色混合的程度。

PNG 優于 GIF 之處在于它能夠逐漸顯示一幅圖像,也就是說,當圖像通過網絡連接配接到達時顯示将越來越近似。PNG 檔案可包含伽瑪校正和顔色校正資訊,以便圖像可在各種各樣的顯示裝置上精确地呈現。

标簽圖像檔案格式 (TIFF)

TIFF 是一種靈活的和可擴充的格式,各種各樣的平台和圖像處理應用程式都支援這種格式。TIFF 檔案能以每像素任意位來存儲圖像,并可以使用各種各樣的壓縮算法。單個的多頁 TIFF 檔案可以存儲數幅圖像。可以把與圖像相關的資訊(掃描器制造商、主機、壓縮類型、列印方向和每像素采樣,等等)存儲在檔案中并使用标簽來排列這些資訊。可以根據需要通過準許和添加新标簽來擴充 TIFF 格式。

2.圖元檔案

GDI+ 提供 Metafile 類,以便您能夠記錄和顯示圖元檔案。圖元檔案,也稱為矢量圖像,是一種存儲為一系列繪圖指令和設定的圖像。Metafile 對象記錄的指令和設定可以存儲在記憶體中或儲存到檔案或流。

GDI+ 能夠顯示用以下格式存儲的圖元檔案:

  • Windows 圖元檔案 (WMF)
  • 增強性圖元檔案 (EMF)
  • EMF+

GDI+ 能夠用 EMF 和 EMF+ 格式記錄圖元檔案,但不能使用 WMF 格式。

EMF+ 是 EMF 的擴充,可存儲 GDI+ 記錄。EMF+ 格式有兩種變體:"EMF+ 唯一"和"EMF+ 雙重"。"EMF+ 唯一"圖元檔案隻包含 GDI+ 記錄。這樣的圖元檔案可由 GDI+ 顯示,但不可由 GDI 顯示。"EMF+ 雙重"圖元檔案包含 GDI+ 和 GDI 記錄。"EMF+ 雙重"圖元檔案的每個 GDI+ 記錄與一個備用 GDI 記錄成對出現。這樣的圖元檔案可由 GDI+ 或 GDI 顯示。

下面的示例顯示了一個以前另存為檔案的圖元檔案。該圖元檔案在顯示時,左上角的位置是 (100,100)。

myMetafile = new Metafile(L"MyDiskFile.emf", hdc);

           
myGraphics = new Graphics(myMetafile);

           
myPen = new Pen(Color(255, 0, 0, 200));

           
myGraphics->SetSmoothingMode(SmoothingModeAntiAlias);

           
myGraphics->DrawLine(myPen, 0, 0, 60, 40);

           
delete myGraphics;

           
delete myPen;

           
delete myMetafile;

           

3.繪制、定位和克隆圖像

您可以使用 Bitmap 類來加載和顯示光栅圖像,還可以利用 Metafile 類來加載和顯示矢量圖像。Bitmap 和 Metafile 類從 Image 類中繼承。要顯示矢量圖像,需要有 Graphics 對象和 Metafile 對象。要顯示光栅圖像,需要有 Graphics 對象和 Bitmap 對象。Graphics 對象提供了 DrawImage 方法,該方法接收 Metafile 或 Bitmap 對象作為參數。

下面的示例從檔案 Climber.jpg 構造 Bitmap 對象并顯示位圖。圖像左上角的目标點 (10,10) 在第二個和第三個參數中指定。

Image myImage(L"Climber.jpg");

           
myGraphics.DrawImage(&myImage, 10, 10);

           

下面的插圖顯示了該圖像。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

您可以從各種各樣的圖形檔案格式(BMP、GIF、JPEG、EXIF、PNG、TIFF 和 ICON)中構造 Bitmap 對象。

下面的示例從各種各樣的檔案類型中構造 Bitmap 對象,然後顯示位圖:

Image myBMP(L"SpaceCadet.bmp");

           
Image myEMF(L"Metafile1.emf");

           
Image myGIF(L"Soda.gif");

           
Image myJPEG(L"Mango.jpg");

           
Image myPNG(L"Flowers.png");

           
Image myTIFF(L"MS.tif");

           
myGraphics.DrawImage(&myBMP, 10, 10);

           
myGraphics.DrawImage(&myEMF, 220, 10);

           
myGraphics.DrawImage(&myGIF, 320, 10);

           
myGraphics.DrawImage(&myJPEG, 380, 10);

           
myGraphics.DrawImage(&myPNG, 150, 200);

           
myGraphics.DrawImage(&myTIFF, 300, 200);

           

Bitmap 類提供了 Clone 方法,可用于制作現有 Bitmap 對象的副本。Clone 方法帶有源矩形參數,可用于指定要複制的原始位圖的部分。下面的示例通過克隆現有 Bitmap 對象的上半部分來建立 Bitmap 對象。然後繪制兩幅圖像。

Bitmap* originalBitmap = new Bitmap(L"Spiral.png");

           
RectF sourceRect(

           
0.0f,

           
0.0f, 

           
(REAL)(originalBitmap->GetWidth()), 

           
(REAL)(originalBitmap->GetHeight())/2.0f);

           
Bitmap* secondBitmap = originalBitmap->Clone(sourceRect, PixelFormatDontCare);

           
myGraphics.DrawImage(originalBitmap, 10, 10);

           
myGraphics.DrawImage(secondBitmap, 100, 10);

           

下面的插圖顯示這兩幅圖像。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

4. 裁切和縮放圖像

您可以使用 Graphics 類的 DrawImage 方法來繪制并定位矢量圖像和光栅圖像。DrawImage 是一種重載方法,是以您有數種方式為它提供參數。DrawImage 方法的一種變體接收 Bitmap 對象和 Rectangle 對象。該矩形指定了繪圖操作的目标,即它指定了将要在其内繪圖的矩形。如果目标矩形的大小與原始圖像的大小不同,原始圖像将進行縮放,以适應目标矩形。下面的示例将同一圖像繪制了三次:一次沒有縮放,一次使用擴充,一次使用壓縮:

Bitmap myBitmap(L"Spiral.png");

           
Rect expansionRect(80, 10, 2 * myBitmap.GetWidth(), myBitmap.GetHeight());

           
Rect compressionRect(210, 10, myBitmap.GetWidth() / 2, 

           
myBitmap.GetHeight() / 2);

           
myGraphics.DrawImage(&myBitmap, 10, 10);

           
myGraphics.DrawImage(&myBitmap, expansionRect);

           
myGraphics.DrawImage(&myBitmap, compressionRect);

           

下面的插圖顯示了這三張圖檔。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

DrawImage 方法的一些變體帶有源矩形參數和目标矩形參數。源矩形參數指定原始圖像要繪制的部分。目标矩形參數指定将要在其内繪制該圖像指定部分的矩形。如果目标矩形的大小與源矩形的大小不同,圖檔将會縮放,以适應目标矩形。

下面的示例從檔案 Runner.jpg 中構造 Bitmap 對象。整個圖像繪制時在 (0,0) 處沒有縮放。然後将該圖像的一小部分繪制兩次:一次使用壓縮,一次使用擴充。

Bitmap myBitmap(L"Runner.jpg"); 
				
           
// The rectangle (in myBitmap) with upper-left corner (80, 70), 

           
// width 80, and height 45, encloses one of the runner's hands.

           
// Small destination rectangle for compressed hand.
					
           
Rect destRect1(200, 10, 20, 16);
				
           
// Large destination rectangle for expanded hand.
					
           
Rect destRect2(200, 40, 200, 160);
				
           
// Draw the original image at (0, 0).
					
           
myGraphics.DrawImage(&myBitmap, 0, 0);
				
           
// Draw the compressed hand.
					
           
myGraphics.DrawImage(

           
&myBitmap, destRect1, 80, 70, 80, 45, UnitPixel);
				
           
// Draw the expanded hand. 
					
           
myGraphics.DrawImage(

           
&myBitmap, destRect2, 80, 70, 80, 45, UnitPixel);

           
myBitmap, destRectangle2, sourceRectangle, GraphicsUnit.Pixel);

           

下面的插圖顯示了未縮放的圖像,以及壓縮的和擴充的圖像部分。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

坐标系統和變形

--------------------------------------------------------------------------------

GDI+ 提供了全局變形和頁面變形,以便您可以使繪制的項目變形(旋轉、縮放、平移,等等)。兩種變形還允許您使用多種坐标系統。

1. 坐标系統類型

GDI+ 使用三個坐标空間:全局、頁面和裝置。

進行 myGraphics.DrawLine(myPen, 0, 0, 160, 80) 調用時,傳遞到 DrawLine 方法的點((0, 0) 和 (160, 80))位于全局坐标空間中。坐标先要通過變形序列,然後 GDI+ 才能在螢幕上繪制線條。一種變形将全局坐标轉換為頁面坐标,另一種變形将頁面坐标轉換為裝置坐标。

假定您想使用原點位于工作區的主體而非左上角的坐标系統。例如,您需要讓原點位于距工作區左邊緣 100 像素、距頂部 50 像素的位置。下圖顯示了這樣的坐标系統。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

進行 myGraphics.DrawLine(myPen, 0, 0, 160, 80) 調用時,可獲得下面插圖中顯示的線條。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

下表顯示了三種坐标空間中線條終點的坐标:

全局 (0, 0) 到 (160, 80)
(100, 50) 到 (260, 130)
裝置 (100, 50) 到 (260, 130)

請注意,頁面坐标空間的原點在工作區的左上角,情況将總是如此。另外請注意,由于度量機關是像素,是以裝置坐标與頁面坐标是相同的。如果将度量機關設定為像素以外的其他機關(例如英寸),裝置坐标将不同于頁面坐标。

将全局坐标映射到頁面坐标的變形稱為"全局變形",儲存在 Graphics 類的 Transform 屬性中。在前面的示例中,全局變形是在 x 方向平移 100 個機關、在 y 方向平移 50 個機關。下面的示例設定了 Graphics 對象的全局變形,并随後使用該 Graphics 對象來繪制前圖中顯示的線條:

myGraphics.TranslateTransform(100.0f, 50.0f);

           
myGraphics.DrawLine(&myPen, 0, 0, 160, 80);
				
           

将頁面坐标映射到裝置坐标的變形稱為"頁面變形"。Graphics 類提供了用于操作頁面變形的 PageUnit 和 PageScale 屬性。Graphics 類還提供了兩個隻讀屬性:DpiX 和 DpiY,可用于檢查顯示裝置每英寸的水準點和垂直點。

Graphics 類的 PageUnit 屬性可用于指定像素以外的其他度量機關。下面的示例從 (0, 0) 至 (2, 1) 繪制線條,其中點 (2, 1) 位于點 (0, 0) 的右邊 2 英寸和下邊 1 英寸處:

myGraphics.SetPageUnit(UnitInch);

           
myGraphics.DrawLine(&myPen, 0, 0, 2, 1);
				
           

注意   如果您在構造鋼筆時不指定鋼筆寬度,前面的示例将繪制一條一英寸寬的線條。您可以在 Pen 構造函數的第二個參數中指定鋼筆寬度:

Pen myPen(Color(255, 0, 0, 0), 1/myGraphics.GetDpiX()).

           

如果我們假定顯示裝置在水準方向和垂直方向每英寸都有 96 個點,則上例中直線的終結點在三個坐标空間中分别具有以下坐标:

全局 (0, 0) 到 (2, 1)
(0, 0) 到 (2, 1)
裝置 (0, 0) 到 (192, 96)

請注意,由于全局坐标空間的原點在工作區的左上角,是以頁面坐标與全局坐标相同。

您可以合并全局變形和頁面變形,以實作多種效果。例如,假定您想使用英寸作為度量機關,并且想讓坐标系統的原點距工作區左邊緣 2 英寸、距工作區頂部 1/2 英寸。下面的示例設定 Graphics 對象的全局變形和頁面變形,然後從 (0, 0) 到 (2, 1) 繪制線條:

myGraphics.TranslateTransform(2.0f, 0.5f);

           
myGraphics.SetPageUnit(UnitInch);

           
myGraphics.DrawLine(&myPen, 0, 0, 2, 1);

           

下圖顯示了線條和坐标系統。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

如果我們假定顯示裝置在水準方向和垂直方向每英寸都有 96 個點,則上例中直線的終結點在三個坐标空間中分别具有以下坐标:

全局 (0, 0) 到 (2, 1)
(2, 0.5) 到 (4, 1.5)
裝置 (192, 48) 到 (384, 144)

2.變形的矩陣表示形式

m×n 矩陣是以 m 行和 n 列排列的一組數字。下圖顯示幾個矩陣。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

您可以通過将單個元素相加來加合兩個尺寸相同的矩陣。下圖顯示了兩個矩陣相加的示例。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

m×n 矩陣可以與 n×p 矩陣相乘,得到的結果是 m×p 矩陣。第一個矩陣的列數必須與第二個矩陣的行數相同。例如,4×2 矩陣可與 2×3 矩陣相乘,産生 4×3 矩陣。

矩陣的行列的平面點可視為矢量。例如,(2, 5) 是具有兩個元件的矢量,(3, 7, 1) 是具有三個元件的矢量。兩個矢量的點産品定義如下:

(a, b) • (c, d) = ac + bd

(a, b, c) • (d, e, f) = ad + be + cf

例如,(2, 3) 和 (5, 4) 的點産品是 (2)(5) + (3)(4) = 22。(2, 5, 1) 和 (4, 3, 1) 的點産品是 (2)(4) + (5)(3) + (1)(1) = 24。請注意,兩個矢量的點産品是數字,而不是另一個矢量。另外請注意,隻有當兩個矢量的元件數相同時,才能計算點産品。

将 A(i, j) 作為矩陣 A 中第 i 行和第 j 列的項。例如,A(3, 2)是矩陣 A 中第 3 行和第 2 列的項。假定 A、B 和 C 是矩陣,且 AB = C,則 C 的項計算如下:

C(i, j) =(A 的第 i 行)•(B 的第 j 列)

下圖顯示了矩陣相乘的幾個示例。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

如果您将平面中的點視為 1×2 矩陣,則可通過将該點乘以 2×2 矩陣來變形該點。下圖顯示了應用于點 (2, 1) 的幾個變形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

前圖中顯示的所有變形都是線性變形。某些其他變形(例如平移)不是線性的,也不能表示為與 2×2 矩陣相乘的形式。假定您要從點 (2, 1) 開始,将其旋轉 90 度,在 x 方向将其平移 3 個機關,在 y 方向将其平移 4 個機關。可通過先使用矩陣乘法再使用矩陣加法來完成此操作。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

後面是平移(與 1×2 矩陣相加)的線性變形(與 2×2 矩陣相乘)被稱為仿射變形。将仿射變形存儲于一對矩陣(一個用于線性部分,一個用于平移)的替換方案是将整個變形存儲于 3×3 矩陣。要使其起作用,平面上的點必須存儲于有虛拟第 3 坐标的 1×3 矩陣。通常的技術是使所有的第 3 坐标等于 1。例如,矩陣 [2 1 1] 代表點 (2, 1)。下圖顯示了表示為與單個 3×3 矩陣相乘的仿射變形(旋轉 90 度;在 x 方向上平移 3 個機關,在 y 方向上平移 4 個機關)。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

在前面的示例中,點 (2, 1) 映射到了點 (2, 6)。請注意,3×3 矩陣的第三列包含數字 0, 0, 1。對于仿射變形的 3×3 矩陣而言,情況将總是如此。重要的數字是列 1 和列 2 中的 6 個數字。矩陣左上角的 2×2 部分表示變形的線性部分,第 3 行中的前兩項表示平移。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

在 GDI+ 中,您可以在 Matrix 對象中存儲仿射變形。由于表示仿射變形的矩陣第三列總是(0, 0, 1),是以建構 Matrix 對象時,隻需指定前兩列中的 6 個數字。語句 Matrix myMatrix = new Matrix(0, 1, -1, 0, 3, 4) 建構了前圖中顯示的矩陣。

複合變形

複合變形是一個接一個的變形序列。請考慮下面清單中的矩陣和變形:

矩陣 A 旋轉 90 度
矩陣 B 在 x 方向上縮放 2 倍
矩陣 C 在 y 方向上平移 3 個機關

如果我們從矩陣 [2 1 1] 表示的點 (2, 1) 開始,并先後乘以 A、B、C,則點 (2, 1) 将按列出的順序經曆三種變形。

[2 1 1]ABC = [-2 5 1]

您可以不将複合變形的三部分存儲于三個單獨的矩陣,而是一起乘以 A、B 和 C,得到一個存儲整個複合變形的單獨的 3×3 矩陣。假定 ABC = D。則一個點乘以 D 得出的結果與一個點先後乘以 A、B、C 的結果相同。

[2 1 1]D = [-2 5 1]

下圖顯示了矩陣 A、B、C 和 D。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

複合變形的矩陣可通過單個變形矩陣相乘來形成,這就意味着任何仿射變形的序列均可存儲于一個單獨的 Matrix 對象中。

警告   複合變形的順序非常重要。一般說來,先旋轉、再縮放、然後平移,與先縮放、再旋轉、然後平移是不同的。同樣,矩陣相乘的順序也是重要的。一般說來,ABC 與 BAC 不同。

Matrix 類提供了建立複合變形的幾種方法:Multiply、Rotate、RotateAt、Scale、Shear 和 Translate。下面的示例建立了複合變形(先旋轉 30 度,再在 y 方向上縮放 2 倍,然後在 x 方向平移 5 個機關)的矩陣。

Matrix myMatrix;

           
myMatrix.Rotate(30.0f);

           
myMatrix.Scale(1.0f, 2.0f, MatrixOrderAppend);

           
myMatrix.Translate(5.0f, 0.0f, MatrixOrderAppend);

           

下圖顯示該矩陣。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

3.全局變形和局部變形

全局變形是應用于由給定的 Graphics 對象繪制的每個項目的變形。要建立全局變形,可建構 Graphics 對象,然後操作其 Transform 屬性。Transform 屬性是 Matrix 對象,是以它能夠儲存仿射變形的任何序列。存儲在 Transform 屬性中的變形被稱為全局變形。Graphics 類提供了建立複合全局變形的幾種方法:MultiplyTransform、RotateTransform、ScaleTransform 和 TranslateTransform。下面的示例繪制了兩次橢圓:一次在建立全局變形之前,一次在建立全局變形之後。變形首先在 y 方向上縮放 0.5 倍,再在 x 方向平移 50 個機關,然後旋轉 30 度。

myGraphics.DrawEllipse(&myPen, 0, 0, 100, 50);

           
myGraphics.ScaleTransform(1.0f, 0.5f);

           
myGraphics.TranslateTransform(50.0f, 0.0f, MatrixOrderAppend);

           
myGraphics.RotateTransform(30.0f, MatrixOrderAppend);

           
myGraphics.DrawEllipse(&myPen, 0, 0, 100, 50);

           

下圖顯示了變形中涉及的矩陣。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

注意   在前面的示例中,橢圓圍繞坐标系統的原點旋轉,該原點在工作區的左上角。與橢圓圍繞其自身中心旋轉相比,這樣會産生不同的結果。

局部變形是應用于要繪制的特定項目的變形。例如,GraphicsPath 對象具有 Transform 方法,此方法可用于将該路徑的資料點變形。下面的示例繪制了一個沒有變形的矩形以及一個有旋轉變形的路徑。(假定沒有全局變形)。

Matrix myMatrix;

           
myMatrix.Rotate(45.0f);

           
myGraphicsPath.Transform(&myMatrix);

           
myGraphics.DrawRectangle(&myPen, 10, 10, 100, 50);

           
myGraphics.DrawPath(&myPen, &myGraphicsPath);

           

全局變形可與局部變形合并,以得到多種結果。例如,全局變形可用于修正坐标系統,而局部變形可用于旋轉和縮放在新坐标系統上繪制的對象。

假定您需要原點距工作區左邊緣 200 像素、距工作區頂部 150 像素的坐标系統。此外,假定您需要的度量機關是像素,且 x 軸指向右方,y 軸指向上方。預設的坐标系統是 y 軸指向下方,是以您需要執行繞水準坐标軸的反射。下圖顯示了這樣的矩陣反射。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

下一步,假定您需要執行一個向右 200 個機關、向下 150 個機關的平移。

下面的示例建立通過設定 Graphics 對象的全局變形來描述的坐标系統。

Matrix myMatrix(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);

           
myGraphics.SetTransform(&myMatrix);

           
myGraphics.TranslateTransform(200.0f, 150.0f, MatrixOrderAppend);

           

下面的代碼(置于前面示例的結尾處)建立了由一個單獨矩形組成的路徑,該矩形的左下角在新坐标系統的原點。矩形經過兩次填充:一次不使用局部變形,一次使用局部變形。局部變形包括在水準方向上縮放 2 倍,然後再旋轉 30 度。

// Create the path.

           
GraphicsPath myGraphicsPath;

           
Rect myRect(0, 0, 60, 60);

           
myGraphicsPath.AddRectangle(myRect);

           
// Fill the path on the new coordinate system.

           
// No local transformation

           
myGraphics.FillPath(&mySolidBrush1, &myGraphicsPath);

           
// Transform the path.

           
Matrix myPathMatrix;

           
myPathMatrix.Scale(2, 1);

           
myPathMatrix.Rotate(30, MatrixOrderAppend);

           
myGraphicsPath.Transform(&myPathMatrix);

           
// Fill the transformed path on the new coordinate system.
				
           
myGraphics.FillPath(&mySolidBrush2, &myGraphicsPath);
				
           

下圖顯示了新的坐标系統和兩個矩形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

圖形容器

--------------------------------------------------------------------------------

圖形狀态(剪輯區域、變形和品質設定)存儲在 Graphics 對象中。GDI+ 允許您通過使用容器來臨時替換或增加 Graphics 對象中狀态的組成部分。您可以通過調用 Graphics 對象的 BeginContainer 方法來啟動容器,通過調用 EndContainer 方法來結束容器。在 BeginContainer 和 EndContainer 之間,您對 Graphics 對象做出的任何狀态更改都屬于容器,且不改寫 Graphics 對象的現有狀态。

下面的示例在 Graphics 對象中建立容器。Graphics 對象的全局變形是向右平移 200 個機關,而容器的全局變形是向下平移 100 個機關。

myGraphics.TranslateTransform(200.0f, 0.0f);

           
myGraphicsContainer = myGraphics.BeginContainer();

           
myGraphics.TranslateTransform(0.0f, 100.0f);

           
myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);

           
myGraphics.EndContainer(myGraphicsContainer);

           
myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);

           

請注意,在前面的示例中,在調用 BeginContainer 和 EndContainer 之間執行語句 myGraphics.DrawRectangle(0, 0, 50, 50) 與在調用 EndContainer 之後執行同一語句,會産生不同的矩形。隻有水準變形應用于在容器外做出的 DrawRectangle 調用。兩種變形(橫向平移 200 個機關及縱向平移 100 個機關)都應用于在容器内進行的 DrawRectangle 調用。下面的插圖顯示這兩個矩形。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

容器可以嵌套在另一容器中。下面的示例在 Graphics 對象中建立容器,并在第一個容器中建立另一容器。Graphics 對象的全局變換是在 x 方向平移 100 個機關,在 y 方向平移 80 個機關。第一個容器的全局變形是旋轉 30 度。第二個容器的全局變形是在 x 方向縮放 2 倍。對 DrawEllipse 方法的調用是在第二個容器内做出的。

myGraphics.TranslateTransform(100.0f, 80.0f, MatrixOrderAppend);

           
container1 = myGraphics.BeginContainer();

           
myGraphics.RotateTransform(30.0f, MatrixOrderAppend);

           
container2 = myGraphics.BeginContainer();

           
myGraphics.ScaleTransform(2.0f, 1.0f);

           
myGraphics.DrawEllipse(&myPen, -30, -20, 60, 40);

           
myGraphics.EndContainer(container2);

           
myGraphics.EndContainer(container1);

           

下圖顯示了該橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

請注意,所有三種變形都應用于在第二個容器内做出的 DrawEllipse 調用。另外請注意變形的順序:先縮放,再旋轉,然後平移。最先應用最裡面的變形,最後應用最外面的變形。

Graphics 對象的任何屬性均可在容器内(對 BeginContainer 和 EndContainer 的調用之間)設定。例如,可在容器内設定剪輯區域。在容器内完成的任何繪圖都将受制于該容器的剪輯區域,并将受制于任何外部容器的剪輯區域和 Graphics 對象自身的剪輯區域。

迄今為止所讨論的屬性(全局變形和剪輯區域)由嵌套的容器聯合在一起。嵌套的容器可臨時替換其他屬性。例如,如果在容器内将 SmoothingMode 屬性設為 SmoothingMode.AntiAlias,那麼在該容器内調用的任何繪圖方法就都将使用 AntiAlias 平滑模式,但在 EndContainer 之後調用的繪圖方法将使用在調用 BeginContainer 之前就位的平滑模式。

對于将 Graphics 對象的全局變形與容器合并的另一示例:假定您要繪制一隻眼睛并将其置于面孔序列上的各種位置。下面的示例以坐标系統原點為中心繪制了一隻眼睛:

void DrawEye(Graphics* pGraphics)

           
{

           
GraphicsContainer eyeContainer;   

           
eyeContainer = pGraphics->BeginContainer();

           
Pen myBlackPen(Color(255, 0, 0, 0));

           
SolidBrush myGreenBrush(Color(255, 0, 128, 0));

           
SolidBrush myBlackBrush(Color(255, 0, 0, 0));

           
GraphicsPath myTopPath;

           
myTopPath.AddEllipse(-30, -50, 60, 60);

           
GraphicsPath myBottomPath;

           
myBottomPath.AddEllipse(-30, -10, 60, 60);

           
Region myTopRegion(&myTopPath);

           
Region myBottomRegion(&myBottomPath);

           
// Draw the outline of the eye.

           
// The outline of the eye consists of two ellipses.

           
// The top ellipse is clipped by the bottom ellipse, and

           
// the bottom ellipse is clipped by the top ellipse.

           
pGraphics->SetClip(&myTopRegion);

           
pGraphics->DrawPath(&myBlackPen, &myBottomPath);

           
pGraphics->SetClip(&myBottomRegion);

           
pGraphics->DrawPath(&myBlackPen, &myTopPath);

           
// Fill the iris.

           
// The iris is clipped by the bottom ellipse.

           
pGraphics->FillEllipse(&myGreenBrush, -10, -15, 20, 22);

           
// Fill the pupil.

           
pGraphics->FillEllipse(&myBlackBrush, -3, -7, 6, 9);

           
pGraphics->EndContainer(eyeContainer);

           
} 

           

下圖顯示了眼睛和坐标軸。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

前面示例中的 DrawEye 函數可接收 Graphics 對象,并立即在該 Graphics 對象中建立容器。此容器将任何調用 DrawEye 函數的代碼與在執行 DrawEye 函數期間做出的屬性設定隔離開來。例如,DrawEye 函數中的代碼設定 Graphics 對象的剪輯區域,但當 DrawEye 将控件傳回到調用例程時,剪輯區域将和它在調用 DrawEye 之前的狀态一樣。

下面的示例繪制三個橢圓(面孔),每個裡面都有一隻眼睛:

// Draw an ellipse with center at (100, 100).

           
myGraphics.TranslateTransform(100.0f, 100.0f);

           
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

           
// Draw the eye at the center of the ellipse.

           
DrawEye(&myGraphics);

           
// Draw an ellipse with center at 200, 100.

           
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);

           
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

           
// Rotate the eye 40 degrees, and draw it 30 units above

           
// the center of the ellipse.

           
myGraphicsContainer = myGraphics.BeginContainer();

           
myGraphics.RotateTransform(-40.0f);

           
myGraphics.TranslateTransform(0.0f, -30.0f, MatrixOrderAppend);

           
DrawEye(&myGraphics);

           
myGraphics.EndContainer(myGraphicsContainer);
					
           
// Draw a ellipse with center at (300.0f, 100.0f).

           
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);

           
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

           
// Stretch and rotate the eye, and draw it at the 

           
// center of the ellipse.

           
myGraphicsContainer = myGraphics.BeginContainer();

           
myGraphics.ScaleTransform(2.0f, 1.5f);

           
myGraphics.RotateTransform(45.0f, MatrixOrderAppend);

           
DrawEye(&myGraphics);

           
myGraphics.EndContainer(myGraphicsContainer); myGraphics.EndContainer(myGraphicsContainer);

           

下圖顯示了這三個橢圓。

VC下如何使用GDI+進行圖像程式設計GDI+介紹 GDI+的新增特性? 直線、曲線和圖形 圖像、位圖和圖元檔案 坐标系統和變形 圖形容器

在前面的示例中,所有的橢圓都是調用 DrawEllipse(myBlackPen, -40, -60, 80, 120) 來繪制的,此調用以坐标系統的原點為中心繪制橢圓。通過設定 Graphics 對象的全局變形,将橢圓從工作區左上角移開。語句 myGraphics.TranslateTransform(100, 100) 使第一個橢圓以 (100, 100) 為中心。語句 myGraphics.TranslateTransform(100, 0) 使第二個橢圓的中心在第一個橢圓的中心右邊 100 個機關處。同樣,第三個橢圓的中心在第二個橢圓的中心右邊 100 個機關處。

前面示例中的容器用于相對給定橢圓的中心來變形眼睛。第一隻眼睛在橢圓中心處繪制,沒有變形,是以不在容器中調用 DrawEye。第二隻眼睛旋轉 40 度并在橢圓中心上方 30 個機關處繪制,是以在容器内調用 DrawEye 函數和設定變形的方法。第三隻眼睛經過拉伸和旋轉,并在橢圓中心處繪制。像處理第二隻眼睛一樣,在容器内調用 DrawEye 函數和設定變形的方法。

繼續閱讀