Quartz2D
Quartz2D
是一个二维绘图引擎,同时支持IOS
和Mac OS X
系统(跨平台,纯C语言),包括在CoreGraphics
框架中
- 绘制图形、文字,生成图片
- 读取/生成
PDF
- 截图/裁剪图片
- 自定义
UI
控件
数据类型以CG
作为前缀
Quartz2D的类型
- 图形上下文
CGContextRef
Quartz2D
提供了以下几种类型的Graphics Context
:Bitmap Graphics Context
PDF Graphics Context
Window Graphics Context
Layer Graphics Context
(UI控件
)Printer Graphics Context
(打印机)- 主要包括这些信息:绘图路径(各种各样的图形)、绘图状态(颜色、线宽、样式、旋转、缩放、平移、图片裁剪区域等)、输出目标(输出到哪里)
UIKit框架
- 对部分
Quartz2D
的API
做封装 - 没有封装的只能调用原生的
- 比如:画图片、文字到控件上(
UIKit
已经封装好了)
绘图的步骤
- 绘制到
UIView
上面,新建一个继承自UIView
的类
在其drawRect方法中绘制,方法1 C
- (void)drawRect:(CGRect)rect {
// Drawing code
// 1.获取当前绘图上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.把路径添加到上下文当中
CGContextMoveToPoint(ctx,50,50); // 起点 移动笔
CGContextAddLineToPoint(ctx,100,100); // 终点 从起点画到终点
// 2.5可以设置线的样式 可以省略
CGContextSetLineWidth(ctx,10); // 线宽10
CGContextSetLineJoin(ctx,kCGLineJoinRound); // 连接处圆弧,kCGLineJoinMiter默认,kCGLineJoinRound圆弧,kCGLineJoinBevel切角
CGContextSetLineCap(ctx,kCGLineCapRound); // 头尾样式 kCGLineCapButt默认,kCGLineCapRound圆弧,kCGLineCapSquare加个平角(相比默认会长一点)
CGContextSetRGBStrokeColor(ctx,0.4,0.4,0.4,1); // 设置颜色 ctx + RGB三个数值 + 透明度
// 3.渲染
CGContextStrokePath(ctx);
}
方法2 C
- (void)drawRect:(CGRect)rect {
// Drawing code
// 1.获取当前绘图上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接路径
CGMutablePathRef path = CGPathCreateMutable();
CGContextMoveToPoint(path,NULL,50,50);
CGContextAddLineToPoint(path,NULL,100,100);
// 3.把路径添加到上下文
CGContextStrokePath(ctx,path);
// 4.渲染
CGContextStrokePath(ctx);
}
方法3 C+OC
- (void)drawRect:(CGRect)rect {
// Drawing code
// 1.获取当前绘图上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接路径
// OC封装
UIBezierPath path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(50,50)];
[path addLineToPoint:CGPointMake(100,100)];
// 3.把路径添加到上下文
CGContextStrokePath(ctx,path.CGPath);
// 4.渲染
CGContextStrokePath(ctx);
}
CGMutablePathRef
转化为UIBezierPath
CGMutablePathRef path = CGPathCreateMutable();
UIBezierPath *path1 = [UIBezierPath bezierPathWithCGPath:path];
方法4 OC **最常用的**
- (void)drawRect:(CGRect)rect {
// Drawing code
// 创建路径对象
UIBezierPath *path = [UIBezierPath bezierPath];
// 通过路径对象,拼接路径
[path moveToPoint:CGPointMake(50,50)];
[path addLineToPoint:CGPointMake(100,100)];
// 设置样式 可省略
[path setLineWidth:10]; // 设置线宽
[path setLineJoinStyle:kCGLineJoinRound]; // 设置连接处样式
[path setLineCapStyle:kCGLineCapRound]; // 设置头尾的样式
[[UIColor blueColor] setStroke]; // 设置颜色
// 渲染
[path stroke];
}
理解(void)drawRect:(CGRect)rect
CGContextRef
是在drawRect
函数内部获取的,而不是创建的(CGRect)rect
是view
的bounds
drawRect
是系统调用的,view
第一次显示或者重绘的时候会调用- 重绘:调用某个需要重绘的
view
对象的setNeedsDisplay
或者setNeedsDisplayInRect
(Rect
是重绘的区域)
[self setNeedsDisplay];
- 手动调用
drawRect
的时候可能获取不到正确的上下文
绘制图形
- 矩形
- (void)drawRect:(CGRect)rect {
// Drawing code
// 创建路径对象
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(100,100,100,100)];
// 渲染
[path stroke];
}
- 圆角矩形
cornerRadius
为正方形边的一半时,变成圆形
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100,100,100,100) cornerRadius:10];
- 椭圆
长宽相等时,变成圆形
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,200,100)];
- 圆
该方法用于画弧线
// ArcCenter圆心 radius半径 startAngle起点 endAngle终点 clockwise顺时针
// 起点是三点钟方向是0 M _PI是π 二分之π是M_PI_2
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150,150) radius:100 startAngle:0 endAngle:2 * M_PI clockwise:1];
渲染方式(描边,填充)
C语言
CGContextClosePath(ctx); // 关闭路径,终点自动连接起点
CGContextStrokePath(ctx); // 描边,正常渲染使用的
CGContextFillPath(ctx); // 填充
CGContextDrawPath(ctx,kCGPathFill); // 可以调用多种方法,描边,填充,也可以同时描边填充,查看枚举选项就可以了
OC语言
[path closePath]; // 关闭路径
[path stroke]; // 描边渲染
[path fill]; // 填充,
// 同时描边填充,同时调用就可以了,区别于C的方法
even-odd rule
:奇偶填充规则
一个特殊的渲染方式
C语言
CGContextDrawPath(ctx,kCGPathEOFill);
OC语言
path.usersEvenOddFillRule = YES;
非零绕数规则
一个默认的渲染方式,如果出现双圆重叠,就会出现
重绘
[self setNeedsDisplay]; // 整体重绘
[self setNeedsDisplayInRect:CGRectMake(0,0,150,150)]; // 重绘指定区域
矩阵操作(旋转、缩放、平移)
在添加上下文之前才能生效,而不是放在渲染之前
// 缩放
void CGContextScaleCTM(CGContextRef c,CGFloat sx,CGFloat sy);
// 旋转
void CGContextRotateCTM(CGContextRef c,CGFloat angle);
// 平移
void CGContextTranslateCTM(CGContextRef c,CGFloat tx,CGFloat ty);
保存状态和恢复状态
图形上下文栈,保存状态进栈,恢复则移出
// 保存 保存颜色和宽度
CGContextSaveGState(ctx);
// 恢复
CGContextRestoreGState(ctx);
Quartz2D内存管理
使用Path
对象时的内存管理问题
- 凡是在函数名字当中包含了
retain
、copy
、create
关键字,那么在调用完毕该函数,创建出的对象,在使用完毕以后,都需要进行release
- 但是
CGPathCreateMutable()
不是OC
方法,所以不是调用某个对象的release
方法 Cgxxxxxcreate
对应的就有Cgxxxxxrelease
- 通过
CFRelease
(任何类型}可以释放任何类型
// 释放 两种方式
CGContextStrokePath(path);
CFRelease(path);
绘制文字
- (void)drawRect:(CGRect)rect {
NSString *str = @"测试";
// 绘制
// 方法一 attribute是字典可以传入文字多个属性 例如:@{NSFontAttributeName:[UIFont systemFontOfSize:30]}
[str drawAtPoint:CGPonitZero withAttributes:nil];
// 方法二
[str drawInRect:CGRectMake(0,0,200,200) withAttributes:nil];
}
绘制图片
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:@"me"];
// 绘制
// 方法一 从点开始绘制
[image drawAtPoint:CGPonitZero];
// 方法二 绘制到某个区域 会拉伸
[image drawInRect:CGRectMake(0,0,200,200)];
// 方法三 小图平铺
[image drawAsPatternInRect:rect];
}
裁剪
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:@"me"];
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 画显示的区域
CGContextAddArc(ctx,150,150,150,0,2 * M_PI,1);
// 裁剪 保留里面的内容 裁剪的是显示区域
CGContextClip(ctx);
// 拉伸显示到view
[image drawInRect:rect];
}
绘制上下文到UIImageView
- 不用在
drawRect
函数里也可以使用 - 还可以转为
NSData
保存在沙盒里面
// 开启图片类型上下文
UIGraphicsBeginImageContext(CGSizeMake(300,300));//方法一
//UIGraphicsBeginImageContextWithOptions(CGSizeMake(300,300),NO,[UIScreen mainScreen].scale); 方法二:多了参数选择 透明 缩放倍速
//[UIScreen mainScreen].scale是屏幕的缩放因子,可以设置为0,自动获取
// 获取当前的图片类型上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 拼接路径
CGContextMoveToPoint(ctx,50,50);
CGContextAddLineToPoint(ctx,100,100);
// 渲染
CGContextStrokePath(ctx);
// 从上下文获取图片对象
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图片类型上下文
UIGraphicsEndImageContext();
// 放到UIImageView上面
self.imageView.image = iamge;
// image保存到沙盒
// image转化为NSData
NSData *data = UIImagePNGRepresentation(image);
// filePath沙盒路径自动获取,png文件结尾,写入沙盒
[data writeToFile:filePath atomically:YES];
UIButton绘制圆角
左上:UIRectCornerTopLeft
左下:UIRectCornerBottomLeft
右上:UIRectCornerTopRight
右下:UIRectCornerBottomRight
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:button.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerTopLeft cornerRadii:CGSizeMake(8, 8)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = button.bounds;
maskLayer.path = maskPath.CGPath;
button.layer.mask = maskLayer;
UIImage添加文字水印和图片水印
+ (UIImage *)waterAtImage:(UIImage *)image
text:(NSString *)text
point:(CGPoint)point
attributes:(NSDictionary *)attributes {
// 开启图形上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 绘制图片
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
// 添加文字
[text drawAtPoint:point withAttributes:attributes];
// 获取图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
return newImage;
}
+ (UIImage *)waterAtImage:(UIImage *)image
waterImgae:(UIImage *)waterImage
rect:(CGRect)rect {
// 开启图形上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 绘制原图片
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.width)];
// 绘制水印
[waterImage drawInRect:rect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}