Skip to content Skip to sidebar Skip to footer

Render .pdf To Single Canvas Using Pdf.js And Imagedata

I am trying to read an entire .pdf Document using PDF.js and then render all the pages on a single canvas. My idea: render each page onto a canvas and get the ImageData (context.ge

Solution 1:

I can’t speak to the part of your code that renders the pdf into a canvas, but I do see some problems.

  • Every resetting canvas.width or canvas.height automatically clears the canvas contents. So in the top section, your clearRect is not needed because the canvas is cleared by canvas.width prior to your every page.render.
  • More importantly, in the bottom section, all your previous pdf drawings are cleared by every canvas resizing (oops!).
  • getImageData() gets an array where each pixel is represented by 4 consecutive elements of that array (red then green then blue then alpha). Since getImageData() is an array, so it doesn’t have a pages[i].width or pages[i].height—it only has a pages[i].length. That array length cannot be used to determine widths or heights.

So to get you started, I would start by changing your code to this (very, very untested!):

var pdf = null;
PDFJS.disableWorker = true;
var pages = newArray();
//Prepare some thingsvar canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
var canvasWidth=0;
var canvasHeight=0;
var pageStarts=newArray();
pageStarts[0]=0;

PDFJS.getDocument(url).then(functiongetPdfHelloWorld(_pdf) {
    pdf = _pdf;
    //Render all the pages on a single canvasfor(var i = 1; i <= pdf.numPages; i ++){
        pdf.getPage(i).then(functiongetPage(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 canvasif(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 contentsfor(var i = 0; i < pages.length; i++){
        context.putImageData(pages[i], 0, pageStarts[i]);
    }

});

Alternatively, here’s a more traditional way of accomplishing your task:

Use a single “display” canvas and allow the user to “page through” each desired page.

Since you already start by drawing each page into a canvas, why not keep a separate, hidden canvas for each page. Then when the user wants to see page#6, you just copy the hidden canvas#6 onto your display canvas.

The Mozilla devs use this approach in their pdfJS demo here: http://mozilla.github.com/pdf.js/web/viewer.html

You can check out the code for the viewer here: http://mozilla.github.com/pdf.js/web/viewer.js

Solution 2:

You can pass the number page to the promises , get that page canvas data and render in the right order on canvas

var renderPageFactory = function (pdfDoc, num) {
        returnfunction () {

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

Complete example

functionrenderPDF(url, canvas) {



    var pdf = null;
    PDFJS.disableWorker = true;
    var pages = newArray();

    var context = canvas.getContext('2d');
    var scale = 1;

    var canvasWidth = 256;
    var canvasHeight = 0;
    var pageStarts = newArray();
    pageStarts[0] = 0;





    var k = 0;

    functionfinishPage(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 contentsfor (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++;


    }

    functionrenderPage(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(functiongetPdfHelloWorld(_pdf) {

        pdf = _pdf;



        var renderPageFactory = function (pdfDoc, num) {
            returnfunction () {

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






    });





}

Post a Comment for "Render .pdf To Single Canvas Using Pdf.js And Imagedata"