有没有办法找到 CGDisplay 的缩放系数?
Is there any way to find the scaling coefficient for a CGDisplay?
我目前正在做一些测试,看看我的应用程序是否可以在 Retina Mac 上正确运行。为此,我安装了 Quartz Debug,目前我处于 运行 缩放模式。我的屏幕模式现在是 960x540,但当然显示器的物理尺寸仍然是全高清,即 1920x1080 像素。
当使用 CGGetActiveDisplayList()
查询监视器数据库,然后在列表中的各个监视器上使用 CGDisplayBounds()
时,returned 监视器大小为 960x540。这是我所期望的,因为据说 CGDisplayBounds()
使用全局显示坐标 space,而不是像素。
然而,令我惊讶的是,CGDisplayPixelsWide()
和 CGDisplayPixelsHigh()
也 return 960x540,尽管它们明确表示为 return 像素,所以我希望它们return 改为 1920x1080。但他们没有。
这让我想知道如何使用 CGDisplay
API 检索显示器的真实物理分辨率而不是缩放模式,即在我的例子中是 1920x1080 而不是 960x540?有什么办法可以得到 CGDisplay
的比例系数,这样我就可以自己计算出真实的物理分辨率了吗?
我知道我可以使用backingScaleFactor
方法得到这个比例系数,但这只适用于NSScreen
,我如何得到CGDisplay
的比例系数?
您需要检查显示器的模式,而不仅仅是显示器本身。使用 CGDisplayCopyDisplayMode()
,然后使用 CGDisplayModeGetPixelWidth()
和 CGDisplayModeGetPixelHeight()
。最后两个是相对较新的函数,文档主要存在于 headers.
当然,不要忘记 CGDisplayModeRelease()
模式 object。
从 Ken 的回答来看,您如何找到本机模式并不明显。为此,请调用 CGDisplayModeGetIOFlags
并从设置了 kDisplayModeNativeFlag
的模式中进行选择(参见 IOKit/IOGraphicsTypes.h
,值为 0x02000000)。
const int kFlagNativeMode = 0x2000000; // see IOGraphicsTypes.h
const CGFloat kNoSize = 100000.0;
NSScreen *screen = NSScreen.mainScreen;
NSDictionary *desc = screen.deviceDescription;
unsigned int displayID = [[desc objectForKey:@"NSScreenNumber"] unsignedIntValue];
CGSize displaySizeMM = CGDisplayScreenSize(displayID);
CGSize nativeSize = CGSizeMake(kNoSize, kNoSize);
CFStringRef keys[1] = { kCGDisplayShowDuplicateLowResolutionModes };
CFBooleanRef values[1] = { kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFArrayRef modes = CGDisplayCopyAllDisplayModes(displayID, options);
int n = CFArrayGetCount(modes);
for (int i = 0; i < n; i++) {
CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (CGDisplayModeGetIOFlags(mode) & kFlagNativeMode) {
int w = CGDisplayModeGetWidth(mode);
// We get both high resolution (screen.backingScaleFactor > 1)
// and the "low" resolution, in CGFloat units. Since screen.frame
// is CGFloat units, we want the lowest native resolution.
if (w < nativeSize.width) {
nativeSize.width = w;
nativeSize.height = CGDisplayModeGetHeight(mode);
}
}
// printf("mode: %dx%d %f dpi 0x%x\n", (int)CGDisplayModeGetWidth(mode), (int)CGDisplayModeGetHeight(mode), CGDisplayModeGetWidth(mode) / displaySizeMM.width * 25.4, CGDisplayModeGetIOFlags(mode));
}
if (nativeSize.width == kNoSize) {
nativeSize = screen.frame.size;
}
CFRelease(modes);
CFRelease(options);
float scaleFactor = screen.frame.size.width / nativeSize.width;
我目前正在做一些测试,看看我的应用程序是否可以在 Retina Mac 上正确运行。为此,我安装了 Quartz Debug,目前我处于 运行 缩放模式。我的屏幕模式现在是 960x540,但当然显示器的物理尺寸仍然是全高清,即 1920x1080 像素。
当使用 CGGetActiveDisplayList()
查询监视器数据库,然后在列表中的各个监视器上使用 CGDisplayBounds()
时,returned 监视器大小为 960x540。这是我所期望的,因为据说 CGDisplayBounds()
使用全局显示坐标 space,而不是像素。
然而,令我惊讶的是,CGDisplayPixelsWide()
和 CGDisplayPixelsHigh()
也 return 960x540,尽管它们明确表示为 return 像素,所以我希望它们return 改为 1920x1080。但他们没有。
这让我想知道如何使用 CGDisplay
API 检索显示器的真实物理分辨率而不是缩放模式,即在我的例子中是 1920x1080 而不是 960x540?有什么办法可以得到 CGDisplay
的比例系数,这样我就可以自己计算出真实的物理分辨率了吗?
我知道我可以使用backingScaleFactor
方法得到这个比例系数,但这只适用于NSScreen
,我如何得到CGDisplay
的比例系数?
您需要检查显示器的模式,而不仅仅是显示器本身。使用 CGDisplayCopyDisplayMode()
,然后使用 CGDisplayModeGetPixelWidth()
和 CGDisplayModeGetPixelHeight()
。最后两个是相对较新的函数,文档主要存在于 headers.
当然,不要忘记 CGDisplayModeRelease()
模式 object。
从 Ken 的回答来看,您如何找到本机模式并不明显。为此,请调用 CGDisplayModeGetIOFlags
并从设置了 kDisplayModeNativeFlag
的模式中进行选择(参见 IOKit/IOGraphicsTypes.h
,值为 0x02000000)。
const int kFlagNativeMode = 0x2000000; // see IOGraphicsTypes.h
const CGFloat kNoSize = 100000.0;
NSScreen *screen = NSScreen.mainScreen;
NSDictionary *desc = screen.deviceDescription;
unsigned int displayID = [[desc objectForKey:@"NSScreenNumber"] unsignedIntValue];
CGSize displaySizeMM = CGDisplayScreenSize(displayID);
CGSize nativeSize = CGSizeMake(kNoSize, kNoSize);
CFStringRef keys[1] = { kCGDisplayShowDuplicateLowResolutionModes };
CFBooleanRef values[1] = { kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFArrayRef modes = CGDisplayCopyAllDisplayModes(displayID, options);
int n = CFArrayGetCount(modes);
for (int i = 0; i < n; i++) {
CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (CGDisplayModeGetIOFlags(mode) & kFlagNativeMode) {
int w = CGDisplayModeGetWidth(mode);
// We get both high resolution (screen.backingScaleFactor > 1)
// and the "low" resolution, in CGFloat units. Since screen.frame
// is CGFloat units, we want the lowest native resolution.
if (w < nativeSize.width) {
nativeSize.width = w;
nativeSize.height = CGDisplayModeGetHeight(mode);
}
}
// printf("mode: %dx%d %f dpi 0x%x\n", (int)CGDisplayModeGetWidth(mode), (int)CGDisplayModeGetHeight(mode), CGDisplayModeGetWidth(mode) / displaySizeMM.width * 25.4, CGDisplayModeGetIOFlags(mode));
}
if (nativeSize.width == kNoSize) {
nativeSize = screen.frame.size;
}
CFRelease(modes);
CFRelease(options);
float scaleFactor = screen.frame.size.width / nativeSize.width;