你现在如何将CIFilter子类化?在 Swift 3 中我可以做一个简单的例子:
class CustomFilter: CIFilter {
var inputImage: CIImage?
var inputOrigin: CIVector?
var inputAnotherVar: String?
}
但是在 Swift 4 中,我得到了一个NSException。如果我删除"输入"从每个变量它工作正常。我可以这样做。但我觉得我错过了一些重要的东西,而且我似乎无法找到解释这种行为的任何东西。
这在 Swift4 :
中编译得很好class CustomFilter: CIFilter {
var image: CIImage?
var origin: CIVector?
var anotherVar: String?
}
这是游乐场中的错误:
答案 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
使用CIColorInvert
和CIHeightFieldFromMask
根据UILabel
中的文字创建“文字掩码”。它还overrides
outputImage
CIFilter
属性CIFilter
。第二个CIKernel
实际上是CIImage
周围的“包装”,inputImage
为inputMask
,掩码(来自第一个过滤器)为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;
希望这有帮助!