iOS 二维码扫描以及二维码生成

tech2023-08-11  108

二维码扫描

在开发过程中,我们经常会遇到二维码扫描功能,下面是iOS原生扫描二维码的实现

类名:ScanViewController

.h 文件

#import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface ScanViewController : UIViewController<AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate> @property (strong, nonatomic) AVCaptureDevice * device; //捕获设备,默认后置摄像头 @property (strong, nonatomic) AVCaptureDeviceInput * input; //输入设备 @property (strong, nonatomic) AVCaptureMetadataOutput * output;//输出设备,需要指定他的输出类型及扫描范围 @property (strong, nonatomic) AVCaptureSession * session; //AVFoundation框架捕获类的中心枢纽,协调输入输出设备以获得数据 @property (strong, nonatomic) AVCaptureVideoPreviewLayer * preview;//展示捕获图像的图层,是CALayer的子类 @property (strong, nonatomic) UIPinchGestureRecognizer *pinchGes;//缩放手势 //扫描框 @property (nonatomic,strong)UIImageView *imageView; //扫描线 @property (nonatomic,retain)UIImageView *line; @end

.m

#import "ScanViewController.h" #import "CommunityHostUserMessageVC.h" #define Height [UIScreen mainScreen].bounds.size.height #define Width [UIScreen mainScreen].bounds.size.width #define XCenter self.view.center.x #define YCenter self.view.center.y #define SHeight 20 #define SWidth (XCenter+30) @interface ScanViewController () { NSTimer *_timer; int num; BOOL upOrDown; } @property (weak, nonatomic) IBOutlet NSLayoutConstraint *height; @end @implementation ScanViewController #pragma mark ===========懒加载=========== //device - (AVCaptureDevice *)device { if (_device == nil) { //AVMediaTypeVideo是打开相机 //AVMediaTypeAudio是打开麦克风 _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; } return _device; } //input - (AVCaptureDeviceInput *)input { if (_input == nil) { _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; } return _input; } //output --- output如果不打开就无法输出扫描得到的信息 // 设置输出对象解析数据时感兴趣的范围 // 默认值是 CGRect(x: 0, y: 0, width: 1, height: 1) // 通过对这个值的观察, 我们发现传入的是比例 // 注意: 参照是以横屏的左上角作为, 而不是以竖屏 // out.rectOfInterest = CGRect(x: 0, y: 0, width: 0.5, height: 0.5) - (AVCaptureMetadataOutput *)output { if (_output == nil) { _output = [[AVCaptureMetadataOutput alloc]init]; [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; //限制扫描区域(上下左右) [_output setRectOfInterest:[self rectOfInterestByScanViewRect:_imageView.frame]]; } return _output; } - (CGRect)rectOfInterestByScanViewRect:(CGRect)rect { CGFloat width = CGRectGetWidth(self.view.frame); CGFloat height = CGRectGetHeight(self.view.frame); CGFloat x = (height - CGRectGetHeight(rect)) / 2 / height; CGFloat y = (width - CGRectGetWidth(rect)) / 2 / width; CGFloat w = CGRectGetHeight(rect) / height; CGFloat h = CGRectGetWidth(rect) / width; return CGRectMake(x, y, w, h); } //session - (AVCaptureSession *)session { if (_session == nil) { //session _session = [[AVCaptureSession alloc]init]; [_session setSessionPreset:AVCaptureSessionPresetHigh]; if ([_session canAddInput:self.input]) { [_session addInput:self.input]; } if ([_session canAddOutput:self.output]) { [_session addOutput:self.output]; } } return _session; } //preview - (AVCaptureVideoPreviewLayer *)preview { if (_preview == nil) { _preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; } return _preview; } - (void)viewWillDisappear:(BOOL)animated{ [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; } #pragma mark ==========ViewDidLoad========== - (void)viewDidLoad{ [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault]; //1 判断是否存在相机 if (self.device == nil) { [self showAlertViewWithMessage:@"未检测到相机"]; return; } self.view.backgroundColor = [UIColor whiteColor]; //打开定时器,开始扫描 [self addTimer]; //界面初始化 [self interfaceSetup]; //初始化扫描 [self scanSetup]; } #pragma mark ==========初始化工作在这里========== - (void)viewDidDisappear:(BOOL)animated { //视图退出,关闭扫描 [self.session stopRunning]; //关闭定时器 [_timer setFireDate:[NSDate distantFuture]]; } //界面初始化 - (void)interfaceSetup { //1 添加扫描框 [self addImageView]; //添加模糊效果 // [self setOverView]; //添加开始扫描按钮 // [self addStartButton]; } //添加扫描框 - (void)addImageView { _imageView = [[UIImageView alloc]initWithFrame:CGRectMake((Width-SWidth)/2, (Height-SWidth)/2, SWidth, SWidth)]; //显示扫描框 _imageView.image = [UIImage imageNamed:@"scanscanBg.png"]; [self.view addSubview:_imageView]; _line = [[UIImageView alloc]initWithFrame:CGRectMake(CGRectGetMinX(_imageView.frame)+5, CGRectGetMinY(_imageView.frame)+5, CGRectGetWidth(_imageView.frame), 3)]; _line.image = [UIImage imageNamed:@"scanLine"]; [self.view addSubview:_line]; UILabel * lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)]; [lable setText:@"将二维码放入框内,自动识别"]; lable.textAlignment = NSTextAlignmentCenter; lable.textColor = [UIColor whiteColor]; lable.font = [UIFont systemFontOfSize:14]; lable.center = CGPointMake(_imageView.center.x , _imageView.center.y+ SWidth/2 + 30); [self.view addSubview:lable]; } //初始化扫描配置 - (void)scanSetup { _height.constant = SafeAreaTopHeight; //2 添加预览图层 self.preview.frame = CGRectMake(0, SafeAreaTopHeight, SCREEN_WIDTH, SCREEN_HEIGHT - SafeAreaTopHeight); self.preview.videoGravity = AVLayerVideoGravityResize; [self.view.layer insertSublayer:self.preview atIndex:0]; //3 设置输出能够解析的数据类型 //注意:设置数据类型一定要在输出对象添加到回话之后才能设置 [self.output setMetadataObjectTypes:@[AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeQRCode]]; //高质量采集率 [self.session setSessionPreset:AVCaptureSessionPresetHigh]; //4 开始扫描 [self.session startRunning]; } //提示框alert - (void)showAlertViewWithMessage:(NSString *)message{ //弹出提示框后,关闭扫描 [self.session stopRunning]; //弹出alert,关闭定时器 [_timer setFireDate:[NSDate distantFuture]]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"扫描结果" message:[NSString stringWithFormat:@"%@",message] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { //点击alert,开始扫描 [self.session startRunning]; //开启定时器 [_timer setFireDate:[NSDate distantPast]]; }]]; [self presentViewController:alert animated:true completion:^{ }]; } //打开系统相册 - (IBAction)chooseButtonClick:(UIButton*)button{ if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { //关闭扫描 [self stopScan]; //1 弹出系统相册 UIImagePickerController *pickVC = [[UIImagePickerController alloc]init]; //2 设置照片来源 /** UIImagePickerControllerSourceTypePhotoLibrary,相册 UIImagePickerControllerSourceTypeCamera,相机 UIImagePickerControllerSourceTypeSavedPhotosAlbum,照片库 */ pickVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; //3 设置代理 pickVC.navigationBar.translucent = NO; //去除毛玻璃效果 pickVC.delegate = self; //4.随便给他一个转场动画 self.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal; [self presentViewController:pickVC animated:YES completion:nil]; } else { [self showAlertViewWithTitle:@"打开失败" withMessage:@"相册打开失败。设备不支持访问相册,请在设置->隐私->照片中进行设置!"]; } } //从相册中选取照片&读取相册二维码信息 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{ //1 获取选择的图片 UIImage *image = info[UIImagePickerControllerOriginalImage]; //初始化一个监听器 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; #pragma mark 扫描结果 } else { [self showAlertViewWithTitle:NSLocalizedString(@"alert_title", @"提示") withMessage:NSLocalizedString(@"QRcode_reading_failed", @"二维码读取失败")]; } }]; } - (IBAction)backAction:(id)sender { [self.navigationController popViewControllerAnimated:YES]; } #pragma mark ===========重启扫描&闪光灯=========== //添加开始扫描按钮 - (void)addStartButton{ UIButton *startButton = [UIButton buttonWithType:UIButtonTypeCustom]; startButton.frame = CGRectMake(60, 420, 80, 40); startButton.backgroundColor = [UIColor orangeColor]; [startButton addTarget:self action:@selector(startButtonClick) forControlEvents:UIControlEventTouchUpInside]; [startButton setTitle:@"扫描" forState:UIControlStateNormal]; [self.view addSubview:startButton]; } - (void)startButtonClick{ //清除imageView上的图片 self.imageView.image = [UIImage imageNamed:@""]; //开始扫描 [self starScan]; } - (void)systemLightSwitch:(BOOL)open{ AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if ([device hasTorch]) { [device lockForConfiguration:nil]; if (open) { [device setTorchMode:AVCaptureTorchModeOn]; } else { [device setTorchMode:AVCaptureTorchModeOff]; } [device unlockForConfiguration]; } } #pragma mark ===========添加提示框=========== //提示框alert - (void)showAlertViewWithTitle:(NSString *)aTitle withMessage:(NSString *)aMessage{ //弹出提示框后,关闭扫描 [self.session stopRunning]; //弹出alert,关闭定时器 [_timer setFireDate:[NSDate distantFuture]]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:aTitle message:[NSString stringWithFormat:@"%@",aMessage] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Sure", @"确定") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { //点击alert,开始扫描 [self.session startRunning]; //开启定时器 [_timer setFireDate:[NSDate distantPast]]; }]]; [self presentViewController:alert animated:true completion:^{}]; } #pragma mark ===========扫描的代理方法=========== //得到扫描结果 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{ if ([metadataObjects count] > 0) { AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0]; if ([metadataObject isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) { NSString *stringValue = [metadataObject stringValue]; if (stringValue != nil) { [self.session stopRunning]; #pragma mark 扫描结果 } } } } #pragma mark ============添加模糊效果============ - (void)setOverView { CGFloat width = CGRectGetWidth(self.view.frame); CGFloat height = CGRectGetHeight(self.view.frame); CGFloat x = CGRectGetMinX(_imageView.frame); CGFloat y = CGRectGetMinY(_imageView.frame); CGFloat w = CGRectGetWidth(_imageView.frame); CGFloat h = CGRectGetHeight(_imageView.frame); [self creatView:CGRectMake(0, 0, width, y)]; [self creatView:CGRectMake(0, y, x, h)]; [self creatView:CGRectMake(0, y + h, width, height - y - h)]; [self creatView:CGRectMake(x + w, y, width - x - w, h)]; } - (void)creatView:(CGRect)rect { CGFloat alpha = 0.5; UIColor *backColor = [UIColor blackColor]; UIView *view = [[UIView alloc] initWithFrame:rect]; view.backgroundColor = backColor; view.alpha = alpha; [self.view addSubview:view]; } #pragma mark ============添加扫描效果============ - (void)addTimer { _timer = [NSTimer scheduledTimerWithTimeInterval:0.008 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES]; } //控制扫描线上下滚动 - (void)timerMethod { if (upOrDown == NO) { num ++; _line.frame = CGRectMake(CGRectGetMinX(_imageView.frame)+5, CGRectGetMinY(_imageView.frame)+5+num, CGRectGetWidth(_imageView.frame)-10, 3); if (num == (int)(CGRectGetHeight(_imageView.frame)-10)) { upOrDown = YES; } } else { num --; _line.frame = CGRectMake(CGRectGetMinX(_imageView.frame)+5, CGRectGetMinY(_imageView.frame)+5+num, CGRectGetWidth(_imageView.frame)-10, 3); if (num == 0) { upOrDown = NO; } } } //暂定扫描 - (void)stopScan { //弹出提示框后,关闭扫描 [self.session stopRunning]; //弹出alert,关闭定时器 [_timer setFireDate:[NSDate distantFuture]]; //隐藏扫描线 _line.hidden = YES; } - (void)starScan { //开始扫描 [self.session startRunning]; //打开定时器 [_timer setFireDate:[NSDate distantPast]]; //显示扫描线 _line.hidden = NO; } @end

二维码生成

#pragma mark - 生成二维码 /** 生产二维码 @param memberId 生成二维码要用的字符串 */ - (void)setUpDisPlayUserQRCodeWithID:(NSString*)memberId{ NSData *stringData = [memberId dataUsingEncoding:NSUTF8StringEncoding]; // 创建filter CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // 设置内容和纠错级别 [qrFilter setValue:stringData forKey:@"inputMessage"]; [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"]; // CIImage CIImage *qrCIImage = qrFilter.outputImage; CGRect extent = CGRectIntegral(qrCIImage.extent); CGFloat scale = 200; // 创建bitmap; size_t width = CGRectGetWidth(extent) * scale; size_t height = CGRectGetHeight(extent) * scale; CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); CIContext *context = [CIContext contextWithOptions:nil]; CGImageRef bitmapImage = [context createCGImage:qrCIImage fromRect:extent]; CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); CGContextScaleCTM(bitmapRef, scale, scale); CGContextDrawImage(bitmapRef, extent, bitmapImage); // 保存bitmap到图片 CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); CGContextRelease(bitmapRef); CGImageRelease(bitmapImage); _QRCodeImageView.image = [UIImage imageWithCGImage:scaledImage]; }

以上便是二维码的扫描和生成

最新回复(0)