【发布时间】:2020-12-03 20:50:58
【问题描述】:
我一直在寻找 UIVisualEffectView 模糊效果的替代品,让我可以改变模糊半径。我考虑过使用 Core Image 过滤器自己创建变量模糊。但是,我对核心图像过滤器有点不习惯。 (我最后一次使用它们是在 Objective-C 中。)
我在 SO 上找到了这个答案,它提供了 UIView 的扩展,它捕获视图及其子视图的合成内容,生成模糊版本,并将其作为图像视图添加到视图顶部:https://stackoverflow.com/a/56521521/205185
我决定将其修改为 UIView 的自定义子类,在视图层的顶部添加一个模糊层。
结果是模糊层的内容大多是透明的,并没有很模糊底层视图。我在视图中添加了一个图像视图,它的内容似乎一点也不模糊。
Here is a link 我创建的项目。
当我生成模糊图像时,我将它安装为视图层顶部的层内容,并将其复制到下面的单独图像视图中。单独的图像视图看起来与我想要的结果完全一样,但是顶部图层的视图几乎没有可见的变化。大多数情况下,下面的原始图像显示出来。
原始合成视图如下所示:
在下面的屏幕截图中,顶部图像是顶部带有模糊层(模糊半径 10)的合成图像,底部图像是安装在单独图像视图中的模糊输出:
您可以从图像视图版本中看到,模糊图像是完全不透明的。绿色背景随处可见。视图控制器的白色背景都没有渗出。然而,在顶部带有模糊层的顶部自定义视图中,文本的清晰边缘以及图像视图和蓝色框视图上的边框仍然可见。 BlurView 顶部有模糊层的外观几乎没有改变。这是为什么呢?
BlurView 类中的两个关键函数如下:
func applyBlur() {
let context = CIContext(options: nil)
self.makeBlurredImage(with: blurLevel, context: context, completed: { processedImage in
self.blurLayer.contents = processedImage.cgImage
self.updateBlurImage?(processedImage)
})
}
private func makeBlurredImage(with level: CGFloat, context: CIContext, completed: @escaping (UIImage) -> Void) {
// screen shot
layer.isOpaque = true
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let beginImage = CIImage(image: resultImage)
//Clamp the image
guard let clampFilter = CIFilter(name: "CIAffineClamp") else {
fatalError()
}
clampFilter.setValue(beginImage, forKey: kCIInputImageKey)
clampFilter.setValue(CGAffineTransform.identity, forKey: kCIInputTransformKey)
var output = clampFilter.outputImage
let blurFilter = CIFilter(name: "CIGaussianBlur")!
blurFilter.setValue(level, forKey: kCIInputRadiusKey)
blurFilter.setValue(output, forKey: kCIInputImageKey)
let cropFilter = CIFilter(name: "CICrop")!
cropFilter.setValue(blurFilter.outputImage, forKey: kCIInputImageKey)
cropFilter.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")
output = cropFilter.outputImage
var cgimg: CGImage?
var extent: CGRect?
let global = DispatchQueue.global(qos: .userInteractive)
global.async {
extent = output!.extent
cgimg = context.createCGImage(output!, from: extent!)!
let processedImage = UIImage(cgImage: cgimg!)
DispatchQueue.main.async {
completed(processedImage)
}
}
}
makeBlurredImage() 函数异步运行,并在模糊图像可用时调用闭包。
applyBlur() 函数调用makeBlurredImage(),它传递的闭包将生成的模糊图像安装在位于 BlurView 内容层之上的层中。
我希望 BlurView 的外观与下面的图像视图的外观完全相同。我被难住了。
【问题讨论】:
标签: ios swift calayer core-image