Ronye Lago
Ronye Lago

Reputation: 122

Show PDF in Xamarin App from byte array

I am creating a mobile application with Xamarin Forms where the user can view the result of exams done. The result of the exams comes from a database in a byte array format and I need to somehow convert the byte array into a PDF and display it to the user. I saw that I can use a WebView to display a PDF, but would need to save it to the device and then display it. Would anyone know how I can convert the byte array to PDF and display it in a WebView without having to save it or do it otherwise?

Thanks in advance.

Upvotes: 1

Views: 4354

Answers (1)

SushiHangover
SushiHangover

Reputation: 74094

Using pdf.js makes it really easy: https://mozilla.github.io/pdf.js/

  1. Add a WebView to your Forms' Page and setup the dependency code to obtain the baseurl path per platform

  2. Add the pdf.js and pdf.worker.js to your application projects (BundleResource for iOS and AndroidAsset for Android)

  3. Convert your PDF stream to a Base64-string (via a MemoryStream if needed) and embed that string into a HTML-based string.

  4. Use JavaScript (atob) to decode that base64 string and setup pdf.js /pdf.worker.jsto render to acanvas` defined in your html.

Example:

XAML:

<StackLayout x:Name="webViewContainer" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
    <WebView x:Name="webView" BindingContext="{x:Reference webViewContainer}" WidthRequest="{Binding Width}" HeightRequest="{Binding Height}"/>
</StackLayout>

Code-behind:

Note: Using a PDF via bundled resource, substitute your stream there....

            var baseUrl = DependencyService.Get<IBaseUrl>().Get();
            string base64Pdf;
            using (var stream = await FileSystem.OpenAppPackageFileAsync("Dank Learning 1806.04510.pdf"))
            using (var memoryStream = new MemoryStream())
            {
                await stream.CopyToAsync(memoryStream);
                base64Pdf = Convert.ToBase64String(memoryStream.ToArray());
            }
            var html = @"
<html>
<head> 
<script type=""text/javascript"" src=""pdf.js""></script>
 <script type=""text/javascript"">
    window.onload=function(){
var pdfData = atob('SUSHIHANGOVER');
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdf.worker.js';
var loadingTask = pdfjsLib.getDocument({data: pdfData});
loadingTask.promise.then(function(pdf) {
  console.log('PDF loaded');
  var pageNumber = 1;
  pdf.getPage(pageNumber).then(function(page) {
    console.log('Page loaded');
    var scale = 1.5;
    var viewport = page.getViewport(scale);
    var canvas = document.getElementById('the-canvas');
    var context = canvas.getContext('2d');
    canvas.height = viewport.height;
    canvas.width = viewport.width;
    var renderContext = {
      canvasContext: context,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);
    renderTask.then(function () {
      console.log('Page rendered');
    });
  });
}, function (reason) {
  console.error(reason);
});
    }
</script>
</head>
<body>
<h1>StackOverflow / Base64 PDF</h1>
<canvas id=""the-canvas"" style=""border: 1px solid""></canvas>
<h2>by SushiHangover</h2>
</body>
</html>
";
            html = html.Replace("SUSHIHANGOVER", base64Pdf);
            webView.Source = new HtmlWebViewSource
            {
                BaseUrl = baseUrl,
                Html = html
            };

Upvotes: 2

Related Questions