Swift 4,Subclassing CIFilter仅与"输入"崩溃实例变量

时间:2017-09-22 03:33:02

标签: swift core-image swift4 cifilter

你现在如何将CIFilter子类化?在 Swift 3 中我可以做一个简单的例子:

class CustomFilter: CIFilter {
   var inputImage: CIImage?
   var inputOrigin: CIVector?
   var inputAnotherVar: String?
}

但是在 Swift 4 中,我得到了一个N​​SException。如果我删除"输入"从每个变量它工作正常。我可以这样做。但我觉得我错过了一些重要的东西,而且我似乎无法找到解释这种行为的任何东西。

这在 Swift4

中编译得很好
class CustomFilter: CIFilter {
   var image: CIImage?
   var origin: CIVector?
   var anotherVar: String?
}

这是游乐场中的错误:

enter image description here

2 个答案:

答案 0 :(得分:3)

我在Swift 4中遇到了这个问题(同样的“错误:执行被中断,原因:EXC_BAD_INSTRUCTION ...”),同时试验了Simon Gladman的“Swift核心图像”。我还尝试在应用程序而不是操场中运行示例代码。我的解决方案是在@objc dynamic前添加var inputImage: CIImage?在您的代码中,它看起来像这样:

class CustomFilter: CIFilter {
    @objc dynamic var inputImage: CIImage?
    var inputOrigin: CIVector?
    var inputAnotherVar: String?
}

据我了解,这是因为默认情况下Swift 4最小化推理以减少二进制代码大小。相比之下,Swift 3隐含地推断了Objc属性。这在实践中意味着,我必须将@objc dynamic添加到将利用Objective-C的动态分派的某些变量,例如设置CoreImage过滤器时:filter.setValue(inputImage, forKey: kCIInputImageKey)。以下是一些描述Swift's static dispatch using Swift4 when dealing with Obj-C API's that rely on dynamic dispatch类似问题的资源,以及migrate from Swift 3 to 4时如何处理调度问题。

答案 1 :(得分:2)

基于这些评论,这里有一些构建和执行的Swift 4代码(与Swift 3不变)。我没有看到你的问题在哪里,所以如果这对你没有帮助,请对它进行评论,我会删除它。 (如果它 帮助,我会编辑我的答案更具体!)

第一个CIFilter使用CIColorInvertCIHeightFieldFromMask根据UILabel中的文字创建“文字掩码”。它还overrides outputImage CIFilter属性CIFilter。第二个CIKernel实际上是CIImage周围的“包装”,inputImageinputMask,掩码(来自第一个过滤器)为outputImage,也像第一个一样覆盖public class Mask: CIFilter { public var inputExtent:CGRect? var inputRadius: Float = 15 { didSet { if oldValue != inputRadius { refractingImage = nil } } } private var refractingImage: CIImage? private var rawTextImage: CIImage? override public var outputImage: CIImage! { if refractingImage == nil { generateRefractingImage() } let mask = refractingImage?.applyingFilter("CIColorInvert", parameters: [:]) return mask } func generateRefractingImage() { let label = UILabel(frame: inputExtent!) label.text = "grand canyon" label.font = UIFont.boldSystemFont(ofSize: 300) label.adjustsFontSizeToFitWidth = true label.textColor = UIColor.white UIGraphicsBeginImageContextWithOptions( CGSize(width: label.frame.width, height: label.frame.height), true, 1) label.layer.render(in: UIGraphicsGetCurrentContext()!) let textImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() rawTextImage = CIImage(image: textImage!)! refractingImage = CIFilter(name: "CIHeightFieldFromMask", withInputParameters: [ kCIInputRadiusKey: inputRadius, kCIInputImageKey: rawTextImage!])?.outputImage? .cropped(to: inputExtent!) } }

几乎所有这些代码都是由Simon Gladman从Core Image for Swift解除的,现在可以作为免费的iBook使用。虽然这本书是用Swift 2编写的,但我发现它是使用Core Image的宝贵资源。

(旁注:这本书结合了所有这些。当我正在努力将其作为水印应用到现有的应用程序时,我将事情分开。我最终走了一条不同的路线!)

Mask.swift

public class Refraction: CIFilter {
    public var inputImage: CIImage?
    public var inputMask:CIImage?

    var inputRefractiveIndex: Float = 4.0
    var inputLensScale: Float = 50
    public var inputLightingAmount: Float = 1.5

    var inputLensBlur: CGFloat = 0
    public var inputBackgroundBlur: CGFloat = 2

    var inputRadius: Float = 15

    override public func setDefaults()
    {
        inputRefractiveIndex = 4.0
        inputLensScale = 50
        inputLightingAmount = 1.5
        inputRadius = 15
        inputLensBlur = 0
        inputBackgroundBlur = 2
    }

    override public var outputImage: CIImage! {
        guard let inputImage = inputImage, let refractingKernel = refractingKernel else {
            return nil
        }

        let extent = inputImage.extent
        let arguments = [inputImage,
                         inputMask!,
                         inputRefractiveIndex,
                         inputLensScale,
                         inputLightingAmount] as [Any]
        return refractingKernel.apply(extent: extent,
                                      roiCallback: {
                                        (index, rect) in
                                        return rect
        },
                                      arguments: arguments)!
    }

    let refractingKernel = CIKernel(source:
        "float lumaAtOffset(sampler source, vec2 origin, vec2 offset)" +
            "{" +
            " vec3 pixel = sample(source, samplerTransform(source, origin + offset)).rgb;" +
            " float luma = dot(pixel, vec3(0.2126, 0.7152, 0.0722));" +
            " return luma;" +
            "}" +


            "kernel vec4 lumaBasedRefract(sampler image, sampler refractingImage, float refractiveIndex, float lensScale, float lightingAmount) \n" +
            "{ " +
            " vec2 d = destCoord();" +

            " float northLuma = lumaAtOffset(refractingImage, d, vec2(0.0, -1.0));" +
            " float southLuma = lumaAtOffset(refractingImage, d, vec2(0.0, 1.0));" +
            " float westLuma = lumaAtOffset(refractingImage, d, vec2(-1.0, 0.0));" +
            " float eastLuma = lumaAtOffset(refractingImage, d, vec2(1.0, 0.0));" +

            " vec3 lensNormal = normalize(vec3((eastLuma - westLuma), (southLuma - northLuma), 1.0));" +

            " vec3 refractVector = refract(vec3(0.0, 0.0, 1.0), lensNormal, refractiveIndex) * lensScale; " +

            " vec3 outputPixel = sample(image, samplerTransform(image, d + refractVector.xy)).rgb;" +

            " outputPixel += (northLuma - southLuma) * lightingAmount ;" +
            " outputPixel += (eastLuma - westLuma) * lightingAmount ;" +

            " return vec4(outputPixel, 1.0);" +
        "}"
    )
}

<强> Refraction.swift

let filterMask = Mask()
let filter = Refraction()
var imgOriginal:CIImage!
var imgMask:CIImage!
var imgEdited:CIImage!

// I have a set of sliders that update a tuple and send an action that executes the following code

filterMask.inputRadius = sliders.valuePCP.3
imgMask = filterMask.outputImage
filter.inputMask = imgMask
filter.inputRefractiveIndex = sliders.valuePCP.0
filter.inputLensScale = sliders.valuePCP.1
filter.inputLightingAmount = sliders.valuePCP.2
imgEdited = filter.outputImage

<强>用法

SELECT months.id, COUNT(clients.id) as total FROM `months` LEFT JOIN `clients` ON  months.id = MONTH(created_at) GROUP BY months.id;

希望这有帮助!