Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Так, например,

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.

Ответ 2

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

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 имеют количество пикселей на точку, которое зависит от текущего "разрешения". msgstr "Настройка в Системных настройках и собственное разрешение устройства (дисплеи 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 физическом пикселе.