// 1. ViewController.m
#import "ViewController.h"
#import "TakeCameraView.h"
#import "CameraCaptureManager.h"
#import "DetailViewController.h"
@interface ViewController ()
// 拍照视图
@property (nonatomic, weak) TakeCameraView *cameraView;
@end
@implementation ViewController
#pragma mark - getter方法
- (TakeCameraView *)cameraView {
if (_cameraView == nil) {
TakeCameraView *cameraView = [[TakeCameraView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:cameraView];
cameraView.backgroundColor = [UIColor blackColor];
_cameraView = cameraView;
}
return _cameraView;
}
#pragma mark - System
- (void)viewDidLoad {
[super viewDidLoad];
// 获取image之后,将image显示到详情控制器 正向传值
[self.cameraView setPhotoBlock:^(NSData *data) {
DetailViewController *detailVC = [[DetailViewController alloc] init];
detailVC.imageData = data;
[self.navigationController pushViewController:detailVC animated:YES];
}];
}
- (void)viewWillAppear:(BOOL)animated {
// 隐藏导航条
[self.navigationController setNavigationBarHidden:YES animated:YES];
[[CameraCaptureManager sharedManager] startRunning];
[super viewWillAppear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[[CameraCaptureManager sharedManager] stopRunning];
[super viewDidDisappear:animated];
}
@end
// 2. TakeCameraView.h
#import <UIKit/UIKit.h>
typedef void(^TakePhotoBlock)(NSData *data);
@interface TakeCameraView : UIView
/**
* 获取图片的回调
*/
@property (nonatomic, copy) TakePhotoBlock photoBlock;
@end
// TakeCameraView.m
#import <AVFoundation/AVFoundation.h>
#import "TakeCameraView.h"
#import "CameraCaptureManager.h"
// 拍照按钮宽度
#define kTakePhotoButtonWidth 100
// 拍照按钮高度
#define kTakePhotoButtonHeight kTakePhotoButtonWidth
@interface TakeCameraView ()
// 拍照按钮
@property (nonatomic, weak) UIButton *takePhotoButton;
// 显示拍摄画面的涂层
@property (nonatomic, weak) AVCaptureVideoPreviewLayer *previewLayer;
// 切换设备按钮
@property (nonatomic, weak) UIButton *switchDeviceButton;
// 手电筒
@property (nonatomic, weak) UIButton *torchButton;
@end
@implementation TakeCameraView
#pragma mark - getter方法
- (UIButton *)takePhotoButton {
if (_takePhotoButton == nil) {
UIButton *takePhotoButton = [[UIButton alloc] init];
[self addSubview:takePhotoButton];
_takePhotoButton = takePhotoButton;
[takePhotoButton setBackgroundImage:[UIImage imageNamed:@"shot_h"] forState:UIControlStateNormal];
[takePhotoButton addTarget:self action:@selector(startPhotoBtnAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _takePhotoButton;
}
- (AVCaptureVideoPreviewLayer *)previewLayer {
if (_previewLayer == nil) {
// 获取桥梁
AVCaptureSession *session = [CameraCaptureManager sharedManager].session;
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
_previewLayer = previewLayer;
[self.layer insertSublayer:previewLayer atIndex:0];
}
return _previewLayer;
}
- (UIButton *)switchDeviceButton {
if (_switchDeviceButton == nil) {
UIButton *switchDeviceButton = [[UIButton alloc] init];
[self addSubview:switchDeviceButton];
_switchDeviceButton = switchDeviceButton;
[switchDeviceButton setBackgroundImage:[UIImage imageNamed:@"record_lensflip_highlighted"] forState:UIControlStateNormal];
[switchDeviceButton addTarget:self action:@selector(switchDeviceBtnAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _switchDeviceButton;
}
- (UIButton *)torchButton {
if (_torchButton == nil) {
UIButton *torchButton = [[UIButton alloc] init];
[self addSubview:torchButton];
_torchButton = torchButton;
[torchButton setBackgroundImage:[UIImage imageNamed:@"record_flashlight_disable"] forState:UIControlStateNormal];
[torchButton setBackgroundImage:[UIImage imageNamed:@"record_flashlight_highlighted"] forState:UIControlStateSelected];
[torchButton addTarget:self action:@selector(torchBtnAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _torchButton;
}
#pragma mark - Actions
/**
* 开始拍照
*/
- (void)startPhotoBtnAction:(UIButton *)button {
// 开始拍摄 让管理者去做拍摄这件事情
[[CameraCaptureManager sharedManager] takePhotoFromCameraWithFinishBlock:^(NSData *imageData) {
// 回调回来的数据再通过block回调给控制器
if (self.photoBlock) {
self.photoBlock(imageData);
}
}];
}
/**
* 切换前后摄像头
*/
- (void)switchDeviceBtnAction:(UIButton *)button {
button.selected = !button.selected;
if (button.selected) {
[[CameraCaptureManager sharedManager] switchDeviceWithCameraDevicePosition:CameraDevicePositionFront];
} else {
[[CameraCaptureManager sharedManager] switchDeviceWithCameraDevicePosition:CameraDevicePositionBack];
}
}
/**
* 开启闪光灯
*/
- (void)torchBtnAction:(UIButton *)button {
button.selected = !button.selected;
if (button.selected) {
[[CameraCaptureManager sharedManager] openTorchWithTorchStatus:TorchStatusOpen];
} else {
[[CameraCaptureManager sharedManager] openTorchWithTorchStatus:TorchStatusClose];
}
}
#pragma mark - System
- (void)layoutSubviews {
[super layoutSubviews];
// 拍摄按钮
self.takePhotoButton.frame = CGRectMake(self.frame.size.width/2-kTakePhotoButtonWidth/2, self.frame.size.height-kTakePhotoButtonHeight-20, kTakePhotoButtonWidth, kTakePhotoButtonHeight);
// 拍摄画面图层
self.previewLayer.frame = self.bounds;
// 切换设备按钮
CGFloat switchBtnW = 40;
CGFloat switchBtnH = switchBtnW;
self.switchDeviceButton.frame = CGRectMake(self.frame.size.width-switchBtnW-20, 30, switchBtnW, switchBtnH);
// 手电筒按钮
self.torchButton.frame = CGRectMake(20, 30, switchBtnW, switchBtnH);
}
@end
// CameraCaptureManager.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
typedef NS_ENUM(NSUInteger, CameraDevicePosition) {
CameraDevicePositionFront, // 前置摄像头
CameraDevicePositionBack // 后置摄像头
};
typedef NS_ENUM(NSUInteger, TorchStatus) {
TorchStatusOpen, // 开启
TorchStatusClose, // 关闭
TorchStatusAuto // 自动
};
// 拍照完成的回调
typedef void(^TakePhotoFinishBlock)(NSData *imageData);
@interface CameraCaptureManager : NSObject
/**
* 输入和输出设备的桥梁
*/
@property (nonatomic, strong, readonly) AVCaptureSession *session;
/**
* 创建单例对象
*/
+ (instancetype)sharedManager;
/**
* 开始拍摄
*/
- (void)startRunning;
/**
* 停止拍摄
*/
- (void)stopRunning;
/**
* 拍照获取图片
*
* @param takePhotoFinishBlock 拍照完成的回调
*/
- (void)takePhotoFromCameraWithFinishBlock:(TakePhotoFinishBlock)takePhotoFinishBlock;
/**
* 摄像头切换
*/
- (void)switchDeviceWithCameraDevicePosition:(CameraDevicePosition)cameraDevicePosition;
/**
* 打开手电筒
*/
- (void)openTorchWithTorchStatus:(TorchStatus)torchStatus;
@end
// CameraCaptureManager.m
#import "CameraCaptureManager.h"
/**
* AVCaptureSession 输入和输出设备的桥梁
* AVCaptureDevice 设备 初始化需要指定设备类型
* AVCaptureDeviceInput 输入对象 初始化使用AVCaptureDevice
* AVCaptureStillImageOutput 图片输出对象 需要设置输出图片的类型
*/
@interface CameraCaptureManager ()
// 虚拟摄像头设备
@property (nonatomic, strong) AVCaptureDevice *device;
// 输入对象
@property (nonatomic, strong) AVCaptureDeviceInput *input;
// 图片输出对象
@property (nonatomic, strong) AVCaptureStillImageOutput *output;
/**
* 输入和输出设备的桥梁
*/
@property (nonatomic, strong, readwrite) AVCaptureSession *session;
@end
@implementation CameraCaptureManager
#pragma mark - 初始化
static CameraCaptureManager *singleton = nil;
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[self alloc] init];
});
return singleton;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
@synchronized(self) {
if (singleton == nil) {
singleton = [super allocWithZone:zone];
}
}
return singleton;
}
#pragma mark - getter方法
/**
* 设备
*/
- (AVCaptureDevice *)device {
if (_device == nil) {
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
// 设置闪光灯打开
// [_device setFlashMode:AVCaptureFlashModeOn];
}
return _device;
}
/**
* 输入对象
*/
- (AVCaptureDeviceInput *)input {
if (_input == nil) {
_input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
}
return _input;
}
/**
* 输出对象
*/
- (AVCaptureStillImageOutput *)output {
if (_output == nil) {
_output = [[AVCaptureStillImageOutput alloc] init];
// 设置输出图片的类型
_output.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
}
return _output;
}
/**
* 输入和输出设备的桥梁
*/
- (AVCaptureSession *)session {
if (_session == nil) {
_session = [[AVCaptureSession alloc] init];
// 将输入设备和输出设备关联
if ([_session canAddInput:self.input]) {
[_session addInput:self.input];
}
if ([_session canAddOutput:self.output]) {
[_session addOutput:self.output];
}
}
return _session;
}
#pragma mark -
/**
* 开始拍摄
*/
- (void)startRunning {
[self.session startRunning];
}
/**
* 停止拍摄
*/
- (void)stopRunning {
[self.session stopRunning];
}
/**
* 拍照获取图片
*/
- (void)takePhotoFromCameraWithFinishBlock:(TakePhotoFinishBlock)takePhotoFinishBlock {
// 创建连接
AVCaptureConnection *connection = [self.output connectionWithMediaType:AVMediaTypeVideo];
// 获取图片
[self.output captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
// 把当前的样本转化为jpeg对象
NSData *data = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
// 回调
if (takePhotoFinishBlock) {
takePhotoFinishBlock(data);
}
}];
}
/**
* 摄像头切换
*/
- (void)switchDeviceWithCameraDevicePosition:(CameraDevicePosition)cameraDevicePosition {
// 前置
AVCaptureDevice *frontDevice;
// 后置
AVCaptureDevice *backDevice;
// 获取支持拍摄的设备
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices) {
if (device.position == AVCaptureDevicePositionFront) { // 前置
frontDevice = device;
} else if (device.position == AVCaptureDevicePositionBack) { // 后置
backDevice = device;
}
}
// 判断是前后摄像头 // 同步
if (cameraDevicePosition == CameraDevicePositionFront) {
[self updateInputWithAVCaptureDevice:frontDevice];
} else if (cameraDevicePosition == CameraDevicePositionBack) {
[self updateInputWithAVCaptureDevice:backDevice];
}
}
/**
* 打开或者关闭手电筒
*/
- (void)openTorchWithTorchStatus:(TorchStatus)torchStatus {
// 手电筒模式
AVCaptureTorchMode torchMode;
if (torchStatus == TorchStatusOpen) {
torchMode = AVCaptureTorchModeOn;
} else if (torchStatus == TorchStatusClose) {
torchMode = AVCaptureTorchModeOff;
} else if (torchStatus == TorchStatusAuto) {
torchMode = AVCaptureTorchModeAuto;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 获取当前的设备对象
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 锁住
[device lockForConfiguration:nil];
// 修改手电筒模式
[device setTorchMode:torchMode];
// 解锁
[device unlockForConfiguration];
});
}
/**
* 更新前后设备
*/
- (void)updateInputWithAVCaptureDevice:(AVCaptureDevice *)device {
[self.session beginConfiguration];
// 1. 移除输入设备
[self.session removeInput:self.input];
// 2. 初始化一个新的输入设备
AVCaptureDeviceInput *newDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 3. 添加新的输入设备
[self.session addInput:newDeviceInput];
[self.session commitConfiguration];
self.input = newDeviceInput;
}
@end<pre name="code" class="objc">#import "DetailViewController.h"
@interface DetailViewController () <UIActionSheetDelegate>
// 显示拍摄的图片
@property (nonatomic, weak) UIImageView *imageView;
@end
@implementation DetailViewController
#pragma mark - getter方法
- (UIImageView *)imageView {
if (_imageView == nil) {
UIImageView *imgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:imgView];
_imageView = imgView;
}
return _imageView;
}
#pragma mark - System
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView.image = [UIImage imageWithData:self.imageData];
[self addLongPressGest];
}
- (void)viewWillAppear:(BOOL)animated {
// 显示导航条
[self.navigationController setNavigationBarHidden:NO animated:YES];
[super viewWillAppear:animated];
}
- (void)addLongPressGest {
UILongPressGestureRecognizer *longPressGest = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestAction:)]; self.imageView.userInteractionEnabled = YES;
[self.imageView addGestureRecognizer:longPressGest];
}
- (void)longPressGestAction:(UILongPressGestureRecognizer *)longPressGest {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"提示" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"保存到相册" otherButtonTitles:nil, nil];
[actionSheet showInView:self.imageView];
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// 保存到相册
/**
* 1. 要写入到相册的图片
* 2. target
* 3. 方法 判断图片有没有保存成功
* 4. 上下文
*/
UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:self.imageData],self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"保存成功" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil];
[alert show];
}
拍照
最新推荐文章于 2021-07-29 04:38:20 发布