6

I am trying to take screenshot of the WebView2 output from a console application. The application is called from a non-interactive Windows Service. The purpose of console application is to generate graphic files from WPF controls. I am currently able to do this for UserControls that draw graphics such as charts. My console application is a WPF application with no user interface. I am trying to do the same for the WebView however the call to EnsureCoreWebView2Async hangs when the control is hidden. It seems the control must be visible. Then all is good. Is there anyway to get this to work without the control actually displaying?

XAML

<Window x:Class="WebView2WPFHidden.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
    xmlns:local="clr-namespace:WebView2WPFHidden"        
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800"
    Visibility="Hidden">
<Grid>
    <wv2:WebView2 Name="webView"/>
</Grid>

Code Behind

    public MainWindow()
    {
        InitializeComponent();

        _ = InitializeAsync();
    }

    private async Task InitializeAsync()
    {
        await webView.EnsureCoreWebView2Async(null);
        webView.NavigationCompleted += WebView_NavigationCompleted;
        webView.Source = new Uri("https://www.microsoft.com");
    }

    private void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
    {
        try
        {
            _ = SaveScreenshot((int)Width, (int)Height);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private async Task SaveScreenshot(int width, int height)
    {
        try
        {
            dynamic clip = new JObject();
            clip.x = 0;
            clip.y = 0;
            clip.width = width;
            clip.height = height;
            clip.scale = 1;

            dynamic settings = new JObject();
            settings.format = "png";
            settings.clip = clip;
            settings.fromSurface = true;
            settings.captureBeyondViewport = true;

            var p = settings.ToString(Newtonsoft.Json.Formatting.None);

            var devData = await webView.CoreWebView2.CallDevToolsProtocolMethodAsync("Page.captureScreenshot", p);

            var imgData = (string)((dynamic)JObject.Parse(devData)).data;
            var ms = new MemoryStream(Convert.FromBase64String(imgData));
            var bitmap = (Bitmap)Image.FromStream(ms);
            bitmap.Save("c:\\temp\\screenshot.png");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
Mike
  • 559
  • 5
  • 21
  • Just as a reference, it seems that using `HWND_MESSAGE` as described in [#202](https://github.com/MicrosoftEdge/WebView2Feedback/issues/202) allows to use WebView2 headless e.g. in a .NET Console application. – Uwe Keim May 03 '23 at 19:35

1 Answers1

1

WebView2 can't render offscreen. So that is impossible.

Bill.W
  • 21
  • 1
  • 5
  • Since recently, WebView2 _can_ render offscreen. See [#202](https://github.com/MicrosoftEdge/WebView2Feedback/issues/202). – Uwe Keim May 10 '23 at 11:03