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

◇◆丶佛笑我妖孽 提交于 2019-11-26 09:29:22

问题


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?


回答1:


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;
}



回答2:


I finally made the PDFView.open method working. Now if I embed the viewer into my page and call the open function as Rob suggested in the first 2 examples it works.

For those who are looking for this kind of solution I provide some lines of code here:

This is the code in my Lightswitch mainPage.lsml.js The js scripts (pdf.js, viewer and Others) are referenced in the main html page of the Lightswitch project (Default.html); I assume it should work with any other html page not Lightswitch based.

myapp.MainPage.ShowPdf_execute = function (screen) {
// Write code here.
// Getting the stream from sql
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
// Pass the stream to an aspx page that makes some manipulations and returns a response
var formData = new FormData();
formData.tagName = pdfName;
formData.append(pdfName, blob);
var xhr = new XMLHttpRequest();
var url = "../OpenPdf.aspx";
xhr.open('POST', url, false);
xhr.onload = function (e) {
    var response = e.target.response;
        var pdfAsArray = convertDataURIToBinary("data:application/pdf;base64, " + response);
        var pdfDocument;
// Use PDFJS to render a pdfDocument from pdf array
    PDFJS.getDocument(pdfAsArray).then(function (pdf) {
        pdfDocument = pdf;
        var url = URL.createObjectURL(blob);
        PDFView.load(pdfDocument, 1.5)
    })
};
xhr.send(formData);  // multipart/form-data 
};

This is the convertDataURIToBinary function

function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));

for (i = 0; i < rawLength; i++) {
    array[i] = raw.charCodeAt(i);
}
return array;
}

What is still missed is the possibility to pass the stream directly to the viewer.html page in order to open it in a new window and have a separate ui where make the rendering.

This code is still not working since I got an empty viewer with no document inside

var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
var url = URL.createObjectURL(blob);
var viewerUrl = 'Scripts/pdfViewer/web/viewer.html?file=' + encodeURIComponent(url);
window.open(viewerUrl);

Looks like the encodeURIComponent(url) is not passing to the viewer a good object to load into the viewer. Any idea or suggestion?




回答3:


If you've got an typed array (e.g. an Uint8Array), then the file can be opened using PDFView.open(typedarray, 0);.

If you've got a Blob or File object, then the data has to be converted to a typed array before you can view it:

var fr = new FileReader();
fr.onload = function() {
    var arraybuffer = this.result;
    var uint8array = new Uint8Array(arraybuffer);
    PDFView.open(uint8array, 0);
};   
fr.readAsArrayBuffer(blob);

Another method is to create a URL for the Blob/File object:

var url = URL.createObjectURL(blob);
PDFView.open(url, 0);

If the PDF Viewer is hosted at the same origin as your website that embeds the frame, then you can also view the PDF by passing the blob URL to the viewer:

var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.



回答4:


var url = URL.createObjectURL(blob);

var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);

// TODO: Load the PDF.js viewer in a frame or new tab/window.

//-- Abobe code opens a new window but with errors : 'Missing PDF 
// blob://http://server-addr:port/converted-blob' 


来源:https://stackoverflow.com/questions/24535799/pdf-js-and-viewer-js-pass-a-stream-or-blob-to-the-viewer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!