【.NET 5】【WPF】Print WebView2
Tags: dotnet, csharp, wpf
Published: 2021-01-30 10:14:46

## Intro
In this time, I try setting print settings and print WebView2.

* [【.NET 5】【WPF】【ClosedXML】Draw and print spreadsheets 1](https://dev.to/masanori_msl/net-5-wpf-closedxml-draw-and-print-spreadsheets-1-16g6)
* [【.NET 5】【WPF】Try MVVM](https://dev.to/masanori_msl/net-5-wpf-try-mvvm-3m0e)
* [【.NET 5】【WPF】Try WebView2](https://dev.to/masanori_msl/net-5-wpf-try-webview2-41kn)

## Printer settings
I can set printing settings like paper size, etc. by "PrintTicket".

* [PrintTicket Class (System.Printing) | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/system.printing.printticket?view=net-5.0)

```cs
using System.Printing;
using System.Windows.Media;
using System.Windows.Xps;

namespace PrintSample.Prints
{
    public class Printer: IPrinter
    {
        public void Print(Visual target)
        {
            LocalPrintServer printServer = new LocalPrintServer();
            PrintQueue queue = printServer.GetPrintQueue("Microsoft Print to PDF");
            
            PrintTicket ticket = queue.DefaultPrintTicket;
            ticket.PageMediaSize = new PageMediaSize(200d, 300d);
            // I can get defined paper sizes like "A3" by PageMediaSizeName
            // ticket.PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA3);
            
            ticket.CopyCount = 2;
            ticket.PageResolution = new PageResolution(72, 72);
            // Setting this value to Landscape reverses the "MediaSize" designation
            ticket.PageOrientation = PageOrientation.Landscape;
            // no margins
            ticket.PageBorderless = PageBorderless.Borderless;
            
            XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(queue); 
            writer.Write(target, ticket);
        }
    }
}
```
## Print WebView2
Because I had been able to set a WebView2 instance as argument of XpsDocumentWriter.Write, I have thought I could print HTML of WebView2.

```cs
using System;
using System.Printing;
using System.Windows;
using System.Windows.Xps;
using Microsoft.Web.WebView2.Core;

namespace PdfPrintSample.Main
{
    public partial class MainWindow : Window
    {
        public MainWindow(MainViewModel viewModel)
        {
            DataContext = viewModel;
            InitializeComponent();
            InitializeAsync();
            webView.NavigationCompleted += NavigationCompleted;
        }
        private async void InitializeAsync()
        {
            await webView.EnsureCoreWebView2Async(null);
        }
        private async void NavigationCompleted(object? sender,
            CoreWebView2NavigationCompletedEventArgs args)
        {
            LocalPrintServer printServer = new LocalPrintServer();
            PrintQueue queue = printServer.GetPrintQueue("Microsoft Print to PDF");
            XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(queue); 
            writer.Write(webView);
        }
    }
}
```
#### WPF
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bhycyg9t3hniyswxqf15.jpg)

#### Printed
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cxglho0v1mwt13oi7qlu.jpg)

The HTML wasn't printed :(

### Use DevTool of WebView2
One of the way to print HTML of WebView2 is taking screenshot by DevTool of WebView2.

```cs
using System;
using System.IO;
using System.Printing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Xps;
using Microsoft.Web.WebView2.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;

namespace PdfPrintSample.Main
{
    public partial class MainWindow : Window
    {
...
        private async void NavigationCompleted(object? sender,
            CoreWebView2NavigationCompletedEventArgs args)
        {
            string pic = await webView.CoreWebView2.CallDevToolsProtocolMethodAsync("Page.captureScreenshot", "{}");
            JObject o3 = JObject.Parse(pic);
            JToken data = o3["data"]!;

            byte[] bytes = Convert.FromBase64String(data.ToString());
            Image image = new Image();
            double picHeight = 0d;
            double picWidth = 0d;
            using(MemoryStream stream = new MemoryStream(bytes))
            {
                BitmapFrame bitmap = System.Windows.Media.Imaging.BitmapDecoder.Create(stream, BitmapCreateOptions.None,    
                                        BitmapCacheOption.OnLoad).Frames[0];
                picHeight = bitmap.Height;
                picWidth = bitmap.Width;
                image.Source = bitmap;
            }

            LocalPrintServer printServer = new LocalPrintServer();
            PrintQueue queue = printServer.GetPrintQueue("Microsoft Print to PDF");
            PrintTicket ticket = queue.DefaultPrintTicket;
            // must set PageMediaSize
            ticket.PageMediaSize = new PageMediaSize(picWidth, picHeight);

            XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(queue); 
            writer.Write(image, ticket);
        }
    }
}
```

* [WebView2 DrawToBitmap returns only background · Issue #529 · MicrosoftEdge/WebView2Feedback · GitHub](https://github.com/MicrosoftEdge/WebView2Feedback/issues/529)
* [CoreWebView2.CallDevToolsProtocolMethodAsync(String, String) Method (Microsoft.Web.WebView2.Core) | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.calldevtoolsprotocolmethodasync?view=webview2-dotnet-1.0.705.50)
* [C# Base64 String to JPEG Image - Stack Overflow](https://stackoverflow.com/questions/18827081/c-sharp-base64-string-to-jpeg-image)

### Set PageMediaSize
An important thing is I must set PageMediaSize because XpsDocumentWriter may not be able to get the image size.
So if I don't do this, the result like below.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jxnuk4tb18jhdgn5vkrg.jpg)