简体   繁体   English

如何使用 CopyFromScreen 在 WPF Window 中创建 win32 控件的图像

[英]How to use CopyFromScreen to create an image of a win32 control in a WPF Window

I want to create an image from a win32 control (ie WindowsFormsHost, Hwndhost, webview2) being displayed in a WPF window.我想从显示在 WPF window 中的 win32 控件(即 WindowsFormsHost、Hwndhost、webview2)创建图像。

  1. Am I correct that RenderTargetBitmap will not work for these kinds of controls?我是否正确 RenderTargetBitmap 不适用于这些类型的控件?

Assuming I am correct, I am looking at the methods used in this GitHub project to make the image.假设我是正确的,我正在查看此 GitHub 项目中用于制作图像的方法。 The project wraps the webbrowser control in a ContenControl.该项目将 webbrowser 控件包装在 ContenControl 中。 It then gets the position of this content control on the screen and uses the Graphics class method CopyFromScreen.然后它在屏幕上获取此内容控件的 position 并使用 Graphics class 方法 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;
    }
}

The GitHub project uses the WebBrowser control. GitHub 项目使用 WebBrowser 控件。 One small complication is I am updating this to the WebView2 control which is newer but is also just a win32 control in WPF.一个小问题是我将其更新为 WebView2 控件,它更新但也只是 WPF 中的一个 win32 控件。

All works fine if the PC's scaling is 100%.如果 PC 的缩放比例为 100%,则一切正常。 The resulting image almost perfectly matches what the control displays.生成的图像几乎完全匹配控件显示的内容。 Unfortunately this does not if scaling is changed.不幸的是,如果缩放比例改变,这不会。

This is how the window looks with the Webbrowser control with 200% scaling.这就是 window 与 200% 缩放的 Webbrowser 控件的外观。 WebBrowser 控件。

The image however is considerable enlarged when the scaling is 200%.然而,当缩放比例为 200% 时,图像会显着放大。 200% 的图像

My project now targets 4.7.2.Net Framework which if I understand correctly means it is now DPI aware thus I understand I do not need to do anything extra with the app config or manifest.我的项目现在针对 4.7.2.Net 框架,如果我理解正确,这意味着它现在可以识别 DPI,因此我知道我不需要对应用程序配置或清单做任何额外的事情。 Am I correct Manifest changes like below are no longer needed?我是否不再需要像下面这样的清单更改?

<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>

Assuming _scalingFactor is problematic, I would recommend to use VisualTreeHelper.GetDpi method.假设 _scalingFactor 有问题,我建议使用 VisualTreeHelper.GetDpi 方法。 In this case, GetScalingFactor method will be like the following:在这种情况下,GetScalingFactor 方法将如下所示:

public void GetScalingFactor()
{
    _scalingFactor = (float)VisualTreeHelper.GetDpi(_airspaceContent).DpiScaleX;
}

I think this class has much room for refactoring though.我认为这个 class 有很大的重构空间。

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

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