苹果原生二维码扫描器

项目中一直用的ZBar的扫描,后来发现速度明显和微信差很多,然后就想着替换成原生的,自己动手弄了一个简陋的扫描器,支持相册扫描,手电筒等。大神勿喷。

项目连接:https://github.com/SunshineTraveller/LMScaner 

直接上代码:

#define LMSCWID [UIScreen mainScreen].bounds.size.width

#define LMSCHEI [UIScreen mainScreen].bounds.size.height


#import "BHelperViewController.h"

#import "UIImage+OriginalImage.h"

#import "ZLMNoticeLabel.h"

#import "UIView_extra.h"

#import <AVFoundation/AVFoundation.h>

#import "LMScaner.h"


@interface LMScaner ()<AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate>


@property (nonatomic,strong) AVCaptureSession      *session;      // 捕获器

@property (nonatomic,strong) UIView                *maskView1;    // 遮罩1

@property (nonatomic,strong) UIView                *maskView2;    // 遮罩2

@property (nonatomic,strong) UIView                *maskView4;    // 遮罩4

@property (nonatomic,strong) UIView                *maskView5;    // 遮罩5

@property (nonatomic,strong) UIView                *scanWindow;   // 扫描窗

@property (nonatomic,strong) UIImageView           *redImageView; // 扫描条

@property (nonatomic,weak) NSTimer                 *timer;        // 计时器


@end


@implementation LMScaner




- (void)viewWillAppear:(BOOL)animated {

    self.navigationController.navigationBar.backgroundColor = [UIColor clearColor];

    self.navigationController.navigationBar.hidden = NO;

    [self resumeAnimation];

    [self.session startRunning];

}


- (void)viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];

    self.navigationController.navigationBar.hidden = NO;

    self.hidesBottomBarWhenPushed = NO;

    [self.timer setFireDate:[NSDate distantFuture]];

    [self.timer invalidate];

    self.timer = nil;

    [self.scanWindow removeFromSuperview];

    

}

-(void)viewDidDisappear:(BOOL)animated{

    [super viewDidDisappear:animated];

    [self.session stopRunning];

    

}

- (void)viewDidLoad {

    

    [super viewDidLoad];

    self.title = @"扫一扫";

    [self setupScanWindow];

    [self beginScanning];

    

}

-(void)setupScanWindow {

    

    [self.view addSubview:self.maskView1];

    [self.view addSubview:self.maskView2];

    [self.view addSubview:self.maskView4];

    [self.view addSubview:self.maskView5];

    [self.view addSubview:_scanWindow];

    

    //绿色角边框,因为扫描框比实际看到的要大,这里没用全用扫描框位置坐依据

    UIImageView *lu = [[UIImageView alloc] initWithFrame:CGRectMake(self.maskView2.right, self.scanWindow.y, 18, 18)];

    lu.backgroundColor = [UIColor clearColor];

    lu.image = [UIImage imageNamed:@"scan_l_u"];

    [self.view addSubview:lu];

    

    UIImageView *ld = [[UIImageView alloc] initWithFrame:CGRectMake(self.maskView2.right, self.maskView5.y-18, 18, 18)];

    ld.backgroundColor = [UIColor clearColor];

    ld.image = [UIImage imageNamed:@"scan_l_d"];

    [self.view addSubview:ld];

    

    UIImageView *ru = [[UIImageView alloc] initWithFrame:CGRectMake(self.maskView4.x-20, self.scanWindow.y, 18, 18)];

    ru.backgroundColor = [UIColor clearColor];

    ru.image = [UIImage imageNamed:@"scan_r_u"];

    [self.view addSubview:ru];

    

    UIImageView *rd = [[UIImageView alloc] initWithFrame:CGRectMake(self.maskView4.x-20, self.maskView5.y-20, 18, 18)];

    rd.backgroundColor = [UIColor clearColor];

    rd.image = [UIImage imageNamed:@"scan_r_d"];

    [self.view addSubview:rd];

    

    _redImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"homePage_Scanline"]];

    _redImageView.frame = CGRectMake(LMSCWID/6-1, self.maskView1.bottom, 2*LMSCWID/3+2, 1);

    [self.view addSubview:self.redImageView];

    [self.view bringSubviewToFront:self.redImageView];

}

-(UIView *)scanWindow {

    

    if (_scanWindow == nil) {

//        _scanWindow = [[UIView alloc] initWithFrame:CGRectMake(LMSCWID/6, self.maskView1.bottom, 2*LMSCWID/3, 2*LMSCWID/3)];

        _scanWindow = [[UIView alloc] initWithFrame:CGRectMake(0, self.maskView1.bottom, LMSCWID, LMSCWID)];

        _scanWindow.clipsToBounds = YES;

    }

    return _scanWindow;

    

}

-(UIView *)maskView2 {

    

    if (_maskView2 == nil) {

        _maskView2 = [[UIView alloc] initWithFrame:CGRectMake(0, self.maskView1.y+self.maskView1.height, LMSCWID/6, 2*LMSCWID/3)];

        _maskView2.alpha = 0.5;

        _maskView2.backgroundColor = [UIColor blackColor];

        _maskView2.userInteractionEnabled = NO;

    }

    return _maskView2;

}


-(UIView *)maskView4 {

    

    if (_maskView4 == nil) {

        _maskView4 = [[UIView alloc] initWithFrame:CGRectMake(LMSCWID-LMSCWID/6, self.maskView1.y+self.maskView1.height, LMSCWID/6, 2*LMSCWID/3)];

        _maskView4.backgroundColor = [UIColor blackColor];

        _maskView4.alpha = 0.5;

        _maskView4.userInteractionEnabled = NO;

    }

    return _maskView4;

}


-(UIView *)maskView5 {

    

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

    btn.frame = CGRectMake(LMSCWID/2-50, 15, 30, 30);

    [btn setImage:[UIImage imageNamed:@"homePage_PhotosOFF"] forState:UIControlStateNormal];

    [btn setBackgroundColor:[UIColor clearColor]];

    [btn addTarget:self action:@selector(myAlbum:) forControlEvents:UIControlEventTouchUpInside];

    

    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];

    btn1.frame = CGRectMake(LMSCWID/2+20, 15, 30, 30);

    [btn1 addTarget:self action:@selector(openFlash:) forControlEvents:UIControlEventTouchUpInside];

    [btn1 setImage:[UIImage imageNamed:@"homePage_TorchOFF"] forState:UIControlStateNormal];

    

    [btn1 setBackgroundColor:[UIColor clearColor]];

    

    UILabel *la = [[UILabel alloc] initWithFrame:CGRectMake(btn.center.x - 35, btn.frame.origin.y+btn.frame.size.height, 70, 30)];

    la.text = @"相册";

    la.font = [UIFont systemFontOfSize:14];

    la.textColor = [UIColor whiteColor];

    la.textAlignment = NSTextAlignmentCenter;

    la.backgroundColor = [UIColor clearColor];

    

    UILabel *lb = [[UILabel alloc] initWithFrame:CGRectMake(btn1.center.x - 35, btn.bottom, 70, 30)];

    lb.text = @"照明";

    lb.textAlignment = NSTextAlignmentCenter;

    lb.font = [UIFont systemFontOfSize:14];

    lb.textColor = [UIColor whiteColor];

    lb.backgroundColor = [UIColor clearColor];

    

    if (_maskView5 == nil) {

        _maskView5 = [[UIView alloc] initWithFrame:CGRectMake(0, self.maskView4.frame.origin.y+self.maskView4.frame.size.height, LMSCWID, LMSCHEI-(self.maskView4.frame.origin.y+self.maskView4.frame.size.height))];

        _maskView5.backgroundColor = [UIColor blackColor];

        _maskView5.userInteractionEnabled = YES;

        _maskView5.alpha = 0.5;

        [_maskView5 addSubview:btn];

        [_maskView5 addSubview:btn1];

        [_maskView5 addSubview:la];

        [_maskView5 addSubview:lb];

    }

    return _maskView5;

}


-(UIView *)maskView1 {

    

    UILabel *tip = [[UILabel alloc] initWithFrame:CGRectMake(LMSCWID/4, LMSCHEI/5-32, LMSCWID/2, 30)];

    tip.text = @"将条码/二维码放入框内";

    tip.font = [UIFont systemFontOfSize:14];

    CGFloat widths = [tip.text boundingRectWithSize:CGSizeMake(FLT_MAX, tip.frame.size.height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:tip.font} context:nil].size.width;

    

    UIImageView *im = [[UIImageView alloc] initWithFrame:CGRectMake(LMSCWID/4+5, tip.y, 30, 30)];

    im.backgroundColor = [UIColor clearColor];

    im.image = [UIImage imageNamed:@"homePage_ErWeiMa"];

    [tip setFrame:CGRectMake(LMSCWID/2-widths/2+15, LMSCHEI/5-32, widths, 30)];

//    im.right = tip.x;

    tip.backgroundColor = [UIColor clearColor];

    tip.textColor = [UIColor whiteColor];

    

    if (_maskView1 == nil) {

        _maskView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, LMSCWID, LMSCHEI/5)];

        _maskView1.backgroundColor = [UIColor blackColor];

        _maskView1.userInteractionEnabled = NO;

        _maskView1.alpha = 0.5;

        [_maskView1 addSubview:tip];

        [_maskView1 addSubview:im];

    }

    return _maskView1;

}

-(void)beginScanning {

    

    //获取摄像设备

    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    //创建输入流

    AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

    if (!input) return;

    //创建输出流

    AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];

    //设置代理 在主线程里刷新

    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    //设置有效扫描区域 (注意:这里的x,y是互换的,width,height是互换的),且其值等于相对于屏幕的比例,即为(0~1)之间

    CGRect scanCrop=[self getScanCrop:self.scanWindow.bounds readerViewBounds:self.view.frame];

    output.rectOfInterest = scanCrop;

    //初始化链接对象

    _session = [[AVCaptureSession alloc]init];

    //高质量采集率

    [_session setSessionPreset:AVCaptureSessionPresetHigh];

    

    [_session addInput:input];

    [_session addOutput:output];

    //设置扫码支持的编码格式(如下设置条形码和二维码兼容)

    output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];

    

    AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];

    layer.videoGravity=AVLayerVideoGravityResizeAspectFill;

    layer.frame=self.view.layer.bounds;

    [self.view.layer insertSublayer:layer atIndex:0];

    //开始捕获

    [_session startRunning];

}


-(CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)readerViewBounds{

    

    CGFloat x,y,width,height;

    

    x = (CGRectGetHeight(readerViewBounds)-CGRectGetHeight(rect))/2/CGRectGetHeight(readerViewBounds);

    y = (CGRectGetWidth(readerViewBounds)-CGRectGetWidth(rect))/2/CGRectGetWidth(readerViewBounds);

    width = CGRectGetHeight(rect)/CGRectGetHeight(readerViewBounds);

    height = CGRectGetWidth(rect)/CGRectGetWidth(readerViewBounds);

    

    return CGRectMake(x, y, width, height);

    

}


#pragma mark 恢复动画

- (void)resumeAnimation

{

    if (_timer == nil) {

        _timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scanTimerAction) userInfo:nil repeats:YES];

    }

    [self.timer setFireDate:[NSDate distantPast]];

    [self.timer fire];

    

}


-(void)scanTimerAction {

    

    if (self.redImageView.center.y <=  self.maskView1.bottom +2*LMSCWID/3) {

        [self.redImageView moveBy:CGPointMake(0, 3)];

    }else{

        

        self.redImageView.frame = CGRectMake(LMSCWID/6-1, self.scanWindow.y, 2*LMSCWID/3+2, 1);

    }

}


-(void)openFlash:(UIButton*)button{

    

    button.selected = !button.selected;

    if (button.selected) {

        [self turnTorchOn:YES];

        [button setImage:[UIImage imageNamed:@"homePage_TorchON"] forState:UIControlStateNormal];

    }

    else{

        [self turnTorchOn:NO];

        [button setImage:[UIImage imageNamed:@"homePage_TorchOFF"] forState:UIControlStateNormal];

    }

}


/** 打开闪光灯 */

- (void)turnTorchOn:(BOOL)on

{

    

    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");

    if (captureDeviceClass != nil) {

        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        if ([device hasTorch] && [device hasFlash]){

            

            [device lockForConfiguration:nil];

            if (on) {

                [device setTorchMode:AVCaptureTorchModeOn];

                [device setFlashMode:AVCaptureFlashModeOn];

                

            } else {

                [device setTorchMode:AVCaptureTorchModeOff];

                [device setFlashMode:AVCaptureFlashModeOff];

            }

            [device unlockForConfiguration];

        }

    }

}


-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{

    

    

    if (metadataObjects.count>0) {

        

        [self.session stopRunning];

        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0];

        NSString *scanResult = metadataObject.stringValue;

        

        if (!IsEmpty(scanResult)) {

            

            [SVProgressHUD showWithStatus:@"正在加载数据.."];

            WEAK_REF(self);

            [[HttpEngine sharedHttpEngine] qrCodeJionTeam:USER_VALUE partnerTeamID:scanResult success:^(MKNetworkOperation *completedOperation) {

                NSDictionary *dict = [completedOperation responseJSONRemoveNull];

                [SVProgressHUD showWithStatus:dict[@"msg"]];

                BHelperViewController *helper = [BHelperViewController new];

                helper.tid = scanResult;

                [weak_self.navigationController pushViewController:helper animated:YES];

                [SVProgressHUD dismissWithDelay:3.0];

                return ;

            } error:^(MKNetworkOperation *completedOperation, NSError *error) {

                [SVProgressHUD dismiss];

                [SVProgressHUD showErrorWithStatus:@"网络错误,请检查网络"];

            }];

            

            

        }

        

        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scanResult]]) {

            // 打开网页

            [self.session startRunning];

            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:scanResult] options:@{} completionHandler:^(BOOL success) {

                

                /*

                 ...

                 */

            }];

            

            // 其他

        }else {

            

             NSString *resultStr = [NSString stringWithFormat:@"扫描结果:%@",scanResult];

             [self.view addSubview:[ZLMNoticeLabel message:resultStr delaySecond:2]];

            

        }

    }

}


#pragma mark-> 我的相册

-(void)myAlbum:(UIButton *)button{

    

    button.selected = !button.selected;

    if (button.selected) {

        [button setImage:[UIImage imageNamed:@"homePage_PhotosON"] forState:UIControlStateNormal];

    }

    else{

        [button setImage:[UIImage imageNamed:@"homePage_PhotosOFF"] forState:UIControlStateNormal];

    }

    

    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){

        //1.初始化相册拾取器

        UIImagePickerController *controller = [[UIImagePickerController alloc] init];

        //2.设置代理

        controller.delegate = self;

        //3.设置资源:

        controller.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;

        //4.随便给他一个转场动画

        controller.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;

        [self presentViewController:controller animated:YES completion:nil];

    }else{

        

        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"设备不支持访问相册,请在设置->隐私->照片中进行设置!" preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction *ok = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];

        [alert addAction:ok];

        [self presentViewController:alert animated:YES completion:nil];

    }

}

#pragma mark-> imagePickerController delegate


//-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

//    [picker dismissViewControllerAnimated:NO completion:^{

//        [self.session startRunning];

//    }];

//}



/**

 相册照片扫描

 

 @param picker 相册

 @param info 字典

 */

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    

    [self.session stopRunning];

    //1.获取选择的图片

    UIImage *image = info[UIImagePickerControllerEditedImage];

    

    if (!image) {

        image = info[UIImagePickerControllerOriginalImage];

    }

    //2.初始化一个监测器

    CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];

    

    [picker dismissViewControllerAnimated:YES completion:^{

        

        //监测到的结果数组  放置识别完之后的数据

        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];

        //判断是否有数据(即是否是二维码)

        if (features.count >=1) {

            /**结果对象 */

            CIQRCodeFeature *feature = [features objectAtIndex:0];

            NSString *scannedResult = feature.messageString;

            

            

            [SVProgressHUD showWithStatus:@"正在加载数据.."];

            WEAK_REF(self);

            [[HttpEngine sharedHttpEngine] qrCodeJionTeam:USER_VALUE partnerTeamID:scannedResult success:^(MKNetworkOperation *completedOperation) {

                NSDictionary *dict = [completedOperation responseJSONRemoveNull];

                [SVProgressHUD showWithStatus:dict[@"msg"]];

                [picker dismissViewControllerAnimated:YES completion:nil];

                BHelperViewController *helper = [BHelperViewController new];

                helper.tid = scannedResult;

                [weak_self.navigationController pushViewController:helper animated:YES];

                [SVProgressHUD dismissWithDelay:3.0];

                return ;

            } error:^(MKNetworkOperation *completedOperation, NSError *error) {

                [SVProgressHUD dismiss];

                [SVProgressHUD showErrorWithStatus:@"网络错误,请检查网络"];

            }];

            

            if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scannedResult]]) {

                

                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:scannedResult] options:@{} completionHandler:nil];

            }else {

                if (scannedResult.length) {

                    NSString *resultStr = [NSString stringWithFormat:@"扫描结果:%@",scannedResult];

                    [self.view addSubview:[ZLMNoticeLabel message:resultStr delaySecond:2]];

                    

                }else {

                    [self.view addSubview:[ZLMNoticeLabel message:@"未检测到信息" delaySecond:2]];

                }

            }

            

        }

        else{

            

            [self.view addSubview:[ZLMNoticeLabel message:@"该图片没有包含二维码!" delaySecond:2]];

            

        }

    }];

    

}



@end






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值