1. 前言:
- 公司项目需要实现一个功能:将电子签名的图片嵌入到一个pdf文件中,然后导出
- 思路:利用第三方插件
pdf.lib
实现
2. 实现思路
- 首先需要一个已知的pdf文件(转成ArrayBuffer类型),一个电子签名图片(转成Base64类型)
- 然后在vue项目中引入
pdf.lib
插件 - 先通过
pdf.lib
的load()
方法读取pdf文件,通过embebPng()
方法将图片嵌入到pdf文件中 - 然后利用
drawImg()
方法调整图片到指定为止 - 最后用
save()
方法生成处理好的pdf文件(此时是ArrayBuffer类型) - 如果是需要下载处理好的文件,转成
Blob
类型然后实现下载 - 如果是传入后端接口,转成
file
类型用formData
表单形式发送文件数据
3. 实现代码:
首先安装插件:
npm install pdf-lib --save
typescript
import { PDFDocument } from "pdf-lib";
import axios from "axios";
// 处理函数,注意处理文件是异步的,async/await 不能漏
async function handleSubmit() {
// 1. 通过fetch请求拿到本地的拿到PDF文件
const pdfResponse = await fetch("/example.pdf");
// 2. 将pdf文件转成ArrayBuffer形式
const pdfArrayBuffer = await pdfResponse.arrayBuffer();
// 3. 拿到签名图片,这里的imgData就是png图片,要是Base64格式的
const pngBase64 = imgData;
// 4. 使用pdf.lib插件读取PDF文档
const pdfDoc = await PDFDocument.load(pdfArrayBuffer);
// 5. 将Base64格式的图片转成相应的png图片格式,如果要转成jpg的,改用`embebJpg()`方法
const pngImage = await pdfDoc.embedPng(pngBase64);
// 6. 读取PDF页数
const pages = pdfDoc.getPages();
// 7. 在PDF相应页码中绘制,这里是在第二页绘制
pages[1].drawImage(pngImage, { x: 120, y: 80, width: pngImage.width / 20, height: pngImage.height / 20 });
// 8. 处理完后,将数据另存为pdf文件(此时是ArrayBuffer格式)
const pdfBytes = await pdfDoc.save();
// 9. 这里是下载功能:ArrayBuffer 转 Blob 再转 File,然后生成下载链接
const blob = new Blob([pdfBytes], { type: "application/pdf" });
const file = new File([blob], "example.pdf", { type: "application/pdf" });
// 10. 生成下载链接
const url = URL.createObjectURL(blob);
// 11. 触发下载
const a = document.createElement("a");
a.href = url;
a.download = "example.pdf";
document.body.appendChild(a);
a.click();
// 12. 释放 URL 对象
URL.revokeObjectURL(url);
document.body.removeChild(a);
// 13. 这里是上传数据到服务器的方法:上传 PDF 文件
const formData = new FormData();
formData.append("file", file);
// 14. 这里是接口的一个自定义参数biz,用来指定上传到哪个目录
formData.append("biz", "report");
// 15. 发送接口数据
await axios({
headers: {
"Content-Type": "multipart/form-data",
},
method: "POST",
url: "http://example.com/upload",
data: formData
});
}
</script>