进阶!Quartz2D对UIImage的常用操作

1.将方形图片绘制成圆形图片
2.给图片加水印
3.将图片裁剪成圆形
4.将图片裁剪成带有边框的圆形
5.屏幕截屏

一.将方形图片绘制成圆形图片

在实际开发过程中,我们常常使用到将图片的变成圆形,我们想讲讲如何用quartz2D绘制一个圆形的图片

原始图片

通过以下代码绘制成圆形的图片

- (void)drawRect:(CGRect)rect {
   //1.获取图形上下文
   CGContextRef ctx = UIGraphicsGetCurrentContext();
   //2.画个圆
   CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 70, 70));
   //3.剪切
   CGContextClip(ctx);
   //4.将图片绘制上去
   UIImage *image = [UIImage imageNamed:@"5.jpg"];
   [image drawAtPoint:CGPointMake(0, 0)];
   
   //5.渲染
   CGContextFillPath(ctx);
}
绘制的圆形图片

1.使用图形上下文,一定是要先获取
2.我们打算绘制一个圆形的,所以,先绘制一个圆形,在去使用CGContextClip剪切,以后绘制的任何东西,不论在任何位置,只有处在圆心的位置才会显示。


使用三角形裁剪图片

随意画一个三角形,然后绘制图片
- (void)drawRect:(CGRect)rect {
    //1.获取图形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.画个三角形
    CGContextMoveToPoint(ctx, 0, 10);
    CGContextAddLineToPoint(ctx, 250, 67);
    CGContextAddLineToPoint(ctx, 256, 190);
    CGContextClosePath(ctx);
    //3.剪切
    CGContextClip(ctx);
    //4.将图片绘制上去
    UIImage *image = [UIImage imageNamed:@"5.jpg"];
    [image drawAtPoint:CGPointMake(0, 0)];
    
    //绘制一个正方形
    [[UIColor redColor] set];
//    CGContextAddRect(ctx, CGRectMake(10, 10, 203, 240));
    
    //5.渲染
    CGContextFillPath(ctx);
}
  • 想在里面绘制一个红色的矩形,于是打开注释代码CGContextAddRect(ctx, CGRectMake(10, 10, 203, 240)),得到了这个图片
在绘制一个矩形

1.也就是说,只要你调用CGContextClip裁剪方法,那么将来所有的绘制,都只能在裁剪的范围只能绘制
2.如果我们想不受裁剪的影响,想在三角形旁边绘制一个rect,就要用到图形上下文栈的知识了

出战在redColor之后
出战在redColor之前
- (void)drawRect:(CGRect)rect {
    //1.获取图形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    //1.1保存空白的上下文
    CGContextSaveGState(ctx);
    //2.画个三角形
    CGContextMoveToPoint(ctx, 0, 10);
    CGContextAddLineToPoint(ctx, 250, 67);
    CGContextAddLineToPoint(ctx, 256, 190);
    CGContextClosePath(ctx);
    
    //3.剪切
    CGContextClip(ctx);
    //4.将图片绘制上去
    UIImage *image = [UIImage imageNamed:@"5.jpg"];
    [image drawAtPoint:CGPointMake(0, 0)];
    //绘制一个正方形
    
    //还原上下文
    CGContextRestoreGState(ctx);
    [[UIColor redColor] set];
    CGContextAddRect(ctx, CGRectMake(10, 10, 20, 230));
    
    //5.渲染
    CGContextFillPath(ctx);
}

总结:
1.想去剪切图片,而且不形象别的绘制图片,就是用上下文
2.使用绘制图片,我们只是在上下文中显示了,但是要知道我们没有获得一张三角形或者圆形的照片!


二.给图片加水印

1.过去我们做demo使用的是图层上下文,实际上就是将东西绘制到CALayer上,用UIVIew来显示,但是获取不到具体的图片。
2.位图上下文,我们将东西绘制,然后获取一张图片,不再是一个UIVIew了
2.5 绘制到东西到不同上下文,获取的结果是不一样的
3.使用图层上下文,绘制的时候通过UIGraphicsGetCurrentContextdrawRect方法中获取已经生成好的图形上下文。
4.使用位图上下文可以在viewdidLoad中直接写,使用begin,end方法去开启和关闭位图上下文

想将两张图片合成一下,制作出一个水印效果的UIImage图片,保存到本地

水印logo
背景图片
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //0.获取旧的图片
    UIImage *oldImage = [UIImage imageNamed:@"5.jpg"];
    
    //1.开启位图上下文(这句话的意思就是生产了一个这么大的图片!)
     //    UIGraphicsBeginImageContext(oldImage.size);
    /**
     *  有两种开启位图上下文的方法,推荐第二种
     *  size 生成图片的大小,和oldIamge一样大
     * opaque 不透明,YES是不透明,NO是透明
     * scale    拉伸比例,推荐不拉伸 0.0
     */
    UIGraphicsBeginImageContextWithOptions(oldImage.size, NO, 0.0);
    
    //2.绘制背景图片
    [oldImage drawAtPoint:CGPointZero];
    
    //3.绘制logo图片
    UIImage *logoImg = [UIImage imageNamed:@"fgg.png"];
    CGFloat margin = 10;
    CGFloat logoX = oldImage.size.width - margin - logoImg.size.width;
    CGFloat lognY = oldImage.size.height - margin - logoImg.size.height;
    //绘制的位置
    [logoImg drawAtPoint:CGPointMake(logoX,lognY)];
    
    //4.获得新的照片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    //5.关闭位图上下文
    UIGraphicsEndImageContext();
    
    //6.测试,我们将图片放到IamgeView上看看对不对
    self.bgImageView.image = newImage;
    
}
合成之后的图片
  1. 开启位图上下文 UIGraphicsBeginImageContextWithOptions

2.调用UIGraphicsBeginImageContextWithOptions方法就是创建了一个图片,如果是水印,就是bgView的尺寸,也可以自定义size
3.绘制logo的时候,可以设置一个比例,或者具体的位置,这个看实际开发的要求
4.使用UIGraphicsGetImageFromCurrentImageContext方法获取位图上下文制作的图片(如果是打水印,就是获取合成后的图片)
5.关闭上下文UIGraphicsEndImageContext
6.UIGraphicsGetImageFromCurrentImageContext一定要在关闭之前执行,如果关闭了,就获取不到了
7.在实际的开发过程中,我们将打印后的图片保存到沙河目录中,然后上传到自己的服务器中

    //接着上边的代码写的 

    //7,将图片保存到本地沙河目录中
    NSData *data = UIImagePNGRepresentation(newImage);
    //UIImageJPEGRepresentation 中第二个参数,代表压缩的质量,0-1之间,推荐1,但是这个方法出来的图片不如UIImagePNGRepresentation的好,所以推荐使用上边的
//    NSData *data1 = UIImageJPEGRepresentation(newImage, 1);
    
    //8.保存到沙河目录中
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"newIage.png"];
    [data writeToFile:path atomically:YES];

   //这样就可以保存图片到本地了,亲测可用,可以制作一个分类,方便管理使用
三.剪切方形图片成圆形
UIGraphicsBeginImageContextWithOptions中设置**不透明**属性为 YES,底部就是黑色的,建议设置成NO
设置成NO,周边都是透明的非常好
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //裁剪一个圆形的图片(最后会有两张图片,一张是原来方形的,一张是圆形的,过去的讲解的是,如何绘制到UIVIew,但是并没有生成新的图片)
    
    //获取过去的方形的图片
    UIImage * oldIamge = [UIImage imageNamed:@"5.jpg"];
    //1.开启图形上下文
    
    //自定义一个高度也可以,不一定非要用照片的高度!
    CGFloat imgHeight = 100;
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(imgHeight, imgHeight), NO, 0.0);
    
    //2.绘制一个圆形的图片,然后裁剪
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //绘制一个圆形
    CGContextAddArc(ctx, imgHeight*0.5, imgHeight*0.5, imgHeight*0.5, 0, M_PI * 2, NO);
    //剪切上下文,只能在圈子里绘制东西
    CGContextClip(ctx);
    
    //3.将image绘制到圆圈中
    [oldIamge drawInRect:CGRectMake(0, 0, imgHeight, imgHeight)];
    
    //4.获取新的照片
    UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
    
    //5.结束位图上下文
    UIGraphicsEndImageContext();
    
    //显示一下,保存到桌面中
    self.bgImageView.image = newImg;
    
    //保存
    NSData *data = UIImagePNGRepresentation(newImg);
    [data writeToFile:@"/Users/wangxin/Desktop/wangxin2.png" atomically:YES];
}

裁剪图片步骤
1.开启位图上下文,并设置大小,可以使照片的大小,也可以自己设置。我给了一个100dx
2.获取图形上下文,绘制圆形供我们圈定绘图的范围
3.圈定好为绘图的范围,我们来CGContextClip裁剪
4.将图片绘制到指定的圆中
5.获取当前位图上下文所绘制的image
6.关闭上下文


四.将图片裁剪成带有边框的圆形
带有边框的图片

绘制带有边框的圆形图片如何制作?
1.假设原图是100dx * 100dx,边框为10dx
2.先绘制一个大圆,红色,宽高是1000.5+10,填充,绘制
3.绘制一个小圆,用于将来切割,小圆的圆心和大圆相同,但是半径是原图高的一般,也就是100dx
0.5
4.圈定绘制范围
5.将原图绘制到小圆上(x = border,y=border)
6.获取新的图片
7.关闭上下文
8.使用图片即可

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1.加载一张图片
    UIImage * oldIamge = [UIImage imageNamed:@"5.jpg"];
    
    //2.开启图像上下文
    CGFloat border = 10;
    CGFloat imageW = oldIamge.size.width + 2*border;
    CGFloat imageH = oldIamge.size.height + 2*border;
    CGSize imageSize = CGSizeMake(imageW, imageH);
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
    
    //3.取得当前上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    //4.绘制边框(大圆)
    [[UIColor redColor] set];
    CGContextAddArc(ctx, imageW*0.5, imageH*0.5, imageW*0.5, 0, M_PI*2, NO);
    CGContextFillPath(ctx);
    
    //5.绘制小圆(oldimage那么大就行)
    [[UIColor blueColor] set];
    CGContextAddArc(ctx, imageW*0.5, imageW*0.5, oldIamge.size.width*0.5, 0, M_PI*2, NO);
    //裁剪
    CGContextClip(ctx);
    
    //6.将图片绘制到小圆上
    [oldIamge drawInRect:CGRectMake(border, border, oldIamge.size.width, oldIamge.size.width)];
    
    //7.获取当前上下文合成的图片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    //8.结束位图上下文
    UIGraphicsEndImageContext(ctx);

    //9.显示和存储本地
    self.bgImageView.image = newImage;
    NSData *data = UIImagePNGRepresentation(newImage);
    [data writeToFile:@"/Users/wangxin/Desktop/name1.jpg" atomically:YES];
}
五.剪切屏幕
用xib描述view是这样婶儿的
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //截屏
    
    //1.开启上下文
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
    
    //2.将控制器view的layer渲染到上下文
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    
    //3.取出照片
    UIImage *newIamge = UIGraphicsGetImageFromCurrentImageContext();
    
    //4.保存到本地
    NSData *data = UIImagePNGRepresentation(newIamge);
    [data writeToFile:@"/Users/wangxin/Desktop/name13.jpg" atomically:YES];
    
    //5.关闭上下文
    UIGraphicsEndImageContext();
}
截屏效果

1.self.view就是截取的屏幕,我们可以随意的获取某个控件,通过layer截屏
2.所有的UI控件的本质,都是将东西绘制到CALayer,UIView就是一个容器,接受手势的,看到的东西都是CALayer

截取的seg

写在后边
0.本文的所有功可以合并成分类,方便使用,高度自定义,非常好用
1.这些对图片的常用操作很使用,所以我们可以给UIImage写一个分类,将来拿来就用.代码在进阶教程demo
2.推荐一个非常著名的第三方库CorePlot。绘制饼状图,柱状图,和K线图都非常方便。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容