iOS自定义拍照

来源:互联网 发布:ajax如何解析json数据 编辑:程序博客网 时间:2024/06/06 10:41
////  ScanCameraController.m//  FanHeIOS2.0////  Created by 胡梦驰 on 2017/8/14.//  Copyright © 2017年 胡梦驰. All rights reserved.//#import "ScanCameraController.h"#import <AVFoundation/AVFoundation.h>#import <AssetsLibrary/AssetsLibrary.h>#import "ScanCardViewController.h"typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice);@interface ScanCameraController ()<UIImagePickerControllerDelegate, UINavigationControllerDelegate>@property (strong,nonatomic) AVCaptureSession *captureSession;//负责输入和输出设置之间的数据传递@property (strong,nonatomic) AVCaptureDeviceInput *captureDeviceInput;//负责从AVCaptureDevice获得输入数据@property (strong,nonatomic) AVCaptureStillImageOutput *captureStillImageOutput;//照片输出流@property (strong,nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;//相机拍摄预览图层@property (weak, nonatomic) IBOutlet UIView *viewContainer;@property (weak, nonatomic) IBOutlet UIButton *takeButton;//拍照按钮@property (weak, nonatomic) IBOutlet UIButton *flashButton;//选择闪光灯按钮@property (weak, nonatomic) IBOutlet UIButton *flashAutoButton;//自动闪光灯按钮@property (weak, nonatomic) IBOutlet UIButton *flashOnButton;//打开闪光灯按钮@property (weak, nonatomic) IBOutlet UIButton *flashOffButton;//关闭闪光灯按钮@property (weak, nonatomic) IBOutlet UIImageView *focusCursor; //聚焦光标@end@implementation ScanCameraController// 作用:拦截手势触发- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{    return NO;}- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = BLACK_COLOR;}- (void)viewWillAppear:(BOOL)animated{    [super viewWillAppear:animated];    [[UIApplication sharedApplication] setStatusBarHidden:YES];        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {        if(granted){        }else{            dispatch_async(dispatch_get_main_queue(), ^{                [[[CommonUIAlert alloc] init] showCommonAlertView:self title:@"" message:@"请在iPhone的“设置>隐私>相机”选项中,允许金脉+访问你的相机" cancelButtonTitle:@"取消" otherButtonTitle:@"设置" cancle:^{                    [self.navigationController popViewControllerAnimated:YES];                } confirm:^{                    if(IOS_X >= 10){                        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];                    }else{                        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy"]];                    }                }];                                });            return;        }    }];    //初始化会话    _captureSession=[[AVCaptureSession alloc] init];    if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {        //设置分辨率,1280x720, 图片的旋转方向是向右        _captureSession.sessionPreset=AVCaptureSessionPreset1280x720;    }        //获得输入设备    AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置摄像头    if (!captureDevice) {        NSLog(@"取得后置摄像头时出现问题.");        return;    }        //根据输入设备初始化设备输入对象,用于获得输入数据    NSError *error=nil;    _captureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:captureDevice error:&error];    if (error) {        NSLog(@"取得设备输入对象时出错,错误原因:%@",error.localizedDescription);        return;    }        //初始化设备输出对象,用于获得输出数据    _captureStillImageOutput = [[AVCaptureStillImageOutput alloc] init];    NSDictionary *outputSettings = @{AVVideoWidthKey : @(WIDTH),AVVideoHeightKey: @(HEIGHT-132),AVVideoCodecKey:AVVideoCodecJPEG};    [_captureStillImageOutput setOutputSettings:outputSettings];//输出设置        //将设备输入添加到会话中    if ([_captureSession canAddInput:_captureDeviceInput]) {        [_captureSession addInput:_captureDeviceInput];    }        //将设备输出添加到会话中    if ([_captureSession canAddOutput:_captureStillImageOutput]) {        [_captureSession addOutput:_captureStillImageOutput];    }        //创建视频预览层,用于实时展示摄像头状态    _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];        CALayer *layer = self.viewContainer.layer;    layer.masksToBounds = YES;        _captureVideoPreviewLayer.frame = CGRectMake(0, 0, WIDTH, HEIGHT-132);    _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;//填充模式    //将视频预览层添加到界面中//    [layer addSublayer:_captureVideoPreviewLayer];    [layer insertSublayer:_captureVideoPreviewLayer below:self.focusCursor.layer];        [self addNotificationToCaptureDevice:captureDevice];    [self addGenstureRecognizer];    [self setFlashModeButtonStatus];}- (void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];    [self.captureSession startRunning];}- (void)viewDidDisappear:(BOOL)animated{    [super viewDidDisappear:animated];    [self.captureSession stopRunning];    [self removeNotification];}- (void)dealloc{    [self removeNotification];}#pragma mark - 获取图片跳转到扫面结果页面 - (void)gotoScanCardVC:(UIImage*)image{    ScanCardViewController *vc = [CommonMethod getVCFromNib:[ScanCardViewController class]];    vc.imageData = image;    [self.navigationController pushViewController:vc animated:YES];}#pragma mark - UI按钮方法#pragma mark 拍照- (IBAction)takeButtonClick:(UIButton *)sender {    //根据设备输出获得连接    AVCaptureConnection *captureConnection = [self.captureStillImageOutput connectionWithMediaType:AVMediaTypeVideo];    //根据连接取得设备输出的数据    [self.captureStillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer,NSError *error) {        if (imageDataSampleBuffer) {            NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];            UIImage *image = [UIImage imageWithData:imageData];            //保存到手机相册//            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);            [self gotoScanCardVC:[self scaleImage:[UIImage fixOrientation:image]]];        }            }];}#pragma mark 选择闪光灯- (IBAction)flashChoiceClick:(UIButton *)sender {    BOOL isShow = !self.flashAutoButton.hidden;    self.flashOnButton.hidden = isShow;    self.flashOffButton.hidden = isShow;    self.flashAutoButton.hidden = isShow;}#pragma mark 自动闪光灯开启- (IBAction)flashAutoClick:(UIButton *)sender {    [self setFlashMode:AVCaptureFlashModeAuto];    [self setFlashModeButtonStatus];}#pragma mark 打开闪光灯- (IBAction)flashOnClick:(UIButton *)sender {    [self setFlashMode:AVCaptureFlashModeOn];    [self setFlashModeButtonStatus];}#pragma mark 关闭闪光灯- (IBAction)flashOffClick:(UIButton *)sender {    [self setFlashMode:AVCaptureFlashModeOff];    [self setFlashModeButtonStatus];}#pragma mark 取消- (IBAction)navBackClick:(UIButton *)sender {    [self.navigationController popViewControllerAnimated:NO];}#pragma mark 相册- (IBAction)photoClick:(UIButton *)sender {    ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];    if (author == kCLAuthorizationStatusRestricted || author ==kCLAuthorizationStatusDenied){        [[[CommonUIAlert alloc] init] showCommonAlertView:self title:@"" message:@"请在iPhone的“设置>隐私>相册”选项中,允许金脉+访问你的相册" cancelButtonTitle:@"取消" otherButtonTitle:@"设置" cancle:^{        } confirm:^{            if(IOS_X >= 10){                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];            }else{                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy"]];            }        }];        return;    }    [[UIApplication sharedApplication] setStatusBarHidden:NO];    UIImagePickerController *ctrl = [[UIImagePickerController alloc] init];    ctrl.delegate = self;    [self setNavigationBar_white];    ctrl.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;    if([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0) {        self.modalPresentationStyle = UIModalPresentationOverCurrentContext;    }    [self presentViewController:ctrl animated:YES completion:^{        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];    }];}- (UIImage*)scaleImage:(UIImage*)originImage{    CGSize retSize = originImage.size;    CGFloat sizeWidth = retSize.width;    CGFloat sizeHeight = sizeWidth*(HEIGHT-132)/WIDTH;        CGImageRef imageRef = CGImageCreateWithImageInRect([originImage CGImage], CGRectMake(0, (retSize.height-sizeHeight)/2, sizeWidth, sizeHeight));//获取图片整体部分    UIImage *image = [UIImage imageWithCGImage:imageRef scale:originImage.scale orientation:UIImageOrientationUp];    return image;}#pragma mark -- UIImagePickerControllerDelegate//点击相册中的图片 货照相机照完后点击use  后触发的方法- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{    [self setNavigationBar_kdefaultColor];    UIImage *image = info[@"UIImagePickerControllerOriginalImage"];    [self gotoScanCardVC:image];    [picker dismissViewControllerAnimated:YES completion:nil];}//点击cancel 调用的方法- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{    [self setNavigationBar_kdefaultColor];    [picker dismissViewControllerAnimated:YES completion:nil];}#pragma mark - 通知 给输入设备添加通知-(void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{    //注意添加区域改变捕获通知必须首先设置设备允许捕获    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {        captureDevice.subjectAreaChangeMonitoringEnabled=YES;    }];    //捕获区域发生改变    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];}#pragma mark - 移除所有通知-(void)removeNotification{    [[NSNotificationCenter defaultCenter] removeObserver:self];}-(void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession{    //会话出错    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];}/** *  设备连接成功 * *  @param notification 通知对象 */-(void)deviceConnected:(NSNotification *)notification{    NSLog(@"设备已连接...");}/** *  设备连接断开 * *  @param notification 通知对象 */-(void)deviceDisconnected:(NSNotification *)notification{    NSLog(@"设备已断开.");}/** *  捕获区域改变 * *  @param notification 通知对象 */-(void)areaChange:(NSNotification *)notification{    NSLog(@"捕获区域改变...");}/** *  会话出错 * *  @param notification 通知对象 */- (void)sessionRuntimeError:(NSNotification *)notification{    NSLog(@"会话发生错误.");}#pragma mark - 私有方法/** *  取得指定位置的摄像头 * *  @param position 摄像头位置 * *  @return 摄像头设备 */- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{    NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];    for (AVCaptureDevice *camera in cameras) {        if ([camera position]==position) {            return camera;        }    }    return nil;}/** *  改变设备属性的统一操作方法 * *  @param propertyChange 属性改变操作 */- (void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{    AVCaptureDevice *captureDevice = [self.captureDeviceInput device];    NSError *error;    //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁    if ([captureDevice lockForConfiguration:&error]) {        propertyChange(captureDevice);        [captureDevice unlockForConfiguration];    }else{        NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription);    }}/** *  设置闪光灯模式 * *  @param flashMode 闪光灯模式 */- (void)setFlashMode:(AVCaptureFlashMode )flashMode{    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {        if ([captureDevice isFlashModeSupported:flashMode]) {            [captureDevice setFlashMode:flashMode];        }    }];}/** *  设置聚焦模式 * *  @param focusMode 聚焦模式 */- (void)setFocusMode:(AVCaptureFocusMode )focusMode{    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {        if ([captureDevice isFocusModeSupported:focusMode]) {            [captureDevice setFocusMode:focusMode];        }    }];}/** *  设置曝光模式 * *  @param exposureMode 曝光模式 */- (void)setExposureMode:(AVCaptureExposureMode)exposureMode{    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {        if ([captureDevice isExposureModeSupported:exposureMode]) {            [captureDevice setExposureMode:exposureMode];        }    }];}/** *  设置聚焦点 * *  @param point 聚焦点 */- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {        if ([captureDevice isFocusModeSupported:focusMode]) {            [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];        }        if ([captureDevice isFocusPointOfInterestSupported]) {            [captureDevice setFocusPointOfInterest:point];        }        if ([captureDevice isExposureModeSupported:exposureMode]) {            [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];        }        if ([captureDevice isExposurePointOfInterestSupported]) {            [captureDevice setExposurePointOfInterest:point];        }    }];}/** *  添加点按手势,点按时聚焦 */- (void)addGenstureRecognizer{    UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];    [self.viewContainer addGestureRecognizer:tapGesture];}- (void)tapScreen:(UITapGestureRecognizer *)tapGesture{    CGPoint point= [tapGesture locationInView:self.viewContainer];    //将UI坐标转化为摄像头坐标    CGPoint cameraPoint= [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point];    [self setFocusCursorWithPoint:point];    [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];}/** *  设置闪光灯按钮状态 */- (void)setFlashModeButtonStatus{    AVCaptureDevice *captureDevice = [self.captureDeviceInput device];    AVCaptureFlashMode flashMode=captureDevice.flashMode;    if([captureDevice isFlashAvailable]){        self.flashAutoButton.hidden = YES;        self.flashOnButton.hidden = YES;        self.flashOffButton.hidden = YES;        self.flashAutoButton.selected = NO;        self.flashOnButton.selected = NO;        self.flashOffButton.selected = NO;        switch (flashMode) {            case AVCaptureFlashModeAuto:                self.flashAutoButton.selected = YES;                [self.flashButton setImage:kImageWithName(@"btn_smmp_flashauto") forState:UIControlStateNormal];                break;            case AVCaptureFlashModeOn:                self.flashOnButton.selected = YES;                [self.flashButton setImage:kImageWithName(@"btn_smmp_flashopen") forState:UIControlStateNormal];                break;            case AVCaptureFlashModeOff:                self.flashOffButton.selected = YES;                [self.flashButton setImage:kImageWithName(@"btn_smmp_flashclose") forState:UIControlStateNormal];                break;            default:                break;        }    }else{        self.flashAutoButton.hidden=YES;        self.flashOnButton.hidden=YES;        self.flashOffButton.hidden=YES;    }}/** *  设置聚焦光标位置 * *  @param point 光标位置 */- (void)setFocusCursorWithPoint:(CGPoint)point{    self.focusCursor.center = point;    self.focusCursor.transform = CGAffineTransformMakeScale(1.5, 1.5);    self.focusCursor.alpha = 1.0;    [UIView animateWithDuration:1.0 animations:^{        self.focusCursor.transform = CGAffineTransformIdentity;    } completion:^(BOOL finished) {        self.focusCursor.alpha = 0;            }];}@end