我不知道如何动态过滤(滤色器)正在加载的图像。例如我想动态增加饱和度。
在 SwiftUI 中过滤图像看起来直接使用 [
CI library
] (https://www.hackingwithswift.com/books/ios-swiftui/basic-image-filtering-using-core-image)。
但是我无法弄清楚如何从要操作的异步图像中获取核心图像对象。
我想象它的工作原理是这样的:
AsyncImage(url: URL(string: "https://example.com/icon.png")) { image in
Image(uiImage: myFilter(image.uiImage.ciImage).uiImage).resizable()
} placeholder: {
ProgressView()
}
.frame(width: 50, height: 50)
或者也许图像可以扩展?
AsyncImage
无法给您 UIImage
,但编写自己的 AsyncImage
并为您提供 UIImage
相对容易。
struct AsyncUIImage<Content: View, Placeholder: View>: View {
let url: URL
let contentBuilder: (UIImage) -> Content
let placeholder: Placeholder
@State private var content: Content?
init(url: URL, @ViewBuilder content: @escaping (UIImage) -> Content, @ViewBuilder placeholder: () -> Placeholder) {
self.url = url
self.contentBuilder = content
self.placeholder = placeholder()
}
var body: some View {
if let content {
content
} else {
placeholder
.task {
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let uiImage = UIImage(data: data) {
content = contentBuilder(uiImage)
}
} catch {
print(error)
}
}
}
}
}
使用示例:
var body: some View {
AsyncUIImage(url: URL(string: "https://picsum.photos/200")!) { uiImage in
VStack {
if let ciImage = CIImage(image: uiImage) {
processImage(ciImage)
}
Image(uiImage: uiImage)
}
} placeholder: {
ProgressView()
}
}
func processImage(_ ciImage: CIImage) -> Image? {
let context = CIContext()
let filter = CIFilter.sepiaTone()
filter.inputImage = ciImage
filter.intensity = 1
guard let output = filter.outputImage else { return nil }
guard let cgImage = context.createCGImage(output, from: output.extent) else { return nil }
return Image(uiImage: UIImage(cgImage: cgImage))
}
另请注意,某些
CIFilter
的效果可以使用 SwiftUI 视图修饰符来实现,例如 blur
、colorInvert
、hueRotation
等。对于这些滤镜,您只需将它们应用到 Image
由 AsyncImage
制作。