基于MacOSX平台下的二维码扫码功能

    最近项目接受了一个需求,要在macOS的系统上实现一个二维码扫码的功能.通过多方面的学习,最终实现了要求,具体的实现步骤将会在下面展示。

核心功能模块

    实现途径上,最开始我是打算采用iOS自带有的原生Api实现的,也是一般iOS通用的二维码识别方式,代码如下:
// 条码类型 AVMetadataObjectTypeQRCode
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
_output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
    但是非常遗憾的是,此api只支持iOS7.0+,对于OS系统是不支持的,那么就不能采用这个方法来识别二维码了。如果使用ZXing的话,存在相当多的问题,需要修改的内容也是非常多的。楼主能力与时间有限,所以没有走通,如果有好的方法大家可以互相交流下。而这里主要使用的解析模块是系统自带的一个模块CIDetector.利用AVCaptureSession截取某一时刻的图像,然后转换成CIImage,传输给CIDetector解析。

1、初始化session

    与iOS的扫码功能一样,需要创建一个AVCaptureSession的上下文处理器。  设备和输入设备都是别无二致的,但是采集信息的时候不能采用AVCaptureMetadataOutput(iOS独有的)。    这里采用的是AVCaptureStillImageOutput,用来获取某一帧的图像。具体代码如下:
/**设置上下文处理器和输入输出*/
- (void)setupCamera
{_session = [[AVCaptureSession alloc] init];[_session setSessionPreset:AVCaptureSessionPresetHigh];NSError *error = nil;_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];AVCaptureDeviceInput *myDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];[self.session addInput:myDeviceInput];_output = [[AVCaptureStillImageOutput alloc] init];NSDictionary *myOutputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];[_output setOutputSettings:myOutputSettings];[self.session addOutput:_output];}

2、设置加载图层

    这块的部分和iOS的功能和作用一样,无需多言。
/**设置视频加载图层@param layer 图层
@param bounds 范围*/
- (void)setAVCaptureVideoPreviewLayerWithSupLayer:(CALayer *)layerwithBounds:(NSRect)bounds
{if (preview!=nil){[preview removeFromSuperlayer];}preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];[preview setVideoGravity:AVLayerVideoGravityResizeAspectFill];[preview setBounds:bounds];[layer addSublayer:preview];
}

3、调用方法识别图片

    因为不是使用的AVCaptureMetadataOutput,所以获取图像的方法,可以是用一个计时器定时每秒去获取到当前的图像信息。   用一个计时器调用这个方法即可。
/**识别图片中的二维码@param fib 完成识别后返回的block*/
- (void)identifyImageQR:(FinishIdentifyBlock)fib
{AVCaptureConnection *myVideoConnection =[self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self output] connections]];//撷取影像(包含拍照音效)[_output captureStillImageAsynchronouslyFromConnection:myVideoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {//完成撷取时的处理程序(Block)if (imageDataSampleBuffer) {NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];//取得的静态影像NSImage *myImage = [[NSImage alloc] initWithData:imageData];NSString * qrString_ = [self stringFromCiImage:[self getCIImage:myImage]];if (![qrString_ isEqualToString:@""]) {fib(qrString_,nil);}else{fib(nil,@"");}}}];
}
/**根据媒体类型,总共得到的数据,筛选出自己需要的数据@param mediaType 媒体类型
@param connections 数组组
@return 需要的数据*/
- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections
{for ( AVCaptureConnection *connection in connections ) {for ( AVCaptureInputPort *port in [connection inputPorts] ) {if ( [[port mediaType] isEqual:mediaType] ) {return connection;}}}return nil;
}

5、NSImage转换成CIImage,并进行解析。

    截取到的图片获取到的是NSImage(类似于UIImage),这个图像是不能用于二维码识别的。  利用getCIImage方法可以将输入的NSImage转换成CIImage,然后进一步交给后续的方法解析。
/**NIImage转换成CIIMage图像@param myImage 输入的NSimage图线@return 返回CIImage图像*/
- (CIImage *)getCIImage:(NSImage *)myImage
{NSData  * tiffData = [myImage TIFFRepresentation];NSBitmapImageRep * bitmap;bitmap = [NSBitmapImageRep imageRepWithData:tiffData];// create CIImage from bitmapCIImage * ciImage = [[CIImage alloc] initWithBitmapImageRep:bitmap];// create affine transform to flip CIImageNSAffineTransform *affineTransform = [NSAffineTransform transform];[affineTransform translateXBy:0 yBy:128];[affineTransform scaleXBy:1 yBy:-1];// create CIFilter with embedded affine transformCIFilter *transform = [CIFilter filterWithName:@"CIAffineTransform"];[transform setValue:ciImage forKey:@"inputImage"];[transform setValue:affineTransform forKey:@"inputTransform"];// get the new CIImage, flipped and ready to serveCIImage * result = [transform valueForKey:@"outputImage"];// draw to view[result drawAtPoint: NSMakePoint ( 0,0 )fromRect: NSMakeRect  ( 0,0,128,128 )operation: NSCompositingOperationSourceOverfraction: 1.0];// cleanupreturn ciImage;
}/**根据CIImage图像来进行二维码解析工作@param ciimage 输入的CIImage图像@return 返回解析的字符串*/
- (NSString *)stringFromCiImage:(CIImage *)ciimage {NSString *content = @"" ;if (!ciimage) {return content;}CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCodecontext:[CIContext contextWithOptions:nil]options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];NSArray *features = [detector featuresInImage:ciimage];if (features.count) {for (CIFeature *feature in features) {if ([feature isKindOfClass:[CIQRCodeFeature class]]) {content = ((CIQRCodeFeature *)feature).messageString;break;}}} else {NSLog(@"未正常解析二维码图片, 请确保iphone5/5c以上的设备");}return content;
}

扫码功能单例化头实现

    以上的方法全是自定的对象方法,可以用于写成一个单例类进行使用,头文件内容如下:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
typedef void(^FinishIdentifyBlock)(NSString * qrString,NSString * error);
@interface MacQRScanSDK : NSObject@property (strong,nonatomic)AVCaptureDevice * device;
@property (strong,nonatomic)AVCaptureDeviceInput * input;@property (strong,nonatomic)AVCaptureStillImageOutput * output;@property (strong,nonatomic)AVCaptureSession * session;
@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;/**创建MacQRScanSDK的单利对象@return 返回MacQRScanSDK对象*/
+ (MacQRScanSDK *)sharedManager;/**设置上下文处理器和输入输出*/
- (void)setupCamera;/**设置视频加载的图层@param layer 图层*//**设置视频加载图层@param layer 图层
@param bounds 范围*/
- (void)setAVCaptureVideoPreviewLayerWithSupLayer:(CALayer*)layerwithBounds:(NSRect)bounds;/**开始扫描*/
- (void)beginScan;/**结束扫描*/
- (void)stopScan;/**识别图片中的二维码@param fib 完成识别后返回的block*/
- (void)identifyImageQR:(FinishIdentifyBlock)fib;
@end

在ViewController中的调用

在viewDidLoad中实现初始化,并且设置对应的代码
- (void)viewDidLoad {[super viewDidLoad];//初始化单例类mac_qr_scan_ = [MacQRScanSDK sharedManager];//初始化相机[mac_qr_scan_ setupCamera];//设置AVCaptureVideoPreviewLayer[mac_qr_scan_ setAVCaptureVideoPreviewLayerWithSupLayer:self.centView_.layer withBounds:NSMakeRect(0, 0, window_width*2 , window_height*2 )];
}
    上面的setAVCaptureVideoPreviewLayerWithSupLayer,在Mac软件中会因为拖拽界面导致window重新设置。那么这个layer也是需要实时获取到window的宽和高来修改范围。具体的方法可以参考使用windowDidResize。windowDidResize会在屏幕改变的时候调用,是系统的一个通知,具体的使用方法可以自己查看一下api或者谷歌百度。
- (void)windowDidResize:(NSNotification *)aNotification
{window_width=self.window.frame.size.width;window_height=self.window.frame.size.height;
}
    因为使用AVCaptureStillImageOutput,它的作用是可以截取某一时刻摄像头捕捉的某一帧的图像。那么对于二维码来说,我们可以采用一个计时器,然后定时去调用下面的方法,获取图像并解析。
[mac_qr_scan_ identifyImageQR:^(NSString *qrString, NSString *error) {if (error==nil) {// 没有error,可以对qr进行操作}else{//有error,说明有问题,需要追踪}
}];
   通过这些方法,基本可以实现摄像头采集二维码并解析的功能。对于二维码采集,前置摄像头识别率情况堪忧,尽量保证在光线充足,且不要反光的情况下扫描,不然容易失败。

基于MacOSX平台下的二维码扫码功能相关推荐

  1. iOS原生二维码扫码实现(含蒙版和扫码动画)

    #一.iOS实现原生扫码的意义 二维码扫码功能对于现在的iOS App开发来说是非常重要的. 通常为了节省开发时间,很多开发者会采用ZXing和ZBar等第三方SDK进行开发. 这样的好处是快速便捷, ...

  2. 微信公众平台----带参数二维码生成和扫描事件

    原文:微信公众平台----带参数二维码生成和扫描事件 摘要: 账号管理----生成带参数的二维码 消息管理----接收消息----接收事件推送 为了满足用户渠道推广分析和用户帐号绑定等场景的需要,公众 ...

  3. 基于jquery类库的绘制二维码的插件jquery.qrcode.js

     jquery.qrcode.min.js 如下 (function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.d ...

  4. 【A_star二维路径规划】基于matlab A_star算法无人机二维路径规划(起终点障碍物可设置)【含Matlab源码 1321期】

    ⛄一.获取代码方式 获取代码方式1: 通过订阅紫极神光博客付费专栏,凭支付凭证,私信博主,可获得此代码. 获取代码方式2: 完整代码已上传我的资源:[A_star二维路径规划]基于matlab A_s ...

  5. java实现微信支付宝等多个支付平台合一的二维码支付(SSM框架)

    点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐] ♪ 点击上方绿标 收听java实现微信支付宝等多个支付平台合一的二维码支付(SSM框架) 整体思路: 实现微信支付宝等支付平台合多为一的二 ...

  6. 基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能

    NextQRCode ZXing开源库的精简版 **基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能 原文博客 附源码下载地址** 与原ZXingMini项目对比 N ...

  7. 基于机器视觉的Data Matrix二维码识别

    基于机器视觉的Data Matrix二维码识别 二维码识别,这个在视觉应用中占有很重要的比例,各种各样的二维码都有可能需要识别.常见的QR码.Data Matrix码.本方案是识别Data Matri ...

  8. 开放平台–扫描微信二维码登录

    准备 如不了解第三方登录流程,建议先大概了解一下,在来看看代码. 说明: 由于开放平台无测试号测试,所以只能上开放平台进行配置信息.公众平台的测试号并不能给开放平台使用. 微信开放平台地址:https ...

  9. 基于zxing的仿微信二维码扫描界面

    基于zxing的仿微信二维码扫描界面 https://github.com/iamlocky/ZxingLite 本项目fork自yangxixi88/ZxingLite,在原项目基础上添加了本地图片 ...

最新文章

  1. 如何完全卸载 mysql 数据库
  2. 蚂蚁金服核心技术:百亿特征实时推荐算法揭秘
  3. 如何测试网络视频服务器(DVS)
  4. Developer Tools
  5. linux 定时器_定时器: Nodejs 中的 timers
  6. 关于异地高考引发的又一次舆论攻势
  7. 数组的fill方法_数组fill()方法以及JavaScript中的示例
  8. 阿里如何面试MySQL优化CPU消耗
  9. antd checkbox 默认选中_antd + select 默认选中问题?
  10. 微信公众号Web页面CSS文件里面的样式不加载
  11. struts2、ajax实现前后端交互
  12. Android入门学习2
  13. 实践torch.fx第一篇——基于Pytorch的模型优化量化神器
  14. IDEA创建类注释模板和方法注释模板
  15. 异常解决:Generated keys not requested. You need to specify Statement.RETURN_GENERA_KEYS to Statement.
  16. linux 检查zip是否损坏,用-v参数 unzip -v test.zip 检查zip文件是否损坏代常亮
  17. 南华大学计算机考研真题,2021南华大学考研历年真题复习资料
  18. POI 导出Excel
  19. 分布式系统论文精读2:GFS
  20. python 整行_python dataframe 输出结果整行显示的方法

热门文章

  1. QQ 聊天机器人小薇 2.1.0 发布!
  2. 【媒体工具】音视频信息常用解析工具
  3. 强人为自己,更强的人为大家
  4. loadrunner常见报错解决
  5. 什么是https(加密)协议,彻底搞懂https
  6. 迎合5G浪潮刷脸支付技术落地
  7. 【深入理解JVM】JVM5
  8. 作品版权登记需要的资料
  9. 简单的脚本在linux下将坚果云下同步的文件转移到zotero
  10. 在线使用Python通过染色体id+位置查询基因名列表