J'essaie de lire un document .pdf entier à l'aide de PDF.js, puis de restituer toutes les pages sur un même document.
Mon idée: rendre chaque page sur un canevas et obtenir le ImageData (context.getImageData ()), effacer le canevas pour faire la page suivante. Je stocke tous les ImageDatas dans un tableau et une fois que toutes les pages y figurent, je souhaite placer tous les ImageDatas du tableau sur un seul et même canevas.
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);
p.Out("pre-rendered page " + i);
});
}
//Now we have all 'dem Pages in "pages" and need to render 'em out
canvas.height = 0;
var start = 0;
for(var i = 0; i < pages.length; i++){
if(canvas.width < pages[i].width) canvas.width = pages[i].width;
canvas.height = canvas.height + pages[i].height;
context.putImageData(pages[i], 0, start);
start += pages[i].height;
}
});
Donc, si je comprends bien, cela devrait fonctionner, non? Lorsque je lance ceci, je me retrouve avec la toile qui est assez grande pour contenir toutes les pages du pdf mais ne montre pas le pdf ...
Merci pour l'aide.
Je ne peux pas parler de la partie de votre code qui convertit le pdf en canevas, mais je vois des problèmes.
Donc, pour commencer, je commencerais par changer votre code en ceci (très, très non testé!):
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
var canvasWidth=0;
var canvasHeight=0;
var pageStarts=new Array();
pageStarts[0]=0;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
// changing canvas.width and/or canvas.height auto-clears the canvas
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
// calculate the width of the final display canvas
if(canvas.width>maxCanvasWidth){
maxCanvasWidth=canvas.width;
}
// calculate the accumulated with of the final display canvas
canvasHeight+=canvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[i]=pageStarts[i-1]+canvas.height;
p.Out("pre-rendered page " + i);
});
}
canvas.width=canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for(var i = 0; i < pages.length; i++){
context.putImageData(pages[i], 0, pageStarts[i]);
}
});
Vous pouvez également utiliser votre méthode de manière plus traditionnelle:
Utilisez un seul canevas «display» et permettez à l'utilisateur de «feuilleter» chaque page désirée.
Puisque vous commencez déjà par dessiner chaque page dans un canevas, pourquoi ne pas conserver un canevas caché distinct pour chaque page. Ensuite, lorsque l'utilisateur souhaite voir la page n ° 6, il vous suffit de copier le canevas masqué n ° 6 sur votre canevas d'affichage.
Les développeurs de Mozilla utilisent cette approche dans leur démo pdfJS ici: http://mozilla.github.com/pdf.js/web/viewer.html
Vous pouvez consulter le code du lecteur ici: http://mozilla.github.com/pdf.js/web/viewer.js
Les opérations PDF sont asynchrones à toutes les étapes. Cela signifie que vous devez également saisir la promesse lors du dernier rendu. Si vous ne l'attrapez pas, vous obtiendrez uniquement un canevas vierge car le rendu n'est pas terminé avant que la boucle ne passe à la page suivante.
Conseil: Je vous recommanderais également d'utiliser autre chose que getImageData
, car cette option stockera des images non compressées, par exemple, data-uri, qui est plutôt des données compressées.
Voici une approche légèrement différente qui élimine la boucle perdue et utilise mieux les promesses à cette fin:
var canvas = document.createElement('canvas'), // single off-screen canvas
ctx = canvas.getContext('2d'), // to render to
pages = [],
currentPage = 1,
url = 'path/to/document.pdf'; // specify a valid url
PDFJS.getDocument(url).then(iterate); // load PDF document
/* To avoid too many levels, which easily happen when using chained promises,
the function is separated and just referenced in the first promise callback
*/
function iterate(pdf) {
// init parsing of first page
if (currentPage <= pdf.numPages) getPage();
// main entry point/function for loop
function getPage() {
// when promise is returned do as usual
pdf.getPage(currentPage).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
// now, tap into the returned promise from render:
page.render(renderContext).then(function() {
// store compressed image data in array
pages.Push(canvas.toDataURL());
if (currentPage < pdf.numPages) {
currentPage++;
getPage(); // get next page
}
else {
done(); // call done() when all pages are parsed
}
});
});
}
}
Lorsque vous devez ensuite récupérer une page, vous créez simplement un élément d'image et définissez le data-uri en tant que source:
function drawPage(index, callback) {
var img = new Image;
img.onload = function() {
/* this will draw the image loaded onto canvas at position 0,0
at the optional width and height of the canvas.
'this' is current image loaded
*/
ctx.drawImage(this, 0, 0, ctx.canvas.width, ctx.canvas.height);
callback(); // invoke callback when we're done
}
img.src = pages[index]; // start loading the data-uri as source
}
En raison du chargement de l'image, elle sera également de nature asynchrone, raison pour laquelle nous avons besoin du rappel. Si vous ne souhaitez pas utiliser la nature asynchrone, vous pouvez également effectuer cette étape (création et définition de l'élément image) dans la promesse de rendu au-dessus de la sauvegarde d'éléments d'image au lieu de données-uris.
J'espère que cela t'aides!
Ce n'est pas une réponse, mais une donnée HTML complète telle que l'information peut être plus complète. Le but est d'utiliser une solution minimale pdf.js pour afficher plusieurs pages pdf car le exemple helloworld ne peut restituer qu'une seule page. Le JavasScript suivant ne fonctionne pas, espérons que quelqu'un pourra résoudre le problème.
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<!-- Use latest PDF.js build from Github -->
<script src=https://raw.github.com/mozilla/pdf.js/gh-pages/build/pdf.js></script>
</head>
<body>
<canvas id=the-canvas style="border:1px solid black"></canvas>
<script>
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
var scale = 1.5;
var canvasWidth = 0;
var canvasHeight = 0;
var pageStarts = new Array();
pageStarts[0] = 0;
var url = 'pdfjs.pdf';
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i=1; i<=pdf.numPages; i++) {
pdf.getPage(i).then(function getPage(page) {
var viewport = page.getViewport(scale);
canvas.width = viewport.width; // changing canvas.width and/or canvas.height auto-clears the canvas
canvas.height = viewport.height;
page.render({canvasContext:context, viewport:viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
if(canvas.width>canvasWidth) { // calculate the width of the final display canvas
canvasWidth = canvas.width;
}
canvasHeight += canvas.height; // calculate the accumulated with of the final display canvas
pageStarts[i] = pageStarts[i-1] + canvas.height; // save the "Y" starting position of this pages[i]
});
}
canvas.width = canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for(var i=0; i<pages.length; i++) {
context.putImageData(pages[i], 0, pageStarts[i]);
}
});
</script>
</body>
</html>