• Swift3.0生成二维码、扫描二维码、相册读取二维码,兼容iOS7(结合ZXingObjC)


     

    二维码生成

     

    //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,  Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: 0)!
            
            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)/2, y: (superImgView.bounds.size.height-sizeWH)/2,  sizeWH, height: sizeWH)
            iconImgView.layer.cornerRadius = 5
            iconImgView.layer.borderColor = UIColor.white.cgColor
            iconImgView.layer.borderWidth = 4
            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: 0, y: 0,  KScreenWidth, height: KScreenHeight)
                            self.view.layer.insertSublayer(self.preview, at: 0)
                        }
                        
                    }
                    
                }
                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>0{
                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 >= 1){
                
                for (int index = 0; 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 <= 0{
                return
            }
            
            for feature in features! {
                if let qrcode = feature as? CIQRCodeFeature{
                    self.playBeep()
                    print(qrcode.messageString)
                }
            }
            
        }

    最后,获取源码地址

    点击这里获取源码

    Enjoy~

  • 相关阅读:
    从goauth2的一个bug说起
    Vagrant与skynet框架
    离开博客园了
    (转) Android开发性能优化简介
    ListFragment源码 (待分析)
    Activity来了
    Android下的屏幕适配
    恶心的content
    Android下的xml资源详解
    各个页面样子的实现与演示
  • 原文地址:https://www.cnblogs.com/yajunLi/p/5942361.html
Copyright © 2020-2023  润新知