iOS相机功能
江枫夜雨 人气:0大多数app都会涉及到上传照片这个功能,图片来源无非是从相册获取或者相机拍摄。如果不是特别要求,调用系统已经满足需求。但对于特殊需求,就需要自定义相机拍摄界面了。
对于无需定制的相机,使用系统的UIKit库里的UIImagePickerController类,几行代码,几个代理方法就可满足所需。但如果要深度定制,就要系统库AVFoundation内部的相关类。
创建自己的相机管理类CameraManager(继承于NSObject)
.h文件
#import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> //拍照后的回调,传递拍摄的照片 typedef void(^DidCapturePhotoBlock)(UIImage *stillImage); @interface PXCameraManager : NSObject @property (nonatomic, strong) AVCaptureSession *session;//AVCaptureSession对象来执行输入设备和输出设备之间的数据传递 @property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;//预览图层,来显示照相机拍摄到的画面 @property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;//AVCaptureDeviceInput对象是输入流 @property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;//照片输出流对象 @property (nonatomic, assign) CGRect previewLayerFrame;//拍照区域 /* 为其他类提供的自定义接口 */ //设置拍照区域 (其中targetView为要展示拍照界面的view) - (void)configureWithtargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect; //拍照成功回调 - (void)takePicture:(DidCapturePhotoBlock)block; //添加/移除相机浮层(如果有需求要在相机拍照区域添加浮层的时候使用) - (void)addCoverImageWithImage:(UIImage *)image; - (void)removeCoverImageWithImage:(UIImage *)image; //前后摄像头切换 - (void)switchCameras; //闪光灯切换 - (void)configCameraFlashlight; @end
.m文件
@property (nonatomic, strong) UIView *preview;//展现拍照区域的view @property (nonatomic, strong) UIImageView *coverImageView;//拍照区域浮层 @property (nonatomic, assign) BOOL isCaremaBack; @property (nonatomic, assign) AVCaptureFlashMode flashMode; //初始化的时候设置自己想要的默认属性 - (instancetype)init{ self = [super init]; if (self) { self.isCaremaBack = YES;//默认后置摄像头 self.flashMode = AVCaptureFlashModeAuto;//默认自动闪光灯 } return self; }
实现接口的方法
1、准备相关硬件
- (void)configureWithTargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect{ self.preview = targetView; //开始一些相机相关硬件配置 [self addSession];//创建session [self addVideoPreviewLayerWithRect:preivewRect];//用session 创建 创建layer [self addvideoInputBackCamera:self.isCaremaBack];//给session 配置摄像头 [self addVideoFlashlightWithFlashModel:self.flashMode];//配置闪光灯 [self addStillImageOutput];//给session 配置输出 }
2、拍照
#pragma mark - - (void)takePicture:(DidCapturePhotoBlock)block{ AVCaptureConnection *captureConnection = [self findCaptureConnection]; [captureConnection setVideoScaleAndCropFactor:1.0f]; [_stillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; UIImage *image = [UIImage imageWithData:imageData]; //这里可以根据不同需求对拍摄到的照片做一些压缩或者裁剪的处理,这里我就偷懒不弄了。 if (block) { block(image); } }]; }
3、切换摄像头
- (void)switchCameras{ if (!_deviceInput) { return; } [_session beginConfiguration]; [_session removeInput:_deviceInput]; self.isCaremaBack = !self.isCaremaBack; [self addvideoInputBackCamera:self.isCaremaBack]; [_session commitConfiguration]; }
4、切换闪光灯
- (void)configCameraFlashlight{ switch (self.flashMode) { case AVCaptureFlashModeAuto: { self.flashMode = AVCaptureFlashModeOff; } break; case AVCaptureFlashModeOff: { self.flashMode = AVCaptureFlashModeOn; } break; case AVCaptureFlashModeOn: { self.flashMode = AVCaptureFlashModeAuto; } break; default: break; } [self addVideoFlashlightWithFlashModel:self.flashMode]; }
添加/移除 浮层
- (void)addCoverImageWithImage:(UIImage *)image{ _coverImageView.image = image; } - (void)removeCoverImageWithImage:(UIImage *)image{ _coverImageView.image = nil; }
下面是配置硬件里的几个方法实现
- (void)addSession{ if (!self.session) { AVCaptureSession *session = [[AVCaptureSession alloc]init]; self.session = session; } }
- (void)addVideoPreviewLayerWithRect:(CGRect)previewRect{ if (!self.previewLayer) { AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_session]; previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; self.previewLayer = previewLayer; [self.preview.layer addSublayer:self.previewLayer]; } self.previewLayer.frame = previewRect; }
- (void)addvideoInputBackCamera:(BOOL)back{ NSArray *devices = [AVCaptureDevice devices]; AVCaptureDevice *frontCamera; AVCaptureDevice *backCamera; //获取 前、后 摄像头 for (AVCaptureDevice *device in devices) { if ([device hasMediaType:AVMediaTypeVideo]) { if ([device position] == AVCaptureDevicePositionBack) { backCamera = device; }else if([device position] == AVCaptureDevicePositionFront){ frontCamera = device; } } } NSError *error = nil; if(back){ AVCaptureDeviceInput *backCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error]; if (!error) { if ([_session canAddInput:backCameraDeviceInput]) { [_session addInput:backCameraDeviceInput]; self.deviceInput = backCameraDeviceInput; }else{ NSLog(@"出错啦"); } } }else{ AVCaptureDeviceInput *frontCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error]; if (!error) { if ([_session canAddInput:frontCameraDeviceInput]) { [_session addInput:frontCameraDeviceInput]; self.deviceInput = frontCameraDeviceInput; }else{ NSLog(@"出错啦"); } } } }
- (void)addVideoFlashlightWithFlashModel:(AVCaptureFlashMode )flashModel{ AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; [device lockForConfiguration:nil]; if ([device hasFlash]) { device.flashMode = self.flashMode; } [device unlockForConfiguration]; }
- (void)addStillImageOutput{ if (!self.stillImageOutput) { AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc]init]; NSDictionary *outPutSettingDict = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil]; stillImageOutput.outputSettings = outPutSettingDict; [_session addOutput:stillImageOutput]; self.stillImageOutput = stillImageOutput; } }
- (AVCaptureConnection *)findCaptureConnection{ AVCaptureConnection *videoConnection; for (AVCaptureConnection *connection in _stillImageOutput.connections ) { for (AVCaptureInputPort *port in connection.inputPorts) { if ([[port mediaType] isEqual:AVMediaTypeVideo]) { videoConnection = connection; return videoConnection; } } } return nil; }
到此,一个自定义相机的类就有了,要使用的时候,尽管调用吧。
加载全部内容