• 周三. 6月 29th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

PDF预览

admin

11月 28, 2021

背景介绍:

最近在做小程序发票相关的东西,与后端调试过程中发现,给的发票是pdf格式的,看到这想完了,pdf预览在移动端一直是老大难的问题,心里想着后端就不能转成图片给我一个图片格式的嘛,但是转念一想,对呀,移动端预览pdf一直是个问题不能总是逃避呀,不能每次都依靠后端,带着这种想法,就开启了pdf预览之路。

正文:

思路:使用pdf.js将pdf加载到canvas里,然后将canvas转成图片

环境:”vue”: “^2.6.10”,

先附上正确的完整的代码步骤

(一)准备pdf.js、pdf.work.js、pdf.work.entry.js这三个文件

  1. 注意版本:这里使用的是2.0.288(如果实在找不到可以在项目中使用npm install [email protected],然后到node_modules里去找到相应的文件)

(二)将这三个文件放到public文件夹里面

 (三)在public文件夹下的index.html文件中引入pdf.js和pdf.work.js这两个文件

注意:不要使用cdn的地址,后面我们需要需改pdf.work.js

(四)在发票预览的页面写相应的处理操作

  1. template
    1. <div class="img-con" id="img-con">
            <canvas id="myCanvas" canvas-id="myCanvas" style="display: none"></canvas>
      </div> 
  2. js
    1.     this.invoiceUrl = 'http://localhost:8080/dev/cnr-web/江苏移动.pdf';
          let canvasWidth = document.body.clientWidth - 40;
          PDFJS.cMapUrl = 'https://cdn.jsdelivr.net/npm/[email protected]/cmaps/'; //字体解析
          PDFJS.cMapPacked = true;
          PDFJS.workerSrc = 'http://localhost:8080/dev/cnr-web/pdf.worker.entry.js';
          let loadingTask = PDFJS.getDocument(this.invoiceUrl);
          loadingTask.promise.then(
            function (pdf) {
              console.log('PDF loaded');
              let pageNumber = 1;
              pdf.getPage(pageNumber).then(function (page) {
                console.log('Page loaded');
                let scale = 2;
                let viewport = page.getViewport(scale);
                console.log(viewport, 'viewport');
                let canvas = document.getElementById('myCanvas');
                let context = canvas.getContext('2d');
                viewport.viewBox.forEach((e, index) => {
                  viewport.viewBox[index] = 0;
                });
                canvas.height = viewport.height;
                canvas.width = viewport.width;
                let renderContext = {
                  canvasContext: context,
                  viewport: viewport,
                };
                let renderTask = page.render(renderContext);
                renderTask.then(function () {
                  let image = new Image();
                  image.src = canvas.toDataURL('image/png');
                  image.width = canvasWidth;
                  let ImgCon = document.getElementById('img-con');
                  ImgCon.appendChild(image);
                });
              });
            },
            function (reason) {
              console.error(reason);
            });

注意:

 1.cmaps版本不对会影响pdf内容显示

PDFJS.cMapUrl = 'https://cdn.jsdelivr.net/npm/[email protected]/cmaps/'; //字体解析

2. pdf.worker.entry.js不要使用相对路径,使用绝对路径 。

原因:构建之后pdf不显示

PDFJS.workerSrc = 'http://localhost:8080/dev/cnr-web/pdf.worker.entry.js';

3.需要将canvas转成图片,不然不好在手机上显示

let renderTask = page.render(renderContext);
renderTask.then(function () {
   let image = new Image();
   image.src = canvas.toDataURL('image/png');
   image.width = canvasWidth;
   let ImgCon = document.getElementById('img-con');
   ImgCon.appendChild(image);
});

(五)修改pdf.work.js文件,原因是个别发票的印章出不来

// if (data.fieldType === 'Sig') {
      // _this2.setFlags(_util.AnnotationFlag.HIDDEN);
// }

 

到此,就结束了……..

碰到的问题:

  1. 使用npm install pdfjs-dist,在import PDFJS from ‘pdfjs-dist’时报错, 应该是pdfjs-dist版本问题,最后选择的是2.0.288的版本
  2. 使用script引入pdf.js和pdf.work.js时,发票显示不出来,需要通过pdf.work.entry.js引入pdf.work.js
  3. 个别发票印章显示不出来,将pdf.work.js中的印章代码注释掉,参考(五)
  4. 代码构建之后发票显示不出来,PDFJS.workerSrc要用绝对路径,不要使用相对路径

最终效果:

下面附上我的历程:

 由于是在小程序端开发,首先就是考虑小程序自带的方法,使用wx.openDocument,但是这个是直接打开,我们的需求是,如下图,这个样子的,摇头~,然后又用了web-view,嗯,web-view也是占满整个屏幕的,就跟H5或者PC端使用iframe展示效果一样,也是不行,后来又看到用canvas加载pdf,就网上找各种办法。哎,第一步就不行了,使用npm install pdfjs-dist后,import PDFJS from ‘pdfjs-dist’,就开始报错,百度又说是版本问题,但是换了几个版本还是不行,想着说找个html文件用scipt标签引入cdn地址好吧,可惜小程序中没有这么一个html文件让我引入,在网上查找了好久,还是不行,陷入了死局,这可咋整。睡了一觉醒来想着说先不在小程序里写了,先写一个纯html,js的,这种不会因为是小程序环境还是H5环境而影响,说干就干,嗯,一个简单的demo就出来了,但是发票内容有些显示不出来,百度说cMapUrl地址不对,有改过版本有下载到本地…..网上说的方法都试过还是不行,又陷入了死局,后来用safari浏览器打开,发票显示的非常完美,啥问题都没有,难道是个别浏览器不支持这种字体,抱着在手机上显示正常的侥幸心理,打算把它迁移到项目里。想着小程序里不行,咋办呢,突然灵机一动H5吧,H5环境比小程序好点,然后就开始了迁移之路,因为是vue项目第一想法还是使用npm install pdfjs-dist,然后根据demo中引入的是2.0.288的cdn地址,又联想到小程序测试的时候安装使用的时候报错,就果断选择了2.0.288的版本安装。这次没报错,将代码移植过去之后发票没有显示,又陷入了死局,后来想着js能显示,移过来咋就不行了呢,就比对了下,区别就是一个使用的cdn地址一个是npm install的呗,行那咱就换,我还就不信了。换了之后,显示了但是没显示全,而且跟demo显示不全的还不一样,然后又陷入了死局。后来在来回切换使用的是npm还是script引入的时候,混搭了一下,pdf.js使用的是Script标签,pdf.work.js使用的是npm,发票内容竟然出来了,但是个别发票的印章没有出来,之前在研究发票内容显示不全的时候看到过这个问题,就是把pdf.work.js里的印章的代码注释掉,但是这个使用npm安装的呀,要改node_modules。的确,注释掉就可以了。但这也不是个好办法,我们使用的是jekins部署的,自动打包,不好修改node_modules,如果这样的话就只能手动打包了。然后就想着继续研究研究,发现,script标签引入的pdf.work.js,而node_modules引入的是pdf.work.entry.js。然后把node_modules里的俩文件copy出来放在了本地,放在vue文件同级时,会报require is undefined;然后就放到了main.js的同级,但是pdf.js中会报错,里面会用到pdf.work.js里的东西,由于pdf.js是放在了public里面,在public下面的index.html中引入的,会先加载,这个时候pdf.work.js还没有加载,所以会报错,后来把pdf.work.js也放到了public 里,pdf.work.entry.js还是放到了main.js的同级,将pdf.work.entry.js里的pdf.work.js指向了public下的pdf.work.js,然后注释pdf.work.js里的签名代码,发票完美的显示好了。真的是太开心了。可是,好景不长,后来发现构建之后发票不显示,在控制台发现报错了,如下图,这个错误之前在本地调试是也有过,但是由于没有影响发票展示就没在意。这下好了,为啥呢,map文件之前也见过就想着把这俩map文件也放到public里,再次构建,嗯不报错了,啥报错也没有,就是不展示,后来经过再次使用npm install pdfjs-dist,最新版的、2.3.000版的、2.0.288版的调试,还是会出现各种各样的问题,最后想到之前混搭使用npm install [email protected]的时候只是印章不出来,就想着这种条件下构建呢。说干就干,发现构建之后,也只是印章显示不出来,这就说明是pdf.work.entry.js的路径有问题,这里我写的是相对路径,想着改成http开头的路径呢,构建了一下,发现果然发票有完美的出来了,到此,结束,目前还没发现有什么问题。

发表评论

您的电子邮箱地址不会被公开。