问题描述
我想从 WPF 窗口中显示的 win32 控件(即 windowsformshost、Hwndhost、webview2)创建一个图像。
- rendertargetBitmap 不适用于这些类型的控件,我是否正确?
假设我是对的,我正在查看 this GitHub project 中用于制作图像的方法。该项目将 webbrowser 控件包装在 ContenControl 中。然后获取此内容控件在屏幕上的位置,并使用 Graphics 类方法 copyFromScreen。
private void CreateScreenshotFromContent()
{
Point upperLeftPoint = _airspaceContent.PointToScreen(new Point(0,0));
var bounds = new System.Drawing.Rectangle((int)(upperLeftPoint.X * _scalingFactor),(int)(upperLeftPoint.Y * _scalingFactor),(int)(_airspaceContent.RenderSize.Width * _scalingFactor),(int)(_airspaceContent.RenderSize.Height * _scalingFactor));
using (var bitmap = new System.Drawing.Bitmap((int)bounds.Width,(int)bounds.Height))
{
using (var g = system.drawing.graphics.FromImage(bitmap))
{
g.copyFromScreen(new System.Drawing.Point(bounds.Left,bounds.Top),System.Drawing.Point.Empty,new System.Drawing.Size((int)bounds.Width,(int)bounds.Height));
}
_airspaceScreenshot.source = GetimageSourceFromBitmap(bitmap);
}
}
// https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc,int nIndex);
private void GetScalingFactor()
{
var g = system.drawing.graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = GetDeviceCaps(desktop,10);
int PhysicalScreenHeight = GetDeviceCaps(desktop,117);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
_scalingFactor = ScreenScalingFactor; // 1.25 = 125%
}
public ImageSource GetimageSourceFromBitmap(System.Drawing.Bitmap bitmap)
{
using (var memory = new MemoryStream())
{
bitmap.Save(memory,ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
return bitmapImage;
}
}
GitHub 项目使用 Webbrowser 控件。一个小问题是我将其更新为 WebView2 控件,该控件较新,但也只是 WPF 中的一个 win32 控件。
如果 PC 的缩放比例为 100%,则一切正常。生成的图像几乎完全匹配控件显示的内容。不幸的是,如果缩放比例发生变化,则不会发生这种情况。
这是带有 200% 缩放比例的 Webbrowser 控件的窗口的外观。
我的项目现在面向 4.7.2 .Net Framework,如果我理解正确,这意味着它现在可以识别 DPI,因此我知道我不需要对应用程序配置或清单做任何额外的事情。我是否正确 不再需要像下面这样的清单更改?
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
</windowsSettings>
</application>
解决方法
假设 _scalingFactor 有问题,我建议使用 VisualTreeHelper.GetDpi 方法。在这种情况下,GetScalingFactor 方法将如下所示:
public void GetScalingFactor()
{
_scalingFactor = (float)VisualTreeHelper.GetDpi(_airspaceContent).DpiScaleX;
}
我认为这个类有很大的重构空间。