场景:前端下载 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>