В тех случаях, когда трудно или невозможно «связать» вместе несколько вызовов CIFilter
для достижения желаемого эффекта - возможно, из-за класса, имеющего одно свойство, один из способов преодоления этого заключается в следующем:
- Подкласс
CIFilter
, переопределяя все, что вам нужно.Это может включать attributes
, setValue(forKey:)
и, самое главное, outputImage
. - подкласс
CIFilterConstructor
и создание метода registerFilter()
.
Например,Допустим, вы хотите объединить размытие по Гауссу, а затем добавить монохромный красный тон на изображение.По сути, вы можете сделать это:
class BlurThenColor:CIFilter {
let blurFilter = CIFilter(name: "CIGaussianBlur")
override public var attributes: [String : Any] {
return [
kCIAttributeFilterDisplayName: "Blur then Color",
"inputImage": [kCIAttributeIdentity: 0,
kCIAttributeClass: "CIImage",
kCIAttributeDisplayName: "Image",
kCIAttributeType: kCIAttributeTypeImage]
]
}
override init() {
super.init()
}
@available(*, unavailable) required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func setValue(_ value: Any?, forKey key: String) {
switch key {
case "inputImage":
blurFilter?.setValue(inputImage, forKey: "inputImage")
default:
break
}
}
override public var outputImage: CIImage {
return (blurFilter?.outputImage)! .applyingFilter("CIColorMonochrome", parameters: ["inputColor": CIColor(red: 1.0, green: 0.0, blue: 0.0)])
}
}
Если вы хотите предоставить больше атрибутов, вы можете просто добавить их в переопределения attributes
и setValue(forKey:)
вдоль добавления переменных wist и setDefaults
.Здесь я просто использую значения по умолчанию.
Теперь, когда вы объединили свой эффект в один пользовательский фильтр, вы можете зарегистрировать его и использовать его:
let CustomFilterCategory = "CustomFilter"
public class CustomFilterConstructor: NSObject, CIFilterConstructor {
static public func registerFilter() {
CIFilter.registerName(
"BlurThenColor",
constructor: CustomFilterConstructor(),
classAttributes: [
kCIAttributeFilterCategories: [CustomFilterCategory]
])
}
public func filter(withName name: String) -> CIFilter? {
switch name {
case "BlurThenColor":
return BlurThenColor()
default:
return nil
}
}
}
Чтобы использовать это,просто обязательно зарегистрируйте фильтр (я стараюсь поставить мой в AppDelegate
, если это возможно):
CustomFilterConstructor.registerFilter()
Оттуда вы можете использовать BlurThenColor
, как и любой другой CIFilter
.Создайте его, используйте setValue
и позвоните outputImage
.
Обратите внимание, этот код будет аварийно завершать работу из-за принудительного развертывания inputImage
и / или опечаток.Я уверен, что вы можете сделать это более безопасно - но будьте уверены, что я проверил это, и это работает.(Я создал этот пользовательский фильтр и заменил его в приложении, в котором не выполняется принудительное развертывание.)