比如需要给图片加上水印,绘制对图片进行裁剪和处理,都是绘图中对图片的特定操作。
绘图图片
UIImage类
UIImage类中提供了创建UIImage对象的方法,这其中既有类方法(class method),也有实例方法(instance method),最常用的有如下几个方法:
imageNamed: 类方法,从main bundle中读取图片文件。通常情况下图片放置在工程的Assets.xcassets文件夹中,只要提供文件名即可创建UIImage对象;
+(nullable UIImage *)imageNamed:(NSString *)name;
imageWithContentOfFile: 类方法,从工程文件中读取图片,传入一个图片路径参数,最终得到一个UIImage对象;
+(nullable UIImage *)imageWithContentsOfFile:(NSString *)path;
imageWithData: 类方法,从一个NSData对象中加载图片;
+(nullable UIImage *)imageWithData:(NSData *)data;
initWithContentsOfFile:实例方法,与imageWithContentOfFile类似,需要传入图片的路径。
-(nullable instancetype)initWithContentsOfFile:(NSString *)path;
下方的示例代码中演示了创建UIImage对象的常用方法。
UIImage *image1 = [UIImage imageNamed:@"logo"];
NSString *path = [[NSBundle mainBundle] pathForResource:@"99ios" ofType:@"png"];
UIImage *image2 = [UIImage imageWithContentsOfFile:path];
绘图方法
在UIImage类中提供了2个主要的绘图方法,可以把图片绘制到绘图上下文中(有些类似于绘画结束后盖印章,只需一盖就可以把一个完整的印章图形显示在纸面上,这个和用笔画画有些区别):
drawAtPoint: 以图片的左上角为锚点,显示在制定的Point位置,图片不做压缩处理,显示原始大小;
-(void)drawAtPoint:(CGPoint)point;
drawInRect: 把图片装在一个矩形区域内显示,图片有可能会放大/缩小或者拉伸/压缩。
-(void)drawInRect:(CGRect)rect;
使用
后绘制的图会把先绘制的盖住。
创建一个名为MainView的类,继承自UIView,在StoryBoard中,修改主控制器View的类型为MainView。
// MainView.m
// UIImage与绘图
//
// Created by on 2019/7/22.
// Copyright © 2019 Shae. All rights reserved.
//
#import "MainView.h"
@implementation MainView
- (void)drawRect:(CGRect)rect{
UIImage *image1=[UIImage imageNamed:@"1"];
NSString *path=[[NSBundle mainBundle] pathForResource: @"2"ofType:@"jpg"];
UIImage *imgae2=[UIImage imageWithContentsOfFile:path];
//先绘制image1
[image1 drawAtPoint:CGPointZero];
//绘制imgae2
[imgae2 drawInRect:CGRectMake(0, 250, 100, 100)];
}
@end
添加水印
在类似新浪微博的应用中,上传的图片都会自动添加水印watermark,水印的添加也是通过绘图的方式实现的,即首先在画布上画上图片,然后再添加上水印签名。
对UIImage对象的修改和加工,经常会使用到UIGraphics类中提供的函数。对UIImage对象进行修改,通常会采取如下步骤:
- 调用UIGraphicsBeginImageContext方法,开启一个空白的图像上下文,图像上下文包含了绘图的参数和属性,就是一个画布,一个绘图环境;
UIKIT_EXTERN void UIGraphicsBeginImageContext(CGSize size);
UIKIT_EXTERN void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
- 绘制该上下文中的内容,例如添加图片,添加文字等;
- 根据最新的图像上下文中的内容,调用UIGraphicsGetImageFromCurrentImageContext函数,得到一个图像合成后的UIImage对象;
UIKIT_EXTERN UIImage* __null_unspecified UIGraphicsGetImageFromCurrentImageContext(void);
- 调用UIGraphicsEndImageContext函数,关闭上下文,以节省内存。
UIKIT_EXTERN void UIGraphicsEndImageContext(void);
使用
分类的方式为UIImage添加水印的函数
分类.h
//
// UIImage+MYImage.h
// UIImage与绘图
//
// Created by on 2019/7/22.
// Copyright © 2019 Shae. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (MYImage)
+(UIImage *) image:(UIImage *)image addWaterMarkWithString:(NSString *)string;
@end
NS_ASSUME_NONNULL_END
分类.m
//
// UIImage+MYImage.m
// UIImage与绘图
//
// Created by on 2019/7/22.
// Copyright © 2019 Shae. All rights reserved.
//
#import "UIImage+MYImage.h"
@implementation UIImage (MYImage)
+ (UIImage *)image:(UIImage *)image addWaterMarkWithString:(NSString *)string{
//开启一个图形上下文
UIGraphicsBeginImageContext(image.size);
//绘制上下文:1.绘制图片
[image drawAtPoint:CGPointMake(0, 20)];
//绘制上下文:2.添加文字到上下文
NSDictionary *dict=@{NSFontAttributeName:[UIFont systemFontOfSize:80.0],
NSForegroundColorAttributeName:[UIColor blackColor]
};
[string drawAtPoint:CGPointMake(60, 60) withAttributes:dict];
//从图形上下文中获取合成的图片
UIImage *watermarkImage=UIGraphicsGetImageFromCurrentImageContext();
//关闭上下文
UIGraphicsEndImageContext();
return watermarkImage;
}
@end
使用分类
-(void)addWaterMark{
UIImage *image1=[UIImage imageNamed:@"1"];
UIImage *imageWater =[UIImage image:image1 addWaterMarkWithString:@"Shae"];
UIImageView *imageView=[[UIImageView alloc]initWithImage:imageWater];
imageView.frame=CGRectMake(0, 0, 1025, 576);
[self addSubview:imageView];
}
代码1:
https://github.com/ShaeZhuJiu/UIImgaeAndDraw_1.git
裁剪圆形图片
比如把一个方形图片裁剪成圆形,比如个人头像。
使用绘图的方式裁剪
当使用绘图的方式对图片进行裁剪时,主要的思路就是裁剪出来一个圆形的图形上下文,相当于得到了一张圆形的画布,然后在这个圆形的画布上绘画,自然得到了一张圆形的图片。
下面的示例代码实现了对一个正方形的图片进行裁剪,最终得到一个圆形的图片。
-(UIImage *)clipImageView:(UIImage *)image{
//开启上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
// 获取路径
UIBezierPath *path=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//裁剪圆形
[path addClip];
//n把图片塞进上下文
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//保存新图片
UIImage *newImage=UIGraphicsGetImageFromCurrentImageContext();
//关闭上下文
UIGraphicsEndImageContext();
return newImage;
}
//
// ViewController.m
// UIImageLipe
//
// Created by 谢鑫 on 2019/7/23.
// Copyright © 2019 Shae. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *clipImageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *image=[UIImage imageNamed:@"2"];
UIImage *newImage=[self clipImageView:image];
_clipImageView.image=newImage;
}
设置背景颜色clearColor,可以图片没占的地方为透明。
headImage.backgroundColor=[UIColor clearColor];
或
/// 对图片生成圆角,可用于button等的背景图片
/// @param OriginalImage 原图,可用纯色图片
/// @param sizeToFit 大小
/// @param radius 圆角弧度
+ (UIImage *)OriginalImage:(UIImage *)OriginalImage WithRoundedCornersAndSize:(CGSize)sizeToFit andCornerRadius:(CGFloat)radius
{
CGRect rect = (CGRect){0.f, 0.f, sizeToFit};
UIGraphicsBeginImageContextWithOptions(sizeToFit, NO, UIScreen.mainScreen.scale);
CGContextAddPath(UIGraphicsGetCurrentContext(),
[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:4].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[OriginalImage drawInRect:rect];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
其他方法
在实际的开发过程中,还有一种更加常用并且简便的方法,能够实现对图片控件的裁剪,即修改UIView的layer属性。
UIView类中有一个CALayer类型的属性–layer,通过对layer的修改,也可以达到对图片的裁剪效果。
CALayer类中有两个常用的属性,cornerRadius和masksToBounds属性
以上方法只适用于一个界面只有几个按钮,如果是大量的按钮,如UITableViewCell上那么就会出现卡顿,造成这个原因就是离屏渲染。
@property CGFloat cornerRadius;//圆角半径
@property BOOL masksToBounds; //是否裁剪
-(void)clipImageView2{
UIImage *image=[UIImage imageNamed:@"2"];
_clipImageView.image=image;
_clipImageView.layer.cornerRadius=_clipImageView.bounds.size.width*0.5;
_clipImageView.layer.masksToBounds=YES;
}
截屏
在游戏应用中,通常会提供截屏的功能,用来记录辉煌的游戏记录。UIKit框架中,也提供了简单高效的截屏方法,以及保存截屏文件的方法,供开发者直接调用。
通常情况下,在应用中添加截屏功能需要有如下两个步骤:
第一步,获取当前屏幕截屏图片。在UIView类中,提供了drawViewHierarchyInRect: afterScreenUpdates方法,利用该方法可以实现对任何View视图的截取图像操作。在使用之前,需要提前准备绘图上下文。
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates ;
第二步,保存图片到本地相册。在UIImagePickerController类中,封装了一个专门用于保存图片到相册的函数UIImageWriteToSavedPhotosAlbum。通过该函数可以把UIImage图片对象存放到手机相册中。
UIKIT_EXTERN void UIImageWriteToSavedPhotosAlbum(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo) ;
使用
-(void)myScreenShot{
//开启一个图形上下文
UIGraphicsBeginImageContext(self.view.bounds.size);
//截屏
if([self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES]){
NSLog(@"Successfully draw the screenshot.");
}else{
NSLog(@"Failed to draw the screenshot.");
}
//获取当前d上下文
UIImage *screenShot= UIGraphicsGetImageFromCurrentImageContext();
//关闭上下文
UIGraphicsEndImageContext();
//保存到相册
UIImageWriteToSavedPhotosAlbum(screenShot, self, nil, nil);
}
保存图片报错 权限Crash问题:
解决:
1.在项目中找到info.plist文件,右键点击以 Source Code形式打开
2.添加报错信息中的键值对,这里以 PhotoLibrary 作为例子
<key>NSPhotoLibraryAddUsageDescription</key>
<string>此 App 需要您的同意才能读取媒体资料库</string>
绘制纯色图片
/// 生成纯色图片
/// @param color [UIColor redColor]
/// @param rect CGRectMake(0, 0, _editBtn.frame.size.width, _editBtn.frame.size.height)],必须0,0开始
+ (UIImage *)createImageWithColor:(UIColor *)color frame:(CGRect)rect
{
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
代码2
https://github.com/ShaeZhuJiu/UIImageClip.git