前端使用vue-pdf、pdf-lib、canvas 给PDF文件添加水印,并预览与下载

这篇具有很好参考价值的文章主要介绍了前端使用vue-pdf、pdf-lib、canvas 给PDF文件添加水印,并预览与下载。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

效果预览

pdf-lib插件库,知识点(小记),工具,前端,vue.js,pdf

使用第三方插件

安装依赖插件

npm i vue-pdf --save
npm i pdf-lib --save
npm install --save @pdf-lib/fontkit  //为 pdf-lib 加载自定义字体的工具

import 导入依赖

import pdf from "vue-pdf";
import { degrees, PDFDocument, rgb, StandardFonts } from "pdf-lib";
import fontkit from "@pdf-lib/fontkit"; 

预览添加水印的pdf

setWatermarkContent() {
  let ele = document.createElement("canvas");
  ele.width = 250;
  ele.height = 200;
  let objmsg = {
    canvas: ele,
    fontText: "张三-2023-01-01",
    fontSize: 20,
    fontFamily: "microsoft yahei",
    fontcolor: "#dadbdc", //字体颜色   默认 #dadbdc
    rotate: 25, //旋转角度   数字类型
    textAlign: "left", //水印文字居中方式:left center right  默认 left
  };
  this.createWaterMark(objmsg);
  this.drawWaterMark(ele);
},
// 创建canvas水印图片
createWaterMark({ canvas, fontText, fontFamily = "microsoft yahei", fontSize = 30, fontcolor = "#dadbdc", rotate = 30, textAlign = "left" }) {
  let ctx = canvas.getContext("2d");
  ctx.font = `${fontSize}px ${fontFamily}`;
  ctx.rotate((-rotate * Math.PI) / 180);
  ctx.fillStyle = fontcolor;
  ctx.textAlign = textAlign;
  ctx.textBaseline = "Middle";
  ctx.fillText(fontText, canvas.width / 6, canvas.height / 2);
},
// 给pdf增加水印遮罩层
drawWaterMark(ele) {
  let div = document.createElement("div");
  div.style.pointerEvents = "none";
  div.style.top = "0";
  div.style.left = "0px";
  div.style.position = "absolute";
  div.style.background = "url(" + ele.toDataURL("image/png") + ") left top repeat";
  let width = document.getElementById("pdfBox").clientWidth || 700;
  let height = document.getElementById("pdfBox").clientHeight || 700;
  div.style.width = width + "px";
  div.style.height = height + "px";
  document.getElementById("myIframe").appendChild(div);
},

下载添加水印的pdf

原理就是给显示pdf 的容器增加一层水印遮罩层


// 处理PDF
async downFile() {
  /*2.获取pdf文件的arrarybuffer文件流
  可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
  可访问前端项目中的本地文件,不能直接访问服务器链接文件,会有跨域问题*/
  try {
    // 1.通过url获取pdf文件的arrarybuffer文件流
    const existingPdfBytes = await fetch(this.fileUrl).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("/fonts/SourceHanSansCN-Normal.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("张三-2023-01-01", {
            x: 230 * j,
            y: (height / 4) * i,
            size: 20,
            font: fontkitFile, //字体(内置/自定义)
            color: rgb(0.46, 0.53, 0.6),
            rotate: degrees(45),
            opacity: 0.3,
          });
        }
      }
    }
    //5. 保存pdf文件的unit64Arrary文件流
    const pdfBytes = await pdfDoc.save();
    this.saveByteArray(this.waterFile.fileName + ".pdf", pdfBytes);
  } catch (error) {
    this.$message.warning("文件下载失败!");
  }
},
// 下载文件
saveByteArray(reportName, byte) {
  var blob = new Blob([byte], { type: "application/pdf" });
  var link = document.createElement("a");
  link.href = window.URL.createObjectURL(blob);
  var fileName = reportName;
  link.download = fileName;
  link.click();
},

预览及下载总结

下载:

  1. 通过url获取pdf文件的arrarybuffer文件流
  2. 将arraybuffer数据转成pdf文档
  3. 添加水印字体(内置/自定义)
  4. 为每页pdf添加文字水印
  5. 保存pdf文件的unit64Arrary文件流

预览:文章来源地址https://www.toymoban.com/news/detail-819829.html

  1. 创建canvas容器(用于显示水印文字)
  2. 创建水印canvas
  3. 将水印canvas遮罩层定位到pdf容器中

完整代码

<template>
  <div>
    <div class="content">
      <div id="myIframe" style="max-width: 700px; min-height: 550px; position: relative; margin: 0 auto">
        <pdf id="pdfBox" :page="pageNum" :src="fileUrl" @progress="loadedRatio = $event" @num-pages="totalPages = $event"></pdf>
      </div>
      <el-button v-if="false" type="primary" @click="downFile" plain style="width: 300px">保存并下载pdf</el-button>
    </div>
    <span slot="footer" class="dialog-footer">
      <div class="btnGroup" v-if="totalPages">
        <div class="pageNum">{{ pageNum }} / {{ totalPages }}</div>
        <el-button-group>
          <el-button round plain type="primary" icon="el-icon-arrow-left" size="mini" @click="prePage">上一页</el-button>
          <el-button round plain type="primary" size="mini" @click="nextPage">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
        </el-button-group>
      </div>
    </span>
  </div>
</template>

<script>
/* npm i vue-pdf --save
npm install --save @pdf-lib/fontkit
npm i pdf-lib --save
*/

import pdf from "vue-pdf";
import { degrees, PDFDocument, rgb, StandardFonts } from "pdf-lib";
import fontkit from "@pdf-lib/fontkit"; //为 pdf-lib 加载自定义字体的工具

export default {
  components: {
    pdf,
  },
  data() {
    return {
      pageNum: 1, //显示第一页
      loadedRatio: 0, // 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了
      totalPages: 0, //pdf总页数
      fileUrl:"XXXXX.pdf",
    };
  },

  mounted() {
    this.getPageNum();
  },
  methods: {
   // 获取PDF总页数
    getPageNum() {
      let loadingTask = pdf.createLoadingTask(this.fileUrl);
      loadingTask.promise
        .then((pdf) => {
          this.totalPages = pdf.numPages;
          this.$nextTick(() => {
            this.setWatermarkContent();
          });
        })
        .catch((err) => {
          this.$message.warning("pdf加载失败");
        });
    },
    // 上一页
    prePage() {
      let page = this.pageNum;
      page = page > 1 ? page - 1 : this.totalPages;
      this.pageNum = page;
      window.scrollTo(0, 0);
    },

    // 下一页
    nextPage() {
      let page = this.pageNum;
      page = page < this.totalPages ? page + 1 : 1;
      this.pageNum = page;
      window.scrollTo(0, 0);
    },

    setWatermarkContent() {
      // 1.创建canvas容器(用于显示水印文字)
      let ele = document.createElement("canvas");
      ele.width = 250;
      ele.height = 200;
      let objmsg = {
        canvas: ele,
        fontText: "张三-2023-01-01", // String
        fontSize: 20,
        fontFamily: "microsoft yahei",
        fontcolor: "#dadbdc", //字体颜色   默认 #dadbdc
        rotate: 25, //旋转角度   数字类型
        textAlign: "left", //水印文字居中方式:left center right  默认 left
      };
      // 2.创建水印canvas
      this.createWaterMark(objmsg);
       // 2.将水印canvas遮罩层定位到pdf容器中
      this.drawWaterMark(ele);
    },
    // 创建canvas水印图片
    createWaterMark({ canvas, fontText, fontFamily = "microsoft yahei", fontSize = 30, fontcolor = "#dadbdc", rotate = 30, textAlign = "left" }) {
      let ctx = canvas.getContext("2d");
      ctx.font = `${fontSize}px ${fontFamily}`;
      ctx.rotate((-rotate * Math.PI) / 180);
      ctx.fillStyle = fontcolor;
      ctx.textAlign = textAlign;
      ctx.textBaseline = "Middle";
      ctx.fillText(fontText, canvas.width / 6, canvas.height / 2);
    },
    // 给pdf增加水印遮罩层
    drawWaterMark(ele) {
      let div = document.createElement("div");
      div.style.pointerEvents = "none";
      div.style.top = "0";
      div.style.left = "0px";
      div.style.position = "absolute";
      div.style.background = "url(" + ele.toDataURL("image/png") + ") left top repeat";
      let width = document.getElementById("pdfBox").clientWidth || 700;
      let height = document.getElementById("pdfBox").clientHeight || 700;
      div.style.width = width + "px";
      div.style.height = height + "px";
      document.getElementById("myIframe").appendChild(div);
    },

    // PDF 下载
    async downFile() {
      /*2.获取pdf文件的arrarybuffer文件流
       可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
       可访问前端项目中的本地文件,不能直接访问服务器链接文件,会有跨域问题*/
      try {
        // 1.通过url获取pdf文件的arrarybuffer文件流
        const existingPdfBytes = await fetch(this.fileUrl).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("/fonts/SourceHanSansCN-Normal.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('张三-2023-01-01', {
                x: 230 * j,
                y: (height / 4) * i,
                size: 20,
                font: fontkitFile, //字体(内置/自定义)
                color: rgb(0.46, 0.53, 0.6),
                rotate: degrees(45),
                opacity: 0.3,
              });
            }
          }
        }
        //5. 保存pdf文件的unit64Arrary文件流
        const pdfBytes = await pdfDoc.save();
        this.saveByteArray( "水印PDF.pdf", pdfBytes);
      } catch (error) {
        this.$message.warning("文件下载失败!");
      }
    },
    // 下载文件
    saveByteArray(fileName, byte) {
      var blob = new Blob([byte], { type: "application/pdf" });
      var link = document.createElement("a");
      link.href = window.URL.createObjectURL(blob);
      var fileName = reportName;
      link.download = fileName;
      link.click();
    },
  },
};
</script>

到了这里,关于前端使用vue-pdf、pdf-lib、canvas 给PDF文件添加水印,并预览与下载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【vue-pdf】PDF文件预览插件

    1 插件安装 vue-pdf GitHub:https://github.com/FranckFreiburger/vue-pdf#readme 参考文档:https://www.cnblogs.com/steamed-twisted-roll/p/9648255.html catch报错:vue-pdf组件报错vue-pdf Cannot read properties of undefined (reading ‘catch‘)_你看我像是会的样子吗?的博客-CSDN博客 2 代码示例 Example.01 超简单分页预览 E

    2024年02月14日
    浏览(76)
  • vue-pdf实现pdf文件在线预览

    在日常的工作中在线预览 PDF 文件的需求是很多的,下面介绍一下使用 vue-pdf 实现pdf文件在线预览 使用 npm 安装 vue-pdf npm install vue-pdf 使用 vue-pdf 显示 PDF 文件 此时页面中就会显示我们提供的 PDF 文件了,但是此时只显示了 PDF 文件的第一页 按页显示 PDF 文件 使用 vue-pdf 能满足

    2024年02月13日
    浏览(49)
  • 使用vue-pdf插件加载pdf

    安装: 使用: 报错:  这样执行会报一个catch的错误,然后找到node_modules下面的vue-pdf目录src文件下面的pdfjsWrapper.js文件中,第197行的catch注释掉就好。

    2024年01月18日
    浏览(48)
  • vue前端实现将页面显示内容生成pdf文件的几种方法,html2canvas、dom-to-image、jspdf(带分页)基本使用以及介绍

    实际开发需求:vue项目中,根据数据结构生成echarts图表组件,生成带有样式的图表以后,点击下载按钮,把图表以pdf格式的文件下载到本地 实现思路:将vue界面的echarts组件生成图片,然后使用插件将生成的图片放入pdf中,再实现pdf文件的下载 涉及框架以及插件:vue、echar

    2024年01月25日
    浏览(53)
  • vue中如何使用vue-pdf及相应报错解决

      目录 一、安装npm 依赖 二、引入组件 1、html中使用组件 单页 多页  2、数据处理 单页 多页  三、项目使用--代码部分 四、报错解决 前言 使用vue-pdf组件实现文件预览功能 并在文件上增加操作按钮 vue3不支持vue-pdf,vue3项目用pdfjs-dist   1、在根目录下输入一下命令 2、修改

    2023年04月12日
    浏览(37)
  • vue-pdf 单列显示多个pdf页面

    注意:文件要放在public文件夹下,不然会报错:如果文件放在远程服务器上,则直接写远程地址 Warning: Ignoring invalid character \\\"33\\\" in hex string\\\' 原因:读取 PDF 文件时,路径不合法,导致读取不到文件; 在 vue-cli3 脚手架搭建的项目中,读取本地的 PDF 文件需要放到 public 文件夹中

    2024年02月15日
    浏览(53)
  • 【vue2中的pdf预览】iframe/pdf.js/vue-pdf

    vue2中预览pdf的方法有pdf.js和vue-pdf等。下面进行简单对比使用方法的介绍。 使用iframe预览pdf 如果后端返回的不是url,那么需要使用 responseType = \\\'blob\\\' 来读取后端传来的内容。 扩展: 同样是使用iframe进行预览,如果有 其他格式 如word/xls/ppt/txt的文件需要预览,可以使用微软解

    2024年02月09日
    浏览(58)
  • Vue-pdf踩坑记录

    最近在公司的一个项目中,需要在线预览PDF文件。基于vue-admin-electron的模板中开发。开发机系统为Windows,使用的框架为electron-vue。 坑1:在通过vue-router路由到含有vue-pdf组件的页面时报:“syntaxError: Unexpected token ” 错误。 解决方法: 将vue-pdf添加到webpack配置文件的白名单中。

    2024年02月11日
    浏览(44)
  • 前端vue基于html2canva jspdf 实现前端页面加水印 并导出页面PDF

    随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。通过组件化开发,可以有效实现单独开发,单独维护,而且他们之间可以随

    2024年02月03日
    浏览(47)
  • Vue中 引入使用 patch-package 为依赖打补丁 (以修改 vue-pdf 打包后 [hash].worker.js 路径问题为例)

    1. patch-package 简介 patch-package npm地址 patch-package github文档 如果不需要在生产中运行 npm (如:正在制作 web 前端,则可使用 --save dev) 1.2 使用方法 制作修补程序 首先更改 node_modules 文件夹中特定包的文件,然后运行 或使用 npx (npm 5.2) package-name 与所更改的程序包的名称相匹配

    2024年02月10日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包