//
// ContentView.swift
// ORCode
//
//
import SwiftUI
import CoreImage.CIFilterBuiltins
struct ContentView: View {
var body: some View {
Image(uiImage: generateQRCode(from: "123")).interpolation(.none)
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
.padding()
}
func generateQRCode(from string: String) -> UIImage {
let context = CIContext()
let filter = CIFilter.qrCodeGenerator()
let data = Data(string.utf8)
filter.setValue(data, forKey: "inputMessage")
if let outputImage = filter.outputImage {
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgimg)
}
}
return UIImage(systemName: "xmark.circle") ?? UIImage()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
生成和缩放二维码
Core Image 可以让我们基于任何字符串输入生成一个二维码,而且过程极快。不过,这里有一个问题:图像的尺寸很小,只包含承载数据必要的像素。要让二维码更好用,需要借助 SwiftUI 的图像插值。因此,在这一步我们要让用户在表单里输入他们的名字和邮件地址,然后用这两条信息生成一个能标识他们的二维码,并且放大这个二维码。
二维码是一块由黑白像素构成的方块,可以通过手机和其他设备来扫描。Core Image 对此提供了专门的滤镜。如果你之前学习过如何使用 Core Image 滤镜,你会发现下面的过程很相似。
首先,我们需要用一个新的 import 来导入 Core Image 内置的滤镜:
import CoreImage.CIFilterBuiltins
其次,我们要用两个属性来分别存储一个激活的 Core Image 上下文和一个 Core Image 的二维码生成器滤镜的实例。
let context = CIContext()<br>let filter = CIFilter.qrCodeGenerator()
接下来是有趣的部分:制作二维码。如果你还记得,Core Image 滤镜要求我们使用 setValue(_:forKey:) 来设置输入数据,然后把输出的 CIImage 转成 CGImage,再把 CGImage 转成 UIImage。这里的步骤相似,除了以下三点:
- 我们的输入是字符串,但滤镜的输入是
Data,所以我们需要做转换。 - 如果转换因为某种原因失败,我们会返回 SF Symbols 的 “xmark.circle” 图像。
- 如果该图像不能读取 —— 理论上这是有可能的,因为 SF Symbols 是基于字符串的 —— 那么我们将返回一个空的
UIImage。
把下面这个方法添加到 结构体:
func generateQRCode(from string: String) -> UIImage {
let data = Data(string.utf8)
filter.setValue(data, forKey: "inputMessage")
if let outputImage = filter.outputImage {
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgimg)
}
}
return UIImage(systemName: "xmark.circle") ?? UIImage()
}
在 SwiftUI 中,通过函数分离功能的做法很奏效,因为这意味着我们放进 body 属性的代码将会尽可能地简单。实际上,我们可以直接使用 generateQRCode(from:) 生成的 Image,然后把它放大到一个合理的尺寸 .
把这个新 Image 视图直接添加到 视图上面
Image(uiImage: generateQRCode(from: "\(name)\n\(emailAddress)"))
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
不过,近距离观察一下二维码 —— 你注意到它是模糊的吗?这是因为 Core Image 生成的是小图像,而 SwiftUI 在放大时尝试平滑像素。
像二维码这样的线条艺术,最好是禁用图像插值,把下面这个 modifier 添加到图像:
.interpolation(.none)
这样二维码就会以比较锐利的方式渲染,因为 SwiftUI 只会复制像素而不会混合像素。对于相机来说,它不关心二维码长啥样,但这样对用户来说比较好看。