Пользовательский фильтр Core Image и "sig abrt" в Xcode 9.x
Я пишу код. Вот мой полный исходный код.
Я подтвердил, что мой код успешно работает в Xcode 8.3.3.
Однако мой код потерпел крах в Xcode 9.x (9.1 и 9.2).
Точно, мой код потерпел крах в "filter.setValue(inputCIImage, forKey: kCIInputImageKey)" с "NSException (sig abrt)"
Я не нашел причину, хотя я использовал отладчик.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
let inputImage = UIImage(named: "testImage.png")
override func viewDidLoad() {
super.viewDidLoad()
let inputCIImage = CIImage(image: inputImage!)
let filter = CustomFilter()
filter.setValue(inputCIImage, forKey: kCIInputImageKey)
let outputImage = filter.outputImage!
let context = CIContext()
let outputCGImage = context.createCGImage(outputImage, from: outputImage.extent)
imageView.image = UIImage(cgImage: outputCGImage!)
}
}
class CustomFilter: CIFilter {
var inputImage: CIImage?
override public var outputImage: CIImage! {
get {
if let inputImage = self.inputImage {
let args = [inputImage as AnyObject]
return createCustomKernel().apply(extent: inputImage.extent, arguments: args)
} else {
return nil
}
}
}
func createCustomKernel() -> CIColorKernel {
let kernelString =
"kernel vec4 chromaKey(__sample s){\n" +
"vec4 newPixel = s.rgba;\n" +
"newPixel[0] = 0.0;\n" +
"newPixel[2] = newPixel[2] / 2.0;\n" +
"return newPixel;\n" + "}"
return CIColorKernel(source: kernelString)!
}
}
1 ответ
Единственный способ, которым я смог использовать setValue(forKey:)
это на самом деле зарегистрировать мой пользовательский фильтр. Конечно, я делал это только в приложении Swift 4, но я довольно удивлен, что это сработало в Swift 3.
Имейте в виду, что `setValue(forKey:) синтаксически допустим - то есть он будет собираться - когда CoreImage попытается выполнить ваш фильтр, возникнут любые ошибки.
Я думаю, у вас есть два варианта:
(1) Легче всего изменить способ передачи входного изображения (именно так я и делал со времен Swift 2). Попробуйте заменить эту строку на это:
filter.inputImage = inputCIImage
(2) Зарегистрируйте свой фильтр. В вашем CustomFilter
класс, добавьте это:
var inputImage: CIImage!
override var attributes: [String : Any] {
return [
kCIAttributeFilterDisplayName: "My custom filter",
"inputImage": [kCIAttributeIdentity: 0,
kCIAttributeClass: "CIImage",
kCIAttributeDisplayName: "Image",
kCIAttributeType: kCIAttributeTypeImage]
]
}
Далее подкласс CIFilterConstructor
:
class CustomFilters: NSObject, CIFilterConstructor {
static func registerFilters() {
CIFilter.registerName(
"My custom filter",
constructor: CustomFilters(),
classAttributes: [
kCIAttributeFilterCategories: [CategoryCustom]
])
}
func filter(withName name: String) -> CIFilter? {
switch name {
case "My custom filter":
return CustomFilter()
default:
return nil
}
}
}
Наконец, в коде приложения сделайте две вещи:
(A) Зарегистрируйте свой фильтр. Я обычно делаю это в viewDidLoad
:
CustomFilters.RegisterFilters()
(B) Создайте свой фильтр, назвав его по имени:
let filter = CIFilter(name: "My custom filter")