session-ios/Session/Utilities/QRCode.swift

45 lines
2.1 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
enum QRCode {
/// Generates a QRCode for the give string
///
/// **Note:** If the `hasBackground` value is true then the QRCode will be black and white and
/// the `withRenderingMode(.alwaysTemplate)` won't work correctly on some iOS versions (eg. iOS 16)
static func generate(for string: String, hasBackground: Bool) -> UIImage {
let data = string.data(using: .utf8)
var qrCodeAsCIImage: CIImage
let filter1 = CIFilter(name: "CIQRCodeGenerator")!
filter1.setValue(data, forKey: "inputMessage")
qrCodeAsCIImage = filter1.outputImage!
guard !hasBackground else {
let filter2 = CIFilter(name: "CIFalseColor")!
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
filter2.setValue(CIColor(color: .black), forKey: "inputColor0")
filter2.setValue(CIColor(color: .white), forKey: "inputColor1")
qrCodeAsCIImage = filter2.outputImage!
let scaledQRCodeAsCIImage = qrCodeAsCIImage.transformed(by: CGAffineTransform(scaleX: 6.4, y: 6.4))
return UIImage(ciImage: scaledQRCodeAsCIImage)
}
let filter2 = CIFilter(name: "CIColorInvert")!
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
qrCodeAsCIImage = filter2.outputImage!
let filter3 = CIFilter(name: "CIMaskToAlpha")!
filter3.setValue(qrCodeAsCIImage, forKey: "inputImage")
qrCodeAsCIImage = filter3.outputImage!
let scaledQRCodeAsCIImage = qrCodeAsCIImage.transformed(by: CGAffineTransform(scaleX: 6.4, y: 6.4))
// Note: It looks like some internal method was changed in iOS 16.0 where images
// generated from a CIImage don't have the same color information as normal images
// as a result tinting using the `alwaysTemplate` rendering mode won't work - to
// work around this we convert the image to data and then back into an image
let imageData: Data = UIImage(ciImage: scaledQRCodeAsCIImage).pngData()!
return UIImage(data: imageData)!
}
}