iOS之图片截取

在项目中有的时候需要用截取图片的功能,有的时候还需要将特定的视图进行截取,所以就写了这个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)。

Simulator Screen Shot - iPhone 8 - 2017-11-28 at 22.37.59.png

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

你可能感兴趣的:(iOS之图片截取)