CIFilter 是 Core Image 框架中的一个类,用于执行图像的滤镜操作或效果处理。通过 CIFilter,可以对图像进行各种操作,比如模糊、色彩调整、锐化、扭曲等。
CIFilter 的核心特点
1、滤镜操作的核心对象:
每个 CIFilter 实例代表一个特定的图像处理操作。
它接收一个输入图像(通常是 CIImage)并应用滤镜处理后输出一个新的 CIImage。
2、丰富的内置滤镜:
Core Image 提供了大量预定义的滤镜,比如:
模糊滤镜:CIGaussianBlur
色彩调整:CIColorControls
扭曲效果:CITwirlDistortion
合成效果:CISourceOverCompositing
3、动态参数设置:
每个滤镜都有自己的参数,允许自定义效果强度或方式。
4、链式操作:
滤镜可以串联使用,每个滤镜的输出可以作为下一个滤镜的输入。
CIFilter 的基本使用
1、创建 CIFilter
创建一个滤镜实例:
import CoreImage
import CoreImage.CIFilterBuiltins
let filter = CIFilter.gaussianBlur()
或者使用名字创建:
let filter = CIFilter(name: "CIGaussianBlur")
2、设置滤镜输入
向滤镜提供输入图像(CIImage)和参数:
filter.inputImage = CIImage(image: UIImage(named: "example")!)
filter.radius = 10.0 // 模糊半径
3、获取输出图像
滤镜的结果是一个新的 CIImage:
if let outputImage = filter.outputImage {
print("Filter applied successfully")
}
4、渲染最终图像
CIImage 是一个抽象对象,通常需要通过 CIContext 渲染为 UIImage 或 CGImage:
let context = CIContext()
if let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
let uiImage = UIImage(cgImage: cgImage)
}
内置滤镜示例
模糊效果
let filter = CIFilter.gaussianBlur()
filter.inputImage = CIImage(image: UIImage(named: "example")!)
filter.radius = 20.0
色彩调整
let filter = CIFilter.colorControls()
filter.inputImage = CIImage(image: UIImage(named: "example")!)
filter.saturation = 0.5
filter.brightness = 0.1
filter.contrast = 1.2
扭曲效果
let filter = CIFilter.twirlDistortion()
filter.inputImage = CIImage(image: UIImage(named: "example")!)
filter.center = CGPoint(x: 150, y: 150)
filter.radius = 100
filter.angle = 3.14
链式操作
可以将多个滤镜串联起来实现复杂效果:
let inputImage = CIImage(image: UIImage(named: "example")!)
// 模糊滤镜
let blurFilter = CIFilter.gaussianBlur()
blurFilter.inputImage = inputImage
blurFilter.radius = 10.0
// 色彩调整滤镜
let colorFilter = CIFilter.colorControls()
colorFilter.inputImage = blurFilter.outputImage
colorFilter.saturation = 0.8
colorFilter.brightness = 0.2
colorFilter.contrast = 1.5
// 渲染最终图像
let context = CIContext()
if let outputImage = colorFilter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
let uiImage = UIImage(cgImage: cgImage)
}
动态参数与查找滤镜
可以动态获取和设置滤镜参数:
if let filter = CIFilter(name: "CIGaussianBlur") {
print(filter.attributes) // 打印所有参数信息
filter.setValue(20.0, forKey: kCIInputRadiusKey) // 设置半径
}
所有参数信息示例:
["CIAttributeFilterAvailable_iOS": 6, // 此滤镜自 iOS 6 开始可用。
"inputImage": {
CIAttributeClass = CIImage; // 输入必须是 CIImage 类型
CIAttributeDescription = "The image to use as an input for the effect."; // 描述该参数是滤镜效果的输入图像
CIAttributeDisplayName = Image; // 输入参数的显示名称为“Image”
CIAttributeType = CIAttributeTypeImage; // 输入类型是图像。
}, "CIAttributeFilterCategories": <__NSArrayI_Transfer 0x600000259960>(
CICategoryBlur, // 类别模糊
CICategoryStillImage, // 可用于静态图片
CICategoryVideo, // 可用于视频
CICategoryBuiltIn, // 系统内置滤镜
CICategoryHighDynamicRange // 可用于 HDR 图像处理
)
, "inputRadius": { // 滤镜的模糊半径参数
CIAttributeClass = NSNumber; // 类型是数字
CIAttributeDefault = 10; // 默认为10
CIAttributeDescription = "The radius determines how many pixels are used to create the blur. The larger the radius, the blurrier the result."; // 描述模糊半径的作用,半径越大,模糊越明显
CIAttributeDisplayName = Radius; // 参数的显示名称是“Radius”
CIAttributeIdentity = 0; // 表示模糊半径的标识值(通常是默认值或最小值)
CIAttributeMin = 0; // 最小值是 0
CIAttributeSliderMax = 100; // 指定 UI 滑块的范围在 0 到 100。
CIAttributeSliderMin = 0; // 指定 UI 滑块的范围在 0 到 100。
CIAttributeType = CIAttributeTypeScalar; // 参数是标量类型。
},
"CIAttributeFilterName": CIGaussianBlur, // 滤镜的系统标识符
"CIAttributeFilterAvailable_Mac": 10.4, // 此滤镜自 macOS 10.4 开始可用。
"CIAttributeReferenceDocumentation": http://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/filter/ci/CIGaussianBlur, // 滤镜的官方文档链接,提供详细的使用说明
"CIAttributeFilterDisplayName": Gaussian Blur // 滤镜的显示名称
]
需要注意的是,filter.attributes 是描述性元数据,不反映动态运行时的参数值,因此这些值不会随着运行时动态参数值的更改而变化。
如果想要验证动态参数可以使用filter.value进行验证:
// 获取运行时的 inputRadius 值
if let currentRadius = filter.value(forKey: kCIInputRadiusKey) as? CGFloat {
print("Current inputRadius value: \(currentRadius)") // 输出 10.0
}
filter.setValue(20.0, forKey: kCIInputRadiusKey) // 设置半径
// 获取运行时的 inputRadius 值
if let currentRadius = filter.value(forKey: kCIInputRadiusKey) as? CGFloat {
print("Current inputRadius value: \(currentRadius)") // 输出 20.0
}
获取所有可用滤镜名称:
let allFilters = CIFilter.filterNames(inCategory: nil)
print(allFilters)
输出内容为:
filterName:["CIAccordionFoldTransition", "CIAdditionCompositing", "CIAffineClamp", "CIAffineTile", "CIAffineTransform", "CIAreaAverage", "CIAreaHistogram",
...]
可接受的所有输入参数
inputKeys 是一个字符串数组,包含滤镜可接受的所有输入参数的键名。这些键名是常量(如 kCIInputImageKey、kCIInputRadiusKey 等)。
用途:
方便开发者快速获取当前滤镜支持的输入参数。
用于动态判断某个参数是否可设置,例如:
let inputKeys = currentFilter.inputKeys
if inputKeys.contains(kCIInputIntensityKey) {
currentFilter.setValue(amount, forKey: kCIInputIntensityKey) }
if inputKeys.contains(kCIInputRadiusKey) { currentFilter.setValue(amount * 200, forKey: kCIInputRadiusKey) }
if inputKeys.contains(kCIInputScaleKey) { currentFilter.setValue(amount * 10, forKey: kCIInputScaleKey) }
inputKeys 返回当前滤镜可接受的所有参数键(String 类型数组)。每个滤镜都有不同的输入参数集。
if inputKeys.contains(…): 检查滤镜是否支持特定的输入参数。
currentFilter.setValue(…): 动态设置滤镜的参数值。
示例参数设置
1、kCIInputIntensityKey:
如果滤镜支持 “强度” 参数(Intensity),设置其值为 amount。
2、kCIInputRadiusKey:
如果滤镜支持 “半径” 参数(Radius),设置其值为 amount * 200。
半径控制漩涡扭曲的范围,值越大,扭曲范围越广。
3、kCIInputScaleKey:
如果滤镜支持 “缩放” 参数(Scale),设置其值为 amount * 10。
inputKeys和attributes对比
1、inputKeys:
数据结构为[String]。
提供参数键名,用于快速检查支持的参数。
信息仅包含参数名称(键值)。
用于判断参数是否存在并动态设置值。
简单快捷,只有名称列表。
2、attributes:
数据结构为 [String:Any]。
提供参数的详细描述信息,用于动态生成 UI 或调整界限。
参数的类型、默认值、取值范围、功能描述等。
用于构建智能、动态的滤镜 UI 或为用户提供参数的约束提示。
复杂但全面,适合深入操作。
何时使用?
1、inputKeys:
在代码中动态检查参数是否存在,设置值时非常方便。
示例:
if inputKeys.contains("inputRadius") {
filter.setValue(100, forKey: "inputRadius")
}
2、attributes:
如果需要动态生成滤镜参数的 UI,或为用户提供更智能的选项限制(如滑动条范围),attributes 非常有用。
示例:
if let radiusAttributes = filter.attributes["inputRadius"] as? [String: Any] {
let defaultRadius = radiusAttributes[kCIAttributeDefault] as? Float ?? 0
let maxRadius = radiusAttributes[kCIAttributeMax] as? Float ?? 1000
print("Radius: Default=\(defaultRadius), Max=\(maxRadius)")
}
另一种滤镜输入方式
前面提到的滤镜输入方式为:
filter.inputImage = CIImage(image: UIImage(named: "example")!)
还有另一种滤镜输入方式:
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
在上面的代码中,currentFilter是创建的滤镜示例,beginImage为CIImage。
示例代码:
struct ContentView: View {
@State private var currentFilter = CIFilter.sepiaTone()
...
func loadImage() {
Task {
guard let imageData = try await selectedItem?.loadTransferable(type: Data.self) else { return }
guard let inputImage = UIImage(data: imageData) else { return }
let beginImage = CIImage(image: inputImage)
// 设置滤镜输入
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
}
}
...
}
输入方式的区别
1、setValue(_:forKey:):
这是 Core Image 提供的通用方式,用于设置任何滤镜参数。
形式:
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
作用:
通过字符串键(如 kCIInputImageKey)设置滤镜的输入属性。
支持任何参数,不限于 inputImage。
适合动态场景,比如通过键值对动态修改滤镜参数。
灵活性:
适用于所有 CIFilter,即使某些滤镜没有为参数提供属性封装。
允许通过键访问滤镜的隐藏属性。
缺点:
字符串键可能导致拼写错误,编译器无法校验键的有效性(不安全)。
2、filter.inputImage
这是 Core Image 提供的强类型方式,专门用于设置输入图像。
形式:
filter.inputImage = beginImage
作用:
使用滤镜的强类型接口(如果存在)。
直接通过属性访问,设置滤镜的输入图像。
灵活性:
仅适用于特定的滤镜(例如 CIFilter.sepiaTone()),这些滤镜已经为参数提供了强类型的属性。
如果滤镜没有强类型属性(如 CIFilter.custom()),就无法使用这种方式。
优点:
强类型和编译器支持,能减少拼写错误。
更符合 Swift 的类型安全特性。
何时使用哪种方式?
使用 setValue(_:forKey:) 的场景
动态滤镜:需要动态切换滤镜,或者对滤镜的参数进行动态操作。
let randomFilter = CIFilter(name: "CISepiaTone")!
randomFilter.setValue(beginImage, forKey: kCIInputImageKey)
访问非公开参数:一些滤镜的参数可能没有强类型属性,必须通过键访问。
使用 filter.inputImage 的场景
静态滤镜:明确使用某个固定的滤镜(如 CIFilter.sepiaTone())。
let sepiaFilter = CIFilter.sepiaTone()
sepiaFilter.inputImage = beginImage
最佳实践
在能够使用 filter.inputImage 的场景下,优先选择这种强类型方式;只有在需要动态操作或访问非公开参数时,才考虑使用 setValue(_:forKey:)。
CoreImage.CIFilterBuiltins
CoreImage.CIFilterBuiltins 是 Core Image 提供的一组类型安全的滤镜构造器。导入它可以更直观的方式使用 Core Image 的滤镜,而不需要手动处理字符串类型的滤镜名称。
什么是 CoreImage.CIFilterBuiltins?
CoreImage.CIFilterBuiltins 是 Core Image 的一个扩展,它提供了特定滤镜的强类型接口。例如,它允许通过 .gaussianBlur() 或 .sepiaTone() 等方法直接创建滤镜实例,而不是通过 CIFilter(name:) 的方式使用字符串创建。
特性和优点
类型安全:编译器会检查调用的方法和参数,避免拼写错误或传递不正确的值。
自动补全:通过 Xcode 自动补全功能,可以快速找到可用的滤镜。
语义清晰:相比于字符串形式的滤镜名称,方法名更具可读性。
是否必须导入 CoreImage.CIFilterBuiltins?
必须导入的场景:如果想使用类型安全的构造器(如 .gaussianBlur()),需要显式导入:
import CoreImage
import CoreImage.CIFilterBuiltins
不需要导入的场景:如果使用的是传统的字符串构造方式 CIFilter(name:),则无需导入 CoreImage.CIFilterBuiltins。
示例比较
传统字符串方式
使用字符串名称时,创建滤镜和设置参数需要手动指定:
let filter = CIFilter(name: "CIGaussianBlur")
filter?.setValue(ciImage, forKey: kCIInputImageKey)
filter?.setValue(10.0, forKey: kCIInputRadiusKey)
缺点:
不支持类型检查,容易出现拼写错误。
参数和方法的提示较少。
使用 CoreImage.CIFilterBuiltins
通过内置构造器,可以更安全地创建和使用滤镜:
let filter = CIFilter.gaussianBlur()
filter.inputImage = ciImage
filter.radius = 10.0
优点:
更加简洁直观。
提供了类型检查和参数补全。
CoreImage.CIFilterBuiltins 的作用
本质上,它是为每个 Core Image 滤镜定义了一个 Swift 原生接口,使开发者无需记忆滤镜的字符串名称,并且能够更自然地与 Swift 的类型系统和语法集成。例如:
extension CIFilter {
static func gaussianBlur() -> CIGaussianBlur {
return CIFilter(name: "CIGaussianBlur") as! CIGaussianBlur
}
}
CoreImage.CIFilterBuiltins 提供的这些方法在背后封装了上述实现。
总结
CIFilter 是 Core Image 的核心,用于实现强大的图像处理功能。
它提供了丰富的预定义滤镜和参数,支持动态操作。
通过链式使用滤镜,可以创建复杂的效果。
与 GPU 加速渲染结合,CIFilter 能高效处理大规模图像任务,是开发者处理图像时的重要工具。
CoreImage.CIFilterBuiltins 是一个扩展,为 Core Image 提供了类型安全的滤镜创建接口。
是否导入取决于具体的需求:
如果需要类型安全的方式(推荐),请导入。
如果继续使用传统的字符串构造方式,则不需要导入。
它是 Swift 化的设计,旨在简化 Core Image 的使用并提高代码的安全性和可读性。