Using the CIFilter.qrCodeGenerator() to create a QR code I wanted to change the colours dynamically to suit Light/Dark mode, but was unable to figure out how to achieve this, is it possible please ?
struct QrCodeImage {
let context = CIContext()
func generateQRCode(from text: String) -> UIImage {
var qrImage = UIImage(systemName: "xmark.circle") ?? UIImage()
let data = Data(text.utf8)
let filter = CIFilter.qrCodeGenerator()
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 2, y: 2)
if let outputImage = filter.outputImage?.transformed(by: transform) {
if let image = context.createCGImage(
outputImage,
from: outputImage.extent) {
qrImage = UIImage(cgImage: image)
}
}
return qrImage
}
}
Further, I cannot see an option for the different modes and assume that any colour could be used, which would be a lot better for me.
ref: https://developer.apple.com/documentation/coreimage/ciqrcodegenerator
You can use the QR code as a mask and blend it with a solid color to effectively colorize it. So you can, for example, create a black and a white version and use the register(...)
method of UIImage
to "bundle" them both into one dynamic image:
let qrCode = filter.outputImage!.transformed(by: transform)
// Use the QR code as a mask for blending with a color.
// Note that we need to invert the code for that, so the actual code becomes white
// and the background becomes black, because white = let color through, black = transparent.
let maskFilter = CIFilter.blendWithMask()
maskFilter.maskImage = qrCode.applyingFilter("CIColorInvert")
// create a version of the code with black foreground...
maskFilter.inputImage = CIImage(color: .black)
let blackCIImage = maskFilter.outputImage!
// ... and one with white foreground
maskFilter.inputImage = CIImage(color: .white)
let whiteCIImage = maskFilter.outputImage!
// render both images
let blackImage = context.createCGImage(blackCIImage, from: blackCIImage.extent).map(UIImage.init)!
let whiteImage = context.createCGImage(whiteCIImage, from: whiteCIImage.extent).map(UIImage.init)!
// use black version for light mode
qrImage = blackImage
// assign the white version to be used in dark mode
qrImage.imageAsset?.register(whiteImage, with: UITraitCollection(userInterfaceStyle: .dark))
return qrImage