UNIAPP给PDF添加内容并下载
插件选择
选择 pdf-lib 插件,安装插件的字体库 @pdf-lib/fontkit
npm install pdf-lib
npm install @pdf-lib/fontkit
获取PDF文档
import { PDFDocument, rgb } from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';
// 获取PDF文档
const getPdfDoc = async () => {
// 获取PDF文档
const templateUrl = '/static/pdf/template.pdf';
const pdfResponse = await fetch(templateUrl)
const pdfBytes = new Uint8Array(await pdfResponse.arrayBuffer())
const pdfDoc = await PDFDocument.load(pdfBytes)
}
给PDF文档添加文本内容
可以通过获取PDF的表单,精确地的将表单数据插入到PDF的指定位置
const fillPdfDoc = (pdfDoc) => { const form = pdfDoc.getForm() // 获取所有字段,查看表单字段然后根据自己的表单数据,对应的字段插入进去 const fields = form.getFields() fields.forEach(field => { console.log('字段名称:', field.getName(), '类型:', field.constructor.name); }); const formData = {...} // 填充文本字段 if (formData.name) { form.getTextField('NameField').setText(formData.name); } // 填充邮箱字段 if (formData.email) { form.getTextField('EmailField').setText(formData.email); } return await pdfDoc.save(); }我这边的pdf文件获取不到表单,就选择了
在指定坐标位置添加文本const fillPdfDoc = (pdfDoc) => { const pages = pdfDoc.getPages() // 添加中文字体 const fontUrl = '/static/font/simsun.otf'; const fontResponse = await fetch(fontUrl); const fontBytes = await fontResponse.arrayBuffer(); pdfDoc.registerFontkit(fontkit); const chineseFont = await pdfDoc.embedFont(fontBytes); // 插入图片文件 const imageUrl = '/static/images/home.png' const imageRes = await fetch(imageUrl) const imageBytes = await imageRes.arrayBuffer() // 嵌入图片到PDF 图片是png格式,这里的方法是embedPng const image = await pdfDoc.embedPng(imageBytes); pages.forEach((page, pageIndex) => { page.drawImage(image, { x: 130, // 图片的x坐标 y: 346, // y坐标从页面底部计算 width: 90, // 图片宽度 height: 40, // 图片高度 }); page.drawText('文本内容', { x: 130, // 图片的x坐标 y: 346, // y坐标从页面底部计算 size: 10, // 字体大小 // 使用导入的字体文件能正确展示中文,遇到数字英文展示问题,可以不填font字段,用默认的 font: chineseFont, // 字体颜色,红色是rgb(1, 0, 0),不是css中的255,范围是0-1 color: rgb(0, 0, 0) }) // 如果不知道具体坐标是多少,可以写个算法把画一个网格线出来 addGridInPdf(page) }) return await pdfDoc.save(); } // 给PDF添加网格线 const addGridInPdf = async (page) => { // 添加网格线 const { width, height } = page.getSize(); for (let x = 0; x < width; x += 50) { page.drawLine({ start: { x, y: 0 }, end: { x, y: height }, thickness: 0.5, color: rgb(0.9, 0, 0), opacity: 0.5 }); page.drawText(x.toString(), { x: x + 2, y: 10, size: 8, color: rgb(0.9, 0, 0) }); } for (let y = 0; y < height; y += 50) { page.drawLine({ start: { x: 0, y }, end: { x: width, y }, thickness: 0.5, color: rgb(0, 0, 0.9), opacity: 0.5 }); page.drawText(y.toString(), { x: 2, y: y + 4, size: 8, color: rgb(0, 0, 0.9) }); } }
下载完成后的PDF文档
const newPdf = await fillPdfDoc(pdfDoc)
downloadPdf(newPdf, 'template.pdf')
// 下载PDF
const downLoadPdf = (pdfBytes, filename) => {
const blob = new Blob([pdfBytes], { type: 'application/pdf' })
const url = URL.createObjectURL(blob)
// #ifdef H5
localDownloadPdf(pdfBytes, filename) // 浏览器下载,测试用
// #endif
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
// 此时把文件上传给后端
}
},
fail: (err) => {
}
});
// 释放内存
setTimeout(() => {
URL.revokeObjectURL(url);
}, 100);
}
// 下载文件到浏览器中
const localDownloadPdf = async (pdfBytes, filename) => {
try {
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(() => {
URL.revokeObjectURL(url);
}, 100);
} catch (err) {
uni.showToast({
title: '本地浏览器文件下载失败',
icon: 'none'
})
}
}