Html2Canvas 和 jsPDF 每页添加1个图像

4
我正在使用jsPDF和html2canvas(0.4.1),将一个div中的图像保存为单个pdf。
到目前为止,我的代码几乎可以正常工作,但我有一个问题。
当用户选择多张图片时,图像会被保存在同一页中。因此,我希望每个图像都在不同的页面上。我的代码如下:
<div id="imagesPreview"></div>

<script>
$(document).ready(function(){
$("#modalSave").click(function(){

var inputValue = $('#form29').val()
var imagesnumber = $("#imagesPreview img").length;
//alert(imagesnumber);

var imgData;
html2canvas(document.getElementById("imagesPreview"),{
    useCORS: true,
    onrendered:function(canvas){
    imgData = canvas.toDataURL('image/png');
    //Make The Pdf Document
    var doc = new jsPDF('p','pt','a4');

    if (imagesnumber > 1){
        var i;
        for (i = 1; i < imagesnumber; i++) 
        {
        doc.addImage(imgData,'PNG',10,10)[i];
        doc.addPage()[i];
        }
    }else{
        doc.addImage(imgData,'PNG',10,10);
    }

        if($('#inputValue').val() == ''){
    doc.save('MyPdf.pdf');
    }else{
    doc.save(inputValue+'.pdf');
    }
    window.open(imgData);
    }

    })

});
});
</script>

我正在使用imagesnumber来计算div内部的图像数量。有任何想法吗?
1个回答

4
你可以这样做:
  1. 循环遍历所有图片
  2. 在遍历过程中,将每个画布转换为PNG格式
  3. 将每个PNG添加到PDF中
  4. 检查数组长度是否还有更多的图片需要添加。如果是,则使用addPage()
  5. 添加then()方法以确保只有在所有操作完成后才保存PDF。此外,在then()方法中,检查循环索引的位置,以便仅在添加了最后一张图片后才保存PDF。

在我的示例中,那两个小蓝色块将是要添加到PDF中的图片。现在,由于沙箱限制,此示例无法在Stack Overflow上运行,但您可以在此处查看工作正常的JSFiddle。

const imgs = [...document.querySelectorAll('.img')]
const btn = document.querySelector('a')

btn.addEventListener('click', () => {
    const doc = new jsPDF()
    imgs.forEach((a, i) => {
        html2canvas(a)
        .then(canvas => {
            const img = canvas.toDataURL('image/png')
            doc.addImage(img,'PNG', 45, 45, 100, 100);
            if (imgs.length > (i+1)) {
                doc.addPage()
            }
        })
        .then(() => {
            if ((i+1) === imgs.length) {
                doc.save('MyPdf.pdf')
            }
        })
    })
})
span {width: 20px; height: 20px; background-color: blue; display: inline-block}
a {display: block}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js" crossorigin="anonymous"></script>
<span class="img"></span>
<span class="img"></span>
<a href="#">Download PDF</a>

更新

以下是使用<img>标签完成同样功能的方法,不需要使用Html2canvas创建图片。在这个例子中,你完全不需要Html2canvas。我已经更新了上面的JSFiddle链接以展示这个例子。

const imgs = [...document.querySelectorAll('.img')]
const btn = document.querySelector('a')

btn.addEventListener('click', () => {
    const doc = new jsPDF()
    let dataUrl
    async function makeImg(img) {
        let blob = await fetch(img.src).then(res => res.blob());
        dataUrl = await new Promise(resolve => {
            let reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsDataURL(blob);
        })
    }
    imgs.forEach((a, i) => {
        makeImg(a)
        .then(res => {
            doc.addImage(dataUrl, 'PNG', 45, 45, a.style.width, a.style.height)
            if (imgs.length > (i+1)) {
                doc.addPage()
            }
        })
        .then(() => {
            if ((i+1) === imgs.length) {
                doc.save('MyPdf.pdf')
            }
        })
    })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>
<img class="img" src="https://i.postimg.cc/NfMXcB4c/Screenshot-2020-06-09-at-18-35-56.png">
<img class="img" src="https://i.postimg.cc/NfMXcB4c/Screenshot-2020-06-09-at-18-35-56.png">
<a href="#" style="display: block">Download PDF</a>


如果我用图片替换你的span,并且保留类名为img,它就无法工作。在导出的PDF中会得到空白页面。有什么想法吗? - undefined
嘿@YeorgiosLaskos .. 嗯,我确实有一个想法。我认为这是因为html2canvas将HTML元素呈现为<canvas>元素,然后再呈现为实际图像 - 当您从开始使用实际图像时,html2canvas无法将其呈现为<canvas>元素。我认为解决方法可能是首先使用toDataUrl()方法创建这些图像的数据URL,在这种情况下,您可能实际上不需要html2canvas。现在是睡觉时间,但如果可以的话,我可以尝试弄清楚然后在早上更新答案? - undefined
非常感谢你的时间,伙计。请在有空的时候更新你的代码。不幸的是,我不能按上箭头来点赞你的回答,因为这需要15+的声望... :-( - undefined
只是一种愉悦的感觉,兄弟 =) 我将尽快尝试解决并更新答案。啊,还有谢谢你至少尝试了,我很感激。我会给你的问题点赞,因为没有其他人回答意味着这是一个棘手的问题和一个好问题。这将给你一些积分 ;) 虽然不够,但你会有更多积分。 - undefined
@YeorgiosLaskos 我已经搞清楚了并更新了答案。希望对你有所帮助,需要更多帮助的话就大声喊我 =) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接