我正在尝试使用MTKTextureLoader将CGImage加载为纹理。这是原始图像
然而,在我将CGImage转换为MTLTexture并将纹理转换回CGImage后,它看起来很可怕,如下所示:
以下是代码中的内容。
图像作为CGImage加载(我已经检查过,图像看起来确实具有完整的视觉质量)
我有一个函数视图(),它允许我在CALayer中使用它来查看NSImage,如下所示:
func view() {
.....
imageView!.layer = CALayer()
imageView!.layer!.contentsGravity = kCAGravityResizeAspectFill
imageView!.layer!.contents = img
imageView!.wantsLayer = true
所以我做了以下
let cg = CoolImage()
let ns = NSImage(cgImage: cg, size: Size(width: cg.width, height: cg.height))
view(image: ns)
并且确定它具有完全的视觉保真度。
然后我将cg图像加载到像这样的MTLTexture
let textureLoader = MTKTextureLoader(device: metalState.sharedDevice!)
let options = [
MTKTextureLoader.Option.textureUsage: NSNumber(value: MTLTextureUsage.shaderRead.rawValue | MTLTextureUsage.shaderWrite.rawValue | MTLTextureUsage.renderTarget.rawValue),
MTKTextureLoader.Option.SRGB: false
]
return ensure(try textureLoader.newTexture(cgImage: cg, options: options))
然后我将MTLTexture转换回UIImage,如下所示:
let texture = self
let width = texture.width
let height = texture.height
let bytesPerRow = width * 4
let data = UnsafeMutableRawPointer.allocate(bytes: bytesPerRow * height, alignedTo: 4)
defer {
data.deallocate(bytes: bytesPerRow * height, alignedTo: 4)
}
let region = MTLRegionMake2D(0, 0, width, height)
texture.getBytes(data, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
var buffer = vImage_Buffer(data: data, height: UInt(height), width: UInt(width), rowBytes: bytesPerRow)
var map: [UInt8] = [0, 1, 2, 3]
if (pixelFormat == .bgra8Unorm) {
map = [2, 1, 0, 3]
}
vImagePermuteChannels_ARGB8888(&buffer, &buffer, map, 0)
guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
guard let context = CGContext(data: data, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else { return nil }
guard let cgImage = context.makeImage() else { return nil }
return NSImage(cgImage: cgImage, size: Size(width: width, height: height))
并观看了它。
生成的图像非常饱和,我相信这是因为我过去相当成功的CGImage转换为MTLTexture。
请注意,此纹理从未呈现过仅转换过的。
您可能想知道我为什么要使用所有这些转换,这是一个很好的观点。我的实际管道不能像这样工作,但它确实要求每个转换组件都能顺利运行。这不是我的实际用例只是为了表明问题。
答案 0 :(得分:3)
此处的问题不是从CGImage
转换为MTLTexture
。问题是您假设源图像的颜色空间是线性的。更可能的是,图像数据实际上是sRGB编码的,因此通过创建具有通用线性颜色空间的位图上下文,您错误地告诉CG它应该在显示之前对图像数据进行伽马编码,这会导致去饱和你看到了。
您可以使用原始CGImage
的原生色彩空间来解决此问题,或者通过考虑您的图像数据是sRGB编码的事实来解决此问题。