在iOS上,您可以向CIFilter
添加多个SKEffectsNode
吗?
CIFilterGenerator
似乎是我想要的,但在iOS上不可用。
我知道您可以通过将{的输出作为下一个的输入来使用multiple filters on an image,但是如果您想影响非图像节点,则无济于事。
这是否意味着我必须创建SKEffectNode
的人工层次结构,并为每个过滤器添加一个过滤器,而我的实际内容才是最底部?有更好的方法吗?
答案 0 :(得分:2)
在难以或不可能将多个CIFilter
调用“链接”在一起以实现所需效果的情况下-可能由于具有单个属性的类,一种克服此问题的方法是执行以下操作:>
CIFilter
,覆盖您需要的所有内容。这可能包括attributes
,setValue(forKey:)
,最重要的是outputImage
。CIFilterConstructor
,并创建一个registerFilter()
方法。例如,假设您希望合并高斯模糊,然后向图像添加单色红色调。最基本的方法是:
class BlurThenColor:CIFilter {
let blurFilter = CIFilter(name: "CIGaussianBlur")
override public var attributes: [String : Any] {
return [
kCIAttributeFilterDisplayName: "Blur then Color",
"inputImage": [kCIAttributeIdentity: 0,
kCIAttributeClass: "CIImage",
kCIAttributeDisplayName: "Image",
kCIAttributeType: kCIAttributeTypeImage]
]
}
override init() {
super.init()
}
@available(*, unavailable) required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func setValue(_ value: Any?, forKey key: String) {
switch key {
case "inputImage":
blurFilter?.setValue(inputImage, forKey: "inputImage")
default:
break
}
}
override public var outputImage: CIImage {
return (blurFilter?.outputImage)! .applyingFilter("CIColorMonochrome", parameters: ["inputColor": CIColor(red: 1.0, green: 0.0, blue: 0.0)])
}
}
如果您希望公开更多属性,则可以简单地将它们添加到attributes
和setValue(forKey:)
覆盖中,同时添加变量和setDefaults
。在这里,我只是使用默认值。
现在,您已将效果链接到一个自定义滤镜中,可以注册并使用它:
let CustomFilterCategory = "CustomFilter"
public class CustomFilterConstructor: NSObject, CIFilterConstructor {
static public func registerFilter() {
CIFilter.registerName(
"BlurThenColor",
constructor: CustomFilterConstructor(),
classAttributes: [
kCIAttributeFilterCategories: [CustomFilterCategory]
])
}
public func filter(withName name: String) -> CIFilter? {
switch name {
case "BlurThenColor":
return BlurThenColor()
default:
return nil
}
}
}
要使用此功能,只需确保注册过滤器(如果可能,我倾向于将我的过滤器放在AppDelegate
中)
CustomFilterConstructor.registerFilter()
从那里,您可以像使用其他BlurThenColor
一样使用CIFilter
。实例化它,使用setValue
,然后调用outputImage
。
请注意,由于强制inputImage
和/或拼写错误,此代码将崩溃。我相信您可以使此操作更加安全-但请放心,我已经对此进行了测试并且可以正常工作。 (我创建了这个自定义过滤器,并在不会发生强制拆包的应用中将其替换。)
答案 1 :(得分:2)
遵循dfd的有用建议,我最终选择了这个简单的子类。我将他的答案标记为正确,因为a)他建议使用这种方法,我想给他功劳,b)它具有使用CIFilterConstructor注册过滤器的更多常规信息。
有用的参考资料: -Apple Docs -Related Question -Free Core Image eBook
class MyChainFilter: CIFilter {
let chainedFilters: [CIFilter]
@objc dynamic var inputImage: CIImage?
init(filters: [CIFilter]) {
self.chainedFilters = filters
super.init()
}
// run filters in order on the specified source image
override var outputImage: CIImage? {
get {
let imageKey = "inputImage"
var workingImage = self.inputImage
for filter in chainedFilters {
assert(filter.inputKeys.contains(imageKey))
filter.setValue(workingImage, forKey: imageKey)
guard let result = filter.outputImage else {
assertionFailure("filter failed: \(filter.name)")
return nil
}
workingImage = result
}
return workingImage
}
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}