Quartz2D --> 二維繪圖引擎(一 - 綜述、圖形上下文)

The Quartz 2D API is easy to use and provides access to powerful features such as transparency layers, path-based drawing, offscreen rendering, advanced color management, anti-aliased rendering, and PDF document creation, display, and parsing.

在官方文檔介紹中就已經(jīng)直述:Quartz 2D API易于使用和提供強(qiáng)大的特性,如透明層,基于路徑畫圖,離屏渲染,先進(jìn)的色彩管理,反鋸齒的渲染,PDF文檔創(chuàng)建、顯示、解析。

一、Quartz 2D 可以完成的功能:

  • 圖形繪制(繪圖,自定義控件,生成圖片等);
  • 在程序中提供圖形編輯功能(圖片剪輯等);
  • 創(chuàng)建或顯示 bitmap images;
  • 與PDF文件相關(guān)操作(讀取,創(chuàng)建,解析PDF文件等);

二、Quartz 2D 概述:

Quartz 2D是一個(gè)二維圖形繪制引擎,支持iOS環(huán)境和Mac OS X環(huán)境。我們可以使用Quartz 2D API來(lái)實(shí)現(xiàn)許多功能,如基本路徑的繪制、透明度、描影、繪制陰影、透明層、顏色管理、反鋸齒渲染、PDF文檔生成和PDF元數(shù)據(jù)訪問。
?在Mac OS X中,Quartz 2D可以與其它所有圖形圖像技術(shù)混合使用,如Core Image、Core Video、OpenGL、QuickTime。
?同樣,在iOS中Quartz 2D可以使用所有可用的圖形和動(dòng)畫技術(shù),如核心動(dòng)畫-Core Animation , OpenGL ES , UIKit類。

1、頁(yè)面(The Page)

Quartz 2D在圖像中使用了繪畫者模型(painter’s model)。在繪畫者模型中,每個(gè)連續(xù)的繪制操作都是將一個(gè)繪制層(a layer of ‘paint’)放置于一個(gè)畫布(‘canvas’),通常稱這個(gè)畫布為(Page)。 Page上的繪圖可以通過額外的繪制操作來(lái)疊加更多的繪圖。意味著每一次繪制都是一層,然后按照順序一層層的疊加到畫板上。Page上的圖形對(duì)象只能通過疊加更多的繪圖來(lái)改變而不能直接修改。這個(gè)模型允許我們使用小的圖元來(lái)構(gòu)建復(fù)雜的圖形。
?圖1-1展示了繪畫者模型如何工作。從圖中可以看出不同的繪制順序所產(chǎn)生的效果不一樣。在繪畫者模型中的順序是很重要的。

Figure 1-1

The Page可能是一個(gè)真正的紙(如果輸出設(shè)備是一臺(tái)打印機(jī));這可能是一個(gè)虛擬的紙(如果輸出設(shè)備是一個(gè)PDF文件),甚至可能是一個(gè)bitmap image。 The Page的確切性質(zhì)取決于你所使用的特定的圖形上下文(graphics context )。

2、繪制目標(biāo):圖形上下文(Drawing Destinations: The Graphics Context)

Graphics Context是一個(gè)不透明的數(shù)據(jù)類型(CGContextRef),用于封裝Quartz繪制圖像到輸出設(shè)備的信息,如PDF文件、bitmap圖片或者正在顯示的窗口。(所謂 “不透明”是指 opaque,指顏色不可復(fù)合顯示,與alpha是不一樣的!這種數(shù)據(jù)模型是C的結(jié)構(gòu)體,存儲(chǔ)了渲染到屏幕上需要的一切信息。 Graphics Context中的信息包括在Page中的圖像的圖形繪制參數(shù)和設(shè)備相關(guān)的表現(xiàn)形式。Quartz中所有的對(duì)象都是繪制到或者被包含到一個(gè)Graphics Context中。
?我們可以將Graphics Context作為繪制目標(biāo),如圖1-2所示。當(dāng)用Quartz繪圖時(shí),所有設(shè)備相關(guān)的特性都包含在我們所使用的Graphics Context中。換句話說(shuō),我們可以簡(jiǎn)單地給Quartz繪圖序列指定不同的Graphics Context,就可將相同的圖像繪制到不同的設(shè)備上。我們不需要任何設(shè)備相關(guān)的計(jì)算;這些都由Quartz替我們完成。

Figure 1-2

** Quartz 2D 提供了一下幾種類型的Graphics Context:**

  • Bitmap graphics context: 允許使用RGB colors、CMYK colors和 灰度模式。A bitmap 就是一個(gè)像素的矩形數(shù)組,每一個(gè)像素在圖片上一個(gè)點(diǎn)。Bitmap 圖片也稱為采樣圖片。
  • PDF graphics context: 允許創(chuàng)建一個(gè)PDF文件,在PDF中,你的繪制會(huì)作為一系列的命令被保存。在這里有一些值得注意的PDF files 和 bitmaps 的不同:
    • PDF files可能包含不止一個(gè)頁(yè)面,而 bitmaps只包含一個(gè)頁(yè)面;
    • 當(dāng)在不同設(shè)備中繪制頁(yè)面時(shí),結(jié)果圖片是對(duì)于該設(shè)備顯示性能來(lái)說(shuō)最優(yōu)的顯示結(jié)果圖片。
    • PDF本質(zhì)上是與分辨率無(wú)關(guān)的,尺寸上的增加和減少都不會(huì)犧牲圖像的細(xì)節(jié)。用戶感知的一個(gè)bitmap圖片的質(zhì)量與 該bitmap的分辨率相關(guān)聯(lián)。
  • Window graphics context: 允許在窗口內(nèi)繪制。因?yàn)镼uartz 2D是圖形引擎,而不是窗口管理系統(tǒng),所以你可以使用一個(gè)應(yīng)用程序框架獲得窗口的圖形上下文。
  • Layer Context: (CGLayerRef) 是一個(gè)與另一個(gè)graphics context有關(guān)系的幕后繪制目的的上下文。它旨在當(dāng)繪制layer層圖形上下文時(shí)提供最佳性能而創(chuàng)建。Layer Context 在幕后繪制方面相對(duì)于Bitmap graphics context來(lái)說(shuō)是一個(gè)更好的選擇。
  • PostScript graphics context: 當(dāng)你在Mac OS X情況下想要打印時(shí),你發(fā)送內(nèi)容內(nèi)容到由printing framework管理管理的PostScript graphics context。iOS下不可用!
3、Quartz 2D 數(shù)據(jù)類型

除了 Graphics Context 之外,Quartz 2D API還定義一些數(shù)據(jù)類型。由于這些API就Core Graphics框架的一部分,所以這些數(shù)據(jù)類型都是以CG開頭的。
?Quartz 2D使用這些數(shù)據(jù)類型來(lái)創(chuàng)建對(duì)象,通過操作這些對(duì)象來(lái)獲取特定的圖形。圖1-3例舉了三個(gè)使用Quartz 2D的繪制操作所獲得的圖像。

  • 你可以通過創(chuàng)建一個(gè)PDF 頁(yè)面對(duì)象,然后對(duì)圖形上下文應(yīng)用一個(gè)旋轉(zhuǎn)的操作,同時(shí)請(qǐng)求Quartz 2D將這一頁(yè)面繪制到圖形上下文來(lái)實(shí)現(xiàn)旋轉(zhuǎn)和顯示一個(gè)PDF頁(yè)面。
  • 你可以通過創(chuàng)建一個(gè)圖案對(duì)象,定義組成圖案的形狀模型及當(dāng)Quartz 2D繪制一個(gè)圖形上下文時(shí)設(shè)置Quartz 2D作為顏料被應(yīng)用于該圖案去繪制一個(gè)圖案。
  • 你可以通過創(chuàng)建一個(gè)底紋對(duì)象,同時(shí)提供一個(gè)確定在底紋上每一點(diǎn)的顏色的函數(shù),然后請(qǐng)求Quartz 2D使用這一底紋作為填充顏色的這樣一個(gè)軸向的或放射狀的底紋,去填充某一塊區(qū)域。
Figure 1-3

在Quartz 2D中可用的不透明數(shù)據(jù)類型包含以下幾種:

  • CGPathRef :用于向量圖,可創(chuàng)建路徑,并進(jìn)行填充(fill)或描畫(stroke),用來(lái)繪制路徑(注意帶有ref后綴的一般都是繪制的畫板);
  • CGImageRef: 用于描述你提供的bitmap images和基于樣本據(jù)的bitmap圖像遮罩;
  • CGLayerRef : 用于描述可用于重復(fù)繪制(如背景或圖案)和幕后繪制(offscreen drawing)的繪畫層(繪制layer,layer可復(fù)用,可離屏渲染);
  • CGPatternRef : 用于重繪;
  • CGShadingRef 和 CGGradientRef : 用于繪制漸變;
  • CGFunctionRef : 用于定義回調(diào)函數(shù),該函數(shù)包含一個(gè)隨機(jī)的浮點(diǎn)值參數(shù)。當(dāng)為陰影創(chuàng)建漸變時(shí)使用該類型;
  • CGColorRef 和 CGColorSpaceRef : 用于告訴Quartz如何解釋(描述)顏色(處理顏色);
  • CGImageSourceRef 和 CGImageDestinationRef : 用于在Quartz中移入移出數(shù)據(jù);
  • CGFontRef : 用于繪制文本;
  • CGPDFDictionaryRef, CGPDFObjectRef, CGPDFPageRef, CGPDFStream, CGPDFStringRef 和 CGPDFArrayRef : 提供PDF文檔元數(shù)據(jù)的訪問;
  • CGPDFScannerRef 和 CGPDFContentStreamRef : 用于解析PDF元數(shù)據(jù);
  • CGPSConverterRef : 用于將PostScript轉(zhuǎn)換為PDF。它在iOS是不可用的!
4、Graphics States(圖形狀態(tài))

Quartz通過修改當(dāng)前圖形狀態(tài)(current graphics state)來(lái)修改繪制操作的結(jié)果。圖形狀態(tài)包含用于繪制程序的參數(shù)。繪制程序根據(jù)這些繪圖狀態(tài)來(lái)決定如何渲染結(jié)果。例如,當(dāng)你調(diào)用設(shè)置填充顏色的函數(shù)時(shí),你將改變存儲(chǔ)在當(dāng)前繪圖狀態(tài)中的顏色值。當(dāng)前圖形狀態(tài)常用的元素有:線寬(line width)、當(dāng)前位置(position)、文本字體大?。╢ont)。
?Graphics Context包含一個(gè)繪圖狀態(tài)棧。當(dāng)Quartz創(chuàng)建一個(gè)Graphics Context時(shí),棧為空。當(dāng)保存圖形狀態(tài)時(shí),Quartz將當(dāng)前圖形狀態(tài)的一個(gè)副本壓入棧中。當(dāng)還原圖形狀態(tài)時(shí),Quartz將棧頂?shù)膱D形狀態(tài)出棧。出棧的狀態(tài)成為當(dāng)前圖形狀態(tài)。
?使用函數(shù)CG_EXTERN void CGContextSaveGState(CGContextRef cg_nullable c)來(lái)保存圖形狀態(tài),這里需要注意當(dāng)前路徑(The Current Path)不被認(rèn)為是圖形狀態(tài)的一部分,不會(huì)保存路徑。使用函數(shù)CG_EXTERN void CGContextRestoreGState(CGContextRef cg_nullable c)來(lái)出棧棧頂圖形狀態(tài)用以代替當(dāng)前圖形狀態(tài)(還原圖形狀態(tài))。

并不是當(dāng)前繪制環(huán)境的所有方面都是圖形狀態(tài)的元素,下面列表中參數(shù)在保存圖形狀態(tài)時(shí)會(huì)被保存:

Parameters 參數(shù)
Current transformation matrix (CTM) 當(dāng)前裝換矩陣
Clipping area 剪裁區(qū)域
Line: width, join, cap, dash, miter limit 線的寬度、連接風(fēng)格、線帽樣式、線條緩沖類型(虛線樣式)、斜接限制
Accuracy of curve estimation (flatness) 曲線平滑度
Anti-aliasing setting 反鋸齒設(shè)置
Color: fill and stroke settings 顏色填充和描繪設(shè)置
Alpha value (transparency) 透明度
Rendering intent 渲染目標(biāo)
Color space: fill and stroke settings 顏色空間填充和描繪設(shè)置
Text: font, font size, character spacing, text drawing mode 文本設(shè)置:字體、字體大小、字符間距、文字繪制模型
Blend mode 混合模型
5、Quartz 2D Coordinate Systems(Quartz 2D 坐標(biāo)系統(tǒng))

該坐標(biāo)系是以默認(rèn)是以左下為圓點(diǎn),是一個(gè)標(biāo)準(zhǔn)的數(shù)學(xué)坐標(biāo)系(注意區(qū)別于UIKit坐標(biāo)系),它定義了用于描述被繪制于畫布上的對(duì)象的位置和大小的位置范圍。

Figure 1-4

因?yàn)椴煌脑O(shè)備有不同的潛在成像能力,所以圖形位置和尺寸必須在定義時(shí)使用與設(shè)備無(wú)關(guān)的方式。例如,一個(gè)顯示設(shè)備的屏幕可能顯示不超過每英寸96個(gè)像素,而打印機(jī)可能能夠顯示每英寸300個(gè)像素。如果您定義坐標(biāo)系統(tǒng)在設(shè)備層面(在這個(gè)例子中,96像素或300像素),那么繪制于該空間的對(duì)象不可能在沒有明顯的失真的情況下復(fù)制在其他設(shè)備中,他們會(huì)出現(xiàn)太大或太小的情況。這顯然不是我們想要的。
? Quartz使用當(dāng)前變換矩陣(current transformation matrix又稱為 CTM)將一個(gè)獨(dú)立坐標(biāo)系統(tǒng)(用戶空間)映射到輸出設(shè)備的坐標(biāo)系統(tǒng)(設(shè)備空間)來(lái)實(shí)現(xiàn)設(shè)備獨(dú)立性。矩陣是用于高效的描述一組相關(guān)方程的數(shù)學(xué)架構(gòu),CTM是一種被稱為 affine transform (仿射變換)的特殊矩陣。關(guān)于仿射變換可以看一下這篇文章。但是CTM與文章中的略有不同,CTM主要變換的是 坐標(biāo)系!
?CTM還有一個(gè)次要目的:允許你通過轉(zhuǎn)換來(lái)決定對(duì)象如何被繪制。例如,為了繪制一個(gè)旋轉(zhuǎn)了45度的盒子,我們可以在繪制盒子之前旋轉(zhuǎn)Page的坐標(biāo)系統(tǒng)。Quartz使用旋轉(zhuǎn)過的坐標(biāo)系統(tǒng)來(lái)將盒子繪制到輸出設(shè)備中。
?有一些技術(shù)在設(shè)置它們的graphics context時(shí)使用了不同于Quartz的默認(rèn)坐標(biāo)系統(tǒng)。當(dāng)在這些坐標(biāo)系統(tǒng)中顯示Quartz繪制的圖形時(shí),Quartz的默認(rèn)坐標(biāo)系統(tǒng)必須進(jìn)行轉(zhuǎn)換。最常見的一種修改的坐標(biāo)系統(tǒng)是原點(diǎn)位于左上角,而沿著y軸從上到下坐標(biāo)值逐漸增大(即UIKit坐標(biāo)系)。例如:UIView的-(void)drawRect:方法(這個(gè)方法在loadView、viewDidLoad方法后執(zhí)行)中直接獲取上下文的方法UIGraphicsGetCurrentContext()返回的圖形上下文就是用的是這種坐標(biāo)系。這是因?yàn)閁IKit類已經(jīng)對(duì)上下文進(jìn)行了額外的修改以匹配UIKit的約定。但是有一些方法在錄入 graphics context 時(shí)是使用的Quartz的默認(rèn)坐標(biāo)系統(tǒng),例如CG_EXTERN void CGContextDrawImage(CGContextRef cg_nullable c, CGRect rect, CGImageRef cg_nullable image)方法將圖片繪制于上下文中時(shí)就是使用的Quartz的默認(rèn)坐標(biāo)系統(tǒng)。特別的,patterns和shadows不被CTM影響,是單獨(dú)進(jìn)行調(diào)整以來(lái)匹配UIKit坐標(biāo)系統(tǒng)。
?注意: 轉(zhuǎn)換坐標(biāo)系前,應(yīng)使用CG_EXTERN void CGContextSaveGState(CGContextRef cg_nullable c)保存當(dāng)前上下文狀態(tài);然后當(dāng)轉(zhuǎn)換后一系列操作完成后再使用CG_EXTERN void CGContextRestoreGState(CGContextRef cg_nullable c)恢復(fù)之前保存的上下文狀態(tài)

6、Memory Management: Object Ownership(內(nèi)存管理:對(duì)象所有權(quán))

Quartz使用Core Foundation內(nèi)存管理機(jī)制-引用計(jì)數(shù)。在Quartz中使用需要注意以下幾點(diǎn):

  • 如果你創(chuàng)建或復(fù)制一個(gè)對(duì)象,你擁有它,因此你必須釋放它。一般來(lái)說(shuō),如果你從一個(gè)函數(shù)名包含“Create”或者“Copy”的函數(shù)中獲得一個(gè)對(duì)象,當(dāng)你使用結(jié)束時(shí)就必須釋放對(duì)象,否則會(huì)導(dǎo)致內(nèi)存泄漏。
  • 相反,如果使用不含有”Create”或“Copy”的函數(shù)獲取一個(gè)對(duì)象,你將不會(huì)擁有對(duì)象的引用,不需要釋放它。
  • 如果你尚未擁有該對(duì)象同時(shí)打算持有它的引用,則必須retain它并且在不需要時(shí)release掉。可以使用Quartz 2D的特有函數(shù)來(lái)指定retain和release該對(duì)象。例如,如果創(chuàng)建了一個(gè)CGColorspace對(duì)象,則使用函數(shù)CG_EXTERN CGColorSpaceRef cg_nullable CGColorSpaceRetain(CGColorSpaceRef cg_nullable space)CG_EXTERN void CGColorSpaceRelease(CGColorSpaceRef cg_nullable space)來(lái)retain和release對(duì)象。同樣,可以使用Core Foundation的CFTypeRef CFRetain(CFTypeRef cf);void CFRelease(CFTypeRef cf);,但是注意不能傳遞NULL值給這些函數(shù)。

三、Graphics Contexts(圖形上下文)

一個(gè)Graphics Context表示一個(gè)繪制目標(biāo)。它包含繪制系統(tǒng)用于完成繪制指令的繪制參數(shù)和設(shè)備相關(guān)信息。Graphics Context定義了基本的繪制屬性,如顏色、裁減區(qū)域、線條寬度和樣式信息、字體信息、混合模式等。
?我們可以通過幾種方式來(lái)獲取Graphics Context:Quartz提供的創(chuàng)建函數(shù)、Mac OS X框架或IOS的UIKit框架提供的函數(shù)。Quartz提供了多種Graphics Context的創(chuàng)建函數(shù),包括bitmap和PDF,我們可以使用這些Graphics Context創(chuàng)建自定義的內(nèi)容。
?本節(jié)主要介紹如何為不同的繪制目標(biāo)創(chuàng)建Graphics Context。在代碼中,我們用數(shù)據(jù)類型 -- CGContextRef 來(lái)表示一個(gè)Graphics Context。當(dāng)獲得一個(gè)Graphics Context后,可以使用Quartz 2D函數(shù)在上下文(context)中進(jìn)行繪制、完成操作(如平移)、修改圖形狀態(tài)參數(shù)(如線寬和填充顏色)等。

1、Drawing to a View Graphics Context in iOS

在iOS應(yīng)用程序中,如果要在屏幕上進(jìn)行繪制,需要?jiǎng)?chuàng)建一個(gè)UIView對(duì)象,并實(shí)現(xiàn)它的- (void)drawRect:(CGRect)rect:方法。

- (void)drawRect:(CGRect)rect:方法調(diào)用的時(shí)機(jī)與使用注意:

  • drawRect:在UIViewController的loadViewviewDidLoad兩方法之后調(diào)用;
  • 當(dāng)view需要被刷新或者重繪,drawRect:方法就會(huì)被調(diào)用,但是如果在UIView初始化時(shí)沒有設(shè)置frame,drawRect:將不會(huì)被自動(dòng)調(diào)用!!!
  • 重繪時(shí)應(yīng)該調(diào)用setNeedsDisplay方法,而不能直接調(diào)用drawRect:方法,setNeedsDisplay會(huì)自動(dòng)調(diào)用drawRect:,如果設(shè)置UIView的contentMode屬性值為UIViewContentModeRedraw,那么將在每次更改frame時(shí)自動(dòng)調(diào)用drawRect:方法;
  • 當(dāng)重寫drawRect:方法后,作為配置的一部分,系統(tǒng)視圖對(duì)象將為當(dāng)前的繪圖環(huán)境創(chuàng)建一個(gè)Graphics Context。我們可以通過調(diào)用UIGraphicsGetCurrentContext()函數(shù)來(lái)獲取這個(gè)Graphics Context。
2、Creating a PDF Graphics Context

當(dāng)創(chuàng)建一個(gè)PDF Graphics Context并繪制時(shí),Quartz將繪制操作記錄為一系列的PDF繪制命令并寫入文件中。我們需要提供一個(gè)PDF輸出的位置及一個(gè)默認(rèn)的media box(用于指定頁(yè)面邊界的長(zhǎng)方形)。

Quartz 2D API提供了兩個(gè)函數(shù)來(lái)創(chuàng)建PDF Graphics Context。

  • CG_EXTERN CGContextRef __nullable CGPDFContextCreateWithURL(CFURLRef cg_nullable url, const CGRect * __nullable mediaBox, CFDictionaryRef __nullable auxiliaryInfo)
  • CG_EXTERN CGContextRef __nullable CGPDFContextCreate(CGDataConsumerRef cg_nullable consumer, const CGRect *__nullable mediaBox, CFDictionaryRef __nullable auxiliaryInfo)

PS:示例代碼

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    // create PDF
    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentPath = paths[0];
    NSString * filePath = [documentPath stringByAppendingString:@"text_1.pdf"];
    NSLog(@"%@", filePath);
    const char * cFilePath = [filePath UTF8String];
    CFStringRef pathRef = CFStringCreateWithCString(kCFAllocatorDefault, cFilePath, kCFStringEncodingUTF8);
    CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, pathRef, kCFURLPOSIXPathStyle, 0);
    // 凡是使用包含Create或者Copy字符的函數(shù)名創(chuàng)建的對(duì)象,在使用完后一定要釋放!
    CFRelease(pathRef);
    // 這本字典包含額外的選項(xiàng),主要用于簽署的PDF
    CFMutableDictionaryRef muDicRef = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(muDicRef, kCGPDFContextTitle, CFSTR("My Text_1 PDF File"));
    CFDictionarySetValue(muDicRef, kCGPDFContextAuthor, CFSTR("xun mi"));
    CGRect mediaBoxRect = self.view.frame;
    CGContextRef pdfContextRef = CGPDFContextCreateWithURL(urlRef, &mediaBoxRect, muDicRef);
#pragma -------------> 另一種方法創(chuàng)建 PDF context
//    CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithURL(urlRef);
//    CGContextRef pdfContextRef = CGPDFContextCreate(dataConsumer, &mediaBoxRect, muDicRef);
    CFRelease(urlRef);
    CFRelease(muDicRef);
#pragma -------------> 至此PDF context 創(chuàng)建完畢,下面就可以 drawing
    // 創(chuàng)建頁(yè)面
    CGContextBeginPage(pdfContextRef, &mediaBoxRect);
    CGContextSetRGBFillColor(pdfContextRef, 1, 0, 0, 1);
    CGContextFillRect(pdfContextRef, CGRectMake(50, 200, 100, 100));
    CGContextSetRGBStrokeColor(pdfContextRef, 30.0/255, 79.0/255, 233.0/255, 1);
    CGContextStrokeRect(pdfContextRef, CGRectMake(75, 100, 50, 300));
    // 使某一區(qū)域可以響應(yīng)超鏈接
    CFURLRef url = CFURLCreateWithString(NULL, CFSTR("http://www.baidu.com"), NULL);
    CGContextSetRGBFillColor (pdfContextRef, 0, 0, 1, 0.5);
    CGContextFillRect (pdfContextRef, CGRectMake (200, 200, 100, 200 ));
    CGPDFContextSetURLForRect(pdfContextRef, url, CGRectMake (200, 200, 100, 200 ));
    CFRelease(url);
    CGPDFContextEndPage(pdfContextRef);
    CGContextRelease(pdfContextRef);
}
生成的PDF文件,其中藍(lán)色區(qū)域可以響應(yīng)百度的鏈接。
3、Creating a Bitmap Graphics Context

一個(gè)Bitmap Graphics Context接受一個(gè)指向內(nèi)存緩存(包含位圖存儲(chǔ)空間)的指針,當(dāng)你在一個(gè)Bitmap Graphics Context中繪制時(shí),該緩存被更新。在釋放Graphics Context后,你將得到一個(gè)我們指定像素格式的全新的Bitmap。
?在iOS應(yīng)用程序一般使用UIKIT_EXTERN void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)而不是使用低等級(jí)的Quartz函數(shù)。如果使用Quartz創(chuàng)建一個(gè)后臺(tái)bitmap,bitmap Graphics Context使用的坐標(biāo)系統(tǒng)是Quartz默認(rèn)的坐標(biāo)系統(tǒng)。而使用UIGraphicsBeginImageContextWithOptions創(chuàng)建圖形上下文,將會(huì)與UIKit坐標(biāo)系統(tǒng)相匹配。這可以使你的應(yīng)用程序使用相同的繪制代碼而不需要擔(dān)心坐標(biāo)系統(tǒng)問題。雖然我們的應(yīng)用程序可以手動(dòng)調(diào)整CTM達(dá)到相同的效果,但這種做沒有任何好處。
PS:示例代碼

- (void)drawRect:(CGRect)rect {
// 這里最終繪制在了UIGraphicsGetCurrentContext()獲取的上下文中,所以最終顯示的坐標(biāo)系與UIKit相同。
    CGContextRef currentContextRef = UIGraphicsGetCurrentContext();
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;//一個(gè)指向內(nèi)存目標(biāo)的指針,該內(nèi)存用于存儲(chǔ)需要渲染的圖形數(shù)據(jù)。內(nèi)存塊的大小至少需要(bytePerRow * height)字節(jié)
    int             bitmapByteCount; // 渲染圖像所需總共的字節(jié)數(shù)
    int             bitmapBytesPerRow;
    CGFloat pixelsWide = 200;//指定位圖的寬度,單位是像素(pixel)
    CGFloat pixelsHigh = 400;//指定位圖的高度,單位是像素(pixel)
    bitmapBytesPerRow   = (pixelsWide * 4);//指定位圖每行的字節(jié)數(shù)
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);
    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 顏色空間
    bitmapData = calloc(bitmapByteCount, sizeof(uint8_t));
    if (bitmapData == NULL){
        fprintf (stderr, "Memory not allocated!");
    }else{
        context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
//        context =  CGBitmapContextCreateWithData(bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast, NULL, NULL);
        if (context== NULL){
            free (bitmapData);
            fprintf (stderr, "Context not created!");
        }
    }
    CGColorSpaceRelease(colorSpace);
    CGRect myBoundingBox = self.frame;
    CGContextSetRGBFillColor (context, 1, 0, 0, 1);
    CGContextFillRect (context, CGRectMake (0, 0, 200, 100 ));
    CGContextSetRGBFillColor (context, 0, 0, 1, 0.5);
    CGContextFillRect (context, CGRectMake (0, 0, 100, 200 ));
    CGImageRef myImage = CGBitmapContextCreateImage (context);
    CGContextDrawImage(currentContextRef, myBoundingBox, myImage);
    char *bitmapData_char = CGBitmapContextGetData(context);
    CGContextRelease (context);
    if (bitmapData_char) free(bitmapData_char);
    CGImageRelease(myImage);
}
    TextView_1 * view_c = [[TextView_1 alloc] initWithFrame:CGRectMake(0, 100, 100, 200)];
    [self.view addSubview:view_c];

使用UIGraphicsBeginImageContextWithOptions() 創(chuàng)建:

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 1.0);
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    UIBezierPath * bezierPath = [UIBezierPath bezierPath];
    [[UIColor redColor] set];
    [bezierPath moveToPoint:CGPointMake(0, 100)];
    [bezierPath addQuadCurveToPoint:CGPointMake(100, 100) controlPoint:CGPointMake(50, 0)];
    [bezierPath closePath];
    CGContextAddPath(currentContext, bezierPath.CGPath);
    CGContextDrawPath(currentContext, kCGPathStroke);
    UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(150, 100, 100, 100)];
    imageView.image = image;
    imageView.layer.borderWidth = 1.0;
    imageView.layer.borderColor = [UIColor blackColor].CGColor;
    [self.view addSubview:imageView];
視覺效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容