3

在 iOS 上,你可以添加多个CIFilter到 aSKEffectsNode吗?

CIFilterGenerator似乎是我想要的,但它在 iOS 上不可用。

我知道您可以通过将一个的输出作为下一个的输入传递来在图像上使用多个过滤器,但是如果您想影响非图像节点,这将无济于事。

这是否意味着我必须创建一个人为的层次结构SKEffectNode并为它们中的每一个添加一个过滤器,而我的实际内容位于最底部?有没有更好的办法?

4

2 回答 2

5

按照 dfd 的有用建议,我最终选择了这个简单的子类。我将他的答案标记为正确,因为a)他建议了这种方法,我想给他荣誉,b)它有更多关于使用 CIFilterConstructor 注册过滤器的一般使用信息。

有用的参考资料: - Apple Docs -相关问题 -免费 Core Image 电子书

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") }
}
于 2019-04-08T20:11:23.427 回答
2

在难以或不可能将多个CIFilter调用“链接”在一起以达到预期效果的情况下 - 可能是由于具有单个属性的类,克服此问题的一种方法是执行以下操作:

  • 子类CIFilter,覆盖你需要的一切。这可能包括attributessetValue(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)])
    }
}

如果您希望公开更多属性,您可以简单地将它们添加到attributessetValue(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我相信你可以让它更安全 - 但请放心,我已经测试过它并且它有效。(我创建了这个自定义过滤器并将其替换为不会发生强制展开的应用程序。)

于 2019-04-08T12:33:35.253 回答