vue 中利用canvas 给pdf文件加水印---详细教程(附上完整代码)

需求:在h5网页中打开pdf文件,要求给文件添加水印

实现技术及插件:vue,vue-pdf,canvas

插件安装:

npm i vue-pdf --save
npm i pdf-lib --save

原理:实现pdf预览,在显示pdf的容器上添加一层遮罩,用来存放水印

具体实现代码详细介绍:

<template>
    <div>
      <div class="content">
        <div id="myIframe" style="max-width: 1700px; min-height: 1550px; position: relative; margin: 0 auto">
          <pdf id="pdfBox" :page="pageNum" :src="fileUrl" @progress="loadedRatio = $event" @num-pages="totalPages = $event"></pdf>
        </div>
      </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>

相关解释:

         :page 从第几页开始显示

         :src:pdf存放路径

         @progress文档加载进度。范围[0,1]

         @num-pages给定pdf中所有页面的总和

        有可能会报的错误提示pdf打不开,报如下问题:

Warning: getHexString - ignoring invalid character: 33
Warning: getHexString - ignoring invalid character: 79
Warning: getHexString - ignoring invalid character: 84
Warning: getHexString - ignoring invalid character: 89
Warning: getHexString - ignoring invalid character: 80
             Warning: getHexString - ignoring additional invalid characters.

需要注意,在vue项目中,读取本地的pdf文件需要放到public下static文件夹中,不能放在别的地方,引用的方式也有讲究,具体看这篇文章:

vue中本地pdf文件加载错误,文件不显示_vue-pdf 不显示_生活的小欢呼的博客-CSDN博客

pdf预览相关方法:

    // 获取PDF总页数
      getPageNum() {
        let loadingTask = pdf.createLoadingTask(this.fileUrl);
        loadingTask.promise
          .then((pdf) => {
            this.totalPages = pdf.numPages;
            console.log(this.totalPages)
            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 str ="测试水印"
        let ctx = ele.getContext("2d");//绘制2d图形
        ctx.font = `${20}px ${"microsoft yahei"}` // 设置水印文字的大小和字体
        ctx.rotate((-25 * Math.PI) / 180);// 设置水印元素的倾斜, 这一行代码要写在设置水印文字之前,涉及样式的都写在设置水印文字之前
        ctx.fillStyle = "#dadbdc" // 设置水印文字的颜色
        ctx.textAlign = 'left'; // 文本左对齐
        ctx.fillText(str, ele.width / 6, ele.height / 2);// 设置水印文字
         
        // 2.将水印canvas遮罩层作为背景图,添加到div中
        let div = document.createElement("div");
        div.style.pointerEvents = "none";// 元素永远不会成为鼠标事件的target
        div.style.top = "0";
        div.style.left = "0px";
        div.style.position = "fixed";// 固定定位, 让元素撑满整个可视区域
        div.style.background = "url(" + ele.toDataURL("image/png") + ") left top repeat";// 水印图片做div的背景,并且重复,这样看起来就是满屏都是水印
        let width = document.getElementById("pdfBox").clientWidth ; //设置div的宽高
        let height = document.getElementById("pdfBox").clientHeight;
        div.style.width = width + "px";
        div.style.height = height + "px";
        div.style.zIndex = 999999 // 水印元素的权值设得大一些,以此来遮盖所有的元素
        
        // 3.div添加到body元素,水印生成
        document.getElementById("myPdf").appendChild(div);
      }

补充:直接覆盖上去,就类似于添加了一个蒙版,因此是无法触发底下图层的事件的,所以就用到了一个css属性pointer-events

pointer-events:none的作用不只是禁用链接hover,打开链接等效果,是真实意义上的将onlick事件去掉了,能让元素实体虚化,虽然存在这个元素,但是该元素不会触发鼠标事件。

完整代码:

<template>
    <div>
      <div class="content">
        <div id="myPdf" style="max-width: 1700px; min-height: 1550px; position: relative; margin: 0 auto">
          <pdf id="pdfBox" :page="pageNum" :src="fileUrl" @progress="loadedRatio = $event" @num-pages="totalPages = $event"></pdf>
        </div>
      </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>
  
  import pdf from "vue-pdf";
  
  export default {
    components: {
      pdf,
    },
    data() {
      return {
        pageNum: 1, //显示第一页
        loadedRatio: 0, // 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了
        totalPages: 0, //pdf总页数
        fileUrl:"/static/solr高级篇(上).pdf",
      };
    },
  
    mounted() {
      this.getPageNum();
    },
    methods: {
     // 获取PDF总页数
      getPageNum() {
        let loadingTask = pdf.createLoadingTask(this.fileUrl);
        loadingTask.promise
          .then((pdf) => {
            this.totalPages = pdf.numPages;
            console.log(this.totalPages)
            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 str ="测试水印"
        let ctx = ele.getContext("2d");//绘制2d图形
        ctx.font = `${20}px ${"microsoft yahei"}` // 设置水印文字的大小和字体
        ctx.rotate((-25 * Math.PI) / 180);// 设置水印元素的倾斜, 这一行代码要写在设置水印文字之前,涉及样式的都写在设置水印文字之前
        ctx.fillStyle = "#dadbdc" // 设置水印文字的颜色
        ctx.textAlign = 'left'; // 文本左对齐
        ctx.fillText(str, ele.width / 6, ele.height / 2);// 设置水印文字
         
        // 2.将水印canvas遮罩层作为背景图,添加到div中
        let div = document.createElement("div");
        div.style.pointerEvents = "none";// 元素永远不会成为鼠标事件的target
        div.style.top = "0";
        div.style.left = "0px";
        div.style.position = "fixed";// 固定定位, 让元素撑满整个可视区域
        div.style.background = "url(" + ele.toDataURL("image/png") + ") left top repeat";// 水印图片做div的背景,并且重复,这样看起来就是满屏都是水印
        let width = document.getElementById("pdfBox").clientWidth ; //设置div的宽高
        let height = document.getElementById("pdfBox").clientHeight;
        div.style.width = width + "px";
        div.style.height = height + "px";
        div.style.zIndex = 999999 // 水印元素的权值设得大一些,以此来遮盖所有的元素
        
        // 3.div添加到body元素,水印生成
        document.getElementById("myPdf").appendChild(div);
      },
    },
  };
  </script>
  

效果展示:

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿土不土

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值