#import "ViewController.h"
// 捕获摄像头数据需要该框架
#import <AVFoundation/AVFoundation.h>
@interface ViewController () <AVCaptureMetadataOutputObjectsDelegate>
@property (strong, nonatomic) AVCaptureSession *captureSession;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 扫描二维码: 摄像头(捕获设备) -> 捕获摄像头数据(输出) -> 捕获会话 -> 元数据解析(输出) -> 二维码结果
// 1. 获取摄像头 (捕获视频数据) (要获取授权, 不需要写申请代码)
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 2. 输入流 (将摄像头数据传递给会话)
// AVCaptureInput 输入法是基类, AVCaptureDeviceInput 专门处理设备的输入法
NSError *error;
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (error) {
NSLog(@"设备输入流创建失败");
return;
}
// 3. 捕获数据的会话 (协调输入与输出)
self.captureSession = [[AVCaptureSession alloc] init];
// 3.1 将输入流与Session进行绑定
if ([self.captureSession canAddInput:deviceInput]) {
[self.captureSession addInput:deviceInput];
}
/*================= 界面预览 =================*/
// AVCaptureVideoPreviewLayer 是 捕获视频的预览图层
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
// 让layer显示出来
[self.view.layer addSublayer:layer];
// 注意: 需要手动配置layer的frame值
layer.frame = self.view.bounds;
/*================= =================*/
// 4. 输出流 (解析数据 - 对元数据解析(Metadata))
// AVCaptureMetadataOutput 用来对捕获数据进行解析
AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init];
// 4.1 将输出流与Session进行绑定
if ([self.captureSession canAddOutput:metadataOutput]) {
[self.captureSession addOutput:metadataOutput];
}
// 4.2 配置解析的数据类型, 解析结果的回调
// delegate是回调代理对象 queue是代理回调时处理的队列
[metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 查看可用的数据类型
NSArray *types = metadataOutput.availableMetadataObjectTypes;
NSLog(@"%@", types);
// 设置解析的数据类型
// 二维码
// metadataOutput.metadataObjectTypes = @[@"org.iso.QRCode"];
// 条形码
metadataOutput.metadataObjectTypes = @[@"org.gs1.EAN-8", @"org.gs1.EAN-13", @"org.iso.Code128", @"com.intermec.Code93", @"org.iso.Code39"];
// 解析范围, (输出), 有效的扫描范围
CGFloat wh = 300; // 有效范围 300 * 300, 居中
// 参数值是 0.0 ~ 1.0, Rect:(y,x,height,width)
CGFloat width = wh / self.view.bounds.size.width;
CGFloat height = wh / self.view.bounds.size.height;
CGFloat x = (self.view.bounds.size.width - wh) * 0.5 / self.view.bounds.size.width;
CGFloat y = (self.view.bounds.size.height - wh) * 0.5 / self.view.bounds.size.height;
// Rect:(y,x,height,width)
metadataOutput.rectOfInterest = CGRectMake(y, x, height, width);
// 5. 启动会话, 开始工作
[self.captureSession startRunning];
[self addOtherLay:CGRectMake((self.view.bounds.size.width - wh) * 0.5, (self.view.bounds.size.height - wh) * 0.5, wh, wh)];
// // CAShapeLayer 绘制形状的图层, 灰色图层
// CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
//// shapeLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, 200);
// shapeLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.view.bounds.size.width, 200)].CGPath;
// shapeLayer.fillColor = [UIColor blackColor].CGColor;
// shapeLayer.opacity = 0.5;
// [self.view.layer addSublayer:shapeLayer];
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
// 解析到数据时触发 (解析到二维码), 只要会话运行并且扫描到数据, 就会一直触发
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects.lastObject;
NSString *result = metadataObject.stringValue;
NSLog(@"%@", result);
// 字符串, 对字符串处理
// http://121.42.205.189/index.php?cid=2063 http://开头
// Weixin:/dgiojaogjasd // weixin: 微信功能
// 停止会话
[self.captureSession stopRunning];
}
// 添加遮盖
- (void)addOtherLay:(CGRect)rect
{
// Rect为保留的矩形frame值
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat leftWidth = (screenWidth - rect.size.width) / 2;
CAShapeLayer* layerTop = [[CAShapeLayer alloc] init];
layerTop.fillColor = [UIColor blackColor].CGColor;
layerTop.opacity = 0.5;
layerTop.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, screenWidth, rect.origin.y)].CGPath;
[self.view.layer addSublayer:layerTop];
CAShapeLayer* layerLeft = [[CAShapeLayer alloc] init];
layerLeft.fillColor = [UIColor blackColor].CGColor;
layerLeft.opacity = 0.5;
layerLeft.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, rect.origin.y, leftWidth, rect.size.height)].CGPath;
[self.view.layer addSublayer:layerLeft];
CAShapeLayer* layerRight = [[CAShapeLayer alloc] init];
layerRight.fillColor = [UIColor blackColor].CGColor;
layerRight.opacity = 0.5;
layerRight.path = [UIBezierPath bezierPathWithRect:CGRectMake(screenWidth - leftWidth, rect.origin.y, rect.size.width, rect.size.height)].CGPath;
[self.view.layer addSublayer:layerRight];
CAShapeLayer* layerBottom = [[CAShapeLayer alloc] init];
layerBottom.fillColor = [UIColor blackColor].CGColor;
layerBottom.opacity = 0.5;
layerBottom.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, CGRectGetMaxY(rect), screenWidth, screenHeight - CGRectGetMaxY(rect))].CGPath;
[self.view.layer addSublayer:layerBottom];
}
@end
实用知识:实现扫描二维码和条形码功能
最新推荐文章于 2024-06-12 09:31:58 发布