iOSやmacOSで画像を加工しようとした場合、Core Image frameworkを使うのが簡単だ。画像をハードウェアの支援で高速に処理でき、内蔵された様々なフィルターを使うこともできる。Mac OS X 10.4で初めて搭載されて以来、しっかりとアップデートされ続けている。
2019年のiOS 13やmacOS 10.15では、Core Imageの色々なフィルターをSwiftから扱いやすくなった。
CIFilter APIの変遷
最初期は以下のように、Key-Value Codingを活用したAPIだった。もともとCore Image frameworkは、GUIでユーザーに操作させることを想定しており、文字列などから動的に扱えるように作られている。(あるいは組み込みではないフィルターがインストールされている場合もあり、いずれにしてもKVCは有用である。)反面で、フィルター名やフィルターとパラメータの対応に気を配る必要がある。
import CoreImage let image: CIImage = ... guard let filter = CIFilter(name: "CIGaussianBlur") else { fatalError() } filter.setValue(20, forKey: kCIInputRadiusKey) filter.setValue(image, forKey: kCIInputImageKey) guard let processed = filter.value(forKey: kCIOutputImageKey) as? CIImage else { fatalError() } let context = CIContext() context.createCGImage(processed, from: processed.extent)
iOS 8のタイミングで、KVCではないAPIも整備され、CIFilter.init(name:parameters:)
やCIImage.outputImage
を使って、以下のように書けるようになった。
guard let filter = CIFilter(name: "CIGaussianBlur", parameters: [ kCIInputRadiusKey: 20, kCIInputImageKey: image, ]) else { fatalError() } guard let processed = filter.outputImage else { fatalError() }
さらにこれのショートカットで、CIImage.applyingFilter(_:parameters:)
メソッドを使い、以下のようにも書ける。見た目はかなりよくなったが、ガウシアンぼかしのために"CIGaussianBlur"
フィルターを使って、パラメータとしてkCIInputRadiusKey
を与える、ということは知らなければならない。
let processed = image.applyingFilter("CIGaussianBlur", parameters: [ kCIInputRadiusKey: 20, ])
iOS 10の頃にはCIImage.applyingGaussianBlur(sigma:)
メソッドなどが追加され、いくつかの基本的なフィルターが容易に利用可能になった。
let processed = image.applyingGaussianBlur(sigma: 20)
CIFilterBuiltins
iOS 13やmacOS 10.15から、新たにCIFilter
にたくさんのクラスメソッドが追加された。このうちCIFilter.gaussianBlur()
を使えば、これまでと同じ処理を以下のように書ける。
import CoreImage import CoreImage.CIFilterBuiltins let image: CIImage = ... let filter = CIFilter.gaussianBlur() filter.radius = 20 filter.inputImage = image guard let processed = filter.outputImage else { fatalError() } let context = CIContext() context.createCGImage(processed, from: processed.extent)
クラスメソッドのシグネチャがclass func gaussianBlur() -> CIFilter & CIGaussianBlur
になっているので、型を利用して簡単に扱えるようになっている。このようなクラスメソッドが、組み込みのフィルターそれぞれに用意されている。
import CoreImage.CIFIlterBuiltins
を忘れやすいので注意が必要だ。Core Imageのmodulemapをみると、以下のようになっている。
framework module CoreImage [extern_c] { umbrella header "CoreImage.h" export * module * { export * } explicit module CIFilterBuiltins { header "CIFilterBuiltins.h" export * } }
まとめ
Core ImageのAPIは徐々に改良が加えられている。
ユースケースに応じて異なるAPIを使うのがよいだろう。単純にガウシアンぼかしを掛けたいのであれば、CIImage.applyingGaussianBlur(sigma:)
が最も簡単である。こういったショートカットが用意されていない組み込みのフィルターを利用するなら、CIFilterBuiltinsがよい。組み込みではないフィルターを利用するような場合は、必然的にCIImage.applyingFilter(_:parameters:)
メソッドやKVCを使うことになる。