如何将bgra8Unorm iOS金属纹理转换为rgba8Unorm纹理?

1 awuesterose

我正在使用iOS 11,XCode 9和Metal2。我MTLTexture使用像素格式bgra8Unorm我无法更改此像素格式,因为根据pixelFormat文档

金属层的像素格式必须为bgra8Unorm,bgra8Unorm_srgb,rgba16Float,BGRA10_XR或bgra10_XR_sRGB。

其他像素格式不适合我的应用程序。

现在,我想UIImage从纹理创建一个我可以通过从纹理(doc)中提取像素字节来做到这一点

getBytes(_:bytesPerRow:bytesPerImage:from:mipmapLevel:slice:)

我正在处理这些字节以获取UIImage

func getUIImageForRGBAData(data: Data) -> UIImage? {
    let d = (data as NSData)

    let width = GlobalConfiguration.textureWidth
    let height = GlobalConfiguration.textureHeight
    let rowBytes = width * 4
    let size = rowBytes * height

    let pointer = malloc(size)
    memcpy(pointer, d.bytes, d.length)

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let context = CGContext(data: pointer, width: width, height: height, bitsPerComponent: 8, bytesPerRow: rowBytes, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!

    let imgRef = context.makeImage()
    let image = UIImage(cgImage: imgRef!)
    return image
}

但是,CGContext假定像素为rgba8格式。例如,在最终的UIImage中,红色纹理像素为蓝色。有没有办法在此过程中更改pixelFormat以获得正确的颜色?

华伦

该函数会将.bgra8Unorm纹理的字节转换为RGBA顺序,并UIImage根据数据创建一个

func makeImage(from texture: MTLTexture) -> UIImage? {
    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)

    let map: [UInt8] = [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 UIImage(cgImage: cgImage)
}

警告:此功能非常昂贵。从金属纹理创建图像几乎从来都不是您想要做的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章