Apple 最近在 OS X 上启用了 30 位颜色支持。他们发布了一些示例代码来演示如何启用此功能。但是,它们似乎没有提供有关如何检测应用何时在支持 30 位颜色的显示器上运行的示例。
我们希望能够检测显示器何时支持 30 位颜色,并且仅为支持 30 位颜色的显示器启用 30 位颜色,否则将恢复为 24 位颜色。
有谁知道该怎么做?
到目前为止,我已经尝试使用CGDisplay
API(CGDisplayCopyDisplayMode
和CGDisplayModeCopyPixelEncoding
)来查询显示器的像素编码。但这些似乎总是返回 24 位编码,并且CGDisplayModeCopyPixelEncoding
在 Mac OS X 10.11 中已弃用。我也尝试使用NSScreen’s
"深度"属性,但这也返回每像素 24 位。
内置的系统信息应用程序显然能够获取这些信息,我只是无法弄清楚他们是怎么做到的。有什么提示吗?
从macOS 10.12开始,Apple有一些新的API,允许您检测显示器是否能够使用宽色域颜色(即深色)。有几种方法可以做到这一点:
-
使用 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; } }
-
使用
CGColorSpaceIsWideGamutRGB(...)
:hasWideGamutScreen = CGColorSpaceIsWideGamutRGB( screen.colorSpace.CGColorSpace );
-
NSWindow
也有- (BOOL)canRepresentDisplayGamut:(NSDisplayGamut)displayGamut
.
我不知道当显示器被认为是"广色域RGB"或能够NSDisplayGamutP3
时,您是否可以保证在30位支持显示器的显示器上,但这似乎是Apple确定显示器是否能够进行宽色域颜色的官方方法。
有各种糟糕的选择。
首先,如果您记录显示模式(即投射到id
并传递给NSLog(@"%@", ...)
),您会发现真实的像素编码在那里。这很有趣,但你真的不想解析该描述。
如果将(__bridge CFDictionaryRef)@{ (__bridge NSString*)kCGDisplayShowDuplicateLowResolutionModes: @YES }
作为选项参数传递给CGDisplayCopyAllDisplayModes()
,您会发现您将获得一堆额外的显示模式。此键记录在标头中,但不记录在参考文档中。对于 Retina 显示器,一些额外模式是未缩放显示模式的 2 倍缩放对应项。其他是伪装成 24 位模式的 30 位对应项。它们在您可以通过 API 查询的所有方式上都是相同的,但日志记录显示了差异。(顺便说一下,尝试切换到其中一种模式将失败。
我认为,但你必须验证,除了30位彩色显示器之外,你没有得到这些看似相同的模式。
您可以从IOKit获取信息。您必须使用已弃用的函数CGDisplayIOServicePort()
来获取表示 GPU 显示对的 IOFramebuffer
对象的服务端口。然后,您可以使用IORegistryEntrySearchCFProperty()
在服务平面中搜索包含层次结构,以查找具有"display-bpc"或"display-pixel-component-bits"等属性的对象并获取其值。至少,在我能够测试的几个系统上有这样的对象和属性,尽管它们都使用 AMD GPU,并且该属性位于 AMD 特定的对象上,因此它可能不可靠。
最后,可以启动子进程以运行system_profiler -xml SPDisplaysDataType
并使用属性列表序列化 API 从生成的 XML 生成属性列表对象。然后,您可以在那里找到信息。您可以通过将_spdisplays_display-vendor-id
与CGDisplayVendorNumber()
、_spdisplays_display-product-id
与CGDisplayModelNumber()
以及_spdisplays_display-serial-number
与CGDisplaySerialNumber()
匹配来找到相关的显示。然后,深度在键spdisplays_depth
下,其中值 CGSThirtyBitColor
表示 30 位颜色。
您还应该向Apple提交错误报告,要求采取合理的方法来执行此操作。
对我有用的是将NSWindow
的 depthLimit
属性传递给 NSBitsPerPixelFromDepth
并检查返回值是否大于 24。警告:我只有两台iMac要测试,一台是2012年的,另一台是2017年的,它们都运行High Sierra。