如何将 CIFilter 应用于 UIView?

How to apply CIFilter to UIView?

根据 Apple docs, CALayer 的过滤器 属性 在 iOS 中不受支持。因为我使用了一个将 CIFilter 应用到 UIView 的应用程序,即 Splice,Funimate 和 artisto 的视频编辑器 Videoshow FX。这意味着我们可以将 CIFilter 应用于 UIView

我已经使用了 SCRecorder 库并尝试通过 SCPlayerSCFilterImageView 完成这项任务。但是我在应用 CIFilter 后播放视频时遇到黑屏问题。所以请帮助我完成这个任务,这样我就可以将 CIFilter 应用到 UIView 并且还可以通过单击 UIButton 来更改过滤器。

技术上准确的答案是 CIFilter 需要 CIImage。您可以将 UIView 转换为 UIImage,然后将其转换为 CIImage,但是所有使用图像作为输入的 CoreImage 过滤器(有些会生成新图像)都使用`CIImage 用于输入和输出。

  • 请注意 CIImage 的原点是左下角,而不是左上角。基本上 Y 轴是翻转的。
  • 如果您动态使用 CoreImage 滤镜,请学习使用 GLKView 进行渲染 - 它使用 GPU,其中 UIImageView 使用 CPU。
  • 如果您想测试过滤器,最好使用实际设备。模拟器会给你 非常 糟糕的性能。我见过一个简单的模糊处理需要将近一分钟,而在设备上只需几分之一秒!

假设您有一个 UIView,您希望对其应用 CIPhotoEffectMono。执行此操作的步骤是:

  • UIView 转换为 CIImage
  • 应用过滤器,得到 CIImage 作为输出。
  • 使用 CIContext 创建 CGImage,然后将其转换为 UIImage

这是一个 UIView 扩展,它将视图 的所有子视图转换为 UIImage:

extension UIView {
    public func createImage() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(
            CGSize(width: self.frame.width, height: self.frame.height), true, 1)
        self.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
}

UIImage 转换为 CIImage 只需一行代码:

let ciInput =  CIImage(image: myView.createImage)

这是一个将应用过滤器和 return UIImage:

的函数
func convertImageToBW(image:UIImage) -> UIImage {

    let filter = CIFilter(name: "CIPhotoEffectMono")

    // convert UIImage to CIImage and set as input

    let ciInput = CIImage(image: image)
    filter?.setValue(ciInput, forKey: "inputImage")

    // get output CIImage, render as CGImage first to retain proper UIImage scale

    let ciOutput = filter?.outputImage
    let ciContext = CIContext()
    let cgImage = ciContext.createCGImage(ciOutput!, from: (ciOutput?.extent)!)

    return UIImage(cgImage: cgImage!)
}