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>