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,nonatomic) UIButton *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;
}
//闪光灯的设置非常简单,只需要修改device的flashMode属性即可,这里需要注意的是,修改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];//吧self。view上的点转换到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
- AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)
- AVFoundation/AVCaptureSession实现自定义相机界面录像(三)
- TesseractOCR 文字识别 自定义拍照界面(AVFoundation)
- AVFoundation/AVCaptureSession实现视频录制
- iOS使用AVCaptureSession自定义相机
- iOS使用AVCaptureSession自定义相机
- iOS使用AVCaptureSession自定义相机
- iOS使用AVCaptureSession自定义相机
- iOS使用AVCaptureSession自定义相机
- iOS使用AVCaptureSession自定义相机
- AVFoundation自定义相机
- AVFoundation自定义相机
- IOS二维码拍照相机自定义界面实例
- IOS二维码拍照相机自定义界面实例
- IOS二维码拍照相机自定义界面实例
- 自定义使用AVCaptureSession 拍照,摄像,载图
- iOS-使用AVCaptureSession自定义相机(AVFondation)
- iOS-----AVFoundation框架的功能详解 相机自定义拍照和录制视频
- 大话数据结构之:分块索引
- CollapsingToolbarLayout 中的Toolbar Title 居中
- RF +Appium的简单教程及实例
- 树莓派3B + DHT11 + Yeelink云平台(实现温湿度远程监控)
- C、C++变量命名规则
- AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)
- 作业:C++作业2-项目1
- 通过几个helloworld感受.net core开发体验
- spring+struts结合在第一次验证失败之后,不再走action的方法,直接进入input
- 字体加粗
- Spring源码分析----AOP通知以及编程式AOP
- java设计模式学习之单例模式
- TensorBoard 在1.0 版本后的使用
- 用JNI调用C/C++程序