IOS-Quartz2D

一、画基本图形

  1 //
  2 //  BWView.m
  3 //  IOS_0221_Quartz2D画矩形
  4 //
  5 //  Created by ma c on 16/2/21.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8 
  9 #import "BWView.h"
 10 
 11 @implementation BWView
 12 /*
 13  一、什么是Quartz2D
 14  1.Quartz2D是一个二维绘图引擎,同时支持IOS和MAC系统
 15  
 16  2.Quartz2D能完成的工作
 17  1>绘制图形:线条三角形矩形圆形弧
 18  2>绘制文字:
 19  3>绘制生成图片(图像)
 20  4>读取生成PDF
 21  5>裁图裁剪图片
 22  6>自定义UI控件
 23  
 24  3.实例
 25  1>裁剪图片(圆形)
 26  2>涂鸦画板
 27  3>手势解锁
 28  
 29  4.最重要的价值
 30  1>自定义UI控件:因为有些UI界面及其复杂,而且比较个性化,用普通的UI控件根本无法实现,
 31  此时可以利用Quartz2D技术将控件内部结构画出来。
 32  
 33  5.最重要的概念
 34  1>图形上下文
 35  a.图形上下文(Graghics Context):是一个CGContextRef类型的数据
 36  b.作用:
 37  保留绘图信息,绘图状态
 38  决定绘制的输出目标
 39  绘制好的图形 -> (保存)图形上下文 -> (显示)输出目标
 40  c.相同的一套绘制序列,指定不同的Graghics Context,就可以将相同的图像绘制到不同的
 41  目标上。
 42  
 43  2>图形上下文栈
 44  a.将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)
 45    void CGContextSaveGState(CGContextRef c)
 46  b.将栈顶的上下文出栈,替换掉当前的上下文
 47    void CGContextRestoreGState(CGContextRef c)
 48 
 49  6.Quartz2D提供了以下几种类型的Graghics Context:
 50  1>Bitmap Graphics Context
 51  2>PDF Graphics Context
 52  3>Window Graghics Context
 53  4>Layer Graghics Context
 54  5>Printer Graghics Context
 55  
 56  7.如何利用Quartz2D自定义view
 57  1>新建一个类,继承自UIView
 58  2>实现 -(void)drawRect:(CGRect)rect方法
 59  a.取得跟当前view相关联的图形上下文
 60  b.绘制相应的图形内容
 61  c.利用图形上下文将绘制的所有内容显示到view上面
 62  
 63  8.常识:
 64  1>绘图顺序:后绘制的图形覆盖前一个图形
 65  2>Quartz2D的API是纯C语言
 66  3>Quartz2D的API来自于Core Graphics框架
 67  4>数据类型和函数基本都以CG作为前缀
 68  
 69  9.drawRect:中取得的上下文
 70  1>在drawRect:方法中取得上下文后,就可以绘制东西到view上
 71  2>View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,
 72    因此,绘制的东西其实是绘制到view的layer上去了
 73  3>View之所以能显示东西,完全是因为它内部的layer
 74  4>为什么要实现drawRect:方法才能绘图到view上?
 75    因为在drawRect:方法中才能取得跟view相关联的图形上下文
 76  5>drawRect:方法在什么时候被调用?
 77    当view第一次显示到屏幕上时(被加到UIWindow上显示出来)
 78    调用view的setNeedsDisplay或者setNeedsDisplayInRect:时
 79 
 80  
 81  10.Quartz2D绘图的代码步骤
 82  1>获得图形上下文
 83    CGContextRef ctx = UIGraphicsGetCurrentContext();
 84  2>拼接路径(下面代码是搞一条线段)
 85    CGContextMoveToPoint(ctx, 10, 10);
 86    CGContextAddLineToPoint(ctx, 100, 100);
 87  3>绘制路径
 88    CGContextStrokePath(ctx); // CGContextFillPath(ctx);
 89  
 90  11.常用拼接路径函数
 91  1>新建一个起点
 92    void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)
 93  2>添加新的线段到某个点
 94    void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)
 95  3>添加一个矩形
 96    void CGContextAddRect(CGContextRef c, CGRect rect)
 97  4>添加一个椭圆
 98    void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)
 99  5>添加一个圆弧
100    void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
101    CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
102  
103  12.常用绘制路径函数
104  1>Mode参数决定绘制的模式
105    void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)
106  2>绘制空心路径
107    void CGContextStrokePath(CGContextRef c)
108  3>绘制实心路径
109    void CGContextFillPath(CGContextRef c)
110    提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的
111  
112  */
113 
114 // Only override drawRect: if you perform custom drawing.
115 // An empty implementation adversely affects performance during animation.
116 - (void)drawRect:(CGRect)rect {
117     
118     //drawRectangle();
119     //drawLine();
120     //drawCircle();
121     //drawArc();
122     //drawCurve();
123     
124 }
125 ///画曲线
126 void drawCurve()
127 {
128     // 1.获得上下文
129     CGContextRef ctf = UIGraphicsGetCurrentContext();
130     
131     CGRect rect = CGRectMake(50, 50, 100, 100);
132     
133     //中间控制点
134     CGFloat controlX = rect.size.width * 0.5;
135     CGFloat controlY = rect.size.height * 0.5;
136     
137     //当前点
138     CGFloat marginX = 20;
139     CGFloat marginY = 10;
140     CGFloat currentX = controlX - marginX;
141     CGFloat currentY = controlY - marginY;
142     CGContextMoveToPoint(ctf, currentX, currentY);
143     
144     //结束点
145     CGFloat endX = controlX + marginX;
146     CGFloat endY = currentY;
147     
148     //贝塞尔曲线
149     CGContextAddQuadCurveToPoint(ctf, controlX, controlY, endX, endY);
150     
151     // 2.渲染
152     CGContextStrokePath(ctf);
153 }
154 
155 ///画圆弧
156 void drawArc()
157 {
158     // 1.获得上下文
159     CGContextRef ctf = UIGraphicsGetCurrentContext();
160     
161     // 2.画1/4圆
162     CGContextMoveToPoint(ctf, 100, 50);
163     CGContextAddLineToPoint(ctf, 100, 100);
164     
165     //画圆弧
166     /*
167             x/y:圆心
168          radius:半径
169      startAngle:开始角度
170        endAngle:结束角度
171       clockwise:圆弧的伸展方向(0:顺时针,1:逆时针)
172      */
173     CGContextAddArc(ctf, 100, 50, 50, M_PI_2, M_PI, 0);
174     
175     // 关闭路径(连接起点和最后一个点)
176     CGContextClosePath(ctf);
177     
178     // 设置颜色
179     [[UIColor redColor] set];
180 
181     // 3.显示
182     CGContextFillPath(ctf);
183 
184 }
185 
186 ///画圆
187 void drawCircle()
188 {
189     // 1.获得上下文
190     CGContextRef ctf = UIGraphicsGetCurrentContext();
191     
192     // 2.画圆
193     CGContextAddEllipseInRect(ctf, CGRectMake(60, 30, 100, 100));
194     
195     // 3.显示
196     CGContextStrokePath(ctf);
197 }
198 
199 ///画线
200 void drawLine()
201 {
202     // 1.获得上下文
203     CGContextRef ctf = UIGraphicsGetCurrentContext();
204     
205     
206     //2.画线
207     
208     //拷贝当前上下文放到栈中
209     CGContextSaveGState(ctf);
210     
211     // 设置线宽
212     CGContextSetLineWidth(ctf, 5);
213     // 设置颜色
214     CGContextSetRGBStrokeColor(ctf, 1, 1, 0.1, 1);
215     // 设置线段头尾部样式
216     CGContextSetLineCap(ctf, kCGLineCapRound);
217     // 设置线段转折点样式
218     CGContextSetLineJoin(ctf, kCGLineJoinRound);
219 
220     //设置起点
221     CGContextMoveToPoint(ctf, 10, 10);
222     //添加一条线段到(100,100)
223     CGContextAddLineToPoint(ctf, 100, 100);
224     // 渲染显示到view上面
225     CGContextStrokePath(ctf);
226 
227     //将栈顶的上下文出栈,替换当前的上下文
228     CGContextRestoreGState(ctf);
229 
230     //设置起点
231     CGContextMoveToPoint(ctf, 100, 50);
232     //添加一条线段到(100,100)
233     CGContextAddLineToPoint(ctf, 200, 100);
234     CGContextAddLineToPoint(ctf, 230, 50);
235     // 渲染显示到view上面
236     CGContextStrokePath(ctf);
237 }
238 
239 ///画矩形
240 void drawRectangle()
241 {
242     // 1.获得上下文
243     CGContextRef ctf = UIGraphicsGetCurrentContext();
244     
245     // 2.画矩形
246     CGContextAddRect(ctf, CGRectMake(10, 10, 100, 100));
247     
248     // 3.绘制图形
249     //CGContextStrokePath(ctf);
250     CGContextFillPath(ctf);
251 }
252 
253 ///画三角形
254 void drawTriangle()
255 {
256     // 1.获得上下文
257     CGContextRef ctf = UIGraphicsGetCurrentContext();
258     
259     // 2.拼接图形(路径)
260     // 画三角形
261     CGContextMoveToPoint(ctf, 0, 0);
262     CGContextAddLineToPoint(ctf, 100, 100);
263     CGContextAddLineToPoint(ctf, 150, 80);
264     // 关闭路径(连接起点和最后一个点)
265     CGContextClosePath(ctf);
266     
267     // 3.绘制图形
268     CGContextStrokePath(ctf);
269     
270 }
271 
272 @end

二、画文字和图片

 1 //
 2 //  DrawTextAndImgView.m
 3 //  IOS_0221_Quartz2D画矩形
 4 //
 5 //  Created by ma c on 16/2/21.
 6 //  Copyright © 2016年 博文科技. All rights reserved.
 7 //
 8 
 9 #import "DrawTextAndImgView.h"
10 
11 @implementation DrawTextAndImgView
12 
13 
14 // Only override drawRect: if you perform custom drawing.
15 // An empty implementation adversely affects performance during animation.
16 - (void)drawRect:(CGRect)rect {
17     
18 //    drawText();
19 //    drawImage();
20 }
21 
22 ///画图片
23 void drawImage()
24 {
25     // 1.取得图片
26     UIImage *img = [UIImage imageNamed:@"1.jpg"];
27     
28     // 2.画
29 //    [img drawAtPoint:CGPointMake(30, 0)];
30 //    [img drawInRect:CGRectMake(50, 10, 100, 100)];
31     [img drawAsPatternInRect:CGRectMake(0, 0, 400, 200)];
32 }
33 
34 ///画文字
35 void drawText()
36 {
37     
38     //方法一 使用OC
39     NSString *str = @"bowen,哈喽";
40     NSMutableDictionary *dict = [NSMutableDictionary dictionary];
41     dict[NSForegroundColorAttributeName] = [UIColor redColor];
42     dict[NSFontAttributeName] = [UIFont systemFontOfSize:30];
43     //[str drawAtPoint:CGPointZero withAttributes:nil];
44     [str drawInRect:CGRectMake(50, 50, 100, 100) withAttributes:dict];
45     
46     //方法二 使用C
47     // 1.获得上下文
48     CGContextRef ctf = UIGraphicsGetCurrentContext();
49     // 2.画文字
50     
51     // 3.渲染显示
52     CGContextStrokePath(ctf);
53 }
54 
55 @end

三、实用技术

  1 //
  2 //  MatrixOperation.m
  3 //  IOS_0221_Quartz2D画矩形
  4 //
  5 //  Created by ma c on 16/2/21.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8 
  9 #import "MatrixOperation.h"
 10 
 11 @implementation MatrixOperation
 12 /*
 13  1.利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
 14  缩放
 15  void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
 16  旋转
 17  void CGContextRotateCTM(CGContextRef c, CGFloat angle)
 18  平移
 19  void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
 20  
 21  2.裁剪
 22  CGContextClip(CGContextRef ctf);
 23  
 24  3.重绘,刷帧
 25  [self setNeedsDisplay];
 26  
 27  4.屏幕截图
 28  - (void)renderInContext:(CGContextRef)ctx;
 29  调用某个view的layer的renderInContext:方法即可
 30 
 31 
 32  */
 33 
 34 /*
 35  默认只在第一次显示的时候调用(只能由系统自动调用)
 36 */
 37 - (void)drawRect:(CGRect)rect {
 38 //    matrix();
 39 //    cut();
 40 //    brush(self.radius);
 41     
 42 //    customControl(self.image, rect);
 43     
 44 }
 45 
 46 ///矩阵操作
 47 void matrix()
 48 {
 49     CGContextRef ctf = UIGraphicsGetCurrentContext();
 50     
 51     //矩阵操作
 52 //    CGContextScaleCTM(ctf, 0.5, 0.5);
 53 //    CGContextRotateCTM(ctf, M_PI_2 * 0.2);
 54 //    CGContextTranslateCTM(ctf, 50, 50);
 55     
 56     CGContextAddRect(ctf, CGRectMake(10, 10, 50, 50));
 57     CGContextAddEllipseInRect(ctf, CGRectMake(100, 40, 100, 100));
 58     CGContextMoveToPoint(ctf, 100, 40);
 59     CGContextAddLineToPoint(ctf, 200, 150);
 60     
 61     CGContextStrokePath(ctf);
 62 
 63 }
 64 
 65 ///裁剪
 66 void cut()
 67 {
 68     CGContextRef ctf = UIGraphicsGetCurrentContext();
 69     
 70     CGContextAddEllipseInRect(ctf, CGRectMake(100, 100, 50, 50));
 71     
 72     //裁剪
 73     CGContextClip(ctf);
 74     
 75     CGContextStrokePath(ctf);
 76     
 77     UIImage *img = [UIImage imageNamed:@"1.jpg"];
 78     [img drawAtPoint:CGPointMake(100, 100)];
 79 }
 80 
 81 
 82 ///重绘,刷帧
 83 void brush(float radius)
 84 {
 85     CGContextRef ctf = UIGraphicsGetCurrentContext();
 86     CGContextAddArc(ctf, 60, 60, radius, 0, M_PI * 2, 0);
 87     CGContextFillPath(ctf);
 88 }
 89 - (void)setRadius:(float)radius
 90 {
 91     _radius = radius;
 92     //重绘(这个方法内部会重新调用drawRect:方法进行绘制)
 93     [self setNeedsDisplay];
 94 }
 95 
 96 ///自定义UIImageView控件
 97 void customControl(UIImage *image, CGRect rect)
 98 {
 99     [image drawInRect:rect];
100 }
101 - (void)setImage:(UIImage *)image
102 {
103     _image = image;
104     [self setNeedsDisplay];
105 }
106 
107 
108 ///nib文件加载完毕时调用
109 - (void)awakeFromNib
110 {
111     
112 }
113 
114 @end
  1 //
  2 //  ViewController.m
  3 //  IOS_0221_Quartz2D画矩形
  4 //
  5 //  Created by ma c on 16/2/21.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 #import "MatrixOperation.h"
 11 
 12 @interface ViewController ()
 13 
 14 @property (weak, nonatomic) IBOutlet UIImageView *imgView;
 15 - (IBAction)valueChange:(UISlider *)sender;
 16 @property (weak, nonatomic) IBOutlet MatrixOperation *brushView;
 17 - (IBAction)clip:(UIButton *)sender;
 18 
 19 @end
 20 
 21 @implementation ViewController
 22 
 23 - (void)viewDidLoad {
 24     [super viewDidLoad];
 25     
 26 //    [self watermark];
 27     [self picCut2];
 28 }
 29 ///图片裁剪(圆环)
 30 - (void)picCut2
 31 {
 32     // 1.加载原图
 33     UIImage *oldImage = [UIImage imageNamed:@"me.png"];
 34     
 35     // 2.开启上下文
 36     CGFloat borderW = 2; // 圆环的宽度
 37     CGFloat imageW = oldImage.size.width + 2 * borderW;
 38     CGFloat imageH = oldImage.size.height + 2 * borderW;
 39     CGSize imageSize = CGSizeMake(imageW, imageH);
 40     UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
 41     
 42     // 3.取得当前的上下文
 43     CGContextRef ctx = UIGraphicsGetCurrentContext();
 44     
 45     // 4.画边框(大圆)
 46     [[UIColor redColor] set];
 47     CGFloat bigRadius = imageW * 0.5; // 大圆半径
 48     CGFloat centerX = bigRadius; // 圆心
 49     CGFloat centerY = bigRadius;
 50     CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
 51     CGContextFillPath(ctx); // 画圆
 52     
 53     // 5.小圆
 54     CGFloat smallRadius = bigRadius - borderW;
 55     CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
 56     // 裁剪(后面画的东西才会受裁剪的影响)
 57     CGContextClip(ctx);
 58     
 59     // 6.画图
 60     [oldImage drawInRect:CGRectMake(borderW, borderW, oldImage.size.width, oldImage.size.height)];
 61     
 62     // 7.取图
 63     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
 64     
 65     // 8.结束上下文
 66     UIGraphicsEndImageContext();
 67     
 68     // 9.显示图片
 69     self.imgView.image = newImage;
 70     
 71     // 10.写出文件
 72     NSData *data = UIImagePNGRepresentation(newImage);
 73     NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"new.png"];
 74     [data writeToFile:path atomically:YES];
 75 }
 76 
 77 ///图片裁剪(圆)
 78 - (void)picCut1
 79 {
 80     //1.加载原图
 81     UIImage *image = [UIImage imageNamed:@"me.png"];
 82     //2.开启上下文
 83     UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
 84     //3.取得当前上下文
 85     CGContextRef ctf = UIGraphicsGetCurrentContext();
 86     //4.画圆
 87     CGRect circleRect = CGRectMake(0, 0, image.size.width, image.size.height);
 88     CGContextAddEllipseInRect(ctf, circleRect);
 89     //5.按照当前形状裁剪,超出这个形状以外内容不显示
 90     CGContextClip(ctf);
 91     //6.画图
 92     [image drawInRect:circleRect];
 93     //7.取图
 94     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
 95     //8.结束
 96     UIGraphicsEndImageContext();
 97     //9.写入文件
 98     NSData *data = UIImagePNGRepresentation(image);
 99     NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
100     [data writeToFile:path atomically:YES];
101     //10.显示图片
102     self.imgView.image = newImage;
103     
104 }
105 
106 ///制作水印
107 - (void)watermark
108 {
109     UIImage *bgImg = [UIImage imageNamed:@"scene.png"];
110     
111     //上下文:基于位图(bitmap),所有的东西需要绘制到新的图片上去
112     
113     //1.创建一个基于位图的上下文
114     UIGraphicsBeginImageContextWithOptions(bgImg.size, NO, 0.0);
115     //2.画背景
116     [bgImg drawInRect:CGRectMake(0, 0, bgImg.size.width, bgImg.size.height)];
117     //3.画水印
118     UIImage *waterImg = [UIImage imageNamed:@"logo.png"];
119     CGFloat scale = 0.2;
120     CGFloat margin = 5;
121     CGFloat waterW = waterImg.size.width * scale;
122     CGFloat waterH = waterImg.size.height * scale;
123     CGFloat waterX = bgImg.size.width - waterW - margin;
124     CGFloat waterY = bgImg.size.height - waterH - margin;
125     [waterImg drawInRect:CGRectMake(waterX, waterY, waterW, waterH)];
126     //4.从上下文中取得制作完毕的UIImage对象
127     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
128     //5.结束上下文
129     UIGraphicsEndImageContext();
130     //6.显示到UIImageView
131     self.imgView.image = newImage;
132     //7.将image对象压缩为PNG格式的二进制数据
133     NSData *data = UIImagePNGRepresentation(newImage);
134     //8.写入文件
135     NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
136     [data writeToFile:path atomically:YES];
137 }
138 ///截图
139 - (IBAction)clip:(UIButton *)sender {
140     
141     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
142         
143         //1.开启上下文
144         UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
145         //2.将控制器的view的layer渲染到上下文
146         [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
147         //3.取出图片
148         UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
149         NSData *data = UIImagePNGRepresentation(newImage);
150         [data writeToFile:@"/Users/mac/Desktop/a.png" atomically:YES];
151         //4.结束上下文
152         UIGraphicsEndImageContext();
153     });
154 }
155 
156 ///创建自定义ImageView
157 - (void)createimgView
158 {
159     MatrixOperation *imgView = [[MatrixOperation alloc] init];
160     imgView.frame = CGRectMake(100, 100, 100, 100);
161     UIImage *img = [UIImage imageNamed:@"1.jpg"];
162     imgView.image = img;
163     [self.view addSubview:imgView];
164 }
165 
166 - (IBAction)valueChange:(UISlider *)sender {
167     
168     self.brushView.radius = sender.value;
169 }
170 
171 @end
原文地址:https://www.cnblogs.com/oc-bowen/p/5205285.html