swift - 将 UIBezierPath 变成蒙版?
问题描述
不确定我是否正确地问了这个问题,但我有两个组成部分;一个CIImage
和一个UIBezierPath
。理想情况下,我想创建一个CGRect
封装我的UIBezierPath
; 路径内的一切都是白色的,路径外的一切都是黑色的。这样,我可以将其渲染CGRect
为某种图像,然后我可以将其用作其他目的的蒙版。
我正在努力弄清楚如何以性能为重点来做到这一点。如下所述,我的测试利用UIGraphicsImageRenderer
了对于我的需求来说太慢的使用(我将在相机的样本缓冲区上执行此操作)。因此,我想坚持下去CoreImage
。这是我的尝试;
// Path
let path = UIBezierPath()
// ... define the path's shape and close it
// My source image
let image = CIImage(cgImage: UIImage(named: "test.jpg")!.cgImage!)
// Renderer
let renderer = UIGraphicsImageRenderer(size: image.extent.size)
// Render path as mask
let img = renderer.image { ctx in
ctx.cgContext.setFillColor(UIColor.black.cgColor)
ctx.cgContext.fill(CGRect(x: 0, y: 0, width: image.extent.size.width, height: image.extent.size.height))
ctx.cgContext.setFillColor(UIColor.white.cgColor)
ctx.cgContext.addPath(path.cgPath)
ctx.cgContext.drawPath(using: .fill)
}
// Put a filter on the image
let imageFiltered = image.applyingFilter("CIPhotoEffectNoir")
// Blend with mask
let maskFilter = CIFilter.blendWithMask()
maskFilter.inputImage = imageFiltered
maskFilter.backgroundImage = image
maskFilter.maskImage = CIImage(cgImage: img.cgImage!)
// Output
if let output = maskFilter.outputImage {
... use CIContext() to render back to CVPixelBuffer for preview on MTKView.
}
总体而言,目标是定义图像的一部分(不符合正方形或圆形等传统形状),将使用 CIFilter 过滤,然后在原始图像上合成。如果有更好的方法(例如以某种方式获取原始图像,对其进行过滤,将其裁剪到路径(使路径之外的所有内容透明)并进行合成,那可能会更好。
需要注意的是,上面的示例代码会导致崩溃,因为UIGraphicsImageRenderer
无法以足够快的速度渲染蒙版。
解决方案
到目前为止,您的方法看起来不错。我认为缓慢的部分是使用 Core Graphics 生成掩码图像。不幸的是,没有直接的方法可以直接(在 GPU 上)对 Core Image 做同样的事情。但是,您可以尝试以下方法:
(假设您之前的问题中路径始终具有特定的形状,)您可以针对您选择的特定参考尺寸生成一个包含路径的蒙版图像。确保路径不会“接触”边界。
然后,当您想将其用作蒙版时,使用变换将形状图像移动并缩放到正确的位置,并使其边缘无限延伸(以覆盖整个底层图像;这就是形状不应接触边缘的原因)。像这样的东西:
let pathImage = CIImage(cgImage: img.cgImage!)
// scale path to the size of the area you want to mask
var mask = pathImage.transformed(by: CGAffineTransform(scaleX: scaleX, y: scaleY))
// move path to the place you want to cover
mask = mask.transformed(by: CGAffineTransform(translationX: offsetX, y: offsetY))
// let mask fill the rest of the area
mask = mask.clampedToExtent()
// use mask as maskImage...
您应该能够回收pathImage
每一帧,从而避免核心图形和 CPU-GPU 同步。
推荐阅读
- linux - 多次重复每一行并添加升序数字
- swift - Realm 和 UserDefaults - 应用程序版本和更新
- python - QItemDelegate 跨列 QCalendarWidget 的呈现方式不同
- android - 输入两个值后,如何在第三个编辑文本中自动显示两个编辑文本值的结果?
- swift - Subscriber returning value before Firebase returns a value in SwiftUI
- neo4j - NestJS / TypeOrm / Neo4j :Nest 无法解析 NEO4J_DRIVER 的依赖关系
- apache-spark - 是否有可能以及如何读取镶木地板文件以将列作为字符串数据类型?
- css - @extend 不适用于不同浏览器的拇指伪类
- cassandra - 动态生成 Casandra CQL 查询
- android - 视差壁纸应用程序屏幕对设备唤醒的影响