Sur la base des commentaires, voici un code Swift 4 (inchangé par rapport à Swift 3) qui construit et exécute à la fois. Je ne vois pas où votre problème est, donc si cela ne vous aide pas, commentez-le et je vais le supprimer. (Si elle ne aide, je vais modifier ma réponse pour être plus précis!)
Le premier CIFilter
utilise CIColorInvert
et CIHeightFieldFromMask
pour créer un « masque de texte » basé sur le texte dans un UILabel
. Il a également overrides
la propriété outputImage
de CIFilter
. La deuxième CIFilter
est en fait un «wrapper» autour d'un CIKernel
, en utilisant un CIImage
comme inputImage
, le masque (du premier filtre) comme inputMask
et remplace également outputImage
comme le premier fait.
Pratiquement tout ce code a été levé de Core Image for Swift par Simon Gladman, aujourd'hui disponible comme un iBook gratuitement. Alors que le livre a été écrit dans Swift 2, je trouve que c'est une ressource précieuse pour travailler avec Core Image.
(Note:. Le livre combine tout cela je partage des choses que je travaillais sur l'adaptation cela dans une application existante en filigrane j'ai fini par un itinéraire différent.!)
Mask. rapide
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);" +
"}"
)
}
Utilisation
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
Hope this helps!
Il me semble qu'il vous manque du code. Pourquoi exactement 'inputImage' est-il un' CIVector' et * pas * une sorte d'image (probablement 'CIImage')? Et si ce n'est pas le problème, peut-être pourriez-vous fournir plus de code sur ce qui fait 'CustomFilter'? – dfd
Merci d'avoir jeté un coup d'oeil! Vous avez raison, le nom était trompeur. Mais j'ai réédité la question pour, espérons-le, clarifier ce que je veux dire. –
Je suis peut-être un peu confus, mais j'utilise * un "CIFilter" ou un "CIKernel" de trois façons - dont une seule nécessite le sous-classement 'CIFilter'. J'ai vérifié mon code (Swift 3 et 4) et - par exemple - 'public var inputImage: CIImage?' Les deux compilations et fonctionne très bien pour moi. Au-delà de déclarer ma classe «publique» (cela fait partie d'une cible-cadre), je ne vois pas pourquoi vous avez un problème. Obtenez-vous une erreur de construction? Une erreur d'exécution? – dfd