检测显示器是否支持 30 位颜色
Detecting if a display supports 30-bit Color
Apple 最近在 OS X 上启用了 30 位颜色支持。他们发布了一些 sample code 来展示如何启用它。但是,他们似乎没有提供示例来说明如何检测您的应用何时在支持 30 位颜色的显示器上 运行。
我们希望能够检测显示器何时支持 30 位颜色,并且只为支持它的显示器启用 30 位颜色,否则恢复为 24 位颜色。
有人知道怎么做吗?
到目前为止,我已经尝试使用 CGDisplay
API(CGDisplayCopyDisplayMode
和 CGDisplayModeCopyPixelEncoding
)来查询显示器的像素编码。但是这些似乎总是 return 24 位编码并且 CGDisplayModeCopyPixelEncoding
在 Mac OS X 10.11 中被弃用。我也尝试过使用 NSScreen’s
“深度”属性,但这也是 returns 24 位每像素。
内置的系统信息应用程序显然可以获取这些信息,我只是不知道他们是怎么做到的。有什么提示吗?
有各种不好的选择。
首先,如果您记录显示模式(即转换为 id
并传递给 NSLog(@"%@", ...)
),您会发现真正的像素编码就在那里。这很有趣,但您真的不想解析该描述。
如果您将 (__bridge CFDictionaryRef)@{ (__bridge NSString*)kCGDisplayShowDuplicateLowResolutionModes: @YES }
作为选项参数传递给 CGDisplayCopyAllDisplayModes()
,您会发现您获得了一堆额外的显示模式。 headers 中记录了此密钥,但没有参考文档。对于 Retina 显示屏,一些额外模式是未缩放显示模式的 2 倍缩放对应物。其他是 30-bit-masquerading-as-24 位模式的 24 位对应物。这些在您可以通过 API 查询的所有方面都是相同的,但日志记录显示了不同之处。 (顺便说一下,尝试切换到其中一种模式将会失败。)
我想,但你必须验证,除了 30-bit-color-capable 显示,你没有得到这些 seemingly-identical 模式对。
您或许可以从 IOKit 获取信息。您必须使用已弃用的函数 CGDisplayIOServicePort()
来获取表示 GPU-display 对的 IOFramebuffer
object 的服务端口。然后,您可以使用 IORegistryEntrySearchCFProperty()
在服务平面中搜索包含层次结构以找到具有 属性 的 object,例如 "display-bpc" 或 "display-pixel-component-bits" 并获取其价值。至少,在我能够测试的几个系统上有这样的 object 和属性,尽管它们都使用 AMD GPU,并且 属性 在 AMD-specific [=53= 上], 所以不一定靠谱
最后,您可以启动一个子进程到 运行 system_profiler -xml SPDisplaysDataType
并使用 property-list-serialization API 构建一个 属性 列表 object来自结果 XML。然后,您可以在其中找到信息。您可以通过匹配 _spdisplays_display-vendor-id
与 CGDisplayVendorNumber()
、_spdisplays_display-product-id
与 CGDisplayModelNumber()
以及 _spdisplays_display-serial-number
与 CGDisplaySerialNumber()
来找到相关显示。然后,深度在键 spdisplays_depth
下,其中值 CGSThirtyBitColor
表示 30 位颜色。
您还应该向 Apple 提交错误报告,请求以合理的方式执行此操作。
从 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
.
当显示器被认为 "wide gamut RGB" 或能够 NSDisplayGamutP3
时,我不知道你是否保证使用支持 30 位的显示器,但这似乎是 Apple 的官方确定显示器是否具有宽色域颜色的方法。
对我有用的是将 NSWindow
的 depthLimit
属性 传递给 NSBitsPerPixelFromDepth
并检查 return 值是否大于 24。警告:我只有两台 iMac 可以测试,一台是 2012 年的,另一台是 2017 年的,它们都是 运行 High Sierra。
Apple 最近在 OS X 上启用了 30 位颜色支持。他们发布了一些 sample code 来展示如何启用它。但是,他们似乎没有提供示例来说明如何检测您的应用何时在支持 30 位颜色的显示器上 运行。
我们希望能够检测显示器何时支持 30 位颜色,并且只为支持它的显示器启用 30 位颜色,否则恢复为 24 位颜色。
有人知道怎么做吗?
到目前为止,我已经尝试使用 CGDisplay
API(CGDisplayCopyDisplayMode
和 CGDisplayModeCopyPixelEncoding
)来查询显示器的像素编码。但是这些似乎总是 return 24 位编码并且 CGDisplayModeCopyPixelEncoding
在 Mac OS X 10.11 中被弃用。我也尝试过使用 NSScreen’s
“深度”属性,但这也是 returns 24 位每像素。
内置的系统信息应用程序显然可以获取这些信息,我只是不知道他们是怎么做到的。有什么提示吗?
有各种不好的选择。
首先,如果您记录显示模式(即转换为 id
并传递给 NSLog(@"%@", ...)
),您会发现真正的像素编码就在那里。这很有趣,但您真的不想解析该描述。
如果您将 (__bridge CFDictionaryRef)@{ (__bridge NSString*)kCGDisplayShowDuplicateLowResolutionModes: @YES }
作为选项参数传递给 CGDisplayCopyAllDisplayModes()
,您会发现您获得了一堆额外的显示模式。 headers 中记录了此密钥,但没有参考文档。对于 Retina 显示屏,一些额外模式是未缩放显示模式的 2 倍缩放对应物。其他是 30-bit-masquerading-as-24 位模式的 24 位对应物。这些在您可以通过 API 查询的所有方面都是相同的,但日志记录显示了不同之处。 (顺便说一下,尝试切换到其中一种模式将会失败。)
我想,但你必须验证,除了 30-bit-color-capable 显示,你没有得到这些 seemingly-identical 模式对。
您或许可以从 IOKit 获取信息。您必须使用已弃用的函数 CGDisplayIOServicePort()
来获取表示 GPU-display 对的 IOFramebuffer
object 的服务端口。然后,您可以使用 IORegistryEntrySearchCFProperty()
在服务平面中搜索包含层次结构以找到具有 属性 的 object,例如 "display-bpc" 或 "display-pixel-component-bits" 并获取其价值。至少,在我能够测试的几个系统上有这样的 object 和属性,尽管它们都使用 AMD GPU,并且 属性 在 AMD-specific [=53= 上], 所以不一定靠谱
最后,您可以启动一个子进程到 运行 system_profiler -xml SPDisplaysDataType
并使用 property-list-serialization API 构建一个 属性 列表 object来自结果 XML。然后,您可以在其中找到信息。您可以通过匹配 _spdisplays_display-vendor-id
与 CGDisplayVendorNumber()
、_spdisplays_display-product-id
与 CGDisplayModelNumber()
以及 _spdisplays_display-serial-number
与 CGDisplaySerialNumber()
来找到相关显示。然后,深度在键 spdisplays_depth
下,其中值 CGSThirtyBitColor
表示 30 位颜色。
您还应该向 Apple 提交错误报告,请求以合理的方式执行此操作。
从 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
.
当显示器被认为 "wide gamut RGB" 或能够 NSDisplayGamutP3
时,我不知道你是否保证使用支持 30 位的显示器,但这似乎是 Apple 的官方确定显示器是否具有宽色域颜色的方法。
对我有用的是将 NSWindow
的 depthLimit
属性 传递给 NSBitsPerPixelFromDepth
并检查 return 值是否大于 24。警告:我只有两台 iMac 可以测试,一台是 2012 年的,另一台是 2017 年的,它们都是 运行 High Sierra。