版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.09.03 |
前言
Quartz 2D
框架相信大家都知道,也都一直在使用。Quartz 2D
的API是純C語言的,它是一個二維繪圖引擎,同時支持iOS和Mac系統。Quartz 2D
的API來自于Core Graphics
框架,數據類型和函數基本都以CG作為前綴,接下來幾篇我們就一起來看一下這個框架。感興趣可以看上面幾篇文章。
1. Quartz 2D編程指南 (一) —— 簡介(一)
2. Quartz 2D編程指南 (二) —— Quartz 2D概覽(二)
Graphics Contexts - 圖形上下文
圖形上下文表示繪圖目的地。它包含繪圖參數和繪圖系統執行任何后續繪圖命令所需的所有特定于設備的信息。圖形上下文定義基本的繪圖屬性,例如繪制時使用的顏色,剪切區域,線寬和樣式信息,字體信息,合成選項以及其他幾種。
您可以使用Quartz
上下文創建函數或使用某個Mac OS X框架或iOS中UIKit框架提供的更高級別函數來獲取圖形上下文。 Quartz提供各種Quartz圖形上下文函數,包括位圖和PDF,您可以使用它們來創建自定義內容。
本章介紹如何為各種繪圖目的地創建圖形上下文。圖形上下文在代碼中由數據類型CGContextRef
表示,它是一種不透明的數據類型。獲取圖形上下文后,可以使用Quartz 2D
函數繪制上下文,對上下文執行操作(如翻譯),以及更改圖形狀態參數,如線寬和填充顏色。
Drawing to a View Graphics Context in iOS - 在iOS中繪制視圖圖形上下文
要在iOS應用程序中繪制到屏幕,請設置UIView對象并實現其 drawRect: 方法以執行繪圖。當視圖在屏幕上可見并且其內容需要更新時,將調用視圖的drawRect:
方法。在調用自定義drawRect:
方法之前,視圖對象會自動配置其繪圖環境,以便您的代碼可以立即開始繪制。作為此配置的一部分,UIView對象為當前繪圖環境創建圖形上下文( CGContextRef opaque類型)。您可以通過調用UIKit函數UIGraphicsGetCurrentContext在drawRect:
方法中獲取此圖形上下文。
整個UIKit使用的默認坐標系與Quartz使用的坐標系不同。在UIKit中,原點位于左上角,正y值指向下方。 UIView對象通過將原點轉換為視圖的左上角并通過將其乘以-1來反轉y軸來修改Quartz圖形上下文的CTM以匹配UIKit約定。有關修改坐標系統的更多信息以及您自己的繪圖代碼中的含義,請參閱Quartz 2D Coordinate Systems。
UIView對象在適用于View Programming Guide for iOS中有詳細描述。
Creating a Window Graphics Context in Mac OS X - 在Mac OS X中創建窗口圖形上下文
在Mac OS X
中繪圖時,您需要創建適合您正在使用的框架的窗口圖形上下文。 Quartz 2D API
本身不提供獲取Windows圖形上下文的函數。 相反,您使用Cocoa
框架來獲取在Cocoa中創建的窗口的上下文。
您可以使用以下代碼行從Cocoa應用程序的drawRect:
例程中獲取Quartz
圖形上下文:
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
currentContext
方法返回當前線程的NSGraphicsContext
實例。 方法graphicsPort
返回由接收器表示的低級,特定于平臺的圖形上下文,這是一個Quartz圖形上下文。 (不要對方法名稱感到困惑,它們是歷史原因。)有關更多信息,請參閱NSGraphicsContext Class Reference。
獲取圖形上下文后,可以在Cocoa應用程序中調用任何Quartz 2D
繪圖函數。 您還可以將Quartz 2D
調用與Cocoa
繪圖調用混合使用。 通過查看圖2-1,您可以看到Quartz 2D
繪圖到Cocoa視圖的示例。 該圖由兩個重疊的矩形組成,一個是不透明的紅色,另一個是部分透明的藍色。您將了解有關Color and Color Spaces的更多信息。 控制多少“透視”顏色的能力是Quartz 2D的標志性功能之一。
要創建圖2-1中的繪圖,首先要創建一個Cocoa應用程序Xcode項目。 在Interface Builder
中,將自定義視圖拖到窗口并將其子類化。 然后為子類視圖編寫一個實現,類似于LIsting 2-1
所示。 對于此示例,子類視圖名為MyQuartzView
。 視圖的drawRect:
方法包含所有Quartz繪圖代碼。 列表后面會顯示每個編號行代碼的詳細說明。
注意:每次需要繪制視圖時,都會自動調用
NSView
類的drawRect:
方法。 要了解有關覆蓋drawRect:
方法的更多信息,請參閱NSView Class Reference。
// Listing 2-1 Drawing to a window graphics context
@implementation MyQuartzView
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
return self;
}
- (void)drawRect:(NSRect)rect
{
CGContextRef myContext = [[NSGraphicsContext // 1
currentContext] graphicsPort];
// ********** Your drawing code here ********** // 2
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);// 3
CGContextFillRect (myContext, CGRectMake (0, 0, 200, 100 ));// 4
CGContextSetRGBFillColor (myContext, 0, 0, 1, .5);// 5
CGContextFillRect (myContext, CGRectMake (0, 0, 100, 200));// 6
}
@end
這是代碼的作用:
- 1)獲取視圖的圖形上下文。
- 2)這是您插入繪圖代碼的地方。 下面的四行代碼是使用
Quartz 2D
函數的示例。 - 3)設置完全不透明的紅色填充顏色。 有關顏色和alpha(設置不透明度)的信息,請參閱Color and Color Spaces。
- 4)填充原點為(0,0)且寬度為200且高度為100的矩形。有關繪制矩形的信息,請參閱Paths。
- 5)設置部分透明的藍色填充顏色。
- 6)填充一個矩形,其原點為(0,0),寬度為100,高度為200。
Creating a PDF Graphics Context - 創建一個PDF圖像上下文
當您創建PDF圖形上下文并繪制到該上下文時,Quartz會將您的繪圖記錄為一系列寫入文件的PDF繪圖命令。 您提供PDF輸出的位置和默認媒體框 - 指定頁面邊界的矩形。 圖2-2顯示了繪制到PDF圖形上下文然后在預覽中打開生成的PDF的結果。
Quartz 2D API
提供了兩個創建PDF圖形上下文的函數:
-
CGPDFContextCreateWithURL
,當您要將PDF輸出的位置指定為Core Foundation URL時使用。Listing 2-2
顯示了如何使用此函數創建PDF圖形上下文。 -
CGPDFContextCreate
,當您希望將PDF輸出發送給數據使用者時使用。 (有關更多信息,請參閱Data Management in Quartz 2D。)Listing 2-3
顯示了如何使用此函數創建PDF圖形上下文。
每個列表后面的每個編號行代碼的詳細說明。
iOS注意:iOS中的PDF圖形上下文使用Quartz提供的默認坐標系,而不應用變換來匹配UIKit坐標系。如果您的應用程序計劃在PDF圖形上下文和UIView對象提供的圖形上下文之間共享繪圖代碼,則應用程序應修改PDF圖形上下文的
CTM
以修改坐標系。請參見 Quartz 2D Coordinate Systems。
// Listing 2-2 Calling CGPDFContextCreateWithURL to create a PDF graphics context
CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
CFStringRef path)
{
CGContextRef myOutContext = NULL;
CFURLRef url;
url = CFURLCreateWithFileSystemPath (NULL, // 1
path,
kCFURLPOSIXPathStyle,
false);
if (url != NULL) {
myOutContext = CGPDFContextCreateWithURL (url,// 2
inMediaBox,
NULL);
CFRelease(url);// 3
}
return myOutContext;// 4
}
這是代碼的作用:
- 1)調用
Core Foundation
函數從提供給MyPDFContextCreate
函數的CFString
對象創建CFURL
對象。 您將NULL
作為第一個參數傳遞以使用默認分配器。 您還需要指定路徑樣式,對于此示例,路徑樣式是POSIX
樣式的路徑名。 - 2)調用
Quartz 2D
函數,使用剛剛創建的PDF位置(作為CFURL對象)和指定PDF邊界的矩形創建PDF圖形上下文。 矩形(CGRect)
已傳遞給MyPDFContextCreate
函數,并且是PDF的默認頁面媒體邊界框。 - 3)釋放
CFURL
對象。 - 4)返回PDF圖形上下文。 調用者必須在不再需要時釋放圖形上下文。
// Listing 2-3 Calling CGPDFContextCreate to create a PDF graphics context
CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
CFStringRef path)
{
CGContextRef myOutContext = NULL;
CFURLRef url;
CGDataConsumerRef dataConsumer;
url = CFURLCreateWithFileSystemPath (NULL, // 1
path,
kCFURLPOSIXPathStyle,
false);
if (url != NULL)
{
dataConsumer = CGDataConsumerCreateWithURL (url);// 2
if (dataConsumer != NULL)
{
myOutContext = CGPDFContextCreate (dataConsumer, // 3
inMediaBox,
NULL);
CGDataConsumerRelease (dataConsumer);// 4
}
CFRelease(url);// 5
}
return myOutContext;// 6
}
這是代碼的作用:
- 1)調用
Core Foundation
函數從提供給MyPDFContextCreate
函數的CFString
對象創建CFURL對象。您將NULL作為第一個參數傳遞以使用默認分配器。您還需要指定路徑樣式,對于此示例,路徑樣式是POSIX樣式的路徑名。 - 2)使用CFURL對象創建Quartz數據使用者對象。如果您不想使用CFURL對象(例如,您希望將PDF數據放在CFURL對象無法指定的位置),則可以從您在應用程序中實現的一組回調函數創建數據使用者。有關更多信息,請參閱Data Management in Quartz 2D。
- 3)調用
Quartz 2D
函數創建一個PDF圖形上下文,作為參數傳遞給數據使用者和傳遞給MyPDFContextCreate
函數的矩形(CGRect類型)。此矩形是PDF的默認頁面媒體邊界框。 - 4)釋放數據使用者。
- 5)釋放CFURL對象。
- 6)返回PDF圖形上下文。調用者必須在不再需要時釋放圖形上下文。
Listing 2-4
顯示了如何調用MyPDFContextCreate
例程并繪制它。列表后面會顯示每個編號行代碼的詳細說明。
// Listing 2-4 Drawing to a PDF graphics context
CGRect mediaBox;// 1
mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight);// 2
myPDFContext = MyPDFContextCreate (&mediaBox, CFSTR("test.pdf"));// 3
CFStringRef myKeys[1];// 4
CFTypeRef myValues[1];
myKeys[0] = kCGPDFContextMediaBox;
myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof (CGRect));
CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues, 1,
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);
CGPDFContextBeginPage(myPDFContext, &pageDictionary);// 5
// ********** Your drawing code here **********// 6
CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1);
CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 ));
CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5);
CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 ));
CGPDFContextEndPage(myPDFContext);// 7
CFRelease(pageDictionary);// 8
CFRelease(myValues[0]);
CGContextRelease(myPDFContext);
這是代碼的作用:
- 1)聲明用于定義PDF媒體框的矩形的變量。
- 2)將媒體框的原點設置為(0,0),將寬度和高度設置為應用程序提供的變量。
- 3)調用函數
MyPDFContextCreate
(參見Listing 2-3)以獲取PDF圖形上下文,提供媒體框和路徑名。宏CFSTR
將字符串轉換為CFStringRef
數據類型。 - 4)使用頁面選項設置字典。在此示例中,僅指定了媒體框。您不必傳遞用于設置PDF圖形上下文的相同矩形。您在此處添加的媒體框將取代您傳遞的矩形以設置PDF圖形上下文。
- 5)表示頁面的開頭。此函數用于面向頁面的圖形,這是PDF繪圖。
- 6)調用Quartz 2D繪圖函數。您可以使用適合您的應用程序的繪圖代碼替換此代碼和以下四行代碼。
- 7)表示PDF頁面的結尾。
- 8)在不再需要時候,釋放字典和PDF圖形上下文。
您可以將任何內容寫入適合您的應用程序的PDF - 圖像,文本,路徑繪圖 - 并且您可以添加鏈接和加密。有關更多信息,請參閱PDF Document Creation, Viewing, and Transforming。
Creating a Bitmap Graphics Context - 創建位圖圖形上下文
位圖圖形上下文接受指向包含位圖存儲空間的內存緩沖區的指針。當您繪制到位圖圖形上下文時,緩沖區會更新。釋放圖形上下文后,您將以指定的像素格式獲得完全更新的位圖。
注意:位圖圖形上下文有時用于繪制屏幕外。在您決定使用位圖圖形上下文之前,請參閱Core Graphics Layer Drawing。
CGLayer
對象(CGLayerRef
)針對屏幕外繪圖進行了優化,因為只要有可能,Quartz就會在視頻卡上緩存圖層。
iOS注意:iOS應用程序應使用函數。UIGraphicsBeginImageContextWithOptions而不是使用此處描述的低級Quartz函數。如果您的應用程序使用Quartz創建屏幕外位圖,則位圖圖形上下文使用的坐標系是默認的Quartz坐標系。相反,如果您的應用程序通過調用函數
UIGraphicsBeginImageContextWithOptions
來創建圖像上下文,則UIKit將相同的變換應用于上下文的坐標系,就像對UIView對象的圖形上下文一樣。這允許您的應用程序使用相同的繪圖代碼,而無需擔心不同的坐標系。雖然您的應用程序可以手動調整坐標轉換矩陣以獲得正確的結果,但實際上,這樣做沒有性能優勢。
您可以使用函數CGBitmapContextCreate
來創建位圖圖形上下文。此函數采用以下參數:
- 1)
data
。在內存中提供指向要渲染圖形的目標的指針。此內存塊的大小應至少為(bytesPerRow * height)
字節。 - 2)
width
。指定位圖的寬度(以像素為單位)。 - 3)
height
。指定位圖的高度(以像素為單位)。 - 4)
bitsPerComponent
。指定內存中像素的每個組件使用的位數。例如,對于32位像素格式和RGB顏色空間,您將為每個組件指定8位的值。請參閱Supported Pixel Formats。 - 5)
bytesPerRow
。指定位圖每行使用的內存字節數。
提示:創建位圖圖形上下文時,如果確保數據和
bytesPerRow
是16字節對齊,則可以獲得最佳性能。
6)
colorspace
。用于位圖上下文的顏色空間。創建位圖圖形上下文時,可以提供Gray, RGB, CMYK, 和 NULL
顏色空間。有關顏色空間和顏色管理原則的詳細信息,請參閱顏 Color Management Overview。有關在Quartz中創建和使用顏色空間的信息,請參閱Color and Color Spaces。有關支持的顏色空間的信息,請參閱Bitmap Images and Image Masks一章中的Color Spaces and Bitmap Layout。7)
bitmapInfo
。位圖布局信息,表示為CGBitmapInfo
常量,指定位圖是否應包含alpha分量,像素中alpha分量(如果有)的相對位置,alpha分量是否預乘,以及顏色分量是整數或浮點值。有關這些常量的詳細信息,每個常量的使用時間以及位圖圖形上下文和圖像的Quartz支持的像素格式,請參閱Bitmap Images and Image Masks一章中的 Color Spaces and Bitmap Layout。
Listing 2-5
顯示了如何創建位圖圖形上下文。當您繪制到生成的位圖圖形上下文時,Quartz會將您的繪圖記錄為指定內存塊中的位圖數據。列表后面的每個編號行代碼的詳細說明。
// Listing 2-5 Creating a bitmap graphics context
CGContextRef MyCreateBitmapContext (int pixelsWide,
int pixelsHigh)
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
bitmapBytesPerRow = (pixelsWide * 4);// 1
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 2
bitmapData = calloc( bitmapByteCount, sizeof(uint8_t) );// 3
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
return NULL;
}
context = CGBitmapContextCreate (bitmapData,// 4
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast);
if (context== NULL)
{
free (bitmapData);// 5
fprintf (stderr, "Context not created!");
return NULL;
}
CGColorSpaceRelease( colorSpace );// 6
return context;// 7
}
這是代碼的作用:
- 1)聲明一個變量來表示每行的字節數。本例中位圖中的每個像素由4個字節表示:紅色,綠色,藍色和alpha各8位。
- 2)創建通用RGB顏色空間。您還可以創建
CMYK
顏色空間。有關更多信息以及有關通用顏色空間與設備相關顏色空間的討論,請參閱Color and Color Spaces。 - 3)調用
calloc
函數來創建和清除用于存儲位圖數據的內存塊。此示例創建一個32位RGBA位圖(即,每像素32位的數組,每個像素包含紅色,綠色,藍色和alpha信息各8位)。位圖中的每個像素占用4個字節的內存。在Mac OS X 10.6和iOS 4中,可以省略此步驟 - 如果將NULL
作為位圖數據傳遞,Quartz
會自動為位圖分配空間。 - 4)創建位圖圖形上下文,提供位圖數據,位圖的寬度和高度,每個組件的位數,每行的字節數,顏色空間,以及指定位圖是否應包含alpha通道的常量以及它在像素中的相對位置。
kCGImageAlphaPremultipliedLast
表示alpha
分量存儲在每個像素的最后一個字節中,并且顏色分量已經乘以此alpha值。有關預乘alpha的更多信息,請參閱The Alpha Value。 - 5)如果由于某種原因未創建上下文,則釋放為位圖數據分配的內存。
- 6)釋放色彩空間。
- 7)返回位圖圖形上下文。調用者必須在不再需要時釋放圖形上下文。
Listing 2-6
顯示了調用MyCreateBitmapContext
來創建位圖圖形上下文的代碼,使用位圖圖形上下文創建CGImage
對象,然后將生成的圖像繪制到窗口圖形上下文中。圖2-3顯示了繪制到窗口的圖像。列表后面的每個編號行代碼的詳細說明。
// Listing 2-6 Drawing to a bitmap graphics context
CGRect myBoundingBox;// 1
myBoundingBox = CGRectMake (0, 0, myWidth, myHeight);// 2
myBitmapContext = MyCreateBitmapContext (400, 300);// 3
// ********** Your drawing code here ********** // 4
CGContextSetRGBFillColor (myBitmapContext, 1, 0, 0, 1);
CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 200, 100 ));
CGContextSetRGBFillColor (myBitmapContext, 0, 0, 1, .5);
CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 100, 200 ));
myImage = CGBitmapContextCreateImage (myBitmapContext);// 5
CGContextDrawImage(myContext, myBoundingBox, myImage);// 6
char *bitmapData = CGBitmapContextGetData(myBitmapContext); // 7
CGContextRelease (myBitmapContext);// 8
if (bitmapData) free(bitmapData); // 9
CGImageRelease(myImage);// 10
這是代碼的作用:
- 1)聲明一個變量來存儲邊界框的原點和尺寸,Quartz將在其中繪制從位圖圖形上下文創建的圖像。
- 2)將邊界框的原點設置為(0,0),將寬度和高度設置為先前聲明的變量,但其聲明未在此代碼中顯示。
- 3)調用應用程序提供的函數
MyCreateBitmapContext
(參見Listing 2-5
)以創建400像素寬和300像素高的位圖上下文。您可以使用適合您的應用程序的任何維度創建位圖圖形上下文。 - 4)調用
Quartz 2D
函數繪制到位圖圖形上下文中。您可以使用適合您應用程序的繪圖代碼替換此代碼和接下來的四行代碼。 - 5)從位圖圖形上下文創建
Quartz 2D
圖像(CGImageRef)
。 - 6)將圖像繪制到由邊界框指定的窗口圖形上下文中的位置。邊界框指定用戶空間中繪制圖像的位置和尺寸。此示例未顯示窗口圖形上下文的創建。有關如何創建窗口圖形上下文的信息,請參閱Creating a Window Graphics Context in Mac OS X。
- 7)獲取與位圖圖形上下文關聯的位圖數據。
- 8)在不再需要時釋放位圖圖形上下文。
- 9)釋放位圖數據(如果存在)。
- 10)不再需要時釋放圖像。
1. Supported Pixel Formats - 支持像素格式
表2-1總結了位圖圖形上下文支持的像素格式,關聯的色彩空間(cs)
以及格式首次可用的Mac OS X
版本。 像素格式被指定為每像素位數(bpp)
和每個分量位數(bpc)
。 該表還包括與該像素格式相關聯的位圖信息常量。 有關每個位圖信息格式常量所代表的內容的詳細信息,請參閱 CGImage Reference。
2. Anti-Aliasing - 抗鋸齒
位圖圖形上下文支持抗鋸齒,這是人工校正在繪制文本或形狀時有時在位圖圖像中看到的鋸齒(或鋸齒)邊緣的過程。當位圖的分辨率明顯低于眼睛的分辨率時,會出現這些鋸齒狀邊緣。為了使對象在位圖中顯得平滑,Quartz對圍繞形狀輪廓的像素使用不同的顏色。通過以這種方式混合顏色,形狀顯得平滑。您可以在圖2-4中看到使用抗鋸齒的效果。您可以通過調用CGContextSetShouldAntialias
函數來關閉特定位圖圖形上下文的消除鋸齒。抗鋸齒設置是圖形狀態的一部分。
您可以使用CGContextSetAllowsAntialiasing
函數控制是否允許特定圖形上下文的抗鋸齒。傳遞給此函數true
以允許消除鋸齒;傳遞false
不允許它。此設置不是圖形狀態的一部分。當上下文和圖形狀態設置被設置為true
時,Quartz會執行消除鋸齒。
Obtaining a Graphics Context for Printing - 獲取用于打印的圖形上下文
Mac OS X
中的Cocoa應用程序通過自定義NSView子類實現打印。 通過調用print:
方法告訴視圖進行打印。 然后,視圖創建一個以打印機為目標的圖形上下文,并調用其drawRect:
方法。 您的應用程序使用與用于繪制到屏幕相同的繪圖代碼繪制到打印機。 它還可以自定義drawRect:
調用打印機的圖像,該圖像與發送到屏幕的圖像不同。
有關在Cocoa中打印的詳細討論,請參閱Printing Programming Guide for Mac。
后記
本篇主要講述了圖形上下文,感興趣的給個贊或者關注~~~