【发布时间】:2023-03-03 08:06:23
【问题描述】:
我正在尝试从 iOS 上的金属纹理保存具有 P3 颜色空间的 16 位深度 PNG 图像。纹理有pixelformat = .rgba16Unorm,我用这段代码提取数据
func dataProviderRef() -> CGDataProvider? {
let pixelCount = width * height
var imageBytes = [UInt8](repeating: 0, count: pixelCount * bytesPerPixel)
let region = MTLRegionMake2D(0, 0, width, height)
getBytes(&imageBytes, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
return CGDataProvider(data: NSData(bytes: &imageBytes, length: pixelCount * bytesPerPixel * MemoryLayout<UInt8>.size))
}
我发现在iOS上保存PNG图像的方法是先创建一个UIImage,然后初始化它,我需要创建一个CGImage。问题是我不知道将什么传递给 CGIBitmapInfo。在documentation 我可以看到您可以为 32 位格式指定 byteOrder,但不能为 64 位指定。
我用来将纹理转换为 UIImage 的函数是这样的,
extension UIImage {
public convenience init?(texture: MTLTexture) {
guard let rgbColorSpace = texture.defaultColorSpace else {
return nil
}
let bitmapInfo:CGBitmapInfo = [CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue)]
guard let provider = texture.dataProviderRef() else {
return nil
}
guard let cgim = CGImage(
width: texture.width,
height: texture.height,
bitsPerComponent: texture.bitsPerComponent,
bitsPerPixel: texture.bitsPerPixel,
bytesPerRow: texture.bytesPerRow,
space: rgbColorSpace,
bitmapInfo: bitmapInfo,
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
else {
return nil
}
self.init(cgImage: cgim)
}
}
请注意,“纹理”使用的是一系列 MTLTexture 中不存在的属性。为了方便起见,我创建了一个简单的扩展。我猜唯一有趣的一点是色彩空间,目前很简单,
public extension MTLTexture {
var defaultColorSpace: CGColorSpace? {
get {
switch pixelFormat {
case .rgba16Unorm:
return CGColorSpace(name: CGColorSpace.displayP3)
default:
return CGColorSpaceCreateDeviceRGB()
}
}
}
}
看起来我用上面的代码创建的图像是每个像素采样 4 个字节,而不是 8 个。所以我显然最终得到了一个看起来很有趣的图像......
如何创建适当的 CGBitmapInfo?有没有可能?
附:想看完整代码有例子,都在github:https://github.com/endavid/VidEngine/tree/master/SampleColorPalette
【问题讨论】:
标签: ios swift colors uiimage metal