从MTKView创建的UIImage会导致颜色/不透明度的差异

时间:2018-03-11 19:29:10

标签: swift uiimageview metal render-to-texture metalkit

当我将MTKView的内容捕获到UIImage中时,生成的图像看起来质量不同,如下所示:

MTKView vs UIImageView of the same

我用来生成UIImage的代码如下:

let kciOptions = [kCIContextWorkingColorSpace: CGColorSpace(name: CGColorSpace.sRGB)!,
                         kCIContextOutputPremultiplied: true,
                         kCIContextUseSoftwareRenderer: false] as [String : Any]
let lastDrawableDisplayed = self.currentDrawable! // needed to hold the last drawable presented to screen
drawingUIView.image = UIImage(ciImage: CIImage(mtlTexture: lastDrawableDisplayed.texture, options: kciOptions)!)

由于我没有修改ciImage方向(.oriented(CGImagePropertyOrientation.downMirrored)),因此生成的图像是颠倒的,如上图所示。我保持镜像方向不变,因此我可以指出两个图像捕获之间的颜色差异。

无论我如何更改kciOptions参数,(甚至将颜色空间更改为灰度),我都没有看到所产生的UIImage发生任何变化,这种变化看起来比原始颜色更暗淡/不饱和。有没有人对如何准确捕捉我在MTKView上绘制UIImage的内容有任何建议?任何建议都会非常感激。

以下是我可能证明相关的MTKView设置:

let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexFunction = vertexProgram
renderPipelineDescriptor.sampleCount = self.sampleCount
renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm
renderPipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
renderPipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
renderPipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha         renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha            renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha              renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
self.isOpaque = false // makes MTKView bg transparent

3 个答案:

答案 0 :(得分:2)

您的CGColorSpace.sRGB,但您的renderPipelineDescriptor的pixelFormat为.bgra8Unorm。尝试将该行更改为:

renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm_srgb

答案 1 :(得分:2)

我已经在几篇文章中看到了这个问题,但没有明确的答案。这是我发现的:

对于初学者,

var serverData = data[0];

实际上应该只设置为MTKView的本机像素格式

renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm

第二,当我设置CIImage的选项时:

renderPipelineDescriptor.colorAttachments[0].pixelFormat = self.colorPixelFormat

kCIContextWorkingColorSpace 设置为什么无关紧要,无论使用什么,我都看不到任何视觉差异。我真正需要设置的属性称为 KCIImageColorSpace 。因此,更新后的kciOptions看起来像:

let kciOptions = [kCIContextWorkingColorSpace: CGColorSpace(name: CGColorSpace.sRGB)!,
                         kCIContextOutputPremultiplied: true,
                         kCIContextUseSoftwareRenderer: false] as [String : Any]

以类似的方式使用视图的本机像素格式,调用CGColorSpaceCreateDeviceRGB()会创建特定于所使用设备的RGB颜色空间。

答案 2 :(得分:1)

let context = CIContext()
let texture = metalView.currentDrawable!.texture
let cImg = CIImage(mtlTexture: texture, options: nil)!
let cgImg = context.createCGImage(cImg, from: cImg.extent)!
let uiImg = UIImage(cgImage: cgImg)