Swift3.0生成二維碼、掃描二維碼、相冊讀取二維碼,兼容iOS7(結合ZXingObjC)

 

 

 

二維碼生成ios

 

//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,須要用到一個方法,緣由是直接生產的圖片二維碼清晰度不夠,須要處理一下git

//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: 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)
    }

 

 

這樣,咱們就能獲得想要的二維碼圖片了github

有時,咱們須要在二維碼中間添加log水印等,我試過兩種方法,第一種是直接用圖形上下文UIGraphicsBeginImageContext這種實現,不夠實現起來有點模糊,後來就直接用最原始方式了:直接add圖片上去(也多是我第一種實現有問題,這裏你們能夠本身試一下先)swift

添加log:(一些參數能夠本身調,這裏作個示例)session

 

//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, width: 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框架,因此使用前,先importasync

import UIKit
import AVFoundation

一、定義掃描的一些屬性ide

    //掃描定義屬性
    var device:AVCaptureDevice! = nil
    var input:AVCaptureDeviceInput! = nil
    var output:AVCaptureMetadataOutput! = nil
    var session:AVCaptureSession! = nil
    var preview:AVCaptureVideoPreviewLayer! = nil

二、設置掃描oop

/// 設置掃描參數
    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, width: 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,其實都差很少)。

 

一、pod導入ZXingObjc

pod 'ZXingObjC', '~> 3.0'

 

代碼實現記錄以下:

注意:這裏我以前測試的代碼是用oc寫的,還沒來得及轉成swift3,你們先看思路哈,勿怪~~

二、從相冊選擇好圖片  

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

 

三、解析圖片二維碼-(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~

相關文章
相關標籤/搜索