美文网首页
iOS自定义相机

iOS自定义相机

作者: 里克尔梅西 | 来源:发表于2020-11-05 11:34 被阅读0次

项目中的拍照识别题目功能,使用了自定义相机,现将其记录如下:
.h中

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

NS_ASSUME_NONNULL_BEGIN

@class CameraView;
@protocol CameraViewDelegate <NSObject>
@optional;

/// 闪光灯
- (void)torchLightAction:(CameraView *)cameraView handle:(void(^)(NSError *error))handle;

/// 聚焦
- (void)focusAction:(CameraView *)cameraView point:(CGPoint)point handle:(void(^)(NSError *error))handle;

/// 取消
- (void)cancelAction:(CameraView *)cameraView;

/// 拍照
- (void)takePhotoAction:(CameraView *)cameraView withImage:(UIImage *)image;

/// 相册按钮点击
- (void)albumAction:(CameraView *)cameraView;
@end

@interface CameraView : UIView

@property(nonatomic, weak) id <CameraViewDelegate> delegate;
@property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;

@property (nonatomic, strong) UIButton *pictureButton;  //相册按钮
@property (nonatomic, strong) UIButton *flashButton;    //闪光灯按钮
@property (nonatomic, strong) UIButton *takePhotoButton;//拍照按钮
@property (nonatomic, strong) UIButton *backButton;     //关闭按钮
@property (nonatomic, strong) UILabel *scriptLabel;     //描述文字

- (void)startCamera;
- (void)stopCamera;

@end

.m中:

#import "CameraView.h"
#import "CameraPreView.h"
#import "CameraManager.h"
#import "FocusView.h"

#define MAINSCREEN_BOUNDS  [UIScreen mainScreen].bounds

typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice);

@interface CameraView ()<AVCapturePhotoCaptureDelegate>

// AVFoundation 的属性
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureStillImageOutput *imageOutput;
@property (nonatomic, strong) AVCaptureDevice *captureDevice;
@property (nonatomic, strong) CameraPreView *previewView;
@property (nonatomic, retain) AVCapturePhotoSettings *outputSettings;
@property (nonatomic, strong) FocusView *focusView;



@end

@implementation CameraView

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self setUpCameraPreviewLayer];
        // 花线
        [self setLineView];
        [self configureUI];
        [self addGenstureRecognizer];
    }
    return self;
}

#pragma mark - AVFoundation 配置
- (void)setUpCameraPreviewLayer {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied) {
        return;
    }
    if (!self.previewView) {
        [self initSession];
        self.previewView = [[CameraPreView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
        [self addSubview:self.previewView];
        self.previewView.captureSession = self.captureSession;
    }
}

- (void)initSession {
    self.captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    self.captureSession = [[AVCaptureSession alloc] init];
    self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
    
    self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self cameraWithDirection:AVCaptureDevicePositionBack] error:nil];
    
    // 静态图片输出
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    self.imageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    
    
    if ([self.captureSession canAddInput:self.deviceInput]) {
        [self.captureSession addInput:self.deviceInput];
    }
    if ([self.captureSession canAddOutput:self.imageOutput]) {
        [self.captureSession addOutput:self.imageOutput];
    }
    //注意添加区域改变捕获通知必须首先设置设备允许捕获
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        self.captureDevice.subjectAreaChangeMonitoringEnabled = YES;
    }];
}

- (AVCaptureDevice *)cameraWithDirection:(AVCaptureDevicePosition)position {
//    NSArray *devices = [AVCaptureDevice AVCaptureDeviceDiscoverySession:AVMediaTypeVideo];
//    for (AVCaptureDevice *device in devices) {
//        if ([device position] == position) {
//            return device;
//        }
//    }
//    return nil;
    AVCaptureDeviceDiscoverySession *devicesIOS10 = [AVCaptureDeviceDiscoverySession  discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:position];
    
    NSArray *devicesIOS  = devicesIOS10.devices;
    for (AVCaptureDevice *device in devicesIOS) {
        if ([device position] == position) {
            return device;
        }
    }
    return nil;
}

//通过给屏幕上的view添加手势,获取手势的坐标.将坐标用setFocusPointOfInterest方法赋值给device
-(void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{
    AVCaptureDevice *captureDevice= [self.deviceInput device];
    NSError *error;
    //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁
    if ([captureDevice lockForConfiguration:&error]) {
        propertyChange(captureDevice);
        [captureDevice unlockForConfiguration];
    }else{
        NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription);
    }
}

#pragma mark - ConfigureUI
// 线条
- (void)setLineView{
    for (int i=1; i<3; i++) {
        UIView *lineView1 = [[UIView alloc]init];
        lineView1.frame = CGRectMake(MAINSCREEN_BOUNDS.size.width/3 * i, 0, 0.5, MAINSCREEN_BOUNDS.size.height);
        lineView1.backgroundColor = [UIColor whiteColor];
        [self addSubview:lineView1];
        
        UIView *lineView2 = [[UIView alloc]init];
        lineView2.frame = CGRectMake(0, MAINSCREEN_BOUNDS.size.height/3 * i, MAINSCREEN_BOUNDS.size.width, 0.5);
        lineView2.backgroundColor = [UIColor whiteColor];
        [self addSubview:lineView2];
    }
}

- (void)configureUI {
    [self setLineView];
    [self addSubview:self.pictureButton];
    [self addSubview:self.backButton];
    [self addSubview:self.flashButton];
    [self addSubview:self.takePhotoButton];
    [self addSubview:self.scriptLabel];
    [self addSubview:self.focusView];
}

#pragma mark - Action
- (void)startCamera {
    if (self.captureSession) {
        [self.captureSession startRunning];
    }
}
- (void)stopCamera {
    if (self.captureSession) {
        [self.captureSession stopRunning];
    }
}

// 闪光灯
- (void)flashAction:(UIButton *)sender{
    if ([_delegate respondsToSelector:@selector(torchLightAction:handle:)]) {
        [_delegate torchLightAction:self handle:^(NSError *error) {
            if (error) {
//                [self showError:error];
            } else {
                self.flashButton.selected = !self.flashButton.selected;
            }
        }];
    }
}

// 相册
- (void)pictureAction:(UIButton *)sender{
    if ([_delegate respondsToSelector:@selector(albumAction:)]) {
        [_delegate albumAction:self];
    }
}

// 拍照
- (void)takePhotoAction:(UIButton *)sender {
    AVCaptureConnection *connection = [_imageOutput connectionWithMediaType:AVMediaTypeVideo];
    if (connection.isVideoOrientationSupported) {
//        connection.videoOrientation = [self orientationForConnection];
    }
    
    
    [_imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
        if (error) {
            return;
        }
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];
        if ([self.delegate respondsToSelector:@selector(takePhotoAction:withImage:)]) {
            [self.delegate takePhotoAction:self withImage:image];
        }
    }];
}

// 返回
- (void)backAction:(UIButton *)sender {
    if ([_delegate respondsToSelector:@selector(cancelAction:)]) {
        [_delegate cancelAction:self];
    }
}

#pragma mark - 聚焦
//手势点击
- (void)addGenstureRecognizer {
    UITapGestureRecognizer *tapGesture= [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];
    [self addGestureRecognizer:tapGesture];
}

- (void)tapScreen:(UITapGestureRecognizer*)gesture {
    CGPoint point = [gesture locationInView:gesture.view];
    [self focusAtPoint:point];
}

- (void)focusAtPoint:(CGPoint)point {
    CGSize size = self.bounds.size;
    CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );
    NSError *error;
    if ([self.captureDevice lockForConfiguration:&error]) {
        if ([self.captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.captureDevice setFocusPointOfInterest:focusPoint];
            [self.captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        [self.captureDevice unlockForConfiguration];
    }
    [self setFocusCursorWithPoint:point];
}

-(void)setFocusCursorWithPoint:(CGPoint)point{
     //下面是手触碰屏幕后对焦的效果
    self.focusView.center = point;
    self.focusView.hidden = NO;

    [UIView animateWithDuration:0.3 animations:^{
        self.focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);
    }completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5 animations:^{
            self.focusView.transform = CGAffineTransformIdentity;
            self.focusView.alpha = 0.1;
        } completion:^(BOOL finished) {
            self.focusView.hidden = YES;
            self.focusView.alpha = 1;
        }];
    }];
    
}

- (AVCaptureVideoOrientation)orientationForConnection {
    AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait;
    
    switch ([UIDevice currentDevice].orientation) {
        case UIDeviceOrientationLandscapeLeft:
            // yes to the right, this is not bug!
            videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            break;
        case UIDeviceOrientationLandscapeRight:
            videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
            break;
        default:
            videoOrientation = AVCaptureVideoOrientationPortrait;
            break;
    }
    return videoOrientation;
}

#pragma mark - Lazy init
//相册按钮
- (UIButton *)pictureButton {
    if (!_pictureButton) {
        _pictureButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _pictureButton.frame = CGRectMake(self.frame.size.width - 56, kScreenHeight - 66, 40, 40);
        [_pictureButton setBackgroundImage:[UIImage imageNamed:@"wrongbook_xiangce"] forState:UIControlStateNormal];
        [_pictureButton addTarget:self action:@selector(pictureAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _pictureButton;
}

//闪光灯按钮
- (UIButton *)flashButton {
    if (!_flashButton) {
        _flashButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _flashButton.frame = CGRectMake(16, 16, 40, 40);
        [_flashButton setBackgroundImage:[UIImage imageNamed:@"wrongbook_dengpaoOff"] forState:UIControlStateNormal];
        [_flashButton setBackgroundImage:[UIImage imageNamed:@"wrongbook_dengpaoOn"] forState:UIControlStateSelected];
        [_flashButton addTarget:self action:@selector(flashAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _flashButton;
}

//拍照按钮
- (UIButton *)takePhotoButton {
    if (!_takePhotoButton) {
        _takePhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _takePhotoButton.frame = CGRectMake(kScreenWidth / 2 - 31, kScreenHeight - 76, 62, 62);
        [_takePhotoButton setBackgroundImage:[UIImage imageNamed:@"wrongbook_paizhao"] forState:UIControlStateNormal];
        [_takePhotoButton addTarget:self action:@selector(takePhotoAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _takePhotoButton;
}

// 返回按钮
- (UIButton *)backButton {
    if (!_backButton) {
        _backButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backButton.frame = CGRectMake(16, kScreenHeight - 66, 40, 40);
        [_backButton setBackgroundImage:[UIImage imageNamed:@"wrongbook_guanbi"] forState:UIControlStateNormal];
        [_backButton addTarget:self action:@selector(backAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _backButton;
}

//描述文字
- (UILabel *)scriptLabel {
    if (!_scriptLabel) {
        _scriptLabel = [[UILabel alloc]init];
        _scriptLabel.text = @"文字对齐参考线,点击画面可聚焦";
        _scriptLabel.font = [UIFont systemFontOfSize:14];
        _scriptLabel.backgroundColor = [UIColor clearColor];
        _scriptLabel.textColor = [UIColor whiteColor];
        _scriptLabel.frame = CGRectMake(80, kScreenHeight / 2 - 15, kScreenWidth - 160, 30);
        _scriptLabel.textAlignment = NSTextAlignmentCenter;
    }
    return _scriptLabel;;
}

- (FocusView *)focusView {
    if (!_focusView) {
        _focusView = [[FocusView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
        _focusView.hidden = YES;
    }
    return _focusView;
}

参考资料:
https://www.jianshu.com/p/83d7ea181001
https://www.jianshu.com/p/69b31e80ba49

相关文章

网友评论

      本文标题:iOS自定义相机

      本文链接:https://www.haomeiwen.com/subject/zppovktx.html