【问题标题】:Getting actual screen dpi/ppi under windows在 windows 下获取实际屏幕 dpi/ppi
【发布时间】:2012-09-29 12:50:31
【问题描述】:

我想要实际屏幕 dpi/ppi,而不是 C++ 中用于字体的 dpi 设置。

我尝试了以下代码:

版本 1,报告 72 dpi,这是错误的。

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hSize = GetDeviceCaps(screen, HORZSIZE);
double vSize = GetDeviceCaps(screen, VERTSIZE);
double hRes = GetDeviceCaps(screen, HORZRES);
double vRes = GetDeviceCaps(screen, VERTRES);
double hPixelsPerInch = hRes / hSize * 25.4;
double vPixelsPerInch = vRes / vSize * 25.4;
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;

版本 2,报告 96 dpi,这是 Windows dpi 字体设置,但不是实际屏幕 dpi。

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
double vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;

【问题讨论】:

  • @BrianHaak:正如在这个问题和您链接的问题中所指出的,EDID 并不总是可用,有时 EDID 中的信息是错误的。

标签: c++ windows screen dpi ppi


【解决方案1】:

老实说,我对这里的答案感到困惑。

微软有一个 GetDpiForMonitor 方法:

https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx

显示器确实会将其物理尺寸暴露给工具。您可以使用 HWiNFO64 工具读取显示器的宽度和高度(以厘米为单位)。因此,如果他们得到它(DDI?),那么您可以自己访问该信息是有道理的。

即使是不同的 Stack Overflow 帖子也提到使用 WmiMonitorBasicDisplayParams 获取数据。

How to get monitor size

所以顶部的帖子是完全正确的,100% 是错误的。

【讨论】:

  • GetDpiForMonitor 为您提供每逻辑英寸的点数,而不是物理英寸。一些显示器通过 EDID 暴露其物理尺寸。不幸的是,这并不是普遍可用的。许多显示器不支持它。 WmiMonitorBasicDisplayParams 文档的备注部分指出实际值可能不可用。此外,显示器可以是投影仪,投影仪无法知道投射距离,因此即使知道变焦设置也无法计算物理尺寸。在所有情况下都没有获得实际 DPI 的可靠方法。对不起。
  • GetDpiForMonitor 调用 MDT_RAW_DPI 确实会返回实际的物理 DPI(如果它明显可用)。在我的机器上,MDT_EFFECTIVE_DPI = (144, 144), MDT_RAW_DPI = (158, 160)。
  • 当时没有错,只是过时了。我认为您所指的那些 API 是在 Windows 8.1 和 10 中添加的
【解决方案2】:

不幸的是,您所要求的在一般情况下是不可能的。

Windows 不知道物理屏幕大小。 Windows 可能知道您的屏幕有 1024x768 像素,但它不知道屏幕实际有多大。您可以将电缆从旧的 13" 屏幕中拉出,并将其连接到 19" 显示器,而无需更改分辨率。 DPI 会有所不同,但 Windows 不会注意到您更改了显示器。

您可以获得打印机的真实物理尺寸和 DPI(假设驱动程序没有说谎),但不能获得屏幕。至少不可靠。

更新

正如其他人所指出的,在较新的显示器和操作系统 (EDID) 之间存在双向通信标准,这可能使这些信息可用于某些设备。但我还没有找到提供此信息的监视器。

即使 EDID 普遍可用,但在一般情况下仍然无法解决,因为显示器可能是视频投影仪,其中 DPI 取决于变焦、焦距、镜头类型和投射距离。投影仪极不可能知道投射距离,因此它无法报告实际的 DPI。

【讨论】:

  • 赞成正确答案。 Windows 不知道显示器的物理尺寸。它只知道它是1680x1050。它不知道是 22" 显示器 (90dpi)、21" 显示器 (94dpi)、20" 显示器 (99dpi) 还是 4" 手持设备 (495dpi)。幸运的是,作为 Windows 开发人员,您不必关心显示器的物理分辨率。
  • @Ian Boyd Fortunately as a Windows developer you don't have to care about the monitor's physical resolution. 随着 4K 显示器的出现,事实证明并非如此。人们发现 Windows + 4K 并不是非常有用,因为大多数程序不能很好地处理 DPI 增加。即使使用 Windows 进行扩展也不能全面发挥作用。作为渴望获得 4K 显示器的人,我希望事情能得到解决。
  • @leetNightshade:Ian 是对的,Windows 开发人员并不关心 物理 DPI。他们必须关心逻辑 DPI。不幸的是,Windows 让太多的开发人员长期忽视它而侥幸逃脱,所以现在解决方案有了很大的进步,我们都在受苦。
  • @leetNightshade 作为一名 Windows 开发人员,您应该从 1980 年代开始从事 Web 开发人员今天学习的工作。在网络上,您应该在emen 中指定图像、按钮、文本框等的大小。这样你就不用关心显示器的分辨率了。几十年来,Windows 一直在使用 em 的等效项:对话框单元(基于您使用的字体中平均字符的宽度和高度)。
【解决方案3】:

发现获取DPI信息可以使用以下方法产生精确值。

ID2D1Factory* m_pDirect2dFactory;
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);
FLOAT dpiX, dpiY;
m_pDirect2dFactory->GetDesktopDpi( &dpiX, &dpiY );

【讨论】:

  • -1。问题是询问实际的 physical DPI。此 D2D 界面(仅在 Windows 7 及更高版本上可用)只是提供您从GetDeviceCaps(hdcScreen, LOGPIXELSX) 获得的相同逻辑 DPI。正如我在回答中所说,没有办法确切地得到 Andy Li 的要求,因为 Windows 不知道每台显示器的真实尺寸。另请注意,您可以连接两个具有不同物理 DPI 的不同显示器,而这些方法只能为“桌面”提供一个答案。
【解决方案4】:

我想你所追求的是:

GetDeviceCaps(hdcScreen, LOGPIXELSX); GetDeviceCaps(hdcScreen, LOGPIXELSY);

【讨论】:

  • 这对打印机 DC 很有用。对于监视器,它返回每逻辑英寸的像素数,这不太可能与物理 DPI 匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2017-10-29
相关资源
最近更新 更多