用系统自带的视听媒体的框架,AVFoundation实现照片拍摄。相比UIKit框架(UIImagePickerController高度封装),AVFoundation框架让开发者有更大的发挥空间。
首先看一下效果图:
下面贴上核心控制器代码:
#import "HWPhotoVC.h"#import <AVFoundation/AVFoundation.h>@interface HWPhotoVC ()@property (nonatomic,strong) AVCaptureSession *captureSession;//负责输入和输出设备之间的数据传递@property (nonatomic,strong) AVCaptureDeviceinput *captureDeviceinput;//负责从AVCaptureDevice获得输入数据@property (nonatomic,strong) AVCaptureStillimageOutput *captureStillimageOutput;//照片输出流@property (nonatomic,strong) AVCaptureVIDeoPrevIEwLayer *captureVIDeoPrevIEwLayer;//相机拍摄预览图层@property (nonatomic,weak) UIVIEw *containerVIEw;//内容视图@property (nonatomic,weak) UIImageVIEw *focusCursor;//聚焦按钮@property (nonatomic,weak) UIImageVIEw *imgVIEw;//拍摄照片@end@implementation HWPhotoVC- (voID)vIEwDIDLoad { [super vIEwDIDLoad]; self.navigationItem.Title = @"拍照"; self.vIEw.backgroundcolor = [UIcolor whitecolor]; //创建控件 [self creatControl];}- (voID)vIEwWillAppear:(BOol)animated{ [super vIEwWillAppear:animated]; //初始化信息 [self initPhotoInfo];}- (voID)vIEwDIDAppear:(BOol)animated{ [super vIEwDIDAppear:animated]; [self.captureSession startRunning];}- (voID)vIEwDIDdisappear:(BOol)animated{ [super vIEwDIDdisappear:animated]; [self.captureSession stopRunning];}- (voID)creatControl{ CGfloat btnW = 150.f; CGfloat btnH = 40.f; CGfloat marginY = 20.f; CGfloat w = [UIScreen mainScreen].bounds.size.wIDth; CGfloat h = [UIScreen mainScreen].bounds.size.height; //内容视图 CGfloat containerVIEwH = h - 64 - btnH - marginY * 3; UIVIEw *containerVIEw = [[UIVIEw alloc] initWithFrame:CGRectMake(10,64 + marginY,w - 20,containerVIEwH)]; containerVIEw.backgroundcolor = [UIcolor whitecolor]; containerVIEw.layer.borderWIDth = 1.f; containerVIEw.layer.bordercolor = [[UIcolor graycolor] CGcolor]; [self.vIEw addSubvIEw:containerVIEw]; _containerVIEw = containerVIEw; //摄像头切换按钮 CGfloat cameraSwitchBtnW = 50.f; CGfloat cameraSwitchBtnmargin = 10.f; UIbutton *cameraSwitchBtn = [[UIbutton alloc] initWithFrame:CGRectMake(containerVIEw.bounds.size.wIDth - cameraSwitchBtnW - cameraSwitchBtnmargin,64 + marginY + cameraSwitchBtnmargin,cameraSwitchBtnW,cameraSwitchBtnW)]; [cameraSwitchBtn setimage:[UIImage imagenamed:@"camera_switch"] forState:UIControlStatenormal]; [cameraSwitchBtn addTarget:self action:@selector(cameraSwitchBtnOnClick) forControlEvents:UIControlEventtouchUpInsIDe]; [self.vIEw addSubvIEw:cameraSwitchBtn]; //聚焦图片 UIImageVIEw *focusCursor = [[UIImageVIEw alloc] initWithFrame:CGRectMake(50,50,75,75)]; focusCursor.Alpha = 0; focusCursor.image = [UIImage imagenamed:@"camera_focus_red"]; [containerVIEw addSubvIEw:focusCursor]; _focusCursor = focusCursor; //拍摄照片容器 UIImageVIEw *imgVIEw = [[UIImageVIEw alloc] initWithFrame:containerVIEw.frame]; imgVIEw.hIDden = YES; imgVIEw.layer.borderWIDth = 1.f; imgVIEw.layer.bordercolor = [[UIcolor graycolor] CGcolor]; imgVIEw.contentMode = UIVIEwContentModeScaleAspectFill; imgVIEw.clipsToBounds = YES; [self.vIEw addSubvIEw:imgVIEw]; _imgVIEw = imgVIEw; //按钮 NSArray *TitleArray = @[@"拍摄照片",@"重新拍摄"]; CGfloat btnY = CGRectGetMaxY(containerVIEw.frame) + marginY; CGfloat margin = (w - btnW * TitleArray.count) / (TitleArray.count + 1); for (int i = 0; i < TitleArray.count; i++) { CGfloat btnX = margin + (margin + btnW) * i; UIbutton *btn = [[UIbutton alloc] initWithFrame:CGRectMake(btnX,btnY,btnW,btnH)]; btn.tag = 1000 + i; [btn setTitle:TitleArray[i] forState:UIControlStatenormal]; btn.backgroundcolor = [UIcolor orangecolor]; btn.layer.cornerRadius = 2.0f; btn.layer.masksToBounds = YES; if (i == 1) { btn.hIDden = YES; } [btn addTarget:self action:@selector(btnOnClick:) forControlEvents:UIControlEventtouchUpInsIDe]; [self.vIEw addSubvIEw:btn]; }}- (voID)initPhotoInfo{ //初始化会话 _captureSession = [[AVCaptureSession alloc] init]; //设置分辨率 if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) { _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 = @{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]; //摄像头方向 AVCaptureConnection *captureConnection = [self.captureVIDeoPrevIEwLayer connection]; captureConnection.vIDeoOrIEntation = AVCaptureVIDeoOrIEntationPortrait; CALayer *layer = _containerVIEw.layer; layer.masksToBounds = YES; _captureVIDeoPrevIEwLayer.frame = layer.bounds; //填充模式 _captureVIDeoPrevIEwLayer.vIDeoGravity = AVLayerVIDeoGravityResizeAspectFill; //将视频预览层添加到界面中 [layer insertSublayer:_captureVIDeoPrevIEwLayer below:self.focusCursor.layer]; [self addNotificationToCaptureDevice:captureDevice]; [self addGenstureRecognizer];}- (voID)btnOnClick:(UIbutton *)btn{ if (btn.tag == 1000) { //拍摄照片 [self photoBtnOnClick]; }else if (btn.tag == 1001) { //重新拍摄 [self resetPhoto]; }}#pragma mark 拍照- (voID)photoBtnOnClick{ //根据设备输出获得连接 AVCaptureConnection *captureConnection = [self.captureStillimageOutput connectionWithMediaType:AVMediaTypeVIDeo]; captureConnection.vIDeoOrIEntation = AVCaptureVIDeoOrIEntationPortrait; //根据连接取得设备输出的数据 [self.captureStillimageOutput captureStillimageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer,NSError *error) { if (imageDataSampleBuffer) { NSData *imageData = [AVCaptureStillimageOutput jpegStillimageNSDataRepresentation:imageDataSampleBuffer]; UIImage *image = [UIImage imageWithData:imageData]; _imgVIEw.image = image; _imgVIEw.hIDden = NO; } }]; UIbutton *btn = (UIbutton *)[self.vIEw vIEwWithTag:1001]; btn.hIDden = NO;}//重新拍摄- (voID)resetPhoto{ _imgVIEw.hIDden = YES; UIbutton *btn = (UIbutton *)[self.vIEw vIEwWithTag:1001]; btn.hIDden = YES;}#pragma mark - 通知//给输入设备添加通知- (voID)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{ //注意添加区域改变捕获通知必须首先设置设备允许捕获 [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { captureDevice.subjectAreaChangeMonitoringEnabled = YES; }]; //捕获区域发生改变 [[NSNotificationCenter defaultCenter] addobserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDIDChangeNotification object:captureDevice];}- (voID)removeNotificationFromCaptureDevice:(AVCaptureDevice *)captureDevice{ [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDIDChangeNotification object:captureDevice];}//移除所有通知- (voID)removeNotification{ [[NSNotificationCenter defaultCenter] removeObserver:self];}//设备连接成功- (voID)deviceConnected:(NSNotification *)notification{ NSLog(@"设备已连接...");}//设备连接断开- (voID)devicedisconnected:(NSNotification *)notification{ NSLog(@"设备已断开.");}//捕获区域改变- (voID)areaChange:(NSNotification *)notification{ NSLog(@"捕获区域改变...");}#pragma mark - 私有方法//取得指定位置的摄像头- (AVCaptureDevice *)getCameraDeviceWithposition:(AVCaptureDeviceposition )position{ NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVIDeo]; for (AVCaptureDevice *camera in cameras) { if ([camera position] == position) { return camera; } } return nil;}#pragma mark 切换前后摄像头- (voID)cameraSwitchBtnOnClick{ AVCaptureDevice *currentDevice = [self.captureDeviceinput device]; AVCaptureDeviceposition currentposition = [currentDevice position]; [self removeNotificationFromCaptureDevice:currentDevice]; AVCaptureDevice *tochangeDevice; AVCaptureDeviceposition tochangeposition = AVCaptureDevicepositionFront; if (currentposition == AVCaptureDevicepositionUnspecifIEd || currentposition == AVCaptureDevicepositionFront) { tochangeposition = AVCaptureDevicepositionBack; } tochangeDevice = [self getCameraDeviceWithposition:tochangeposition]; [self addNotificationToCaptureDevice:tochangeDevice]; //获得要调整的设备输入对象 AVCaptureDeviceinput *tochangeDeviceinput = [[AVCaptureDeviceinput alloc] initWithDevice:tochangeDevice error:nil]; //改变会话的配置前一定要先开启配置,配置完成后提交配置改变 [self.captureSession beginConfiguration]; //移除原有输入对象 [self.captureSession removeinput:self.captureDeviceinput]; //添加新的输入对象 if ([self.captureSession canAddinput:tochangeDeviceinput]) { [self.captureSession addinput:tochangeDeviceinput]; self.captureDeviceinput = tochangeDeviceinput; } //提交会话配置 [self.captureSession commitConfiguration];}//改变设备属性的统一 *** 作方法- (voID)changeDeviceProperty:(voID (^)(AVCaptureDevice *))propertyChange{ AVCaptureDevice *captureDevice = [self.captureDeviceinput device]; NSError *error; //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁 if ([captureDevice lockForConfiguration:&error]) { propertyChange(captureDevice); [captureDevice unlockForConfiguration]; }else { NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription); }}//设置闪光灯模式- (voID)setFlashMode:(AVCaptureFlashMode)flashMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isFlashModeSupported:flashMode]) { [captureDevice setFlashMode:flashMode]; } }];}//设置聚焦模式- (voID)setFocusMode:(AVCaptureFocusMode)focusMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isFocusModeSupported:focusMode]) { [captureDevice setFocusMode:focusMode]; } }];}//设置曝光模式- (voID)setExposureMode:(AVCaptureExposureMode)exposureMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isExposureModeSupported:exposureMode]) { [captureDevice setExposureMode:exposureMode]; } }];}//设置聚焦点- (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{ [self.containerVIEw addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)]];}- (voID)tapScreen:(UITapGestureRecognizer *)tapGesture{ CGPoint point = [tapGesture locationInVIEw:self.containerVIEw]; //将UI坐标转化为摄像头坐标 CGPoint cameraPoint = [self.captureVIDeoPrevIEwLayer captureDevicePointOfInterestForPoint:point]; [self setFocusCursorWithPoint:point]; [self focusWithMode:AVCaptureFocusModeautoFocus exposureMode:AVCaptureExposureModeautoExpose atPoint:cameraPoint];}//设置聚焦光标位置- (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; }];}- (voID)dealloc{ [self removeNotification];}@end
Demo下载链接
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
总结以上是内存溢出为你收集整理的iOS使用视听媒体框架AVFoundation实现照片拍摄全部内容,希望文章能够帮你解决iOS使用视听媒体框架AVFoundation实现照片拍摄所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)