AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)

来源:互联网 发布:尊享e生 知乎 编辑:程序博客网 时间:2024/04/29 03:05

#import "ViewController.h"

#import <AVFoundation/AVFoundation.h>

#import <AssetsLibrary/AssetsLibrary.h>//写入相册需要的


@interface ViewController ()<UIGestureRecognizerDelegate>

/**

 *  AVCaptureSession对象来执行输入设备和输出设备之间的数据传递

 */

@property (nonatomic,strong)AVCaptureSession* session;

/**

 *  输入设备

 */

@property (nonatomic,strong)AVCaptureDeviceInput* videoInput;

/**

 *  照片输出流

 */

@property (nonatomic,strong)AVCaptureStillImageOutput* stillImageOutput;//10.0以前

//@property (nonatomic, strong) AVCapturePhotoOutput* stillImageOutput;//10.0以后

/**

 *  预览图层

 */

@property (nonatomic,strong)AVCaptureVideoPreviewLayer* previewLayer;


@property (strong,nonatomicUIButton *captureBtn;//拍照按钮

@property (strong,nonatomic)UIButton *openCaptureBtn;//打开摄像头按钮

@property(nonatomic,assign)BOOL isUsingFrontFacingCamera;//切换镜头

/**

 *  记录开始的缩放比例

 */

@property(nonatomic,assign)CGFloat beginGestureScale;

/**

 *  最后的缩放比例

 */

@property(nonatomic,assign)CGFloat effectiveScale;

@end


@implementation ViewController


-(void)takeCapture{

    [selftakePhotoButtonClick:nil];//拍照


}

-(void)openCapture{



}


-(void)flashBtn{

    [selfflashButtonClick:nil];//闪光灯

}


-(void)glassBtn{

    [selfswitchCameraSegmentedControlClick:nil];//切换镜头


}

- (void)viewDidLoad {

    [superviewDidLoad];

    [selfsetUpGesture];


    UIButton *captureBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,300,60,30)];

    self.captureBtn=captureBtn;

    captureBtn.backgroundColor=[UIColorblueColor];

    captureBtn.titleLabel.textColor=[UIColorgreenColor];

    [captureBtn setTitle:@"拍照"forState:UIControlStateNormal];

    [captureBtn addTarget:self action:@selector(takeCapture)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:captureBtn];

    

    UIButton *openCaptureBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,380,60,30)];

    self.openCaptureBtn=openCaptureBtn;

    openCaptureBtn.backgroundColor=[UIColorblueColor];

    [openCaptureBtn setTitle:@"摄像"forState:UIControlStateNormal];

    [openCaptureBtn addTarget:selfaction:@selector(openCapture)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:openCaptureBtn];

    

    UIButton *flashBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,420,60,30)];


    flashBtn.backgroundColor=[UIColorblueColor];

    [flashBtn setTitle:@"闪光灯"forState:UIControlStateNormal];

    [flashBtn addTarget:selfaction:@selector(flashBtn)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:flashBtn];


    UIButton *glassBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,480,60,30)];

    

    glassBtn.backgroundColor=[UIColorblueColor];

    [glassBtn setTitle:@"切换摄像头"forState:UIControlStateNormal];

    [glassBtn addTarget:selfaction:@selector(glassBtn)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:glassBtn];

        [selfinitAVCaptureSession];

//    self.openCaptureBtn.hidden = NO;

//    self.captureBtn.hidden = YES;

}



//闪光灯的设置非常简单,只需要修改deviceflashMode属性即可,这里需要注意的是,修改device时候需要先锁住,修改完成后再解锁,否则会崩溃,设置闪光灯的时候也需要做安全判断,验证设备是否支持闪光灯,有些iOS设备是没有闪光灯的,如果不做判断还是会crash

- (void)flashButtonClick:(UIBarButtonItem *)sender {

    

    NSLog(@"flashButtonClick");

    //mediatype类型: AVMediaTypeVideo, AVMediaTypeAudio, or AVMediaTypeMuxed

    AVCaptureDevice *device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

    

    //修改前必须先锁定

    [device lockForConfiguration:nil];

    //必须判定是否有闪光灯,否则如果没有闪光灯会崩溃

    if ([devicehasFlash]) {

        device.flashMode =AVCaptureFlashModeOn;


//        if (device.flashMode == AVCaptureFlashModeOff) {

//            device.flashMode = AVCaptureFlashModeOn;

//            

////            [sender setTitle:@"flashOn"];

//        } else if (device.flashMode == AVCaptureFlashModeOn) {

//            device.flashMode = AVCaptureFlashModeAuto;

////            [sender setTitle:@"flashAuto"];

//        } else if (device.flashMode == AVCaptureFlashModeAuto) {

//            device.flashMode = AVCaptureFlashModeOff;

////            [sender setTitle:@"flashOff"];

//        }

        

    } else {

        

        NSLog(@"设备不支持闪光灯");

    }

    [device unlockForConfiguration];

}


#pragma 创建手势

- (void)setUpGesture{

    

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePinchGesture:)];

    pinch.delegate =self;

    [self.viewaddGestureRecognizer:pinch];

}


#pragma mark gestureRecognizer delegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

{

    if ( [gestureRecognizerisKindOfClass:[UIPinchGestureRecognizerclass]] ) {

        self.beginGestureScale =self.effectiveScale;

    }

    returnYES;

}

//缩放手势用于调整焦距

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer{

    

    BOOL allTouchesAreOnThePreviewLayer =YES;

    NSUInteger numTouches = [recognizernumberOfTouches], i;//几个手指

    for ( i =0; i < numTouches; ++i ) {

        CGPoint location = [recognizerlocationOfTouch:iinView:self.view];//i是指第几个手指

        CGPoint convertedLocation = [self.previewLayerconvertPoint:locationfromLayer:self.previewLayer.superlayer];//selfview上的点转换到self.previewLayer上坐标

        if ( ! [self.previewLayercontainsPoint:convertedLocation] ) {

            allTouchesAreOnThePreviewLayer = NO;//如果self.view上的转换到preview的坐标不在preview上,设置NO

            break;

        }

    }

    

    if ( allTouchesAreOnThePreviewLayer ) {

        

        

        self.effectiveScale =self.beginGestureScale * recognizer.scale;//获取当前手势的缩放比例

        if (self.effectiveScale <1.0){

            self.effectiveScale =1.0;

        }

        

        NSLog(@"%f-------------->%f------------recognizerScale%f",self.effectiveScale,self.beginGestureScale,recognizer.scale);

        

        //获取最大缩放比例

        CGFloat maxScaleAndCropFactor = [[self.stillImageOutputconnectionWithMediaType:AVMediaTypeVideo]videoMaxScaleAndCropFactor];

        

        NSLog(@"%f",maxScaleAndCropFactor);

        //超过最大,取最大

        if (self.effectiveScale > maxScaleAndCropFactor)

            self.effectiveScale = maxScaleAndCropFactor;

   

        //layer层的隐式动画

        [CATransactionbegin];

        [CATransactionsetAnimationDuration:.025];

        [self.previewLayersetAffineTransform:CGAffineTransformMakeScale(self.effectiveScale,self.effectiveScale)];//缩放

        [CATransactioncommit];//提交动画

        

    }

    

}


//切换镜头

- (void)switchCameraSegmentedControlClick:(UISegmentedControl *)sender {

    

    NSLog(@"%ld",(long)sender.selectedSegmentIndex);

    

    AVCaptureDevicePosition desiredPosition;

    if (self.isUsingFrontFacingCamera){

        desiredPosition = AVCaptureDevicePositionBack;//摄像头位置在后面

    }else{

        desiredPosition = AVCaptureDevicePositionFront;//摄像头位置在前面

    }

    

    for (AVCaptureDevice *din [AVCaptureDevicedevicesWithMediaType:AVMediaTypeVideo]) {

        if ([dposition] == desiredPosition) {

            [self.previewLayer.sessionbeginConfiguration];//开启配置

            AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:derror:nil];

            for (AVCaptureInput *oldInputinself.previewLayer.session.inputs) {

                [[self.previewLayersession]removeInput:oldInput];//移除旧的会话

            }

            [self.previewLayer.sessionaddInput:input];//新的输入关联会话

            [self.previewLayer.sessioncommitConfiguration];//重新配置后,会话重新提交配置

            break;

        }

    }

    

    self.isUsingFrontFacingCamera = !self.isUsingFrontFacingCamera;

}



- (void)initAVCaptureSession{

    

    self.session = [[AVCaptureSessionalloc]init];

    

    NSError *error;

    

    AVCaptureDevice *device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

    

    //更改这个设置的时候必须先锁定设备,修改完后再解锁,否则崩溃

    [device lockForConfiguration:nil];

    //设置闪光灯为自动

    [device setFlashMode:AVCaptureFlashModeAuto];

    [device unlockForConfiguration];

    

    self.videoInput = [[AVCaptureDeviceInputalloc]initWithDevice:deviceerror:&error];

    if (error) {

        NSLog(@"%@",error);

    }

    self.stillImageOutput = [[AVCaptureStillImageOutputalloc]init];

    //输出设置。AVVideoCodecJPEG  输出jpeg格式图片

    NSDictionary * outputSettings = [[NSDictionaryalloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];

    [self.stillImageOutputsetOutputSettings:outputSettings];

    

    if ([self.sessioncanAddInput:self.videoInput]) {

        [self.sessionaddInput:self.videoInput];

    }

    if ([self.sessioncanAddOutput:self.stillImageOutput]) {

        [self.sessionaddOutput:self.stillImageOutput];

    }

    

    //初始化预览图层

    self.previewLayer = [[AVCaptureVideoPreviewLayeralloc]initWithSession:self.session];

    [self.previewLayersetVideoGravity:AVLayerVideoGravityResizeAspect];

    self.previewLayer.frame =CGRectMake(0,0,375,375 - 64);

    self.view.layer.masksToBounds = YES;

    [self.view.layeraddSublayer:self.previewLayer];

}


- (void)viewWillAppear:(BOOL)animated{

    

    [superviewWillAppear:YES];

    

    if (self.session) {

        

        [self.sessionstartRunning];//开启会话

    }

}



- (void)viewDidDisappear:(BOOL)animated{

    

    [superviewDidDisappear:YES];

    

    if (self.session) {

        

        [self.sessionstopRunning];

    }

}



//拍照,输出图片

- (void)takePhotoButtonClick:(UIBarButtonItem *)sender {

    //输出图像的时候需要用到AVCaptureConnection这个类,session通过AVCaptureConnection连接AVCaptureStillImageOutput进行图片输出,

    AVCaptureConnection *stillImageConnection = [self.stillImageOutput        connectionWithMediaType:AVMediaTypeVideo];

    UIDeviceOrientation curDeviceOrientation = [[UIDevicecurrentDevice]orientation];

    AVCaptureVideoOrientation avcaptureOrientation = [selfavOrientationForDeviceOrientation:curDeviceOrientation];

    [stillImageConnection setVideoOrientation:avcaptureOrientation];

//这个方法是控制焦距用的暂时先固定为1,后边写手势缩放焦距的时候会修改这里

    [stillImageConnection setVideoScaleAndCropFactor:1];

    

    [self.stillImageOutputcaptureStillImageAsynchronouslyFromConnection:stillImageConnectioncompletionHandler:^(CMSampleBufferRef imageDataSampleBuffer,NSError *error) {

    //获得图片数据

        NSData *jpegData = [AVCaptureStillImageOutputjpegStillImageNSDataRepresentation:imageDataSampleBuffer];

        

        CFDictionaryRef attachments =CMCopyDictionaryOfAttachments(kCFAllocatorDefault,

                                                                    imageDataSampleBuffer,

                                                                   kCMAttachmentMode_ShouldPropagate);

//

        


    // 写入相册之前需要判断用户是否允许了程序访问相册,否则程序会崩溃,包括在开启相机的时候和拍摄按钮点击的时候都需要做安全验证,验证设别是否支持拍照,用户是否允许程序访问相机。

//        ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];

//        if (author == ALAuthorizationStatusRestricted || author == ALAuthorizationStatusDenied){

//            //无权限

//            return ;

//        }

//        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

//        [library writeImageDataToSavedPhotosAlbum:jpegData metadata:(__bridge id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {

//

//        }];

//        

    }];

    

     }


//设置方向,       照片写入相册之前需要进行旋转

-(AVCaptureVideoOrientation )avOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation

     {

         AVCaptureVideoOrientation result = (AVCaptureVideoOrientation)deviceOrientation;

         if ( deviceOrientation ==UIDeviceOrientationLandscapeLeft )

             result = AVCaptureVideoOrientationLandscapeRight;

         elseif ( deviceOrientation ==UIDeviceOrientationLandscapeRight )

             result = AVCaptureVideoOrientationLandscapeLeft;

         return result;

     }


@end





===================================================




0 0
原创粉丝点击