1

I tried to generate a qrcode, but it has error

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

let myString = "ggigiuui"

let data = myString.data(using: .ascii, allowLossyConversion: false)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(data, forKey: "inputMessage")

let img = UIImage(ciImage: (filter?.outputImage)!)

qponImage.image = img

enter image description here

slavoo
  • 5,798
  • 64
  • 37
  • 39
Eric Chong
  • 495
  • 1
  • 7
  • 21

4 Answers4

6

I have used the following code, and it is working perfectly.Where self.imgQRCode is the imageview on which you want to display QR.

func generateQRCode(from string: String) -> UIImage?
    {
        let data = string.data(using: String.Encoding.ascii)

        if let filter = CIFilter(name: "CIQRCodeGenerator")
        {
            filter.setValue(data, forKey: "inputMessage")

            guard let qrImage = filter.outputImage else {return nil}
            let scaleX = self.imgQRCode.frame.size.width / qrImage.extent.size.width
            let scaleY = self.imgQRCode.frame.size.height / qrImage.extent.size.height
            let transform = CGAffineTransform(scaleX: scaleX, y: scaleY)

            if let output = filter.outputImage?.transformed(by: transform)
            {
                return UIImage(ciImage: output)
            }
        }
        return nil
    }
aBilal17
  • 2,974
  • 2
  • 17
  • 23
3

Please try this,

func generateQRCode(from string: String) -> UIImage? {
    let data = string.data(using: String.Encoding.ascii)

    if let filter = CIFilter(name: "CIQRCodeGenerator") {
        filter.setValue(data, forKey: "inputMessage")
        let transform = CGAffineTransform(scaleX: 3, y: 3)

        if let output = filter.outputImage?.transformed(by: transform) {
            return UIImage(ciImage: output)
        }
    }

    return nil
}
Sapana Ranipa
  • 889
  • 7
  • 20
1

This is how you can generate a QRCode and display in UIImageView

first of all create new Cocoa Touch Class .swift file and import these two framework:

import UIKit
import CoreImage

and the second step you just need to add the extension of URL and CIImage on the same .swift file.

extensions :

extension URL {

    /// Creates a QR code for the current URL in the given color.
    func qrImage(using color: UIColor, logo: UIImage? = nil) -> CIImage? {
        let tintedQRImage = qrImage?.tinted(using: color)
        guard let logo = logo?.cgImage else {
            return tintedQRImage
        }
        return tintedQRImage?.combined(with: CIImage(cgImage: logo))
    }
    
    /// Returns a black and white QR code for this URL.
    var qrImage: CIImage? {
        guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
        let qrData = absoluteString.data(using: String.Encoding.ascii)
        qrFilter.setValue(qrData, forKey: "inputMessage")
        let qrTransform = CGAffineTransform(scaleX: 12, y: 12)
        return qrFilter.outputImage?.transformed(by: qrTransform)
    }
}

extension CIImage {
    
    /// Inverts the colors and creates a transparent image by converting the mask to alpha.
    /// Input image should be black and white.
    var transparent: CIImage? {
        return inverted?.blackTransparent
    }
    
    /// Inverts the colors.
    var inverted: CIImage? {
        guard let invertedColorFilter = CIFilter(name: "CIColorInvert") else { return nil }
        invertedColorFilter.setValue(self, forKey: "inputImage")
        return invertedColorFilter.outputImage
    }
    
    /// Converts all black to transparent.
    var blackTransparent: CIImage? {
        guard let blackTransparentFilter = CIFilter(name: "CIMaskToAlpha") else { return nil }
        blackTransparentFilter.setValue(self, forKey: "inputImage")
        return blackTransparentFilter.outputImage
    }
    
    /// Applies the given color as a tint color.
    func tinted(using color: UIColor) -> CIImage?
    {
        guard
            let transparentQRImage = transparent,
            let filter = CIFilter(name: "CIMultiplyCompositing"),
            let colorFilter = CIFilter(name: "CIConstantColorGenerator") else { return nil }
        
        let ciColor = CIColor(color: color)
        colorFilter.setValue(ciColor, forKey: kCIInputColorKey)
        let colorImage = colorFilter.outputImage
        filter.setValue(colorImage, forKey: kCIInputImageKey)
        filter.setValue(transparentQRImage, forKey: kCIInputBackgroundImageKey)
        return filter.outputImage!
    }
    
    /// Combines the current image with the given image centered.
    func combined(with image: CIImage) -> CIImage? {
        guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else { return nil }
        let centerTransform = CGAffineTransform(translationX: extent.midX - (image.extent.size.width / 2), y: extent.midY - (image.extent.size.height / 2))
        combinedFilter.setValue(image.transformed(by: centerTransform), forKey: "inputImage")
        combinedFilter.setValue(self, forKey: "inputBackgroundImage")
        return combinedFilter.outputImage!
    }
}

and the third step you have to bund the outlet of your imageview in which you want to display generated QRCode.

your ViewController.swift file something like this.

  // desired color of QRCode
    let OrangeColor = UIColor(red:0.93, green:0.31, blue:0.23, alpha:1.00)
  // app logo or whatever UIImage you want to set in the center.
    let Logo = UIImage(named: "logo_which_you_want_to_set_in_the center_of_the_QRCode")!

    @IBOutlet weak var imgQRImage: UIImageView!

and last and final step add the QRCode to imgQRImage and put the code in your viewDidLoad()

override func viewDidLoad() {
    super.viewDidLoad()
    let QRLink = "https://www.peerbits.com/"
    guard let qrURLImage = URL(string: QRLink)?.qrImage(using: self.OrangeColor, logo: self.Logo)else{return}
    self.imgQRImage.image = UIImage(ciImage: qrURLImage)
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Azharhussain Shaikh
  • 1,654
  • 14
  • 17
  • Better comment tutorial link if you have not change anything https://www.avanderlee.com/swift/qr-code-generation-swift/ – karthikeyan Feb 20 '20 at 04:29
0

As mention in docs we can use CIQRCodeGenerator

enter image description here

func qrCode(_ outputSize: CGSize) -> UIImage?
{
    if let data = data(using: .isoLatin1),
       let outputImage = CIFilter(
        name: "CIQRCodeGenerator",
        parameters: [
            "inputMessage": data,
            "inputCorrectionLevel": "Q"
        ]
       )?.outputImage {
        let size: CGRect = outputImage.extent.integral
        
        let format = UIGraphicsImageRendererFormat()
        format.scale = UIScreen.main.scale
        
        return UIGraphicsImageRenderer(size: output, format: format)
            .image { _ in
                outputImage
                    .transformed(
                        by: .init(
                            scaleX: outputSize.width/size.width,
                            y: outputSize.height/size.height
                        )
                    )
                    .uiimage
                    .draw(in: .init(origin: .zero, size: outputSize))
            }

    } else {
        return nil
    }
}

extension CIImage {

   var uiimage: UIImage {
       .init(ciImage: self)
   }
}

this is bit modified version of this post

and in case u need to parse qr code image for content

    func decodeQRCode(_ image: UIImage?) -> [CIQRCodeFeature]? {
        if let image = image,
           let ciImage = CIImage(image: image) {
            
            let context = CIContext()
            var options: [String: Any] = [
                CIDetectorAccuracy: CIDetectorAccuracyHigh
            ]
            
            let qrDetector = CIDetector(
                ofType: CIDetectorTypeQRCode,
                context: context,
                options: options
            )
            
            if ciImage.properties.keys
                .contains((kCGImagePropertyOrientation as String)) {
                options = [
                    CIDetectorImageOrientation: ciImage
                        .properties[(kCGImagePropertyOrientation as String)] as Any
                ]
            } else {
                options = [CIDetectorImageOrientation: 1]
            }
            
            let features = qrDetector?.features(in: ciImage, options: options)
            return features?
                .compactMap({ $0 as? CIQRCodeFeature })
        }
        
        return nil
    }
}
hbk
  • 10,908
  • 11
  • 91
  • 124