vue项目纯前端把PDF转成图片并下载

项目需求是把一个pdf转成图片,并在最后添加上二维码,然后下载下来。

经过一番研究以后,作此记录。

主要用到了pdfjs-dist这个包,我用的是2.16.105版本。

废话不多说,直接上代码。

先下载node_modules包

javascript 复制代码
npm i pdfjs-dist -S

然后在vue页面中引入:

javascript 复制代码
import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf.js";
import * as pdfjsWorker from "pdfjs-dist/legacy/build/pdf.worker.entry.js";
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;

下面是在methods里面写的方法:

javascript 复制代码
// 通过前台用pdf转图片
    async pdfForImage(pdf) {
      this.isExportLoad = true; // 控制加载中
      const pdfurl = pdf; // 传过来的是pdf的连接
      console.log(pdfurl, "pdf地址");
      if (pdfurl) {
        try {
            // 读取pdf文件
          const pdfDoc = await pdfjsLib.getDocument(pdfurl).promise;
          const pageNum = pdfDoc.numPages;
          console.log(pageNum, "pdf页数");
          const promiseArr = [];
          // 循环pdf每一页
          for (let i = 1; i <= pageNum; i++) {
            const page = await pdfDoc.getPage(i);
            const viewport = page.getViewport({ scale: 1.5 }); // 设置合适的缩放比例
            // 创建canvas画布
            const canvas = document.createElement("canvas");
            const ctx = canvas.getContext("2d");
            canvas.width = viewport.width;
            canvas.height = viewport.height;
            // 把每一页Pdf画到canvas中
            const renderTask = page.render({
              canvasContext: ctx,
              viewport: viewport,
            });
            // 因为有好多页,所以通过promise完成每一页的canvas画布以后再统一合并图片
            const promise = new Promise((resolve, reject) => {
              // 等待渲染完成
              renderTask.promise
                .then(() => {
                  resolve({
                    canvas,
                    width: canvas.width,
                    height: canvas.height,
                  });
                })
                .catch((error) => {
                  reject({
                    error,
                    canvas: null,
                    width: 0,
                    height: 0,
                  });
                });
            });
            promiseArr.push(promise);
          }
          // 等所有pdf页面渲染完成
          Promise.all(promiseArr).then((res) => {
            console.log(res, "res");
            if (res.length > 0) {
              // 合并canvas并生成图片
              const canvas = document.createElement("canvas");
              const ctx = canvas.getContext("2d");
              // 获取最大宽度
              let width = Math.max(...res.map((item) => item.width));
              // 获取高度总和
              let height = res.reduce((total, item) => total + item.height, 0);
              let num = 0, qrCanvasHeight = 136; // qrCanvasHeight是二维码图片的高度上下预留出20px的间距
              canvas.width = width;
              canvas.height = height + qrCanvasHeight; // 高度要加上二维码图片的高度
              ctx.fillStyle = "#ffffff"; // 给画布加上白色背景,这个色值可以随便更换
              ctx.fillRect(0, 0, width, height + qrCanvasHeight);
              res.forEach((item) => {
                if (item.canvas && item.height > 0) {
                  // 画图片信息
                  ctx.drawImage(item.canvas, 0, num, item.width, item.height);
                  num += item.height;
                }
              });
              // 添加二维码图片
              const img = new Image();
              img.src = require("@/assets/qrcode.png"); // 二维码图片地址
              img.width = 320; // 二维码宽度
              img.height = 96; // 二维码高度
              img.onload = () => {
                ctx.drawImage(
                  img,
                  width / 2 - 160, // 为了让图片左右剧中
                  num + 20, // 让二维码与上方多20px的间距
                  img.width,
                  img.height
                );
                // 把canvas生成图片
                const imageUrl = canvas.toDataURL("image/jpeg", 1); // 我这里是生成为jpg了,也可以传image/png
                // ctx.scale(2, 2); // 可选:放大图像以便查看(根据需要调整)
                // console.log(imageUrl, "imageUrl"); // 生成的base64图片地址,可以输出查看
                // 下载图片
                const link = document.createElement("a");
                link.href = imageUrl;
                link.download = `分析报告.jpg`;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                this.isExportLoad = false;
              };
            }
          });
        } catch (err) {
          console.log(err);
          this.$message.error("pdf文件加载失败");
        }
      }
    },
相关推荐
郑州光合科技余经理43 分钟前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
+VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue旅游管理系统(源码+数据库+文档)
java·开发语言·vue.js·spring boot·课程设计
雪芽蓝域zzs1 小时前
第 7 章:双 Y 轴组合图(柱状 + 折线,看板高频场景)
vue.js·echars
IT_陈寒1 小时前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
一 乐2 小时前
二手交易平台|基于springboot + vue二手交易平台(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序
Blanche15002 小时前
利用 RAG 为答疑机器人扩展知识范围
前端
天若有情6732 小时前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具
SoonITer2 小时前
怎样构建一个 Agent-friendly 的网站
前端·agent
颜进强2 小时前
01 · NestJS 是什么:用途、解决什么问题、与热门框架对比
前端·后端·ai编程
wendZzoo2 小时前
前端工程师的 3D 第一课:一个模型如何进入网页
前端