0

I want to download image from the page displayed in WebView2 control to local file. There's no API to manipulate page media except getting the page source. Should I use execScriptAsnyc to run script to get the image? No one page was found talking about this in my searching. Hope there's is answer from Overflow visitors.

xxinduan
  • 13
  • 2
  • Checked out "https://stackoverflow.com/questions/3749231/download-file-using-javascript-jquery" and use script like: const outsideRes = await fetch("external_url"); const blob = await outsideRes.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "download"; document.body.appendChild(link); link.click() It works in webview2 devtool console, but no response in "ExecuteScriptAsync()". – xxinduan Jul 11 '23 at 03:23

2 Answers2

0

To download an image from a page displayed in the WebView2 control and save it to a local file, you can indeed use ExecuteScriptAsync method in combination with JavaScript code.

  1. Add the required namespaces:

    using Microsoft.Web.WebView2.Core;
    using System.IO;
    
  2. Assuming you have a WebView2 control named webView2 on your WPF form, retrieve its underlying CoreWebView2 instance:

    var webView2Control = webView2.EnsureCoreWebView2Async().GetAwaiter().GetResult();
    
  3. Use ExecuteScriptAsync to run JavaScript code that retrieves the image source URL:

    var script = "document.querySelector('img').src"; // Replace 'img' with the appropriate selector for your image element
    var imageSourceUrl = await webView2Control.ExecuteScriptAsync(script);
    
  4. Download the image using the retrieved source URL:

    using (var client = new System.Net.WebClient())
    {
        var localFilePath = @"C:\Path\To\Your\Image.jpg"; // Replace with the desired local file path and extension
        client.DownloadFile(imageSourceUrl, localFilePath);
    }
    
  • Thanks. Actually, I'm using "WebClient". But it does not work anymore because the web site forbidden this kind of downloading in its "reference" policy. This is why I want to save the image already rendered in the page. – xxinduan Jul 10 '23 at 04:01
0

Here is an example of how i did it by subscribing to event NavigationCompleted handler of my WebView instance:

async void CoreWebView2_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
{
    if (!e.IsSuccess)
        return;
    string html = await webView.ExecuteScriptAsync("document.documentElement.outerHTML");
    if (html.Contains("any keyword to detect the page you are interested in"))
    {
        string img_link = ...; // extraction of the url (in my case the image is not rendered on the page but inside a css.
        // So i let webview handles all complexity of html request (cookie etc, site protection etc) by navigating on the url
        webView.Source = new Uri(link_from_css); // it triggers NavigationCompleted again! Code will continue on "else" part below
    }
    // assuming the only links that interests me are ending ".jpg"
    else if (webView.Source.AbsolutePath.EndsWith(".jpg"))
    {
        // No need to specify id of img element here, browser uses only one "img" html element in the page it generates to display the image
        // In you case you could call this directly from the code in the if/then part
        var imageData = await GetImageBytesAsync(null); 
        File.WriteAllBytes(@"C:\wherever_you_want\test.jpg", imageData);
    }
}

And the helper method:

/// <summary>
/// Get raw data (bytes) about an image in an "img" html element 
/// where id is indicated by "elementId". 
/// If "elementId" is null, the first "img" element in the page is used 
/// </summary>
async Task<byte[]> GetImageBytesAsync(string elementId = null, bool debug = false)
{
    var script = @"
function getImageAsBase64(imgElementId)
{
    " + (debug ? "debugger;" : "") + @"
    let img = document.getElementById(imgElementId);
    if (imgElementId == '')
    {
        var results = document.evaluate('//img', document, null, XPathResult.ANY_TYPE, null);
        img = results.iterateNext();
    }
    let canvas = document.createElement('canvas');
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;

    let ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);

    let base64String = canvas.toDataURL('image/jpeg');  // or 'image/png'
    return base64String;
};
getImageAsBase64('" + elementId + "')";
    string base64Data = await webView.ExecuteScriptAsync(script);
    base64Data = base64Data.Split("base64,")[1].TrimEnd('"');
    var result = Convert.FromBase64String(base64Data);
    return result;
}

And voila!

Astyan
  • 56
  • 3