【问题标题】:Detecting if a display supports 30-bit Color检测显示器是否支持 30 位颜色
【发布时间】:2016-04-27 22:51:08
【问题描述】:

Apple 最近在 OS X 上启用了 30 位颜色支持。他们发布了一些 sample code 来说明如何启用此功能。但是,它们似乎没有提供示例来说明如何检测您的应用何时在支持 30 位颜色的显示器上运行。

我们希望能够检测显示器何时支持 30 位颜色,并且只为支持它的显示器启用 30 位颜色,否则恢复为 24 位颜色。

有人知道怎么做吗?

到目前为止,我已经尝试使用 CGDisplay API(CGDisplayCopyDisplayModeCGDisplayModeCopyPixelEncoding)来查询显示器的像素编码。但这些似乎总是返回 24 位编码,CGDisplayModeCopyPixelEncoding 在 Mac OS X 10.11 中已被弃用。我也尝试过使用NSScreen’s“深度”属性,但这也返回每像素 24 位。

内置的系统信息应用程序显然能够获取这些信息,我只是不知道他们是如何做到的。有什么提示吗?

【问题讨论】:

    标签: macos retina-display color-management gamut


    【解决方案1】:

    从 macOS 10.12 开始,Apple 提供了一些新的 API,可让您检测显示器是否支持广色域颜色(即深色)。有几种方法可以做到这一点:

    1. 使用 NSScreen 的- (BOOL)canRepresentDisplayGamut:(NSDisplayGamut)displayGamut

      NSArray<NSScreen *> * screens = [NSScreen screens];
      BOOL hasWideGamutScreen = NO;
      
      for ( NSScreen * screen in screens )
      {
          if ( [screen canRepresentDisplayGamut:NSDisplayGamutP3] )
          {
              hasWideGamutScreen = YES;
              break;
          }
      }
      
    2. 使用CGColorSpaceIsWideGamutRGB(...):

      hasWideGamutScreen = CGColorSpaceIsWideGamutRGB( screen.colorSpace.CGColorSpace );
      
    3. NSWindow 也有- (BOOL)canRepresentDisplayGamut:(NSDisplayGamut)displayGamut

    当显示器被认为是“广色域 RGB”或能够NSDisplayGamutP3 时,我不知道你是否能保证使用 30 位的显示器,但这似乎是 Apple 官方确定是否显示器具有广色域色彩。

    【讨论】:

      【解决方案2】:

      有各种不好的选择。

      首先,如果您记录显示模式(即转换为id 并传递给NSLog(@"%@", ...)),您会发现真正的像素编码在那里。这很有趣,但您真的不想解析该描述。

      如果你将(__bridge CFDictionaryRef)@{ (__bridge NSString*)kCGDisplayShowDuplicateLowResolutionModes: @YES } 作为选项参数传递给CGDisplayCopyAllDisplayModes(),你会发现你得到了一堆额外的显示模式。此密钥记录在标题中,但未记录在参考文档中。对于 Retina 显示器,一些额外的模式是未缩放显示模式的 2 倍缩放对应物。其他是 30 位伪装成 24 位模式的 24 位对应物。这些在您可以通过 API 查询的所有方面都是相同的,但日志记录显示了差异。 (顺便说一句,尝试切换到其中一种模式会失败。)

      我认为,但您必须验证,除了支持 30 位颜色的显示器之外,您不会获得这对看似相同的模式。

      您也许可以从 IOKit 获取信息。您必须使用已弃用的函数 CGDisplayIOServicePort() 来获取代表 GPU 显示对的 IOFramebuffer 对象的服务端口。然后,您可以使用IORegistryEntrySearchCFProperty() 在服务平面中搜索包含层次结构,以找到具有“display-bpc”或“display-pixel-component-bits”等属性的对象并获取其值。至少,在我能够测试的几个系统上都有这样的对象和属性,尽管它们都使用 AMD GPU,并且属性位于 AMD 特定的对象上,所以它可能不可靠。

      最后,您可以启动一个子进程来运行system_profiler -xml SPDisplaysDataType 并使用 property-list-serialization API 从生成的 XML 构建一个属性列表对象。然后,您可以在其中找到信息。您可以通过将_spdisplays_display-vendor-idCGDisplayVendorNumber()_spdisplays_display-product-idCGDisplayModelNumber() 以及_spdisplays_display-serial-numberCGDisplaySerialNumber() 匹配来找到相关显示。然后,深度在键 spdisplays_depth 下,其中 CGSThirtyBitColor 的值表示 30 位颜色。

      您还应该向 Apple 提交错误报告,要求以合理的方式执行此操作。

      【讨论】:

      • 哇,那些非常糟糕的选择。在NSLog 提示之后,我发现CGDisplayModeRef 结构有一个指向字典(CFDictionary)的指针,该字典距离内存中结构基数的16 个字节。然后,您可以在该字典中查询 ”PixelEncoding””BitsPerSample” 键。然而,这是一个非常糟糕的解决方案,因为我不想依赖 CGDisplayModeRef 结构的私有实现,因为它可能会在未来的任何操作系统更新中发生变化。我也不想使用CGDisplayIOServicePort(),因为它已被弃用。真的很糟糕的选择...
      【解决方案3】:

      对我有用的是将NSWindowdepthLimit 属性传递给NSBitsPerPixelFromDepth 并检查返回值是否大于24。警告:我只有两台iMac 可以测试,一台是2012 年的,另一台是从 2017 年开始,他们都在运行 High Sierra。

      【讨论】:

        猜你喜欢
        • 2017-10-13
        • 1970-01-01
        • 1970-01-01
        • 2022-07-06
        • 2019-12-15
        • 2015-08-21
        • 1970-01-01
        • 2021-09-23
        • 2021-07-06
        相关资源
        最近更新 更多