iOS中 自定义系统相机

需要框架:

#import <AVFoundation/AVFoundation.h>

#import <AssetsLibrary/AssetsLibrary.h>

布局如下:

iOS中 自定义系统相机

相关属性:

[objc] view plain copy
  1. #import "ViewController.h"  
  2. #import <AVFoundation/AVFoundation.h>  
  3. #import <AssetsLibrary/AssetsLibrary.h>  
  4. typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice);  
  5.   
  6. @interface ViewController ()  
  7.   
  8. @property (strong,nonatomicAVCaptureSession *captureSession;//负责输入和输出设置之间的数据传递  
  9. @property (strong,nonatomicAVCaptureDeviceInput *captureDeviceInput;//负责从AVCaptureDevice获得输入数据  
  10. @property (strong,nonatomicAVCaptureStillImageOutput *captureStillImageOutput;//照片输出流  
  11. @property (strong,nonatomicAVCaptureVideoPreviewLayer *captureVideoPreviewLayer;//相机拍摄预览图层  
  12. @property (weak, nonatomic) IBOutlet UIView *viewContainer;  
  13. @property (weak, nonatomic) IBOutlet UIButton *takeButton;//拍照按钮  
  14. @property (weak, nonatomic) IBOutlet UIButton *flashAutoButton;//自动闪光灯按钮  
  15. @property (weak, nonatomic) IBOutlet UIButton *flashOnButton;//打开闪光灯按钮  
  16. @property (weak, nonatomic) IBOutlet UIButton *flashOffButton;//关闭闪光灯按钮  
  17. @property (weak, nonatomic) IBOutlet UIImageView *focusCursor; //聚焦光标  
  18.   
  19.   
  20.   
  21. @end  
  22.   
  23. @implementation ViewController  


[objc] view plain copy
  1. #pragma mark - 控制器视图方法  
  2. - (void)viewDidLoad {  
  3.     [super viewDidLoad];  
  4.       
  5. }  
  6.   
  7. -(void)viewWillAppear:(BOOL)animated{  
  8.     [super viewWillAppear:animated];  
  9.     //初始化会话  
  10.     _captureSession=[[AVCaptureSession alloc]init];  
  11.     if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {//设置分辨率  
  12.         _captureSession.sessionPreset=AVCaptureSessionPreset1280x720;  
  13.     }  
  14.     //获得输入设备  
  15.     AVCaptureDevice *captureDevice=[self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置摄像头  
  16.     if (!captureDevice) {  
  17.         NSLog(@"取得后置摄像头时出现问题.");  
  18.         return;  
  19.     }  
  20.       
  21.     NSError *error=nil;  
  22.     //根据输入设备初始化设备输入对象,用于获得输入数据  
  23.     _captureDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:captureDevice error:&error];  
  24.     if (error) {  
  25.         NSLog(@"取得设备输入对象时出错,错误原因:%@",error.localizedDescription);  
  26.         return;  
  27.     }  
  28.     //初始化设备输出对象,用于获得输出数据  
  29.     _captureStillImageOutput=[[AVCaptureStillImageOutput alloc]init];  
  30.     NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};  
  31.     [_captureStillImageOutput setOutputSettings:outputSettings];//输出设置  
  32.       
  33.     //将设备输入添加到会话中  
  34.     if ([_captureSession canAddInput:_captureDeviceInput]) {  
  35.         [_captureSession addInput:_captureDeviceInput];  
  36.     }  
  37.       
  38.     //将设备输出添加到会话中  
  39.     if ([_captureSession canAddOutput:_captureStillImageOutput]) {  
  40.         [_captureSession addOutput:_captureStillImageOutput];  
  41.     }  
  42.       
  43.     //创建视频预览层,用于实时展示摄像头状态  
  44.     _captureVideoPreviewLayer=[[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];  
  45.       
  46.     CALayer *layer=self.viewContainer.layer;  
  47.     layer.masksToBounds=YES;  
  48.       
  49.     _captureVideoPreviewLayer.frame=layer.bounds;  
  50.     _captureVideoPreviewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式  
  51.     //将视频预览层添加到界面中  
  52.     //[layer addSublayer:_captureVideoPreviewLayer];  
  53.     [layer insertSublayer:_captureVideoPreviewLayer below:self.focusCursor.layer];  
  54.       
  55.     [self addNotificationToCaptureDevice:captureDevice];  
  56.     [self addGenstureRecognizer];  
  57.     [self setFlashModeButtonStatus];  
  58. }  
  59.   
  60. -(void)viewDidAppear:(BOOL)animated{  
  61.     [super viewDidAppear:animated];  
  62.     [self.captureSession startRunning];  
  63. }  
  64.   
  65. -(void)viewDidDisappear:(BOOL)animated{  
  66.     [super viewDidDisappear:animated];  
  67.     [self.captureSession stopRunning];  
  68. }  
  69.   
  70. -(void)dealloc{  
  71.     [self removeNotification];  
  72. }  

[objc] view plain copy
  1. #pragma mark - UI方法  
  2. #pragma mark 拍照  
  3. - (IBAction)takeButtonClick:(UIButton *)sender {  
  4.     //根据设备输出获得连接  
  5.     AVCaptureConnection *captureConnection=[self.captureStillImageOutput connectionWithMediaType:AVMediaTypeVideo];  
  6.     //根据连接取得设备输出的数据  
  7.     [self.captureStillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {  
  8.         if (imageDataSampleBuffer) {  
  9.             NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];  
  10.             UIImage *image=[UIImage imageWithData:imageData];  
  11.             UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);  
  12. //            ALAssetsLibrary *assetsLibrary=[[ALAssetsLibrary alloc]init];  
  13. //            [assetsLibrary writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:nil];  
  14.         }  
  15.           
  16.     }];  
  17. }  
  18. #pragma mark 切换前后摄像头  
  19. - (IBAction)toggleButtonClick:(UIButton *)sender {  
  20.     AVCaptureDevice *currentDevice=[self.captureDeviceInput device];  
  21.     AVCaptureDevicePosition currentPosition=[currentDevice position];  
  22.     [self removeNotificationFromCaptureDevice:currentDevice];  
  23.     AVCaptureDevice *toChangeDevice;  
  24.     AVCaptureDevicePosition toChangePosition=AVCaptureDevicePositionFront;  
  25.     if (currentPosition==AVCaptureDevicePositionUnspecified||currentPosition==AVCaptureDevicePositionFront) {  
  26.         toChangePosition=AVCaptureDevicePositionBack;  
  27.     }  
  28.     toChangeDevice=[self getCameraDeviceWithPosition:toChangePosition];  
  29.     [self addNotificationToCaptureDevice:toChangeDevice];  
  30.     //获得要调整的设备输入对象  
  31.     AVCaptureDeviceInput *toChangeDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:toChangeDevice error:nil];  
  32.       
  33.     //改变会话的配置前一定要先开启配置,配置完成后提交配置改变  
  34.     [self.captureSession beginConfiguration];  
  35.     //移除原有输入对象  
  36.     [self.captureSession removeInput:self.captureDeviceInput];  
  37.     //添加新的输入对象  
  38.     if ([self.captureSession canAddInput:toChangeDeviceInput]) {  
  39.         [self.captureSession addInput:toChangeDeviceInput];  
  40.         self.captureDeviceInput=toChangeDeviceInput;  
  41.     }  
  42.     //提交会话配置  
  43.     [self.captureSession commitConfiguration];  
  44.       
  45.     [self setFlashModeButtonStatus];  
  46. }  

[objc] view plain copy
  1. #pragma mark 自动闪光灯开启  
  2. - (IBAction)flashAutoClick:(UIButton *)sender {  
  3.     [self setFlashMode:AVCaptureFlashModeAuto];  
  4.     [self setFlashModeButtonStatus];  
  5. }  

[objc] view plain copy
  1. #pragma mark 打开闪光灯  
  2. - (IBAction)flashOnClick:(UIButton *)sender {  
  3.     [self setFlashMode:AVCaptureFlashModeOn];  
  4.     [self setFlashModeButtonStatus];  
  5. }  

[objc] view plain copy
  1. #pragma mark 关闭闪光灯  
  2. - (IBAction)flashOffClick:(UIButton *)sender {  
  3.     [self setFlashMode:AVCaptureFlashModeOff];  
  4.     [self setFlashModeButtonStatus];  
  5. }  

[objc] view plain copy
  1. #pragma mark - 通知  
  2. /** 
  3.  *  给输入设备添加通知 
  4.  */  
  5. -(void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{  
  6.     //注意添加区域改变捕获通知必须首先设置设备允许捕获  
  7.     [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {  
  8.         captureDevice.subjectAreaChangeMonitoringEnabled=YES;  
  9.     }];  
  10.     NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  
  11.     //捕获区域发生改变  
  12.     [notificationCenter addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];  
  13. }  

[objc] view plain copy
  1. /** 
  2.  *  移除所有通知 
  3.  */  
  4. -(void)removeNotification{  
  5.     NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  
  6.     [notificationCenter removeObserver:self];  
  7. }  

[objc] view plain copy
  1. -(void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession{  
  2.     NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  
  3.     //会话出错  
  4.     [notificationCenter addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];  
  5. }  

[objc] view plain copy
  1. /** 
  2.  *  设备连接成功 
  3.  * 
  4.  *  @param notification 通知对象 
  5.  */  
  6. -(void)deviceConnected:(NSNotification *)notification{  
  7.     NSLog(@"设备已连接...");  
  8. }  

[objc] view plain copy
  1. /** 
  2.  *  设备连接断开 
  3.  * 
  4.  *  @param notification 通知对象 
  5.  */  
  6. -(void)deviceDisconnected:(NSNotification *)notification{  
  7.     NSLog(@"设备已断开.");  
  8. }  

[objc] view plain copy
  1. /** 
  2.  *  捕获区域改变 
  3.  * 
  4.  *  @param notification 通知对象 
  5.  */  
  6. -(void)areaChange:(NSNotification *)notification{  
  7.     NSLog(@"捕获区域改变...");  
  8. }  

[objc] view plain copy
  1. /** 
  2.  *  会话出错 
  3.  * 
  4.  *  @param notification 通知对象 
  5.  */  
  6. -(void)sessionRuntimeError:(NSNotification *)notification{  
  7.     NSLog(@"会话发生错误.");  
  8. }  

[objc] view plain copy
  1. #pragma mark - 私有方法  
  2.   
  3. /** 
  4.  *  取得指定位置的摄像头 
  5.  * 
  6.  *  @param position 摄像头位置 
  7.  * 
  8.  *  @return 摄像头设备 
  9.  */  
  10. -(AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{  
  11.     NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];  
  12.     for (AVCaptureDevice *camera in cameras) {  
  13.         if ([camera position]==position) {  
  14.             return camera;  
  15.         }  
  16.     }  
  17.     return nil;  
  18. }  

[objc] view plain copy
  1. /** 
  2.  *  改变设备属性的统一操作方法 
  3.  * 
  4.  *  @param propertyChange 属性改变操作 
  5.  */  
  6. -(void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{  
  7.     AVCaptureDevice *captureDevice= [self.captureDeviceInput device];  
  8.     NSError *error;  
  9.     //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁  
  10.     if ([captureDevice lockForConfiguration:&error]) {  
  11.         propertyChange(captureDevice);  
  12.         [captureDevice unlockForConfiguration];  
  13.     }else{  
  14.         NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription);  
  15.     }  
  16. }  

[objc] view plain copy
  1. /** 
  2.  *  设置闪光灯模式 
  3.  * 
  4.  *  @param flashMode 闪光灯模式 
  5.  */  
  6. -(void)setFlashMode:(AVCaptureFlashMode )flashMode{  
  7.     [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {  
  8.         if ([captureDevice isFlashModeSupported:flashMode]) {  
  9.             [captureDevice setFlashMode:flashMode];  
  10.         }  
  11.     }];  
  12. }  

[objc] view plain copy
  1. /** 
  2.  *  设置聚焦模式 
  3.  * 
  4.  *  @param focusMode 聚焦模式 
  5.  */  
  6. -(void)setFocusMode:(AVCaptureFocusMode )focusMode{  
  7.     [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {  
  8.         if ([captureDevice isFocusModeSupported:focusMode]) {  
  9.             [captureDevice setFocusMode:focusMode];  
  10.         }  
  11.     }];  
  12. }  

[objc] view plain copy
  1. /** 
  2.  *  设置曝光模式 
  3.  * 
  4.  *  @param exposureMode 曝光模式 
  5.  */  
  6. -(void)setExposureMode:(AVCaptureExposureMode)exposureMode{  
  7.     [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {  
  8.         if ([captureDevice isExposureModeSupported:exposureMode]) {  
  9.             [captureDevice setExposureMode:exposureMode];  
  10.         }  
  11.     }];  
  12. }  

[objc] view plain copy
  1. /** 
  2.  *  设置聚焦点 
  3.  * 
  4.  *  @param point 聚焦点 
  5.  */  
  6. -(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{  
  7.     [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {  
  8.         if ([captureDevice isFocusModeSupported:focusMode]) {  
  9.             [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];  
  10.         }  
  11.         if ([captureDevice isFocusPointOfInterestSupported]) {  
  12.             [captureDevice setFocusPointOfInterest:point];  
  13.         }  
  14.         if ([captureDevice isExposureModeSupported:exposureMode]) {  
  15.             [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];  
  16.         }  
  17.         if ([captureDevice isExposurePointOfInterestSupported]) {  
  18.             [captureDevice setExposurePointOfInterest:point];  
  19.         }  
  20.     }];  
  21. }  

[objc] view plain copy
  1. /** 
  2.  *  添加点按手势,点按时聚焦 
  3.  */  
  4. -(void)addGenstureRecognizer{  
  5.     UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapScreen:)];  
  6.     [self.viewContainer addGestureRecognizer:tapGesture];  
  7. }  
  8. -(void)tapScreen:(UITapGestureRecognizer *)tapGesture{  
  9.     CGPoint point= [tapGesture locationInView:self.viewContainer];  
  10.     //将UI坐标转化为摄像头坐标  
  11.     CGPoint cameraPoint= [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point];  
  12.     [self setFocusCursorWithPoint:point];  
  13.     [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];  
  14. }  

[objc] view plain copy
  1. /** 
  2.  *  设置闪光灯按钮状态 
  3.  */  
  4. -(void)setFlashModeButtonStatus{  
  5.     AVCaptureDevice *captureDevice=[self.captureDeviceInput device];  
  6.     AVCaptureFlashMode flashMode=captureDevice.flashMode;  
  7.     if([captureDevice isFlashAvailable]){  
  8.         self.flashAutoButton.hidden=NO;  
  9.         self.flashOnButton.hidden=NO;  
  10.         self.flashOffButton.hidden=NO;  
  11.         self.flashAutoButton.enabled=YES;  
  12.         self.flashOnButton.enabled=YES;  
  13.         self.flashOffButton.enabled=YES;  
  14.         switch (flashMode) {  
  15.             case AVCaptureFlashModeAuto:  
  16.                 self.flashAutoButton.enabled=NO;  
  17.                 break;  
  18.             case AVCaptureFlashModeOn:  
  19.                 self.flashOnButton.enabled=NO;  
  20.                 break;  
  21.             case AVCaptureFlashModeOff:  
  22.                 self.flashOffButton.enabled=NO;  
  23.                 break;  
  24.             default:  
  25.                 break;  
  26.         }  
  27.     }else{  
  28.         self.flashAutoButton.hidden=YES;  
  29.         self.flashOnButton.hidden=YES;  
  30.         self.flashOffButton.hidden=YES;  
  31.     }  
  32. }  

[objc] view plain copy
  1. /** 
  2.  *  设置聚焦光标位置 
  3.  * 
  4.  *  @param point 光标位置 
  5.  */  
  6. -(void)setFocusCursorWithPoint:(CGPoint)point{  
  7.     self.focusCursor.center=point;  
  8.     self.focusCursor.transform=CGAffineTransformMakeScale(1.51.5);  
  9.     self.focusCursor.alpha=1.0;  
  10.     [UIView animateWithDuration:1.0 animations:^{  
  11.         self.focusCursor.transform=CGAffineTransformIdentity;  
  12.     } completion:^(BOOL finished) {  
  13.         self.focusCursor.alpha=0;  
  14.           
  15.     }];  

关注博主微博每日更新技术:http://weibo.com/hanjunqiang

原文地址:http://blog.csdn.net/qq_31810357/article/details/49942327