Set Webview2 Source directly to a binary stream
Asked Answered
C

3

6

I have a Webview2 Control in my application, used to view PDF documents.
The application also stores to and reads from MS SQL server PDFs data.

Currently, I am retrieving binary data from SQL, convert them to a temporary file to disk and set:

webview2.source = New Uri("file://" + filename)  

That's working fine so far, but of course I would like to do the job without writing and reading to and from disk.

Is there a way to do the same without accessing the disk?

Update (as recommended), what I tried. With part of code for better understandg:

                Dim fieldOrdinal = reader.GetOrdinal(ColumnName)
                reader.Read()
                Dim blob = New Byte(reader.GetBytes(fieldOrdinal, 0, Nothing, 0, 0) - 1) {}
                reader.GetBytes(fieldOrdinal, 0, blob, 0, blob.Length)

                Dim pdfBase64 As String = Convert.ToBase64String(blob)
                Dim html As String = "<!DOCTYPE html><html><head></head><body><div>" & $"<iframe width=100% height=500 src=\" & Chr(&H22) & "data:Application/pdf;base64,{pdfBase64}\" & Chr(&H22) & ">" & "</iframe></div></body></html>"

The webview2 control shows a frame, but without content

Final Update: Here the (correct) to VB translated and working code:

Dim html As String = "<!DOCTYPE html><html><head></head><body><div>" & $"<iframe width=100% height=500 src=""data:Application/pdf;base64,{pdfBase64}"">" & "</iframe></div></body></html>"
Coulter answered 5/8, 2021 at 16:8 Comment(2)
The value in src needs to be surrounded in quotes. Also the backslash was an escape for " in C#.Haplo
Got it ! The equivalent in VB is "". Working ! Thx to both of you !Coulter
N
8

You can embed the PDF in an IFRAME as Base64, the same way you embed images.
In this case, the mime type is of course application/pdf.
Convert to Base64 your source PDF bytes with Convert.ToBase64String(), use a standard HTML5 header and set the IFRAME and/or DIV container to the desired size.

Use the WebView2.NavigateToString() method to load the HTML with the embedded PDF:

  • See the Remarks section: currently the content's size cannot exceed 2097152 bytes (2MB)
string pdfBase64 = Convert.ToBase64String([Your PDF bytes]);

string html = "<!DOCTYPE html><html><head></head><body><div>" +
    $"<iframe width=100% height=500 src=\"data:application/pdf;base64,{pdfBase64}\">" +
    "</iframe></div></body></html>";

webView2.NavigateToString(html);

VB.Net version:

Dim pdfBytes = [DataReader].GetSqlBytes([DataReader].GetOrdinal("[Column Name]")).Value
Dim pdfBase64 As String = Convert.ToBase64String(pdfBytes)

Dim html As String = "<!DOCTYPE html><html><head></head><body><div>" &
    $"<iframe width=100% height=500 src=""data:Application/pdf;base64,{pdfBase64}"">" &
    "</iframe></div></body></html>"

webView2.NavigateToString(html)

The iframe size should not be set like that, you should use CSS styles (and probably a simple JavaScript to handle late redefinition of the size of the Window that contains your PDF).
You could build a simple HTML template and fill the Base64 content as described.

Nutmeg answered 5/8, 2021 at 17:27 Comment(0)
C
1

Just to finalize the answer. Below the final version I'm using, including CSS in the framing HTML to make the pdf borderless and 100% x 100% size of the parent webview2:

Dim pdfBase64 As String = Convert.ToBase64String(pdfBytes)
Dim html As String = "<!DOCTYPE html><html><head>
                            </head>
                            <style>
                                   body   {margin: 0;}
                                   iframe {display: block; background: #000; border: none; height: 100vh; width: 100vw;}
                            </style>
                            <body>" & $"<iframe src=""data:Application/pdf;base64,{pdfBase64}"">" & "</iframe></body></html>"
Coulter answered 9/8, 2021 at 13:15 Comment(0)
T
0

There is one problem, when using Base64 string: 2Mb limit for encoded string.

The workaround for the really big content is to use Blob:

var s = $"let bytes = new Uint8Array([{string.Join(",", bytes)}]);";
s += "let blob = new Blob([bytes], {type: 'application/pdf'}); ";
s += "window.location = URL.createObjectURL(blob);";
webView.ExecuteScriptAsync(s);
Tabanid answered 25/9 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.