Как прочитать физический размер экрана OSX?

Я хотел бы узнать физический размер экрана под Mac OSX. Но NSDeviceResolution всегда сообщает неправильное значение (72), поэтому результат вычисления разрешения / dpi неверен.

Внутри «Об этом Mac» есть строка с моделью Mac, моя - «15 дюймов, начало 2011 года». Поэтому мне интересно, должен ли быть способ (возможно, в obj-c) прочитать эту строку, а затем я могу использовать ее в качестве физического размера экрана.

Любая помощь приветствуется.


person Andy Li    schedule 25.09.2012    source источник


Ответы (2)


Вы можете использовать CGDisplayScreenSize, чтобы получить физический размер экрана в миллиметрах. Исходя из этого, вы можете вычислить DPI, учитывая, что вы уже знаете разрешение.

So e.g.

NSScreen *screen = [NSScreen mainScreen];
NSDictionary *description = [screen deviceDescription];
NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
CGSize displayPhysicalSize = CGDisplayScreenSize(
            [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);

NSLog(@"DPI is %0.2f", 
         (displayPixelSize.width / displayPhysicalSize.width) * 25.4f); 
         // there being 25.4 mm in an inch

Эта @"NSScreenNumber" штука выглядит хитроумной, но является явным документированным средством для получения CGDirectDisplayID от NSScreen.

person Tommy    schedule 25.09.2012
comment
Всего одно замечание - NSDeviceSize содержит размер в системных точках, а не в физических пикселях. На дисплее Retina (например, iMac 27 Retina или новый MacBook Pro) системная точка обычно составляет 2 пикселя. Таким образом, вы должны умножить NSDeviceSize на [[NSScreen mainScreen] backingScaleFactor], чтобы получить физические пиксели. Еще больше беспорядка, если кто-то установит масштабируемое разрешение в системных настройках macOS - ›Дисплеи - person Slyv; 21.02.2017

Ответ Томми выше превосходен - я перенес его на Swift (для собственного использования) и размещаю здесь в качестве справки, но ответ Томми следует считать каноническим.

import Cocoa

public extension NSScreen {
    var unitsPerInch: CGSize {
        let millimetersPerInch:CGFloat = 25.4
        let screenDescription = deviceDescription
        if let displayUnitSize = (screenDescription[NSDeviceDescriptionKey.size] as? NSValue)?.sizeValue,
            let screenNumber = (screenDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber)?.uint32Value {
            let displayPhysicalSize = CGDisplayScreenSize(screenNumber)
            return CGSize(width: millimetersPerInch * displayUnitSize.width / displayPhysicalSize.width,
                          height: millimetersPerInch * displayUnitSize.height / displayPhysicalSize.height)
        } else {
            return CGSize(width: 72.0, height: 72.0) // this is the same as what CoreGraphics assumes if no EDID data is available from the display device — https://developer.apple.com/documentation/coregraphics/1456599-cgdisplayscreensize?language=objc
        }
    }
}

if let screen = NSScreen.main {
    print("main screen units per inch \(screen.unitsPerInch)")
}

Обратите внимание, что возвращаемое значение является своего рода фактически «точками на дюйм» (но не для всех определений; см. Ниже) и почти никогда не является «пикселями на дюйм» - современные компьютеры Mac имеют определенное количество пикселей. на точку, которая зависит от текущего параметра «Разрешение» в Системных настройках и внутреннего разрешения устройства (дисплеи Retina имеют намного больше пикселей).

Что вы знаете о возвращаемом значении, так это то, что если вы нарисуете линию с таким кодом, как

CGRect(origin: .zero, size: CGSize(width: 10, height: 1)).fill()

линия будет иметь высоту 1 / pointsPerInch.height и ширину 1 / pointsPerInch.width дюйма, если вы будете измерять ее очень точной линейкой, поднесенной к экрану.

(Долгое время графические фреймворки определяли «точку» как оба «1/72 дюйма в реальном мире» и также как «независимо от ширины или высоты коробки размером 1 x 1 оказывается на текущем мониторе с текущим разрешением - два определения, которые обычно конфликтуют друг с другом.)

Поэтому в этом коде я использую слово «единица измерения», чтобы пояснить, что мы имеем дело не с 1/72 дюйма и не с 1 физическим пикселем.

person Wil Shipley    schedule 28.04.2019