Тема: AHK: Как определить размер пикселя монитора
Добрый вечер.
Ответьте, если кто знает.
Можно ли скриптом автохоткей - определить размер пикселя монитора (в сантиметрах или миллиметрах - в общем в метрической системе) ?
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Добрый вечер.
Ответьте, если кто знает.
Можно ли скриптом автохоткей - определить размер пикселя монитора (в сантиметрах или миллиметрах - в общем в метрической системе) ?
У разных мониторов размер пикселя разный. Откуда скрипту его узнать - скачать из интернета паспортные данные монитора? А с проектором ещё интереснее: чем дальше отодвинешь, тем больше пиксель.
А разве монитор не передаёт в систему какую либо информацию?
Только что в AIDA64 Extreme нашёл инфу о своём мониторе, т.е. прога её взяла из самого устройства я полагаю.
Монитор сообщает компьютеру, какое поддерживается разрешение и частота кадров. По-моему, компьютеру просто незачем знать размеры его пикселей. Всякие программы, как мне кажется, видят только коды оборудования и сверяют их с какой-то своей базой. Появится в продаже новый монитор - программа его не сможет опознать без обновления базы данных.
21 Horizontal screen size, in centimetres (range 1–255). If vertical screen size is 0, landscape aspect ratio (range 1.00–3.54), datavalue = (AR×100) − 99 (example: 16:9, 79; 4:3, 34.)
22 Vertical screen size, in centimetres. If horizontal screen size is 0, portrait aspect ratio (range 0.28–0.99), datavalue = (100/AR) − 99 (example: 9:16, 79; 3:4, 34.) If either byte is 0, screen size and aspect ratio are undefined (e.g. projector)
Решил попробовать, как-то не очень легко вышло.
if Arr := GetMonitorPhysicalSize() {
for k, v in Arr
res .= (res = "" ? "" : "`n`n") . "monitor " . k . "`n"
. "width: " . v.width . " mm" . "`n"
. "height: " . v.height . " mm"
}
MsgBox, % res
GetMonitorPhysicalSize() {
DeviceIDs := GetMonitorIDs()
if !DeviceIDs[1]
throw "Failed to get monitors device ids"
DevRegKeys := GetDevRegKeys(DeviceIDs)
if !DevRegKeys[1]
throw "Failed to get reg keys"
Info := GetPhysicalSizeFromReg(DevRegKeys)
if !Info[1]
throw "Failed to get reg data"
Return Info
}
GetMonitorIDs() {
static DISPLAY_DEVICE_ACTIVE := 0x00000001
, DISPLAY_DEVICE_MIRRORING_DRIVER := 0x00000008
VarSetCapacity(DISPLAY_DEVICE, size := 8 + (416 << !!A_IsUnicode), 0)
NumPut(size, DISPLAY_DEVICE)
deviceIdOffset := &DISPLAY_DEVICE + 4 + ((32 + 128) << !!A_IsUnicode) + 4
DeviceIDs := []
while DllCall("EnumDisplayDevices", "Ptr", 0, "UInt", A_Index - 1, "Ptr", &DISPLAY_DEVICE, "UInt", 0) {
deviceName := StrGet(&DISPLAY_DEVICE + 4)
while DllCall("EnumDisplayDevices", "Str", deviceName, "UInt", A_Index - 1, "Ptr", &DISPLAY_DEVICE, "UInt", 0) {
flag := NumGet(deviceIdOffset - 4, "UInt")
if (flag & DISPLAY_DEVICE_ACTIVE) && !(flag & DISPLAY_DEVICE_MIRRORING_DRIVER) {
str := StrGet(deviceIdOffset)
RegExMatch(str, "\\\K[^\\]+", deviceId)
DeviceIDs.Push(deviceId)
}
}
}
Return DeviceIDs
}
GetDevRegKeys(DeviceIDs) {
static GUID_CLASS_MONITOR := "{4D36E96E-E325-11CE-BFC1-08002BE10318}"
, flags := (DIGCF_PROFILE := 0x00000004)
| (DIGCF_PRESENT := 0x00000002)
, INVALID_HANDLE_VALUE := 0xFFFFFFFF
, MAX_DEVICE_ID_LEN := 0x000000C8
, DICS_FLAG_GLOBAL := 0x00000001
, DIREG_DEV := 0x00000001
, KEY_READ := 0x00020019
hLib := DllCall("LoadLibrary", "Str", "setupapi.dll", "Ptr")
VarSetCapacity(CLSID, 16, 0)
DllCall("ole32\CLSIDFromString", "WStr", GUID_CLASS_MONITOR, "Ptr", &CLSID)
hDeviceInfoSet := DllCall("setupapi\SetupDiGetClassDevsEx", "Ptr", &CLSID, "Ptr", 0, "Ptr", 0, "UInt", flags, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")
VarSetCapacity(SP_DEVINFO_DATA, size := 24 + A_PtrSize, 0)
NumPut(size, SP_DEVINFO_DATA)
VarSetCapacity(deviceID, MAX_DEVICE_ID_LEN << !!A_IsUnicode, 0)
RegKeys := []
while DllCall("setupapi\SetupDiEnumDeviceInfo", "Ptr", hDeviceInfoSet, "UInt", A_Index - 1, "Ptr", &SP_DEVINFO_DATA) {
DllCall("setupapi\SetupDiGetDeviceInstanceId", "Ptr", hDeviceInfoSet, "Ptr", &SP_DEVINFO_DATA, "Str", deviceID, "UInt", MAX_DEVICE_ID_LEN, "UInt", 0)
for k, v in DeviceIDs {
if InStr(deviceID, v) {
hKey := DllCall("setupapi\SetupDiOpenDevRegKey", "Ptr", hDeviceInfoSet, "Ptr", &SP_DEVINFO_DATA
, "UInt", DICS_FLAG_GLOBAL, "UInt", 0, "UInt", DIREG_DEV, "UInt", KEY_READ, "UInt")
( hKey && hKey != INVALID_HANDLE_VALUE && RegKeys.Push(hKey) )
break
}
}
}
DllCall("setupapi\SetupDiDestroyDeviceInfoList", "Ptr", hDeviceInfoSet)
DllCall("FreeLibrary", "Ptr", hLib)
Return RegKeys
}
GetPhysicalSizeFromReg(DevRegKeys) {
static ERROR_NO_MORE_ITEMS := 0x00000103
VarSetCapacity(valueName, 10, 0)
VarSetCapacity(EDID, 1024, 0)
PhysicalSizes := []
for k, hKey in DevRegKeys {
Loop {
hr := DllCall("Advapi32\RegEnumValue", "Ptr", hKey, "UInt", A_Index - 1, "Str", valueName, "UIntP", 10
, "Ptr", 0, "UIntP", type, "Ptr", &EDID, "UIntP", 1024, "UInt")
if (hr = ERROR_NO_MORE_ITEMS)
break
if (valueName = "EDID") {
PhysicalSizes.Push({ width: ( (*(&EDID + 68) & 0xF0) << 4 ) + *(&EDID + 66)
, height: ( (*(&EDID + 68) & 0x0F) << 8 ) + *(&EDID + 67) })
}
}
DllCall("Advapi32\RegCloseKey", "Ptr", hKey)
}
Return PhysicalSizes
}
Вариант с дополнительным чтением 21 и 22 байтов и сравнением результатов:
if Arr := GetMonitorPhysicalSize() {
for k, v in Arr
res .= (res = "" ? "" : "`n`n") . "monitor " . k . "`n"
. "width: " . v.width . " cm" . "`n"
. "height: " . v.height . " cm"
}
MsgBox, % res
GetMonitorPhysicalSize() {
DeviceIDs := GetMonitorIDs()
if !DeviceIDs[1]
throw "Failed to get monitors device ids"
DevRegKeys := GetDevRegKeys(DeviceIDs)
if !DevRegKeys[1]
throw "Failed to get reg keys"
Info := GetPhysicalSizeFromReg(DevRegKeys)
if !Info[1]
throw "Failed to get reg data"
Return Info
}
GetMonitorIDs() {
static DISPLAY_DEVICE_ACTIVE := 0x00000001
, DISPLAY_DEVICE_MIRRORING_DRIVER := 0x00000008
VarSetCapacity(DISPLAY_DEVICE, size := 8 + (416 << !!A_IsUnicode), 0)
NumPut(size, DISPLAY_DEVICE)
deviceIdOffset := &DISPLAY_DEVICE + 4 + ((32 + 128) << !!A_IsUnicode) + 4
DeviceIDs := []
while DllCall("EnumDisplayDevices", "Ptr", 0, "UInt", A_Index - 1, "Ptr", &DISPLAY_DEVICE, "UInt", 0) {
deviceName := StrGet(&DISPLAY_DEVICE + 4)
while DllCall("EnumDisplayDevices", "Str", deviceName, "UInt", A_Index - 1, "Ptr", &DISPLAY_DEVICE, "UInt", 0) {
flag := NumGet(deviceIdOffset - 4, "UInt")
if (flag & DISPLAY_DEVICE_ACTIVE) && !(flag & DISPLAY_DEVICE_MIRRORING_DRIVER) {
str := StrGet(deviceIdOffset)
RegExMatch(str, "\\\K[^\\]+", deviceId)
DeviceIDs.Push(deviceId)
}
}
}
Return DeviceIDs
}
GetDevRegKeys(DeviceIDs) {
static GUID_CLASS_MONITOR := "{4D36E96E-E325-11CE-BFC1-08002BE10318}"
, flags := (DIGCF_PROFILE := 0x00000004)
| (DIGCF_PRESENT := 0x00000002)
, INVALID_HANDLE_VALUE := 0xFFFFFFFF
, MAX_DEVICE_ID_LEN := 0x000000C8
, DICS_FLAG_GLOBAL := 0x00000001
, DIREG_DEV := 0x00000001
, KEY_READ := 0x00020019
hLib := DllCall("LoadLibrary", "Str", "setupapi.dll", "Ptr")
VarSetCapacity(CLSID, 16, 0)
DllCall("ole32\CLSIDFromString", "WStr", GUID_CLASS_MONITOR, "Ptr", &CLSID)
hDeviceInfoSet := DllCall("setupapi\SetupDiGetClassDevsEx", "Ptr", &CLSID, "Ptr", 0, "Ptr", 0, "UInt", flags, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")
VarSetCapacity(SP_DEVINFO_DATA, size := 24 + A_PtrSize, 0)
NumPut(size, SP_DEVINFO_DATA)
VarSetCapacity(deviceID, MAX_DEVICE_ID_LEN << !!A_IsUnicode, 0)
RegKeys := []
while DllCall("setupapi\SetupDiEnumDeviceInfo", "Ptr", hDeviceInfoSet, "UInt", A_Index - 1, "Ptr", &SP_DEVINFO_DATA) {
DllCall("setupapi\SetupDiGetDeviceInstanceId", "Ptr", hDeviceInfoSet, "Ptr", &SP_DEVINFO_DATA, "Str", deviceID, "UInt", MAX_DEVICE_ID_LEN, "UInt", 0)
for k, v in DeviceIDs {
if InStr(deviceID, v) {
hKey := DllCall("setupapi\SetupDiOpenDevRegKey", "Ptr", hDeviceInfoSet, "Ptr", &SP_DEVINFO_DATA
, "UInt", DICS_FLAG_GLOBAL, "UInt", 0, "UInt", DIREG_DEV, "UInt", KEY_READ, "UInt")
( hKey && hKey != INVALID_HANDLE_VALUE && RegKeys.Push(hKey) )
break
}
}
}
DllCall("setupapi\SetupDiDestroyDeviceInfoList", "Ptr", hDeviceInfoSet)
DllCall("FreeLibrary", "Ptr", hLib)
Return RegKeys
}
GetPhysicalSizeFromReg(DevRegKeys) {
static ERROR_NO_MORE_ITEMS := 0x00000103
VarSetCapacity(valueName, 10, 0)
VarSetCapacity(EDID, 1024, 0)
PhysicalSizes := []
for k, hKey in DevRegKeys {
Loop {
hr := DllCall("Advapi32\RegEnumValue", "Ptr", hKey, "UInt", A_Index - 1, "Str", valueName, "UIntP", 10
, "Ptr", 0, "UIntP", type, "Ptr", &EDID, "UIntP", 1024, "UInt")
if (hr = ERROR_NO_MORE_ITEMS)
break
if (valueName = "EDID") {
p := &EDID, n := *(p + 68)
w_mm := ( (n & 0xF0) << 4 ) + *(p + 66)
h_mm := ( (n & 0x0F) << 8 ) + *(p + 67)
w_cm := *(p + 21)
h_cm := *(p + 22)
if Round(w_mm/10) = w_cm && Round(h_mm/10) = h_cm
w := Round(w_mm/10, 1), h := Round(h_mm/10, 1)
else
w := w_cm, h := h_cm
PhysicalSizes.Push({ width: w, height: h })
}
}
DllCall("Advapi32\RegCloseKey", "Ptr", hKey)
}
Return PhysicalSizes
}
Здесь ответ выдаётся в сантиметрах.
teadrinker, работает!
monitor 1
width: 476 mm
height: 268 mmmonitor 2
width: 476 mm
height: 268 mm
Почему-то показывает, что у меня 2 монитора. На самом деле 2 видеокарты: к встроенной ничего не подключено, к внешней подключен один монитор по HDMI.
У меня показало: 1 монитор, 480х270мм.
В аиде64: Макс. видимая область экрана 480 mm x 270 mm (21.7").
Хотя монитор на 27" (59.5х33.5мм реальных).
Решил попробовать, как-то не очень легко вышло
Проще наверное 21-ый и 22-ой байт читать из реестра.
У меня показало: 1 монитор, 480х270мм.
А что показывает эта утилита?
http://www.nirsoft.net/utils/monitor_info_view.html
Malcev
Те же данные 48х27 см (21.7")
Показало две строки подключения (1 не актив, 2 актив = оба один монитор, видать распознало переустановку виндовс).
teadrinker, у меня этот скрипт выдает ошибку при запуске.
В чем может быть дело ?
Пишет что: "Error: Failed to get reg data"
Те же данные 48х27 см (21.7")
Значит криво написан edid.
ОсиповаТатьяна, а эта утилита показывает?
http://www.nirsoft.net/utils/monitor_info_view.html
Malcev
Я думаю наоборот - данные совпали, значит эта инфа и приходит от монитора в комп.
Только вопрос: почему не верны эти данные...
Я думаю наоборот - данные совпали, значит эта инфа и приходит от монитора в комп
Ну я и говорю, что edid у монитора криво написан.
А что за модель?
Malcev, эта утилита показывает - пустое место. То есть ничего.
Монитор у меня - всего один.
Но утилита его не видит.
ОсиповаТатьяна
Возможно драйвера не установлены / криво установлены.
Malcev
Монитор LG Full HD, модель 27MK600M.
__Михаил__, у меня "универсальный монитор не PnP"
Решил попробовать
dxva2 не то?
Не думаю. Насколько я понял, эти данные записаны только в реестре, и именно в кусте HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY. Так что задача сводится к тому, чтобы в этом кусте выбрать правильный ключ из нескольких, и не важно, какими функциями/интерфейсами для этого пользоваться.
А может кто-то с двумя мониторами проверить?
У меня два монитора, я правда сейчас не особо в форме, скажи какой код запустить?
Через dxva2 я получаю состояние монитора и управляю им, была тема. Просто подумал что это может помочь, и вроде как кода меньше, и насколько помню, это не про реестр, а про обращение непосредственно к девайсу.
Вот этот. Правда, имеет смысл, если мониторы разного размера.
monitor 1
width: 477 mm
height: 268 mmmonitor 2
width: 521 mm
height: 293 mm
Всё как есть, точь в точь.
Правда, имеет смысл, если мониторы разного размера.
Не понял про размер, но у мониторов разное разрешение 1680х1050 и 1920х1080.
Имеешь в виду, что например при разрешении 1920х1080 покажет одинаковый размер?
Может тогда в интерфейсе есть параметр DPI монитора.
Не, всё ок, DPI не при чём.
Правда, имеет смысл, если мониторы разного размера.
Так а что ты имел в виду?
Имел в виду физический размер.
Ну то есть при одинаковом разрешении двух мониторов, физический размер каждого из них будет реальным?
Должен быть в любом случае. Мы же его из реестра читаем,для каждого монитора свой ключ. Я просто сомневался в одном месте
hKey := DllCall("setupapi\SetupDiOpenDevRegKey", "Ptr", hDeviceInfoSet, "Ptr", &SP_DEVINFO_DATA
, "UInt", DICS_FLAG_GLOBAL, "UInt", 0, "UInt", DIREG_DEV, "UInt", KEY_READ)
hKey здесь не уникальное значение, думал, как бы оно всё время одинаковым не было.
Кстати, пока тема тёплая, пиксель квадратный? Если разделить ширину в мм на ширину в пикселях то получится DPI, или по высоте может получится другое?
__Михаил__, а какие значения у 21 и 22 байта в реестре?
Просто в коде teadrinkera и, возможно, этой утилиты вместо the active physical screen size of the display device:
3.6.2Horizontal and Vertical ScreenSizeorAspect Ratio: 2BytesThe horizontal and vertical screensize oraspect ratio parameter fields are required ELEMENTSin EDID structure version 1, revision 4 for all display productsexcept for certain types of projectors. The horizontal and vertical screen size parameters provide information on the screendimensions of the display device, rounded to the nearest centimeter (cm)
мы получаем the addressable video size of the displayed image (derived from the incoming video signal):
15.Horizontal and vertical screensize fields in Table 3.12 define the active physical screen size of the display device. The active physical screen size is defined as the rectangular area where light can be controlled on the display. The horizontal and vertical addressable video image size fields in Table 3.21define the addressable video size of the displayed image (derived from the incoming video signal). For Example:When a16:9ARvideo signal with 1280 x 720 pixelsis displayed on a 5:4 AR screen with 1280 x 1024 pixels,the horizontal image size in table 3.21 will be equal to the horizontal screen size in table 3.12. Andthe vertical image size in Table 3.21will be less than the vertical screen size listed in table 3.12 (common term is “letterbox”). Another Example: When a5:4 AR video signal with 1280x1024 pixels isdisplayed on a 16:9 AR screen with 1920x1080 pixels, the verticalimage size in Table 3.21will be equal to the vertical screen size in Table 3.12. Andthe horizontal image size in table 3.21will be less than the horizontal screen size listed in Table 3.12 (common term is “pillarbox”). These examples assume that the scaling function (in the display) maintains the image aspect ratio of the video content while scaling the image up (or down) to the maximum horizontal or vertical screensize listed in Table 3.12.16. The horizontal and vertical addressable video image sizes in Table 3.21shall be less than or equal to the maximum horizontal and vertical screensizes listed in Table 3.12.
https://glenwing.github.io/docs/VESA-EEDID-A2.pdf
Не совсем уверен, что это правильно.
У меня 21 и 22 байты определяют размер в сантиметрах, то же самое, но менее точно.
Чтобы проверить, нужно просто заменить это
PhysicalSizes.Push({ width: ( (*(&EDID + 68) & 0xF0) << 4 ) + *(&EDID + 66)
, height: ( (*(&EDID + 68) & 0x0F) << 8 ) + *(&EDID + 67) })
на это
PhysicalSizes.Push({ width: *(&EDID + 21)
, height: *(&EDID + 22) })
у меня "универсальный монитор не PnP"
Нужно чтоб PnP был.
Либо драйвер устанавливать, либо пробовать через другой интерфейс подключать.
У меня 21 и 22 байты определяют размер в сантиметрах, то же самое, но менее точно.
У меня тоже.
Но вот пишут:
I don’t know how common this problem is, but a large set Dell 2007FP monitors at our site reported:
41cmx31cm in EDID 21-22 (0x29 0x1F)
367mmx275mm in EDID 66-68 (0x6F 0x13 0x11)
An actual physical measurement gave 406mmx305mm.
https://ofekshilon.com/2011/11/13/readi … omment-624
Кстати, пока тема тёплая, пиксель квадратный?
В редких случаях (некоторые дисплеи для промышленных устройств) бывает и неквадратный.
Но вот пишут:
Ну, можно тогда сравнить одни значения с другими, если разные — брать в сантиметрах.
Если разделить ширину в мм на ширину в пикселях то получится DPI
Ха-ха, нет.
serzh82saratov
https://ru.wikipedia.org/wiki/Ppi
Тогда такой вопрос.
Мой монитор называется LG-22M38A
Размер экрана (дюйм) 21.5
Разрешение дисплея 1920х1080
И как по этим двум характеристикам вычислить примерную ширину пикселя (только ширину) ?
ОсиповаТатьяна, размер экрана в данном случае — это размер по диагонали. Если у нас есть прямоугольник с известными размерами сторон, то как вычислить его диагональ?
teadrinker, так я не про вычисление диагонали спрашиваю, а про ширину одного пикселя.
Боюсь, без вычисления диагонали в данном случае не обойтись.
Чтобы узнать ширину одного пикселя, нужно ширину матрицы (миллиметры) разделить на количество пикселей по ширине (штуки). Длина диагонали известна, соотношение сторон известно (1920х1080). Осталось вспомнить геометрию чтобы вычислить ширину матрицы.
Malcev
Не стоит путать это с dpi, так как некоторые принтеры при печати ставят точки без смешения красок
Не принципиально в общем случае, или я недопонял.
serzh82saratov пишет:Если разделить ширину в мм на ширину в пикселях то получится DPI
Ха-ха, нет.
Да, я ошибаюсь, я упомянул про количество точек на площадь, а разговор про количество точек на отрезок.
Если разделить ширину в мм на ширину в пикселях то получится DPI, или по высоте может получится другое?
DPI - это "точек на дюйм". Строго говоря, разрешающую способность монитора выражают в PPI. Ну а если разделить ширину в мм на ширину в пикселях... Получим ширину пикселя в миллиметрах. А не "точек на дюйм".
Вы полностью перефразировали мой пост.
А не "точек на дюйм".
Я бы сказал - "точек на дюйм квадратный".
Я бы сказал - "точек на дюйм квадратный".
Тоже нет, на линейный.
То есть например 600ppi, это 360000 точек на дюйм квадратный?
Ну наверно, а что?
Так как же ширину пикселя узнать ?
ОсиповаТатьяна, начните с диагонали. Ну, или можно, как советовал ypppu. Тут понадобится система уравнений с двумя неизвестными, не знаю, что вам будет проще.
ОсиповаТатьяна, а для чего вам нужна эта информация?
Наверное чертёж прикладывать к монитору или типа того.
teadrinker, а как выглядит эта система уравнений с двумя неизвестными ?
Да обычно. У вас есть два неизвестных — физические ширина и высота, при этом есть физ. размер диагонали. Гуглите, каково соотношение сторон прямоугольника и диагонали. Это будет первым уравнением. Далее, у вас есть соотношение ширины и высоты — 1920/1080, это будет вторым.
Добавил вариант с чтением 21 и 22 байтов, может, у кого-то лучше заработает.
Сначала я привел ссылку на вычисление ppi, потом ypppu, а топикстартеру все никак непонятно, как его вычислить. ОсиповаТатьяна, по диагонали свою тему читаете?
teadrinker
Одинаковые результаты выдают оба скрипта, разве что разница в мм и см.
Malcev
Чуток не понял про какие значения у 21 и 22 байта в реестре нужно?
Можно более подробнее.
__Михаил__, уже не нужно, мой скрипт читает эти байты.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться