2017-09-22 10 views
1

どのようにCIFilterを今すぐサブクラス化しますか? スウィフト3では、私は簡単な例として、これを行うことができます:Swift 4、サブクラスCIFilterは "入力"インスタンス変数でのみクラッシュします

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

しかしスウィフト4に私がNSExceptionを取得します。私は各変数から "入力"を削除する場合、それは正常に動作します。私はちょうどそれを行うことができます。しかし、私は何か重要なことを逃しているように感じ、私はこの行動を説明するものを見つけることができないようです。

これはSwift4で罰金コンパイル:

class CustomFilter: CIFilter { 
    var image: CIImage? 
    var origin: CIVector? 
    var anotherVar: String? 
} 

ここではプレイグラウンドでのエラーです:コメントに基づいて

enter image description here

+0

あなたはいくつかのコードが不足しているように見えます(私に)。なぜ、 'inputImage'は' CIVector'で、何らかのイメージではありません(おそらく 'CIImage')?それが問題ではない場合、おそらく 'CustomFilter'を作るためのコードをもっと提供することができますか? – dfd

+0

ありがとうございました!名前が間違っていたのは間違いありません。しかし私は、その意味をより明確にするために質問を再編集しました。 –

+0

まだちょっと混乱しているかもしれませんが、私は* CIFilter'や 'CIKernel'を3通り使っています - そのうちの1つだけが' CIFilter'をサブクラス化する必要があります。私は自分のコード(Swift 3と4の両方)と - 例えば 'public var inputImage:CIImage? 'をチェックしました。私のクラス 'public'(それはフレームワークターゲットの一部です)を宣言する以外に、私はなぜあなたが問題を抱えているのか見ていません。ビルドエラーが発生していますか?ランタイムエラー? – dfd

答えて

1

は、ここスウィフト3からいくつかのスウィフト4コード(そのままです両方ともビルドして実行します)。私はあなたの問題がどこにあるか見ていないので、これがあなたを助けないなら、コメントして、私はそれを削除します。 (それヘルプがない場合、私はより具体的には私の答えを編集しましょう!)

最初CIFilterUILabel内のテキストをもとに、「テキストマスク」を作成するCIColorInvertCIHeightFieldFromMaskを使用しています。またoverrides プロパティはCIFilterです。第2のCIFilterは、実際には、CIImageとしてCIImageCIKernelの周りの「ラッパー」とし、inputMaskというマスク(最初のフィルタのマスク)と、最初のものと同じようにoutputImageを上書きします。

このコードのほぼすべては、Simon GladmanによってCore Image for Swiftから取り除かれました。現在、iBookとして無料で提供されています。この本はSwift 2で書かれていましたが、Core Imageを扱うための貴重なリソースとなっています。

(サイドノート:。。!本は、私が透かしとして、既存のアプリにこれを適応させるに取り組んでいたとして、私は物事を分割し、このすべてを兼ね備えた、私は別のルートを行くことになった)

マスク。迅速

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!) 
    } 
} 

Refraction.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);" + 
     "}" 
    ) 
} 

使用法

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 

希望します。

3

Simon Gladmanの「Core Image for Swift」を試しながら、Swift 4でこの問題に遭遇しました(同じ「エラー:実行が中断されました、理由:EXC_BAD_INSTRUCTION ...」)。私はまた、遊び場の代わりにアプリでサンプルコードを実行しようとしました。私のための解決策は、次のようになりますあなたのコードではvar inputImage: CIImage?の前で@objc dynamicを追加しました:

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

私はそれを理解したようバイナリコードサイズを小さくするように、これはデフォルトでスウィフト4は推論を最小限に抑えているので、 。対照的に、Swift 3は暗黙のうちにObjc属性を推定します。つまり、CoreImageフィルタを設定するときなど、Objective-Cの動的ディスパッチを利用する特定の変数に@objc dynamicを追加する必要があります: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の場合のディスパッチの処理方法について説明します。

+0

私は '@objc dynamic'をすべての変数の前に置いて、それをプレイグラウンドでコンパイルする必要がありました。アプリでは、私は '@objc dynamic'を使う必要はありませんでした....奇妙です。 –

関連する問題