PDF.jsを使用して.pdfドキュメント全体を読み取り、すべてのページを単一のキャンバスにレンダリングしようとしています。
私の考え:各ページをキャンバスにレンダリングしてImageData(context.getImageData())を取得し、キャンバスをクリアして次のページを実行します。すべてのImageDataを配列に格納し、すべてのページがそこに配置されたら、配列のすべてのImageDataを単一のキャンバスに配置します。
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;
}
});
だから私はこれがうまくいくはずだということを理解していますか?これを実行すると、PDFのすべてのページを含めるのに十分な大きさのキャンバスが表示されますが、PDFは表示されません...
助けてくれてありがとう。
PDFをキャンバスにレンダリングするコードの一部についてはお話しできませんが、いくつか問題があります。
だからあなたを始めるために、私はあなたのコードをこれに変更することから始めます(非常に、非常にテストされていません!):
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]);
}
});
あるいは、ここでは、タスクを達成するためのより伝統的な方法を示します:
単一の「表示」キャンバスを使用して、ユーザーが目的の各ページを「ページ送り」できるようにします。
すでに各ページをキャンバスに描画することから始めているので、各ページに個別の非表示のキャンバスを保持してみませんか。次に、ユーザーがpage#6を表示したい場合は、非表示のcanvas#6を表示キャンバスにコピーするだけです。
Mozilla開発者は、pdfJSデモでこのアプローチを使用しています。 http://mozilla.github.com/pdf.js/web/viewer.html
ここでビューアのコードをチェックアウトできます: http://mozilla.github.com/pdf.js/web/viewer.js
PDF操作はすべての段階で非同期です。これは、最後のレンダリングでもプロミスをキャッチする必要があることを意味します。それをキャッチしない場合、レンダリングが行われていないため、空白のキャンバスしか取得できませんループが次のページに続く前に終了していません。
ヒント:getImageData
以外のものを使用することをお勧めします。これは、圧縮されていないビットマップ、たとえば圧縮データであるdata-uriなどを格納するためです。
これは、forループを排除するわずかに異なるアプローチであり、この目的のためにより良い約束を使用します:
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
}
});
});
}
}
その後、ページを取得する必要がある場合は、単に画像要素を作成し、data-uriをソースとして設定します。
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
}
画像の読み込みが原因で、画像も非同期になるため、コールバックが必要になります。非同期の性質が必要ない場合は、データURIの代わりに画像要素を格納する上記のレンダープロミスでこの手順(画像要素の作成と設定)を行うこともできます。
お役に立てれば!
これは答えではありませんが、情報がより完全になるようなHTMLデータ全体です。 helloworld example は1ページしかレンダリングできないため、目的は最小限のpdf.jsソリューションを使用して複数のpdfページを表示することです。次のJavasScriptが機能していません。誰かが問題を解決できることを願っています。
<!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>
あなたは番号ページをpromiseに渡し、そのページのキャンバスデータを取得し、キャンバス上で正しい順序でレンダリングできます。
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
完全な例
function renderPDF(url, canvas) {
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
var context = canvas.getContext('2d');
var scale = 1;
var canvasWidth = 256;
var canvasHeight = 0;
var pageStarts = new Array();
pageStarts[0] = 0;
var k = 0;
function finishPage(localCanvas, num) {
var ctx = localCanvas.getContext('2d');
pages[num] = ctx.getImageData(0, 0, localCanvas.width, localCanvas.height);
// calculate the accumulated with of the final display canvas
canvasHeight += localCanvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[num] = pageStarts[num -1] + localCanvas.height;
if (k + 1 >= pdf.numPages)
{
canvas.width = canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for (var i = 0; i < pages.length; i++) {
context.putImageData(pages[i+1], 0, pageStarts[i]);
}
var img = canvas.toDataURL("image/png");
$scope.printPOS(img);
}
k++;
}
function renderPage(page, localCanvas, num) {
var ctx = localCanvas.getContext('2d');
var viewport = page.getViewport(scale);
// var viewport = page.getViewport(canvas.width / page.getViewport(1.0).width);
// changing canvas.width and/or canvas.height auto-clears the canvas
localCanvas.width = viewport.width;
/// viewport.width = canvas.width;
localCanvas.height = viewport.height;
var renderTask = page.render({canvasContext: ctx, viewport: viewport});
renderTask.then(() => {
finishPage(localCanvas, num);
});
}
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
});
}