123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- //
- // AVCaptureViewController.m
- // 实时视频Demo
- //
- // Created by zhongfeng1 on 2017/2/16.
- // Copyright © 2017年 zhongfeng. All rights reserved.
- //
- #import "AVCaptureViewController.h"
- #import <AVFoundation/AVFoundation.h>
- #import <AssetsLibrary/AssetsLibrary.h>
- #import "LHSIDCardScaningView.h"
- #import "IDInfo.h"
- #import "excards.h"
- //#import "IDInfoViewController.h"
- #import "UIImage+Extend.h"
- #import "RectManager.h"
- #import "UIAlertController+Extend.h"
- @interface AVCaptureViewController () <AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureMetadataOutputObjectsDelegate>
- // 摄像头设备
- @property (nonatomic,strong) AVCaptureDevice *device;
- // AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
- @property (nonatomic,strong) AVCaptureSession *session;
- // 输出格式
- @property (nonatomic,strong) NSNumber *outPutSetting;
- // 出流对象
- @property (nonatomic,strong) AVCaptureVideoDataOutput *videoDataOutput;
- // 元数据(用于人脸识别)
- @property (nonatomic,strong) AVCaptureMetadataOutput *metadataOutput;
- // 预览图层
- @property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer;
- // 人脸检测框区域
- @property (nonatomic,assign) CGRect faceDetectionFrame;
- // 队列
- @property (nonatomic,strong) dispatch_queue_t queue;
- // 是否打开手电筒
- @property (nonatomic,assign,getter = isTorchOn) BOOL torchOn;
- @end
- @implementation AVCaptureViewController
- #pragma mark - 检测是模拟器还是真机
- #if TARGET_IPHONE_SIMULATOR
- // 是模拟器的话,提示“请使用真机测试!!!”
- -(void)viewDidLoad {
- [super viewDidLoad];
-
- self.navigationItem.title = @"扫描身份证";
-
- __weak __typeof__(self) weakSelf = self;
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"返回" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
-
- [weakSelf dismissViewControllerAnimated:YES completion:nil];
- //[weakSelf.navigationController popViewControllerAnimated:YES];
- }];
- UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"模拟器没有摄像设备" message:@"请使用真机测试!!!" okAction:okAction cancelAction:nil];
-
- [self presentViewController:alertC animated:YES completion:nil];
- }
- #else
- #pragma mark - 懒加载
- #pragma mark device
- -(AVCaptureDevice *)device {
- if (_device == nil) {
- _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
-
- NSError *error = nil;
- if ([_device lockForConfiguration:&error]) {
- if ([_device isSmoothAutoFocusSupported]) {// 平滑对焦
- _device.smoothAutoFocusEnabled = YES;
- }
-
- if ([_device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {// 自动持续对焦
- _device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
- }
-
- if ([_device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure ]) {// 自动持续曝光
- _device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
- }
-
- if ([_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {// 自动持续白平衡
- _device.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
- }
-
- // NSError *error1;
- // CMTime frameDuration = CMTimeMake(1, 30); // 默认是1秒30帧
- // NSArray *supportedFrameRateRanges = [_device.activeFormat videoSupportedFrameRateRanges];
- // BOOL frameRateSupported = NO;
- // for (AVFrameRateRange *range in supportedFrameRateRanges) {
- // if (CMTIME_COMPARE_INLINE(frameDuration, >=, range.minFrameDuration) && CMTIME_COMPARE_INLINE(frameDuration, <=, range.maxFrameDuration)) {
- // frameRateSupported = YES;
- // }
- // }
- //
- // if (frameRateSupported && [self.device lockForConfiguration:&error1]) {
- // [_device setActiveVideoMaxFrameDuration:frameDuration];
- // [_device setActiveVideoMinFrameDuration:frameDuration];
- //// [self.device unlockForConfiguration];
- // }
-
- [_device unlockForConfiguration];
- }
- }
-
- return _device;
- }
- #pragma mark outPutSetting
- -(NSNumber *)outPutSetting {
- if (_outPutSetting == nil) {
- _outPutSetting = @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
- }
-
- return _outPutSetting;
- }
- #pragma mark metadataOutput
- -(AVCaptureMetadataOutput *)metadataOutput {
- if (_metadataOutput == nil) {
- _metadataOutput = [[AVCaptureMetadataOutput alloc]init];
-
- [_metadataOutput setMetadataObjectsDelegate:self queue:self.queue];
- }
-
- return _metadataOutput;
- }
- #pragma mark videoDataOutput
- -(AVCaptureVideoDataOutput *)videoDataOutput {
- if (_videoDataOutput == nil) {
-
- _videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
-
- _videoDataOutput.alwaysDiscardsLateVideoFrames = YES;
- _videoDataOutput.videoSettings = @{(id)kCVPixelBufferPixelFormatTypeKey:self.outPutSetting};
-
-
- [_videoDataOutput setSampleBufferDelegate:self queue:self.queue];
- }
-
- return _videoDataOutput;
- }
- #pragma mark session
- -(AVCaptureSession *)session {
- if (_session == nil) {
- _session = [[AVCaptureSession alloc] init];
-
- _session.sessionPreset = AVCaptureSessionPresetHigh;
-
- // 2、设置输入:由于模拟器没有摄像头,因此最好做一个判断
- NSError *error = nil;
- AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
-
- if (error) {
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
- [self alertControllerWithTitle:@"没有摄像设备" message:error.localizedDescription okAction:okAction cancelAction:nil];
- }else {
- if ([_session canAddInput:input]) {
- [_session addInput:input];
- }
-
- if ([_session canAddOutput:self.videoDataOutput]) {
- [_session addOutput:self.videoDataOutput];
- }
- if(_cardType == 0)
- {
- if ([_session canAddOutput:self.metadataOutput]) {
- [_session addOutput:self.metadataOutput];
- // 输出格式要放在addOutPut之后,否则奔溃
- self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeFace];
- }
- }
- }
- }
-
- return _session;
- }
- #pragma mark previewLayer
- -(AVCaptureVideoPreviewLayer *)previewLayer {
- if (_previewLayer == nil) {
- _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
-
- _previewLayer.frame = self.view.frame;
- _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- }
-
- return _previewLayer;
- }
- #pragma mark queue
- -(dispatch_queue_t)queue {
- if (_queue == nil) {
- // _queue = dispatch_queue_create("AVCaptureSession_Start_Running_Queue", DISPATCH_QUEUE_SERIAL);
- _queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- }
-
- return _queue;
- }
- #pragma mark - 运行session
- // session开始,即输入设备和输出设备开始数据传递
- - (void)runSession {
- if (![self.session isRunning]) {
- dispatch_async(self.queue, ^{
- [self.session startRunning];
- });
- }
- }
- #pragma mark - 停止session
- // session停止,即输入设备和输出设备结束数据传递
- -(void)stopSession {
- if ([self.session isRunning]) {
- dispatch_async(self.queue, ^{
- [self.session stopRunning];
- });
- }
- }
- #pragma mark - 打开/关闭手电筒
- -(void)turnOnOrOffTorch {
- self.torchOn = !self.isTorchOn;
-
- if ([self.device hasTorch]){ // 判断是否有闪光灯
- [self.device lockForConfiguration:nil];// 请求独占访问硬件设备
-
- if (self.isTorchOn) {
- self.navigationItem.rightBarButtonItem.image = [[UIImage imageNamed:@"nav_torch_on"] originalImage];
- [self.device setTorchMode:AVCaptureTorchModeOn];
- } else {
- self.navigationItem.rightBarButtonItem.image = [[UIImage imageNamed:@"nav_torch_off"] originalImage];
- [self.device setTorchMode:AVCaptureTorchModeOff];
- }
- [self.device unlockForConfiguration];// 请求解除独占访问硬件设备
- }else {
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
- [self alertControllerWithTitle:@"提示" message:@"您的设备没有闪光设备,不能提供手电筒功能,请检查" okAction:okAction cancelAction:nil];
- }
- }
- #pragma mark - view即将出现时
- -(void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-
- // 将AVCaptureViewController的navigationBar调为透明
- [[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:0];
- // [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
-
- // 每次展现AVCaptureViewController的界面时,都检查摄像头使用权限
- [self checkAuthorizationStatus];
-
- // rightBarButtonItem设为原样
- self.torchOn = NO;
- self.navigationItem.rightBarButtonItem.image = [[UIImage imageNamed:@"nav_torch_off"] originalImage];
- }
- #pragma mark - view即将消失时
- -(void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
-
- // 将AVCaptureViewController的navigationBar调为不透明
- [[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:1];
- // [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]}];
-
- [self stopSession];
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- self.navigationItem.title = @"扫描身份证";
-
- // 初始化rect
- const char *thePath = [[[NSBundle mainBundle] resourcePath] UTF8String];
- int ret = EXCARDS_Init(thePath);
- if (ret != 0) {
- NSLog(@"初始化失败:ret=%d", ret);
- }
-
- // 添加预览图层
- [self.view.layer addSublayer:self.previewLayer];
-
- // 添加自定义的扫描界面(中间有一个镂空窗口和来回移动的扫描线)
- LHSIDCardScaningView *IDCardScaningView = [[LHSIDCardScaningView alloc] initWithFrame:self.view.frame];
- IDCardScaningView.cardType = _cardType;
- [IDCardScaningView loadImage];
- self.faceDetectionFrame = IDCardScaningView.facePathRect;
- [self.view addSubview:IDCardScaningView];
-
- // 设置人脸扫描区域
- /*
-
- 为什么做人脸扫描?
-
- 经实践证明,由于预览图层是全屏的,当用户有时没有将身份证对准拍摄框边缘时,也会成功读取身份证上的信息,即也会捕获到不完整的身份证图像。
- 因此,为了截取到比较完整的身份证图像,在自定义扫描界面的合适位置上加了一个身份证头像框,让用户将该小框对准身份证上的头像,最终目的是使程序截取到完整的身份证图像。
- 当该小框检测到人脸时,再对比人脸区域是否在这个小框内,若在,说明用户的确将身份证头像放在了这个框里,那么此时这一帧身份证图像大小正好合适且完整,接下来才捕获该帧,就获得了完整的身份证截图。(若不在,那么就不捕获此时的图像)
-
- 理解:检测身份证上的人脸是为了获得证上的人脸区域,获得人脸区域是为了希望人脸区域能在小框内,这样的话,才截取到完整的身份证图像。
-
- 个人认为:有了文字、拍摄区域的提示,99%的用户会主动将身份证和拍摄框边缘对齐,就能够获得完整的身份证图像,不做人脸区域的检测也可以。。。
-
- ps: 如果你不想加入人脸识别这一功能,你的app无需这么精细的话或者你又想读取到身份证反面的信息(签发机关,有效期),请这样做:
-
- 1、请注释掉所有metadataOutput的代码及其下面的那个代理方法(-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection)
-
- 2、请在videoDataOutput的懒加载方法的if(_videoDataOutput == nil){}语句块中添加[_videoDataOutput setSampleBufferDelegate:self queue:self.queue];
-
- 3、请注释掉AVCaptureVideoDataOutputSampleBufferDelegate下的那个代理方法中的
- if (self.videoDataOutput.sampleBufferDelegate) {
- [self.videoDataOutput setSampleBufferDelegate:nil queue:self.queue];
- }
-
- 4、运行程序,身份证正反两面皆可被检测到,请查看打印的信息。
-
- */
- // [[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification* _Nonnull note) {
- // __weak __typeof__(self) weakSelf = self;
- // self.metadataOutput.rectOfInterest = [self.previewLayer metadataOutputRectOfInterestForRect:IDCardScaningView.facePathRect];
- // }];
-
- // 添加关闭按钮
- [self addCloseButton];
-
- // 添加rightBarButtonItem为打开/关闭手电筒
- self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStylePlain target:self action:@selector(turnOnOrOffTorch)];
- }
- #pragma mark - 添加关闭按钮
- -(void)addCloseButton {
- UIButton *closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
-
- [closeBtn setImage:[UIImage imageNamed:@"common_icon_close"] forState:UIControlStateNormal];
- CGFloat closeBtnWidth = 40;
- CGFloat closeBtnHeight = closeBtnWidth;
- CGRect viewFrame = self.view.frame;
- closeBtn.frame = (CGRect){CGRectGetMaxX(viewFrame) - closeBtnWidth - 15, CGRectGetMaxY(viewFrame) - closeBtnHeight - 20, closeBtnWidth, closeBtnHeight};
-
- [closeBtn addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside];
-
- [self.view addSubview:closeBtn];
- }
- #pragma mark 绑定“关闭按钮”的方法
- -(void)close {
- [self dismissViewControllerAnimated:YES completion:nil];
- //[self.navigationController popViewControllerAnimated:YES];
- }
- #pragma mark - 检测摄像头权限
- -(void)checkAuthorizationStatus {
- AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
-
- switch (authorizationStatus) {
- case AVAuthorizationStatusNotDetermined:[self showAuthorizationNotDetermined]; break;// 用户尚未决定授权与否,那就请求授权
- case AVAuthorizationStatusAuthorized:[self showAuthorizationAuthorized]; break;// 用户已授权,那就立即使用
- case AVAuthorizationStatusDenied:[self showAuthorizationDenied]; break;// 用户明确地拒绝授权,那就展示提示
- case AVAuthorizationStatusRestricted:[self showAuthorizationRestricted]; break;// 无法访问相机设备,那就展示提示
- }
- }
- #pragma mark - 相机使用权限处理
- #pragma mark 用户还未决定是否授权使用相机
- -(void)showAuthorizationNotDetermined {
- __weak __typeof__(self) weakSelf = self;
- [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
- granted? [weakSelf runSession]: [weakSelf showAuthorizationDenied];
- }];
- }
- #pragma mark 被授权使用相机
- -(void)showAuthorizationAuthorized {
- [self runSession];
- }
- #pragma mark 未被授权使用相机
- -(void)showAuthorizationDenied {
- NSString *title = @"相机未授权";
- NSString *message = @"请到系统的“设置-隐私-相机”中授权此应用使用您的相机";
-
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
- // 跳转到该应用的隐私设授权置界面
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
- }];
- UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil];
- [self alertControllerWithTitle:title message:message okAction:okAction cancelAction:cancelAction];
- }
- #pragma mark 使用相机设备受限
- -(void)showAuthorizationRestricted {
- NSString *title = @"相机设备受限";
- NSString *message = @"请检查您的手机硬件或设置";
-
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
- [self alertControllerWithTitle:title message:message okAction:okAction cancelAction:nil];
- }
- #pragma mark - 展示UIAlertController
- -(void)alertControllerWithTitle:(NSString *)title message:(NSString *)message okAction:(UIAlertAction *)okAction cancelAction:(UIAlertAction *)cancelAction {
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message okAction:okAction cancelAction:cancelAction];
- [self presentViewController:alertController animated:YES completion:nil];
- }
- #pragma mark - AVCaptureMetadataOutputObjectsDelegate
- #pragma mark 从输出的元数据中捕捉人脸
- // 检测人脸是为了获得“人脸区域”,做“人脸区域”与“身份证人像框”的区域对比,当前者在后者范围内的时候,才能截取到完整的身份证图像
- -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
- if (metadataObjects.count) {
- AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects.firstObject;
-
- AVMetadataObject *transformedMetadataObject = [self.previewLayer transformedMetadataObjectForMetadataObject:metadataObject];
- CGRect faceRegion = transformedMetadataObject.bounds;
-
- if (metadataObject.type == AVMetadataObjectTypeFace) {
- NSLog(@"是否包含头像:%d, facePathRect: %@, faceRegion: %@",CGRectContainsRect(self.faceDetectionFrame, faceRegion),NSStringFromCGRect(self.faceDetectionFrame),NSStringFromCGRect(faceRegion));
-
- if (CGRectContainsRect(self.faceDetectionFrame, faceRegion)) {// 只有当人脸区域的确在小框内时,才再去做捕获此时的这一帧图像
- // 为videoDataOutput设置代理,程序就会自动调用下面的代理方法,捕获每一帧图像
- if (!self.videoDataOutput.sampleBufferDelegate) {
- [self.videoDataOutput setSampleBufferDelegate:self queue:self.queue];
- }
- }
- }
- }
- }
- #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate
- #pragma mark 从输出的数据流捕捉单一的图像帧
- // AVCaptureVideoDataOutput获取实时图像,这个代理方法的回调频率很快,几乎与手机屏幕的刷新频率一样快
- -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
- if ([self.outPutSetting isEqualToNumber:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]] || [self.outPutSetting isEqualToNumber:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]]) {
- CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
-
- if ([captureOutput isEqual:self.videoDataOutput]) {
- // 身份证信息识别
- [self IDCardRecognit:imageBuffer];
-
- // 身份证信息识别完毕后,就将videoDataOutput的代理去掉,防止频繁调用AVCaptureVideoDataOutputSampleBufferDelegate方法而引起的“混乱”
- if(_cardType == 0)
- {
- if (self.videoDataOutput.sampleBufferDelegate) {
- [self.videoDataOutput setSampleBufferDelegate:nil queue:self.queue];
- }
- }
-
- }
- } else {
- NSLog(@"输出格式不支持");
- }
- }
- #pragma mark - 身份证信息识别
- - (void)IDCardRecognit:(CVImageBufferRef)imageBuffer {
- CVBufferRetain(imageBuffer);
-
- // Lock the image buffer
- if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) {
- size_t width= CVPixelBufferGetWidth(imageBuffer);// 1920
- size_t height = CVPixelBufferGetHeight(imageBuffer);// 1080
-
- CVPlanarPixelBufferInfo_YCbCrBiPlanar *planar = CVPixelBufferGetBaseAddress(imageBuffer);
- size_t offset = NSSwapBigIntToHost(planar->componentInfoY.offset);
- size_t rowBytes = NSSwapBigIntToHost(planar->componentInfoY.rowBytes);
- unsigned char* baseAddress = (unsigned char *)CVPixelBufferGetBaseAddress(imageBuffer);
- unsigned char* pixelAddress = baseAddress + offset;
-
- static unsigned char *buffer = NULL;
- if (buffer == NULL) {
- buffer = (unsigned char *)malloc(sizeof(unsigned char) * width * height);
- }
-
- memcpy(buffer, pixelAddress, sizeof(unsigned char) * width * height);
-
- unsigned char pResult[1024];
- int ret = EXCARDS_RecoIDCardData(buffer, (int)width, (int)height, (int)rowBytes, (int)8, (char*)pResult, sizeof(pResult));
- if (ret <= 0) {
- NSLog(@"ret=[%d]", ret);
- } else {
- NSLog(@"ret=[%d]", ret);
-
- // 播放一下“拍照”的声音,模拟拍照
- AudioServicesPlaySystemSound(1108);
-
- if ([self.session isRunning]) {
- [self.session stopRunning];
- }
- char ctype;
- char content[256];
- int xlen;
- int i = 0;
-
- IDInfo *iDInfo = [[IDInfo alloc] init];
- iDInfo.type=self.cardType+1;
- ctype = pResult[i++];
-
- // iDInfo.type = ctype;
- while(i < ret){
- ctype = pResult[i++];
- for(xlen = 0; i < ret; ++i){
- if(pResult[i] == ' ') { ++i; break; }
- content[xlen++] = pResult[i];
- }
-
- content[xlen] = 0;
-
- if(xlen) {
- NSStringEncoding gbkEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
- if(ctype == 0x21) {
- iDInfo.num = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x22) {
- iDInfo.name = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x23) {
- iDInfo.gender = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x24) {
- iDInfo.nation = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x25) {
- iDInfo.address = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x26) {
- iDInfo.issue = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- } else if(ctype == 0x27) {
- iDInfo.valid = [NSString stringWithCString:(char *)content encoding:gbkEncoding];
- }
- }
- }
- NSArray *saleArray = [iDInfo.valid componentsSeparatedByString:@"-"];
- iDInfo.valid=[NSString stringWithFormat:@"%@-%@-%@",[saleArray[1] substringToIndex:4],[saleArray[1] substringWithRange:NSMakeRange(4,2)],[saleArray[1] substringFromIndex:6]];
- if (iDInfo) {// 读取到身份证信息,实例化出IDInfo对象后,截取身份证的有效区域,获取到图像
- NSLog(@"\n正面\n姓名:%@\n性别:%@\n民族:%@\n住址:%@\n公民身份证号码:%@\n\n反面\n签发机关:%@\n有效期限:%@",iDInfo.name,iDInfo.gender,iDInfo.nation,iDInfo.address,iDInfo.num,iDInfo.issue,iDInfo.valid);
-
- CGRect effectRect = [RectManager getEffectImageRect:CGSizeMake(width, height)];
- CGRect rect = [RectManager getGuideFrame:effectRect];
-
- UIImage *image = [UIImage getImageStream:imageBuffer];
- UIImage *subImage = [UIImage getSubImage:rect inImage:image];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.delegate AVCaptureViewReData:iDInfo img:subImage];
- //[self.navigationController popViewControllerAnimated:YES];
- [self dismissViewControllerAnimated:YES completion:nil];
- });
-
- // 推出IDInfoVC(展示身份证信息的控制器)
- // IDInfoViewController *IDInfoVC = [[IDInfoViewController alloc] init];
- //
- // IDInfoVC.IDInfo = iDInfo;// 身份证信息
- // IDInfoVC.IDImage = subImage;// 身份证图像
- //
- // dispatch_async(dispatch_get_main_queue(), ^{
- // [self.navigationController pushViewController:IDInfoVC animated:YES];
- // });
- }
- }
-
- CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
- }
-
- CVBufferRelease(imageBuffer);
- }
- /*
- - (UIImage*)imageWithImageSimple:(NSData *)data scaledToSize:(CGSize)newSize {
- UIImage *image = [UIImage imageWithData:data];
-
- // Create a graphics image context
- UIGraphicsBeginImageContext(newSize);
-
- // Tell the old image to draw in this new context, with the desired
- // new size
- [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
-
- // Get the new image from the context
- UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
-
- // End the context
- UIGraphicsEndImageContext();
-
- // Return the new image.
-
- return newImage;
- }
- - (UIImage *)clipImageWithImage:(UIImage *)image InRect:(CGRect)rect {
- CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
- UIImage *thumbScale = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
-
- return thumbScale;
- }
- - (void)addConnection {
- AVCaptureConnection *videoConnection;
- for (AVCaptureConnection *connection in [self.videoDataOutput connections]) {
- for (AVCaptureInputPort *port in [connection inputPorts]) {
- if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
- videoConnection = connection;
- }
- }
- }
-
- if ([videoConnection isVideoStabilizationSupported]) {
- if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
- videoConnection.enablesVideoStabilizationWhenAvailable = YES;
- }
- else {
- videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
- }
- }
- }
- - (void)configureDevice:(AVCaptureDevice *)device {
- // Use Smooth focus
- if( YES == [device lockForConfiguration:NULL] )
- {
- if([device respondsToSelector:@selector(setSmoothAutoFocusEnabled:)] && [device isSmoothAutoFocusSupported] )
- {
- [device setSmoothAutoFocusEnabled:YES];
- }
- AVCaptureFocusMode currentMode = [device focusMode];
- if( currentMode == AVCaptureFocusModeLocked )
- {
- currentMode = AVCaptureFocusModeAutoFocus;
- }
- if( [device isFocusModeSupported:currentMode] )
- {
- [device setFocusMode:currentMode];
- }
- [device unlockForConfiguration];
- }
- }
- */
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- #endif
- @end
|