使用pdf.js和ImageData将.pdf渲染到单个画布
Render .pdf to single Canvas using pdf.js and ImageData
我正在尝试使用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操作在所有阶段都是异步的。这意味着你还需要在最后一次渲染时捕获承诺。如果你没有捕捉到它,你只会得到一个空白的画布,因为在循环继续到下一页之前渲染还没有完成。
提示:我还建议您使用getImageData
以外的其他东西,因为它将存储未压缩的位图,例如data-uri,而不是压缩数据。
LIVE FIDDLE
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
}
});
});
}
}
当需要检索页面时,只需创建一个image元素并将data-uri设置为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
}
由于图像加载,它将是异步的性质,以及这就是为什么我们需要回调。如果你不想要异步特性,那么你也可以在上面的渲染承诺中执行这一步(创建和设置image元素)来存储image元素而不是data-uri。
希望这对你有帮助!
我不能说你的代码将pdf渲染成画布的部分,但我确实看到了一些问题。
- 每次重置画布。宽度或画布。Height自动清除画布内容。在顶部部分,你的clearRect是不需要的因为画布被画布清除了。宽度之前,你的每个页面。渲染。
- 更重要的是,在底部部分,所有你以前的pdf图纸被清除每次画布大小调整(哎呀!)。
- getImageData()获得一个数组,其中每个像素由该数组的4个连续元素表示(红色然后绿色然后蓝色然后alpha)。因为getImageData()是一个数组,所以它没有pages[i]。宽度或页面[i]。高度,它只有一个页面[i],长度。该数组长度不能用于确定宽度或高度。
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]);
}
});
或者,这里有一种更传统的完成任务的方法:
使用单个"显示"画布,并允许用户"浏览"每个所需的页面。
既然您已经开始将每个页面绘制到画布中,为什么不为每个页面保留一个单独的隐藏画布呢?然后,当用户想要看到第6页时,只需将隐藏画布#6复制到显示画布上。
Mozilla开发人员在他们的pdfJS演示中使用了这种方法:http://mozilla.github.com/pdf.js/web/viewer.html
您可以在这里查看查看器的代码:http://mozilla.github.com/pdf.js/web/viewer.js
你可以将数字页面传递给承诺,获取页面画布数据并在画布上以正确的顺序呈现
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);
});
}
- 如何使用javascript或html下载PDF格式的填写表单
- Javascript,有没有一种方法可以将数组写成没有逗号或空格的单个文本字符串
- 如何使用javascript获取嵌套对象中所有子对象的单个属性
- 是否可以禁用jquery中的单个单选按钮
- 如何将PDF作为二进制文件传递到window.open()
- 引导程序:在导航栏中,显示悬停在单个位置的基于Li Link的不同内容
- 为什么在画布上画线;t出现
- javascript.点击显示嵌入的pdf
- 在地图上画一条路线
- 使用jquery选中/取消选中单个复选框
- Javascript/Jquery Blob not showing Chrome PDF
- 单个页面上有多个标记表单
- 在不破坏未定义函数的情况下,对多个视图使用单个js文件
- 在提交时打开thankyou.html+下载PDF
- 生成pdf或其他非html文件时的错误处理
- 用于多个类事件Jquery的单个函数
- how to convert html <div> to pdf
- 将多个页面的html导出为单个pdf
- 使用PDFJS从单个PDF页面提取图像
- 使用pdf.js和ImageData将.pdf渲染到单个画布