使用pdf-lib.js实现pdf添加自定义水印功能

 更新时间:2024年11月14日 15:20:38   作者:忠实米线  
pdf-lib是一个强大的JavaScript库,允许在任何JavaScript环境中创建和修改PDF文档,下面就跟随小编一起来学习一下如何使用pdf-lib实现pdf添加自定义水印功能吧

项目介绍

pdf-lib是一个强大的JavaScript库,允许在任何JavaScript环境中创建和修改PDF文档。无论是前端浏览器环境还是Node.js服务器端,它都能提供全面的功能来满足你的需求。

快速启动

要开始使用pdf-lib,首先确保你已经安装了相应的npm包。在命令行中运行以下命令:

npm install --save pdf-lib

或者如果你是yarn的使用者:

yarn add pdf-lib

实现代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>PDF Watermark Example</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/pdf-lib/1.17.1/pdf-lib.min.js"></script> 
</head>

<body>
  <input type="file" id="pdfFile" accept="application/pdf">
  <button onclick="addWatermark()">添加水印</button>
  <a id="downloadLink" style="display:none;">下载PDF</a>

  <script>
    async function addWatermark() {
      const fileInput = document.getElementById('pdfFile');
      const file = fileInput.files[0];

      if (!file) {
        alert('请选择一个PDF文件');
        return;
      }

      const arrayBuffer = await file.arrayBuffer();
      const pdfDoc = await PDFLib.PDFDocument.load(arrayBuffer);
      const pages = pdfDoc.getPages();
      // 获取当前时间并格式化
      const now = new Date();
      const year = now.getFullYear();
      const month = String(now.getMonth() + 1).padStart(2, '0');
      const day = String(now.getDate()).padStart(2, '0');
      const hour = String(now.getHours()).padStart(2, '0');
      const minute = String(now.getMinutes()).padStart(2, '0');

      // 创建水印
      const watermarkText = `无敌暴龙兽-${year}-${month}-${day}-${hour}:${minute}-加密`;
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const fontSize = 20;
      const textColor = 'rgba(0, 0, 0, 0.2)';

      // 计算文本宽度和高度
      ctx.font = `${fontSize}px Arial`;
      const textMetrics = ctx.measureText(watermarkText);
      const textWidth = textMetrics.width;
      const textHeight = fontSize;

      // 计算旋转后的文本边界
      const angle = -Math.PI / 4; // 旋转45度
      const rotatedWidth = Math.abs(textWidth * Math.cos(angle)) + Math.abs(textHeight * Math.sin(angle));
      const rotatedHeight = Math.abs(textHeight * Math.cos(angle)) + Math.abs(textWidth * Math.sin(angle));

      // 设置Canvas大小
      canvas.width = rotatedWidth + 20; // 增加一些边距
      canvas.height = rotatedHeight + 20;

      // 绘制水印文本
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate(angle);
      ctx.font = `${fontSize}px Arial`;
      ctx.fillStyle = textColor;
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(watermarkText, 0, 0);

      // 将Canvas转换为Image对象
      const image = new Image();
      image.src = canvas.toDataURL('image/png');

      // 添加水印到每一页PDF
      for (const page of pages) {
        const { width, height } = page.getSize();

        // 计算新的水印尺寸,以便它可以跨越页面的两个相邻边缘
        const cornerMargin = 50; // 角落与页面边缘之间的最小距离
        const cornerSizeMultiplier = 0.5; // 控制水印相对于页面尺寸的比例
        const scale = 1; // 水印缩放比例

        const cornerWidth = Math.min(width, height) * cornerSizeMultiplier * scale;
        const cornerHeight = cornerWidth; // 假设是正方形水印

        // 计算水印的新位置,使其跨越页面的两个相邻边缘
        const positions = [
          { x: cornerMargin, y: cornerMargin }, // 左上角
          { x: width - cornerWidth - cornerMargin, y: cornerMargin }, // 右上角
          { x: cornerMargin, y: height - cornerHeight - cornerMargin }, // 左下角
          { x: width - cornerWidth - cornerMargin, y: height - cornerHeight - cornerMargin } // 右下角
        ];

        // 需要重新创建水印图像以匹配新尺寸
        const newCanvas = document.createElement('canvas');
        const newCtx = newCanvas.getContext('2d');
        newCanvas.width = cornerWidth;
        newCanvas.height = cornerHeight;

        // 复制旧水印到新画布
        newCtx.drawImage(canvas, 0, 0, cornerWidth, cornerHeight);

        // 将新画布转换回Image对象
        const newImage = new Image();
        newImage.src = newCanvas.toDataURL('image/png');

        // 嵌入新水印到PDF文档
        const newImg = await pdfDoc.embedPng(newImage.src);

        for (const pos of positions) {
          page.drawImage(newImg, {
            x: pos.x,
            y: pos.y,
            width: newImg.width,
            height: newImg.height,
          });
        }
      }

      // 保存修改后的PDF
      const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
      const downloadLink = document.getElementById('downloadLink');
      downloadLink.href = pdfDataUri;
      downloadLink.download = 'watermarked.pdf';
      downloadLink.click();
    }
  </script>
</body>

</html>

效果图

到此这篇关于使用pdf-lib.js实现pdf添加自定义水印功能的文章就介绍到这了,更多相关pdf-lib实现pdf添加自定义水印内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript常见打开链接的几种方法小结

    JavaScript常见打开链接的几种方法小结

    在页面中的链接除了常规的方式以外,如果使用javascript,还有很多种方式,下面这篇文章主要给大家介绍了关于JavaScript常见打开链接的几种方法,需要的朋友可以参考下
    2024-01-01
  • assert()函数用法总结(推荐)

    assert()函数用法总结(推荐)

    assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。这篇文章主要介绍了assert()函数用法总结,需要的的朋友参考下
    2017-01-01
  • 一文解决前端JS小数运算精度问题

    一文解决前端JS小数运算精度问题

    在做项目的时候,前端需要在表格的底部做一个汇总的功能,在采用reduce对当前属性所有值汇总时,发现汇总结果存在好长的小数位,本文给大家介绍了如何解决前端JS小数运算精度问题,需要的朋友可以参考下
    2024-02-02
  • javascript发送短信验证码实现代码

    javascript发送短信验证码实现代码

    我们在注册账号,或者是参加活动时,都会向手机发送收短信验证码,短信验证码到底是如何实现的,本文为大家揭晓,并为大家分项1javascript发送短信验证码实现代码,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • js中关于new Object时传参的一些细节分析

    js中关于new Object时传参的一些细节分析

    这里讨论给Object传参时,其内部的处理。参考:ECMA262 V5 15.2.2.1
    2011-03-03
  • 浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总结

    浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总

    本文是小编给大家总结的关于javascript中的map, filter, some, every, forEach, for in, for of 用法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-03-03
  • 基于Bootstrap模态对话框只加载一次 remote 数据的解决方法

    基于Bootstrap模态对话框只加载一次 remote 数据的解决方法

    下面小编就为大家带来一篇基于Bootstrap模态对话框只加载一次 remote 数据的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • 微信jssdk踩坑之签名错误invalid signature

    微信jssdk踩坑之签名错误invalid signature

    这篇文章主要介绍了微信jssdk踩坑之签名错误invalid signature,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • JavaScript 隐性类型转换步骤浅析

    JavaScript 隐性类型转换步骤浅析

    隐性类型转换,是==引起的转换,下面通过本文给大家分享JavaScript 隐性类型转换步骤,感兴趣的朋友一起看看吧
    2018-03-03
  • Javascript 原型和继承(Prototypes and Inheritance)

    Javascript 原型和继承(Prototypes and Inheritance)

    前面我们看到了如何使用 constructor 来初始化对象。如果这样做,那么每一个创建的新对象都会对那些相同的属性,方法建立一个独立的副本。而实际上有更加有效的方法来指定方法,常量,以及其他一些可被所有该类的对象共享的属性。
    2009-04-04

最新评论