PDF文件实现在线盖章

需求:需要实现给预览的PDF文件,盖上电子印章

🌼 🌼 实现效果:(注:pdf文件资源和图片资源都是网上获取到的)

安装插件

npm install pdfjs-dist --save

引入

import PDFJS from 'pdfjs-dist';

PDFJS.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker.js';

这两个文件包含了获取、解析和展示PDF文档的方法,但是解析和渲染PDF需要较长的时间,可能会阻塞其它JS代码的运行。

PDF.js的API都会返回一个Promise,使得我们可以优雅的处理异步操作。

如果引入报错

修改参考:关于前端PDF显示和盖章(vue)_Harrietjia的博客-CSDN博客PDFhttps://www.jianshu.com/p/94cf6ddcb299https://segmentfault.com/a/1190000016963084https://blog.csdn.net/qq_38188485/article/details/104452542

使用canvas当作为预览pdf文件的画布

<div id="pdf-container" class="center"></div>

渲染PDF文件(一次渲染文件的所有页)

initPdf(flag) {
      let vm = this;
      var val = vm.pdfurl;
      if (val === '' || val === undefined) return;
      // 用于异步获取PDf文档,发送多个Ajax请求以块的形式下载文档。它返回一个Promise,该Promise的成功回调传递一个对象,该对象包含PDF文档的信息,该回调中的代码将在完成PDf文档获取时执行。
      PDFJS.getDocument(val)
        .then(function(pdfDoc_) {
          // 初始化pdf
          vm.pdfDoc = pdfDoc_;
          vm.pageCount = vm.pdfDoc.numPages;
          // 根据页码创建画布
          let id = '';
          let idTemplate = 'cw-pdf-';
          if (flag === 'init') {
            vm.createSeriesCanvas(vm.pdfDoc.numPages, idTemplate);
          }
          // 将pdf渲染到画布上去
          for (var i = 1; i <= vm.pdfDoc.numPages; i++) {
            id = idTemplate + i;
            vm.renderPDF(vm.pdfDoc, i, id);
          }
        })
        .catch(function(err) {
          if (err) {
            console.log(err);
            vm.throwerr(vm.pdfurl);
          }
        });
    },
    renderPDF(pdf, i, id) {
      let vm = this;
      pdf.getPage(i).then(function(page) {
        //  准备用于渲染的 canvas 元素
        var canvas = document.getElementById(id);
        var context = canvas.getContext('2d');
        var viewport = page.getViewport(vm.compuscale, vm.leftrotate);
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        // 将 PDF 页面渲染到 canvas 上下文中
        var renderContext = {
          canvasContext: context,
          viewport: viewport
        };
        page.render(renderContext);
      });
    },
    createSeriesCanvas(num, template) {
      var id = '';
      for (var j = 1; j <= num; j++) {
        id = template + j;
        this.createPdfContainer(id, 'canvasstyle');
      }
    },
    createPdfContainer(id, className) {
      var pdfContainer = document.getElementById('pdf-container');
      var divNew = document.createElement('div');
      var canvasNew = document.createElement('canvas');
      divNew.id = 'div-' + id;
      canvasNew.id = id;
      canvasNew.className = className;
      divNew.appendChild(canvasNew);
      pdfContainer.appendChild(divNew);
    },

getPage():用于获取PDF文档中的各个页面。

getViewport():针对提供的展示比例,返回PDf文档的页面尺寸。

render():渲染PDF。

此时pdf文件就可以基本显示了。

之后实现印章的拖拽功能。

基本思路:我们在点击印章的时候,(鼠标按下)新创建一个和印章一模一样的节点(可以是克隆)并添加在pdf容器内(也就是作为pdf容器的子节点),之后移动鼠标(拖拽),移动的是这个新克隆出来的节点,此时根据移动的位置,给该信节点设置定位的像素值,鼠标抬起,取消鼠标移动事件。每个已经拖拽过去的印章还得支持改变位置,所以每个新戈隆的节点,需要添加对应的事件;每个拖拽的印章还需要计算边界值。

数据源data:

data() {
    return {
      cloneDragSeal: null,
      draggedSeal: null,
      scrollTop: 0,
      dragSealList: null,
      sealList: [
        {
          url: require('../../../assets/images/yinzhang1.png'),
          id: 'seal1'
        },
        {
          url: require('../../../assets/images/yinzhang2.png'),
          id: 'seal2'
        }
      ],
      pdfurl:
        'https://dakaname.oss-cn-hangzhou.aliyuncs.com/file/2018-12-28/1546003237411.pdf', // pdf链接地址
      pdfDoc: null, // pdfjs 生成的对象
      pageNum: 1, //
      pageRendering: false,
      pageNumPending: null,
      compuscale: 1, // 放大倍数
      leftrotate: 0,
      scale: 1.6, // 放大倍数  相当于初始倍数
      pageNumC: 0, // 当前页数
      pageCount: 0, // 总页数
      gotopageNum: '', // 跳转到指定的页面
      // maxscale: 2, //最大放大倍数
      // minscale: 0.8, //最小放大倍数
      isready: false
    };
  },

印章渲染:

 <div class="side-bar">
        <h2>推拽章的信息</h2>
        <div class="side-barinfo">
          <!-- <div class="sign-img" @mousedown="signPic" @mouseup="removeSignPic"> -->
          <div style="display: flex; justify-content: space-around">
            <div
              ><div
                v-for="item in sealList"
                :key="item.id"
                class="drag_seal"
                style="width: 100px; height: 100px"
                :sealId="item.id"
              >
                <img
                  :src="item.url"
                  alt=""
                  style="width: 100px; height: 100px"
                />
                <!-- img的鼠标按按下  事件失效 覆盖一个div -->
                <!-- <div class="seal_img_copy"></div> -->
                <!-- <i class="el-icon-close"></i> -->
              </div></div
            >
            
          </div>
        </div>
      </div>

给印章添加事件

let bgDom = document.getElementsByClassName('bg_mask')[0];
bgDom.addEventListener('scroll', this.scrollFn);

    sealAddEvent() {
      this.dragSealList = document.getElementsByClassName('drag_seal');
      [...this.dragSealList].forEach((item) => {
        // console.log(item.getAttribute('sealId'),'item');
        item.addEventListener('mousedown', (e) => {
          this.itemMouseDownFn({ e: e, id: item.getAttribute('sealId') });
        });
        // item.addEventListener('mouseup', (e) => {
        //   this.itemMouseupFn({ e: e, id: item.getAttribute('sealId') });
        // });
      });
    },

事件函数定义

itemMouseupFn(e) {
      if (!this.cloneDragSeal) {
        return false;
      }
      document.removeEventListener('mousemove', this.signmouseMve, false);
      let pdfContainer = document.getElementById('pdf-container');
      // 找边界值
      let left = this.cloneDragSeal.style.left.replace('px', '');
      if (
        left < 0 ||
        e.clientX > pdfContainer.offsetLeft + pdfContainer.clientWidth
      ) {
        this.cloneDragSeal && pdfContainer.removeChild(this.cloneDragSeal);
      }
      this.cloneDragSeal = null;
    },
    draggedSealOverFn(e) {
      let nextSibling = e.target.nextSibling;
      if (nextSibling) nextSibling.style.display = '';
    },
    draggedSealOutFn(e) {
      let nextSibling = e.target.nextSibling;
      if (nextSibling) nextSibling.style.display = 'none';
    },
    draggedSealUpFn(e) {
      if (!this.draggedSeal) {
        return false;
      }
      document.removeEventListener('mousemove', this.draggedSealMove, false);
      let pdfContainer = document.getElementById('pdf-container');
      // 找边界值
      let left = this.draggedSeal.style.left.replace('px', '');
      if (
        left < 0 ||
        e.clientX > pdfContainer.offsetLeft + pdfContainer.clientWidth
      ) {
        this.draggedSeal && pdfContainer.removeChild(this.draggedSeal);
      }
      this.draggedSeal = null;
    },
    draggedSealDownFn(e) {
      this.draggedSeal = e.target.parentNode;
      console.log('draggedSealDownFn', e.target.parentNode);
      document.addEventListener('mousemove', this.draggedSealMove, false);
    },
    // 已经拖拽过去的印章 移动事件
    draggedSealMove(e) {
      e.preventDefault();
      let pdfContainer = document.getElementById('pdf-container');
      this.draggedSeal.style.position = 'absolute';
      // this.draggedSeal.style.top =
      //   ((e.clientY -
      //     pdfContainer.offsetTop -
      //     this.draggedSeal.clientHeight / 2 +
      //     this.scrollTop -
      //     108) /
      //     pdfContainer.clientHeight) *
      //     100 +
      //   '%';
      this.draggedSeal.style.top =
        e.clientY -
        pdfContainer.offsetTop -
        this.draggedSeal.clientHeight / 2 -
        108 +
        this.scrollTop +
        'px';
      this.draggedSeal.style.left =
        e.clientX -
        pdfContainer.offsetLeft -
        this.draggedSeal.clientWidth / 2 +
        'px';
    },
    // 待拖拽印章的  鼠标按下事件函数
    itemMouseDownFn(obj) {
      console.log('按下');
      let e = obj.e || window.event;
      e.preventDefault();
      // 鼠标 按下 开始移动
      // 1、原印章不变  新创建一个印章(克隆)
      this.cloneDragSeal = e.currentTarget.cloneNode(true);
      let delBtn = document.createElement('div');
      delBtn.innerText = 'X';
      delBtn.style.position = 'absolute';
      delBtn.style.top = 0;
      delBtn.style.right = 0;
      delBtn.style.display = 'none';
      delBtn.addEventListener('click', this.sealDelFn);

      this.cloneDragSeal.appendChild(delBtn);
      this.cloneDragSeal.addEventListener('mousedown', this.draggedSealDownFn);
      this.cloneDragSeal.addEventListener('mouseup', this.draggedSealUpFn);
      this.cloneDragSeal.addEventListener('mouseover', this.draggedSealOverFn);
      this.cloneDragSeal.addEventListener('mouseout', this.draggedSealOutFn);
      let pdfContainer = document.getElementById('pdf-container');
      this.cloneDragSeal.className = 'dragged_seal';
      pdfContainer.appendChild(this.cloneDragSeal);
      document.addEventListener('mousemove', this.signmouseMve, false);
      document.addEventListener('mouseup', this.itemMouseupFn, false);
    },
    scrollFn(e) {
      this.scrollTop = e.target.scrollTop;
    },
    signmouseMve(e) {
      // let e = e || window.event;
      e.preventDefault();
      let pdfContainer = document.getElementById('pdf-container');

      this.cloneDragSeal.style.position = 'absolute';
      // left:  鼠标点击位置 - 当前页码pdf的offsetLeft
      // top:  鼠标点击位置 - header
      this.cloneDragSeal.style.top =
        e.clientY -
        pdfContainer.offsetTop -
        this.cloneDragSeal.clientHeight / 2 -
        108 +
        this.scrollTop +
        'px';
    },

至于和后端交互上的设计,还在实验中,请稍后。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Vue.js 是一个流行的前端框架,可以很好地与其他库和工具集成。实现 PDF 盖章需要使用一些专门的库和工具,如 pdf-lib、qrcode 和 Canvas 等。 具体实现步骤如下: 1. 使用 pdf-lib 库打开要盖章PDF 文件。 2. 在页面上添加一个 Canvas 元素,并使用 qrcode 库生成二维码图片。 3. 在 Canvas 上绘制二维码图片和要盖章的图标。 4. 将 Canvas 转换为图像,并将其插入到 PDF 中。 5. 将 PDF 保存到本地或上传到服务器。 下面是一个简单的示例代码,用于演示如何在 Vue.js实现 PDF 盖章功能: ``` <template> <div> <canvas ref="canvas"></canvas> <button @click="addStamp">Add Stamp</button> <button @click="savePDF">Save PDF</button> </div> </template> <script> import { PDFDocument } from 'pdf-lib' import QRCode from 'qrcode' export default { data() { return { pdf: null, image: null, qrCode: null, stampWidth: 50, stampHeight: 50, stampX: 100, stampY: 100 } }, async mounted() { // Load the PDF file const pdfUrl = 'example.pdf' const response = await fetch(pdfUrl) const arrayBuffer = await response.arrayBuffer() this.pdf = await PDFDocument.load(arrayBuffer) // Load the image file const imageUrl = 'stamp.png' const imageResponse = await fetch(imageUrl) const imageArrayBuffer = await imageResponse.arrayBuffer() this.image = await this.pdf.embedPng(imageArrayBuffer) // Generate the QR code this.qrCode = await QRCode.toDataURL('https://example.com') }, methods: { async addStamp() { // Create a new page const page = this.pdf.addPage() // Draw the stamp image const stamp = page.drawImage(this.image, { x: this.stampX, y: this.stampY, width: this.stampWidth, height: this.stampHeight }) // Draw the QR code const canvas = this.$refs.canvas const context = canvas.getContext('2d') const img = new Image() img.src = this.qrCode img.onload = function() { context.drawImage(img, 0, 0, canvas.width, canvas.height) const imageData = canvas.toDataURL('image/png') const pngImage = this.pdf.embedPng(imageData) page.drawImage(pngImage, { x: this.stampX + this.stampWidth + 10, y: this.stampY + (this.stampHeight - pngImage.height), width: pngImage.width, height: pngImage.height }) }.bind(this) }, async savePDF() { const pdfBytes = await this.pdf.save() const blob = new Blob([pdfBytes], { type: 'application/pdf' }) const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = 'stamped.pdf' document.body.appendChild(link) link.click() document.body.removeChild(link) } } } </script> ``` 相关问题: 1. 如何在 Vue.js 中生成二维码图片? 2. 如何在 Canvas 上绘制图像? 3. 如何将 Canvas 转换为图像,并将其插入到 PDF 中? 4. 如何将 PDF 文件保存到本地或上传到服务器?

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值