拍照

// 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];
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值