【问题标题】:QR Code reader & generator in SwiftSwift 中的二维码阅读器和生成器
【发布时间】:2014-09-24 02:17:50
【问题描述】:

目前在 Objective-C 中,我使用 Zbar(http://zbar.sourceforge.net/) 来生成和读取 QR 码。现在,我只想继续 Swift 开发,是否有任何关于在 Swift 中生成和读取 QR 码的“方法”或库?

【问题讨论】:

标签: swift


【解决方案1】:

这是我为快速生成二维码而编写的代码。

//MARK:- generate QR code
func generateQRImage(stringQR:NSString, withSizeRate rate:CGFloat) -> UIImage
{
    var filter:CIFilter = CIFilter(name:"CIQRCodeGenerator")
    filter.setDefaults()

    var data:NSData = stringQR.dataUsingEncoding(NSUTF8StringEncoding)!
    filter.setValue(data, forKey: "inputMessage")

    var outputImg:CIImage = filter.outputImage

    var context:CIContext = CIContext(options: nil)
    var cgimg:CGImageRef = context.createCGImage(outputImg, fromRect: outputImg.extent())

    var img:UIImage = UIImage(CGImage: cgimg, scale: 1.0, orientation: UIImageOrientation.Up)!

    var width  = img.size.width * rate
    var height = img.size.height * rate

    UIGraphicsBeginImageContext(CGSizeMake(width, height))
    var cgContxt:CGContextRef = UIGraphicsGetCurrentContext()
    CGContextSetInterpolationQuality(cgContxt, kCGInterpolationNone)
    img.drawInRect(CGRectMake(0, 0, width, height))
    img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img
}

【讨论】:

    【解决方案2】:

    从 iOS 7 开始,iOS 设备可以读取二维码。但是,没有生成 QR 码的内置方法。这是一个又快又脏的二维码阅读器。

    首先,import AVFoundation 并添加 AVCaptureMetadataOutputObjectsDelegate

    接下来,设置捕获会话:

    func captureQRCode() {
        let session = AVCaptureSession()
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    
        let input = AVCaptureDeviceInput.deviceInputWithDevice(device, error: nil) as AVCaptureDeviceInput
        session.addInput(input)
    
        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
    
        let previewLayer = AVCaptureVideoPreviewLayer(session: session)
        let bounds = self.view.layer.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        previewLayer.bounds = bounds
        previewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
    
        self.view.layer.addSublayer(previewLayer)
        session.startRunning()
    }
    

    最后,处理委托

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        for item in metadataObjects {
            if let metadataObject = item as? AVMetadataMachineReadableCodeObject {
                if metadataObject.type == AVMetadataObjectTypeQRCode {
                    println("QR Code: \(metadataObject.stringValue)")
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      这个 GitHub 项目提供了一些关于如何生成二维码的代码:

      https://github.com/aschuch/QRCode

      // NSData
      let data = "http://schuch.me".dataUsingEncoding(NSISOLatin1StringEncoding)
      let qrCode = QRCode(data)
      qrCode.image
      

      至于阅读,这里还有一个不错的GitHub项目:

      https://github.com/yannickl/QRCodeReader.swift

      // Good practice: create the reader lazily to avoid cpu overload during the
      // initialization and each time we need to scan a QRCode
      lazy var reader = QRCodeReaderViewController(metadataObjectTypes: [AVMetadataObjectTypeQRCode])
      
      @IBAction func scanAction(sender: AnyObject) {
        // Retrieve the QRCode content
        // By using the delegate pattern
        reader.delegate = self
      
        // Or by using the closure pattern
        reader.completionBlock = { (result: String?) in
          println(result)
        }
      
        // Presents the reader as modal form sheet
        reader.modalPresentationStyle = .FormSheet
        presentViewController(reader, animated: true, completion: nil)
      }
      
      // MARK: - QRCodeReader Delegate Methods
      
      func reader(reader: QRCodeReader, didScanResult result: String) {
        self.dismissViewControllerAnimated(true, completion: nil)
      }
      
      func readerDidCancel(reader: QRCodeReader) {
        self.dismissViewControllerAnimated(true, completion: nil)
      }
      

      我建议您查看这两个项目并结合代码来实现您想要的行为。

      【讨论】:

        【解决方案4】:

        这是我编写的用于在 Objective-C 中生成二维码的代码:

        #pragma mark - qrimage
        
        -(UIImage *)generateQRimg:(NSString *)a withsize:(CGFloat)b
        {
        
            CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        
            [filter setDefaults];
        
            NSData *data = [a dataUsingEncoding:NSUTF8StringEncoding];
            [filter setValue:data forKey:@"inputMessage"];
        
            CIImage *outputImage = [filter outputImage];
        
            CIContext *context = [CIContext contextWithOptions:nil];
            CGImageRef cgImage = [context createCGImage:outputImage
                                               fromRect:[outputImage extent]];
        
            UIImage *image = [UIImage imageWithCGImage:cgImage
                                                 scale:1.
                                           orientation:UIImageOrientationUp];
        
            // Resize without interpolating
            UIImage *resized = [self resizeImage:image
                                     withQuality:kCGInterpolationNone
                                            rate:b];
        
            CGImageRelease(cgImage);
            return resized;
        }
        
        
        - (UIImage *)resizeImage:(UIImage *)image withQuality  (CGInterpolationQuality)quality rate:(CGFloat)rate
        
        {
        
            UIImage *resized = nil;
            CGFloat width = image.size.width * rate;
            CGFloat height = image.size.height * rate;
        
            UIGraphicsBeginImageContext(CGSizeMake(width, height));
            CGContextRef context = UIGraphicsGetCurrentContext();
            CGContextSetInterpolationQuality(context, quality);
            [image drawInRect:CGRectMake(0, 0, width, height)];
            resized = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            return resized;
        }
        

        【讨论】:

        • @tesmojones 检查下面的评论是我为快速生成二维码而编写的代码。
        【解决方案5】:

        Swift 中的二维码生成器:

        viewDidLoad

        var qrcodeImage: CIImage!    
        @IBOutlet var qrtext: UITextField!
        @IBOutlet var imgQRCode: UIImageView!
        @IBAction func displayQRcode(sender: AnyObject) {
          if qrcodeImage == nil {
            if qrtext.text == "" {
              return
            }
        
            let data = qrtext.text!.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
        
            let filter = CIFilter(name: "CIQRCodeGenerator")
            filter!.setValue(data, forKey: "inputMessage")
            filter!.setValue("Q", forKey: "inputCorrectionLevel")
            qrcodeImage = filter!.outputImage
            qrtext.resignFirstResponder()
            displayQRCodeImage()
          }
          else {
            self.imgQRCode.image = nil
            self.qrcodeImage = nil
          }
        }
        
        func displayQRCodeImage() {
          let scaleX = imgQRCode.frame.size.width / qrcodeImage.extent.size.width
          let scaleY = imgQRCode.frame.size.height / qrcodeImage.extent.size.height
          let transformedImage = qrcodeImage.imageByApplyingTransform(CGAffineTransformMakeScale(scaleX, scaleY))
          imgQRCode.image = UIImage(CIImage: transformedImage)
        }
        

        对于二维码阅读器

        请查看本教程 http://www.appcoda.com/qr-code-reader-swift/

        【讨论】:

          【解决方案6】:

          SWIFT 3: 二维码阅读器

          第一步: 只需在 info.plist 中添加一行,然后在新创建的行中输入 Privacy - CameraUsageDescription 并添加一个字符串表示用于告知用户为什么需要在您的应用中访问相机。

          第二步:在您的 ViewController 类中使用此代码

          class QrCodeScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
          
          var calssName:String = "QrCodeScannerViewController"
          
          var captureSession:AVCaptureSession?
          var videoPreviewLayer:AVCaptureVideoPreviewLayer?
          var qrCodeFrameView:UIView?
          
          @IBOutlet weak var messageLabel: UILabel!
          
          override func viewDidLoad() {
              super.viewDidLoad()
          
              captureQRCode()
          
          }
          
          
          /* Open camera to capture QR CODE */
          func captureQRCode() {
              captureSession = AVCaptureSession()
              let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
          
              let input = try! AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput
              captureSession?.addInput(input)
          
              let output = AVCaptureMetadataOutput()
              output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
              captureSession?.addOutput(output)
              output.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
          
              videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
              let bounds = self.view.layer.bounds
              videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
              videoPreviewLayer?.bounds = bounds
              videoPreviewLayer?.position = CGPoint(x:bounds.midX, y:bounds.midY)
          
              self.view.layer.addSublayer(videoPreviewLayer!)
              captureSession?.startRunning()
          }
          
          
          /* onAtivityResult from App Delegate */
          func captureOutput(_ captureOutput: AVCaptureOutput!,
                             didOutputMetadataObjects metadataObjects: [Any]!,
                             from connection: AVCaptureConnection!) {
              for item in metadataObjects {
                  if let metadataObject = item as? AVMetadataMachineReadableCodeObject {
                      if metadataObject.type == AVMetadataObjectTypeQRCode {
          
                          print("QR Code: \(metadataObject.stringValue)")
                          hideCamera(voucherHashkey: metadataObject.stringValue)
          
                      }
                  }
              }
          
          }
          
          
          /* Hide camera after getting result */
          func hideCamera(voucherHashkey:String){
          
              self.captureSession?.stopRunning()
              self.videoPreviewLayer?.removeFromSuperlayer()
              self.videoPreviewLayer = nil;
              self.captureSession = nil;
          
              // sendVocherDataToServer(voucherHashKey: voucherHashkey)
          
          }
          }
          

          【讨论】:

            【解决方案7】:

            考虑到AVCaptureSessionstartRunning() 是阻塞调用和其他详细信息,可以在此处找到二维码阅读器的不太快速和肮脏的 Swift 实现:

            https://bitbucket.org/snippets/stefanpilger/gE98R/qr-code-reader-class-swift

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多