1. 本demo通过选择相册和拍照的照片,进行裁剪,然后展示出来。
主要通过LJPhotoCutViewController这个类来裁剪照片,然后通过block回传裁剪后的照片,具体使用如下:
LJPhotoCutViewController *_cutVC = [[LJPhotoCutViewController alloc] initWithImage:image cropFrame:CGRectMake(0, (kDEVICEHEIGHT-kDEVICEWIDTH*_scale)/2, kDEVICEWIDTH, kDEVICEWIDTH*_scale) limitScaleRatio:1];
__weak typeof(self) weakself = self;
[_cutVC setSubmitblock:^(UIViewController *viewController , UIImage *image) {
weakself.LJImageView.image = image;
NSLog(@"裁剪图片完毕");
}];
_cutVC.cancelblock = ^(UIViewController *viewController){
NSLog(@"取消了裁剪图片");
};
[self.navigationController pushViewController:_cutVC animated:YES];
2.
LJPhotoCutViewController源码(.m和.h文件)
#import "LJPhotoCutViewController.h"
#import "UIView+RGSize.h"
#define SCALE_FRAME_Y 100.0f
#define BOUNDCE_DURATION 0.3f
@interface LJPhotoCutViewController ()
@property (nonatomic, strong) UIImage *originalImage;
@property (nonatomic, strong) UIImage *editedImage;
@property (nonatomic, strong) UIImageView *showImgView;
@property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, strong) UIView *ratioView;
@property (nonatomic, assign) CGRect oldFrame;
@property (nonatomic, assign) CGRect largeFrame;
@property (nonatomic, assign) CGFloat limitRatio;
@property (nonatomic, assign) CGRect latestFrame;
@end
@implementation LJPhotoCutViewController
#pragma mark -- dealloc
- (void)dealloc
{
self.originalImage = nil;
self.showImgView = nil;
self.editedImage = nil;
self.overlayView = nil;
self.ratioView = nil;
}
#pragma mark - LifeCycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self initNav];
[self initSubView];
[self initControlBtn];
[self addGestureRecognizers];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO];
}
- (id)initWithImage:(UIImage *)originalImage
cropFrame:(CGRect)cropFrame
limitScaleRatio:(NSInteger)limitRatio
{
if (self = [super init])
{
self.cropFrame = cropFrame;
self.limitRatio = limitRatio;
self.originalImage = originalImage;
}
return self;
}
- (void)initNav
{
//顶部透明条
UIView *_topBar = [[UIView alloc]initWithFrame:CGRectMake(0,0,kDEVICEWIDTH,64)];
_topBar.backgroundColor = [UIColor blackColor];
_topBar.alpha = 0.5;
[self.view addSubview:_topBar];
[self.view bringSubviewToFront:_topBar];
UILabel *_currentPhotoLabel = UILabel.new;
_currentPhotoLabel.frame = CGRectMake(0, 22 + 5, kDEVICEWIDTH, 20);
_currentPhotoLabel.textColor = [UIColor whiteColor];
_currentPhotoLabel.font = loadFont(20);
_currentPhotoLabel.text = @"图片裁剪";
_currentPhotoLabel.textAlignment = NSTextAlignmentCenter;
[_topBar addSubview:_currentPhotoLabel];
}
#pragma mark - Private
- (void)initSubView
{
self.showImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
[self.showImgView setMultipleTouchEnabled:YES];
[self.showImgView setUserInteractionEnabled:YES];
[self.showImgView setImage:self.originalImage];
// scale to fit the screen
CGFloat oriWidth = self.cropFrame.size.width;
CGFloat oriHeight = self.originalImage.size.height * (oriWidth / self.originalImage.size.width);
CGFloat oriX = self.cropFrame.origin.x + (self.cropFrame.size.width - oriWidth) / 2;
CGFloat oriY = self.cropFrame.origin.y + (self.cropFrame.size.height - oriHeight) / 2;
self.oldFrame = CGRectMake(oriX, oriY, oriWidth, oriHeight);
self.latestFrame = self.oldFrame;
self.showImgView.frame = self.oldFrame;
self.largeFrame = CGRectMake(0, 0, self.limitRatio * self.oldFrame.size.width, self.limitRatio * self.oldFrame.size.height);
[self.view addSubview:self.showImgView];
self.overlayView = [[UIView alloc] initWithFrame:self.view.bounds];
self.overlayView.alpha = .5f;
self.overlayView.backgroundColor = [UIColor blackColor];
self.overlayView.userInteractionEnabled = NO;
self.overlayView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.overlayView];
self.ratioView = [[UIView alloc] initWithFrame:self.cropFrame];
self.ratioView.layer.borderColor = [UIColor whiteColor].CGColor;
self.ratioView.layer.borderWidth = 1.0f;
self.ratioView.autoresizingMask = UIViewAutoresizingNone;
[self.view addSubview:self.ratioView];
[self overlayClipping];
[self.view setBackgroundColor:[UIColor blackColor]];
}
- (void)overlayClipping
{
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGMutablePathRef path = CGPathCreateMutable();
// Left side of the ratio view
CGPathAddRect(path, nil, CGRectMake(0, 0,self.cropFrame.origin.x,self.overlayView.frame.size.height));
// Right side of the ratio view
CGPathAddRect(path, nil, CGRectMake(self.cropFrame.origin.x + self.ratioView.frame.size.width,
0,
self.overlayView.frame.size.width - self.ratioView.frame.origin.x - self.cropFrame.size.width,
self.overlayView.frame.size.height));
// Top side of the ratio view
CGPathAddRect(path, nil, CGRectMake(0, 0,
self.overlayView.frame.size.width,
self.cropFrame.origin.y));
// Bottom side of the ratio view
CGPathAddRect(path, nil, CGRectMake(0,
self.cropFrame.origin.y + self.ratioView.frame.size.height,
self.overlayView.frame.size.width,
self.overlayView.frame.size.height - self.ratioView.frame.origin.y + self.cropFrame.size.height));
maskLayer.path = path;
self.overlayView.layer.mask = maskLayer;
CGPathRelease(path);
}
- (void)initControlBtn
{
UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 70.0f, self.view.frame.size.width, 70)];
backView.backgroundColor = [UIColor colorWithRed:40/255.f green:40/255.f blue:40/255.f alpha:0.8];
UIButton *cancelBtn = [self buttonWithTitle:@"取消"];
cancelBtn.frame = CGRectMake(0, 10, 100, 50);
[cancelBtn addTarget:self action:@selector(cancel:) forControlEvents:UIControlEventTouchUpInside];
[backView addSubview:cancelBtn];
UIButton *confirmBtn = [self buttonWithTitle:@"确定"];
confirmBtn.frame = CGRectMake(self.view.frame.size.width - 100.0f, 10, 100, 50);
[confirmBtn addTarget:self action:@selector(confirm:) forControlEvents:UIControlEventTouchUpInside];
[backView addSubview:confirmBtn];
[self.view addSubview:backView];
}
- (UIButton *)buttonWithTitle:(NSString *)title
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor = [UIColor clearColor];
[button setTitle:title forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:18.0f]];
[button.titleLabel setTextAlignment:NSTextAlignmentCenter];
[button.titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
[button.titleLabel setNumberOfLines:0];
[button setTitleEdgeInsets:UIEdgeInsetsMake(5.0f, 5.0f, 5.0f, 5.0f)];
return button;
}
#pragma mark - Action
- (void)confirm:(id)sender
{
if (self.submitblock){
self.submitblock(self, [self getSubImage]);
}
[self backButtonClick];
}
- (void)cancel:(id)sender
{
if (self.cancelblock) {
self.cancelblock(self);
}
[self backButtonClick];
}
#pragma mark - Gestures
// register all gestures
- (void) addGestureRecognizers
{
// add pinch gesture
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
[self.view addGestureRecognizer:pinchGestureRecognizer];
// add pan gesture
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
[self.view addGestureRecognizer:panGestureRecognizer];
}
// pinch gesture handler
- (void) pinchView:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
UIView *view = self.showImgView;
if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || pinchGestureRecognizer.state == UIGestureRecognizerStateChanged)
{
view.transform = CGAffineTransformScale(view.transform, pinchGestureRecognizer.scale, pinchGestureRecognizer.scale);
pinchGestureRecognizer.scale = 1;
}
else if (pinchGestureRecognizer.state == UIGestureRecognizerStateEnded)
{
CGRect newFrame = self.showImgView.frame;
newFrame = [self handleScaleOverflow:newFrame];
newFrame = [self handleBorderOverflow:newFrame];
[UIView animateWithDuration:BOUNDCE_DURATION animations:^{
self.showImgView.frame = newFrame;
self.latestFrame = newFrame;
}];
}
}
// pan gesture handler
- (void) panView:(UIPanGestureRecognizer *)panGestureRecognizer
{
UIView *view = self.showImgView;
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan || panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
// calculate accelerator
CGFloat absCenterX = self.cropFrame.origin.x + self.cropFrame.size.width / 2;
CGFloat absCenterY = self.cropFrame.origin.y + self.cropFrame.size.height / 2;
CGFloat scaleRatio = self.showImgView.frame.size.width / self.cropFrame.size.width;
CGFloat acceleratorX = 1 - ABS(absCenterX - view.center.x) / (scaleRatio * absCenterX);
CGFloat acceleratorY = 1 - ABS(absCenterY - view.center.y) / (scaleRatio * absCenterY);
CGPoint translation = [panGestureRecognizer translationInView:view.superview];
[view setCenter:(CGPoint){view.center.x + translation.x * acceleratorX, view.center.y + translation.y * acceleratorY}];
[panGestureRecognizer setTranslation:CGPointZero inView:view.superview];
}
else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) {
// bounce to original frame
CGRect newFrame = self.showImgView.frame;
newFrame = [self handleBorderOverflow:newFrame];
[UIView animateWithDuration:BOUNDCE_DURATION animations:^{
self.showImgView.frame = newFrame;
self.latestFrame = newFrame;
}];
}
}
#pragma mark - Handle
- (CGRect)handleScaleOverflow:(CGRect)newFrame
{
// bounce to original frame
CGPoint oriCenter = CGPointMake(newFrame.origin.x + newFrame.size.width/2, newFrame.origin.y + newFrame.size.height/2);
if (newFrame.size.width < self.oldFrame.size.width) {
newFrame = self.oldFrame;
}
if (newFrame.size.width > self.largeFrame.size.width) {
newFrame = self.largeFrame;
}
newFrame.origin.x = oriCenter.x - newFrame.size.width/2;
newFrame.origin.y = oriCenter.y - newFrame.size.height/2;
return newFrame;
}
- (CGRect)handleBorderOverflow:(CGRect)newFrame
{
// horizontally
if (newFrame.origin.x > self.cropFrame.origin.x) newFrame.origin.x = self.cropFrame.origin.x;
if (CGRectGetMaxX(newFrame) < self.cropFrame.size.width) newFrame.origin.x = self.cropFrame.size.width - newFrame.size.width;
// vertically
if (newFrame.origin.y > self.cropFrame.origin.y) newFrame.origin.y = self.cropFrame.origin.y;
if (CGRectGetMaxY(newFrame) < self.cropFrame.origin.y + self.cropFrame.size.height) {
newFrame.origin.y = self.cropFrame.origin.y + self.cropFrame.size.height - newFrame.size.height;
}
// adapt horizontally rectangle
if (self.showImgView.frame.size.width > self.showImgView.frame.size.height && newFrame.size.height <= self.cropFrame.size.height) {
newFrame.origin.y = self.cropFrame.origin.y + (self.cropFrame.size.height - newFrame.size.height) / 2;
}
return newFrame;
}
- (UIImage *)getSubImage
{
CGRect squareFrame = self.cropFrame;
CGFloat scaleRatio = self.latestFrame.size.width / self.originalImage.size.width;
CGFloat x = (squareFrame.origin.x - self.latestFrame.origin.x) / scaleRatio;
CGFloat y = (squareFrame.origin.y - self.latestFrame.origin.y) / scaleRatio;
CGFloat w = squareFrame.size.width / scaleRatio;
CGFloat h = squareFrame.size.height / scaleRatio;
if (self.latestFrame.size.width < self.cropFrame.size.width) {
CGFloat newW = self.originalImage.size.width;
CGFloat newH = newW * (self.cropFrame.size.height / self.cropFrame.size.width);
x = 0; y = y + (h - newH) / 2;
w = newH; h = newH;
}
if (self.latestFrame.size.height < self.cropFrame.size.height) {
CGFloat newH = self.originalImage.size.height;
CGFloat newW = newH * (self.cropFrame.size.width / self.cropFrame.size.height);
x = x + (w - newW) / 2; y = 0;
w = newH; h = newH;
}
CGRect myImageRect = CGRectMake(x, y, w, h);
CGImageRef imageRef = self.originalImage.CGImage;
CGImageRef subImageRef = CGImageCreateWithImageInRect(imageRef, myImageRect);
CGSize size;
size.width = myImageRect.size.width;
size.height = myImageRect.size.height;
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, myImageRect, subImageRef);
UIImage* smallImage = [UIImage imageWithCGImage:subImageRef];
UIGraphicsEndImageContext();
CGImageRelease(subImageRef);
return smallImage;
}
@end
#import <UIKit/UIKit.h>
typedef void(^submitBlock)(UIViewController *viewController , UIImage *image);
typedef void(^cancelBlock)(UIViewController *viewController);
@interface LJPhotoCutViewController : CHBaseViewController
@property (nonatomic, copy) submitBlock submitblock;
@property (nonatomic, copy) cancelBlock cancelblock;
@property (nonatomic, assign) CGRect cropFrame;
- (id)initWithImage:(UIImage *)originalImage
cropFrame:(CGRect)cropFrame
limitScaleRatio:(NSInteger)limitRatio;
@end
3.本demo的UI界面(包含相册和拍照图片的获取)
#import "LJPhotoViewController.h"
#import "LJPhotoCutViewController.h"
// 经典16:9裁剪
double deafaultScale = 9.0/16.0;
@interface LJPhotoViewController ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
{
UIImageView *_LJImageView;
}
@property (nonatomic, strong) UIImagePickerController *imagePickerController;
@end
@implementation LJPhotoViewController
#pragma mark -- life cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTopNavBackButton];
[self setTopNavBarTitle:@"图片裁剪"];
[self.view addSubview:self.LJImageView];
[self createTestButton];
//[self requestNetData:newImageUrl];
}
- (UIImagePickerController *)imagePickerController
{
if (!_imagePickerController)
{
_imagePickerController = [[UIImagePickerController alloc] init];
_imagePickerController.delegate = self;
_imagePickerController.allowsEditing = YES;
}
return _imagePickerController;
}
- (void)createTestButton
{
UIButton *_cameraBtn = [[UIButton alloc]initWithFrame:CGRectMake(15, kDEVICEHEIGHT - 64 - 64, kDEVICEWIDTH-30, 44)];
_cameraBtn.backgroundColor = [UIColor grayColor];
[_cameraBtn addTarget:self action:@selector(cameraSysClick) forControlEvents:UIControlEventTouchUpInside];
[_cameraBtn setTitle:@"拍照裁剪" forState:UIControlStateNormal];
_cameraBtn.titleLabel.textColor = [UIColor whiteColor];
_cameraBtn.layer.cornerRadius = 4;
[self.view addSubview:_cameraBtn];
UIButton *_photoLibraryBtn = [[UIButton alloc]initWithFrame:CGRectMake(15, kDEVICEHEIGHT - 64, kDEVICEWIDTH-30, 44)];
_photoLibraryBtn.backgroundColor = [UIColor grayColor];
[_photoLibraryBtn addTarget:self action:@selector(photoLibraryClick) forControlEvents:UIControlEventTouchUpInside];
[_photoLibraryBtn setTitle:@"相册裁剪" forState:UIControlStateNormal];
_photoLibraryBtn.titleLabel.textColor = [UIColor whiteColor];
_photoLibraryBtn.layer.cornerRadius = 4;
[self.view addSubview:_photoLibraryBtn];
}
- (void)showImagePickerWithType:(UIImagePickerControllerSourceType)type
targetController:(UIViewController *)viewController
scale:(double)scale
{
if (type == UIImagePickerControllerSourceTypeCamera)
{
#if TARGET_IPHONE_SIMULATOR //模拟器
NSLog(@"请使用真机测试");
return;
#elif TARGET_OS_IPHONE //真机
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
}
else if(type == UIImagePickerControllerSourceTypePhotoLibrary)
{
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
self.imagePickerController.allowsEditing = YES;
[viewController presentViewController:self.imagePickerController animated:YES completion:nil];
}
#pragma mark -- 图片裁剪
- (UIImageView*)LJImageView
{
if (!_LJImageView) {
_LJImageView = [[UIImageView alloc]init];
//等比例缩放
_LJImageView.contentMode = UIViewContentModeScaleAspectFit;
_LJImageView.frame = CGRectMake((kDEVICEWIDTH - 200)/2.0, 90, 200, 200);
}
return _LJImageView;
}
#pragma mark -- 从相册获取的照片拿过来裁剪
- (void)getEditImage:(UIImage*)image targetVC:(UIViewController*)VC
{
float _scale = 1;//默认
if(deafaultScale > 0 && deafaultScale <= 1.5){
_scale = deafaultScale;
}
LJPhotoCutViewController *_cutVC = [[LJPhotoCutViewController alloc] initWithImage:image cropFrame:CGRectMake(0, (kDEVICEHEIGHT-kDEVICEWIDTH*_scale)/2, kDEVICEWIDTH, kDEVICEWIDTH*_scale) limitScaleRatio:1];
__weak typeof(self) weakself = self;
[_cutVC setSubmitblock:^(UIViewController *viewController , UIImage *image) {
weakself.LJImageView.image = image;
NSLog(@"裁剪图片完毕");
}];
_cutVC.cancelblock = ^(UIViewController *viewController){
NSLog(@"取消了裁剪图片");
};
[self.navigationController pushViewController:_cutVC animated:YES];
}
#pragma mark -- 拍照图片裁剪
- (void)cameraSysClick
{
[self showImagePickerWithType:UIImagePickerControllerSourceTypeCamera targetController:self scale:deafaultScale];
}
#pragma mark -- 系统相册图片裁剪
- (void)photoLibraryClick
{
[self showImagePickerWithType:UIImagePickerControllerSourceTypePhotoLibrary targetController:self scale:deafaultScale];
}
#pragma mark -- UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
UIImage * image = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImageOrientation imageOrientation=image.imageOrientation;
if(imageOrientation != UIImageOrientationUp)
{
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
//Creating an image format with an unknown type is an error
// 方法一:异步赋值
// dispatch_async(dispatch_get_main_queue(), ^{
// self.LJImageView.image = image;
// });
__weak typeof(self) weakself = self;
[picker dismissViewControllerAnimated:YES completion:^{
// 方法二:等UIImagePickerController消失后再去调用image
//weakself.LJImageView.image = image;
//从相册获取的照片拿过来裁剪
[weakself getEditImage:image targetVC:picker];
}];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:^{}];
}
4.图片裁剪界面
5.裁剪后的效果图