Patterns
模式是重復繪制到圖形上下文的一系列繪圖操作。你可以像使用顏色一樣使用圖案。當您使用模式進行繪制時,Quartz將頁面劃分為一組模式單元格,每個單元格的大小與模式圖像相同,并且使用您提供的回調來繪制每個單元格。圖6-1顯示了繪制到窗口圖形上下文的模式。
The Anatomy of a Pattern
模式單元是模式的基本組件。圖6-1所示模式的模式單元如圖6-2所示。黑色矩形不是圖案的一部分;它的繪制目的是顯示模式單元格的結束位置。這個特定模式單元格的大小包括四個彩色矩形的面積和矩形上方和右側的空間,如圖6-3所示。圖中每個圖案單元格周圍的黑色矩形不是單元格的一部分;它表示單元格的邊界。創建模式單元格時,定義單元格的界限并在界限內繪制。
您可以指定在水平和垂直方向上,Quartz從每個模式單元的開始繪制到下一個單元的距離。繪制圖6-3中的模式單元,使一個模式單元的開始與下一個模式單元的開始完全是一個模式寬度,從而導致每個模式單元鄰接下一個模式單元。圖6-4中的模式單元在水平方向和垂直方向上都增加了空間??梢詾槊總€方向指定不同的間距值。如果間距小于模式單元格的寬度或高度,模式單元格就會重疊。
繪制模式單元時,Quartz使用模式空間作為坐標系統。模式空間是一個抽象空間,它通過創建模式矩陣時指定的轉換矩陣映射到默認用戶空間。
注意:模式空間與用戶空間是分開的。未轉換的模式空間映射到基本(未轉換)用戶空間,而不考慮當前轉換矩陣的狀態。當您對模式空間應用轉換時,Quartz只對模式空間應用轉換。
模式坐標系統的默認約定是基礎圖形上下文的約定。默認情況下,Quartz使用一個坐標系,其中正值x表示向右的位移,正值y表示向上的位移。然而,UIKit創建的圖形上下文使用不同的約定,其中正值y表示向下位移。雖然這種約定通常通過將轉換連接到坐標系統來應用于圖形上下文,但是在本例中,Quartz還修改了模式空間的默認約定來匹配。
如果不希望Quartz轉換模式單元格,可以指定單位矩陣。然而,您可以通過提供一個轉換矩陣來實現有趣的效果。圖6-5顯示了縮放模式單元的效果,如圖6-2所示。圖6-6顯示了模式單元格的旋轉。轉換模式單元格要微妙一些。圖6-7顯示了模式的起源,模式單元在水平方向和垂直方向都進行了翻譯,因此模式不再像圖6-1那樣與窗口相連。
Colored Patterns and Stencil (Uncolored) Patterns
彩色圖案有與之相關的固有顏色。改變用于創建模式單元格的顏色,模式就失去了意義。蘇格蘭格子呢(如圖6-8所示的樣品)是彩色圖案的一個例子。彩色模式中的顏色被指定為模式單元創建過程的一部分,而不是模式繪圖過程的一部分.
其他的圖案完全是根據它們的形狀來定義的,因此,可以把它們看作是蠟紙圖案、沒有顏色的圖案,甚至是圖像蒙版。圖6-9所示的紅色和黑色恒星是相同模式單元的每個表示。細胞本身由一個形狀組成——一個充滿恒星。在定義模式單元格時,沒有與之關聯的顏色。顏色被指定為圖案繪制過程的一部分,而不是圖案單元創建的一部分。
您可以在Quartz 2D中創建圖案顏色或模板。
Tiling
平鋪是將模式單元格渲染到頁面的一部分的過程。當Quartz向設備呈現模式時,Quartz可能需要調整模式以適應設備空間。也就是說,在用戶空間中定義的模式單元在呈現給設備時可能不太適合,因為用戶空間單元和設備像素之間存在差異。
石英有三個瓷磚選擇,它可以用來調整模式,在必要時。石英可以保存:
1、這種模式,以稍微調整模式單元格之間的間距為代價,但不超過一個設備像素。這被稱為無失真。
2、單元格之間的間距,以稍微扭曲模式單元格為代價,但不超過一個設備像素。這被稱為恒定間距與最小失真。
3、單元格之間的間隔(對于最小失真選項)以盡可能多地扭曲模式單元格來獲得快速平鋪為代價。這被稱為常數間距。
How Patterns Work
模式的操作與顏色類似,您可以設置一個填充或筆畫模式,然后調用一個繪畫函數。Quartz使用您設置的模式作為“油漆”。例如,如果你想用純色繪制一個填充矩形,你首先調用一個函數,比如CGContextSetFillColor來設置填充顏色。然后調用函數CGContextFillRect,用指定的顏色繪制填充矩形。要使用模式進行繪制,首先調用函數CGContextSetFillPattern來設置模式。然后調用CGContextFillRect,實際使用指定的模式繪制填充矩形。用顏色畫和用圖案畫的區別在于你必須定義圖案。您可以向CGContextSetFillPattern函數提供模式和顏色信息。您將看到如何在繪畫中創建、設置和繪制模式、彩色模式和繪畫模板模式。
下面是Quartz如何在幕后使用您提供的模式進行繪制的示例。當您使用模式填充或描邊時,Quartz概念性地執行以下任務來繪制每個模式單元格:
1、保存圖形狀態。
2、將當前變換矩陣轉換為模式單元格的原點。
3、將CTM與模式矩陣連接起來。
4、剪輯到模式單元格的邊框。
5、調用繪圖回調來繪制模式單元格。
6、恢復圖像的狀態。
Quartz會為您處理所有的平鋪,不斷地將圖案單元渲染到繪圖空間,直到整個空間都被繪制出來。你可以用圖案填充或描邊。模式單元格可以是您指定的任何大小。如果您想要查看模式,您應該確保模式單元格適合繪圖空間。例如,如果您的模式單元格是8個單位乘10個單位,并且您使用模式來描出寬度為2個單位的線,那么模式單元格將被裁剪,因為它是10個單位寬。在這種情況下,您可能無法識別模式。
Painting Colored Patterns
畫彩色圖案需要執行的五個步驟如下所示:
1、編寫一個繪制彩色模式單元格的回調函數
2、設置彩色圖案的顏色空間
3、建立彩色圖案的解剖結構
4、將彩色模式指定為填充模式或筆畫模式
5、用彩色圖案畫畫
這些步驟與您繪制模具圖案的步驟相同。兩者的區別在于如何設置顏色信息。您可以看到所有的步驟如何配合在一個完整的彩色圖案繪畫功能。
Write a Callback Function That Draws a Colored Pattern Cell
模式單元格的外觀完全取決于您。對于這個示例,清單6-1中的代碼繪制了圖6-2所示的模式單元格?;叵胍幌拢J絾卧裰車暮诰€不是單元格的一部分;繪制它是為了顯示模式單元格的邊界大于代碼繪制的矩形。稍后將模式大小指定為Quartz。
您的模式單元格繪制函數是一個回調函數,它遵循以下形式:
typedef void (*CGPatternDrawPatternCallback) (
void *info,
CGContextRef context
);
你可以任意命名你的回調。清單6-1中的一個名為MyDrawColoredPattern?;卣{需要兩個參數:
info,一個指向與模式關聯的私有數據的通用指針。這個參數是可選的;你可以傳遞NULL。傳遞給回調的數據與您稍后創建模式時提供的數據相同。
上下文,用于繪制模式單元格的圖形上下文。
清單6-1中的代碼繪制的模式單元格是任意的。您的代碼繪制適合您創建的模式的任何內容。這些代碼的細節非常重要:
模式大小被聲明。在編寫繪圖代碼時,需要記住模式大小。在這里,大小被聲明為全局的。繪圖函數不專門引用大小,除非在注釋中引用。稍后,您將模式大小指定為Quartz 2D。請看對彩色圖案的解剖。
繪圖函數遵循由CGPatternDrawPatternCallback類型定義定義的原型。
代碼中執行的繪圖設置了顏色,這使其成為彩色模式。
Listing 6-1 A drawing callback that draws a colored pattern cell
#define H_PATTERN_SIZE 16
#define V_PATTERN_SIZE 18
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGFloat subunit = 5; // the pattern cell itself is 16 by 18
CGRect myRect1 = {{0,0}, {subunit, subunit}},
myRect2 = {{subunit, subunit}, {subunit, subunit}},
myRect3 = {{0,subunit}, {subunit, subunit}},
myRect4 = {{subunit,0}, {subunit, subunit}};
CGContextSetRGBFillColor (myContext, 0, 0, 1, 0.5);
CGContextFillRect (myContext, myRect1);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 0.5);
CGContextFillRect (myContext, myRect2);
CGContextSetRGBFillColor (myContext, 0, 1, 0, 0.5);
CGContextFillRect (myContext, myRect3);
CGContextSetRGBFillColor (myContext, .5, 0, .5, 0.5);
CGContextFillRect (myContext, myRect4);
}
Set Up the Colored Pattern Color Space
清單6-1中的代碼使用顏色來繪制模式單元格。通過將基本模式顏色空間設置為NULL,您必須確保使用繪圖例程中使用的顏色繪制Quartz,如清單6-2所示。下面是對每一行代碼的詳細說明。
Listing 6-2 Creating a base pattern color space
CGColorSpaceRef patternSpace;
patternSpace = CGColorSpaceCreatePattern (NULL);// 1
CGContextSetFillColorSpace (myContext, patternSpace);// 2
CGColorSpaceRelease (patternSpace);
下面是代碼的作用:
1、通過調用函數CGColorSpaceCreatePattern,傳遞NULL作為基本顏色空間,創建適合于彩色圖案的圖案顏色空間。
2、將填充顏色空間設置為模式顏色空間。如果您正在繪制模式,請調用CGContextSetStrokeColorSpace。
3、釋放圖案顏色空間。
Set Up the Anatomy of the Colored Pattern
有關模式解剖的信息保存在CGPattern對象中。您可以通過調用函數CGPatternCreate來創建一個CGPattern對象,其原型如清單6-3所示
Listing 6-3 The CGPatternCreate function prototype
CGPatternRef CGPatternCreate ( void *info,
CGRect bounds,
CGAffineTransform matrix,
CGFloat xStep,
CGFloat yStep,
CGPatternTiling tiling,
bool isColored,
const CGPatternCallbacks *callbacks );
info參數是一個指向要傳遞給繪圖回調的數據的指針。這是在Write回調函數中討論的相同指針,該函數繪制彩色模式單元格。
在bounds參數中指定模式單元格的大小。矩陣參數是指定模式矩陣的地方,它將模式坐標系統映射到圖形上下文的默認坐標系統。如果你想用和圖形上下文相同的坐標系來繪制圖案,就使用單位矩陣。xStep和yStep參數指定模式坐標系中單元格之間的水平和垂直間距。請參閱對模式的剖析,以查看關于界限、模式矩陣和間距的信息。
平鋪參數可以是以下三個值之一:
kCGPatternTilingNoDistortion
kCGPatternTilingConstantSpacingMinimalDistortion
kCGPatternTilingConstantSpacing
參見Tiling查看關于Tiling的信息。
isColored參數指定模式單元格是彩色模式(true)還是模板模式(false)。如果在這里傳遞true,則繪圖模式回調將指定模式顏色,并且必須將模式顏色空間設置為彩色模式顏色空間(請參閱設置彩色模式顏色空間)。
傳遞給函數CGPatternCreate的最后一個參數是指向一個CGPatternCallbacks數據結構的指針。這個結構有三個領域:
struct CGPatternCallbacks
{
unsigned int version;
CGPatternDrawPatternCallback drawPattern;
CGPatternReleaseInfoCallback releaseInfo;
};
將version字段設置為0。drawPattern字段是一個指向繪圖回調的指針。releaseInfo字段是在釋放CGPattern對象時調用的回調的指針,用于釋放傳遞給繪圖回調的info參數的存儲。如果沒有在此參數中傳遞任何數據,則將該字段設置為NULL。
Specify the Colored Pattern as a Fill or Stroke Pattern
您可以通過調用適當的函數—cgcontextsetfillpattern或CGContextSetStrokePattern來使用您的模式來填充或描邊。Quartz會使用您的模式進行后續的填充或撫摸。
這些函數都有三個參數:
1、圖形上下文
2、您之前創建的CGPattern對象
3、顏色組件的數組
盡管彩色模式提供了它們自己的顏色,但是您必須傳遞一個alpha值,以便在繪制模式時通知Quartz該模式的整體不透明度。Alpha值可以從1(完全不透明)到0(完全透明)不等。這些代碼行顯示了如何為填充顏色模式設置不透明度的示例。
CGFloat alpha = 1;
CGContextSetFillPattern (myContext, myPattern, &alpha);
Draw With the Colored Pattern
完成前面的步驟后,可以調用繪制的任何Quartz 2D函數。你的圖案被用作“顏料”。例如,您可以調用CGContextStrokePath、CGContextFillPath、CGContextFillRect或任何其他繪制函數。
A Complete Colored Pattern Painting Function
清單6-4中的代碼包含一個繪制彩色模式的函數。該函數包含前面討論的所有步驟。下面是對每一行代碼的詳細說明。
Listing 6-4 A function that paints a colored pattern
void MyColoredPatternPainting (CGContextRef myContext,
CGRect rect)
{
CGPatternRef pattern;// 1
CGColorSpaceRef patternSpace;// 2
CGFloat alpha = 1,// 3
width, height;// 4
static const CGPatternCallbacks callbacks = {0, // 5
&MyDrawPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);// 6
CGContextSetFillColorSpace (myContext, patternSpace);// 7
CGColorSpaceRelease (patternSpace);// 8
pattern = CGPatternCreate (NULL, // 9
CGRectMake (0, 0, H_PSIZE, V_PSIZE),// 10
CGAffineTransformMake (1, 0, 0, 1, 0, 0),// 11
H_PATTERN_SIZE, // 12
V_PATTERN_SIZE, // 13
kCGPatternTilingConstantSpacing,// 14
true, // 15
&callbacks);// 16
CGContextSetFillPattern (myContext, pattern, &alpha);// 17
CGPatternRelease (pattern);// 18
CGContextFillRect (myContext, rect);// 19
CGContextRestoreGState (myContext);
}
下面是代碼的作用:
1、為稍后創建的CGPattern對象聲明存儲。
2、為稍后創建的模式顏色空間聲明存儲。
3、為alpha聲明一個變量,并將其設置為1,這將指定模式的不透明度為完全不透明。
4、聲明變量以保存窗口的高度和寬度。在這個例子中,圖案被繪制在窗口的區域上。
5、聲明并填充回調結構,傳遞0作為版本和一個指向繪圖回調函數的指針。這個示例沒有提供release info回調,因此該字段被設置為NULL。
6、創建一個模式顏色空間對象,將模式的基本顏色空間設置為NULL。當您繪制有顏色的圖案時,圖案在繪圖回調中提供自己的顏色,這就是為什么您將顏色空間設置為NULL。
7、將填充顏色空間設置為剛才創建的模式顏色空間對象。
釋放圖案顏色空間對象。
8、傳遞NULL,因為模式不需要傳遞給繪圖回調的任何額外信息。
9、傳遞指定模式單元格邊界的CGRect對象。
10、傳遞CGAffineTransform矩陣,該矩陣指定如何將模式空間轉換為使用模式的上下文的默認用戶空間。這個例子傳遞單位矩陣。
11、將水平模式大小作為每個單元開始之間的水平位移傳遞。在本例中,一個單元格與下一個單元格相鄰。
12、通過垂直模式大小作為每個單元開始之間的垂直位移。
13、傳遞常量kcgpatterntilingconstant間隔以指定Quartz如何呈現模式。有關更多信息,請參見平鋪。
14、為isColored參數傳遞true,以指定模式是有色模式。
傳遞一個指針到包含版本信息的回調結構,以及一個指向繪圖回調函數的指針。
15、設置填充模式,傳遞上下文、剛剛創建的CGPattern對象和一個指向alpha值的指針,該值指定要將Quartz應用到該模式的不透明度。
16、 釋放CGPattern對象。
17、填充一個矩形,該矩形是傳遞給MyColoredPatternPainting例程的窗口大小。Quartz使用剛才設置的模式填充矩形。
Painting Stencil Patterns
您需要執行的五個步驟來繪制一個鋼網圖案在以下部分描述:
1、編寫一個回調函數來繪制模板單元格
2、設置模板顏色空間
3、建立鋼網圖案的解剖結構
4、將模板模式指定為填充模式或筆畫模式
5、用蠟紙圖案畫畫
這些步驟和你畫彩色圖案的步驟是一樣的。兩者的區別在于如何設置顏色信息。您可以看到所有的步驟如何配合在一個完整的鋼網圖案繪畫功能。
Write a Callback Function That Draws a Stencil Pattern Cell
您為繪制模板模式而編寫的回調與為彩色模式單元格所描述的格式相同。請參閱編寫一個回調函數來繪制彩色模式單元格。唯一的區別是繪圖回調沒有指定任何顏色。圖6-10所示的模式單元格沒有從繪圖回調中獲得顏色。顏色設置在圖案顏色空間的繪圖顏色之外。
看看清單6-5中的代碼,它繪制了圖6-10所示的模式單元格。注意,代碼只是創建一個路徑并填充路徑。代碼沒有設置顏色。
Listing 6-5 A drawing callback that draws a stencil pattern cell
#define PSIZE 16 // size of the pattern cell
static void MyDrawStencilStar (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextFillPath(myContext);
}
Set Up the Stencil Pattern Color Space
模板模式要求您為Quartz設置一個用于繪制的模式顏色空間,如清單6-6所示。下面是對每一行代碼的詳細說明。
Listing 6-6 Code that creates a pattern color space for a stencil pattern
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
baseSpace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);// 1
patternSpace = CGColorSpaceCreatePattern (baseSpace);// 2
CGContextSetFillColorSpace (myContext, patternSpace);// 3
CGColorSpaceRelease(patternSpace);// 4
CGColorSpaceRelease(baseSpace);
下面是代碼的作用:
1、這個函數創建一個通用的RGB空間。泛型顏色空間將顏色匹配留給系統。有關更多信息,請參見創建通用顏色空間。
2、創建一個圖案顏色空間。您提供的顏色空間指定如何為模式表示顏色。稍后,當您為模式設置顏色時,您必須使用模式顏色空間來設置它們。對于本例,您需要使用RGB值指定顏色。
3、設置填充圖案時要使用的顏色空間。您可以通過調用函數
CGContextSetStrokeColorSpace來設置筆畫的顏色空間。
4、釋放圖案顏色空間對象。
5、釋放基本顏色空間對象。
Set Up the Anatomy of the Stencil Pattern
您可以通過調用CGPatternCreate函數來指定模式解析的信息,如你可以用有色模式的方法來指定模式的解剖學知識。唯一的區別是,對于isColored參數傳遞false。有關為CGPatternCreate函數提供的參數的更多信息,請參閱建立彩色模式的解剖關系。
Specify the Stencil Pattern as a Fill or Stroke Pattern
您可以通過調用適當的函數CGContextSetFillPattern或CGContextSetStrokePattern來使用您的模式來填充或描邊。Quartz會使用您的模式進行后續的填充或撫摸。
這些函數都有三個參數:
圖形上下文
您之前創建的CGPattern對象
顏色組件的數組
在繪圖回調中,模板模式不提供顏色,因此必須向填充或筆畫函數傳遞顏色,以告知Quartz使用什么顏色。清單6-7顯示了如何為模板模式設置顏色的示例。顏色數組中的值由前面設置的顏色空間中的Quartz解釋。因為本例使用設備RGB,所以顏色數組包含紅色、綠色和藍色組件的值。第四個值指定顏色的不透明度。
Listing 6-7 Code that sets opacity for a colored pattern
static const CGFloat color[4] = { 0, 1, 1, 0.5 }; //cyan, 50% transparent
CGContextSetFillPattern (myContext, myPattern, color);
Drawing with the Stencil Pattern
完成前面的步驟后,可以調用繪制的任何Quartz 2D函數。你的圖案被用作“顏料”。例如,您可以調用CGContextStrokePath、CGContextFillPath、CGContextFillRect或任何其他繪制函數。
A Complete Stencil Pattern Painting Function
清單6-8中的代碼包含一個繪制模板模式的函數。該函數包含前面討論的所有步驟。下面是對每一行代碼的詳細說明。
Listing 6-8 A function that paints a stencil pattern
#define PSIZE 16
void MyStencilPatternPainting (CGContextRef myContext,
const Rect *windowRect)
{
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
static const CGFloat color[4] = { 0, 1, 0, 1 };// 1
static const CGPatternCallbacks callbacks = {0, &drawStar, NULL};// 2
baseSpace = CGColorSpaceCreateDeviceRGB ();// 3
patternSpace = CGColorSpaceCreatePattern (baseSpace);// 4
CGContextSetFillColorSpace (myContext, patternSpace);// 5
CGColorSpaceRelease (patternSpace);
CGColorSpaceRelease (baseSpace);
pattern = CGPatternCreate(NULL, CGRectMake(0, 0, PSIZE, PSIZE),// 6
CGAffineTransformIdentity, PSIZE, PSIZE,
kCGPatternTilingConstantSpacing,
false, &callbacks);
CGContextSetFillPattern (myContext, pattern, color);// 7
CGPatternRelease (pattern);// 8
CGContextFillRect (myContext,CGRectMake (0,0,PSIZE*20,PSIZE*20));// 9
}
下面是代碼的作用:
1、聲明一個數組以保存顏色值,并將該值(將位于RGB顏色空間中)設置為不透明綠色。
2、聲明并填充回調結構,傳遞0作為版本和一個指向繪圖回調函數的指針。這個示例沒有提供release info回調,因此該字段被設置為NULL。
3、創建一個RGB設備顏色空間。如果將模式繪制到顯示器上,則需要提供這種類型的顏色空間。
4、從RGB設備顏色空間創建一個模式顏色空間對象。
5、將填充顏色空間設置為剛才創建的模式顏色空間對象。
6、創建一個模式對象。注意,最后一個參數是isColored參數是false。蠟紙圖案不提供顏色,因此您必須為這個參數傳遞false。所有其他參數都類似于為彩色模式示例傳遞的參數。查看完整的彩色圖案繪畫功能。
7、設置填充模式,傳遞之前聲明的顏色數組。
8、釋放CGPattern對象。
9、填補了一個矩形。Quartz使用剛才設置的模式填充矩形。