Pdf.js and viewer.js. Pass a stream or blob to the viewer

Efrael picture Efrael · Jul 2, 2014 · Viewed 69.7k times · Source

I'm having troubles in finding a solution for this: I retrieve a PDF blob from a SQL filestream field using Javascript in this way (it's a lightswitch project)

var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });

I have the blob and I can even convert it in a filestream or to base64("JVBERi0....." or "%PDF 1.6 ......", etc.)

No problem so far.

Now I need to display it in a viewer. I prefer the viewer to open in a new window but i'm open to embed it into my page somehow.

I'm wondering if I can directly pass the blob or the stream to the viewer and display the document. I've tried something like

PDFView.open(pdfAsArray, 0)

Nothing happens in the embedded viewer in this case.

The pdfAsArray is good since I can display it appending the stream to a canvas within the same page. I just want to display the viewer, not embed the PDF in a canvas, possibly in a new window.

Can anyone provide few lines of code on how to achieve that in Javascript?

Answer

toddmo picture toddmo · Sep 17, 2015

I'm using PDFJS.version = '1.0.1040'; PDFJS.build = '997096f';

The code that worked for me to get base64 pdf data loaded was this:

function (base64Data) {
  var pdfData = base64ToUint8Array(base64Data);
  PDFJS.getDocument(pdfData).then(function (pdf) {
    pdf.getPage(1).then(function (page) {
      var scale = 1;
      var viewport = page.getViewport(scale);
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      canvas.height = viewport.height;
      canvas.width = viewport.width;
      page.render({ canvasContext: context, viewport: viewport });
    });
  });

  function base64ToUint8Array(base64) {
    var raw = atob(base64);
    var uint8Array = new Uint8Array(raw.length);
    for (var i = 0; i < raw.length; i++) {
      uint8Array[i] = raw.charCodeAt(i);
    }
    return uint8Array;
  }
}

This function could be the success function of an api call promise. What I'm doing here is rendering the pdf onto a canvas element myCanvas.

<canvas id="myCanvas"></canvas>

This shows the first page of the pdf but has no functionality. I can see why the viewer is desirable. If I get this hooked up to the viewer (viewer.html / viewer.js) I will edit my answer.

EDIT: How to hook up the viewer

1 In bower.json, add "pdfjs-viewer": "1.0.1040"

2 Html:

<iframe id="pdfViewer" src="lib/pdfjs-viewer/web/viewer.html" style="width: 100%; height: 700px;" allowfullscreen="" webkitallowfullscreen=""></iframe>

3 Change the stupid default document in the viewer.js file:

var DEFAULT_URL = '';

4 Controller:

var pdfjsframe = document.getElementById('pdfViewer');
pdfjsframe.onload = function() {
  LoadPdfDocument();
};

$scope.myApiCallThatReturnsBase64PdfData.then(
  function(base64Data) {
    $scope.base64Data = base64Data;
    LoadPdfDocument();
  },
  function(failure) {

    //NotificationService.error(failure.Message);

  });

function LoadPdfDocument() {
  if ($scope.PdfDocumentLoaded)
    return;
  if (!$scope.base64Data)
    return;

  var pdfData = base64ToUint8Array($scope.base64Data);
  pdfjsframe.contentWindow.PDFViewerApplication.open(pdfData);

  $scope.PdfDocumentLoaded = true;
}

function base64ToUint8Array(base64) {
  var raw = atob(base64);
  var uint8Array = new Uint8Array(raw.length);
  for (var i = 0; i < raw.length; i++) {
    uint8Array[i] = raw.charCodeAt(i);
  }
  return uint8Array;
}