iOS扫描功能

2019-03-28  本文已影响0人  始白

扫描大概流程:

  1. 创建设备对象,输入输出对象(这个比较好理解,扫描毕竟需要手机设备,扫描肯定是有输入输出操作)
  2. 创建session来管理输入输出对象,设置扫描要支持的格式比如二维码条形码
  3. 设置扫描窗口,这个就是你要设置扫描作用域范围
#import "ScanViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>

@interface ScanViewController ()<AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate>{
    AVCaptureSession *session;//输入输出的管理者
    AVCaptureDevice  *device;//获取摄像设备
    AVCaptureDeviceInput *input;//创建输入流
    AVCaptureMetadataOutput *output;//创建输出流
    AVCaptureVideoPreviewLayer *layer;//扫描窗口
    CGFloat imageX;
    CGFloat imageY;
}
@property (nonatomic, strong) UIImagePickerController *imagePickerVC;
@property (nonatomic, strong) UIImageView *activeImage;
@property (nonatomic, strong) UIButton  *torchButton;
@end

@implementation ScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"扫描";
    self.view.backgroundColor = [UIColor  whiteColor];
    
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"相册" style:UIBarButtonItemStylePlain target:self action:@selector(libraryPhoto)];
    imageX = DeviceSize.width*0.15;
    imageY = DeviceSize.width*0.15+64;
    // 判断相机权限
    [self checkCaptureStatus];
    [self initMaskView];
    [self initScan];
    
    [self performSelectorOnMainThread:@selector(timerFired) withObject:nil waitUntilDone:NO];
}
- (void)initMaskView{
    //扫描的框框
    UIImageView *scanImgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"card_box2"]];
    scanImgView.frame = CGRectMake(imageX, imageY, DeviceSize.width*0.7, DeviceSize.width*0.7);
    [self.view addSubview:scanImgView];
    //扫描的线
    UIImageView *lineImgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"card_thread"]];
    lineImgView.frame = CGRectMake(imageX, imageY, DeviceSize.width*0.7, 8);
    [self.view addSubview:lineImgView];
    self.activeImage = lineImgView;
    //扫描下面的提示按钮
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(scanImgView.frame), DeviceSize.width, 40)];
    label.text = @"将二维码放入框内即可自动扫描";
    label.textColor = [UIColor whiteColor];
    label.font = [UIFont systemFontOfSize:15];
    label.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:label];
    //添加全屏的黑色半透明蒙版
    UIView *maskView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, DeviceSize.width, DeviceSize.height+20)];
    maskView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
    [self.view addSubview:maskView];
    //从蒙版中扣出扫描框那一块,这块的大小尺寸将来也设成扫描输出的作用域大小
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
    [maskPath appendPath:[[UIBezierPath bezierPathWithRect:CGRectMake(imageX, imageY, DeviceSize.width*0.7, DeviceSize.width*0.7)]bezierPathByReversingPath]];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
    maskLayer.path = maskPath.CGPath;
    maskView.layer.mask = maskLayer;
}
- (void)initScan{
    //获取摄像设备
    device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //创建输入流
    input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    //创建输出流
    output = [[AVCaptureMetadataOutput alloc]init];
    //设置代理  在主线程里刷新
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    //初始化session
    session = [[AVCaptureSession alloc]init];
    //高质量采集率
    [session setSessionPreset:AVCaptureSessionPresetHigh];
    [session addInput:input];
    [session addOutput:output];
    //设置扫码支持的格式(二维码和条形码)
    output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code];
    layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    //设置相机可是范围--全屏
    layer.frame = self.view.bounds;
    [self.view.layer insertSublayer:layer atIndex:0];
    //开始捕获
    [session startRunning];
 //设置扫描作用域范围(中间透明的扫描框)
    CGRect intertRect = [layer metadataOutputRectOfInterestForRect:CGRectMake(imageX, imageY, DeviceSize.width*0.7, DeviceSize.width*0.7)];
    
    output.rectOfInterest = intertRect;
}
//扫描线运动
- (void)timerFired{
    [self.activeImage.layer addAnimation:[self time:2.5 Y:[NSNumber numberWithFloat:(DeviceSize.width*0.7-8)]] forKey:nil];
}
//动画 time单次滑动完成时间 y滑动距离
- (CABasicAnimation *)time:(float)time Y:(NSNumber *)y{
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    animation.toValue = y;
    animation.duration = time;
    animation.removedOnCompletion = YES;//yes返回原位置
    animation.repeatCount = MAXFLOAT;
    animation.fillMode = kCAFillModeForwards;
    return animation;
}
//代理方法扫描到的结果
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    if (metadataObjects.count>0) {
        [session stopRunning];
        AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
        NSLog(@"stringValue = %@",metadataObject.stringValue);
    }
}
- (void)checkCaptureStatus{
    // 判断是否支持相机
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if ((authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)) {
        // 无权限
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法使用相机" message:@"请在iPhone的""设置-隐私-相机""中允许访问相机" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"设置", nil];
        [alert show];
    }
}
- (void)libraryPhoto{
    // 判断是否支持照片
    PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
    if ((authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)) {
        // 无权限
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法使用相册" message:@"请在iPhone的""设置""中允许访问照片" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"设置", nil];
        [alert show];
    } else {
        self.imagePickerVC = [[UIImagePickerController alloc]init];
        self.imagePickerVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        self.imagePickerVC.mediaTypes = @[(NSString *)kUTTypeImage];
        self.imagePickerVC.delegate = self;
        self.imagePickerVC.allowsEditing = NO;
        self.imagePickerVC.navigationBar.barTintColor = [UIColor whiteColor];
        self.imagePickerVC.navigationBar.tintColor = kWord25Color;
        [self.imagePickerVC.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : kWord25Color}];
        [self presentViewController:_imagePickerVC animated:YES completion:NULL];
    }
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
        if (ios8AndUper) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        } else {
            
        }
    }
}
// 选择图片成功调用此方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    UIImage *pickerImage = info[UIImagePickerControllerOriginalImage];
    CIImage *ciImage = [CIImage imageWithData:UIImagePNGRepresentation(pickerImage)];
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyLow}];
    NSArray *features = [detector featuresInImage:ciImage];
    if (features.count >0) {
        CIQRCodeFeature *feature = features[0];
        NSLog(@"%@",feature.messageString);
    }
    [picker dismissViewControllerAnimated:NO completion:^{
    }];
}
// 取消图片选择调用此方法
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    // dismiss UIImagePickerController
    [self dismissViewControllerAnimated:YES completion:nil];
}
//开灯按钮事件处理
- (void)torchHandle{
    [self setTorch:![self torchIsOn]];
}
// 开关手电筒 status yes-开,no-关
- (void)setTorch:(BOOL)status{
    if (TARGET_IPHONE_SIMULATOR){
        return;
    }
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo];
        [device lockForConfiguration:nil];
        if ( [device hasTorch] ){
            if (status) {
                [device setTorchMode:AVCaptureTorchModeOn];
                [_torchButton setTitle:ZZYLocal(@"关灯") forState:UIControlStateNormal];
            }else{
                [device setTorchMode:AVCaptureTorchModeOff];
                [_torchButton setTitle:ZZYLocal(@"开灯") forState:UIControlStateNormal];
            }
        }
        [device unlockForConfiguration];
    }
}
//判断设备灯光开关
- (BOOL)torchIsOn{
    if (TARGET_IPHONE_SIMULATOR) {
        return NO;
    }
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil)
    {
        AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo];
        if ( [device hasTorch] ){
            return [device torchMode] == AVCaptureTorchModeOn;
        }
        [device unlockForConfiguration];
    }
    return NO;
}
@end

借鉴:https://www.jianshu.com/p/09742ec7ec78

上一篇下一篇

猜你喜欢

热点阅读