前端vue实现给pdf添加水印

该文章介绍了一个使用pdfjs-dist库在Vue.js应用中实现PDF文件的渲染,包括在每一页上添加水印的功能。作者提到需要特定版本的pdfjs-dist(2.6.347),并提供了Vue组件的代码示例,展示如何处理文件上传、PDF加载、页面渲染以及添加水印的过程。

实现效果:

实现原理:将PDF文件一页一页的渲染在画布上面,然后将水印文字也渲染在画布上面。

在网上也找了很多教程,自己试了一下,或多或少有点问题,最后结合了一下,做了些修改实现了。

 使用到的插件 pdfjs-dist,这个版本需要注意,太低或太高版本都不行。我最后选的是2.6.347,成功运行了。

package.json配置文件:

{
  "name": "pdf",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "pdfjs-dist": "^2.6.347",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "vue-template-compiler": "^2.6.14"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

vue代码:


<template>
  <div class="main-container">
    <input type="file" ref="fielinput" @change="uploadFile" />
    <div ref="canvasCont" class="canvas-container">
      <canvas ref="myCanvas" class="pdf-container"></canvas>
    </div>
    <div class="pagination-wrapper">
      <button @click="clickPre">上一页</button>
      <span>第{{ pageNo }} / {{ pdfPageNumber }}页</span>
      <button @click="clickNext">下一页</button>
    </div>
  </div>
</template>

<script>
const pdfJS = require("pdfjs-dist");

pdfJS.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/build/pdf.worker.entry");
export default {
  props: {
    watermark: {
      type: String,
      default: "水印文字",
    },
  },
  mounted() {},
  data() {
    return {
      pageNo: null,
      pdfPageNumber: null,
      renderingPage: false,
      pdfData: null, // PDF的base64
      scale: 1, // 缩放值
      width: "",
      height: "",
    };
  },
  methods: {
    uploadFile() {
      let inputDom = this.$refs.fielinput;
      let file = inputDom.files[0];
      let reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => {
        let data = atob(
          reader.result.substring(reader.result.indexOf(",") + 1)
        );
        this.loadPdfData(data);
      };
    },
    loadPdfData(data) {
      // 引入pdf.js的字体
      let CMAP_URL = "https://unpkg.com/pdfjs-dist@2.0.943/cmaps/";
      //读取base64的pdf流文件
      this.pdfData = pdfJS.getDocument({
        data: data, // PDF base64编码
        cMapUrl: CMAP_URL,
        cMapPacked: true,
      });
      console.log(this.pdfData);
      this.renderPage(1);
    },

    // 根据页码渲染相应的PDF
    renderPage(num) {
      this.renderingPage = true;
      this.pdfData.promise.then((pdf) => {
        this.pdfPageNumber = pdf.numPages;

        pdf.getPage(num).then((page) => {
          // 获取DOM中为预览PDF准备好的canvasDOM对象
          let canvas = this.$refs.myCanvas;
          let ctx = canvas.getContext("2d");

          // 获取页面比率
          let ratio = this._getRatio(ctx);

          // 根据页面宽度和视口宽度的比率就是内容区的放大比率
          let dialogWidth = this.$refs["canvasCont"].offsetWidth;
          let pageWidth = page.view[2] * ratio;
          let scale = dialogWidth / pageWidth;
          let viewport = page.getViewport({ scale });

          // 记录内容区宽高,后期添加水印时需要
          this.width = viewport.width * ratio;
          this.height = viewport.height * ratio;

          canvas.width = this.width;
          canvas.height = this.height;

          // 缩放比率
          ctx.setTransform(ratio, 0, 0, ratio, 0, 0);

          let renderContext = {
            canvasContext: ctx,
            viewport: viewport,
          };
          page.render(renderContext).promise.then(() => {
            this.renderingPage = false;
            this.pageNo = num;

            // 添加水印
            this._renderWatermark();
          });
        });
      });
    },
    // 计算角度
    _getRatio(ctx) {
      let dpr = window.devicePixelRatio || 1;
      let bsr =
        ctx.webkitBackingStorePixelRatio ||
        ctx.mozBackingStorePixelRatio ||
        ctx.msBackingStorePixelRatio ||
        ctx.oBackingStorePixelRatio ||
        ctx.backingStorePixelRatio ||
        1;
      return dpr / bsr;
    },

    // 在画布上渲染水印
    _renderWatermark() {
      let canvas = this.$refs.myCanvas;
      let ctx = canvas.getContext("2d");
      // 平铺水印
      let pattern = ctx.createPattern(this._initWatermark(), "repeat");
      ctx.rect(0, 0, this.width, this.height);
      ctx.fillStyle = pattern;
      ctx.fill();
    },

    // 生成水印图片
    _initWatermark() {
      let canvas = document.createElement("canvas");
      canvas.width = 200;
      canvas.height = 200;
      let ctx = canvas.getContext("2d");
      ctx.rotate((-18 * Math.PI) / 180);
      ctx.font = "14px Vedana";
      ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
      ctx.textAlign = "left";
      ctx.textBaseline = "middle";
      ctx.fillText(this.watermark, 50, 50);
      return canvas;
    },

    clickPre() {
      if (!this.renderingPage && this.pageNo && this.pageNo > 1) {
        this.renderPage(this.pageNo - 1);
      }
    },
    clickNext() {
      if (
        !this.renderingPage &&
        this.pdfPageNumber &&
        this.pageNo &&
        this.pageNo < this.pdfPageNumber
      ) {
        this.renderPage(this.pageNo + 1);
      }
    },
  },
};
</script>

<style scoped>
.main-container {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.canvas-container {
  width: 600px;
  height: 700px;
  border: 1px dashed black;
  position: relative;
  display: flex;
  justify-content: center;
}
.pdf-container {
  width: 100%;
  height: 100%;
}

.pagination-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

Vue应用中实现PDF预览并添加水印和加密功能,可以通过集成第三方库和自定义组件来实现。以下是实现的关键步骤和相关技术。 ### 1. PDF预览实现 Vue项目中可以使用`vue-pdf-embed`或`pdfjs-dist`库来实现PDF预览功能。`pdfjs`是Mozilla开发的开源PDF渲染引擎,支持在浏览器中直接显示PDF内容。 使用`vue-pdf-embed`的示例代码如下: ```vue <template> <div> <pdf :src="pdfUrl" /> </div> </template> <script> import pdf from 'vue-pdf' export default { components: { pdf }, data() { return { pdfUrl: 'https://example.com/sample.pdf' } } } </script> ``` ### 2. 添加水印 要在PDF添加水印,可以在PDF预览层上叠加一个包含水印文本或图片的`<div>`。通过CSS设置透明度、位置和层级,实现水印效果。 示例CSS代码: ```css .watermark { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0.3; font-size: 36px; color: #000; transform: rotate(-45deg); text-align: center; line-height: 100%; z-index: 10; } ``` 在Vue模板中添加水印层: ```vue <template> <div style="position: relative;"> <pdf :src="pdfUrl" /> <div class="watermark">Confidential</div> </div> </template> ``` ### 3. PDF加密功能 PDF加密可以通过后端服务或使用库如`pdf-lib`来实现。`pdf-lib`支持修改和加密PDF文件,但需要注意其性能限制和兼容性。 以下是一个简单的PDF加密示例(使用Node.js环境): ```javascript const { PDFDocument } from 'pdf-lib' const fs = require('fs') async function encryptPDF(inputPath, outputPath, userPassword, ownerPassword) { const pdfBytes = await fs.promises.readFile(inputPath) const pdfDoc = await PDFDocument.load(pdfBytes) const security = pdfDoc.context.obj({ Filter: 'Standard', V: 4, Length: 128, CF: { AuthEvent: 'DocOpen', CipherAlgorithm: 'AESV2', Length: 16, Recipient: 'User', }, StmF: 'StdCF', StrF: 'StdCF', U: 'UserPassword', P: -4, }) pdfDoc.catalog.set(PDFName.of('Encrypt'), security) const encryptedPdfBytes = await pdfDoc.save() await fs.promises.writeFile(outputPath, encryptedPdfBytes) } encryptPDF('input.pdf', 'output.pdf', 'user123', 'owner123') ``` ### 4. 安全性注意事项 - **加密强度**:确保使用强加密算法,如AES-256。 - **密码管理**:避免硬编码密码,建议通过用户输入动态设置。 - **前端限制**:由于浏览器安全限制,某些加密功能可能需要后端支持。 ### 相关问题 1. 如何在Vue实现PDF注释功能? 2. 有哪些支持水印和加密的PDF库? 3. 如何在Vue应用中集成PDF签名功能? 4. PDF加密的常见标准有哪些? 5. 如何在PDF预览时动态更改水印内容?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值