Quartz 2D是二維圖形繪制引擎斋荞,可以實(shí)現(xiàn)N多圖形圖像的操作功能虐秦,如基本路徑的繪制悦陋、透明度俺驶、描影棍辕、繪制陰影楚昭、透明層抚太、顏色管理昔案、反鋸齒踏揣、PDF文檔生成和PDF元數(shù)據(jù)訪問(wèn)捞稿。
畫(huà)布Page
在圖像操作過(guò)程中使用了繪畫(huà)者模型括享,繪制過(guò)程是將繪制層鋪到畫(huà)布上珍促,這個(gè)畫(huà)布稱為Page猪叙。類似于Photoshop中穴翩,將每個(gè)圖層疊加放在畫(huà)布上,形成最后的圖像歉嗓。
圖形上下文Graphics Context
圖形上下文(Graphics Context)是一個(gè)數(shù)據(jù)類型CGContextRef鉴分,它存放了Quartz 2D繪制的圖形輸出信息志珍,可以看做是圖形到設(shè)備輸出的介質(zhì)工具伦糯。Quartz 2D繪制的圖形可以放到多種設(shè)備上,比如:PDF文件喂击、顯示器窗口惭等、bitmap(位圖)辞做、view的Layer層等等秤茅,這就需要不同的Graphics Context來(lái)完成輸出到不同設(shè)備上的工作童叠。這好比人要上高速需要汽車厦坛,去海上需要船杜秸,去天空需要飛機(jī)撬碟,這里人相當(dāng)于圖形,高速路惶傻、海银室、天空相當(dāng)于設(shè)備蜈敢,而汽車扶认、船殊橙、飛機(jī)就是Graphics Context。
Graphics Context的幾種類型:
1. Bitmap Graphics Context
2. PDF Graphics Context
3. Window Graphics Context
4. Layer Context
5. Post Graphics Context
Quartz 2D的數(shù)據(jù)類型
Quartz 2D API屬于Code Graphics框架季研,所以Quartz 2D的數(shù)據(jù)類型是以CG開(kāi)頭的与涡。有以下數(shù)據(jù)類型:
1. CGPathRef:用于向量圖驼卖,可創(chuàng)建路徑酌畜,并進(jìn)行填充或描畫(huà)(stroke)
2. CGImageRef:用于表示bitmap圖像和基于采樣數(shù)據(jù)的bitmap圖像遮罩桥胞。
3. CGLayerRef:用于表示可用于重復(fù)繪制(如背景)和幕后(offscreen)繪制的繪畫(huà)層
4. CGPatternRef:用于重繪圖
5. CGShadingRef贩虾、CGGradientRef:用于繪制漸變
6. CGFunctionRef:用于定義回調(diào)函數(shù)沥阱,該函數(shù)包含一個(gè)隨機(jī)的浮點(diǎn)值參數(shù)喳钟。當(dāng)為陰影創(chuàng)建漸變時(shí)使用該類型
7. CGColorRef, CGColorSpaceRef:用于告訴Quartz如何解釋顏色
8. CGImageSourceRef,CGImageDestinationRef:用于在Quartz中移入移出數(shù)據(jù)
9. CGFontRef:用于繪制文本
10. CGPDFDictionaryRef, CGPDFObjectRef, CGPDFPageRef, CGPDFStream, CGPDFStringRef, and CGPDFArrayRef:用于訪問(wèn)PDF的元數(shù)據(jù)
11. CGPDFScannerRef, CGPDFContentStreamRef:用于解析PDF元數(shù)據(jù)
12. CGPSConverterRef:用于將PostScript轉(zhuǎn)化成PDF。在iOS中不能使用易茬。
圖形狀態(tài)
Quartz通過(guò)修改圖形狀態(tài)來(lái)修改繪制結(jié)果抽莱,圖形狀態(tài)直接決定了圖形的最終渲染結(jié)果骄恶。圖形狀態(tài)包含用于繪制程序的參數(shù)僧鲁,繪制參數(shù)改變了,圖形自然就變了偶惠。比如修改了填充色值忽孽,圖形顏色就變了兄一。
iOS中使用Graphics Context繪制圖形
在iOS中要想用Quartz 2D在屏幕上繪圖瘾腰,需要自定義一個(gè)UIView覆履,在UIView的- (void)drawRect:(CGRect)rect方法中實(shí)現(xiàn)繪圖操作栖雾,這個(gè)方法會(huì)在UIView顯示在屏幕上和需要被刷新的時(shí)候調(diào)用伟众。創(chuàng)建上下文的方法如下:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
}
在上下文中繪制圖形:
- (void)drawRect:(CGRect)rect {
//獲取圖形上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//設(shè)置紅色透明度0.5的填充色
CGContextSetRGBFillColor(context, 1, 0, 0, 0.5);
//填充一個(gè)矩形frame為(10, 20, 100, 40)
CGContextFillRect(context, CGRectMake(10, 20, 100, 40));
//設(shè)置藍(lán)色透明度0.5的填充色
CGContextSetRGBFillColor(context, 0, 0, 1, 0.5);
//填充一個(gè)矩形frame為(10, 20, 40, ?100)
CGContextFillRect(context, CGRectMake(10, 20, 40, 100));
}
注意:設(shè)置填充色和填充矩形的方法順序不能顛倒账胧,不然填充色填充不到想填充的矩形中治泥。得不到填充色填充的會(huì)是黑色居夹。
路徑
路徑可以構(gòu)建出多種圖形,可以是點(diǎn)本冲、直線准脂、弧線、不規(guī)則線檬洞、規(guī)則或不規(guī)則形狀狸膏,可以對(duì)閉合路徑進(jìn)行填充行程面。使用路徑繪制出想要的圖形添怔,有兩步:創(chuàng)建路徑和繪制路徑湾戳。創(chuàng)建出點(diǎn)、線等路徑院塞,使用函數(shù)CGContextDrawPath繪制路徑遮晚。
點(diǎn)
點(diǎn)是依靠x、y值固定的位置拦止,可作為路徑的起始點(diǎn)位置县遣。比如要畫(huà)一個(gè)線段,必須要有一個(gè)起點(diǎn)和一個(gè)終點(diǎn)汹族,兩點(diǎn)確定一條線段萧求。使用函數(shù)CGContextMoveToPoint來(lái)確定起始點(diǎn),傳入圖形上下文和x,y坐標(biāo)點(diǎn)顶瞒。
//確定一個(gè)坐標(biāo)為(10,10)的點(diǎn)
CGContextMoveToPoint(context, 10, 10);
直線
有起始點(diǎn)夸政,再指定一個(gè)終點(diǎn)位置就能確定一條直線了,使用函數(shù)CGContextAddLineToPoint來(lái)指定終點(diǎn)位置榴徐。
- (void)drawRect:(CGRect)rect {
//獲取圖形上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//設(shè)置起點(diǎn)
CGContextMoveToPoint(context, 20, 20);
//起點(diǎn)延長(zhǎng)至終點(diǎn)位置
CGContextAddLineToPoint(context, 50, 50);
//繪制路徑
CGContextDrawPath(context, kCGPathStroke);
}
可以使用CGContextAddLineToPoint函數(shù)指定多個(gè)位置點(diǎn)守问,線段會(huì)一個(gè)接一個(gè)畫(huà)下去,形成折線圖形坑资。也可以使用CGContextAddLines函數(shù)一次性指定多個(gè)位置點(diǎn)耗帕,完成折線圖形,此時(shí)無(wú)需指定起始點(diǎn)袱贮,第一個(gè)點(diǎn)默認(rèn)為起始點(diǎn)(即使用CGContextMoveToPoint指定起始點(diǎn)也無(wú)效)仿便。
//一個(gè)一個(gè)點(diǎn)繼續(xù)加
CGContextMoveToPoint(context, 20, 20);
CGContextAddLineToPoint(context, 50, 50);
CGContextAddLineToPoint(context, 30, 80);
//一次性指定多個(gè)點(diǎn)
CGPoint pos[3] = {CGPointMake(80, 20), CGPointMake(20, 50), CGPointMake(100, 200)};
CGContextAddLines(context, pos, 3);
由于CGContextAddLineToPoint函數(shù)必須得有CGContextMoveToPoint函數(shù)固定起始點(diǎn),CGContextAddLines函數(shù)默認(rèn)第一個(gè)點(diǎn)為起始點(diǎn)攒巍,所以CGContextAddLines后面可以跟著CGContextAddLineToPoint繼續(xù)加點(diǎn)畫(huà)線嗽仪,能連成一組折線,而CGContextMoveToPoint+CGContextAddLineToPoint畫(huà)線后面不能跟CGContextAddLines柒莉,會(huì)畫(huà)成兩組無(wú)關(guān)聯(lián)的折線闻坚。
圓弧
畫(huà)圓弧提供了兩個(gè)函數(shù),一個(gè)是CGContextAddArc常柄,依次指定圖形上下文鲤氢、圓心坐標(biāo)、半徑西潘、起始弧度、終止弧度哨颂、畫(huà)線順時(shí)針(1)或逆時(shí)針(0)喷市。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddArc(context, 100, 200, 30, 0, M_PI, 0);
CGContextDrawPath(context, kCGPathStroke);
第二個(gè)函數(shù)是CGContextAddArcToPoint,三點(diǎn)+半徑確定一個(gè)圓弧威恼。CGContextMoveToPoint函數(shù)確定第一個(gè)點(diǎn)品姓,CGContextAddArcToPoint添加第二個(gè)點(diǎn)寝并、第三個(gè)點(diǎn)和還有半徑。原理:以第二點(diǎn)為中心腹备,分別向第一點(diǎn)衬潦、第三點(diǎn)延長(zhǎng)兩條射線,射線夾角小于180°的一側(cè)植酥,以指定半徑畫(huà)圓弧,圓弧與射線相切。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100);
CGContextAddArcToPoint(context, 100, 150, 150, 150, 50);
CGContextDrawPath(context, kCGPathStroke);
曲線
畫(huà)Bezier曲線也提供了兩個(gè)函數(shù)洞渔,函數(shù)CGContextAddCurveToPoint用于畫(huà)三次Bezier曲線蹬屹,由一個(gè)起點(diǎn)、一個(gè)終點(diǎn)和兩個(gè)控制點(diǎn)構(gòu)成一條三次Bezier曲線卸留。當(dāng)兩個(gè)控制點(diǎn)在起點(diǎn)和終點(diǎn)連線的同側(cè)時(shí)走越,曲線會(huì)只有一個(gè)拱向,在不同側(cè)時(shí)有兩個(gè)拱向耻瑟。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100);
CGContextAddCurveToPoint(context, 150, 50, 200, 200, 300, 100);
CGContextDrawPath(context, kCGPathStroke);
畫(huà)二次Bezier曲線旨指,使用函數(shù)CGContextAddQuadCurveToPoint。以當(dāng)前點(diǎn)為起始點(diǎn)喳整,指定一個(gè)控制點(diǎn)一個(gè)終點(diǎn)淤毛,確定一條二次Bezier曲線∷懔控制點(diǎn)決定了曲線拱的方向低淡,該函數(shù)只能創(chuàng)建一個(gè)拱向的Bezier曲線,而且曲線不可能交叉瞬项。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100);
CGContextAddQuadCurveToPoint(context, 200, 200, 300, 100);
CGContextDrawPath(context, kCGPathStroke);
閉合路徑
Quartz 2D提供函數(shù)CGContextClosePath來(lái)閉合路徑蔗蹋。就是將終點(diǎn)和起點(diǎn)用直線連接起來(lái),使整個(gè)路徑閉合囱淋。對(duì)于直線猪杭、弧、曲線等不能自動(dòng)閉合的路徑妥衣,如果想完成路徑閉合必須調(diào)用該函數(shù)皂吮。
調(diào)用了CGContextClosePath完成閉合路徑后,再調(diào)用Add...添加路徑的函數(shù)税手,添加直線蜂筹、弧線、曲線等路徑芦倒,會(huì)從閉合路徑的起始點(diǎn)開(kāi)始艺挪。如果沒(méi)有完成閉合路徑函數(shù)的調(diào)用,則從終點(diǎn)繼續(xù)開(kāi)始新添加的路徑兵扬。 ?
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100);
CGContextAddCurveToPoint(context, 150, 50, 150, 200, 300, 100);
CGContextClosePath(context);
CGContextAddLineToPoint(context, 200, 500);
CGContextDrawPath(context, kCGPathStroke);
矩形
使用函數(shù)CGContextAddRect來(lái)畫(huà)矩形麻裳,函數(shù)中的rect中x,y是矩形左上角口蝠,寬高是矩形的寬高。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddRect(context, CGRectMake(20, 20, 100, 40));
CGContextDrawPath(context, kCGPathStroke);
橢圓
使用函數(shù)CGContextAddEllipseInRect來(lái)畫(huà)橢圓津坑,是以矩形來(lái)確定橢圓妙蔗。坐標(biāo)參數(shù)意義和矩形一樣,以確定的矩形內(nèi)切畫(huà)出的橢圓疆瑰。矩形的圓心即是橢圓的圓心眉反,矩形的寬高即是橢圓的長(zhǎng)軸短軸,當(dāng)矩形的寬高相等時(shí)乃摹,橢圓就是一個(gè)圓了禁漓。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(context, CGRectMake(0, 0, 30, 50));
CGContextDrawPath(context, kCGPathStroke);
創(chuàng)建路徑
*在開(kāi)始繪制路徑前,調(diào)用 CGContextBeginPath 或 UI孵睬。
*直線播歼、弧、曲線開(kāi)始于當(dāng)前點(diǎn)掰读∶啬空路徑?jīng)]有當(dāng)前點(diǎn);我們必須調(diào)用CGContextMoveToPoint來(lái)設(shè)置第一個(gè)子路徑的起始點(diǎn)蹈集,或者調(diào)用一個(gè)便利函數(shù)來(lái)隱式地完成該任務(wù)烁试。
*如果要閉合當(dāng)前子路徑,調(diào)用函數(shù) CGContextClosePath拢肆。隨后路徑將開(kāi)始一個(gè)新的子路徑减响,即使我們不顯示設(shè)置一個(gè)新的起始點(diǎn)。
*當(dāng)繪制弧時(shí)郭怪,Quartz 將在當(dāng)前點(diǎn)與弧的起始點(diǎn)間繪制一條直線支示。
*添加橢圓和矩形的 Quartz 程序?qū)⒃诼窂街刑砑有碌拈]合子路徑。
*我們必須調(diào)用繪制函數(shù)來(lái)填充或者描邊一條路徑鄙才,因?yàn)閯?chuàng)建路徑時(shí)并不會(huì)繪制路徑颂鸿。
*Quartz 提供了兩個(gè)數(shù)據(jù)類型來(lái)創(chuàng)建可復(fù)用路徑 CGPathRef 和 CGMutablePathRef。
*Quartz 提供了一個(gè)類似于操作圖形上下文的 CGPath 的函數(shù)集合攒庵。這些路徑函數(shù)操作 CGPath 對(duì)象嘴纺,而不是圖形上下文。
1.? ? CGPathCreateMutable 取代 CGContextBeginPath
2. ? ?CGPathMoveToPoint 取代 CGContextMoveToPoint
3. ? ?CGPathAddLineToPoint 取代 CGContexAddLineToPoint
4. ? ?CGPathAddCurveToPoint 取代 CGContexAddCurveToPoint
5. ? ?CGPathAddEllipseInRect 取代 CGContexAddEllipseInRect
6. ? ?CGPathAddArc 取代 CGContexAddArc
7. ? ?CGPathAddRect 取代 CGContexAddRect
8. ? ?CGPathCloseSubpath 取代 CGContexClosePath
如果想要添加一個(gè)路徑到圖形上下文浓冒,可以調(diào)用CGContextAddPath栽渴。路徑將保留在圖形上下文中,直到Quartz繪制它裆蒸。我們可以調(diào)用CGContextAddPath再次添加路徑熔萧。
繪制路徑
通過(guò)圖形上下文加上一系列創(chuàng)建路徑的函數(shù)得到最終的路徑,還需要繪制路徑操作僚祷,才能使得路徑呈現(xiàn)佛致。如上文中一直用到的繪制路徑的函數(shù)操作CGContextDrawPath(context, kCGPathStroke);。
繪制路徑分為描邊和填充辙谜,描邊是繪制路徑的邊框俺榆,填充是繪制路徑所包含的區(qū)域。
影響描邊的屬性
填充路徑
填充規(guī)則有兩種:非零纏繞數(shù)規(guī)則(nonzero winding number rule)装哆、偶數(shù)-奇數(shù)規(guī)則(even-odd rule)罐脊。
默認(rèn)的填充規(guī)則為非零纏繞數(shù)規(guī)則。方法或枚舉帶有“EO”的為偶數(shù)-奇數(shù)規(guī)則蜕琴。
非零纏繞數(shù)的填充規(guī)則與繪制的方向有關(guān)萍桌、偶數(shù)-奇數(shù)規(guī)則則與方向無(wú)關(guān)。如圖凌简。
CGContextDrawPath函數(shù)的使用:
*CGContextDrawPath(context, kCGPathFill) 填充路徑上炎。
*CGContextDrawPath(context, kCGPathEOFill) 使用奇偶規(guī)則填充路徑。
*CGContextDrawPath(context, kCGPathStroke) 描邊路徑雏搂。
*CGContextDrawPath(context, kCGPathFillStroke) 填充并描邊路徑藕施。
*CGContextDrawPath(context, kCGPathEOFillStroke) 使用奇偶規(guī)則填充并描邊路徑。
混合模式
混合模式是Quartz將繪圖繪制到背景上的方式凸郑,其實(shí)就是前景圖和背景圖怎么混合疊加裳食。疊加公式如下:
result = (alpha * foreground) + (1 - alpha) *background
Quartz默認(rèn)使用普通混合模式,也就是kCGBlendModeNormal芙沥。下面舉例幾個(gè)混合模式的樣式诲祸,案例樣式的代碼見(jiàn)下一節(jié)裁剪路徑:
裁剪路徑
裁剪是一個(gè)遮罩,會(huì)遮住不允許繪制的地方而昨。裁剪區(qū)域是一個(gè)閉合路徑救氯,Quartz只會(huì)渲染裁剪區(qū)域里面的東西,外面的東西不渲染配紫。通過(guò)函數(shù)CGContextClip裁剪径密,具體的裁剪代碼和執(zhí)行結(jié)果如下,注意代碼位置:
參考文章:南峰子翻譯的Quartz2D編程指南
原文:http://mp.weixin.qq.com/s/Sbt2goTNRDjgGQpmuus_gQ