Excel如何计算复制范围时生成的元文件的分辨率(如屏幕上所示)?

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

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

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

  • 随着印刷选项显示,分辨率是600,我相信对应于我在Excel中的DPI设置。

  • 如屏幕设置所示 ,它会吐出类似于Metafile.VerticalResolution = 72.08107Metafile.HorizontalResolution = 71.95952 。 在其他机器上,我看到这个值有很大的不同(值大约在111,130等)。

缩放级别似乎没有影响到这一点。 从我所观察到的,这些值在一台机器上保持一致,但是可能因机器而异。

任何人都可以解释的计算的图元文件的解决scheme, 下面的逻辑Excel 如屏幕模式所示

在更改窗口分辨率和测量图元文件分辨率后,下面是我生成的表格(希望看起来格式正确):

 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 

我的假设

我相信这与在LCD监视器上运行非本地分辨率有关。 在“旧时代”,CRT本身没有原生parsing度。 因此,计算机不知道给定的显示器尺寸或宽高比的任何首选分辨率。 对于较新的数字显示器(LCD),如果正确安装,则计算机现在知道显示器的首选分辨率和宽高比。 我的Windows 7机器显示“推荐”旁边我的液晶显示器的原始分辨率,然后显示其他2个相等的纵横比分辨率在黑色,其余的“不匹配”是未标签,但可选(导致我讨厌看到挤压或拉伸的外观在其他人的电脑!)。

CRT窗口中的默认DPI为96和120。 我的Windows 7机器甚至没有说DPI了,它只是说“更小”,“中等”,“更大”。

无论哪种方式,当您购买1920×1080或1920×1200的液晶显示器,但将显示分辨率设置为更小时,则会产生转换因子。 在水平分辨率和垂直分辨率不匹配的情况下,非原生的显示分辨率可能与垂直分辨率不完全相同,因为水平分辨率的差异很小。

如何检验我的假设

在每个testing机器上logging操作系统configuration的分辨率和显示器的原始分辨率。 看看这两者之间的比例是否接近你的图元文件的“屏幕上”与96或120dpi之间的比例。 我宁愿你在物理机器上进行这个testing,以便简单地排除使用远程桌面或虚拟机驱动程序进一步扩展的可能性。

如果解决scheme不是立即显现,请进一步loggingDPI或“更小”,“中等”和“更大”的操作和控制面板设置。 Windows XP的行为可能与Windows Vista / Windows 7不同。

您也可以在同一台物理机器上多次重新运行testing,调整testing之间configuration的显示分辨率并观察任何更改。 如果我的假设是正确的,您应该在同一物理机器/显示组合上看到每个configuration显示分辨率的不同图元文件分辨率,并且此结果应该是可预测和可重复的(返回到第一个分辨率应返回到相同的图元文件分辨率)

编辑#1

我发现了一篇很好的文章,讨论物理DPI vs逻辑DPI。 读一下这个: 96 DPI从哪里来的?

所以现在我build议的下一个testing是改变显示器! 你有不同的品牌/尺寸/分辨率的液晶显示器可供testing吗? 你不需要像上面第一次testing那么多的线,因为我们已经build立了各种分辨率倾向于产生相同的显示非常相似的DPI。 只是testing一些常见的解决scheme,包括显示器的原始分辨率和1024×768作为比较的“基准”。

同时,在Windows 7中,我还在控制面板 – >显示中find了“设置自定义文本大小(DPI)”链接,其中包括“使用Windows XP样式DPI缩放”选项。 虽然我不认为这是主要问题,但好奇心使我对它的效果感兴趣,所以我想我会提到它。

编辑#2 – 已解决!

您在元文件中看到的分辨率是显示器的物理DPI。 我会在这里张贴一些C#代码来testing你自己:

 [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毫米
  • 桌面分辨率:1920×1080
  • 逻辑DPI:96×96
  • 物理DPI:72.0354505169867×72

注意逻辑DPI和物理DPI? 这个物理DPI看起来很熟悉吗? 阅读那篇反映1pt = 1px的72dpi的文章,这一切都是有道理的。 试试这个代码,在你的各种testing机器上,让我知道它是怎么回事! (仅供参考,我在C#winforms应用程序中运行此代码,控制台应用程序应该能够获取屏幕设备上下文,但也许不会…)