繁体   English   中英

在Windows中准确确定DPI(10)

[英]Accurately determine DPI in Windows (10)

我有一些代码(从技术上来说)对于在Windows 10中获取监视器的DPI是正确的。

[DllImport("shcore.dll")]
static extern UInt32 GetDpiForMonitor(IntPtr hmonitor,
                                      int dpiType,
                                      out UInt32 dpiX,
                                      out UInt32 dpiY);

[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, UInt32 dwFlags);
...
var whdl = Process.GetCurrentProcess().MainWindowHandle;
var mhdl = MonitorFromWindow(whdl, 0);

GetDpiForMonitor(mhdl, 2, out DpiX, out DpiY); // 255, 256

var ct = PresentationSource.FromVisual(MainImage).CompositionTarget;
var scaleX = ct.TransformToDevice.M11;
var scaleY = ct.TransformToDevice.M22;

var pixelWidth = (int)(GridImage.ActualWidth * DpiX / 96.0);
var pixelHeight = (int)(GridImage.ActualHeight * DpiY / 96.0);

writeableBitmap = new WriteableBitmap(pixelWidth, 
                                      pixelHeight,
                                      DpiX,
                                      DpiY,
                                      System.Windows.Media.PixelFormats.Bgr32,
                                      null);

我使用17英寸(笔记本电脑)4K面板(3840x2160,缩放比例为250%)对此进行了测试。我使用了一个简单的WPF网格控件,其中包含一个图像控件。来自GetDpiForMonitor的DPI为(X:Y)255:256。问题是,这是不准确的。当我绘制一个简单的网格(DPI线分开)时,正方形不是1英寸,它们短了17(原始)像素。 WriteableBitmap在WPF Image控件内部,并且该控件具有Stretch="None"

任何人都知道为什么这些值不正确或如何获得准确的值。 有没有一种方法可以获取显示器的分辨率和尺寸(因此我可以计算DPI)?

更新资料

好吧,这个问题已被否决,但我仍然没有答案,但是我发现这个小难题既有趣又令人恼火(“交流”,“令人烦恼”)。 无论如何,这是将来发送给运行它的任何人的一些其他信息。

首先,这是一台运行Windows 10 Pro Build 15063.483的HP Envy 4K笔记本电脑(W2K87UA#ABA)。 使用我为系统监视器尺寸查询的GetDevCaps

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

private const int HORZSIZE = 4;
private const int VERTSIZE = 6;
private const double MM_TO_INCH_CONVERSION_FACTOR = 25.4;
...
var hDC = System.Drawing.Graphics.FromHwnd(whdl).GetHdc();
int horizontalSizeInMilliMeters = GetDeviceCaps(hDC, HORZSIZE);
double horizontalSizeInInches = horizontalSizeInMilliMeters / MM_TO_INCH_CONVERSION_FACTOR;
int vertivalSizeInMilliMeters = GetDeviceCaps(hDC, VERTSIZE);
double verticalSizeInInches = vertivalSizeInMilliMeters / MM_TO_INCH_CONVERSION_FACTOR;

这将返回以下内容:

horizontalSizeInMilliMeters: 382
horizontalSizeInInches: 15.039370078740159
Measured by hand: 15 1/32 "      15.0625"   382.6 mm

vertivalSizeInMilliMeters: 214
verticalSizeInInches: 8.4251968503937018
Measured by hand:  8 15/32"       8.46875   215.1 mm

这全部算出X dpi为255.329842931937,Y dpi为256.373831775701,大约等于(255,256),这正是GetDpiForMonitor返回的值。

使用WriteableBitmap,我使用以下代码在屏幕上绘制网格:

color = Colors.White;
int color_data = (color.R << 16)
               | (color.G << 8)
               | color.B;
dpiy = (int) DpiY;
for (var y = 0; y < height; y += dpiy) {
    for (var x = 0; x < width; x++) {
        var p = BackBuffer + (y * Stride) + (x * 4);
        unsafe {
            *((int*)p) = color_data;
            }
        }
    }
dpix = (int) DpiX;
for (var x = 0; x < width; x += dpix) {
    for (var y = 0; y < height; y++) {
        var p = BackBuffer + (y * Stride) + (x * 4);
        unsafe {
            *((int*)p) = color_data;
            }
        }
    }

当我测量网格线时,我发现两种方法都需要添加大约17个像素才能获得1英寸的单位正方形。如果我的“实际” DPI是272(255 + 17),那么屏幕的实际宽度将是14.1176470588235” (3840/272)。

出于好奇,我打开了Word 2016,将比例设置为100%,并测量了Word“统治者”工具。 它也是〜15/16“而不是1”,我必须缩放到105%到106%之间才能获得“真实”英寸。 因此,无论出现什么问题,都会影响MS编写的应用程序。

自.NET Framework 4.6.2起,WPF具有按监视器的DPI支持。 在GitHub上有更多信息和示例: http : //github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI

您可能还想签出VisualTreeHelper.GetDpi方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM