我正在使用显示CIImage的相当标准的MTKView
子类,目的是使用CIFilters快速更新。 draw()
函数的代码如下。
我遇到的问题是,实际上仅重绘了图像所覆盖的视图部分,在本例中为scaledImage
。这意味着,如果新图像小于前一个图像,我仍然可以看到旧图像的某些部分从后面露出来。
当所包含图像的大小发生变化时,是否有办法清除可绘制对象纹理的内容,从而不会发生这种情况?
override func draw() {
guard let image = image,
let targetTexture = currentDrawable?.texture,
let commandBuffer = commandQueue.makeCommandBuffer()
else { return }
let bounds = CGRect(origin: CGPoint.zero, size: drawableSize)
let scaleX = drawableSize.width / image.extent.width
let scaleY = drawableSize.height / image.extent.height
let scale = min(scaleX, scaleY)
let width = image.extent.width * scale
let height = image.extent.height * scale
let originX = (bounds.width - width) / 2
let originY = (bounds.height - height) / 2
let scaledImage = image
.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
.transformed(by: CGAffineTransform(translationX: originX, y: originY))
ciContext.render(
scaledImage,
to: targetTexture,
commandBuffer: commandBuffer,
bounds: bounds,
colorSpace: colorSpace
)
guard let drawable = currentDrawable else { return }
commandBuffer.present(drawable)
commandBuffer.commit()
super.draw()
}
答案 0 :(得分:0)
我有以下可行的解决方案,但由于它很笨拙,我对此不太满意,所以请有人告诉我一种更好的解决方法!
我正在做的是跟踪图像大小何时更改并设置一个名为needsRefresh
的标志。然后,在视图的draw()
函数中,检查是否设置了此标志,如果是,则从视图的clearColor
创建一个新的CIImage,其大小与drawable相同,并在继续之前进行渲染到我实际想要渲染的图像。
这似乎效率很低,因此欢迎更好的解决方案!
这是其他绘图代码:
if needsRefresh {
let color = UIColor(mtkColor: clearColor)
let clearImage = CIImage(cgImage: UIImage.withColor(color, size: bounds.size)!.cgImage!)
ciContext.render(
clearImage,
to: targetTexture,
commandBuffer: commandBuffer,
bounds: bounds,
colorSpace: colorSpace
)
needsRefresh = false
}
以下是UIColor
扩展名,用于转换纯色:
extension UIColor {
convenience init(mtkColor: MTLClearColor) {
let red = CGFloat(mtkColor.red)
let green = CGFloat(mtkColor.green)
let blue = CGFloat(mtkColor.blue)
let alpha = CGFloat(mtkColor.alpha)
self.init(red: red, green: green, blue: blue, alpha: alpha)
}
}
最后,是一个小扩展,用于从给定的背景色创建CIImage:
extension UIImage {
static func withColor(_ color: UIColor, size: CGSize = CGSize(width: 10, height: 10)) -> UIImage? {
UIGraphicsBeginImageContext(size)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setFillColor(color.cgColor)
context.fill(CGRect(origin: .zero, size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
答案 1 :(得分:0)
MTKView
具有clearColor
属性,您可以像这样使用:
clearColor = MTLClearColorMake(1, 1, 1, 1)
或者,如果您想使用CIImage
,则可以使用CIColor
创建一个,就像这样:
CIImage(color: CIColor(red: 1, green: 1, blue: 1)).cropped(to: CGRect(origin: .zero, size: drawableSize))
答案 2 :(得分:0)
您可以做的是告诉ciContext
在绘制纹理之前先清除纹理。
所以在您这样做之前,
ciContext.render(
scaledImage,
to: targetTexture,
commandBuffer: commandBuffer,
bounds: bounds,
colorSpace: colorSpace)
首先清除上下文。
let renderDestination = CIRenderDestination(
width: Int(sizeToClear.width),
height: Int(sizeToClear.height),
pixelFormat: colorPixelFormat,
commandBuffer: nil) { () -> MTLTexture in
return drawable.texture
}
do {
try ciContext.startTask(toClear: renderDestination)
} catch {
}
有关更多信息,请参见documentation