我的假设
我相信这与在 LCD 显示器上运行非原生分辨率有关。在“过去”中,CRT 本身并没有原生分辨率。因此,对于给定的显示器尺寸或纵横比,计算机不知道任何首选分辨率。使用较新的数字显示器 (LCD),如果安装正确,计算机现在可以知道显示器的首选分辨率和纵横比。我的 Windows 7 机器在我的 LCD 的原始分辨率旁边显示“推荐”,然后以黑色显示其他 2 个相同纵横比的分辨率,其余的“不匹配”没有标记但可以选择(导致我讨厌看到的压扁或拉伸外观在其他人的计算机上!)。
Windows 中 96 和 120 的默认 DPI 是在 CRT 时代建立的。我的 Windows 7 机器甚至不再说 DPI,它只是说“更小”、“中”、“更大”。
无论哪种方式,当您购买 1920x1080 或 1920x1200 的 LCD 显示器但将显示分辨率设置为更小时,都会产生转换系数。在接近 72 的水平和垂直分辨率不匹配的情况下,您的非原生显示分辨率可能与水平方向的缩放因子不完全相同,从而导致这种小的差异。
如何检验我的假设
在您的每台测试机器上记录操作系统配置的分辨率和显示的原始分辨率。查看这两者之间的比率是否接近您的图元文件“在屏幕上”与 96 或 120dpi 之间的比率。我希望您在物理机上进行此测试,以简单地排除使用远程桌面或虚拟机驱动程序进一步扩展的可能性。
如果解决方案没有立即显现,请进一步记录 DPI 或“更小”、“中”和“更大”的操作和控制面板设置。Windows XP 的行为可能与 Windows Vista/Windows 7 不同。
您还可以在同一台物理机器上多次重新运行测试,在测试之间调整配置的显示分辨率并观察任何变化。如果我的假设是正确的,您应该在同一物理机器/显示器组合上看到每个配置的显示分辨率的不同元文件分辨率,并且该结果应该是可预测和可重复的(返回第一个分辨率应该返回相同的元文件分辨率)
编辑#1
我发现了一篇很好的文章,讨论了物理 DPI 与逻辑 DPI。阅读以下内容:Windows 中的 96 DPI 从何而来?
所以现在我推荐的下一个测试是改变显示器!您是否有不同品牌/尺寸/分辨率的 LCD 显示器可供测试?您不需要像上面的第一次测试那样多的线,因为我们已经确定各种分辨率往往会为相同的显示器产生非常相似的 DPI。只需测试几个常见的分辨率,包括显示器的原始分辨率和 1024x768 作为比较的“基线”。
同样在 Windows 7 中浏览时,我确实在控制面板->显示中找到了“设置自定义文本大小 (DPI)”链接,其中包括“使用 Windows XP 样式 DPI 缩放”选项。虽然我认为这不是主要问题,但好奇心让我对它的效果感兴趣,所以我想我会提到它。
编辑#2 - 已解决!
您在元文件中看到的分辨率是显示器的物理 DPI。我将在此处发布一些 C# 代码供您测试:
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,
/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,
/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,
// Printing related DeviceCaps. These replace the appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,
/// <summary>
/// Current vertical refresh rate of the display device (for displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}
private void GetScreenInfo()
{
IntPtr sdc = IntPtr.Zero;
try
{
//Get the Screen Device Context
sdc = GetDC(IntPtr.Zero);
// Get the Screen Devive Context Capabilities Information
Console.WriteLine(string.Format("Size: {0} mm X {1} mm", GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE), GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE)));
Console.WriteLine(string.Format("Desktop Resolution: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES), GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES)));
Console.WriteLine(string.Format("Logical DPI: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSX), GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSY)));
//Remember: Convert Millimeters to Inches 25.4mm = 1 inch
double PhsyicalDPI_X = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE);
double PhsyicalDPI_Y = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE);
Console.WriteLine(string.Format("Physical DPI: {0}x{1}", PhsyicalDPI_X, PhsyicalDPI_Y));
}
finally
{
ReleaseDC(IntPtr.Zero, sdc);
}
}
我显示器上的这段代码输出以下内容:
- 尺寸:677 毫米 X 381 毫米
- 桌面分辨率:1920x1080
- 逻辑 DPI:96x96
- 物理 DPI:72.0354505169867x72
注意到逻辑和物理 DPI 了吗?物理 DPI 看起来是不是很眼熟?读完那篇关于 72dpi 反映 1pt=1px 的文章后,这一切都说得通了。在您的各种测试机器上尝试此代码,让我知道它是如何运行的!(仅供参考,我在 C# winforms 应用程序中运行此代码,控制台应用程序应该能够获取屏幕设备上下文,但可能不是......)