IOS-Quartz2D

时间:2023-03-09 23:05:02
IOS-Quartz2D

一、画基本图形

 //
// BWView.m
// IOS_0221_Quartz2D画矩形
//
// Created by ma c on 16/2/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWView.h" @implementation BWView
/*
一、什么是Quartz2D
1.Quartz2D是一个二维绘图引擎,同时支持IOS和MAC系统 2.Quartz2D能完成的工作
1>绘制图形:线条\三角形\矩形\圆形\弧
2>绘制文字:
3>绘制\生成图片(图像)
4>读取\生成PDF
5>裁图\裁剪图片
6>自定义UI控件 3.实例
1>裁剪图片(圆形)
2>涂鸦\画板
3>手势解锁 4.最重要的价值
1>自定义UI控件:因为有些UI界面及其复杂,而且比较个性化,用普通的UI控件根本无法实现,
此时可以利用Quartz2D技术将控件内部结构画出来。 5.最重要的概念
1>图形上下文
a.图形上下文(Graghics Context):是一个CGContextRef类型的数据
b.作用:
保留绘图信息,绘图状态
决定绘制的输出目标
绘制好的图形 -> (保存)图形上下文 -> (显示)输出目标
c.相同的一套绘制序列,指定不同的Graghics Context,就可以将相同的图像绘制到不同的
目标上。 2>图形上下文栈
a.将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)
void CGContextSaveGState(CGContextRef c)
b.将栈顶的上下文出栈,替换掉当前的上下文
void CGContextRestoreGState(CGContextRef c) 6.Quartz2D提供了以下几种类型的Graghics Context:
1>Bitmap Graphics Context
2>PDF Graphics Context
3>Window Graghics Context
4>Layer Graghics Context
5>Printer Graghics Context 7.如何利用Quartz2D自定义view
1>新建一个类,继承自UIView
2>实现 -(void)drawRect:(CGRect)rect方法
a.取得跟当前view相关联的图形上下文
b.绘制相应的图形内容
c.利用图形上下文将绘制的所有内容显示到view上面 8.常识:
1>绘图顺序:后绘制的图形覆盖前一个图形
2>Quartz2D的API是纯C语言
3>Quartz2D的API来自于Core Graphics框架
4>数据类型和函数基本都以CG作为前缀 9.drawRect:中取得的上下文
1>在drawRect:方法中取得上下文后,就可以绘制东西到view上
2>View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,
因此,绘制的东西其实是绘制到view的layer上去了
3>View之所以能显示东西,完全是因为它内部的layer
4>为什么要实现drawRect:方法才能绘图到view上?
因为在drawRect:方法中才能取得跟view相关联的图形上下文
5>drawRect:方法在什么时候被调用?
当view第一次显示到屏幕上时(被加到UIWindow上显示出来)
调用view的setNeedsDisplay或者setNeedsDisplayInRect:时 10.Quartz2D绘图的代码步骤
1>获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
2>拼接路径(下面代码是搞一条线段)
CGContextMoveToPoint(ctx, 10, 10);
CGContextAddLineToPoint(ctx, 100, 100);
3>绘制路径
CGContextStrokePath(ctx); // CGContextFillPath(ctx); 11.常用拼接路径函数
1>新建一个起点
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)
2>添加新的线段到某个点
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)
3>添加一个矩形
void CGContextAddRect(CGContextRef c, CGRect rect)
4>添加一个椭圆
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)
5>添加一个圆弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise) 12.常用绘制路径函数
1>Mode参数决定绘制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)
2>绘制空心路径
void CGContextStrokePath(CGContextRef c)
3>绘制实心路径
void CGContextFillPath(CGContextRef c)
提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的 */ // Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect { //drawRectangle();
//drawLine();
//drawCircle();
//drawArc();
//drawCurve(); }
///画曲线
void drawCurve()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); CGRect rect = CGRectMake(, , , ); //中间控制点
CGFloat controlX = rect.size.width * 0.5;
CGFloat controlY = rect.size.height * 0.5; //当前点
CGFloat marginX = ;
CGFloat marginY = ;
CGFloat currentX = controlX - marginX;
CGFloat currentY = controlY - marginY;
CGContextMoveToPoint(ctf, currentX, currentY); //结束点
CGFloat endX = controlX + marginX;
CGFloat endY = currentY; //贝塞尔曲线
CGContextAddQuadCurveToPoint(ctf, controlX, controlY, endX, endY); // 2.渲染
CGContextStrokePath(ctf);
} ///画圆弧
void drawArc()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); // 2.画1/4圆
CGContextMoveToPoint(ctf, , );
CGContextAddLineToPoint(ctf, , ); //画圆弧
/*
x/y:圆心
radius:半径
startAngle:开始角度
endAngle:结束角度
clockwise:圆弧的伸展方向(0:顺时针,1:逆时针)
*/
CGContextAddArc(ctf, , , , M_PI_2, M_PI, ); // 关闭路径(连接起点和最后一个点)
CGContextClosePath(ctf); // 设置颜色
[[UIColor redColor] set]; // 3.显示
CGContextFillPath(ctf); } ///画圆
void drawCircle()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); // 2.画圆
CGContextAddEllipseInRect(ctf, CGRectMake(, , , )); // 3.显示
CGContextStrokePath(ctf);
} ///画线
void drawLine()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); //2.画线 //拷贝当前上下文放到栈中
CGContextSaveGState(ctf); // 设置线宽
CGContextSetLineWidth(ctf, );
// 设置颜色
CGContextSetRGBStrokeColor(ctf, , , 0.1, );
// 设置线段头尾部样式
CGContextSetLineCap(ctf, kCGLineCapRound);
// 设置线段转折点样式
CGContextSetLineJoin(ctf, kCGLineJoinRound); //设置起点
CGContextMoveToPoint(ctf, , );
//添加一条线段到(100,100)
CGContextAddLineToPoint(ctf, , );
// 渲染显示到view上面
CGContextStrokePath(ctf); //将栈顶的上下文出栈,替换当前的上下文
CGContextRestoreGState(ctf); //设置起点
CGContextMoveToPoint(ctf, , );
//添加一条线段到(100,100)
CGContextAddLineToPoint(ctf, , );
CGContextAddLineToPoint(ctf, , );
// 渲染显示到view上面
CGContextStrokePath(ctf);
} ///画矩形
void drawRectangle()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); // 2.画矩形
CGContextAddRect(ctf, CGRectMake(, , , )); // 3.绘制图形
//CGContextStrokePath(ctf);
CGContextFillPath(ctf);
} ///画三角形
void drawTriangle()
{
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext(); // 2.拼接图形(路径)
// 画三角形
CGContextMoveToPoint(ctf, , );
CGContextAddLineToPoint(ctf, , );
CGContextAddLineToPoint(ctf, , );
// 关闭路径(连接起点和最后一个点)
CGContextClosePath(ctf); // 3.绘制图形
CGContextStrokePath(ctf); } @end

二、画文字和图片

 //
// DrawTextAndImgView.m
// IOS_0221_Quartz2D画矩形
//
// Created by ma c on 16/2/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "DrawTextAndImgView.h" @implementation DrawTextAndImgView // Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect { // drawText();
// drawImage();
} ///画图片
void drawImage()
{
// 1.取得图片
UIImage *img = [UIImage imageNamed:@"1.jpg"]; // 2.画
// [img drawAtPoint:CGPointMake(30, 0)];
// [img drawInRect:CGRectMake(50, 10, 100, 100)];
[img drawAsPatternInRect:CGRectMake(, , , )];
} ///画文字
void drawText()
{ //方法一 使用OC
NSString *str = @"bowen,哈喽";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = [UIColor redColor];
dict[NSFontAttributeName] = [UIFont systemFontOfSize:];
//[str drawAtPoint:CGPointZero withAttributes:nil];
[str drawInRect:CGRectMake(, , , ) withAttributes:dict]; //方法二 使用C
// 1.获得上下文
CGContextRef ctf = UIGraphicsGetCurrentContext();
// 2.画文字 // 3.渲染显示
CGContextStrokePath(ctf);
} @end

三、实用技术

 //
// MatrixOperation.m
// IOS_0221_Quartz2D画矩形
//
// Created by ma c on 16/2/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "MatrixOperation.h" @implementation MatrixOperation
/*
1.利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
缩放
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
旋转
void CGContextRotateCTM(CGContextRef c, CGFloat angle)
平移
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty) 2.裁剪
CGContextClip(CGContextRef ctf); 3.重绘,刷帧
[self setNeedsDisplay]; 4.屏幕截图
- (void)renderInContext:(CGContextRef)ctx;
调用某个view的layer的renderInContext:方法即可 */ /*
默认只在第一次显示的时候调用(只能由系统自动调用)
*/
- (void)drawRect:(CGRect)rect {
// matrix();
// cut();
// brush(self.radius); // customControl(self.image, rect); } ///矩阵操作
void matrix()
{
CGContextRef ctf = UIGraphicsGetCurrentContext(); //矩阵操作
// CGContextScaleCTM(ctf, 0.5, 0.5);
// CGContextRotateCTM(ctf, M_PI_2 * 0.2);
// CGContextTranslateCTM(ctf, 50, 50); CGContextAddRect(ctf, CGRectMake(, , , ));
CGContextAddEllipseInRect(ctf, CGRectMake(, , , ));
CGContextMoveToPoint(ctf, , );
CGContextAddLineToPoint(ctf, , ); CGContextStrokePath(ctf); } ///裁剪
void cut()
{
CGContextRef ctf = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(ctf, CGRectMake(, , , )); //裁剪
CGContextClip(ctf); CGContextStrokePath(ctf); UIImage *img = [UIImage imageNamed:@"1.jpg"];
[img drawAtPoint:CGPointMake(, )];
} ///重绘,刷帧
void brush(float radius)
{
CGContextRef ctf = UIGraphicsGetCurrentContext();
CGContextAddArc(ctf, , , radius, , M_PI * , );
CGContextFillPath(ctf);
}
- (void)setRadius:(float)radius
{
_radius = radius;
//重绘(这个方法内部会重新调用drawRect:方法进行绘制)
[self setNeedsDisplay];
} ///自定义UIImageView控件
void customControl(UIImage *image, CGRect rect)
{
[image drawInRect:rect];
}
- (void)setImage:(UIImage *)image
{
_image = image;
[self setNeedsDisplay];
} ///nib文件加载完毕时调用
- (void)awakeFromNib
{ } @end
 //
// ViewController.m
// IOS_0221_Quartz2D画矩形
//
// Created by ma c on 16/2/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "ViewController.h"
#import "MatrixOperation.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imgView;
- (IBAction)valueChange:(UISlider *)sender;
@property (weak, nonatomic) IBOutlet MatrixOperation *brushView;
- (IBAction)clip:(UIButton *)sender; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; // [self watermark];
[self picCut2];
}
///图片裁剪(圆环)
- (void)picCut2
{
// 1.加载原图
UIImage *oldImage = [UIImage imageNamed:@"me.png"]; // 2.开启上下文
CGFloat borderW = ; // 圆环的宽度
CGFloat imageW = oldImage.size.width + * borderW;
CGFloat imageH = oldImage.size.height + * borderW;
CGSize imageSize = CGSizeMake(imageW, imageH);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); // 3.取得当前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext(); // 4.画边框(大圆)
[[UIColor redColor] set];
CGFloat bigRadius = imageW * 0.5; // 大圆半径
CGFloat centerX = bigRadius; // 圆心
CGFloat centerY = bigRadius;
CGContextAddArc(ctx, centerX, centerY, bigRadius, , M_PI * , );
CGContextFillPath(ctx); // 画圆 // 5.小圆
CGFloat smallRadius = bigRadius - borderW;
CGContextAddArc(ctx, centerX, centerY, smallRadius, , M_PI * , );
// 裁剪(后面画的东西才会受裁剪的影响)
CGContextClip(ctx); // 6.画图
[oldImage drawInRect:CGRectMake(borderW, borderW, oldImage.size.width, oldImage.size.height)]; // 7.取图
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 8.结束上下文
UIGraphicsEndImageContext(); // 9.显示图片
self.imgView.image = newImage; // 10.写出文件
NSData *data = UIImagePNGRepresentation(newImage);
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"new.png"];
[data writeToFile:path atomically:YES];
} ///图片裁剪(圆)
- (void)picCut1
{
//1.加载原图
UIImage *image = [UIImage imageNamed:@"me.png"];
//2.开启上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
//3.取得当前上下文
CGContextRef ctf = UIGraphicsGetCurrentContext();
//4.画圆
CGRect circleRect = CGRectMake(, , image.size.width, image.size.height);
CGContextAddEllipseInRect(ctf, circleRect);
//5.按照当前形状裁剪,超出这个形状以外内容不显示
CGContextClip(ctf);
//6.画图
[image drawInRect:circleRect];
//7.取图
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//8.结束
UIGraphicsEndImageContext();
//9.写入文件
NSData *data = UIImagePNGRepresentation(image);
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
[data writeToFile:path atomically:YES];
//10.显示图片
self.imgView.image = newImage; } ///制作水印
- (void)watermark
{
UIImage *bgImg = [UIImage imageNamed:@"scene.png"]; //上下文:基于位图(bitmap),所有的东西需要绘制到新的图片上去 //1.创建一个基于位图的上下文
UIGraphicsBeginImageContextWithOptions(bgImg.size, NO, 0.0);
//2.画背景
[bgImg drawInRect:CGRectMake(, , bgImg.size.width, bgImg.size.height)];
//3.画水印
UIImage *waterImg = [UIImage imageNamed:@"logo.png"];
CGFloat scale = 0.2;
CGFloat margin = ;
CGFloat waterW = waterImg.size.width * scale;
CGFloat waterH = waterImg.size.height * scale;
CGFloat waterX = bgImg.size.width - waterW - margin;
CGFloat waterY = bgImg.size.height - waterH - margin;
[waterImg drawInRect:CGRectMake(waterX, waterY, waterW, waterH)];
//4.从上下文中取得制作完毕的UIImage对象
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//5.结束上下文
UIGraphicsEndImageContext();
//6.显示到UIImageView
self.imgView.image = newImage;
//7.将image对象压缩为PNG格式的二进制数据
NSData *data = UIImagePNGRepresentation(newImage);
//8.写入文件
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
[data writeToFile:path atomically:YES];
}
///截图
- (IBAction)clip:(UIButton *)sender { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //1.开启上下文
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
//2.将控制器的view的layer渲染到上下文
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
//3.取出图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
NSData *data = UIImagePNGRepresentation(newImage);
[data writeToFile:@"/Users/mac/Desktop/a.png" atomically:YES];
//4.结束上下文
UIGraphicsEndImageContext();
});
} ///创建自定义ImageView
- (void)createimgView
{
MatrixOperation *imgView = [[MatrixOperation alloc] init];
imgView.frame = CGRectMake(, , , );
UIImage *img = [UIImage imageNamed:@"1.jpg"];
imgView.image = img;
[self.view addSubview:imgView];
} - (IBAction)valueChange:(UISlider *)sender { self.brushView.radius = sender.value;
} @end