项目中一直用的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