我认为在技术上(在技术上)正确的代码可以在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网格控件,其中包含一个Image控件。来自GetDpiForMonitor
的DPI是(X: Y)255:256。问题是这不准确。当我绘制一个简单的网格(线DPI分开)时,正方形不是1“,它们是17(原始)像素短。 WriteableBitmap
位于WPF图像控件中,该控件具有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编写的应用程序。
答案 0 :(得分:0)
WPF自.NET Framework 4.6.2以来一直支持DPI。 GitHub提供了更多信息和示例:http://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI。
您可能还想查看VisualTreeHelper.GetDpi方法。