一、画基本图形
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