浏览器html代码生成图片保存为PDF并上传

1,303 阅读2分钟

使用html2canvas生成图片

使用的资源npm i html2canvas 获得base64的图片

const container = document.body;
const canvas = await html2canvas(container, {
    scale: window.devicePixelRatio,
    width: container.offsetWidth,
    height: container.offsetHeight,
    useCORS: true,
    allowTaint: false
});
const missionImg = canvas.toDataURL('image/jpeg', 1.0);

下载图片

var a = document.createElement('a');
a.download = '文件.jpg';  //下载的文件名,默认是'下载'
a.href = missionImg; 
document.body.appendChild(a);
a.click();
a.remove();  //下载之后把创建的元素删除

使用jspdf生成pdf

使用的资源<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>,这个包安装的太大,所以引用静态资源放在本地,

使用jspdf获取pdf实例

const contentWidth = canvas.width;
const contentHeight = canvas.height;
// 一页pdf显示html页面生成的canvas高度;
const pageHeight = contentWidth / 592.28 * 841.89;
// 未生成pdf的html页面高度
let leftHeight = contentHeight;
// pdf页面偏移
let position = 0;
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = 595.28;
const imgHeight = 592.28 / contentWidth * contentHeight;
const missionImg = canvas.toDataURL('image/jpeg', 1.0);
// 三个参数,第一个方向,第二个尺寸,第三个尺寸格式
const doc = new jspdf.jsPDF('', 'pt', 'a4');
// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
// 当内容未超过pdf一页显示的范围,无需分页
// console.log('--leftHeight--', leftHeight, '--pageHeight--', pageHeight);
if (leftHeight < pageHeight) {
    doc.addImage(missionImg, 'JPEG', 0, 0, imgWidth, imgHeight);
} else {
    while (leftHeight > 0) {
        // console.log('--leftHeight--', leftHeight, '--position--', position);
        doc.addImage(missionImg, 'JPEG', 0, position, imgWidth, imgHeight);
        leftHeight -= pageHeight;
        position -= 841.89;
        // 避免添加空白页
        if (leftHeight > 0) {
            doc.addPage();
        }
    }
}

上面代码仅考虑分页情况,所以每页的留白和每页的分割,都需要自己根据实际情况去处理,当需要添加padding的时候注意box-sizing: border-box;配合使用

pdf 文件下载

doc.save('download.pdf');

pdf 文件上传

这里的文件上传使用的把base64格式转换成文件再上传,因此需要有一个转换的过程。

同时如果上传数据里面有对象或者数组需要对每个属性单独添加。params.append('obj[keyName]', keyValue),数组就需要加上索引的属性访问。

// 生成file
function dataURLtoFile(dataurl) {
    const arr = dataurl.split(','); 
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    const file = new File([u8arr], 'file.pdf', {type: mime});
    return file;
}

const file = dataURLtoFile(doc.output('datauri'))
const params = new FormData();
params.append(file, file);

// axios.post(url, params)

直接打开文件

在文件上传的基础上,当生成了文件以后生成一个文件链接并打开

const blob = dataURLtoFile(doc.output('datauri'));
window.open(URL.createObjectURL(blob));

如果被浏览器拦截,在点击按钮之前优先生成好链接,点击按钮以后仅仅open一下生成的链接。