本文分析的步骤主要是围绕CIFilter渲染滤镜后,从CIFilter逐步渲染为UIImaged的步骤,因为是常用的渲染输出流程,因此拿出来单独进行分析。
示例代码:
struct ContentView: View {
var body: some View {
if let image = applyBlurEffect(to: UIImage(named: "example")) {
Image(uiImage: image)
.resizable()
.scaledToFit()
}
}
func applyBlurEffect(to inputImage: UIImage?) -> UIImage? {
guard let inputImage = inputImage else { return nil }
let ciImage = CIImage(image: inputImage)
// 创建模糊滤镜
let filter = CIFilter.twirlDistortion()
filter.inputImage = ciImage
filter.center = CGPoint(x: 500, y: 500)
filter.radius = 300
filter.angle = 3.14
// 渲染滤镜效果
let context = CIContext()
if let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgImage)
}
return nil
}
}
上述代码实现了一张经过“扭曲失真”滤镜处理的图片。
View视图
var body: some View {
if let image = applyBlurEffect(to: UIImage(named: "example")) {
Image(uiImage: image)
.resizable()
.scaledToFit()
}
}
在View视图中,创建Image临时变量并调用applyBlurEffect方法,将UImage(named:”example”)传入该方法中,如果该方法正常返回内容,则会被赋值给image,并通过Image(uiImage:)显示处理后的图片。
applyBlurEffect方法
此方法对传入的图片应用 “扭曲失真” 滤镜并返回处理后的图片。
func applyBlurEffect(to inputImage: UIImage?) -> UIImage? {
guard let inputImage = inputImage else { return nil }
let ciImage = CIImage(image: inputImage)
// 创建模糊滤镜
let filter = CIFilter.twirlDistortion()
filter.inputImage = ciImage
filter.center = CGPoint(x: 500, y: 500)
filter.radius = 300
filter.angle = 3.14
// 渲染滤镜效果
let context = CIContext()
if let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgImage)
}
return nil
}
1、检查输入图片是否存在
guard let inputImage = inputImage else { return nil }
如果 inputImage 为 nil,返回 nil,避免后续操作发生错误。
2、转换图片为 Core Image 格式
let ciImage = CIImage(image: inputImage)
将 UIImage 转换为 Core Image 的 CIImage,以便后续滤镜操作。
3、配置滤镜
let filter = CIFilter.twirlDistortion()
filter.inputImage = ciImage
filter.center = CGPoint(x: 500, y: 500)
filter.radius = 300
filter.angle = 3.14
使用 CIFilter.twirlDistortion() 创建 “扭曲失真” 滤镜。
inputImage:指定要处理的图片。
center:设置扭曲的中心点,坐标 (500, 500)。
radius:设置扭曲的半径,值为 300 像素。
angle:设置扭曲的角度,值为 3.14(约等于 π)。
4、创建渲染上下文
let context = CIContext()
创建 CIContext 对象,用于渲染 CIImage,生成最终的图像数据。
5、渲染处理后的图片
if let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgImage)
}
return nil
filter.outputImage:获取滤镜处理后的 CIImage。
context.createCGImage:
渲染 outputImage,将描述性的 CIImage 转换为具体的 CGImage。
渲染范围为 outputImage.extent,即处理图片的完整区域。
返回处理后的图片:
将 CGImage 转换为 UIImage 以供 SwiftUI 显示。
如果渲染失败,返回 nil。
整体流程总结
1、加载图片。
2、应用 “扭曲失真” 滤镜。
3、使用 CIContext 渲染滤镜输出,生成具体的图像数据。
4、将渲染结果转换为 UIImage,以供 SwiftUI 显示。
多次转换及背后的工作原理
CIImage 是描述性的
CIImage 是 Core Image 的基础图像类型,它的设计理念是描述图像处理的链条,而不是存储最终的像素数据。
它内部记录了:
图像来源(如文件路径、像素数据、URL 等)。
应用的滤镜效果及参数。
未渲染的处理步骤。
let filter = CIFilter.gaussianBlur()
filter.inputImage = CIImage(image: UIImage(named: "example"))
filter.radius = 10.0
此时,filter.outputImage 是一个包含模糊效果描述的 CIImage,它告诉系统如何模糊原始图像,但尚未生成像素化的结果。
为什么需要 CIContext
CIContext 是渲染引擎:它将 CIImage 的描述“执行”成实际的图像数据。
渲染过程需要计算每个像素的值,例如模糊的强度、颜色调整等。
CIContext 的作用:
将 Core Image 的描述性图像处理链条(CIImage)转换为像素级数据。
支持 Metal、CPU 或 OpenGL 渲染,为处理提供高效的性能优化。
CIFilter的输入和输出
inputImage:提供原始图像,作为滤镜的输入。
outputImage:滤镜处理后生成的结果图像。
inputImage
定义:inputImage 是 CIFilter 的一个输入属性,表示滤镜需要处理的原始图像。
类型:它通常是一个 CIImage?(可选类型的 CIImage),即 Core Image 用来描述图像数据的对象。
用途:
通过设置 inputImage,我们告诉滤镜要对哪张图像进行处理。
如果没有为滤镜指定有效的 inputImage,滤镜将无法工作,其输出也会为空。
filter.inputImage = ciImage
这里的 ciImage 是一个通过 UIImage 转换得到的 CIImage,表示原始的待处理图像。
outputImage
定义:outputImage 是 CIFilter 的一个输出属性,表示滤镜处理后的结果图像。
类型:它是一个 CIImage?(可选类型的 CIImage),即处理后的图像描述。
用途:
调用 outputImage 属性时,Core Image 会基于滤镜的配置(如参数设置)生成一个处理后的图像描述。
需要进一步渲染(通过 CIContext)才能将其转化为实际的图像格式(如 UIImage 或 CGImage)。
let outputImage = filter.outputImage
渲染后的结果:CGImage
context.createCGImage(outputImage, from: outputImage.extent)
context.createCGImage 是使用 Core Image 的 CIContext 来渲染 CIImage,生成实际的像素图像(CGImage 类型)。
参数:
outputImage 是需要渲染的 CIImage。
outputImage.extent 指定渲染的图像区域(通常是图像的边界)。
为什么要渲染?
CIImage 是一种延迟计算的数据结构,只描述图像和操作,但没有实际的像素数据。要显示、保存或进一步处理,就需要将其渲染为具体格式,如 CGImage。
渲染后的图像是 CGImage 类型,它代表已生成的、具体的像素图像。
为什么渲染为 CGImage?
Core Graphics 是底层的 2D 图形库,CGImage 是 Core Graphics 处理图像的核心类型。
iOS 和 macOS 的大部分图像处理管道(如 PDF 渲染、屏幕显示等)依赖 CGImage。
转换为 UIImage 的必要性
UIImage 是 UIKit 的图像类型,用于在 iOS 上显示或进一步处理。
为什么不能直接从 CIImage 转换为 UIImage?
UIKit 无法直接理解 Core Image 的描述链条。
需要通过 CIContext 渲染 CIImage 并生成像素数据(CGImage),再封装为 UIImage。
完整转换过程的作用
1、CIImage:
用于描述图像处理链条,包括滤镜和参数。
不占用太多内存,因为它不包含实际的像素数据。
2、CIContext:
负责解析和执行 CIImage 的处理链条,将其渲染为像素数据。
3、CGImage:
渲染后的图像,包含具体的像素数据。
高效、轻量,可用于图像操作或显示。
4、UIImage:
iOS 的标准图像类型,直接用于用户界面(如 UIImageView)。
包装了 CGImage 和元数据信息(如方向、缩放比例等)。
为什么需要分阶段转换?
性能考虑:
CIImage 是懒加载的,仅在需要渲染时生成实际数据,节约内存和计算资源。
渲染过程可选择 CPU、GPU 或 Metal,以适应不同的性能需求。
灵活性:
CGImage 可以直接用于 Core Graphics 和其他底层处理。
UIImage 用于 UI 层更方便。