在项目中有的时候需要用截取图片的功能,有的时候还需要将特定的视图进行截取,所以就写了这个demo。
1.从相册中进行选择一张图片,然后将这张图片进行裁剪,然后将图片展示。这有点类似于上传头像时首先要编辑图片的流程。
2.在图片进行编辑的时候,将截取的图片的视图进行处理。
一、选择图片
点击进入到相册中,选择图片。
- (void)selectedImageAction:(UIButton *)btn {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image = info[UIImagePickerControllerOriginalImage];
WJEditPhotoVC *editPhotoVC = [[WJEditPhotoVC alloc] init];
editPhotoVC.selectedImage = image;
// block回调将编辑好的图片展示到UIImageView上去。
__weak typeof(self) weakSelf = self;
editPhotoVC.block = ^(UIImage *image) {
weakSelf.imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
weakSelf.imageView.contentMode = UIViewContentModeScaleAspectFill;
};
[self presentViewController:editPhotoVC animated:YES completion:nil];
}
二、展示编辑图片
思路:
截取图片,底层放一个底层的UIImageView(backgroundImageView),然后再在上面放置一层蒙层(coveredView)。作用就是单纯的展示这个图片。然后在蒙层上再放置一个UIImageView,他的作用就是被截取,然后回调回之前的页面进行展示的图片。需要处理的页面也是这个最后一个UIImagView(editImageView)。
UI界面的搭建
- (void)setUpUI {
UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:self.view.frame];
backgroundImageView.image = self.selectedImage;
backgroundImageView.userInteractionEnabled = YES;
[backgroundImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
backgroundImageView.clipsToBounds = YES;
[self.view addSubview:backgroundImageView];
UIView *coveredView = [[UIView alloc] initWithFrame:self.view.frame];
coveredView.userInteractionEnabled = YES;
coveredView.backgroundColor = [UIColor blackColor];
coveredView.alpha = 0.6;
[backgroundImageView addSubview:coveredView];
// 剪切的imageView
UIImageView *editImageView = [[UIImageView alloc] initWithFrame:self.view.frame];
editImageView.image = self.selectedImage;
[coveredView addSubview:editImageView];
editImageView.userInteractionEnabled = YES;
[editImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
editImageView.contentMode = UIViewContentModeScaleAspectFit;
editImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
editImageView.clipsToBounds = YES;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panInPicture:)];
[editImageView addGestureRecognizer:pan];
self.editImageView = editImageView;
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:@"重置" forState:UIControlStateNormal];
button.frame = CGRectMake(50, 50, 50, 30);
[button addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
UIButton *sureButton = [UIButton buttonWithType:UIButtonTypeCustom];
[sureButton setTitle:@"确定" forState:UIControlStateNormal];
sureButton.frame = CGRectMake(300, 50, 50, 30);
[sureButton addTarget:self action:@selector(sureAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sureButton];
[self.view bringSubviewToFront:sureButton];
UIButton *reSelectImageButton = [UIButton buttonWithType:UIButtonTypeCustom];
[reSelectImageButton setTitle:@"重选" forState:UIControlStateNormal];
reSelectImageButton.frame = CGRectMake(175, 50, 50, 30);
[reSelectImageButton addTarget:self action:@selector(reSelectedImageAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:reSelectImageButton];
[self.view bringSubviewToFront:reSelectImageButton];
// 图片左下角的展示截取图片的视图
UIImageView *lookOutImageView = [[UIImageView alloc] initWithFrame:CGRectMake(300, 600, 50, 50)];
// lookOutImageView.contentMode = UIViewContentModeScaleAspectFit;
lookOutImageView.backgroundColor = [UIColor cyanColor];
[lookOutImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
lookOutImageView.contentMode = UIViewContentModeScaleAspectFill;
lookOutImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
lookOutImageView.clipsToBounds = YES;
[self.view addSubview:lookOutImageView];
[self.view bringSubviewToFront:lookOutImageView];
self.lookOutImageView = lookOutImageView;
}
按钮的点击事件:
- (void)reSelectedImageAction:(UIButton *)btn {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)cancelAction:(UIButton *)btn {
self.editImageView.frame = self.view.frame;
self.editImageView.image = self.selectedImage;
}
- (void)sureAction:(UIButton *)btn {
self.block(self.neweditImage);
[self dismissViewControllerAnimated:YES completion:nil];
}
在图片被截取后,editImageView的尺寸大小实际上是发生变化了的。所以在重置按钮的点击后,editImageView的frame需要和self.view的大小一致,图片也是需要进行使用之前的图片。同理在截取后,重新截取的时候,也是需要进行以上的操作。
要使用截取操作,就是需要用到手势了,所以在editImageView上添加了UIPanGestureRecognizer手势,要想手势起作用,就需要父视图的交互是可以用的。
// 在storyBoard中拖入的一个手势
- (void)panInPicture:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self.view];
// 1判断手势状态
if (pan.state == UIGestureRecognizerStateBegan) {
// 获取当前点
self.startPoint = currentPoint;
} else if (pan.state == UIGestureRecognizerStateChanged) {
// 移除遮盖
[self.coverView removeFromSuperview];
CGFloat x = self.startPoint.x;
CGFloat y = self.startPoint.y;
CGFloat width = currentPoint.x - self.startPoint.x;
CGFloat height = currentPoint.y - self.startPoint.y;
// 主要是避免从左下想右上方向上的截取造成的rect值无实际意义。
if (width < 0) {
width = -width;
x = x - width;
}
if (height < 0) {
height = -height;
y = y - height;
}
CGRect rect = CGRectMake(x, y, width, height);
// 添加一个view
self.coverView.frame = rect;
[self.editImageView addSubview:_coverView]; // 解决下次进行裁剪的时候没有coverview的覆盖
self.coverRect = rect;
} else if (pan.state == UIGestureRecognizerStateEnded) {
NSLog(@"coverView:%@ - coverRect:%@",NSStringFromCGRect(self.coverView.frame), NSStringFromCGRect(self.coverRect));
[self.coverView removeFromSuperview];
UIImageView *resultImageView = self.editImageView;
UIImage *resultImage = [self editImageFromView:resultImageView];
// 超过遮盖以外的内容裁剪掉
UIGraphicsBeginImageContextWithOptions(self.editImageView.bounds.size, NO, [UIScreen mainScreen].scale);
// 设置一个裁剪区域
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:self.coverView.frame];
[clipPath addClip];
// 移除遮盖
// 进行渲染
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.editImageView.layer renderInContext:ctx];
// 生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.editImageView.image = newImage;
NSLog(@"coverView:%@ - coverRect:%@",NSStringFromCGRect(self.coverView.frame), NSStringFromCGRect(self.coverRect));
self.neweditImage = resultImage;
self.lookOutImageView.image = resultImage;
}
}
完成了截取图片的展示,还差一步就是展示需要使用的图片。也就是说截取的视图并不是我们需要的,因为图片大小和位置都是有偏差的,展示在视图上是有误差的,所以我们要进行处理,这部分的内容。
- (UIImage *)editImageFromView:(UIView *)theView {
//截取全屏
UIGraphicsBeginImageContext(theView.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//截取所需区域
CGRect captureRect = self.coverRect;
CGImageRef sourceImageRef = [image CGImage];
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, captureRect);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
return newImage;
}
附相关的完整代码:
WJSelectedImageVC.h
#import
@interface WJSelectedImageVC : UIViewController
@end
WJSelectedImageVC.m
// 修改截取从相册中选取的图片或者是摄像头拍摄的图片
#import "WJSelectedImageVC.h"
#import "WJEditPhotoVC.h"
@interface WJSelectedImageVC ()
@property (nonatomic, strong) UIImageView *imageView;
@end
@implementation WJSelectedImageVC
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpUI];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.imageView.image = nil;
}
- (void)setUpUI {
self.title = @"截取图片";
self.view.backgroundColor = [UIColor whiteColor];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 100, 100)];
imageView.backgroundColor = [UIColor cyanColor];
[imageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
imageView.clipsToBounds = YES;
[self.view addSubview:imageView];
self.imageView = imageView;
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:@"选择图片" forState:UIControlStateNormal];
button.frame = CGRectMake(80, 300, 80, 30);
[button setBackgroundColor:[UIColor orangeColor]];
[button addTarget:self action:@selector(selectedImageAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)selectedImageAction:(UIButton *)btn {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image = info[UIImagePickerControllerOriginalImage];
WJEditPhotoVC *editPhotoVC = [[WJEditPhotoVC alloc] init];
editPhotoVC.selectedImage = image;
__weak typeof(self) weakSelf = self;
editPhotoVC.block = ^(UIImage *image) {
weakSelf.imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
weakSelf.imageView.contentMode = UIViewContentModeScaleAspectFill;
};
[self presentViewController:editPhotoVC animated:YES completion:nil];
}
@end
WJEditPhotoVC.h
#import
typedef void(^WJEditPhotoBlock)(UIImage *image);
@interface WJEditPhotoVC : UIViewController
@property (nonatomic, strong) UIImage *selectedImage;
@property (nonatomic, strong) WJEditPhotoBlock block;
@end
WJEditPhotoVC.m
// 编辑图片
#import "WJEditPhotoVC.h"
@interface WJEditPhotoVC ()
// 开始手指的点
/* startPoint*/
@property (nonatomic, assign) CGPoint startPoint;
@property (nonatomic, strong) UIImageView *editImageView;
/** coverView*/
@property (nonatomic, strong) UIView *coverView;
@property (nonatomic, strong) UIImage *neweditImage;
@property (nonatomic, strong) UIImageView *lookOutImageView;
@property (nonatomic, assign) CGRect coverRect;
@end
@implementation WJEditPhotoVC
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpUI];
}
- (void)setUpUI {
UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:self.view.frame];
backgroundImageView.image = self.selectedImage;
backgroundImageView.userInteractionEnabled = YES;
[backgroundImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
backgroundImageView.clipsToBounds = YES;
[self.view addSubview:backgroundImageView];
UIView *coveredView = [[UIView alloc] initWithFrame:self.view.frame];
coveredView.userInteractionEnabled = YES;
coveredView.backgroundColor = [UIColor blackColor];
coveredView.alpha = 0.6;
[backgroundImageView addSubview:coveredView];
// 剪切的imageView
UIImageView *editImageView = [[UIImageView alloc] initWithFrame:self.view.frame];
editImageView.image = self.selectedImage;
[coveredView addSubview:editImageView];
editImageView.userInteractionEnabled = YES;
[editImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
editImageView.contentMode = UIViewContentModeScaleAspectFit;
editImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
editImageView.clipsToBounds = YES;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panInPicture:)];
[editImageView addGestureRecognizer:pan];
self.editImageView = editImageView;
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:@"重置" forState:UIControlStateNormal];
button.frame = CGRectMake(50, 50, 50, 30);
[button addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
UIButton *sureButton = [UIButton buttonWithType:UIButtonTypeCustom];
[sureButton setTitle:@"确定" forState:UIControlStateNormal];
sureButton.frame = CGRectMake(300, 50, 50, 30);
[sureButton addTarget:self action:@selector(sureAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sureButton];
[self.view bringSubviewToFront:sureButton];
UIButton *reSelectImageButton = [UIButton buttonWithType:UIButtonTypeCustom];
[reSelectImageButton setTitle:@"重选" forState:UIControlStateNormal];
reSelectImageButton.frame = CGRectMake(175, 50, 50, 30);
[reSelectImageButton addTarget:self action:@selector(reSelectedImageAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:reSelectImageButton];
[self.view bringSubviewToFront:reSelectImageButton];
UIImageView *lookOutImageView = [[UIImageView alloc] initWithFrame:CGRectMake(300, 600, 50, 50)];
// lookOutImageView.contentMode = UIViewContentModeScaleAspectFit;
lookOutImageView.backgroundColor = [UIColor cyanColor];
[lookOutImageView setContentScaleFactor:[[UIScreen mainScreen] scale]];
lookOutImageView.contentMode = UIViewContentModeScaleAspectFill;
lookOutImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
lookOutImageView.clipsToBounds = YES;
[self.view addSubview:lookOutImageView];
[self.view bringSubviewToFront:lookOutImageView];
self.lookOutImageView = lookOutImageView;
}
- (UIView *)coverView {
if (!_coverView) {
_coverView = [[UIView alloc] init];
_coverView.backgroundColor = [UIColor darkGrayColor];
_coverView.alpha = 0.6;
}
return _coverView;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.editImageView.frame = self.view.frame;
self.editImageView.image = self.selectedImage;
}
// 在storyBoard中拖入的一个手势
- (void)panInPicture:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self.view];
// 1判断手势状态
if (pan.state == UIGestureRecognizerStateBegan) {
// 获取当前点
self.startPoint = currentPoint;
} else if (pan.state == UIGestureRecognizerStateChanged) {
// 移除遮盖
[self.coverView removeFromSuperview];
CGFloat x = self.startPoint.x;
CGFloat y = self.startPoint.y;
CGFloat width = currentPoint.x - self.startPoint.x;
CGFloat height = currentPoint.y - self.startPoint.y;
if (width < 0) {
width = -width;
x = x - width;
}
if (height < 0) {
height = -height;
y = y - height;
}
CGRect rect = CGRectMake(x, y, width, height);
// 添加一个view
self.coverView.frame = rect;
[self.editImageView addSubview:_coverView]; // 解决下次进行裁剪的时候没有coverview的覆盖
self.coverRect = rect;
} else if (pan.state == UIGestureRecognizerStateEnded) {
NSLog(@"coverView:%@ - coverRect:%@",NSStringFromCGRect(self.coverView.frame), NSStringFromCGRect(self.coverRect));
[self.coverView removeFromSuperview];
UIImageView *resultImageView = self.editImageView;
UIImage *resultImage = [self editImageFromView:resultImageView];
// 超过遮盖以外的内容裁剪掉
UIGraphicsBeginImageContextWithOptions(self.editImageView.bounds.size, NO, [UIScreen mainScreen].scale);
// 设置一个裁剪区域
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:self.coverView.frame];
[clipPath addClip];
// 移除遮盖
// 进行渲染
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.editImageView.layer renderInContext:ctx];
// 生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.editImageView.image = newImage;
NSLog(@"coverView:%@ - coverRect:%@",NSStringFromCGRect(self.coverView.frame), NSStringFromCGRect(self.coverRect));
self.neweditImage = resultImage;
self.lookOutImageView.image = resultImage;
}
}
- (UIImage *)editImageFromView:(UIView *)theView {
//截取全屏
UIGraphicsBeginImageContext(theView.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//截取所需区域
CGRect captureRect = self.coverRect;
CGImageRef sourceImageRef = [image CGImage];
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, captureRect);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
return newImage;
}
- (void)reSelectedImageAction:(UIButton *)btn {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)cancelAction:(UIButton *)btn {
self.editImageView.frame = self.view.frame;
self.editImageView.image = self.selectedImage;
}
- (void)sureAction:(UIButton *)btn {
self.block(self.neweditImage);
[self dismissViewControllerAnimated:YES completion:nil];
}
@end