代码之家  ›  专栏  ›  技术社区  ›  Jory de Kort

在CALayer上使用自定义CIFilter显示CALayer没有变化

  •  1
  • Jory de Kort  · 技术社区  · 4 年前

    我们正在尝试创建自定义 CIFilter 添加到我们的 CALayer's. 为什么只有默认的CIFilters似乎在 CALayer.

    我们在 ViewController.swift 我们补充道:

    import Cocoa
    import CoreImage
    
    class ViewController: NSViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // Create some layers to work with! (square with gradient color)
            let mainLayer = CALayer()
            let shapeLayer = CAShapeLayer()
            let gradientLayer = CAGradientLayer()
            gradientLayer.colors = [NSColor.red.cgColor, NSColor.white.cgColor, NSColor.yellow.cgColor, NSColor.black.cgColor]
            
            shapeLayer.path = CGPath(rect: CGRect(x: 0, y: 0, width: 500, height: 500), transform: nil)
            shapeLayer.fillColor = CGColor.black
            
            gradientLayer.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
            gradientLayer.mask = shapeLayer
            
            gradientLayer.setAffineTransform(CGAffineTransform(translationX: 50, y: 50))
            mainLayer.addSublayer(gradientLayer)
            
            mainLayer.filters = []
            self.view.layer?.addSublayer(mainLayer)
    
            // Register the custom filter
            CustomFilterRegister.register()
            
            // Test with a normal image file, WORKS!
    //      if let image = NSImage(named: "test"), let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
    //          if let filter = CIFilter(name: "CustomFilter") {
    //              filter.setValue(CIImage(cgImage: cgImage), forKey: kCIInputImageKey)
    //              let output = filter.outputImage
    //              // WORKS! Image filtered as expected!
    //          }
    //      }
            
            // Does NOT work. No change in color of the layer!
            if let filter = CIFilter(name: "CustomFilter") {
                filter.name = "custom"
                mainLayer.filters?.append(filter)
            }
    
            // This works: mainLayer and sublayers are blurred!
    //      if let filter = CIFilter(name: "CIGaussianBlur") {
    //          filter.name = "blur"
    //          mainLayer.filters?.append(filter)
    //      }
    
    
        }
    }
    }
    

    我们创建了一个简单的自定义 CIFilter 在我们开始建立自己的习惯之前先试试 CIFilter.

    class CustomFilter: CIFilter {
        
        // Error in xcode if you don't add this in!
        override class var supportsSecureCoding: Bool {
            return true
        }
            
        @objc dynamic var inputImage: CIImage?
        @objc dynamic var inputSaturation: CGFloat = 1
        @objc dynamic var inputBrightness: CGFloat = 0
        @objc dynamic var inputContrast: CGFloat = 1
        override func setDefaults() {
            inputSaturation = 1
            inputBrightness = 0
            inputContrast = 2
        }
        
        override public var outputImage: CIImage? {
            guard let image = inputImage else {
                return nil
            }
            return image.applyingFilter("CIPhotoEffectProcess")
                .applyingFilter("CIColorControls", parameters: [
                    kCIInputSaturationKey: inputSaturation,
                    kCIInputBrightnessKey: inputBrightness,
                    kCIInputContrastKey: inputContrast
                ])
        }
    }
    
    class CustomFilterRegister: CIFilterConstructor {
        static func register() {
            CIFilter.registerName(
                "CustomFilter", constructor: CustomFilterRegister(),
                classAttributes: [
                    kCIAttributeFilterCategories: [kCICategoryBlur, kCICategoryVideo, kCICategoryStillImage]
                ])
        }
        func filter(withName name: String) -> CIFilter? {
            switch name {
            case "CustomFilter":
                return CustomFilter()
            default:
                return nil
            }
        }
    }
    

    在ViewController中,我们添加了代码来测试普通图像。这确实有效,所以过滤器似乎没问题。我们还尝试了默认设置 CIGaussianBlur 这确实对 卡拉耶。

    我们不知道需要什么才能获得定制 CIFilter 与合作 CALayer, 似乎找不到任何相关信息。

    请注意,我们不是在寻找这种类型的 CIFilter 或者以不同的方式获得过滤器结果。我们需要一个定制 CIFilter 在a上工作 卡拉耶。

    0 回复  |  直到 4 年前
        1
  •  3
  •   DonMag    4 年前

    我假设你在代码中没有显示的地方做了这件事:

    self.view.wantsLayer = true
    

    但你也会想这样做:

    self.view.layerUsesCoreImageFilters = true
        
    

    结果 没有 这条线:

    enter image description here

    结果 具有 这条线:

    enter image description here

    (不管怎样,不要问我为什么“CIGaussianBlur”有效……)


    编辑 -我用来产生上述输出的确切代码:

    import CoreImage
    
    class ViewController: NSViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.view.wantsLayer = true
            self.view.layerUsesCoreImageFilters = true
            
            // Create some layers to work with! (square with gradient color)
            let mainLayer = CALayer()
            let shapeLayer = CAShapeLayer()
            let gradientLayer = CAGradientLayer()
            gradientLayer.colors = [NSColor.red.cgColor, NSColor.white.cgColor, NSColor.yellow.cgColor, NSColor.black.cgColor]
            
            shapeLayer.path = CGPath(rect: CGRect(x: 0, y: 0, width: 500, height: 500), transform: nil)
            shapeLayer.fillColor = CGColor.black
            
            gradientLayer.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
            gradientLayer.mask = shapeLayer
            
            gradientLayer.setAffineTransform(CGAffineTransform(translationX: 50, y: 50))
            mainLayer.addSublayer(gradientLayer)
            
            mainLayer.filters = []
            self.view.layer?.addSublayer(mainLayer)
    
            // Register the custom filter
            CustomFilterRegister.register()
            
            let t = 2
            
            if t == 1 {
                // Test with a normal image file, WORKS!
                if let image = NSImage(named: "test"), let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
                    if let filter = CIFilter(name: "CustomFilter") {
                        filter.setValue(CIImage(cgImage: cgImage), forKey: kCIInputImageKey)
                        let output = filter.outputImage
                        // WORKS! Image filtered as expected!
                        print()
                    }
                }
            }
            
            else if t == 2 {
                // 
                // Does NOT work. No change in color of the layer!
                // 
                // This NOW works for me
                // 
                if let filter = CIFilter(name: "CustomFilter") {
                    filter.name = "custom"
                    mainLayer.filters?.append(filter)
                }
                
            } else {
                
                // This works: mainLayer and sublayers are blurred!
                if let filter = CIFilter(name: "CIGaussianBlur") {
                    filter.name = "blur"
                    mainLayer.filters?.append(filter)
                }
                
            }
            
        }
    }
    
    class CustomFilter: CIFilter {
        
        // Error in xcode if you don't add this in!
        override class var supportsSecureCoding: Bool {
            return true
        }
        
        @objc dynamic var inputImage: CIImage?
        @objc dynamic var inputSaturation: CGFloat = 1
        @objc dynamic var inputBrightness: CGFloat = 0
        @objc dynamic var inputContrast: CGFloat = 1
        override func setDefaults() {
            inputSaturation = 1
            inputBrightness = 0
            inputContrast = 2
        }
        
        override public var outputImage: CIImage? {
            guard let image = inputImage else {
                return nil
            }
            return image.applyingFilter("CIPhotoEffectProcess")
                .applyingFilter("CIColorControls", parameters: [
                    kCIInputSaturationKey: inputSaturation,
                    kCIInputBrightnessKey: inputBrightness,
                    kCIInputContrastKey: inputContrast
                ])
        }
    }
    
    class CustomFilterRegister: CIFilterConstructor {
        static func register() {
            CIFilter.registerName(
                "CustomFilter", constructor: CustomFilterRegister(),
                classAttributes: [
                    kCIAttributeFilterCategories: [kCICategoryBlur, kCICategoryVideo, kCICategoryStillImage]
                ])
        }
        func filter(withName name: String) -> CIFilter? {
            switch name {
            case "CustomFilter":
                return CustomFilter()
            default:
                return nil
            }
        }
    }
    

    编辑

    奇怪的是,如果我添加一个计数器var和 print() 这样的陈述:

    var applyCount: Int = 0
    
    override public var outputImage: CIImage? {
        print("getting outputImage...")
        guard let image = inputImage else {
            return nil
        }
        applyCount += 1
        print("apply", applyCount)
        return image.applyingFilter("CIPhotoEffectProcess")
            .applyingFilter("CIColorControls", parameters: [
                kCIInputSaturationKey: inputSaturation,
                kCIInputBrightnessKey: inputBrightness,
                kCIInputContrastKey: inputContrast
            ])
    }
    

    在macOS 10.15.4/XXcode 12.4上,我在调试控制台中得到以下结果:

    getting outputImage...
    apply 1
    getting outputImage...
    apply 2
    getting outputImage...
    apply 3
    getting outputImage...
    apply 4
    getting outputImage...
    apply 5
    getting outputImage...
    apply 6
    getting outputImage...
    apply 7
    getting outputImage...
    apply 8
    getting outputImage...
    apply 9
    getting outputImage...
    apply 10
    getting outputImage...
    apply 11
    getting outputImage...
    apply 12
    getting outputImage...
    apply 13
    getting outputImage...
    apply 14
    getting outputImage...
    apply 15
    getting outputImage...
    apply 16
    

    (例如,当窗口改变大小时,它会继续被重复调用)。

    但是,在macOS 11.4/Xcode 12.5.1上运行时,我得到 没有什么 在调试控制台中。。。 outputImage 从未被请求?

        2
  •  2
  •   Jory de Kort    3 年前

    正如@DonMag所指出的那样,它应该与他所描述的变化相一致。多么不幸的是,我们今天收到了苹果的回复;

    此时,有一个错误阻止CALayer上的自定义CIFilters工作。目前还没有解决此错误的方法。

    当我们提交bug时,我会在这里为感兴趣的人添加链接。但此时,您无法在macOS 11上向CALayer添加自定义CIFilter。

    让我们希望他们能为所有阅读本文的人解决这个问题。


    编辑 :

    那么坏消息。。。目前在macOS 12.2.1上,它仍然存在同样的问题,根据我们的工单没有发生任何事情。苹果似乎不想解决这个问题。对于那些正在寻找的人:这仍然不适用于 CALayer 即使有其他答案中描述的所有选项。内置 CIFilter 按预期工作。

    请注意,使用相同的自定义 CIFilter 在a CALayer 对于导出使用 AVVideoCompositionCoreAnimationTool 工作!