场景:前端下载 pdf 文件的时候,需要加上水印,再反给用户下载
用到的库:pdf-lib
和 @pdf-lib/fontkit
一、引入pdf-lib插件
使用 cdn 引入 pdf-lib 包
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.14.1/pdf-lib.min.js"></script>
使用 cdn 引入自定义字体工具,因pdf-lib添加水印时默认不支持中文,所以必须自定义一个字体来显示中文水印
<script src="https://unpkg.com/@pdf-lib/fontkit/dist/fontkit.umd.js"></script>
引入文件下载工具,pdf添加水印后直接使用该工具下载
<script src="https://unpkg.com/downloadjs@1.4.7"></script>
二、 使用pdf-lib
index.js文件:
可直接粘贴下去测试,需要注意代码中的以下两个路径问题:
1. const url = './201805510.pdf'; 这个路径是你需要放在index.js同个项目中的pdf文件
2. const fonturl = './watermarkfont.ttf'; 这个路径是你需要放在index.js同个项目中的下载好的自定义字体文件路径
有vscode + live-server 条件的话,可通过以下方法运行这个pdf添加水印功能
创建一个project文件夹,将 index.js、pdf文件、自定义字体文件.ttf 放在该文件夹中,用vscode打开project文件夹,使用live-server运行该文件夹就能测试该pdf水印添加功能
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.14.1/pdf-lib.min.js"></script>
<script src="https://unpkg.com/@pdf-lib/fontkit/dist/fontkit.umd.js"></script>
<script src="https://unpkg.com/downloadjs@1.4.7"></script>
</head>
<style>
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
p {
font-family: helvetica;
font-size: 24px;
text-align: center;
margin: 25px;
}
.small {
font-family: helvetica;
font-size: 18px;
text-align: center;
margin: 25px;
}
button {
background-color: #008CBA;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
font-size: 16px;
}
</style>
<body>
<p>点击这个按钮通过<code>pdf-lib</code>给原来的pdf文件添加水印</p>
<button onclick="modify()">Modify PDF</button>
<p class="small">(点击后自动下载修改完成后的pdf文件)</p>
</body>
<script>
//1. 引入相关对象和方法
const { degrees, PDFDocument, rgb, StandardFonts } = PDFLib //引入PDFLib相关方法
const fontkit = window.fontkit; //引入自定义字体工具包
// pdf浏览
async function modify() {
/*2. 获取pdf文件的arrarybuffer文件流
可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
可访问前端项目中的本地文件
不能直接访问服务器链接文件,会有跨域问题*/
const url = './201805510.pdf';
const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer())
// 将arraybuffer数据转成pdf文档
const pdfDoc = await PDFDocument.load(existingPdfBytes)
//3. 自定义字体,如不需要使用自定义字体可以将这一段全部注释掉,也不用下载自定义字体文件和自定义字体工具fontkit
//将自己下载好的.ttf文件放置项目中,然后访问文件路径
const fonturl = './watermarkfont.ttf';
const fontBytes = await fetch(fonturl).then((res) => res.arrayBuffer());
// 自定义字体挂载、fontkit为自定义字体注册工具
pdfDoc.registerFontkit(fontkit)
const customFont = await pdfDoc.embedFont(fontBytes)
// 内置字体(不支持中文), 如果水印中不包含中文可直接用内置字体,本次这里没用到内置字体
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
//4. 添加水印
//为每页pdf添加文字水印
const pages = pdfDoc.getPages()
for (let i = 0; i < pages.length; i++) {
const noPage = pages[i]
const { width, height } = noPage.getSize()
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 3; j++) {
noPage.drawText('水印', {
x: 230 * j,
y: (height / 4) * i,
size: 16,
font: customFont, //这里使用的是自定义字体
//使用上面定义好的内置字体 font:helveticaFont
color: rgb(0.46, 0.53, 0.6),
rotate: degrees(45),
opacity: 0.3,
})
}
}
}
//5. 保存pdf文件的unit64Arrary文件流
const pdfBytes = await pdfDoc.save();
download(pdfBytes, 'test.pdf', "application/pdf"); //下载带水印的pdf
//6. 新标签页预览、打印
let blobData = new Blob([pdfBytes], { type: "application/pdf;Base64" });
let a = document.createElement("a");
a.target = "_blank";
a.href = window.URL.createObjectURL(blobData);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
</script>
</html>