本文翻譯自蘋果官方文檔:原文地址
Quartz 2D 概述
Quartz 2D 是一個二維的繪畫引擎,在Mac OS X和iOS環境下可以使用,它在內核之外。你可以使用Quartz 2D 的API來完成各種各樣的操作,例如:基于路徑的繪圖、透明度繪圖、陰影繪圖、透明圖層、顏色管理、抗鋸齒渲染、PDF操作等。Quartz 2D能夠盡可能的發揮出圖形硬件的性能。
頁(The Page)
Quartz 2D 使用畫家模型來成像。在這個模型中,每次連續的繪圖操作都將一個叫做“油漆”的圖層應用到一個通常叫做“頁”的輸出“畫布”上。在“頁”上的“油漆”能夠被后續的的繪圖操作所覆蓋。只有你進行額外的繪圖操作,原先在“頁”上的物體才會被修改。這個模型允許你使用少量的基本元素來構建復雜精細的圖像。
圖 1-1 展示了畫家模型的工作原理。按照從左往右的順序繪制圖形,可以看到結果是不一樣的,因此繪制的順序在這個模型中是十分重要的。
這個“頁”或許是一個真正的紙張(輸出設備是打印機);也或許是一個虛擬的紙張(輸出設備是一個PDF文件);還可能是一個位圖圖像。準確的說,這個“頁”的本質取決于你使用的繪圖上下文的類型。
繪圖地點:圖形上下文(The Graphics Context)
圖形上下文(graphics context)是一個未開源的數據類型(CGContextRef),它包含了Quartz需要繪圖到輸出設備(如:PDF文件、bitmap、顯示器上的一個窗口等等)的信息。在圖形上下文中的信息,不僅包含繪圖需要的參數,還包含了特定設備的繪圖信息。所有Quartz需要的信息都包含在一個圖形上下文中。
你可以把一個圖形上下文看做繪圖的地方,就像 圖 1-2展示的那樣。當你使用Quartz繪圖時,所有指定設備的特征都包含在你使用的那個特定的圖形上下文中。換句話說,你可以僅僅為繪圖這一系列操作提供不同的圖形上下文就可以在不同的設備上繪制出相同的內容。
下列這些圖形上下文在你的應用程序用可以使用:
- 位圖圖形上下文允許你在位圖(bitmap)中繪制RGB顏色、CMYK顏色或者灰階(grayscale)。位圖是像素的矩形陣列(或柵格),每個像素表示圖像中的點。位圖圖像也稱為采樣圖像。請參閱創建位圖圖形上下文。
- PDF圖形上下文允許你創建PDF文件。在一個PDF文件中,你的繪圖操作將被當做一系列命令被保留。PDF文件和位圖有以下明顯的不同點:
- PDF文件可能擁有多個page(不像位圖只有一個)。
- 當您從不同設備上的PDF文件中繪制頁面時,生成的映像將針對該設備的顯示特性進行優化。
- 被繪制的PDF文件天生就可以在不損失細節的情況下無限放大和縮小,而位圖圖像的分辨率直接影響感官效果。
- 詳見創建PDF圖形上下文。
- 窗口(window)圖形上下文是一個你可以在窗口中繪制的圖形上下文。注意,因為Quartz 2D是一個圖形引擎而不是窗口管理系統,你可以使用應用程序的框架來獲取一個窗口的圖形上下文。詳見:在Mac OS X下創建窗口圖形上下文。
- 圖層上下文(CGLayerRef)是一個和其他圖形上下文關聯的一個離屏繪制的目標。它是為了在將圖層繪制到創建它的圖形上下文的最佳性能而設計的。在離屏繪制中,圖層上下文是一個比位圖圖形上下文更好的選擇。詳見:核心圖層繪制。
- 當你在Mac OS X中想要打印時,可以把要打印的內容發送到一個叫做PostScript 圖形上下文中,這個PostScript 圖形上下文在printing框架中。詳見:獲取打印的圖形上下文。
Quartz 2D 中的數據類型
Quartz 2D 的 API 定義了大量的不透明數據類型。因為這些 API 是Core Graphics 框架中的一部分,所以這些數據類型按照慣例都是以“CG”開頭的。
為了實現指定的繪圖輸出,你的應用程序運行Quartz 2D,并使用這些閉源的數據類型來創造對象。圖 1-3 展示了一系列你能夠使用Quartz 2D提供的三種數據類型來實現的不同效果。例如:
- 你能夠通過創建PDF page對象,應用旋轉變換,并將其繪制到圖形上下文中來實現旋轉并展示一個PDF page的效果。
- 你能夠通過創建一個樣章對象并定義構成圖案的形狀來進行相應的繪制。
- 你可以通過創建陰影對象來填充具有軸向或者鏡像的漸變區域。
Quartz 2D中包含的閉源數據類型如下:
- CGPathRef,用于你要填充或者描邊的矢量圖形。詳見:路徑。
- CGImageRef,通常代表根據您提供的樣本數據來表示位圖圖像和位圖圖像遮罩。詳見:位圖圖像和圖像遮罩。
- CGLayerRef,通常代表一個可以重復使用的或者離屏繪制的圖層。詳見:核心圖形圖層繪制。
- CGPatternRef,用于重復繪制。詳見:樣章。
- CGShadingRef和CGGradientRef,用于繪制漸變。詳見:漸變。
- CGFunctionRef,用于定義具有任意數量的浮點類型的參數的回調函數。當你在創建一個漸變時會用到這種數據類型,詳見:漸變。
- CGColorRef和CGColorSpaceRef,用來告知Quartz如何解析顏色。詳見:顏色和色域。
- CGImageSourceRef和CGImageDestinationRef,用來從Quartz中導入或導出數據。詳見:Quartz 2D的數據管理和Image I/O 編程指導。
- CGFontRef,用于繪制文字。詳見:文字(Text)。
- CGPDFDictionaryRef,CGPDFObjectRef,CGPDFPageRef,CGPDFStream,CGPDFStringRef和CGPDFArrayRef,這些類提供了獲取PDF元數據的方法。詳見:PDF文檔的創建、預覽和轉換。
- CGPDFSacnnerRef和CGPDFContenStreamRef,用來解析PDF元數據。詳見:PDF文檔解析。
- CGPSConverterRef,被用來將PostScript轉換成PDF,iOS中不可用。詳見:PostScript 轉換。
圖形狀態(Graphics States)
Quartz繪制的結果是根據存儲在當前圖形狀態(Graphics States)中的參數決定的。圖形狀態(Graphics States)中所包含的參數在相應的情況下會被用于繪制過程,這些參數的值決定了Quartz如何去渲染繪圖的結果。例如:當你使用一個函數去設置了填充顏色(fill color),那么你就修改了存儲在當前圖形狀態(Graphics States)中一個參數的值。其他一些經常使用的參數有:線寬、當前的位置、字體的大小等等。
圖形上下文(Graphics Context)使用棧的方式來存儲圖形狀態(Graphics States)。當Quartz創建圖形上下文時,這個棧是空的。當你保存保存圖形狀態(Graphics States)時,Quartz將當前圖形狀態的復制壓入到棧中。當你重置圖形狀態時,Quartz將棧頂的圖形狀態推出。推出之后棧中的圖形狀態成為了當前的圖形狀態。
如果想要保存當前的圖形狀態,那么可以使用CGContextSaveGState函數;如果要重置之前的圖形狀態,那么可以使用CGContextRestoreGState。
需要注意的是,不是所有當前繪畫涉及的內容都屬于圖形狀態的。例如:當前的路徑(path)就不是圖形狀態中的內容,因此,當你保存圖形狀態時并不會保存這些不屬于圖形狀態的內容。表 1-1 列舉了當調用保存狀態方法時會保存的圖形狀態參數:
表 1-1 圖形狀態相關參數
參數名 | 詳細講述章節 |
---|---|
當前變換矩陣(Current transformation matrix 也即CTM) | 變換 |
剪輯區域(Clipping area) | 路徑 |
線:寬度、連接、線帽、虛線、連接線的斜接限制(miter limit) | 路徑 |
曲線的平直度 | 路徑 |
抗鋸齒設置 | 圖形上下文 |
顏色:填充和描邊設置 | 顏色和色域 |
Alpha值(透明度) | 顏色和色域 |
渲染意圖 | 顏色和色域 |
色域:填充和描邊設置 | 顏色和色域 |
文字:字體、大小、間距、繪制模式 | 文字(Text) |
混色模式 | 路徑、位圖圖像與圖像遮罩 |
Quartz 2D 的坐標系
如圖1-4 所示,這個坐標系定義了位置的范圍,用它可以描述需要被繪制圖形的大小和位置。你可以在用戶空間坐標系統(user-space coordinate system)中指定位置和大小,簡稱為用戶空間(user space)。這個坐標系被定義為浮點值。
因為不同的設備具有不同的底層繪圖方式,所以圖形的位置和大小必須由這些獨立的設備單獨定義和管理。例如:一個屏幕可能能夠展示超過96個像素每英寸,而一個打印機能夠展示超過300個像素每英寸。如果以設備的級別來定義坐標系,那么繪制到該坐標系的圖形不能在視覺效果一致的情況下重新繪制到其他的設備上,它不是太大就是太小。
Quartz用一個單獨的坐標系使得設備變得獨立。利用當前變換矩陣(CTM)能夠將用戶空間(user-space)的坐標系映射成當前輸出設備的坐標系。矩陣是數學上的一個結構,用它來描述一系列相等關系是非常有效率的。當前變換矩陣(CTM)是一個特殊的矩陣,叫做仿射變換,仿射變換將一個坐標系的很多點映射到另一個坐標系的其他對應的點(通過平移、旋轉、縮放等操作)。
當前轉換矩陣(CTM)還有一個次要的目的:可以使用它改變對象的繪制。例如:繪制一個傾斜45°的盒子,你僅僅需要在繪制之前旋轉當前的坐標系(CTM),Quartz 繪制的輸出就自動使用了旋轉之后的坐標系。
一個點在用戶空間(user space)下用一個坐標對表示 (x,y) ,其中x代表水平(左和右)的距離,y代表距離垂直(上和下)的距離。坐標系的原點是(0,0),它在"頁"的左下角,如 圖1-4 所示。在Quartz默認的坐標系中,x從左向右時增加,y從下向上時增加。
在某些技術條件下所使用的圖形上下文的坐標系和Quartz默認的坐標系是不同的。對于Quartz而言,這些坐標系是被修改過的,因此當使用Quartz來進行一些繪圖操作時,就應該對此進行相應的補償。最常見的補償方式就是:將原點由左下角移動到左上角,并且y軸的正半軸方向向下延伸。下面是一些使用到上述坐標系的地方:
- 在 MAC OS X 中,當一個NSView的子類重寫了它的isFlipped方法并返回YES時。
- 在iOS中,使用UIView獲取到的繪圖上下文。
- 在iOS中,使用UIGraphicsBeginImageContextWithOptions方法獲取到的繪圖上下文。
UIKit之所以返回給Quartz的坐標系與Quartz默認的坐標系不一致,是因為UIKit默認使用另一個不同的坐標系。為了使得創建的Quartz上下文符合這個默認的坐標系,UIKit對其應用了變換。如果你想使用相同的坐標系來繪制UIView和一個PDF圖形上下文(由Quartz創建并使用Quartz默認的坐標系),你可以對PDF的圖形上下文進行相應的變換(將原點轉換到左上角,將y軸以scale的方式乘以-1)。
使用縮放(scale)的方式使y軸的方向改變后同時也改變了Quartz中一些默認的東西。例如:如果你在這樣的圖形上下文中調用CGContextDrawImage來繪制圖片時,它會被這個變換所修改。同樣,路徑繪制中所接受的參數(如弧的順時針、逆時針方向)也可能會被修改。如 圖1-5 所示,在默認的坐標系中是順時針繪制的,但是應用上述變換后,繪制的方向就變成了逆時針。
在Quartz繪制時,這些變換的應用完全取決于你的應用程序。例如,如果你想將一個圖片或者PDF正確的繪制到圖形上下文中,你的應用程序需要暫時調整該圖形上下文的CTM。在iOS中如果你使用一個UIImage對象來包裝你創建的一個CGImage對象,你不需要修改CTM,UIImage自動修改了UIKit對坐標系應用的變換。
重點:上述討論對于你想直接在iOS上使用Quartz是十分重要的,但是它還不足夠讓你徹底理解。在iOS 3.2和之后的版本中,當UIKit為你的應用程序創建圖形上下文時,它同時也附加了額外的操作使得這個圖形上下文能夠符合UIKit默認的坐標系標準。特別地,不受CTM影響的樣章(Patterns)和陰影(shadows)被單獨調整,使得它們的約定與UIKit的坐標系匹配。在這種情況下,您的應用程序不能使用等效的CTM機制來更改由Quartz創建的上下文以匹配UIKit提供的上下文的行為;您的應用程序必須意識到它正在什么樣的上下文中進行繪制,并調整其行為以符合上下文的期望。
內存管理:對象的歸屬(Object Ownership)
Quartz使用了Core Foundation 內存管理模型,即對象使用了引用計數。當創建時,這些對象具有1的引用計數。你可以通過調用函數增加對象的引用計數來保留這個對象,也可以調用相應的函數較少對象的引用計數來釋放對象。當對象的引用計數減少到0時,這個對象就會被釋放,這個模型提供了安全的對象共享方式。
你應當記住這三個簡單的規則:
- 如果你創建或者拷貝(copy)了一個對象,那么你就擁有它,因此你必須要釋放(release)它。也就是說,如果你使用帶有"Create"或者"Copy"這樣名字的方法獲得了這個對象,當你不需要使用時你就必須釋放它(release),否則就會造成內存泄露。
- 如果你沒有使用帶有"Create"或者"Copy"這樣名字的方法獲得了一個對象,那么你就沒有擁有這個對象的引用,因此不能釋放這個對象。這個對象在將來會被它的擁有者所釋放。
- 如果你沒有擁有一個對象,但是你需要讓他在你的使用周期內存在時,你必須retain它,當你不用時還要release它。你可以使用Quartz提供的方法來retain和release一個對象。例如:你得到一個CGColorspace對象,你可以使用CGColorSpaceRetain 方法和 CGColorSpaceRelease 方法來retain和release這個你需要的對象。同樣,你也可以使用 Core Foundation 提供的 CFReatin 和 CFRelease 方法,但是你一定要注意不要對這些方法傳入NULL。
上一章:Core Graphics(Quartz 2D)編程簡介
下一章:圖形上下文(Graphics Context)