图像滤镜效果CIFilter
图像滤镜效果CIFilter

图像滤镜效果CIFilter

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 的使用并提高代码的安全性和可读性。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注