64位RGBA UIImage? CGBitmapInfo用于64位 [英] 64-bit RGBA UIImage? CGBitmapInfo for 64-bit

查看:180
本文介绍了64位RGBA UIImage? CGBitmapInfo用于64位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从iOS上的Metal纹理保存具有P3色彩空间的16位深度PNG图像.纹理的像素格式为.rgba16Unorm,我使用此代码提取数据

I'm trying to save a 16-bit depth PNG image with P3 color space from a Metal texture on iOS. The texture has pixelformat = .rgba16Unorm, and I extract the data with this code

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.在文档中,我可以看到您可以为32位格式,但不适用于64位.

I figured out that the way to save a PNG image on iOS would be to create a UIImage first, and to initialize it, I need to create a CGImage. The problem is I don't know what to pass to CGIBitmapInfo. In the documentation I can see you can specify the byteOrder for 32-bit formats, but not for 64-bit.

我用来将纹理转换为UIImage的函数是

The function I use to convert the texture to an UIImage is this,

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中不存在的一系列属性.为了方便起见,我创建了一个简单的扩展.我猜唯一有趣的一点是色彩空间,目前很简单,

Note that "texture" is using a series of attributes that do not exist in MTLTexture. I created a simple extension for convenience. The only interesting bit I guess it's the color space, that at the moment is simply,

public extension MTLTexture {
  var defaultColorSpace: CGColorSpace? {
    get {
        switch pixelFormat {
        case .rgba16Unorm:
            return CGColorSpace(name: CGColorSpace.displayP3)
        default:
            return CGColorSpaceCreateDeviceRGB()
        }
    }
  }
}

看起来我用上面的代码创建的图像每个像素采样了4个字节,而不是8个字节.所以我显然得到了一个有趣的图像...

It looks like the image I'm creating with that code above is sampling 4 bytes per pixel, instead of 8. So I obviously end up with a funny looking image...

如何创建适当的CGBitmapInfo?甚至有可能吗?

How do I create the appropriate CGBitmapInfo? Is it even possible?

P.S.如果您想查看带有示例的完整代码,则全部在github中: https://github.com/endavid/VidEngine/tree/master/SampleColorPalette

P.S. If you want to see the full code with an example, it's all in github: https://github.com/endavid/VidEngine/tree/master/SampleColorPalette

推荐答案

答案是使用byteOrder16.例如,为此,我在上面的代码中替换了bitmapInfo,

The answer was using byteOrder16. For instance, I've replace bitmapInfo in the code above for this,

    let isFloat = texture.bitsPerComponent == 16
    let bitmapInfo:CGBitmapInfo = [isFloat ? .byteOrder16Little : .byteOrder32Big, CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue)]

(Alpha也可以预乘).

(The alpha can be premultiplied as well).

SDK文档并未提供许多提示,说明了为什么这样做是,但是这本书

The SDK documentation does not provide many hints of why this is, but the book Programming with Quartz has a nice explanation of the meaning of these 16 bits:

值byteOrder16Little向Quartz指定Quartz,应按小端顺序对数据提供者提供的每个16位数据块进行处理.例如,当对指定RGB格式的图像使用byteOrder16Little值时每个分量有16位,每个像素有48位,您的数据提供程序为分量按R,G,B顺序排列的每个像素提供数据,但是每个颜色分量的值都按低位序排列[...]使用byteOrder16Little时,图像的像素大小或分量大小必须为16位.

The value byteOrder16Little specifies to Quartz that each 16-bit chunk of data supplied by your data provider should be treated in little endian order [...] For example, when using a value of byteOrder16Little for an image that specifies RGB format with 16 bits per component and 48 bits per pixel, your data provider supplies the data for each pixel where the components are ordered R, G, B, but each color component value is in little-endian order [...] For best performance when using byteOrder16Little, either the pixel size or the component size of the image must be 16 bits.

因此对于rgba16中的64位图像,像素大小为64位,但是组件大小为16位.它很好用:)

So for a 64-bit image in rgba16, the pixel size is 64 bits, but the component size is 16 bits. It works nicely :)

(感谢@warrenm!)

(Thanks @warrenm !)

这篇关于64位RGBA UIImage? CGBitmapInfo用于64位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆