- 概覽
- 圖形上下文
- 路徑
- 顏色與顏色空間
- 變換
- 圖案
- 陰影
- 漸變
- 透明層
- Quartz 2D 中的數據管理
- 位圖與圖像遮罩
- CoreGraphics 繪制 Layer
0.說明
本篇博客主要是對官方文檔的總結與補充。翻譯部分參考了南峰子的博客。你可以在參考資料中查看。
1.概覽
簡介
- Quartz2D 是二維圖形繪制引擎,支持 iOS 和 OS X。
Page
- Quartz2D 在圖像中使用了繪畫者模型。在繪畫者模型中,每個連續的繪制操作都是將一個繪制層放置於一個畫布,我們通常稱這個畫布為 Page。
Graphics Context
- Graphics Context 是一個數據類型(CGContextRef),用於封裝 Quartz 繪制圖像到輸出設備的信息。設備可以是PDF文件、bitmap或者顯示器的窗口。 CGContextRef 對應繪畫者模式中的 Page。
- 當用 Quartz 繪圖時,所有設備相關的特性都包含在我們所使用的Graphics Context 中。我們可以簡單地給 Quartz 繪圖序列指定不同的 Graphics Context,就可將相同的圖像繪制到不同的設備上。
- Quartz提供了 5 種類型的 Graphics Context。Bitmap Graphics Context、PDF Graphics Context、Window Graphics Context、Layer Context、Post Graphics Context。
數據類型
- Quartz 2D 使用如下數據類型來創建對象,通過操作這些對象來獲取特定的圖形。
- CGPathRef:用於向量圖,可創建路徑,並進行填充或描畫(stroke)
- CGImageRef:用於表示bitmap圖像和基於采樣數據的bitmap圖像遮罩。
- CGLayerRef:用於表示可用於重復繪制(如背景)和幕后 (offscreen)繪制的繪畫層
- CGPatternRef:用於重繪圖
- CGShadingRef、CGGradientRef:用於繪制漸變
- CGFunctionRef:用於定義回調函數,該函數包含一個隨機的浮點值參數。當為陰影創建漸變時使用該類型
- CGColorRef, CGColorSpaceRef:用於告訴Quartz如何解釋顏色
- CGImageSourceRef,CGImageDestinationRef:用於在Quartz中移入移出數據
- CGFontRef:用於繪制文本
- *CGPDFDictionaryRef, CGPDFObjectRef, CGPDFPageRef, CGPDFStream, CGPDFStringRef, and CGPDFArrayRef:用於訪問PDF的元數據
- *CGPDFScannerRef, CGPDFContentStreamRef:用於解析PDF元數據
- *CGPSConverterRef:用於將PostScript轉化成PDF。在iOS中不能使用。
圖形狀態
-
Quartz 通過修改當前圖形狀態(current graphics state)來修改繪制操作的結果。圖形狀態包含用於繪制程序的參數。繪制程序根據這些繪圖狀態來決定如何渲染結果。
-
可使用函數CGContextSaveGState來保存圖形狀態,CGContextRestoreGState來還原圖形狀態。
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGContextRestoreGState(context);
- 並不是當前繪制環境的所有屬性都是圖形狀態的元素。如,圖形狀態不包含當前路徑(current path)。
坐標系統
-
Quartz 的坐標系與 UIKit 坐標系 Y 軸相反。
-
Quartz 通過使用當前轉換矩陣(current transformation matrix, CTM)將一個獨立的坐標系統(user space)映射到輸出設備的坐標系統(device space),以此來解決設備依賴問題。
-
使用 UIGraphicsBeginImageContextWithOptions 返回的繪圖上下文與UIKit 的坐標系統相同。
-
在 iOS 中,如果使用 UIImage 對象來包裹創建的 CGImage 對象,可以不需要修改 CTM。UIImage 將自動進行補償以適用 UIKit 的坐標系統。
-
在 iOS 3.2 后,當 UIKit 為你的應用程序創建一個繪圖上下文時,也對上下文進行了額外的修改以匹配 UIKit 的約定。
內存管理
-
如果創建或拷貝一個對象,你將擁有它,因此你必須釋放它。通常,如果使用含有”Create”或“Copy”單詞的函數獲取一個對象,當使用完后必須釋放,否則將導致內存泄露。
-
如果使用不含有”Create”或“Copy”單詞的函數獲取一個對象,你將不會擁有對象的引用,不需要釋放它。
-
如果你不擁有一個對象而打算保持它,則必須 retain 它並且在不需要時 release 掉。可以使用 Quartz2D 的函數來指定 retain 和 release 一個對象。例如,如果創建了一個 CGColorspace 對象,則使用函數 CGColorSpaceRetain 和 CGColorSpaceRelease 來 retain 和 release 對象。同樣,可以使用 Core Foundation 的 CFRetain 和 CFRelease,但是注意不能傳遞 NULL 值給這些函數。
2.圖形上下文
簡介
我們可以通過兩種方式來獲取 Graphics Context:Quartz提供的創建函數、OS X 框架或 iOS 的 UIKit 框架提供的函數。
創建 Window Graphics Context
-
在 iOS 應用程序中,如果要在屏幕上進行繪制,需要創建一個 UIView 對象,並實現它的 drawRect: 方法。
-
drawRect: 方法中視圖對象將為當前的繪圖環境創建一個 Graphics Context。我們可以通過調用 UIGraphicsGetCurrentContext 函數來獲取這個 Graphics Context。
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, 1, 0, 0, 1); CGContextFillRect(context, CGRectMake (0, 0, 200, 100)); CGContextSetRGBFillColor(context, 0, 0, 1, .5); CGContextFillRect(context, CGRectMake (0, 0, 100, 200));
*創建 PDF Graphics Context
Quartz2D API 提供了兩個函數來創建 PDF Graphics Context。
-
CGPDFContextCreateWithURL。當你需要用 Core Foundation URL 指定 PDF 輸出的位置時使用該函數。
-
CGPDFContextCreate 當需要將pdf輸出發送給數據用戶時使用該方法。
創建 Bitmap Graphics Context
- iOS 中使用 UIGraphicsBeginImageContextWithOptions 取代 CGBitmapContextCreate 來創建 Bitmap Graphics Context 以便獲得相同的坐標系。
UIGraphicsBeginImageContext([UIScreen mainScreen].bounds.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, 1, 0, 0, 1); CGContextFillRect(context, CGRectMake (0, 0, 200, 100)); CGContextSetRGBFillColor(context, 0, 0, 1, .5); CGContextFillRect(context, CGRectMake (0, 0, 100, 200)); UIImage *image = UIGraphicsGetImageFromCurrentImageContext();//CGBitmapContextCreateImage(context) UIGraphicsEndImageContext();
像素格式
-
像素格式是在使用 CGBitmapContextCreate 創建 Bitmap Graphics Context 時需要指定的參數。
-
像素格式用 bpp(每像素的位數)和 bpc(每個組件的位數)來表示。
-
iOS 共支持 8 種像素格式。
- Null 8 bpp, 8 bpc, kCGImageAlphaOnly
- Gray 8 bpp, 8 bpc, kCGImageAlphaNone
- Gray 8 bpp, 8 bpc, kCGImageAlphaOnly
- RGB 16 bpp, 5 bpc, kCGImageAlphaNoneSkipFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaNoneSkipFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaNoneSkipLast
- RGB 32 bpp, 8 bpc, kCGImageAlphaPremultipliedFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaPremultipliedLast
抗鋸齒
-
我們可以通過調用 CGContextSetShouldAntialias 來關閉位圖Graphics Context的反鋸齒效果。反鋸齒設置是圖形狀態的一部分。
-
可以調用函數CGContextSetAllowsAntialiasing來控制一個特定Graphics Context是否支持反鋸齒;false表示不支持。該設置不是圖形狀態的一部分。當上下文及圖形狀態設置為true時,Quartz執行反鋸齒。
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetShouldAntialias(context, YES); CGContextSetAllowsAntialiasing(context, YES);
3.路徑
簡介
-
路徑定義了一個或多個形狀或者子路徑。一個子路徑可由直線,曲線,或者同時由兩者構成。它可以是開放的,也可以是閉合的;可以是實線,可以是曲線;可以填充,也可以描邊等等。
-
路徑創建及路徑繪制是兩個獨立的工作。首先我們創建路徑。當我們需要渲染路徑時,我們需要使用Quartz來繪制它。
點
- 調用 CGContextMoveToPoint(context, 0, 0) 為新的子路徑指定起始點。
直線
-
調用 CGContextAddLineToPoint(context, 200, 200) 從起始點到指定點添加直線。
-
調用 CGContextAddLines(context, points, 3) 函數添加一系列相關的直線到子路徑中。
弧
-
調用 CGContextAddArc(context, 200, 200, 100, 0, M_PI_2, 0) 以指定圓心、半徑、起始/終止角度、順/逆時針畫弧。
-
調用 CGContextAddArcToPoint(context, 200, 400, 400, 400, 100) 以當前點與指定的兩個點連接的兩條直線為切線畫弧。
曲線
-
調用 CGContextAddQuadCurveToPoint(context, 0, 100, 200, 100) 以一個控制點畫曲線。
-
調用 CGContextAddCurveToPoint(context, 100, 400, 200, 300, 100, 200) 以兩個控制點畫曲線。
閉合路徑
- 調用 CGContextClosePath(context) 閉合路徑。
橢圓
- 調用 CGContextAddEllipseInRect(context, CGRectMake(0, 0, 100, 200)) 畫橢圓。
矩形
- 調用 CGContextAddRect(context, CGRectMake(200, 400, 100, 200)) 畫矩形。
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, 200, 200); CGPoint point2 = CGPointMake(200, 200); CGPoint point3 = CGPointMake(200, 400); CGPoint point4 = CGPointMake(0, 200); CGPoint points[3] = {point2, point3, point4}; CGContextAddLines(context, points, 3); // reset start point CGContextAddArc(context, 200, 200, 100, 0, M_PI_2, 0); CGContextAddArcToPoint(context, 200, 400, 400, 400, 100); CGContextAddCurveToPoint(context, 100, 400, 200, 300, 100, 200); CGContextAddQuadCurveToPoint(context, 0, 100, 200, 100); CGContextClosePath(context); CGContextAddEllipseInRect(context, CGRectMake(0, 0, 100, 200)); CGContextAddRect(context, CGRectMake(200, 400, 100, 200)); CGContextDrawPath(context, kCGPathStroke);
創建路徑
-
在開始繪制路徑前,調用 CGContextBeginPath 或 UI。
-
直線、弧、曲線開始於當前點。空路徑沒有當前點;我們必須調用CGContextMoveToPoint來設置第一個子路徑的起始點,或者調用一個便利函數來隱式地完成該任務。
-
如果要閉合當前子路徑,調用函數 CGContextClosePath。隨后路徑將開始一個新的子路徑,即使我們不顯示設置一個新的起始點。
-
當繪制弧時,Quartz 將在當前點與弧的起始點間繪制一條直線。
-
添加橢圓和矩形的 Quartz 程序將在路徑中添加新的閉合子路徑。
-
我們必須調用繪制函數來填充或者描邊一條路徑,因為創建路徑時並不會繪制路徑。
-
Quartz 提供了兩個數據類型來創建可復用路徑 CGPathRef 和 CGMutablePathRef。
-
Quartz 提供了一個類似於操作圖形上下文的 CGPath 的函數集合。這些路徑函數操作 CGPath 對象,而不是圖形上下文。
- CGPathCreateMutable 取代 CGContextBeginPath
- CGPathMoveToPoint 取代 CGContextMoveToPoint
- CGPathAddLineToPoint 取代 CGContexAddLineToPoint
- CGPathAddCurveToPoint 取代 CGContexAddCurveToPoint
- CGPathAddEllipseInRect 取代 CGContexAddEllipseInRect
- CGPathAddArc 取代 CGContexAddArc
- CGPathAddRect 取代 CGContexAddRect
- CGPathCloseSubpath 取代 CGContexClosePath
- 如果想要添加一個路徑到圖形上下文,可以調用 CGContextAddPath。
填充規則
-
填充規則有兩種:非零纏繞數規則(nonzero winding number rule)、偶數-奇數規則(even-odd rule)。
-
默認的填充規則為非零纏繞數規則。方法或枚舉帶有“EO”的為偶數-奇數規則。
-
非零纏繞數的填充規則與繪制的方向有關、偶數-奇數規則則與方向無關。如圖。
繪制路徑
-
調用 CGContextDrawPath(context, kCGPathFill) 填充路徑。
-
調用 CGContextDrawPath(context, kCGPathEOFill) 使用奇偶規則填充路徑。
-
調用 CGContextDrawPath(context, kCGPathStroke) 描邊路徑。
-
調用 CGContextDrawPath(context, kCGPathFillStroke) 填充並描邊路徑。
-
調用 CGContextDrawPath(context, kCGPathEOFillStroke) 使用奇偶規則填充並描邊路徑。
描邊路徑
-
調用快捷方法 CGContextStrokePath(context) 來描邊路徑。
-
調用如下函數來快捷的創建形狀路徑並描邊。
CGContextStrokeRect(context, CGRectMake(200, 400, 100, 200)); CGContextStrokeRectWithWidth(context, CGRectMake(200, 400, 100, 200), 2); CGContextStrokeEllipseInRect(context, CGRectMake(200, 400, 100, 200));
- 調用 CGContextStrokeLineSegments(context, points, 4) 快捷的創建多條不連續的線段並描邊。
CGPoint point2 = CGPointMake(200, 200); CGPoint point3 = CGPointMake(200, 400); CGPoint point4 = CGPointMake(100, 300); CGPoint point5 = CGPointMake(300, 300); CGPoint points[4] = {point2, point3, point4, point5}; CGContextStrokeLineSegments(context, points, 4);
填充路徑
-
調用快捷方法 CGContextFillPath(context) 或 CGContextEOFillPath(context) 填充路徑。
-
CGContextStrokePath(context) 和 CGContextFillPath(context) 不能同時使用。
-
調用如下函數來快捷的創建形狀路徑並填充。
CGContextFillRect(context, CGRectMake(100, 100, 100, 200)); CGRect rects[2] = {CGRectMake(100, 100, 100, 200), CGRectMake(200, 300, 100, 200)}; CGContextFillRects(context, rects, 2); CGContextFillEllipseInRect(context, CGRectMake(100, 100, 100, 200));
混合模式
-
調用 CGContextSetBlendMode(context, kCGBlendModeNormal) 設置回合模式。
-
常用的混合模式:
- kCGBlendModeNormal 正常
- kCGBlendModeMultiply 正片疊底
- kCGBlendModeScreen 濾色(屏幕)
- kCGBlendModeOverlay 疊加
- kCGBlendModeDarken 變暗
- kCGBlendModeLighten 變亮
- kCGBlendModeColorDodge 顏色減淡
- kCGBlendModeColorBurn 顏色加深
- kCGBlendModeSoftLight 柔光
- kCGBlendModeHardLight 強光
- kCGBlendModeDifference 差值
- kCGBlendModeExclusion 排除
- kCGBlendModeHue 色相
- kCGBlendModeSaturation 飽和度
- kCGBlendModeColor 顏色
- kCGBlendModeLuminosity 明度
- 你可以在《Quartz 2D Programming Guide》官方文檔中的 Paths 章節和 Bitmap Images and Image Masks 章節的最后部分查看混合模式的具體效果。這里的混合模式與常用的圖形軟件(如 Photoshop)的混合模式效果相同,這里只展示正片疊底和濾色兩種效果。
-
原圖
-
正片疊底
-
濾色
顏色與顏色空間
簡介
-
Quartz 中的顏色是用一組數值來表示。而顏色空間用於解析這些顏色信息,常用顏色空間有 RGB 、CMYK等。
-
Quartz 支持通用顏色空間、設備獨立顏色空間、設備依賴顏色空間、索引顏色空間和模式(Pattern)顏色空間。
-
iOS不支持設備獨立顏色空間和通用顏色空間。iOS應用程序必須使用設備顏色空間。
透明度
-
使用 CGContextSetAlpha(context, 0.2) 設置透明度。
-
使用 CGContextClearRect 清除上下文的 alpha 通道。
創建設備依賴顏色空間
-
CGColorSpaceCreateDeviceGray() 創建設備依賴灰度顏色空間。
-
CGColorSpaceCreateDeviceRGB() 創建設備依賴RGB顏色空間。
-
CGColorSpaceCreateDeviceCMYK() 創建設備依賴CMYK顏色空間。
-
調用 CGContextSetFillColorSpace(context, colorSpace) 或 CGContextSetStrokeColorSpace(context, colorSpace) 設置顏色空間。
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextSetFillColorSpace(context, colorSpace); CGContextSetStrokeColorSpace(context, colorSpace);
- 調用如下函數來便捷的設置設備依賴RGB顏色空間並設置顏色值。
//Device RGB.
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1); CGContextSetRGBFillColor(context, 1, 0, 0, 1);
- 調用如下函數來便捷的設置設備依賴CMYK顏色空間並設置顏色值。
//Device CMYK.
CGContextSetCMYKStrokeColor(context, 1, 0, 0, 0, 1); CGContextSetCMYKFillColor(context, 1, 0, 0, 0, 1);
- 調用如下函數來便捷的設置設備依賴灰度顏色空間並設置顏色值。
//Device Gray.
CGContextSetGrayStrokeColor(context, 0.5, 1); CGContextSetGrayFillColor(context, 0.5, 1);
- 調用如下函數來便捷的使用 CGColor 設置顏色值並使用 CGColor 指定的顏色空間。
//Any color space; you supply a CGColor object that specifies the color space. Use these functions for colors you need repeatedly.
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGFloat colors[4] = {1.0, 0.0, 0.0, 1.0}; CGColorRef color = CGColorCreate(colorSpace, colors); CGContextSetStrokeColorWithColor(context, color); CGContextSetFillColorWithColor(context, color);
- 調用如下函數來便捷的設置顏色值並使用正在使用的顏色空間。
//The current color space. Not recommended. Instead, set color using a CGColor object and the functions CGContextSetStrokeColorWithColor and CGContextSetFillColorWithColor.
CGContextSetStrokeColor(context, colors); CGContextSetFillColor(context, colors);
設置和創建顏色
- 通過如下函數設置和創建顏色。
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor); CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor));
設置再現意圖(Rending Intent)
每個設備都有固定的可復制的顏色范圍(gamut),這是設備的物理性質決定的。當圖像從一個顏色空間向另一個顏色空間轉換時,有些源設備顏色空間中呈現的顏色,不能在目標設備顏色空間中復制出來,這些不能復制的顏色叫色域外(out-of-gamut)顏色。比如 RGB 顏色空間比 CMYK 的顏色空間要大,有些在顯示器上能顯示的顏色不能在打印機上同樣打印出來。因為我們不能在目標設備顏色空間中復制出色域外顏色,我們必須用一些其他顏色來替代他們。顏色空間轉換時顏色替換調整的規則就是再現意圖。更詳細的說明可以查看 這里 和 這里
-
再現意圖用於指定如何將源顏色空間的顏色映射到圖形上下文的目標顏色空間的顏色范圍內。
-
如果不顯式的指定再現意圖,Quartz 使用“相對色度再現意圖”應用於所有繪制(不包含位圖圖像)。
-
對於位圖圖像,Quartz默認使用“感知再現意圖”。
-
調用 CGContextSetRenderingIntent(context, kCGRenderingIntentDefault) 來設置再現意圖。
-
再現意圖共有以下 5 種。
typedef CF_ENUM (int32_t, CGColorRenderingIntent) {
kCGRenderingIntentDefault,
kCGRenderingIntentAbsoluteColorimetric,
kCGRenderingIntentRelativeColorimetric,
kCGRenderingIntentPerceptual,
kCGRenderingIntentSaturation
};
- kCGRenderingIntentDefault:默認再現意圖。
- kCGRenderingIntentAbsoluteColorimetric:絕對色度再現意圖。將輸出設備顏色域外的顏色映射為輸出設備域內與之最接近的顏色。這可以產生一個裁減效果,因為色域外的兩個不同的顏色值可能被映射為色域內的同一個顏色值。當圖形使用的顏色值同時包含在源色域及目標色域內時,這種方法是最好的。常用於logo或者使用專色(spot color)時。
- kCGRenderingIntentRelativeColorimetric:相對色度再現意圖。轉換所有的顏色(包括色域內的),以補償圖形上下文的白點與輸出設備白點之間的色差。
- kCGRenderingIntentPerceptual:感知再現意圖。通過壓縮圖形上下文的色域來適應輸出設備的色域,並保持源顏色空間的顏色之間的相對性。感知渲染意圖適用於相片及其它復雜的高細度圖片。
- kCGRenderingIntentSaturation:飽和度再現意圖。把顏色轉換到輸出設備色域內時,保持顏色的相對飽和度。結果是包含亮度、飽和度顏色的圖片。飽和度意圖適用於生成低細度的圖片,如描述性圖表。
原文:http://xuyafei.cn/post/cocoatouch/quartz2d-bian-cheng-zhi-nan-gai-lan-tu-xing-shang-xia-wen-lu-jing-yan-se-yu-yan-se-kong-jian