web-dev-qa-db-fra.com

Pdf.js et viewer.js. Passer un flux ou un blob au spectateur

J'ai du mal à trouver une solution à cela: je récupère un PDF blob d'un champ de flux de fichiers SQL en utilisant Javascript de cette manière (c'est un projet lightswitch)

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

J'ai le blob et je peux même le convertir dans un flux de fichiers ou en base64 ("JVBERi0 ....." ou "% PDF 1.6 ......", etc.)

Aucun problème jusqu'ici.

Maintenant, je dois l'afficher dans une visionneuse. Je préfère que le spectateur ouvre dans une nouvelle fenêtre mais je suis ouvert pour l'intégrer dans ma page d'une manière ou d'une autre.

Je me demande si je peux directement transmettre le blob ou le flux au visualiseur et afficher le document. J'ai essayé quelque chose comme

PDFView.open(pdfAsArray, 0)

Dans ce cas, rien ne se produit dans la visionneuse intégrée.

Le pdfAsArray est bon car je peux l'afficher en ajoutant le flux à un canevas dans la même page. Je veux juste afficher la visionneuse, pas intégrer le PDF dans une toile, peut-être dans une nouvelle fenêtre.

Quelqu'un peut-il fournir quelques lignes de code sur la façon d'y parvenir en Javascript?

22
Efrael

J'ai finalement fait fonctionner la méthode PDFView.open. Maintenant, si j'intègre la visionneuse dans ma page et appelle la fonction ouverte comme Rob l'a suggéré dans les 2 premiers exemples, cela fonctionne.

Pour ceux qui recherchent ce type de solution, je fournis ici quelques lignes de code:

C'est le code dans ma Lightswitch mainPage.lsml.js Les scripts js (pdf.js, viewer et Others) sont référencés dans la page html principale du projet Lightswitch (Default.html); Je suppose que cela devrait fonctionner avec toute autre page html non basée sur Lightswitch.

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

Ceci est la fonction convertDataURIToBinary

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

Ce qui manque encore, c'est la possibilité de passer le flux directement à la page viewer.html afin de l'ouvrir dans une nouvelle fenêtre et d'avoir une interface utilisateur séparée où faire le rendu.

Ce code ne fonctionne toujours pas depuis que j'ai une visionneuse vide sans document à l'intérieur

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

On dirait que l'encodeURIComponent (url) ne transmet pas au visualiseur un bon objet à charger dans le visualiseur. Une idée ou une suggestion?

9
Efrael

J'utilise PDFJS.version = '1.0.1040'; PDFJS.build = '997096f';

Le code qui a fonctionné pour moi pour charger les données pdf base64 était le suivant:

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

Cette fonction pourrait être la fonction de réussite d'une promesse d'appel api. Ce que je fais ici, c'est le rendu du pdf sur un élément canvas myCanvas.

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

Cela montre la première page du pdf mais n'a aucune fonctionnalité. Je peux voir pourquoi le spectateur est désirable. Si je le connecte au spectateur (viewer.html/viewer.js), je modifierai ma réponse.

EDIT: Comment connecter le spectateur

1 Dans bower.json, ajouter "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>

Changer le stupide document par défaut dans le viewer.js fichier:

var DEFAULT_URL = '';

4 Contrôleur:

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

Si vous avez un tableau typé (par exemple un Uint8Array), Alors le fichier peut être ouvert en utilisant PDFView.open(typedarray, 0);.

Si vous avez un objet Blob ou File, les données doivent être converties en un tableau typé avant de pouvoir les visualiser:

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

Une autre méthode consiste à créer une URL pour l'objet Blob/File:

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

Si la visionneuse PDF est hébergée chez même origine que votre site Web qui incorpore le cadre, vous pouvez également afficher la PDF en passant l'URL de blob au spectateur:

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.
8
Rob W
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' 
3
Gaurav Kumar Jha