iOS Quartz2D

一悲敷、簡(jiǎn)介

Quartz 2D是一個(gè)二維圖形繪制引擎究恤,支持iOS環(huán)境和Mac OS X環(huán)境。我們可以使用Quartz 2D API來(lái)實(shí)現(xiàn)許多功能后德,如繪制基本路徑部宿、圖形,繪制文字探遵、陰影窟赏、圖層,繪制和生成圖片(圖像)箱季,讀取和生成PDF涯穷,自定義UI控件。
Quartz 2D在圖像中使用了繪畫者模型(painter’s model)藏雏。在繪畫者模型中拷况,每個(gè)連續(xù)的繪制操作都是將一個(gè)繪制層(a layer of ‘paint’)放置于一個(gè)畫布,我們通常稱這個(gè)畫布為(Page)掘殴。 Page上的繪圖可以通過額外的繪制操作來(lái)疊加更多的繪圖赚瘦。Page上的圖形對(duì)象只能通過疊加更多的繪圖來(lái)改變。這個(gè)模型允許我們使用小的圖形元素來(lái)構(gòu)建復(fù)雜的圖形奏寨。不同的繪制順序所產(chǎn)生的效果也是不一樣的起意。Page可以是一張紙(如果輸出設(shè)備是打印機(jī))逞力,也可以是虛擬的紙張(如果輸出設(shè)備是PDF文件)最楷,還可以是bitmap圖像。這根據(jù)實(shí)際使用的graphics context而定粟关。

1.圖形上下文

Graphics Context是一個(gè)數(shù)據(jù)類型(CGContextRef)套菜,用于封裝Quartz繪制圖像到輸出設(shè)備的信息亲善,輸出設(shè)備可以是PDF文件、bitmap或者顯示器的窗口上逗柴。Graphics Context中的信息包括了Page中的圖像的圖形繪制參數(shù)和設(shè)備相關(guān)的表現(xiàn)形式蛹头。當(dāng)使用Quartz繪圖時(shí),所有設(shè)備相關(guān)的特性都包含在我們所使用的Graphics Context中。簡(jiǎn)單地說渣蜗,給Quartz繪圖序列指定不同的Graphics Context屠尊,就可將相同的圖像繪制到不同的設(shè)備上。

Quartz提供了以下幾種類型的Graphics Context:

  • Bitmap Graphics Context
  • PDF Graphics Context
  • Window Graphics Context
  • Layer Context
  • Post Graphics Context

2.數(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)獲取特定的圖形。

下面列出了Quartz 2D包含的數(shù)據(jù)類型:

  • CGPathRef:用于向量圖止潘,可創(chuàng)建路徑掺炭,并進(jìn)行填充或描畫
  • CGImageRef:用于表示bitmap圖像和基于采樣數(shù)據(jù)的bitmap圖像遮罩。
  • CGLayerRef:用于表示可用于重復(fù)繪制(如背景)和幕后(offscreen)繪制的繪畫層
  • CGPatternRef:用于重繪圖
  • CGShadingRef凭戴、CGGradientRef:用于繪制漸變
  • CGFunctionRef:用于定義回調(diào)函數(shù)涧狮,該函數(shù)包含一個(gè)隨機(jī)的浮點(diǎn)值參數(shù)。當(dāng)為陰影創(chuàng)建漸變時(shí)使用該類型
  • CGColorRef, CGColorSpaceRef:用于使用什么樣顏色么夫,顏色空間
  • 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中不能使用。

3.坐標(biāo)系統(tǒng)

坐標(biāo)系統(tǒng)定義是被繪制到Page上的對(duì)象的位置及大小范圍档痪。由于不同的設(shè)備有不同的圖形功能涉枫,所以圖像的位置及大小依賴于設(shè)備。如果在設(shè)備級(jí)別上定義坐標(biāo)系統(tǒng)腐螟,則在一個(gè)設(shè)備上繪制的圖形無(wú)法在其它設(shè)備上正常顯示愿汰。
Quartz通過使用當(dāng)前轉(zhuǎn)換矩陣(current transformation matrix, CTM)將一個(gè)獨(dú)立的坐標(biāo)系統(tǒng)(user space)映射到輸出設(shè)備的坐標(biāo)系統(tǒng)(device space)乐纸,以此來(lái)解決設(shè)備依賴問題衬廷。 CTM是一種特殊類型的矩陣(affine transform, 仿射矩陣),通過平移(translation)汽绢、旋轉(zhuǎn)(rotation)吗跋、縮放(scale)操作將點(diǎn)從一個(gè)坐標(biāo)空間映射到另外一個(gè)坐標(biāo)空間。
UIKit默認(rèn)的坐標(biāo)系統(tǒng)與Quartz不同宁昭。在UIKit中跌宛,原點(diǎn)位于左上角,y軸正方向?yàn)橄蛳戮每摺IView通過將修改Quartz的Graphics Context的CTM[原點(diǎn)平移到左下角秩冈,同時(shí)將y軸反轉(zhuǎn)(y值乘以-1)]以使其與UIView匹配本缠。

4.內(nèi)存管理

Quartz使用Core Foundation內(nèi)存管理斥扛。所以,對(duì)象的創(chuàng)建與銷毀與通常的方式是一樣的。在Quartz中稀颁,需要記住如下一些規(guī)則:

如果創(chuàng)建或拷貝一個(gè)對(duì)象芬失,你將擁有它,因此你必須釋放它匾灶。通常棱烂,如果使用含有”Create”或“Copy”單詞的函數(shù)獲取一個(gè)對(duì)象,當(dāng)使用完后必須釋放阶女,否則將導(dǎo)致內(nèi)存泄露颊糜。
如果使用不含有”Create”或“Copy”單詞的函數(shù)獲取一個(gè)對(duì)象,你將不會(huì)擁有對(duì)象的引用秃踩,不需要釋放它衬鱼。
如果你不擁有一個(gè)對(duì)象而打算保持它,則必須retain它并且在不需要時(shí)release掉憔杨∧窈眨可以使用Quartz 2D的函數(shù)來(lái)指定retain和release一個(gè)對(duì)象。例如消别,如果創(chuàng)建了一個(gè)CGColorspace對(duì)象抛蚤,則使用函數(shù)CGColorSpaceRetain和CGColorSpaceRelease來(lái)retain和release對(duì)象。同樣寻狂,可以使用Core Foundation的CFRetain和CFRelease岁经,但是注意不能傳遞NULL值給這些函數(shù)。

5.部分API

方法 說明
UIGraphicsGetCurrentContext() 獲取當(dāng)前圖形上下文
CGContextAddPath(CGContextRef c, CGPathRef path) 將路徑添加到圖形上下文中
CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y) 在當(dāng)前路徑中從點(diǎn)(x荆虱,y)開始創(chuàng)建一個(gè)新路徑
CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y) 從當(dāng)前點(diǎn)添加一個(gè)直線段到點(diǎn)(x蒿偎,y)
CGContextAddRect(CGContextRef,rect) 在上下文路徑中添加一個(gè)矩形
CGContextAddEllipseInRect(CGContextRef c, CGRect rect) 在上下文路徑中添加一個(gè)橢圓
CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise) 在上下文路徑中添加一個(gè)圓弧,點(diǎn)(x怀读,y)為圓心诉位,radius為半徑,startAngle為開始角度菜枷,endAngle為結(jié)束角度苍糠,clockwise:伸展方向,為0是順時(shí)針啤誊,為1是逆時(shí)針
CGContextAddArcToPoint(CGContextRef c,CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius) 以當(dāng)前點(diǎn)到點(diǎn)(x1岳瞭,y1),和(x1蚊锹,y1)到(x2瞳筏,y2)的兩條線段為切線,畫一條半徑為radius的圓弧
CGContextAddCurveToPoint(CGContextRef c, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y) 在當(dāng)前點(diǎn)添加一個(gè)三次貝塞爾曲線牡昆,控制點(diǎn)1(cp1x姚炕,cp1y),控制點(diǎn)2(cp2x,cp2y)柱宦,結(jié)束點(diǎn)(x些椒,y)
CGContextAddQuadCurveToPoint(CGContextRef c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y) 在當(dāng)前點(diǎn)添加一個(gè)二次貝塞爾曲線,控制點(diǎn)(cpx掸刊,cpy)免糕,結(jié)束點(diǎn)(x,y)
CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode) 設(shè)置繪制模式
CGContextStrokePath(CGContextRef c) 封閉所有路徑忧侧,將圖形上下文的路徑描線
CGContextFillPath(CGContextRef c) 封閉所有路徑石窑,將圖形上下文的路徑填充
CGContextClosePath(CGContextRef c) 把當(dāng)前點(diǎn)和起點(diǎn)連接起來(lái)形成封閉路徑
CGContextClip(CGContextRef c) 裁剪當(dāng)前圖形上下文中交叉的路徑并使用,將所生成的路徑作為后續(xù)渲染操作的路徑
CGContextSetLineWidth(CGContextRef c, CGFloat width) 設(shè)置線寬
CGContextSetLineDash(CGContextRef c, CGFloat phase, const CGFloat * lengths, size_t count) 設(shè)置虛線(點(diǎn)線模式)蚓炬,phase表示繪制第一條虛線時(shí)跳過多少個(gè)點(diǎn)尼斧,lengths 用來(lái)指明虛線如何交替繪制,count 為數(shù)組lengths的長(zhǎng)度
CGContextSetRGBStrokeColor(CGContextRef c, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) 設(shè)置Stroke渲染時(shí)顏色试吁,也可以使用UIColor的setStroke方法來(lái)設(shè)置棺棵,set方法同時(shí)設(shè)置StrokeColor和FillColor
CGContextSetRGBFillColor(CGContextRef, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) 設(shè)置Fill渲染時(shí)顏色,也可以使用UIColor的setFill方法來(lái)設(shè)置熄捍,set方法同時(shí)設(shè)置StrokeColor和FillColor
CGContextSetLineCap(CGContextRef c, CGLineCap cap) 設(shè)置線段頭尾部樣式
CGContextSetLineJoin(CGContextRef c, CGLineJoin join) 設(shè)置線段連接點(diǎn)樣式
CGContextSetTextDrawingMode(CGContextRef c, CGTextDrawingMode mode) 設(shè)置文字繪制模式
CGContextSetBlendMode(CGContextRef c, CGBlendMode mode) 設(shè)置混合模式
CGContextSetShadow(CGContextRef c, CGSize offset, CGFloat blur) 設(shè)置陰影烛恤,offset 為陰影在X,Y方向上的偏移量余耽;blur 為陰影的模糊程度缚柏,值越大,陰影越模糊碟贾。
CGContextSetShadowWithColor(CGContextRef c, CGSize offset, CGFloat blur, CGColorRef color) 其他參數(shù)和上一個(gè)方法一樣币喧,只是多了個(gè) color ,用來(lái)設(shè)置陰影顏色
CGContextSaveGState(CGContextRef c) 將當(dāng)前的圖形上下文拷貝一份,保存到圖形上下文棧的棧頂袱耽,路徑不被視為圖形狀態(tài)的一部分杀餐,因此不保存
CGContextRestoreGState(CGContextRef c) 將棧頂?shù)膱D形上下文出棧,替換當(dāng)前的圖形上下文
CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy) 對(duì)當(dāng)前轉(zhuǎn)換矩陣作縮放操作
CGContextRotateCTM(CGContextRef c, CGFloat angle) 對(duì)當(dāng)前轉(zhuǎn)換矩陣作旋轉(zhuǎn)操作
CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty) 對(duì)當(dāng)前轉(zhuǎn)換矩陣作平移操作
CGContextConcatCTM(CGContextRef c, CGAffineTransform transform) 通過 transform 變換矩陣來(lái)對(duì) CGContextRef 的 轉(zhuǎn)換矩陣(坐標(biāo)系統(tǒng))進(jìn)行變換
CGAffineTransform CGContextGetCTM(CGContextRef c) 獲取 CGContextRef 的坐標(biāo)系統(tǒng)的變換矩陣

注: 填充一個(gè)路徑的時(shí)候朱巨,路徑里面的子路徑都是獨(dú)立填充的史翘。假如是重疊的路徑,決定一個(gè)點(diǎn)是否被填充冀续,有兩種規(guī)則:

1.nonzero winding number rule:非零繞數(shù)規(guī)則琼讽,假如一個(gè)點(diǎn)被從左到右跨過,計(jì)數(shù)器+1洪唐,從右到左跨過钻蹬,計(jì)數(shù)器-1,最后凭需,如果結(jié)果是0问欠,那么不填充桂敛,如果是非零,那么填充溅潜。
2.even-odd rule: 奇偶規(guī)則,假如一個(gè)點(diǎn)被跨過薪伏,那么+1滚澜,最后是奇數(shù),那么要被填充嫁怀,偶數(shù)則不填充设捐,和方向沒有關(guān)系。

二塘淑、簡(jiǎn)單使用

1.繪制基本圖形

在 - (void)drawRect:(CGRect)rect 方法中調(diào)用 Quartz2D 的 API

繪制主要步驟:
1.獲得圖形上下文
2.繪制并拼接繪圖路徑
3.將路徑添加到圖形上下文中
4.渲染圖形上下文

① 繪制線段

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 100, 100);
CGContextStrokePath(ctx);

② 繪制三角形

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 120, 80);
CGContextAddLineToPoint(ctx, 0, 0);
//或者 CGContextClosePath(ctx);
CGContextStrokePath(ctx);  //描線
//CGContextFillPath(ctx);  //填充

③ 繪制矩形/正方形

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextStrokePath(ctx);  //描線
//CGContextFillPath(ctx);  //填充

④ 繪制橢圓/圓

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextStrokePath(ctx);  //描線
//CGContextFillPath(ctx);  //填充

⑤ 繪制圓環(huán)

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetLineWidth(ctx, 20); //線寬
CGContextStrokePath(ctx);  

⑥ 繪制圓弧

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddArc(ctx, 100, 100, 50, 0, M_PI, 1);
CGContextStrokePath(ctx);  

⑦ 繪制虛線
CGContextSetLineDash(CGContextRef c, CGFloat phase, const CGFloat * lengths, size_t count)萝招,用來(lái)設(shè)置怎樣來(lái)繪制虛線。

lengths 指明虛線如何交替繪制存捺,若lengths 的值為{10槐沼,10},表示先繪制10個(gè)點(diǎn)捌治,在跳過10個(gè)點(diǎn)岗钩,在繪制10個(gè)點(diǎn),在跳過10個(gè)點(diǎn)肖油,如此反復(fù)兼吓;若lengths的值為{10,20森枪,10}视搏,表示先繪制10個(gè)點(diǎn),跳過20個(gè)點(diǎn)县袱,繪制10個(gè)點(diǎn)浑娜,跳過10個(gè)點(diǎn),繪制20個(gè)點(diǎn)式散,跳過10個(gè)點(diǎn)棚愤,如此反復(fù);數(shù)組中的值循環(huán)使用杂数。
phase 表示繪制第一條虛線時(shí)跳過多少個(gè)點(diǎn)宛畦,若 phase 為 8,lengths 為 {10揍移,10}次和,則繪制第一條虛線時(shí),先跳過8個(gè)點(diǎn)那伐,在繪制(10 - 8)個(gè)點(diǎn)踏施,第一條虛線的長(zhǎng)度僅有2個(gè)點(diǎn)石蔗;phase 的值僅影響第一條虛線的繪制;
count 的值為數(shù)組lengths的長(zhǎng)度畅形。

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat lengths[] = {10.0,10.0}; 
CGContextSetLineDash(ctx, 0, lengths, 2);
CGContextMoveToPoint(ctx, 10, 50);
CGContextAddLineToPoint(ctx, 300, 50);
CGContextStrokePath(ctx);

⑧ 繪制曲線
CGContextAddCurveToPoint(CGContextRef c, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y) 用來(lái)在當(dāng)前點(diǎn)的位置開始繪制一條三次貝塞爾曲線养距,參數(shù)為兩個(gè)控制點(diǎn) (cp1x,cp1y) 和 (cp2x日熬,cp2y) 棍厌,還有一個(gè)結(jié)束點(diǎn)(x,y);

三次貝塞爾曲線.gif

CGContextAddQuadCurveToPoint(CGContextRef c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y) 用來(lái)在當(dāng)前點(diǎn)的位置開始繪制一條二次貝塞爾曲線竖席,參數(shù)為一個(gè)控制點(diǎn)(cpx耘纱,cpy) 和 一個(gè)結(jié)束點(diǎn)(x,y);

二次貝塞爾曲線.gif
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctx, 50, 50);
CGContextAddQuadCurveToPoint(ctx, 125, 184, 300, 50);
CGContextAddCurveToPoint(ctx, 200, 100, 10, 300, 200, 500);
CGContextStrokePath(ctx);

⑨ 繪制圓角矩形
自定義一個(gè)函數(shù)毕荐,來(lái)繪制圓角矩形束析。

 void CGContextAddRoundRect(CGContextRef __nullable c, CGRect rect, CGFloat radius){
    CGContextSaveGState(c);
    CGFloat x = rect.origin.x;
    CGFloat y = rect.origin.y;
    CGFloat width = rect.size.width;
    CGFloat height = rect.size.height;

    CGContextMoveToPoint(c, x + radius, y);
    CGContextAddLineToPoint(c, x + width - radius, y);
    CGContextAddArcToPoint(c, x + width, y, x + width, y + radius, radius);
    CGContextAddLineToPoint(c, x + width, y + height - radius);
    CGContextAddArcToPoint(c, x + width, y + height, x + width - radius, y + height, radius);
    CGContextAddLineToPoint(c, x + radius, y + height);
    CGContextAddArcToPoint(c, x, y + height, x, y + height - radius, radius);
    CGContextAddLineToPoint(c, x, y + radius);
    CGContextAddArcToPoint(c, x, y, x + radius, y, radius);
    CGContextRestoreGState(c);
}

⑩ 繪制多角星(限定角數(shù)為奇數(shù))
自定義一個(gè)函數(shù),來(lái)繪制奇數(shù)多角形憎亚。

void CGContextAddStar(CGContextRef __nullable c, NSInteger n, CGFloat dx, CGFloat dy, CGFloat radius){
    CGContextSaveGState(c);
    CGContextMoveToPoint(c, dx , dy - radius);
    CGFloat angle = 4 * M_PI / n;

    for (int i = 1; i <= n; i++) {
        CGFloat x = dx - sinf(i * angle) * radius;
        CGFloat y = dy - cosf(i * angle) * radius;
        CGContextAddLineToPoint(c, x, y);
    }
    CGContextRestoreGState(c);
}

2.繪制文字

使用NSString的 drawAtPoint:withAttributes: 方法 和 drawInRect:withAttributes: 方法

方法 說明
- (void)drawAtPoint:(CGPoint)point withAttributes:(NSDictionary *)attrs 在某個(gè)點(diǎn)開始繪制文字
- (void)drawInRect:(CGRect)rect withAttributes:(NSDictionary *)attrs 在一個(gè)范圍內(nèi)繪制文字

① 繪制文字

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetTextDrawingMode(ctx, kCGTextStroke);
CGContextSetShadowWithColor(ctx, CGSizeMake(8, -6), 5, [UIColor grayColor].CGColor);
NSString * str = @"Quartz2D";
NSMutableDictionary * attrs = [NSMutableDictionary dictionary];
attrs[NSForegroundColorAttributeName] = [UIColor redColor];
attrs[NSFontAttributeName] = [UIFont systemFontOfSize:18];
[str drawAtPoint:CGPointZero withAttributes:attrs];
[str drawInRect:CGRectMake(0, 0, 100, 100) withAttributes:attrs];

② 在圖片上繪制文字(圖片水釉笨堋)

UIImage * oldImage = [UIImage imageNamed:@"image"];
//創(chuàng)建一個(gè)基于位圖的上下文(context),并將其設(shè)置為當(dāng)前上下文(context),size:大小第美,opaque:是否透明丁恭,scale:縮放比例
UIGraphicsBeginImageContextWithOptions(oldImage.size, NO, 0.0);
 //在指定的點(diǎn)開始繪畫圖片,相當(dāng)于在圖片上添加了一個(gè)空白的圖層
[oldImage drawAtPoint:CGPointZero];
NSString * text =  @"quartz2D";
NSDictionary *dict = @{
                       NSFontAttributeName : [UIFont systemFontOfSize:15],
                       NSForegroundColorAttributeName : [UIColor redColor]
                       };
//在圖層上繪制文字
[text drawAtPoint:CGPointZero withAttributes:dict];
// 通過當(dāng)前的圖形上下文獲取圖片
UIImage * newImage =  UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉圖形上下文
UIGraphicsEndImageContext();
imageView.image = newImage;

3.漸變填充

CGGradientRef 用來(lái)繪制漸變的對(duì)象斋日。

方法 說明
CGGradientCreateWithColors(CGColorSpaceRef space, CFArrayRef colors, const CGFloat * locations) 通過顏色數(shù)組來(lái)創(chuàng)建CGGradientRef
CGGradientCreateWithColorComponents(CGColorSpaceRef space, const CGFloat * components, const CGFloat * locations, size_t count) 通過自定義顏色組件來(lái)創(chuàng)建CGGradientRef
CGGradientRelease(CGGradientRef gradient) 釋放漸變對(duì)象

CGColorSpaceRef : 用來(lái)定義顏色空間牲览,所謂顏色空間,簡(jiǎn)單的說就是不同顏色在不同的維度上取值最終組成一種顏色的過程恶守。例如RGB第献,可以看成是一個(gè)三維坐標(biāo)系,x兔港、y庸毫、z軸坐標(biāo)系分別代表紅、綠衫樊、藍(lán)三種顏色飒赃,那么在這三個(gè)坐標(biāo)上分別取0~255范圍內(nèi)的不同值就可以組成各類顏色。當(dāng)然科侈,不同顏色空間的“坐標(biāo)系”(顏色模型)是不同的(即顏色表示的方式是不同的)载佳,常用的顏色空間有RGB、CMYK臀栈、Gray等蔫慧。
CGColorRef : CoreGaphics中顏色對(duì)象

方法 說明
CGColorSpaceCreateDeviceRGB( ) 創(chuàng)建RGB顏色空間
CGColorSpaceCreateDeviceCMYK( ) 創(chuàng)建CMYK顏色空間
CGColorSpaceCreateDeviceGray( ) 創(chuàng)建Gray顏色空間
CGColorSpaceRelease(CGColorSpaceRef space) 釋放顏色空間
CGColorCreate(CGColorSpaceRef space, const CGFloat * components) 在顏色空間中根據(jù)顏色組件創(chuàng)建一個(gè)顏色對(duì)象

components : 顏色組件的數(shù)組,這個(gè)數(shù)組中具體如何存儲(chǔ)顏色要根據(jù)顏色空間而定权薯;如果顏色空間使用的是RGB姑躲,那么數(shù)組中的元素四個(gè)為一組睡扬,分別是red(紅)、green(綠)黍析、blue(藍(lán))卖怜、alpha(透明度);如果使用CMYK顏色空間阐枣,那么數(shù)組中的元素五個(gè)為一組马靠,分別是cyan(青)、magenta(洋紅)侮繁、yellow(黃)、black(黑)如孝、alpha(透明度)宪哩。

locations : 漸變色所在的位置,默認(rèn)范圍是0.0 ~ 1.0第晰。一個(gè)位置對(duì)應(yīng)著一組顏色組件表示的顏色

count : locations數(shù)組的長(zhǎng)度

注:使用方法名中帶有“Create”字樣的方法創(chuàng)建出來(lái)的對(duì)象锁孟,在該對(duì)象不再使用時(shí),要使用對(duì)象的Release方法銷毀對(duì)象茁瘦。

繪制漸變填充有兩種方式:
① 線性漸變:漸變色以直線方式從開始位置逐漸向結(jié)束位置漸變
② 徑向漸變:漸變色以中心點(diǎn)為圓心開始向四周輻射品抽,直到終止?jié)u變

方法 說明
CGContextDrawLinearGradient(CGContextRef c, CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options) 繪制線性漸變,startPoint : 開始位置甜熔,endPoint : 結(jié)束位置圆恤,options : 繪制方式
CGContextDrawRadialGradient(CGContextRef c, CGGradientRef gradient, CGPoint startCenter, CGFloat startRadius, CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options) 繪制徑向漸變,startCenter : 開始位置腔稀,startRadius : 起點(diǎn)半徑(通常為0盆昙,否則在此該半徑范圍內(nèi)容無(wú)任何填充內(nèi)容),endCenter : 結(jié)束位置(通常和起始點(diǎn)相同焊虏,否則會(huì)有偏移)淡喜,endRadius : 終點(diǎn)半徑(漸變的擴(kuò)散圓范圍),options : 繪制方式

CGGradientDrawingOptions : 漸變的繪制方式有兩種诵闭;
kCGGradientDrawsBeforeStartLocation 開始位置之前就進(jìn)行繪制炼团,到結(jié)束位置之后不再繪制;
kCGGradientDrawsAfterEndLocation開始位置之前不進(jìn)行繪制疏尿,到結(jié)束點(diǎn)之后繼續(xù)填充瘟芝。

① 繪制線性漸變

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef beginColor = CGColorCreate(rgbSpace, (CGFloat[]){0.0, 0.0, 0.0, 1.0});
CGColorRef endColor = CGColorCreate(rgbSpace, (CGFloat[]){1.0, 1.0, 1.0, 1.0});
// 創(chuàng)建顏色數(shù)組
CFArrayRef colors = CFArrayCreate(kCFAllocatorDefault, (const void*[]){beginColor, endColor}, 2, nil); 
CGFloat locations[2] = {0, 1.0};
CGGradientRef gradient = CGGradientCreateWithColors(rgbSpace, colors, locations);
CFRelease(colors);
CGColorRelease(beginColor);
CGColorRelease(endColor);
CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0, 0), CGPointMake(0, 500), kCGGradientDrawsAfterEndLocation);
CGColorSpaceRelease(rgbSpace);
CGGradientRelease(gradient);

② 繪制徑向漸變

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
CGFloat compoents[12] = {
    1.0, 1.0, 1.0, 1.0,
    0.5, 0.5, 0.5, 1.0,
    0.0, 0.0, 0.0, 1.0
};
CGFloat locations[3] = {0, 0.5, 1.0};
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgbSpace, compoents, locations, 3);
CGPoint startCenter = CGPointMake(200, 320);
CGPoint endCenter = CGPointMake(160, 280);
CGContextDrawRadialGradient(ctx, gradient, startCenter, 10, endCenter, 150, kCGGradientDrawsBeforeStartLocation);
CGColorSpaceRelease(rgbSpace);
CGGradientRelease(gradient);

4.模式填充

使用自定義的一種樣式在一個(gè)區(qū)域上平鋪填充,類似于鋪瓷磚褥琐。這里用“磚塊”來(lái)代表自定義的樣式模狭。Quartz 2D支持兩種模式填充:有顏色填充和無(wú)顏色填充;有顏色填充就是在繪制磚塊時(shí)就指定顏色踩衩,在調(diào)用填充時(shí)就不用再指定磚塊顏色嚼鹉;無(wú)顏色模式就是繪制磚塊時(shí)不用指定任何顏色贩汉,在調(diào)用填充時(shí)再指定具體填充顏色。推薦使用前者锚赤。

需要構(gòu)建一個(gè)符合CGPatternDrawPatternCallback簽名的回調(diào)函數(shù)匹舞,遵守 void 函數(shù)名 (void * info,CGContextRef context)的簽名,這個(gè)函數(shù)專門用來(lái)創(chuàng)建“磚塊”线脚。

方法 說明
CGColorSpaceCreatePattern(CGColorSpaceRef baseSpace) 創(chuàng)建模式填充的顏色空間赐稽,在有顏色模式填充下,baseSpace的值為NULL浑侥;在無(wú)顏色模式填充下姊舵,baseSpace的值為基于設(shè)備的顏色空間。
CGContextSetFillColorSpace(CGContextRef c, CGColorSpaceRef space) 在圖形上下文中設(shè)置顏色空間
CGPatternCreate(void * info, CGRect bounds, CGAffineTransform matrix, CGFloat xStep, CGFloat yStep, CGPatternTiling tiling, bool isColored, const CGPatternCallbacks * callbacks) 創(chuàng)建CGPatternRef寓落,info : 傳遞給callback的參數(shù)括丁,bounds : “磚塊”的大小,matrix : 轉(zhuǎn)換矩陣伶选,xStep : “磚塊”橫向間距史飞,yStep : “磚塊”縱向間距,tiling : 平鋪模式仰税,isColored : 是否指定了顏色构资,callbacks : 回調(diào)函數(shù)結(jié)構(gòu)體指針。
CGColorCreateWithPattern(CGColorSpaceRef space, CGPatternRef pattern, const CGFloat * components) 通過填充模式顏色組件創(chuàng)建顏色
CGContextSetFillPattern(CGContextRef c, CGPatternRef pattern, const CGFloat * components) 設(shè)置填充模式顏色組件
CGContextSetFillColorWithColor(CGContextRef c, CGColorRef color) 設(shè)置圖形上下文填充顏色
CGContextFillRect(CGContextRef c, CGRect rect) 填充一個(gè)區(qū)域
CGPatternRelease(CGPatternRef pattern) 釋放CGPatternRef對(duì)象

① 有顏色模式填充

void ColoredPatternCallback(void * info, CGContextRef context){
    CGFloat side = 20;
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextFillRect(context, CGRectMake(0, 0, side, side));
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillRect(context, CGRectMake(0, side, side, side));
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillRect(context, CGRectMake(side, 0, side, side));
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextFillRect(context, CGRectMake(side, side, side, side));
}

- (void)drawRect:(CGRect)rect{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(NULL);
    CGContextSetFillColorSpace(ctx, colorSpace);
    CGPatternCallbacks callback = {0,ColoredPatternCallback,NULL};
    CGPatternRef pattern = CGPatternCreate(NULL, CGRectMake(0, 0, 40, 40), CGAffineTransformIdentity, 40, 40, kCGPatternTilingNoDistortion, true, &callback);
    CGFloat alpha = 1;
    CGColorRef color = CGColorCreateWithPattern(colorSpace, pattern, &alpha);
    CGContextSetFillColorWithColor(ctx, color);
    CGContextFillRect(ctx, CGRectMake(0, 0, 320, 500));
    CGColorRelease(color);
    CGColorSpaceRelease(colorSpace);
    CGPatternRelease(pattern);
}

② 無(wú)顏色模式填充

void PatternCallback(void * info,CGContextRef context){
    CGContextFillRect(context, CGRectMake(0, 0, 20, 20));
    CGContextFillRect(context, CGRectMake(20, 20, 20, 20));
}

- (void)drawRect:(CGRect)rect{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
    CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(rgbSpace);
    CGContextSetFillColorSpace(ctx, colorSpace);
    CGContextSetStrokeColorSpace(ctx, colorSpace);
    CGPatternCallbacks callback = {0, PatternCallback, NULL};
    CGPatternRef pattern = CGPatternCreate(NULL, CGRectMake(0, 0, 40, 40), CGAffineTransformIdentity, 40, 40, kCGPatternTilingNoDistortion, false, &callback);
    CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
    CGContextSetFillPattern(ctx, pattern, components);
    CGContextSetStrokePattern(ctx, pattern, components);
    CGContextFillRect(ctx, CGRectMake(20, 20, 200, 200));
    CGContextStrokeRectWithWidth(ctx, CGRectMake(20,240, 200, 200), 5);
    CGColorSpaceRelease(rgbSpace);
    CGColorSpaceRelease(colorSpace);
    CGPatternRelease(pattern);
}

5.繪制位圖

方法 說明
UIGraphicsBeginImageContext(CGSize size) 開啟一個(gè)繪制位圖的圖形上下文陨簇,size 為區(qū)域大小
UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) 開啟一個(gè)繪制位圖的圖形上下文吐绵,size 為區(qū)域大小,opaque 設(shè)置透明河绽,為YES代表透明拦赠,NO代表不透明,scale代表縮放葵姥,0.0 代表不縮放荷鼠,可以用[UIScreen mainScreen].scale來(lái)獲取
UIGraphicsGetImageFromCurrentImageContext() 從圖形上下文中獲取當(dāng)前繪制的圖形,該方法返回一個(gè)UIImage對(duì)象
UIGraphicsEndImageContext() 關(guān)閉圖形上下文
UIRectFill(CGRect rect) 在當(dāng)前繪圖環(huán)境所創(chuàng)建的內(nèi)存中的圖片上填充一個(gè)矩形
UIRectFillUsingBlendMode(CGRect rect, CGBlendMode blendMode) 在當(dāng)前繪圖環(huán)境所創(chuàng)建的內(nèi)存中的圖片上填充一個(gè)矩形榔幸,繪制時(shí)使用指定的混合模式
UIRectFrame(CGRect rect) 在當(dāng)前繪圖環(huán)境所創(chuàng)建的內(nèi)存中的圖片上繪制一個(gè)矩形邊框
UIRectFrameUsingBlendMode(CGRect rect, CGBlendMode blendMode) 在當(dāng)前繪圖環(huán)境所創(chuàng)建的內(nèi)存中的圖片上繪制一個(gè)矩形邊框允乐,繪制時(shí)使用指定的混合模式
UIRectClip(CGRect rect) 裁剪當(dāng)前圖形上下文中的區(qū)域

UIImage 本身也提供了一些方法:

方法 說明
- (void)drawAtPoint:(CGPoint)point 將該圖片本身繪制到當(dāng)前繪圖CGContextRef的指定點(diǎn),point 為該圖片的繪制點(diǎn)
- (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha 將該圖片本身繪制到當(dāng)前繪圖CGContextRef的指定點(diǎn)削咆,point 為該圖片的繪制點(diǎn)牍疏,同時(shí)還指定繪制圖片的疊加模式 blendMode 和透明度 alpha
- (void)drawInRect:(CGRect)rect 將該圖片本身繪制到當(dāng)前繪圖CGContextRef的指定區(qū)域內(nèi),rect 為該圖片的繪制區(qū)域
- (void)drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha 將該圖片本身繪制到當(dāng)前繪圖CGContextRef的指定區(qū)域內(nèi)拨齐,rect 為該圖片的繪制區(qū)域鳞陨,同時(shí)還指定繪制圖片的疊加模式 blendMode 和透明度 alpha
- (void)drawAsPatternInRect:(CGRect)rect 將該圖片本身采用填充模式繪制到當(dāng)前繪圖CGContextRef的指定區(qū)域內(nèi)

① 繪制圖片

UIImage * image = [UIImage imageNamed:@"Quartz2D"];
[image drawAtPoint:CGPointZero];
[image drawInRect:CGRectMake(0, 0, 100, 100)]; //圖片不夠大則拉伸填充
[image drawAsPatternInRect:CGRectMake(0, 0, 100, 100)]; //圖片不夠大則平鋪填充

② 合成圖片

UIImage * bigImage = [UIImage imageNamed:@"big.jpg"];
UIImage * smallImage = [UIImage imageNamed:@"small.jpg"];

UIGraphicsBeginImageContextWithOptions(bigImage.size, NO, 0.0);
[bigImage drawInRect:CGRectMake(0, 0, bigImage.size.width, bigImage.size.height)];
[smallImage drawInRect:CGRectMake(0, 0, smallImage.size.width, smallImage.size.height)];

UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

③ 裁剪圖片

UIImage * oldImage = [UIImage imageNamed:@"Quartz2D"];
UIGraphicsBeginImageContextWithOptions(oldImage.size, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect circleRect = CGRectMake(0, 0, oldImage.size.width, oldImage.size.height);
CGContextAddEllipseInRect(ctx, circleRect);
CGContextClip(ctx);
[oldImage drawInRect:circleRect];
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

④ 屏幕截圖

UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//給UIImage 添加一個(gè)類方法
+ (UIImage *)captureView:(UIView *)targetView{
    UIGraphicsBeginImageContextWithOptions(targetView.frame.size, NO, 0.0);
    [targetView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瞻惋,隨后出現(xiàn)的幾起案子厦滤,更是在濱河造成了極大的恐慌援岩,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掏导,死亡現(xiàn)場(chǎng)離奇詭異享怀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)趟咆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門添瓷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人值纱,你說我怎么就攤上這事鳞贷。” “怎么了虐唠?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵搀愧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我凿滤,道長(zhǎng)妈橄,這世上最難降的妖魔是什么庶近? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任翁脆,我火速辦了婚禮,結(jié)果婚禮上鼻种,老公的妹妹穿的比我還像新娘反番。我一直安慰自己,他們只是感情好叉钥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布罢缸。 她就那樣靜靜地躺著,像睡著了一般投队。 火紅的嫁衣襯著肌膚如雪枫疆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天敷鸦,我揣著相機(jī)與錄音息楔,去河邊找鬼。 笑死扒披,一個(gè)胖子當(dāng)著我的面吹牛值依,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碟案,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼愿险,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了价说?” 一聲冷哼從身側(cè)響起辆亏,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤风秤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后褒链,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唁情,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年甫匹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甸鸟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兵迅,死狀恐怖抢韭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恍箭,我是刑警寧澤刻恭,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站扯夭,受9級(jí)特大地震影響鳍贾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜交洗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一骑科、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧构拳,春花似錦咆爽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至凫海,卻和暖如春呛凶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背行贪。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工漾稀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓮顽。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓县好,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親暖混。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缕贡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容