iOS:自定义相机

2020-09-28  本文已影响0人  春暖花已开
图片.png
代码部分
#import "MZScanVC.h"

#import <AVFoundation/AVFoundation.h>

#define kScreenWidth UIScreen.mainScreen.bounds.size.width
#define kScreenHeight UIScreen.mainScreen.bounds.size.height

@interface MZScanView : UIView

/// 重写layerClass, 并将该view设置为控制器的view
+ (Class)layerClass;

@end

@implementation MZScanView

+ (Class)layerClass {
    return [AVCaptureVideoPreviewLayer class];
}

@end


@interface MZScanBackgroundView : UIView

@property(nonatomic, assign) CGRect scanFrame;

@end

@implementation MZScanBackgroundView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    [[[UIColor blackColor] colorWithAlphaComponent:0.2] setFill];
    //半透明区域
    UIRectFill(rect);
    //透明的区域
    CGRect holeiInterSection = CGRectIntersection(self.scanFrame, rect);
    [[UIColor clearColor] setFill];
    UIRectFill(holeiInterSection);
}

@end

@interface MZScanVC ()<AVCaptureVideoDataOutputSampleBufferDelegate>

@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (nonatomic, strong) AVCaptureDeviceInput *videoInput;

@property (nonatomic, strong) MZScanBackgroundView *backgroundView;

@end

@implementation MZScanVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor clearColor];
    [self setupSession];
    [self backgroundView];
}

- (void)setupSession {
    
    self.captureSession = [[AVCaptureSession alloc] init];
    NSError *error;
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    //更改这个设置的时候必须先锁定设备,修改完后再解锁,否则崩溃
    [device lockForConfiguration:nil];
    
    [device unlockForConfiguration];
    
    self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
    if (error) NSLog(@"%@",error);
    
    self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    //输出设置AVVideoCodecJPEG  输出jpeg格式图片
    NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    [self.stillImageOutput setOutputSettings:outputSettings];
    
    if ([self.captureSession canAddInput:self.videoInput]) {
        [self.captureSession addInput:self.videoInput];
    }
    if ([self.captureSession canAddOutput:self.stillImageOutput]) {
        [self.captureSession addOutput:self.stillImageOutput];
    }
    
    //初始化预览图层
    self.videoPreviewLayer = (AVCaptureVideoPreviewLayer *)self.view.layer;
    self.videoPreviewLayer.session = self.captureSession;
    [self.videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [self.videoPreviewLayer setFrame:self.view.layer.bounds];
    
    [self resetModes];
}

- (void)resetModes {
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureExposureMode exposureMode = AVCaptureExposureModeContinuousAutoExposure;
    AVCaptureFocusMode focusMode = AVCaptureFocusModeContinuousAutoFocus;
    BOOL canResetFocus = [device isFocusPointOfInterestSupported] && [device isFocusModeSupported:focusMode];
    BOOL canResetExposure = [device isExposurePointOfInterestSupported] && [device isExposureModeSupported:exposureMode];
    CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
    NSError *error;
    if ([device lockForConfiguration:&error]) {
        if (canResetFocus) {
            device.focusMode = focusMode;
            device.focusPointOfInterest = centerPoint;
        }
        if (canResetExposure) {
            device.exposureMode = exposureMode;
            device.exposurePointOfInterest = centerPoint;
        }
        [device unlockForConfiguration];
    }
}

- (void)startCapturing {
    if (!self.captureSession.isRunning) {
        [_captureSession startRunning];
    }
}

- (void)stopCapturing {
    if (self.captureSession.isRunning) {
        [_captureSession stopRunning];
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [self startCapturing];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    [self.navigationController setNavigationBarHidden:NO animated:animated];
    [self stopCapturing];
}

/// 点击取消
- (IBAction)onClickCancel {
    [self stopCapturing];
    [self dismissViewControllerAnimated:YES completion:nil];
}

/// 点击拍照
- (IBAction)onClickTakePhoto {
    AVCaptureConnection *stillImageCon = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    __weak typeof(self) weakself = self;
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageCon completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
        NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:jpegData];
        //返回拍照
        !weakself.getBlock ?: weakself.getBlock(image);
        [weakself onClickCancel];
    }];
}

- (MZScanBackgroundView *)backgroundView {
    if (!_backgroundView) {
        _backgroundView = [MZScanBackgroundView new];
        [self.view addSubview:_backgroundView];
        _backgroundView.frame = [UIScreen mainScreen].bounds;
        CGFloat x = 10;
        CGFloat y = 120 + (kScreenHeight >= 812 ? 44 : 20);
        _backgroundView.scanFrame = CGRectMake(x, y, kScreenWidth - 20, (kScreenWidth - 20)/1.58);
        [self.view insertSubview:_backgroundView atIndex:1];
    }
    return _backgroundView;
}

@end
xib部分
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_1" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MZScanVC">
            <connections>
                <outlet property="view" destination="iN0-l3-epB" id="KHG-9D-L5m"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MZScanView">
            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vTX-dQ-8Gl">
                    <rect key="frame" x="10" y="164" width="394" height="249.5"/>
                    <subviews>
                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="扫描框-人像面" translatesAutoresizingMaskIntoConstraints="NO" id="Ks3-m2-6Bn">
                            <rect key="frame" x="0.0" y="0.0" width="394" height="249.5"/>
                        </imageView>
                    </subviews>
                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <constraints>
                        <constraint firstAttribute="bottom" secondItem="Ks3-m2-6Bn" secondAttribute="bottom" id="klT-V5-ikd"/>
                        <constraint firstAttribute="trailing" secondItem="Ks3-m2-6Bn" secondAttribute="trailing" id="pJd-wp-G1c"/>
                        <constraint firstItem="Ks3-m2-6Bn" firstAttribute="leading" secondItem="vTX-dQ-8Gl" secondAttribute="leading" id="roA-r3-DRd"/>
                        <constraint firstItem="Ks3-m2-6Bn" firstAttribute="top" secondItem="vTX-dQ-8Gl" secondAttribute="top" id="w2u-dR-MmR"/>
                        <constraint firstAttribute="width" secondItem="vTX-dQ-8Gl" secondAttribute="height" multiplier="1.58" id="xof-bC-YQ5"/>
                    </constraints>
                </view>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vzR-sj-lX0">
                    <rect key="frame" x="0.0" y="696" width="414" height="200"/>
                    <subviews>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6up-o4-afi" userLabel="拍照">
                            <rect key="frame" x="174" y="45" width="66" height="66"/>
                            <state key="normal" image="icon-相机"/>
                            <connections>
                                <action selector="onClickTakePhoto" destination="-1" eventType="touchUpInside" id="kCg-Yx-A2g"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aQ9-jg-nlu">
                            <rect key="frame" x="357" y="61" width="37" height="34"/>
                            <state key="normal" title="取消"/>
                            <connections>
                                <action selector="onClickCancel" destination="-1" eventType="touchUpInside" id="c6d-28-eSn"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <constraints>
                        <constraint firstItem="6up-o4-afi" firstAttribute="top" secondItem="vzR-sj-lX0" secondAttribute="top" constant="45" id="AE0-fd-JXs"/>
                        <constraint firstItem="6up-o4-afi" firstAttribute="centerX" secondItem="vzR-sj-lX0" secondAttribute="centerX" id="GdT-Wa-Fq2"/>
                        <constraint firstItem="aQ9-jg-nlu" firstAttribute="centerY" secondItem="6up-o4-afi" secondAttribute="centerY" id="Hsh-RR-RHh"/>
                        <constraint firstAttribute="height" constant="200" id="K7T-ug-cqY"/>
                        <constraint firstAttribute="trailing" secondItem="aQ9-jg-nlu" secondAttribute="trailing" constant="20" id="hHZ-tv-cA7"/>
                    </constraints>
                </view>
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="请将身份证人像面放入扫描框内" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wzH-hl-jRN">
                    <rect key="frame" x="100" y="428.5" width="214.5" height="18"/>
                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                    <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <nil key="highlightedColor"/>
                </label>
            </subviews>
            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
            <constraints>
                <constraint firstItem="vTX-dQ-8Gl" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="120" id="B0s-1Y-6RG"/>
                <constraint firstAttribute="bottom" secondItem="vzR-sj-lX0" secondAttribute="bottom" id="DxT-LM-dSC"/>
                <constraint firstItem="vTX-dQ-8Gl" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="KNV-Ps-uLQ"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="vTX-dQ-8Gl" secondAttribute="trailing" constant="10" id="V9Y-tw-qdn"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="vzR-sj-lX0" secondAttribute="trailing" id="WaY-3C-trz"/>
                <constraint firstItem="vzR-sj-lX0" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="c7n-0A-l75"/>
                <constraint firstItem="wzH-hl-jRN" firstAttribute="top" secondItem="vTX-dQ-8Gl" secondAttribute="bottom" constant="15" id="hVB-v0-vZM"/>
                <constraint firstItem="wzH-hl-jRN" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="v7b-5O-A6w"/>
            </constraints>
            <point key="canvasLocation" x="-249" y="76"/>
        </view>
    </objects>
    <resources>
        <image name="icon-相机" width="66" height="66"/>
        <image name="扫描框-人像面" width="315" height="198"/>
    </resources>
</document>
上一篇下一篇

猜你喜欢

热点阅读