WIN10下系统缩放比例(DPI)的魔幻设置

WIN10下系统缩放比例(DPI)的魔幻设置


前言

前几天突然想起了以前做的一个答题器,原理是截取图片以后用OCR识别出题目,然后再过题库。但是一直有个BUG没法解决,就是WIN7/10有系统缩放(DPI),如果DPI不是100%,就会导致截图区域不对,无法识别。

在网上查阅了很多资料,主要都是通过Windows的GetDeviceCaps加上OGPIXELSX参数(或者OGPIXELSY也行)来获得系统DPI的。这个函数查询出来结果需要换算成缩放百分比。

WIN10下系统缩放比例(DPI)的魔幻设置

但是自己试了很长时间,发现无论缩放比例设置成什么样子,这个函数查出来的永远都是96(就是没有缩放的时候的结果)。过了几天,又突然发现能正常的查出120了(也就是125%的缩放)。绞尽脑汁想了很久,才想出来是为什么。

第二种获得DPI的方法则是用可视桌面的像素(DESKTOPHORZRES)除以真实像素(HORZRES)来获得比例。这两种方法有什么区别后面会着重说,我们先来讲WIN10的坑爹设置。


WIN10的坑爹设置

在WIN10里有两种设置缩放的方法,一种是在“更改文本、应用等项目的大小”里选择,只有几种预设好的比例可以选择(100%、125%什么的),默认是125%。第二种是在这个选项下面的“高级缩放设置”里填写自定义缩放。

然而这两种方法居然不是相同的!甚至一丁点关系都没有!

你可以脑补有两个系统变量,用第一种设置方式的时候变量A的值会改变,而变量B则变回默认的值(100%);用第二种设置方式的时候变量A会变回默认(96 也就是100%),而变量B则会按照设置的值变化。

这也是为什么之前我测试的那么多次有的时候可以有的时候不可以,因为可以的时候我是用高级模式里的自定义缩放设置的,这样可以查询到正确的DPI,但是用桌面像素除以真实像素的方法不可以!你会发现真实像素居然纹丝不动!然而如果你是用默认方法(更改文本、应用等项目的大小),那么DPI是查询不到的,查询到的永远是96,但是真实像素变了,从1920变成1536了,刚好是125%,程序员都感动哭了。

综上所述

  • 当用户使用默认方法设置缩放时,应该使用GetDeviceCaps(DESKTOPHORZRES)/GetDeviceCaps(HORZRES)获得缩放比例
  • 当用户使用高级模式中的自定义缩放时,应该使用GetDeviceCaps(LOGPIXELSX)再除以0.96(再除以100,因为算出来的数字是百分比)

这两种查询方法还有一种内在逻辑关系,某一种方法能查询出正确的值的时候,另外一种方法的结果一定是100%。因为100%是“默认的值”。

所以:

dpiA = GetDeviceCaps(hDC, DESKTOPHORZRES)/GetDeviceCaps(hDC, HORZRES)
dpiB = GetDeviceCaps(hDC, LOGPIXELSX)/0.96/100
if dpiA == 1:
	return dpiB
elif dpiB == 1:
	return dpiA
elif dpiA == dpiB:
	return dpiA
else:
	return None

逻辑就是,两种DPI中肯定至少有一个是1(默认值),如果两个都是,那就是1,如果只有一个是1,那另外一个一定是真实值。如果两个都不是并且相等,那可能是其他设置方式,反正值都一样,那说明可信度比较高,直接返回即可。如果都不是1,又不相等,那可能是某种未知的情况,返回None表示数据不对,再进行排查。

折腾了半天,终于把WIN10的迷醉DPI设置搞好了。