二维码生成

//MARK: 传进去字符串,生成二维码图片(>=iOS7)  text:要生成的二维码内容   WH:二维码高宽
private func creatQRCodeImage(text: String,WH:CGFloat) -> UIImage{ //创建滤镜
let filter = CIFilter(name: "CIQRCodeGenerator")
//还原滤镜的默认属性
filter?.setDefaults()
//设置需要生成二维码的数据
filter?.setValue(text.data(using: String.Encoding.utf8), forKey: "inputMessage")
//从滤镜中取出生成的图片
let ciImage = filter?.outputImage
//这个清晰度好
let bgImage = createNonInterpolatedUIImageFormCIImage(image: ciImage!, size: WH) return bgImage
}

上面生成的image,需要用到一个方法,原因是直接生产的图片二维码清晰度不够,需要处理一下

//MARK: - 根据CIImage生成指定大小的高清UIImage
private func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage { let extent: CGRect = image.extent.integral
let scale: CGFloat = min(size/extent.width, size/extent.height) let width = extent.width * scale
let height = extent.height * scale
let cs: CGColorSpace = CGColorSpaceCreateDeviceGray()
let bitmapRef = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: , bytesPerRow: , space: cs, bitmapInfo: )! let context = CIContext(options: nil)
let bitmapImage: CGImage = context.createCGImage(image, from: extent)! bitmapRef.interpolationQuality = CGInterpolationQuality.none
bitmapRef.scaleBy(x: scale, y: scale)
bitmapRef.draw(bitmapImage, in: extent)
let scaledImage: CGImage = bitmapRef.makeImage()!
return UIImage(cgImage: scaledImage)
}

这样,我们就能得到想要的二维码图片了

有时,我们需要在二维码中间添加log水印等,我试过两种方法,第一种是直接用图形上下文UIGraphicsBeginImageContext这种实现,不够实现起来有点模糊,后来就直接用最原始方式了:直接add图片上去(也可能是我第一种实现有问题,这里大家可以自己试一下先)

添加log:(一些参数可以自己调,这里做个示例)

//MARK: - 根据背景图片和头像合成头像二维码
private func creatIconImage(iconImage:UIImage,sizeWH:CGFloat,superImgView:UIImageView){ let iconImgView = UIImageView(image: iconImage)
iconImgView.contentMode = .scaleAspectFit
iconImgView.frame = CGRect(x: (superImgView.bounds.size.width-sizeWH)/, y: (superImgView.bounds.size.height-sizeWH)/, width: sizeWH, height: sizeWH)
iconImgView.layer.cornerRadius =
iconImgView.layer.borderColor = UIColor.white.cgColor
iconImgView.layer.borderWidth =
iconImgView.layer.masksToBounds = true
superImgView.addSubview(iconImgView) }

二维码扫描

使用AVCaptureDevice,基于系统的AVFoundation框架,所以使用前,先import

import UIKit
import AVFoundation

1、定义扫描的一些属性

    //扫描定义属性
var device:AVCaptureDevice! = nil
var input:AVCaptureDeviceInput! = nil
var output:AVCaptureMetadataOutput! = nil
var session:AVCaptureSession! = nil
var preview:AVCaptureVideoPreviewLayer! = nil

2、设置扫描

/// 设置扫描参数
func setupCamera() {
DispatchQueue.global().async {
if (self.device == nil){
self.device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do{
self.input = try AVCaptureDeviceInput.init(device: self.device)
}catch{
print("self.input init error")
} self.output = AVCaptureMetadataOutput.init()
self.output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) self.session = AVCaptureSession.init()
self.session.canSetSessionPreset(AVCaptureSessionPresetHigh)
if self.session.canAddInput(self.input){
self.session .addInput(self.input)
self.canOpen = true
}else{
DispatchQueue.main.async {
let alert = UIAlertView(title: "提示", message: "打开相机权限", delegate: self, cancelButtonTitle: "取消", otherButtonTitles: "设置")
alert.show()
}
} if self.canOpen{
if self.session.canAddOutput(self.output){
self.session.addOutput(self.output)
}
// 只支持二维码
self.output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] self.preview = AVCaptureVideoPreviewLayer(session: self.session)
self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill
DispatchQueue.main.async {
self.preview.frame = CGRect(x: , y: , width: KScreenWidth, height: KScreenHeight)
self.view.layer.insertSublayer(self.preview, at: )
} } }
if self.canOpen{
DispatchQueue.main.async {
//开启定时器,构造移动动画效果
self.timer = Timer(timeInterval: 0.02, target: self, selector: #selector(self.lineAnimation), userInfo: nil, repeats: true)
RunLoop.current.add(self.timer!, forMode: .defaultRunLoopMode)
//开始采集数据
self.session.startRunning()
}
}
} }

扫描后,会触发一个代理,这里我们可以获取到扫描内容

// MARK: - 扫描二维码后的代理
extension QRCodeScanViewController:AVCaptureMetadataOutputObjectsDelegate{
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
var strValue:String = ""
if metadataObjects.count>{
let obj:AVMetadataMachineReadableCodeObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject
strValue = obj.stringValue
} self.session.stopRunning()
self.timer?.invalidate()
self.timer = nil self.playBeep() self.showQRCode(qrcodeString: strValue)
} }

以上都是一些核心代码,当然,我们还需要对它进行一些UI自定义,比如扫描背景色,扫描提示说明,红线的动画移动等

这里我就不一一贴出来了,文章最后会有获取源码的链接地址。

其实到这里,我们都可以依靠系统提供的API实现二维码的生成和扫描功能,最低要求的系统为iOS7。

下面,如果是从相册获取呢?

二维码相册读取

ios从相册读取二维码,在ios8以上,苹果依然提供了自带的识别图片二维码的功能,这种方式效率最好,也是最推荐的,但在兼容ios7时,我们就必须用其他方式实现。

选择第三方框架:

ZXingObjC  OR  ZBar   ??

这里我选择的是 ZXingObjC,相比于ZBar,这个库一直有人在维护,而且易用性相比后者 也好一点(个人觉得哈,当然也有很多人选择的ZBar,其实都差不多)。

1、pod导入ZXingObjc

pod 'ZXingObjC', '~> 3.0'

代码实现记录如下:

注意:这里我之前测试的代码是用oc写的,还没来得及转成swift3,大家先看思路哈,勿怪~~

2、从相册选择好图片  

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"]; [self dismissViewControllerAnimated:YES completion:^{ [self getInfoWithImage:image];
}]; }

3、解析图片二维码-(void)getInfoWithImage:(UIImage *)image{

//8系统以上用系统提供的方法
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; if (features.count >= ){ for (int index = ; index < [features count]; index ++) {
CIQRCodeFeature *feature = [features objectAtIndex:index];
NSString *scannedResult = feature.messageString;
NSLog(@"result:%@",scannedResult);
//进行自己业务处理
}
}else{
NSLog(@"no image");
} }else{
NSLog(@"ios8 以下系统");
CGImageRef imageToDecode=[image CGImage]; ZXLuminanceSource * source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:imageToDecode];
ZXBinaryBitmap * bitmap = [ZXBinaryBitmap binaryBitmapWithBinarizer:[ZXHybridBinarizer binarizerWithSource:source]];
NSError *error = nil;
ZXDecodeHints *hints = [ZXDecodeHints hints];
ZXMultiFormatReader * reader = [ZXMultiFormatReader reader];
ZXResult *result = [reader decode:bitmap hints:hints error:&error]; if (result) {
NSString *contents = result.text;
NSLog(@"解析成功:%@",contents);
       //进行自己业务处理
     }else{
    NSLog(@" --- 解析失败");
     }
} }

系统 CIDetector识别二维码,我后面加了swift4版本写法,供参考

///  识别图片二维码,要求ios8系统及以上
///
/// - Parameter img: <#img description#>
func getQRCodeWithImage(img:UIImage) {
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
let features = detector?.features(in: CIImage(cgImage: img.cgImage!))
if features == nil || features!.count <= {
return
} for feature in features! {
if let qrcode = feature as? CIQRCodeFeature{
self.playBeep()
print(qrcode.messageString)
}
} }

最后,获取源码地址

点击这里获取源码

Enjoy~

iOS 读取相册二维码,兼容ios7(使用CIDetector 和 ZXingObjC)的更多相关文章

  1. iOS系统原生 二维码的生成、扫描和读取(高清、彩色)

    由于近期工作中遇到了个需求:需要将一些固定的字段 在多个移动端进行相互传输,所以就想到了 二维码 这个神奇的东东! 现在的大街上.连个摊煎饼的大妈 都有自己的二维码来让大家进行扫码支付.可见现在的二维 ...

  2. ios 中生成二维码和相册中识别二维码

    iOS 使用CIDetector扫描相册二维码.原生扫描 原生扫描 iOS7之后,AVFoundation让我们终于可以使用原生扫描进行扫码了(二维码与条码皆可)AVFoundation可以让我们从设 ...

  3. iOS中 扫描二维码/生成二维码详解 韩俊强的博客

    最近大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 指示根视图: se ...

  4. iOS中 扫描二维码/生成二维码具体解释 韩俊强的博客

    近期大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 指示根视图: se ...

  5. iOS开发-二维码

    二维码 从ios7开始集成了二维码的生成和读取功能 此前被广泛使用的zbarsdk目前不支持64位处理器 生成二维码的步骤: 倒入CoreImage框架 通过滤镜CIFilter生成二维码 二维码的内 ...

  6. 微信连WiFi关注公众号流程更新 解决ios微信扫描二维码不关注就能上网的问题

    前几天鼓捣了一下微信连WiFi功能,设置还蛮简单的,但ytkah发现如果是ios版微信扫描微信连WiFi生成的二维码不用关注公众号就可以直接上网了,而安卓版需要关注公众号才能上网,这样就少了很多ios ...

  7. iOS系统原生二维码条形码扫描

    本文讲述如何用系统自带的东东实现二维码扫描的功能:点击当前页面的某个按钮,创建扫描VIEW.细心的小伙伴可以发现 title被改变了,返回按钮被隐藏了.这个代码自己写就行了,与本文关系不大...绿色的 ...

  8. IOS原声二维码条形码扫描实现

    本文讲述如何用系统自带的东东实现二维码扫描的功能:点击当前页面的某个按钮,创建扫描VIEW.细心的小伙伴可以发现 title被改变了,返回按钮被隐藏了.这个代码自己写就行了,与本文关系不大...绿色的 ...

  9. C# vb .NET识别读取QR二维码

    二维码比条形码具有更多优势,有些场合使用二维码比较多,比如支付.那么如何在C#,.Net平台代码里读取二维码呢?答案是使用SharpBarcode! SharpBarcode是C#快速高效.准确的条形 ...

随机推荐

  1. 转:python signal信号

    转自:http://www.jb51.net/article/74844.htm 在liunx系统中要想每隔一分钟执行一个命令,最普遍的方法就是crontab了,如果不想使用crontab,经同事指点 ...

  2. 2016暑假多校联合---Counting Intersections

    原题链接 Problem Description Given some segments which are paralleled to the coordinate axis. You need t ...

  3. 设置placeholder字体颜色

    /*设置placeholder字体颜色*/::-webkit-input-placeholder{ color: #FFF;}:-ms-input-placeholder{ color: #FFF;} ...

  4. malloc和new的区别

    (1)malloc在C和C++中都可以使用,用来申请一段内存:申请的内存一定要用free释放,然后把指针置为null: new只能在C++中使用,用于动态内存分配:new的对象要delete掉: (2 ...

  5. Lua-面向对象中函数使用时冒号(:)和点(.)的区别

    先来看一段简单的代码: local Animal = {} function Animal:Eat( food ) print("Animal:Eat", self, food) ...

  6. java连接hbase报错

    报错信息如下: The node /hbase is not in ZooKeeper. It should have been written by the master. Check the va ...

  7. Android studio git 本地仓库和远程仓库节点对比

    1.初始状态 2.本地修改文件,然后commit 3.本地再次修改文件,然后commit 4.本地push 从上图可以看出,push完成后,本地仓库的节点和远程仓库的节点是一样的.

  8. SwipeBackActivity 的使用

    1.SwipeBackLayout 项目地址:https://github.com/ikew0ng/SwipeBackLayout 2.用法 android studio  compile 'me.i ...

  9. Android jni简便开发流程

    <Android jni helloworld>中介绍了开发jni helloworld的步骤,本文将介绍jni简便开发流程 ① 写java代码 native 声明本地方法 ② 添加本地支 ...

  10. 运算符&,|,^

    1.&按位“与”的计算是把两个数字分别写成二进制形式,然后按照每一位进行比较,&计算中,只要有一个是0就算成02.|运算转换成2进制进行比较,两个位只要有一个为1,那么结果就是1,否则 ...