• vue.js3: 用pdflib给pdf文件添加中文字体水印(pdflib@1.17.1 / vue@3.2.37)


    一,安装pdf-lib库:

    1,pdf-lib的官网:
    https://pdf-lib.js.org/
    2,安装pdf-lib
    liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm install --save pdf-lib
     
    added 4 packages in 5s
    3,查看已安装的pdf-lib库的版本:
    liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list pdf-lib
    image2pdf@0.1.0 /data/vue/pdf/image2pdf
    └── pdf-lib@1.17.1 
    4,安装fontkit,添加中文字体时要用到
    liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm install --save @pdf-lib/fontkit
     
    added 1 package in 3s
    5,查看安装的fontkit库的版本:
    liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list @pdf-lib/fontkit
    image2pdf@0.1.0 /data/vue/pdf/image2pdf
    └── @pdf-lib/fontkit@1.1.1

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/
             或: https://gitee.com/liuhongdi

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,使用pdf-lib

    1,配置:
    创建字体文件夹:
    public/fonts
    把字体文件复制到目录下
     
    说明:
    请使用中文的ttf字体或otf字体,
    使用ttc字体时会报错
     
    2,js代码:
    <template>
      <div>
        <div style="800px;margin: auto;">
    
          <div >
            选择pdf:
            <input type="file" ref="hiddenfile" accept="application/pdf" @change="handlePdf" class="hiddenInput" />
          </div>
          <div style="800px;font-size:12px;margin-top:10px;">
            <el-button type="info" @click="downPdf" plain style="400px;">保存并下载pdf</el-button>
          </div>
          <div style=" 800px;margin-top: 20px;">
            <div  v-for="(item,i) in imgFiles" :key="i" :id="`div_${i}`"
                  style="265px;position: relative;float:left;overflow: hidden;">
              <canvas :id="`pdf_canvas_${item.id}`" style="border: 1px solid #eeeeee;float:left;" ></canvas>
            </div>
          </div>
    
        </div>
      </div>
    </template>
    
    <script>
    import * as pdfjs from 'pdfjs-dist'
    import * as pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
    pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker
    
    import { degrees, PDFDocument, rgb } from 'pdf-lib'
    import fontkit from "@pdf-lib/fontkit";
    import {ref} from "vue"
    
    import {ElMessage} from "element-plus";
    import { showLoading, hideLoading } from '@/utils/loading'
    
    export default {
      name: "PdfText",
      setup() {
        //pdf转成的图片文件,保存在数组中
        const imgFiles = ref([]);
    
        //pdf的名字,记录下来
        const pdfName = ref("");
    
        //加载文件的结果集
        const result = ref("");
        //选择文件的处理
        const handlePdf = (e) => {
          showLoading();
          //hideLoading();
          let filePaths = e.target.files;
          //清空原有缩略图
          if (filePaths.length === 0) {
            //未选择,则返回
            hideLoading();
            return false;
          }
          imgFiles.value.length = 0;
    
          let file = e.target.files[0];
    
          pdfName.value = file.name.substring(0, file.name.lastIndexOf("."));
    
          const reader = new FileReader();
          reader.readAsArrayBuffer(file);
          reader.onload = () => {
            //把读取到的结果集保存到result
            result.value = reader.result;
    
            const loadingTask = pdfjs.getDocument(reader.result)
            loadingTask.promise.then((pdf) => {
    
              var pageNum = pdf.numPages;
              console.log("页数:" + pageNum);
    
              //准备图片
              for (let i = 1; i <= pageNum; i++) {
                let one = {id: i, imgSrc: ''};
                imgFiles.value.push(one);
              }
    
              let maxHeight = 0;
              //处理
              for (let i = 1; i <= pageNum; i++) {
                pdf.getPage(i).then((page) => {
                  const canvas = document.getElementById('pdf_canvas_' + i);
                  const ctx = canvas.getContext('2d')
                  const viewport = page.getViewport({scale: 1})
                  // 画布大小,默认值是300px,height:150px
                  canvas.height = viewport.height;
                  canvas.width = viewport.width;
                  //显示为图片的目标宽度
                  const destWidth = 263;
                  canvas.style.width = destWidth + 'px';
                  // 根据pdf每页的宽高比例设置canvas的高度
                  let destHeight = destWidth * (viewport.height / viewport.width);
                  canvas.style.height = destHeight + 'px';
                  page.render({
                    canvasContext: ctx,
                    viewport,
                  });
    
                  //如果目标高度更高,则调整每个canvas的高度,使显示高度统一
                  if (destHeight > maxHeight) {
                    maxHeight = destHeight;
                    for (let i = 0; i < pageNum; i++) {
                      let canvas = document.getElementById('div_' + i);
                      console.log("canvas name:" + 'div_' + i);
                      console.log(canvas);
                      canvas.style.height = maxHeight + 'px';
                    }
                  }
                })
                //加载完成
              }    // end for
              hideLoading();
            })
          };
        }
        //下载的pdf,下载添加文字水印
        const downPdf = async () => {
          //判断是否选择了pdf文件
          if (imgFiles.value.length <= 0) {
            ElMessage.error("请先选择pdf文件");
            return false;
          }
    
          const pdfDoc = await PDFDocument.load(result.value);
          const pages = pdfDoc.getPages();
    
          // 自定义字体挂载
          pdfDoc.registerFontkit(fontkit);
          var defaultFontBuffer = await fetch(
              '/fonts/SourceHanSerifSC-Light.otf',
          ).then(res => res.arrayBuffer());
          const helveticaFont = await pdfDoc.embedFont(defaultFontBuffer);
          //加文本,演示时只加在了第一页
          const firstPage = pages[0]
          const {  height } = firstPage.getSize()
          firstPage.drawText('用js添加的水印文字上线了,测试看会不会显示完整,字号什么的!', {
            x: 5,
            y: height / 2 + 300,
            size: 50,
            font: helveticaFont,
            color: rgb(0.95, 0.1, 0.1),
            rotate: degrees(-45),
            opacity: 0.8,
          })
    
          const pdfBytes = await pdfDoc.save();
          saveByteArray(pdfName.value + "_" + timeFormat() + '.pdf', pdfBytes);
        }
    
        //保存pdf并下载
        const saveByteArray = (reportName, byte) => {
          var blob = new Blob([byte], {type: "application/pdf"});
          var link = document.createElement('a');
          link.href = window.URL.createObjectURL(blob);
          var fileName = reportName;
          link.download = fileName;
          link.click();
        };
    
    
        //补0
        const add0 = (m) => {
          return m < 10 ? '0' + m : m
        }
    
        //格式化时间
        const timeFormat = () => {
          var time = new Date();
          var y = time.getFullYear();
          var m = time.getMonth() + 1;
          var d = time.getDate();
          var h = time.getHours();
          var mm = time.getMinutes();
          var s = time.getSeconds();
          let res = y + add0(m) + add0(d) + add0(h) + add0(mm) + add0(s);
          return res;
        }
    
        return {
          handlePdf,
          downPdf,
          imgFiles,
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>

    三,测试效果

    pdf的效果:
     说明:pdf文件体积会变大,应该是同时打包了用到的字体文件的原因

    四,查看vue框架的版本: 

    liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list vue
    child@0.1.0 /data/vue/pdf/image2pdf
    ├─┬ @vue/cli-plugin-babel@5.0.6
    │ └─┬ @vue/babel-preset-app@5.0.6
    │   └── vue@3.2.37 deduped
    └─┬ vue@3.2.37
      └─┬ @vue/server-renderer@3.2.37
        └── vue@3.2.37 deduped
  • 相关阅读:
    华为 简单OSPF实验
    华为 基于MAC地址的VLAN划分
    完全背包
    01背包问题
    90. 子集 II
    Java去除字符串中的特殊符号或者指定的字符
    Java查找指定文件夹下的所有文件
    Java面试基础
    Spring获取ApplicationContext
    JSP & EL & JSTL
  • 原文地址:https://www.cnblogs.com/architectforest/p/16557446.html
Copyright © 2020-2023  润新知