举个
我们肯定做过这样的需求,给一个图片切圆角,
当然我们大多采用简单粗暴的方法
imageView.layer.cornerRadius = 10
imageView.layer.masksToBounds = true
如果是图片较少的静态的页面也无关紧要,要是可以滑动的页面,
有很多需要裁剪的图片,那么就要考虑性能了。
- 我们就可以采用异步绘制的方法在子线程操作
extension UIImage {
/*
图片裁剪内切圆 异步绘制
*/
class func clipCircleImage( _ image : UIImage?,
_ resultBlock: @escaping(_ newImage: UIImage?)->()) {
guard let realImage = image else { return }
//全局队列的异步线程
DispatchQueue.global().async {
// 获取图片上下文章
UIGraphicsBeginImageContext(realImage.size)
// 利用贝塞尔曲线裁剪
let clipBezier = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: realImage.size.width, height: realImage.size.height))
//把路径设置为裁剪区域(超出裁剪区域以外的内容会被自动裁剪掉)
clipBezier.addClip()
//把图片绘制到上下文当中
realImage.draw(at: CGPoint.zero)
// 获取当前的上下文
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// 关闭上下文
UIGraphicsEndImageContext()
// 回到主线程 完成回调
DispatchQueue.main.async {
resultBlock(newImage)
}
}
}
}
- 调用
let imageV = UIImageView(frame: CGRect(x: 100, y: 100, width: 165, height: 220))
imageV.backgroundColor = UIColor.re
UIImage.clipCircleImage(UIImage(named: "1")) { (newImage) in
imageV.image = newImage
}
view.addSubview(imageV)
------------------------举个结束---------------------------
基本步骤
1.开启图形上下文
2.绘制图片
- 使用drowInRect或者drawAtPoint绘制图片(区别在哪儿?你可以先想一想)
drawInRect是以rect作为图片绘制的区域,图片是以填充的方式被绘制在当前区域图片的大小,rect的宽高比和原图片的宽高比不同时会造成图片的变形
drowAtPoint是以point作为图片绘制的起点,绘制的图片的大小依然是原图片的大小,不会使图片变形 - 将layer渲染在当前上下文
3.从当前上下文获取新的图片
4.关闭上下文
1.绘制图片,可以设置绘制的图片比例或者指定压缩后的图片的大小,可以当做压缩图片使用
+ (UIImage *)scaleImage:(UIImage *)image sclae:(CGFloat)scale {
//确定压缩后的size
CGFloat scaleWidth = image.size.width * scale;
CGFloat scaleHeight = image.size.height * scale;
CGSize scaleSize = CGSizeMake(scaleWidth, scaleHeight);
//开启图形上下文
UIGraphicsBeginImageContext(scaleSize);
//绘制图片
[image drawInRect:CGRectMake(0, 0, scaleWidth, scaleHeight)];
//从图形上下文获取图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//关闭图形上下文
UIGraphicsEndImageContext();
return newImage;
}
3.绘制水印
文字水印
可能你在添加文字水印之后,显示文字字体并不是你设置的字体大小,这是因为画布的size是图片的size,绘制后的图片被添加到ImageView上时可能被压缩或者放大,文字也就会发生变化。
+ (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;
}
4.截屏
1.创建图形上下文
2.将view的layer渲染到图形上下文
3.从图形上下文得到图片
4.关闭图像上下文
//当然如果你只是需要某个view的快照,在iOS7之后你可以使用[view snapshotViewAfterScreenUpdates:NO];来获得,比如实现长按拖拽cell的操作
+ (void)cutView:(UIView *)view success:(void(^)(UIImage *image))success {
//开启图形上下文
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0);
//获取当前上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//渲染
[view.layer renderInContext:ctx];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
success(newImage);
}
5.擦除
1.设置两张图片,上方为我们要擦除的图片,后方为需要展示的图片
2.设置擦除的区域的大小和位置
+ (UIImage *)wipeView:(UIView *)view
point:(CGPoint)point
size:(CGSize)size {
//开启图形上下文
UIGraphicsBeginImageContext(view.bounds.size);
//获取当前上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//渲染
[view.layer renderInContext:ctx];
//计算擦除的rect
CGFloat clipX = point.x - size.width/2;
CGFloat clipY = point.y - size.height/2;
CGRect clipRect = CGRectMake(clipX, clipY, size.width, size.height);
//将该区域设置为透明
CGContextClearRect(ctx, clipRect);
//获取新的图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
6.图片裁剪
矩形区域的裁剪,这里我们就利用drowAtPoint的特性去进行裁剪
1.假设一张图片的size是(600,600)
2.imageView的size是(300,300)
3.我们选择的裁剪区域是(10,10,150,150)
4.而我们为了能够保持原来图片的分辨率,在图片不拉伸的情况下在原图片上进行剪裁,所以实际我们在图片上的剪裁区域就是(20,20,300,300)
5.图片绘制在画布上的点就是(-20,-20),这样我们不需要进行裁剪就能获得我们想要得到的图片啦
+ (UIImage *)cutImage:(UIImage *)image
imageViewSize:(CGSize)size
clipRect:(CGRect)rect {
//图片大小和实际显示大小的比例
CGFloat scale_width = image.size.width/size.width;
CGFloat scale_height = image.size.height/size.height;
//实际剪切区域
CGRect clipRect = CGRectMake(rect.origin.x * scale_width,
rect.origin.y * scale_height,
rect.size.width * scale_width,
rect.size.height * scale_height);
//开启图形上下文
UIGraphicsBeginImageContext(clipRect.size);
//画图
[image drawAtPoint:CGPointMake(-clipRect.origin.x, -clipRect.origin.y)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
自定义点连线截图
1.将自定义点变换到在图片上的点
2.计算出自定义点所在的区域rect
3.开始图形上下文,rect.size
4.绘制path,机型剪裁
5.绘图drawAtPoint,x: - rect.origin.x y: - rect.origin.y
6.从图形上下文获取图片
7.关闭图形上下文
+ (UIImage *)cutImage:(UIImage *)image
imageViewSize:(CGSize)size
clipPoints:(NSArray *)points {
//图片大小和实际显示大小的比例
CGFloat scale_width = image.size.width/size.width;
CGFloat scale_height = image.size.height/size.height;
//处理剪裁的点
NSArray *newPoints = [UIImage points:points scalex:scale_width scaleY:scale_height];
//确定上下左右边缘的点
//x升序数组
NSArray *point_x = [newPoints sortedArrayUsingComparator:^NSComparisonResult(NSValue *obj1, NSValue *obj2) {
CGPoint point1 = [obj1 CGPointValue];
CGPoint point2 = [obj2 CGPointValue];
return point1.x > point2.x;
}];
//y升序数组
NSArray *point_y = [newPoints sortedArrayUsingComparator:^NSComparisonResult(NSValue *obj1, NSValue *obj2) {
CGPoint point1 = [obj1 CGPointValue];
CGPoint point2 = [obj2 CGPointValue];
return point1.y > point2.y;
}];
//确定剪切的区域
CGRect clipRect = CGRectMake([point_x.firstObject CGPointValue].x,
[point_y.firstObject CGPointValue].y,
[point_x.lastObject CGPointValue].x - [point_x.firstObject CGPointValue].x,
[point_y.lastObject CGPointValue].y - [point_y.firstObject CGPointValue].y);
//开启图形上下文
UIGraphicsBeginImageContext(clipRect.size);
UIBezierPath *path = [UIBezierPath bezierPath];
for (NSInteger i = 0; i < newPoints.count; i ++) {
CGPoint point = [newPoints[i] CGPointValue];
if (i == 0) {
[path moveToPoint:point];
} else {
[path addLineToPoint:point];
}
}
[path closePath];
[path addClip];
//画图
[image drawAtPoint:CGPointMake(-clipRect.origin.x, -clipRect.origin.y)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}