2

我有一些从http://bytes.com/topic/c-sharp/answers/572657-net-clipboard-metafiles获得的 C# 代码,它在以下两个设置下复制单元格范围:

  • 如屏幕所示,
  • 打印时如图所示

当我查看生成的图元文件的分辨率(记录为Gets the resolution, in pixels-per-inch, of this Image object)时,我会根据复制方法获得不同的值。

  • 使用打印时显示的选项,分辨率为 600,我相信这与我在 Excel 中的 DPI 设置相对应。

  • 使用As shown on screen设置,它会吐出类似Metafile.VerticalResolution = 72.08107and的内容Metafile.HorizontalResolution = 71.95952。在其他机器上,我看到这个值变化很大(值在 111、130 左右等)。

缩放级别似乎对此没有影响。根据我的观察,这些值在单台机器上保持一致,但可能因机器而异。

任何人都可以解释 Excel 在计算图元文件的分辨率时遵循的逻辑,如屏幕所示模式?

更改 Windows 分辨率并测量图元文件分辨率后,这是我生成的表(希望它看起来格式正确):

Width   Height  HorizontalResolution    VerticalResolution
1680    1050        71.95952                72.08107
1600    1024        72.05672                72.04874
1600    900         72.05672                71.88678
1360    768         71.96666                71.98228
1280    1024        71.9292                 72.04874
1280    960         71.9292                 71.9292
1280    800         71.9292                 72.05672
1280    768         71.9292                 71.98228
1280    720         71.9292                 71.99999
1152    864         72.07093                71.95278
1088    612         71.96666                71.96666
1024    768         72.04874                71.98228
960     600         71.9292                 71.88678
800     600         72.05672                71.88678

在虚拟机(同一台物理机)上运行类似过程后,结果如下。比物理机本身更不稳定。这些数据可能没有用,但我想我还是会提供它。

Width   Height  HorizontalResolution    VerticalResolution
1680    1050    133.35                  111.125
1280    800     101.6                   84.66666
1024    768     81.27999                81.27999
800     600     63.5                    63.5
4

1 回答 1

4

我的假设

我相信这与在 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 应用程序中运行此代码,控制台应用程序应该能够获取屏幕设备上下文,但可能不是......)

于 2011-12-05T06:04:23.140 回答