二維碼生成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~