简体   繁体   English

如何知道 PDF.JS 是否已完成渲染?

[英]How to know if PDF.JS has finished rendering?

I am using PDF.JS to render pdf pages into different canvas elements.我正在使用 PDF.JS 将 pdf 页面呈现到不同的画布元素中。 my requirement is to capture the output of the canvas and to display it as an image.我的要求是捕获画布的输出并将其显示为图像。 Is there some event to know if the rendering of the pdf page in canvas has been finished or not.是否有一些事件可以知道画布中 pdf 页面的渲染是否已经完成。 because when I try to capture the output of canvas it is blank.因为当我尝试捕获画布的输出时,它是空白的。 but the pdf page is rendered properly.但pdf页面正确呈现。 it looks like my capture event is being called before the pdf.js finishes the rendering process.看起来我的捕获事件在 pdf.js 完成渲染过程之前被调用。

here is my code:这是我的代码:

page.render(renderContext);
var myImage = new Image();
myImage.src = document.getElementById('my-canvas-id').toDataURL();
$('body').append(myImage);

If I execute the same code in my FireFox's console this works fine.如果我在我的 FireFox 控制台中执行相同的代码,它就可以正常工作。 so nothing is wrong with this code.所以这段代码没有任何问题。

Just to let you people know that I already have tried document.ready and window.load events.只是为了让大家知道我已经尝试过 document.ready 和 window.load 事件。

I was also struggling with this problem.. the solution that i used is:我也在努力解决这个问题..我使用的解决方案是:

//Step 1: store a refer to the renderer
var pageRendering = page.render(renderContext);
//Step : hook into the pdf render complete event
var completeCallback = pageRendering.internalRenderTask.callback;
pageRendering.internalRenderTask.callback = function (error) {
  //Step 2: what you want to do before calling the complete method                  
  completeCallback.call(this, error);
  //Step 3: do some more stuff
};

 <script type="text/javascript"> document.addEventListener("pagesloaded", function(e) { //do sth.. }); </script>

worked for me为我工作

At the time of writing, this did work.在撰写本文时,这确实有效。 I'm not sure if it still does.我不确定它是否仍然存在。

PDFJS makes use of Promises . PDFJS 使用Promises The easiest thing to do is the following:最简单的方法如下:

page.render(renderContext).promise.then(function(){
  document.body.appendChild(canvas);
});

Using the textlayerrendered event worked for me:使用textlayerrendered事件对我textlayerrendered

document.addEventListener('textlayerrendered', function (event) {
  // was this the last page?
  if (event.detail.pageNumber === PDFViewerApplication.page) {
    console.log('Finished rendering!');
  }
}, true);

Lyon's solution of more robust.里昂的解决方案更加稳健。 But this is the simplest solution I could find.但这是我能找到的最简单的解决方案。

var renderTask = pdfPage.render(renderContext);
renderTask.promise.then(
  function pdfPageRenderCallback() {
    pageViewDrawCallback(null);
  },
  function pdfPageRenderError(error) {
    pageViewDrawCallback(error);
  }
);

While examining these solutions, I was having issues getting the renderContext , so I ended up using this approach listening to pagerendered :在检查这些解决方案时,我在获取renderContext时遇到了问题,所以我最终使用了这种方法来监听pagerendered

document.addEventListener("pagerendered", function(e){

});

In my case, I just wanted to call some external function after the page was rendered, with minimal effort.就我而言,我只是想在页面呈现后调用一些外部函数,而只需最少的努力。

Hope this helps.希望这可以帮助。 Cheers!干杯!

window.addEventListener('load', function () {
    PDFViewerApplication.eventBus.on('textlayerrendered', function () {
      console.log('textlayerrendered', arguments, PDFViewerApplication)
    })

Event name textlayerrendered includes of PDFViewerApplication.eventBus._listeners事件名称textlayerrendered包括PDFViewerApplication.eventBus._listeners

According to documentation from PDF.js .根据PDF.js 的文档。

for versions before 2.2 use:对于 2.2 之前的版本使用:
page.render(renderContext).then(function(){
var myImage = new Image();
myImage.src = document.getElementById('my-canvas-id').toDataURL();
$('body').append(myImage);
});

For versions after and including 2.2 use: page.render(renderContext).promise.then(function(){对于 2.2 之后的版本,请使用: page.render(renderContext).promise.then(function(){
var myImage = new Image();
myImage.src = document.getElementById('my-canvas-id').toDataURL();
$('body').append(myImage);
});

I have changed my code in this way and it helped me what I wanted to do:我以这种方式更改了我的代码,它帮助了我想要做的事情:

pageRendering = page.render(renderContext);
pageRendering.onData(function(){
    var myImage = new Image();
    myImage.src = document.getElementById('my-canvas-id').toDataURL();
    $('body').append(myImage);
});

This helps only if the specific page has finished rendering.仅当特定页面已完成呈现时,这才有帮助。 it doesn't tell you about the rendering of all of the pages.它不会告诉您所有页面的渲染。

If you want to render all pages of pdf document in different canvases, all one by one synchronously this is kind of solution:如果你想在不同的画布中渲染pdf文档的所有页面,所有页面都是同步的,这是一种解决方案:

index.html索引.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>PDF Sample</title>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="pdf.js"></script>
    <script type="text/javascript" src="main.js">
    </script>
    <link rel="stylesheet" type="text/css" href="main.css">
</head>
<body id="body">  
</body>
</html>

main.css主文件

canvas {
    display: block;
}

main.js主文件

$(function() {  
    var filePath = "document.pdf";

    function Num(num) {
        var num = num;

        return function () {
            return num;
        }
    };

    function renderPDF(url, canvasContainer, options) {
        var options = options || {
                scale: 1.5
            },          
            func,
            pdfDoc,
            def = $.Deferred(),
            promise = $.Deferred().resolve().promise(),         
            width, 
            height,
            makeRunner = function(func, args) {
                return function() {
                    return func.call(null, args);
                };
            };

        function renderPage(num) {          
            var def = $.Deferred(),
                currPageNum = new Num(num);
            pdfDoc.getPage(currPageNum()).then(function(page) {
                var viewport = page.getViewport(options.scale);
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');
                var renderContext = {
                    canvasContext: ctx,
                    viewport: viewport
                };

                if(currPageNum() === 1) {                   
                    height = viewport.height;
                    width = viewport.width;
                }

                canvas.height = height;
                canvas.width = width;

                canvasContainer.appendChild(canvas);

                page.render(renderContext).then(function() {                                        
                    def.resolve();
                });
            })

            return def.promise();
        }

        function renderPages(data) {
            pdfDoc = data;

            var pagesCount = pdfDoc.numPages;
            for (var i = 1; i <= pagesCount; i++) { 
                func = renderPage;
                promise = promise.then(makeRunner(func, i));
            }
        }

        PDFJS.disableWorker = true;
        PDFJS.getDocument(url).then(renderPages);       
    };

    var body = document.getElementById("body");
    renderPDF(filePath, body);
});

As it turns out, your first line, page.render(renderContext);事实证明,你的第一行, page.render(renderContext); returns a RenderTask object which has 3 properties:返回一个RenderTask对象,它有 3 个属性:

  • internalRenderTask - an InternalRenderTask , duh internalRenderTask - 一个InternalRenderTask ,呃
  • cancel - a function, presumably to allow you to cancel the rendering effort取消- 一个函数,大概是为了让你取消渲染工作
  • promise - a jQuery Promise object promise - 一个 jQuery Promise对象

The Promise is the one you want.承诺是你想要的。 To make use of it, it goes like this:要使用它,它是这样的:

 page.render(renderContext).promise.then(function() {

     //do something after the page is rendered here
 });

Hope that helps.希望有帮助。

Depending on which components (and version) of PDF.js you are making use of, you can also use the EventBus.根据您使用的 PDF.js 组件(和版本),您还可以使用 EventBus。

If you are using the simplest implementation of PDF.js then this might not be available, but if you are using their SimpleViewer or PageViewer examples , try this:如果您使用的是最简单的 PDF.js 实现,那么这可能不可用,但如果您使用的是他们的SimpleViewer 或 PageViewer 示例,请尝试以下操作:

        eventBus.on("pagesloaded", function() {
            console.log('pagesloaded');
            // your code here
        });

eventBus should already be defined, if not, you can set it up using: eventBus 应该已经定义好了,如果没有,你可以使用:

var eventBus = new pdfjsViewer.EventBus();

Again, this depends on the level of complexity in your PDF Viewer.同样,这取决于 PDF 查看器的复杂程度。 Turns out there are many different layers within PDF.js.原来 PDF.js 中有许多不同的层。

To listen for every page load, use the eventBus event ' pagerendered '要侦听每个页面加载,请使用 eventBus 事件“ pagerendered

page.render is a promise so you have to do your stuff inside your success like below: page.render 是一个承诺,所以你必须在你的成功中做你的事情,如下所示:

page.render({
  canvasContext: context,
  viewport: viewport
}).then(function() {
//do your stuff here });

If you're using pdf.js with the viewer application, here's the best way I've found to wait for it to be initialized:如果您在查看器应用程序中使用 pdf.js,这是我发现等待它初始化的最佳方法:

// Wait for the PDFViewerApplication to initialize                                                                                                                         
PDFViewerApplication.initializedPromise.then(function() {
    // Do whatever startupcode you need to here, now that the EventBus
    // is read. For example:
    PDFViewerApplication.eventBus.on('pagerendered', function (e) {
        annotationInterface.onPageRendered(e);
    });
});

This is the only way I've found to use the Viewer API and manipulate rendered pages without errors.这是我发现使用 Viewer API 并无错误地操作呈现页面的唯一方法。

onPagesLoaded = () => { 
    // do something, set zoom, current page, ...
};

window.PDFViewerApplication.eventBus.on('pagesloaded', onPagesLoaded);

If you are creating/modifying the PDF on the backend you can add pdfjavascript to the PDF file to print on load.如果您在后端创建/修改 PDF,您可以将 pdf javascript 添加到 PDF 文件以在加载时打印。

var pp = getPrintParams();  
pp.interactive=pp.constants.interactionLevel.full; 
print(pp);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM