Demo: 实现PDF加水印以及自定义水印样式

实现PDF加水印以及自定义水印样式

javascript 复制代码
<template>
    <div>
        <button @click="previewHandle">预览</button>
        <button @click="downFileHandle">下载</button>
        <el-input v-model="watermarkText" />
        <el-input v-model.number="watermarkrotate" />
        <iframe id="log_frame" class="log-iframe" frameborder="0" :src="pdfPreviewUrl"></iframe>
    </div>
</template>
  
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { degrees, PDFDocument, rgb, StandardFonts } from "pdf-lib";
import fontkit from '@pdf-lib/fontkit'

const pdfFileEnd = ref('http://111.229.162.189:8003/file/construction/2024_01_08/三高共管对接接口(5)_14ba6d68.pdf')
const pdfPreviewBlob = ref()
const pdfPreviewUrl = ref('/pdf/web/viewer.html?file=http://111.229.162.189:8003/file/construction/2024_01_08/三高共管对接接口(5)_14ba6d68.pdf')

const watermarkText = ref('2024-01-17') // 水印文字
const watermarkrotate = ref(45) // 水印旋转角度

// PDF 下载
const addWatermark = async (rotate) => {
    /*2.获取pdf文件的arrarybuffer文件流
     可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
     可访问前端项目中的本地文件,不能直接访问服务器链接文件,会有跨域问题*/
    try {
        // 1.通过url获取pdf文件的arrarybuffer文件流
        const existingPdfBytes = await fetch(pdfFileEnd.value).then((res) => res.arrayBuffer());
        // 2.将arraybuffer数据转成pdf文档
        const pdfDoc = await PDFDocument.load(existingPdfBytes);
        // 3.1  内置字体(不支持中文), 如果水印中不包含中文可直接用内置字体(不支持中文)
        // const fontkitFile = await pdfDoc.embedFont(StandardFonts.Helvetica);
        // 3.2 自定义字体,如不需要使用自定义字体可以将这一段全部注释掉,也不用下载自定义字体文件和自定义字体工具fontkit
        // 将自己下载好的.ttf文件放置项目中,然后访问文件路径(不支持访问本地文件)
        // const fontBytes = await fetch("@/assets/DS-DIGIT.TTF").then((res) => res.arrayBuffer());
        // pdfDoc.registerFontkit(fontkit); // 自定义字体挂载、fontkit为自定义字体注册工具
        // const fontkitFile = await pdfDoc.embedFont(fontBytes);
        //  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(watermarkText.value, {
                        x: 230 * j + 36,
                        y: (height / 4) * i + 20,
                        size: 20,
                        // font: fontkitFile, //字体(内置/自定义)
                        color: rgb(0.46, 0.53, 0.6),
                        rotate: degrees(rotate),
                        opacity: 0.3,
                    });
                }
            }
        }
        //5. 保存pdf文件的unit64Arrary文件流
        const pdfBytes = await pdfDoc.save();
        pdfPreviewBlob.value = pdfBytes
        // const blob = new Blob([pdfBytes], { type: 'application/pdf' });
        // const url = window.URL.createObjectURL(blob);
        // pdfPreviewUrl.value = '/pdf/web/viewer.html?file=' + url
        // saveByteArray("水印PDF.pdf", pdfBytes);
    } catch (error) {
        console.log("文件下载失败!");
    }
}
// 预览文件
const previewHandle = async () => {
    console.log(typeof(watermarkrotate.value));
    await addWatermark(watermarkrotate.value)
    const blob = new Blob([pdfPreviewBlob.value], { type: 'application/pdf' });
    const url = window.URL.createObjectURL(blob);
    pdfPreviewUrl.value = '/pdf/web/viewer.html?file=' + url
}
// 下载文件
const downFileHandle = () => {
    var blob = new Blob([pdfPreviewBlob.value], { type: "application/pdf" });
    var link = document.createElement("a");
    link.href = window.URL.createObjectURL(blob);
    link.download = '水印pdf';
    link.click();
}

onMounted(() => {
    addWatermark()
})
</script>

<style lang="scss" scoped>
.log-iframe {
    width: 800px;
    height: 520px;
}
</style>
相关推荐
C_心欲无痕17 分钟前
nginx - alias 和 root 的区别详解
运维·前端·nginx
北辰alk29 分钟前
Vue 路由信息获取全攻略:8 种方法深度解析
vue.js
北辰alk34 分钟前
Vue 三剑客:组件、插件、插槽的深度辨析
vue.js
北辰alk41 分钟前
Vue Watch 立即执行:5 种初始化调用方案全解析
vue.js
北辰alk1 小时前
Vue 组件模板的 7 种定义方式:从基础到高级的完整指南
vue.js
北辰alk1 小时前
深入理解 Vue 生命周期:created 与 mounted 的核心差异与实战指南
vue.js
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue小型房屋租赁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
北辰alk1 小时前
Vuex日渐式微?状态管理的三大痛点与新时代方案
vue.js
我是苏苏2 小时前
Web开发:C#通过ProcessStartInfo动态调用执行Python脚本
java·服务器·前端