Search code examples
javascriptjspdfhtml2canvas

How can I combine multiple images into one page and print it as a pdf?


I've a webpage with 4 charts. I'm taking separate screenshots for each of them. Then tried to put them on another canvas, show them vertically and print it as single-page pdf file. But, I'm getting an Error saying:

Uncaught TypeError: CanvasRenderingContext2D.drawImage: Argument 1 could not be converted to any of: HTMLImageElement, SVGImageElement, HTMLCanvasElement, HTMLVideoElement, ImageBitmap.

Here is the script

function HTMLtoPDF() {

    function verticalCanvases(cnv1, cnv2, cnv3, cnv4) {
        var newCanvas = document.createElement('canvas'),
            ctx = newCanvas.getContext('2d'),
            width = cnv1.width,
            height = cnv1.height + cnv2.height + cnv3.height + cnv4.height;
    
        newCanvas.width = width;
        newCanvas.height = height;
    
        [{
            cnv: cnv1,
            y: 0
        },
        {
            cnv: cnv2,
            y: cnv1.height
        },
        {
            cnv: cnv3,
            y: cnv1.height + cnv2.height
        },
        {
            cnv: cnv4,
            y: cnv1.height + cnv2.height + cnv3.height

        }].forEach(function(n) {
            ctx.beginPath();
            ctx.drawImage(n.cnv, 0, n.y, width, n.cnv.height);
        });
    
         var imgdata = newCanvas.toDataURL();

        return imgdata;
    }

    var forms = $('[id^=caspioform]');

    var canvas1 = html2canvas(forms[3]);
    var canvas2 = html2canvas(forms[5]);
    var canvas3 = html2canvas(forms[7]);
    var canvas4 = html2canvas(forms[9]);

    var dURL = verticalCanvases(canvas1, canvas2, canvas3, canvas4);

    var doc = new jsPDF("p", "mm", "a4");

    var width = doc.internal.pageSize.getWidth();
    var height = doc.internal.pageSize.getHeight();

    doc.addImage(dURL, 'PNG', 0, 0, width, height);

    doc.save('sample.pdf');
}


Solution

  • Since you didn't mention it, I'll assume html2canvas is coming from https://github.com/niklasvh/html2canvas

    In that case, the issue here is that hmtl2canvas returns a Promise and that's what you're passing to verticalCanvases instead of the actual canvas element.

    To fix it just transform the function in an asynchronous one so you can use async/await:

    // |
    // |
    // v
    async function HTMLtoPDF() {
    
        function verticalCanvases(cnv1, cnv2, cnv3, cnv4) {
            var newCanvas = document.createElement('canvas'),
                ctx = newCanvas.getContext('2d'),
                width = cnv1.width,
                height = cnv1.height + cnv2.height + cnv3.height + cnv4.height;
        
            newCanvas.width = width;
            newCanvas.height = height;
        
            [{
                cnv: cnv1,
                y: 0
            },
            {
                cnv: cnv2,
                y: cnv1.height
            },
            {
                cnv: cnv3,
                y: cnv1.height + cnv2.height
            },
            {
                cnv: cnv4,
                y: cnv1.height + cnv2.height + cnv3.height
    
            }].forEach(function(n) {
                ctx.beginPath();
                ctx.drawImage(n.cnv, 0, n.y, width, n.cnv.height);
            });
        
             var imgdata = newCanvas.toDataURL();
    
            return imgdata;
        }
    
        var forms = $('[id^=caspioform]');
    
        var canvas1 = await html2canvas(forms[3]); // <--
        var canvas2 = await html2canvas(forms[5]); // <--
        var canvas3 = await html2canvas(forms[7]); // <--
        var canvas4 = await html2canvas(forms[9]); // <--
    
        var dURL = verticalCanvases(canvas1, canvas2, canvas3, canvas4);
    
        var doc = new jsPDF("p", "mm", "a4");
    
        var width = doc.internal.pageSize.getWidth();
        var height = doc.internal.pageSize.getHeight();
    
        doc.addImage(dURL, 'PNG', 0, 0, width, height);
    
        doc.save('sample.pdf');
    }