ios自定义照相机
2018-12-11 本文已影响0人
画舫烟中浅
由于项目里面需要对拍照后的图片进行编辑,当点击拍照后,拍照按钮变成编辑按钮,然后点击编辑,跳入图片编辑器。系统的照相机已经不再实用。因此只能使用自定义的照相机来实现其功能。
我使用的是AVFoundation这个框架来实现的。说明:图片编辑器使用的是AdobeCreativeSDKCore和AdobeCreativeSDKImage这两个第三方库,要使用此编辑功能的话需要去官网下载AdobeSDK。(下载地址百度一下就有)
具体代码如下:
YHCustomCameraControllerViewController.h文件
#import <UIKit/UIKit.h>
@class YHCustomCameraControllerViewController;
@protocol YHCustomCameraControllerViewControllerDelegate<NSObject>
-(void) YHCustomCameraController:(YHCustomCameraControllerViewController *) pick didFinishPickingMediaWithInfo:(UIImage *) cameraImage;
-(void) YHCustomCameraControllerDidCancel:(YHCustomCameraControllerViewController *) pick;
@end
@interface YHCustomCameraControllerViewController : UIViewController
@property (nonatomic,weak) id <YHCustomCameraControllerViewControllerDelegate> delegate;
@end
YHCustomCameraControllerViewController.m文件
#define KScreenWidth [UIScreen mainScreen].bounds.size.width
#define KScreenHeight [UIScreen mainScreen].bounds.size.height
#import "YHCustomCameraControllerViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>
#import <AdobeCreativeSDKCore/AdobeCreativeSDKCore.h>
#import <AdobeCreativeSDKImage/AdobeCreativeSDKImage.h>
//以下三个静态字符串 是从Adobe获取的 相当于appkey
static NSString * const kCreativeSDKClientId = @"379b94389361494ca14e16b10b16186f";
static NSString * const kCreativeSDKClientSecret = @"2fe9c466-84c5-4ebf-a134-49e54141f4f4";
// static NSString * const kCreativeSDKRedirectURLString = @"ams+2bad2e7649a1288e236fffeeabffa1945276f8aa://adobeid/379b94389361494ca14e16b10b16186f"";
@interface YHCustomCameraControllerViewController ()<AdobeUXImageEditorViewControllerDelegate>{
AdobeUXImageEditorViewController *editorController;
}
// 定义属性
@property (nonatomic,strong) AVCaptureDevice *device; //设备
@property (nonatomic,strong) AVCaptureDeviceInput *input; // 输入
@property (nonatomic,strong) AVCaptureMetadataOutput *output; //输出
@property (nonatomic,strong) AVCaptureStillImageOutput *ImageOutPut; // 图片输出
@property (nonatomic,strong) AVCaptureSession *session; //会话
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer; // 预览
@property (nonatomic,strong) UIButton *photoButton; //拍照按钮
@property (nonatomic,strong) UIButton *cancleButton; //取消按钮
@property (nonatomic,strong) UIButton *switchButton; //切换摄像头按钮
@property (nonatomic,strong) UIButton *edintButton; //编辑按钮
@property (nonatomic,strong) UIView *focusView; //聚焦View
@property (nonatomic,strong) UIImage *image; //返回出去的图片
@property (nonatomic,strong) UIImageView *preImageView;
@end
@implementation YHCustomCameraControllerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
[self initCustomCammra];
[self initSubViews];
// 监听设备横屏
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationDidChangeNotification:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
#pragma mark - 横屏处理
- (BOOL)shouldAutorotate{
return NO;
}
#pragma mark -
- (AVCaptureVideoOrientation)avOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation
{
AVCaptureVideoOrientation result = (AVCaptureVideoOrientation)deviceOrientation;
if ( deviceOrientation == UIDeviceOrientationLandscapeLeft )
result = AVCaptureVideoOrientationLandscapeRight;
else if ( deviceOrientation == UIDeviceOrientationLandscapeRight )
result = AVCaptureVideoOrientationLandscapeLeft;
return result;
}
#pragma mark Notifications 当设备横屏时,修改预览图册frame
- (void)orientationDidChangeNotification:(NSNotification *)nti{
if([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft){
self.previewLayer.frame = CGRectMake(0, 0, KScreenWidth, KScreenHeight-42);
}else if([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait){
self.previewLayer.frame = CGRectMake(0, 42, KScreenWidth, KScreenHeight-100);
}
}
#pragma mark 初始化硬件设备
-(void) initCustomCammra{
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
self.input = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:nil];
self.output = [[AVCaptureMetadataOutput alloc]init];
self.ImageOutPut = [[AVCaptureStillImageOutput alloc]init];
self.session = [[AVCaptureSession alloc]init];
if ([self.session canSetSessionPreset:AVCaptureSessionPreset3840x2160]) {
[self.session setSessionPreset:AVCaptureSessionPreset3840x2160];
}else{
[self.session setSessionPreset:AVCaptureSessionPreset1280x720];
}
if ([self.session canAddInput:self.input]) {
[self.session addInput:self.input];
}
if ([self.session canAddOutput:self.ImageOutPut]) {
[self.session addOutput:self.ImageOutPut];
}
//图像预览
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
self.previewLayer.frame = CGRectMake(0, 42, KScreenWidth, KScreenHeight-42-120);
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:self.previewLayer];
//开始启动
[self.session startRunning];
//修改设备的属性,先加锁
if ([self.device lockForConfiguration:nil]) {
//闪光灯自动
if ([self.device isFlashModeSupported:AVCaptureFlashModeAuto]) {
[self.device setFlashMode:AVCaptureFlashModeAuto];
}
//自动白平衡
if ([self.device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
[self.device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
}
//解锁
[self.device unlockForConfiguration];
}
}
#pragma mark 初始化界面的UI
- (void)initSubViews
{
UIView *stateView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 42)];
stateView.backgroundColor = [UIColor blackColor];
[self.view addSubview:stateView];
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, KScreenHeight-120, KScreenWidth, 120)];
bgView.backgroundColor = [UIColor blackColor];
bgView.tag = 20181206;
[self.view addSubview:bgView];
self.cancleButton = [UIButton new];
[self.cancleButton setTitle:@"取消" forState:UIControlStateNormal];
self.cancleButton.titleLabel.textAlignment = NSTextAlignmentRight;
[self.cancleButton addTarget:self action:@selector(disMiss) forControlEvents:UIControlEventTouchUpInside];
[bgView addSubview:self.cancleButton];
[self.cancleButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@100);
make.height.equalTo(@40);
make.left.equalTo(bgView).offset(1);
make.top.equalTo(bgView).offset(40);
}];
self.photoButton = [UIButton new];
[self.photoButton setImage:[UIImage imageNamed:@"photograph"] forState:UIControlStateNormal];
[self.photoButton addTarget:self action:@selector(shutterCamera) forControlEvents:UIControlEventTouchUpInside];
[bgView addSubview:self.photoButton];
[self.photoButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@60);
make.height.equalTo(@60);
make.centerX.equalTo(bgView.mas_centerX);
make.top.equalTo(@30);
}];
self.edintButton = [UIButton new];
[self.edintButton setTitle:@"编辑" forState:UIControlStateNormal];
[self.edintButton addTarget:self action:@selector(edintingImage) forControlEvents:UIControlEventTouchUpInside];
self.edintButton.hidden = YES;
[bgView addSubview:self.edintButton];
[self.edintButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@40);
make.height.equalTo(@40);
make.centerX.equalTo(bgView.mas_centerX);
make.top.equalTo(@40);
}];
self.focusView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 80, 80)];
self.focusView.layer.borderWidth = 1.0;
self.focusView.layer.borderColor = [UIColor orangeColor].CGColor;
[self.view addSubview:self.focusView];
self.focusView.hidden = YES;
self.switchButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.switchButton setTitle:@"切换" forState:UIControlStateNormal];
self.switchButton.titleLabel.textAlignment = NSTextAlignmentLeft;
[self.switchButton addTarget:self action:@selector(changeCamera) forControlEvents:UIControlEventTouchUpInside];
[bgView addSubview:self.switchButton];
[self.switchButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@100);
make.height.equalTo(@40);
make.right.equalTo(bgView).offset(1);
make.top.equalTo(bgView).offset(40);
}];
UIView *clearView = [[UIView alloc] initWithFrame:self.previewLayer.frame];
clearView.backgroundColor = [UIColor clearColor];
[self.view addSubview:clearView];
// 聚焦的手势
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(focusGesture:)];
[clearView addGestureRecognizer:tapGesture];
}
#pragma mark- 切换摄像头 使用照片
- (void)changeCamera{
//切换摄像头和使用照片为同一个按钮,当点击拍照后,按钮title变为使用照片
if ([self.switchButton.currentTitle isEqualToString:@"切换"]) {
//获取摄像头的数量
NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
//摄像头小于等于1的时候直接返回
if (cameraCount <= 1) return;
AVCaptureDevice *newCamera = nil;
AVCaptureDeviceInput *newInput = nil;
//获取当前相机的方向(前还是后)
AVCaptureDevicePosition position = [[self.input device] position];
//为摄像头的转换加转场动画
CATransition *animation = [CATransition animation];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.duration = 0.5;
animation.type = @"oglFlip";
if (position == AVCaptureDevicePositionFront) {
//获取后置摄像头
newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
animation.subtype = kCATransitionFromLeft;
}else{
//获取前置摄像头
newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
animation.subtype = kCATransitionFromRight;
}
[self.previewLayer addAnimation:animation forKey:nil];
//输入流
newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
if (newInput != nil) {
[self.session beginConfiguration];
//先移除原来的input
[self.session removeInput:self.input];
if ([self.session canAddInput:newInput]) {
[self.session addInput:newInput];
self.input = newInput;
} else {
//如果不能加现在的input,就加原来的input
[self.session addInput:self.input];
}
[self.session commitConfiguration];
}
}else if ([self.switchButton.currentTitle isEqualToString:@"使用照片"]){
//代理方法 将图片传给外部
if ([self.delegate respondsToSelector:@selector(YHCustomCameraController:didFinishPickingMediaWithInfo:)]) {
[self.delegate YHCustomCameraController:self didFinishPickingMediaWithInfo:self.image];
[self dismissViewControllerAnimated:YES completion:nil];
}
[self.preImageView removeFromSuperview];
}
}
#pragma mark - 切换摄像头 系统方法
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for ( AVCaptureDevice *device in devices ){
if ( device.position == position ) {
return device;
}
}
return nil;
}
#pragma mark- 拍照
- (void)shutterCamera
{
AVCaptureConnection * videoConnection = [self.ImageOutPut connectionWithMediaType:AVMediaTypeVideo];
if (videoConnection == nil) {
return;
}
UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
AVCaptureVideoOrientation avcaptureOrientation = [self avOrientationForDeviceOrientation:curDeviceOrientation];
[videoConnection setVideoOrientation:avcaptureOrientation];
if (curDeviceOrientation == UIDeviceOrientationLandscapeLeft || curDeviceOrientation == UIDeviceOrientationLandscapeRight) {
[self horizontalScreenShoot:videoConnection];
}else{
[self.ImageOutPut captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer == nil) {
return;
}
[self.cancleButton setTitle:@"重拍" forState:UIControlStateNormal];
[self.switchButton setTitle:@"使用照片" forState:UIControlStateNormal];
self.photoButton.hidden = YES;
self.edintButton.hidden = NO;
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
self.image = [UIImage imageWithData:imageData];
[self.session stopRunning];
self.previewLayer.hidden = YES;
self.preImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 42, KScreenWidth, KScreenHeight-120-42)];
self.preImageView.layer.masksToBounds = YES;
self.preImageView.image = [self imageCompressForSize:self.image targetSize:self.preImageView.frame.size];
[self.view addSubview:self.preImageView];
}];
}
}
#pragma mark- 横屏模式
-(void)horizontalScreenShoot:(AVCaptureConnection *)videoConnection{
self.view.backgroundColor = [UIColor blackColor];
UIView *view = (UIView*)[self.view viewWithTag:20181206];
view.frame = CGRectMake(0, KScreenHeight-140, KScreenWidth, 120);
[self.ImageOutPut captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer == nil) {
return;
}
[self.cancleButton setTitle:@"重拍" forState:UIControlStateNormal];
[self.switchButton setTitle:@"使用照片" forState:UIControlStateNormal];
self.photoButton.hidden = YES;
self.edintButton.hidden = NO;
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
self.image = [UIImage imageWithData:imageData];
[self.session stopRunning];
self.previewLayer.hidden = YES;
self.preImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, (KScreenHeight-KScreenWidth)/2, KScreenWidth, KScreenWidth*2/3)];
self.preImageView.layer.masksToBounds = YES;
self.preImageView.image = self->_image;
[self.view addSubview:self.preImageView];
}];
}
#pragma mark- 取消
- (void)disMiss
{
//判断取消按钮的状态
if ([self.cancleButton.currentTitle isEqualToString:@"取消"]) {
[self.preImageView removeFromSuperview];
[self dismissViewControllerAnimated:YES completion:nil];
if ([self.delegate respondsToSelector:@selector(YHCustomCameraControllerDidCancel:)]) {
[self.delegate YHCustomCameraControllerDidCancel:self];
}
}else if ([self.cancleButton.currentTitle isEqualToString:@"重拍"]){
[self.cancleButton setTitle:@"取消" forState:UIControlStateNormal];
[self.switchButton setTitle:@"切换" forState:UIControlStateNormal];
self.photoButton.hidden = NO;
self.edintButton.hidden = YES;
self.previewLayer.hidden = NO;
[self.preImageView removeFromSuperview];
[self.session startRunning];
}
}
#pragma mark- 编辑 编辑图片采用的是第三方的Adobe图片编辑器
-(void)edintingImage{
if ([UIDevice currentDevice].systemVersion.floatValue < 9.0) {
[self.view makeToast:NSLocalizedString(@"QBAssetCollectionVC_TostTitle_simple", @"您的系统版本太低,不支持改功能!")];
return;
}
//push 编辑控制器
[[AdobeUXAuthManager sharedManager]setAuthenticationParametersWithClientID:kCreativeSDKClientId clientSecret:kCreativeSDKClientSecret additionalScopeList:@[AdobeAuthManagerUserProfileScope,AdobeAuthManagerEmailScope,AdobeAuthManagerAddressScope]];
[AdobeUXAuthManager sharedManager].redirectURL = [NSURL URLWithString:kCreativeSDKRedirectURLString];
self->editorController = [[AdobeUXImageEditorViewController alloc] initWithImage:self.image];
[self->editorController setDelegate:self];
self->editorController.navigationController.navigationBar.translucent = NO;
[self presentViewController:self->editorController animated:NO completion:^{
}];
}
#pragma mark - AdobeUXImageEditorViewControllerDelegate
-(void)photoEditorCanceled:(AdobeUXImageEditorViewController *)editor{
//横屏状态下编辑强制转化成竖屏
if([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight){
[self interfaceOrientation:UIInterfaceOrientationPortrait];
}
[editor dismissViewControllerAnimated:NO completion:^{
}];
}
-(void)photoEditor:(AdobeUXImageEditorViewController *)editor finishedWithImage:(UIImage *)image{
//横屏状态下编辑强制转化成竖屏
if([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight){
[self interfaceOrientation:UIInterfaceOrientationPortrait];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.image = image;
[self.preImageView setImage:self.image];
[editor dismissViewControllerAnimated:NO completion:^{
}];
});
}
#pragma mark- 聚焦
- (void)focusGesture:(UITapGestureRecognizer*)gesture{
CGPoint point = [gesture locationInView:gesture.view];
[self focusAtPoint:point];
}
- (void)focusAtPoint:(CGPoint)point{
CGSize size = self.previewLayer.frame.size;
CGPoint focusPoint = CGPointMake( point.y /size.height ,1 - point.x/size.width );
if ([self.device lockForConfiguration:nil]) {
if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
[self.device setFocusPointOfInterest:focusPoint];
[self.device setFocusMode:AVCaptureFocusModeAutoFocus];
}
if ([self.device isExposureModeSupported:AVCaptureExposureModeAutoExpose ]) {
[self.device setExposurePointOfInterest:focusPoint];
//曝光量调节
[self.device setExposureMode:AVCaptureExposureModeAutoExpose];
}
[self.device unlockForConfiguration];
_focusView.center = point;
_focusView.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
self->_focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);
}completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
self->_focusView.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
self->_focusView.hidden = YES;
}];
}];
}
}
#pragma mark 强制转屏
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation
{
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = orientation;
// 从2开始是因为0 1 两个参数已经被selector和target占用
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
#pragma mark - 等比例缩放图片
-(UIImage *) imageCompressForSize:(UIImage *)sourceImage targetSize:(CGSize)size{
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = size.width;
CGFloat targetHeight = size.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
if(CGSizeEqualToSize(imageSize, size) == NO){
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if(widthFactor > heightFactor){
scaleFactor = widthFactor;
}else{
scaleFactor = heightFactor;
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
if(widthFactor > heightFactor){
thumbnailPoint.y = (targetHeight - scaledHeight) *0.5;
}else if(widthFactor < heightFactor){
thumbnailPoint.x = (targetWidth - scaledWidth) *0.5;
}
}
UIGraphicsBeginImageContext(size);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil){
NSLog(@"scale image fail");
}
UIGraphicsEndImageContext();
return newImage;
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}
外部调用方法很简单
YHCustomCameraControllerViewController *cemeraVC = [[YHCustomCameraControllerViewController alloc] init];
cemeraVC.delegate = self;
//判断是否有相机权限
[CommonUserPermission getCameraPermissionWith:self completionBlock:^{
[self presentViewController:cemeraVC animated:YES completion:nil];
}];
#pragma mark - YHCustomCameraControllerViewController代理方法 拍照完毕后回调
-(void)YHCustomCameraController:(YHCustomCameraControllerViewController *)pick didFinishPickingMediaWithInfo:(UIImage *)cameraImage{
//将拍照后的图片发送出去
[self sendImage:image];
}
-(void)YHCustomCameraControllerDidCancel:(YHCustomCameraControllerViewController *)pick{
if ([pick isKindOfClass:[YHCustomCameraControllerViewController class]]) {
[pick dismissViewControllerAnimated:YES completion:nil];
}
}
效果图如下:
编辑后的图片IMG_0205.JPG 竖屏拍摄IMG_0274.PNG 横屏拍摄IMG_0276.PNG 点击拍照后IMG_0277.PNG