MTKView 显示广色域 P3 色彩空间

Posted

技术标签:

【中文标题】MTKView 显示广色域 P3 色彩空间【英文标题】:MTKView Displaying Wide Gamut P3 Colorspace 【发布时间】:2017-12-30 22:20:22 【问题描述】:

我正在构建一个基于 CIFilters 和 MetalKit 的实时照片编辑器。但我遇到了在 MTKView 中显示广色域图像的问题。

标准 sRGB 图像显示正常,但 Display P3 图像褪色。

我尝试将 CIContext.render 颜色空间设置为图像颜色空间,但仍然遇到问题。

这里是sn-ps的代码:

 guard let inputImage = CIImage(mtlTexture: sourceTexture!) else  return 
                let outputImage = imageEditor.processImage(inputImage)
                print(colorSpace)
                context.render(outputImage,
                               to: currentDrawable.texture,
                               commandBuffer: commandBuffer,
                               bounds: inputImage.extent,
                               colorSpace: colorSpace)
                commandBuffer?.present(currentDrawable)

let pickedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
        print(pickedImage.cgImage?.colorSpace)
        if let cspace = pickedImage.cgImage?.colorSpace 
            colorSpace = cspace
        

我在 Apple 开发者论坛上发现了一个类似的问题,但没有任何答案:https://forums.developer.apple.com/thread/66166

【问题讨论】:

我不确定它在 ios 中是否可行...在 macOS 中,MTKView 有一个您可以设置的 colorSpace 属性,但显然它在 iOS 中不受支持:(developer.apple.com/documentation/metalkit/mtkview/… 【参考方案1】:

为了支持广色域,您需要将 MTKView 的colorPixelFormat 设置为BGRA10_XR 或bgra10_XR_sRGB。我怀疑 macOS MTKViews 的 colorSpace 属性在 iOS 上不受支持,因为 iOS 中的颜色管理不是活动而是有针对性的(阅读Best practices for color management)。

没有看到您的图像及其实际值,很难诊断,但我会解释我的发现和实验。我建议你像我一样从调试单一颜色开始。

例如,P3 色彩空间中最红的点是什么?它可以像这样通过UIColor 定义:

UIColor(displayP3Red: 1, green: 0, blue: 0, alpha: 1)

为您的视图添加一个 UIButton,并将背景设置为该颜色以进行调试。您可以在代码中获取组件以查看这些值在 sRGB 中的变化,

    var fRed : CGFloat = 0
    var fGreen : CGFloat = 0
    var fBlue : CGFloat = 0
    var fAlpha : CGFloat = 0
    let c = UIColor(displayP3Red: 1, green: 0, blue: 0, alpha: 1)
    c.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha)

或者您可以使用 macOS 颜色同步实用程序中的计算器,

确保选择扩展范围,否则值将被限制为 0 和 1。

因此,如您所见,您的 P3(1, 0, 0) 对应于扩展 sRGB 中的 (1.0930, -0.2267, -0.1501)。

现在,回到你的MTKView

如果您将 MTKView 的 colorPixelFormat 设置为 .BGRA10_XR,那么如果您的着色器的输出是,您将获得最亮的红色,

(1.0930, -0.2267, -0.1501)

如果您将 MTKView 的 colorPixelFormat 设置为 .bgra10_XR_sRGB,那么如果您的着色器的输出是,您将获得最亮的红色,

(1.22486, -0.0420312, -0.0196301)

因为您必须编写线性 RGB 值,因为这种纹理格式将为您应用伽马校正。应用逆伽玛时要小心,因为有负值。我用这个功能,

let f = (c: Float) -> Float in
    if fabs(c) <= 0.04045 
        return c / 12.92
    
    return sign(c) * powf((fabs(c) + 0.055) / 1.055, 2.4)

最后一个缺失的部分是创建广色域UIImage。将颜色空间设置为CGColorSpace.displayP3 并复制数据。但是什么数据,对吧?此图像中最亮的红色将是

(1, 0, 0)

或 (65535, 0, 0) 以 16 位整数表示。

我在代码中所做的是使用.rgba16Unorm 纹理来处理displayP3 颜色空间中的图像,其中 (1, 0, 0) 将是 P3 中最亮的红色。这样,我可以直接将其内容复制到UIImage。然后,为了显示,我将颜色转换传递给着色器以在显示之前从 P3 转换为扩展的 sRGB(因此,不饱和颜色)。我使用线性颜色,所以我的变换只是一个 3x3 矩阵。我将视图设置为.bgra10_XR_sRGB,因此会自动为我应用伽玛。

那个(列主)矩阵是,

 1.2249  -0.2247  0
-0.0420   1.0419  0
-0.0197  -0.0786  1.0979

你可以在这里阅读我是如何生成它的:Exploring the display-P3 color space

这是我使用 UIButtons 和 MTKView 构建的示例,在 iPhoneX 上截屏,

左边的按钮是 sRGB 上最亮的红色,而右边的按钮使用的是 displayP3 颜色。在中心,我放置了一个 MTKView,它输出如上所述的转换后的线性颜色。

同样的绿色实验,

现在,如果您在最近的 iPhone 或 iPad 上看到此内容,您应该会看到中间的正方形和右侧的按钮都具有相同的亮色。如果您在无法显示它们的 Mac 上看到此内容,则左侧按钮将显示相同颜色。如果您在没有适当颜色管理的 Windows 机器或浏览器中看到这一点,左侧按钮也可能看起来具有不同的颜色,但这只是因为整个图像被解释为 sRGB 并且显然这些像素具有不同的值......但外观不会正确。

如果您需要更多参考,请查看我在此处添加的testP3UIColor 单元测试:ColorTests.swift,

我的函数来初始化UIImage:Image.swift,

以及一个用于尝试转换的示例应用:SampleColorPalette

我还没有尝试过CIImages,但我想同样的原则也适用。

我希望这些信息对您有所帮助。我还花了很长时间才弄清楚如何正确显示颜色,因为我在 Metal SDK 文档中找不到对 displayP3 支持的任何明确引用。

【讨论】:

其实1.22486, -0.0420312, -0.0196301不是bgra10_xr_srgb像素格式最亮的红色,1.358, -0.074, -0.012才是。 Justin Stoyles 说,在Working with Wide Color 会话中,您可以通过在MTKViews 之间放置UIView1.0, 0.0, 0.0, 1.0 Display P3 背景颜色来查看1.22486, -0.0420312, -0.01963011.358, -0.074, -0.012 颜色。 看来bgra10_xr_srgb 像素格式使用的颜色空间与CGColorSpace.extendedSRGBCGColorSpace.extendedLinearSRGB 不同。对于将转换矩阵从 Display P3 获取到该色彩空间的任何帮助,我将不胜感激。 感谢您的链接。不确定1.358 来自哪里。如果创建 displayP3 UIColor,let c = UIColor(displayP3Red: 1, green: 0, blue: 0, alpha: 1); c.getRed(&amp;fRed, green: &amp;fGreen, blue: &amp;fBlue, alpha: &amp;fAlpha),红色值为1.0930339097976685。要让它在转换为线性空间时变为1.358,你需要一个gamma=log(1.358)/log(1.093)=3.44 的伽玛,它大得离谱。我敢打赌他们正在使用这种常见的伽马计算:linear=((c+0.055)/1.055)^2.4,他们忘记了除以 1.055 或其他东西。胡思乱想……

以上是关于MTKView 显示广色域 P3 色彩空间的主要内容,如果未能解决你的问题,请参考以下文章

AVCaptureVideoDataOutput P3 色彩空间

[lr & ps] 色彩空间管理

华为nova9和荣耀50参数对比

安云信息科技广州分公司平面设计的色彩管理。

华为nova9屏幕多大尺寸?

ERROR ITMS-90682: Invalid Bundle - The asset catalog at 'Payload/XXXXX/Assets.car' can't