前言 纯前端实现对上传的pdf,进行盖章或签名后,并将处理后的pdf下载下来 目标

1 实现pdf上传与预览 2 手动签名,签名与印章的拖拽移动,实现在pdf上盖章与签名的效果 3 将盖章或签名的pdf文件进行绘制与下载

实现效果展示 mnggiflab-compressed-mnggiflab-video-to-gif (4).gif

所用的第三方依赖

  1. pdfh5 实现pdf文件的在线预览
  2. vue-esign 在画布上面签名,生成签名图片
  3. html2canvas html绘制图片
  4. jspdf 生成pdf、下载pdf

大致的逻辑 盖章与签名以图片的形式在pdf预览上进行拖拽,拖拽到pdf上 将拖拽的图片dragImg放到pdfViewer下,循环pdfViewer下的元素如果有dragImg

文件目录 image.png

DragImg组件:主要是实现图片的拖拽效果 inedx主文件:文件的上传预览等 SignImg组件:签名组件

接下来,一步一步去实现我们所需的效果

1 pdf文件上传

el-upload实现上传并监听before-upload事件,在before-upload事件中限制文件大小、格式、类型等,若文件符合使用FileReader()方法将文件转化为Base64,url接收Base64数据(本文用的是Base64实现文预览效果)。 若你想pdf5中使用地址方式,可以在上传成功之后将文件下载到项目的对应位置,并将地址信息保存在url属性中。

2 pdf在线预览

安装

npm i pdfh5 -S

引入

import Pdfh5 from "pdfh5" import "pdfh5/css/pdfh5.css"

使用

// 将pdf展示在id为preViewPdf的标签中
// pdfurl可以是文件地址,也可以是Base64(本文使用Base64)
this.pdfh5 = new Pdfh5('#preViewPdf', {
        pdfurl: url, // '../../static/test.pdf'文件地址 或 Base64
        maxZoom: 1, // 手势缩放最大倍数
        // lazy:true,
        // scrollEnable:true
})

其它可参考pdf5说明文档<https://www.npmjs.com/package/pdfh5>

3 手动签名

将签名封装到==SignImg==组件中 安装

npm i vue-esign -S

引入

import vueEsign from 'vue-esign'
components: {vueEsign}

使用vue-esign生成签名照 使用了<vueEsign></<vueEsign>标签来调用 vue-esign 插件,并通过设置 widthheight 属性来自定义签字区域的大小。isCrop设置是否裁剪,lineWidth 画笔粗细,lineColor 画笔颜色。

<vueEsign ref="esign" style="width: 100%!important;height:83vh !important;margin-left: -0.3rem;" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" :bgColor.sync="bgColor" >
</vueEsign>

签名完成通过handleGenerate方法将签名转化为图片

    <el-button type="primary" @click="handleGenerate">确定签名</el-button>
    //生成签名图片..
    handleGenerate() {
      this.$refs.esign.generate().then(res => {
        // res是一个图片的Base64格式
        this.handleReset(); //清空画布
        /**
           业务逻辑
        **
      }).catch(err => {
        console.log(err)
        alert("请签名之后提交");
      })
    }

最终效果 image.png

上传印章盖章以及签名照片的对象都是图片,通过拖拽图片从而实现pdf的签名与盖章效果。 以下就不再对以上操作进行一一的详细展示,仅对说明如何实现图片拖拽效果

4 拖拽效果

封装一个DragImg拖拽组件,将签名图片以及电子印章图片都放在这个组件中,从而实现签名与印章在pdf中的拖拽效果。 自定义拖拽指令drag 父元素绑定自定义指令,子元素展示图片 组件中的元素使用的是相对于父元素的绝对定位

 <div v-drag="{ that }" onclick="" style="width: 100%;height: 100%;position: absolute;">
     <img :class="'imgType_' + imgType" style="width: 100%;" :src="imgSrc" />
 </div>
  props: {
    imgData: {
      type: String,
      default: ''
    },
    // ...一些其他辅助参数或方法
    // 禁止拖拽方法
    pauseHandle:{
      type: Function,
      value: null,
    }
  },
 directives: {
    // 自定义指令
    drag: {
      bind: function (el, binding) {
        let oDiv = el;   //当前元素
        let that = binding.value.that;
        oDiv.onmousedown = function (e) {
          e.preventDefault();
          // 下载过程中禁止拖拽
          const isPause = that.pauseHandle() || false
          if(isPause) return
          let bw = document.body.clientWidth;
          let bh = document.body.clientHeight;
          //鼠标按下,计算当前元素距离可视区的距离
          let disX = e.clientX - oDiv.offsetLeft;
          let disY = e.clientY - oDiv.offsetTop;
          // 计算两边坐标
          document.onmousemove = function (e) {
            let l = 0, t = 0;
            // 拖动边界
            if (e.clientX >= bw) {
              l = bw - disX;
            } else if (e.clientX <= 0) {
              {
                l = 0 - disX;
              }
            } else {
              l = e.clientX - disX;
            }
            if (e.clientY >= bh) {
              t = bh - disY;
            } else if (e.clientY <= 0) {
              t = 0 - disY;
            } else {
              t = e.clientY - disY;
            }
            //移动当前元素
            oDiv.style.left = l + 'px';
            oDiv.style.top = t + 'px';
          };
          // 鼠标停止移动时,事件移除
          document.onmouseup = function (e) {
            document.onmousemove = null;
            document.onmouseup = null;
          };
        };
      }
    }
  },

5 pdf下载

会用到的第三放插件是JsPDFhtml2canvas 在下载之前,先大致讲一下盖章与签字到pdf上的处理逻辑 1 将dragImg放到.pdfViewer元素下,通过循环查询.pdfViewer下的元素当className == 'dragImg'。 根据dragImg.style.top - pdfViewer.style.top,计算图片应插入第几页,修改dragImg绝对定位后将dragImg插入相对应的.pageContainer元素下。签名或者印章在对应的页面中。 2 html2canvas将每一页绘制成图片,通过addPage创建空白页与addImage添加图片,实现pdf的生成。 3 PDF.save()下载生成的pdf。 先说明一下 一会儿会用到的几个元素的id

.pdfViewer 存放整个pdf .pageContainer pdf中的一页(多页就多个兄弟pageContainer) .dragImg 是你拖拽的签名或者印章图

创建印章并拖拽

let scrollt = document.querySelector(".pdfViewer").parentElement.parentElement.scrollTop;
var dragImg = Vue.extend(DragImg);
const app = new dragImg({
    propsData: {
          deleteDragImg: this.deleteDragImg, // 删除图片方法
          imgData: imgData || this.signImgBase64, // 图片的Base64
          isReuse: isReuse,
          top: scrollt, //距离顶部的距离
          imgType: type,
          pauseHandle:this.pauseHandle // 是否禁用拖拽方法
        },
    ref: 'a'
}).$mount(document.createElement('div'));
      // this.pdfh5 当前预览pdf
      let currentNum = parseInt(this.pdfh5.pageNow[0].innerText);
      this.pdfh5.pages[this.pdfh5.currentNum - 1].appendChild(app.$el)
      this.pdfh5.pages[currentNum - 1].appendChild(app.$el)
      // 将图片插入到.pdfViewer下
      document.querySelector(".pdfViewer").appendChild(app.$el)
    }

image.png 将签名或者印章方法对应的页面中

    // 页面中有样式名为dragImg的,代表该页面有签名或者签章
          // 有签名或签章就绘制页面
          if (parentElement[i].className == 'dragImg') {
            const promise = new Promise((resolve, reject) => {
              let html = parentElement[i]
              let ele = html.querySelector('#pic')
              let eleImg = html.querySelector('#pic div')
              let top = ele.style.top ? ele.style.top.split('px')[0] - 0 : 0
              let topImg = eleImg.style.top ? eleImg.style.top.split('px')[0] - 0 : 0
              let currentTop = top + topImg
              if (currentTop > baseNum) {
                console.log('第二页及以上')
                let j = Math.ceil(currentTop / baseNum)
                let pageContainer = document.querySelector(".pdfViewer .pageContainer" + j)
                html.style.top = 0
                ele.style.top = 0
                eleImg.style.top = currentTop - baseNum * (j - 1) + 'px'
                // 插入到对应页面中
                pageContainer.appendChild(html)
                resolve()
              } else {
                console.log('第一页')
                let pageContainer = document.querySelector(".pdfViewer .pageContainer1")
                pageContainer.appendChild(html)
                resolve()
              }
            })
// 绘制图片
html2canvas(parent.children[i])
    .then(function (canvas) {
         // 绘制.pageContainer元素
         if (parent.children[i].className != 'dragImg') {
                let url = canvas.toDataURL();
                let contentWidth = canvas.width
                let contentHeight = canvas.height
                let pageHeight = (contentWidth / 592.28) * 841.89
                let leftHeight = contentHeight
                let position = 0
                let imgWidth = 595.28
                let imgHeight = (592.28 / contentWidth) * contentHeight
                let pageData = canvas.toDataURL('image/jpeg', 1.0)
                // 第二页及以上
                if (i != 0) PDF.addPage() // 添加空白页
                if (leftHeight < pageHeight) {
                  PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight) //插入图片
                } else {
                  if (leftHeight > 0) {
                    PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) //插入图片
                    leftHeight -= pageHeight
                    position -= 841.89
                  }
                }
              }
              if (length - 1 == i) {
                setTimeout(()=>{
                  that.loading = false
                  // pdf下载
                  PDF.save(new Date().getTime() + '.pdf')
                },1000)
              }
            });

完整代码下载地址: <https://download.csdn.net/download/weixin_45291798/88580529?spm=1001.2014.3001.5503>

其他

​依赖安装报错解决 ​​8e0cc911f0554beaa033f58970dc9ab1.png

 npm install canvas@2.8.0 --ignore-scripts

只执行npm install canvas会报新的错误