如何将 CIFilter 应用于 UIView?
How to apply CIFilter to UIView?
根据 Apple docs,
CALayer
的过滤器 属性 在 iOS
中不受支持。因为我使用了一个将 CIFilter
应用到 UIView
的应用程序,即 Splice,Funimate 和 artisto 的视频编辑器 Videoshow FX。这意味着我们可以将 CIFilter
应用于 UIView
。
我已经使用了 SCRecorder
库并尝试通过 SCPlayer
和 SCFilterImageView
完成这项任务。但是我在应用 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!)
}
根据 Apple docs,
CALayer
的过滤器 属性 在 iOS
中不受支持。因为我使用了一个将 CIFilter
应用到 UIView
的应用程序,即 Splice,Funimate 和 artisto 的视频编辑器 Videoshow FX。这意味着我们可以将 CIFilter
应用于 UIView
。
我已经使用了 SCRecorder
库并尝试通过 SCPlayer
和 SCFilterImageView
完成这项任务。但是我在应用 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!)
}