【问题标题】:How to programmatically determine native pixel resolution of Retina MacBook Pro screen on OS X?如何以编程方式确定 OS X 上 Retina MacBook Pro 屏幕的原生像素分辨率?
【发布时间】:2012-12-01 07:11:04
【问题描述】:

给定一个从

返回的CGDirectDisplayID
CGError error = CGGetActiveDisplayList(8, directDisplayIDs, &displayCount);

对于 Retina MacBook Pro 上的内置屏幕,我希望使用获取本机像素尺寸

size_t pixelWidth = CGDisplayPixelsWide(directDisplayID);
size_t pixelHeight = CGDisplayPixelsHigh(directDisplayID);

但是,这些调用仅返回当前所选模式的尺寸。如果我改变屏幕分辨率,我会得到不同的值。我希望在 15 英寸 rMBP 上恢复 2880 x 1800。

如何获取 Retina MacBook Pro 屏幕的原生像素尺寸?

【问题讨论】:

    标签: objective-c macos retina-display screen-resolution


    【解决方案1】:

    我认为最好的方法是枚举所有显示模式(包括 1x 模式)并找到最大的 1x 模式的尺寸。

    您将使用CGDisplayCopyAllDisplayModes() 并传递一个字典,其中键kCGDisplayShowDuplicateLowResolutionModes 映射到kCFBooleanTrue 作为options 以获取所有模式。您可以测试CGDisplayModeGetPixelWidth() 是否等于CGDisplayModeGetWidth() 以确定哪些是1x。

    【讨论】:

      【解决方案2】:

      CGDisplayModeGetIOFlags可以告诉你显示的一些信息。本机分辨率设置了kDisplayModeNativeFlag。下面将ns设置为窗口win的当前屏幕的原生分辨率。

      CGDirectDisplayID sid = ((NSNumber *)[win.screen.deviceDescription
          objectForKey:@"NSScreenNumber"]).unsignedIntegerValue;
      CFArrayRef ms = CGDisplayCopyAllDisplayModes(sid, NULL);
      CFIndex n = CFArrayGetCount(ms);
      NSSize ns;
      for(int i = 0; i < n; ++i){
          CGDisplayModeRef m = (CGDisplayModeRef)CFArrayGetValueAtIndex(ms, i);
          if(CGDisplayModeGetIOFlags(m) & kDisplayModeNativeFlag){
              ns.width = CGDisplayModeGetPixelWidth(m);
              ns.height = CGDisplayModeGetPixelHeight(m);
              break;
          }
      }
      CFRelease(ms);
      

      【讨论】:

      • 不幸的是,并非所有显示器都具有设置kDisplayModeNativeFlag 位的分辨率。例如,iMac 5K 2017 内置显示器就是这种情况。这就是为什么我更喜欢 Ken 的答案,也许结合检查 kDisplayModeNativeFlag 位。
      【解决方案3】:

      我会走另一条路。我不会找出屏幕尺寸,而是获取正在运行程序的设备型号,然后将型号与其屏幕尺寸进行比较。对型号和相应的屏幕尺寸进行编程可能很乏味,但这是我能想到的唯一方法。希望这可以帮助。

      【讨论】:

      • 我不确定是否要管理屏幕型号列表,但这是一个选项,谢谢。
      • 有没有其他人已经整理过屏幕型号和分辨率的列表?
      【解决方案4】:

      如果使用 NSScreen 是一个选项,您可以在 OSX 10.7 中执行类似的操作:

      NSRect framePixels = [screen convertRectToBacking:[screen frame]];
      

      其中framePixels.size 是显示器的像素分辨率,screen 是指向NSScreen 的指针。例如,此代码会将所有活动显示器的像素分辨率打印到控制台:

      for (NSScreen* screen in [NSScreen screens])
      {
          NSRect framePixels = [screen convertRectToBacking:[screen frame]];
          NSLog(@"framePixels: (%f, %f)", framePixels.size.width, framePixels.size.height);
      }
      

      【讨论】:

      • 不幸的是,这也不起作用。它只返回用于当前显示模式的后备存储的像素尺寸。不是物理显示器的原生像素尺寸。如果模式更改,则返回不同的大小。例如,在 15" Retina 显示器上,在 Retina (1440x900 2x) 模式下,这将返回 framePixels: (2880.000000, 1800.000000)。但是,将模式更改为最大的“更多空间”(1920x1200 2x),它会返回 framePixels: (3840.000000, 2400.000000)
      • 唯一的事情是 - 这实际上是正确的。这就是屏​​幕运行的分辨率!用户故意将分辨率设置为该大小。
      • 我认为您错过了关键信息。这是一个例子。我有一个原生分辨率为 3840 x 2160 的屏幕。backingScaleFactor 要么是 1.0f,根本没有缩放,要么是 2.0f,对于任何缩放。如果我将系统设置为 1.5f 的缩放因子(显示缩放菜单中的中间设置),那么这段代码会告诉我我的屏幕是 6016x3384。这显然是不正确的。
      【解决方案5】:

      system_profiler SPDisplaysDataType | grep Resolution:

      在两台显示器的机器上,我得到这个输出:

            Resolution: 2880 x 1800 Retina
            Resolution: 2560 x 1440 (QHD/WQHD - Wide Quad High Definition)
      

      我从一个类似的问题中听说过这个:How to get the physical display resolution on MacOS?

      【讨论】:

        【解决方案6】:

        上面Ken/jxy方案的修改版,如果没有找到原生分辨率,默认使用screen frame*backingScaleFactor:

        static float getScreenScaleFactor() {
        NSRect screenFrame = [[NSScreen mainScreen] frame];
        
        // this may well be larger than actual pixel dimensions of screen, as Mac will report the backing scale factor of the render buffer, not the screen, stupidly
        float bestWidth = screenFrame.size.width * [[NSScreen mainScreen] backingScaleFactor];
        
        // if there's a native resolution found in this method, that's more accurate than above
        CFArrayRef myModes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL);
        for (int i = 0; i < CFArrayGetCount(myModes); i++) {
            CGDisplayModeRef myMode = (CGDisplayModeRef) CFArrayGetValueAtIndex(myModes, i);
            if (CGDisplayModeGetIOFlags(myMode) & kDisplayModeNativeFlag) {
                bestWidth = CGDisplayModeGetPixelWidth(myMode);
                //printf("found native resolution: %i %i\n", (int)CGDisplayModeGetPixelWidth(myMode), (int)CGDisplayModeGetPixelHeight(myMode));
                break;
                }
            }
        
        return bestWidth/screenFrame.size.width;
        }
        

        【讨论】:

          猜你喜欢
          • 2011-06-22
          • 2011-05-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 2017-05-01
          • 1970-01-01
          相关资源
          最近更新 更多