Vue项目pdf(base64)转图片遇到的问题及解决方法


Posted in Javascript onOctober 19, 2018

公司有个业务需求,要求后台传pdf的base64编码给前端,前端显示到界面上,后来在网上搜索了很多关于base64转pdf的文章,都写的不是非常的详细,在实现的过程中遇到很多坑,经过一天的研究终于实现了这个功能,分享一下我在这个功能中遇到的问题和解决方法

要注明的是这里用到的核心插件是pdf.js,原理是动态生成canvas标签,然后通过pdf.js生成一个能渲染出pdf的对象,随后渲染每个canvas,并且生成的pdf是画面的形式,并没有pdf之类的控件

引入插件

这里很多博客都是使用JavaScript原生的方法引入pdf.js,例如使用script标签引入外部的js脚本,或者直接把pdf.js的源码复制到项目中,但是我尝试这些方法的时候都不是特别好用,而且引入后导致项目体积过于庞大,

Vue项目pdf(base64)转图片遇到的问题及解决方法

随后我去github上寻找通过包管理器引入pdf.js的方法,在pdf.js的github上官方说明的是用gulp如何使用pdf.js,但是对于npm来说并没有详细说明,终于我在字里行间发现了这么一句话

To use PDF.js in a web application you can choose to use a pre-built version of the library or to build it from source. We supply pre-built versions for usage with NPM and Bower under the pdfjs-dist name. For more information and examples please refer to the wiki page on this subject.

大致的意思就是如果使用npm包管理器或者bower的话,引入的名字为pdfjs-dist,那么我们使用npm的方法引入这个pdfjs-dist,引入的名字就随意取名了这里我叫PDFJS

import PDFJS from 'pdfjs-dist'

使用pdfjs-dist

这里后台传给我的是一个由pdf文件名字和pdf的base64编码组成的对象的数组,我取名为pdfDataList

Vue项目pdf(base64)转图片遇到的问题及解决方法

可以看到fileName是pdf的名字,fileVale是pdf文件的base64编码,thumbnail是pdf缩略图的base64编码这里用不到先不管,之前说到需要动态生成canvas节点(这里不会canvas也不要紧,只需要根据代码一步步做就能渲染canvas)

1.首先我们创建一个承载所有canvas节点的父节点,取名为pdfList

Vue项目pdf(base64)转图片遇到的问题及解决方法

2.然后创建一个异步函数showPdf(不懂什么是异步函数的可以去查一下async/await,这里不用异步函数也可以使用promise.then的方法,但是async/await作为异步操作的终极方案最好还是学习一下)

async showPdf() {   
  }

使用querySelector选择类名为pdfList的dom节点,随后遍历后台传过来的pdfDataList数组的每一项,这里用到一个浏览器自带的atob()方法解码base64,MDN上是这么解释的:

你可以使用 window.btoa() 方法来编码一个可能在传输过程中出现问题的数据,并且在接受数据之后,使用 atob() 方法再将数据解码。

语法: var decodedData = scope.atob(encodedData);

随后调用pdf.js插件的getDocument方法,getDocument是一个promise,所以使用异步函数的话前面需要加await关键字(不使用异步函数的话在方法后面加.then((pdf)=>{.......}),这个pdf对象和我这个pdf对象是同一个,同时这里暂时也没考虑异步操作出错的情况,有要求的话可以在加个catch捕获错误)

getDocument方法的参数是一个对象,对象键名为data,值为base64解码后的值,此方法返回一个pdf对象,这个对象有几个属性,可以打印出来观察一下

Vue项目pdf(base64)转图片遇到的问题及解决方法

这里我们先用到的是numPages属性,它指的是当前pdf文件有多少页

async showPdf() {
    let pdfList = document.querySelector('.pdfList') //通过querySelector选择DOM节点,使用document.getElementById()也一样
    for(let value of this.pdfDataList){ //遍历后台传过来的pdfDataList
      let base64 = value.fileValue //获得bas464编码
      let decodedBase64 = atob(base64) //使用浏览器自带的方法解码
      let pdf = await PDFJS.getDocument({data: decodedBase64}) //返回一个pdf对象
      let pages = pdf.numPages //声明一个pages变量等于当前pdf文件的页数
    }
  }

获取当前pdf文件的对象和当前pdf文件的所有页数后,循环遍历每个页数,执行如下操作:

1)动态创建canvas节点
2)调用pdf对象原型上的getPage()方法和getViewport()方法,依次传入当前循环的页数和canvas的缩放大小(这里不懂的可以直接复制黏贴)
3)渲染当前的canvas节点
4)调用page对象的render()方法渲染当前页,此方法也是一个promise,需要使用await关键字等到状态为resolve后再执行之后的代码
5)给显示当前页面的canvas节点一个className为canvas方便修改样式,最后把这个canvas节点插入到pdfList节点中

async showPdf() {
    let pdfList = document.querySelector('.pdfList') //通过querySelector选择DOM节点,使用document.getElementById()也一样
    for(let value of this.pdfDataList){ //遍历后台传过来的pdfDataList
      let base64 = value.fileValue //获得bas464编码
      let decodedBase64 = atob(base64) //使用浏览器自带的方法解码
      let pdf = await PDFJS.getDocument({data: decodedBase64}) //返回一个pdf对象
      let pages = pdf.numPages //声明一个pages变量等于当前pdf文件的页数
      for (let i = 1; i <= pages; i++) { //循环页数
       let canvas = document.createElement('canvas') 
       let page = await pdf.getPage(i) //调用getPage方法传入当前循环的页数,返回一个page对象
       let scale = 1;//缩放倍数,1表示原始大小
       let viewport = page.getViewport(scale); 
       let context = canvas.getContext('2d'); //创建绘制canvas的对象
       canvas.height = viewport.height; //定义canvas高和宽
       canvas.width = viewport.width;
       let renderContext = {
        canvasContext: context,
        viewport: viewport
       };
       await page.render(renderContext)

       canvas.className = 'canvas' //给canvas节点定义一个class名,这里我取名为canvas
       pdfList.appendChild(canvas) //插入到pdfList节点的最后
      }
    }
  }

至此页面上就会多出一个canvas节点并且显示当前pdf文件的第一页的图片,如果当前pdf文件有多页就会渲染出多个canvas节点,有多个pdf文件就会先循环外层,然后再循环内层,把每个pdf文件的每一页都生成一个canvas节点

 

修改样式

渲染出页面后还有个要注意的点,Vue框架会给每个组件的DOM节点生成一个自定义属性,而节点动态生成的canvas节点,并没有data-v-xxxxx这样的自定义属性

Vue项目pdf(base64)转图片遇到的问题及解决方法

而Vue会给每个组件里面的样式添加这个自定义属性,Vue框架这样做可以防止样式的相互污染(也就是style旁边的scoped属性)

Vue项目pdf(base64)转图片遇到的问题及解决方法

Vue项目pdf(base64)转图片遇到的问题及解决方法

我们这里可以在这个style下面再创建一个style写入样式来达到修改canvas样式的效果,但是记得这样做你整个项目里面类名叫canvas的都会获得这个样式,需要注意

Vue项目pdf(base64)转图片遇到的问题及解决方法

写在最后

这里使用的是动态生成canvas节点然后渲染这个节点生成的图片,然而直接使用createElement生成一个节点并且频繁操作DOM会对性能有一定的影响,如果有更好的方法欢迎留言交流,感谢观看。希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Prototype Class对象学习
Jul 19 Javascript
JQuery替换DOM节点的方法
Jun 11 Javascript
JavaScript实现点击单元格改变背景色的方法
Feb 12 Javascript
JS只能输入正整数的简单实例
Oct 07 Javascript
jQuery实现弹出窗口弹出div层的实例代码
Jan 09 Javascript
解决vue页面刷新或者后退参数丢失的问题
Mar 13 Javascript
Angular搜索场景中使用rxjs的操作符处理思路
May 30 Javascript
jQuery实现点击自身以外区域关闭弹出层功能完整示例【改进版】
Jul 31 jQuery
4个顶级开源JavaScript图表库
Sep 29 Javascript
微信小程序实现的动态设置导航栏标题功能示例
Jan 31 Javascript
解决layui使用layui-icon出现默认图标的问题
Sep 11 Javascript
利用js实现简易红绿灯
Oct 15 Javascript
使用pkg打包Node.js应用的方法步骤
Oct 19 #Javascript
简化版的vue-router实现思路详解
Oct 19 #Javascript
vue中el-upload上传图片到七牛的示例代码
Oct 19 #Javascript
浅析vue-router原理
Oct 19 #Javascript
vue-cli3.0 脚手架搭建项目的过程详解
Oct 19 #Javascript
vue-quill-editor+plupload富文本编辑器实例详解
Oct 19 #Javascript
vue+VeeValidate 校验范围实例详解(部分校验,全部校验)
Oct 19 #Javascript
You might like
PHP 5.0对象模型深度探索之绑定
2006/09/05 PHP
基于数据库的在线人数,日访问量等统计
2006/10/09 PHP
php date()日期时间函数详解
2010/05/16 PHP
解析PHP SPL标准库的用法(遍历目录,查找固定条件的文件)
2013/06/18 PHP
php curl post 时出现的问题解决
2014/01/30 PHP
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
使用配置类定义Codeigniter全局变量
2014/06/12 PHP
PHP面向对象程序设计内置标准类,普通数据类型转为对象类型示例
2019/06/12 PHP
laravel框架使用FormRequest进行表单验证,验证异常返回JSON操作示例
2020/02/18 PHP
jquery tools之tabs 选项卡/页签
2009/07/25 Javascript
滚动图片效果 jquery实现回旋滚动效果
2013/01/08 Javascript
js冒泡法和数组转换成字符串示例代码
2013/08/14 Javascript
jquery 漂亮的删除确认和提交无刷新删除示例
2013/11/13 Javascript
fckeditor粘贴Word时弹出窗口取消的方法
2014/10/30 Javascript
第二章之Bootstrap 页面排版样式
2016/04/25 Javascript
又一款js时钟!transform实现时钟效果
2016/08/15 Javascript
JS解决iframe之间通信和自适应高度的问题
2016/08/24 Javascript
js 判断各种数据类型的简单方法(推荐)
2016/08/29 Javascript
浅谈js键盘事件全面控制
2016/12/01 Javascript
深入理解Vue Computed计算属性原理
2018/05/29 Javascript
通过webpack引入第三方库的方法
2018/07/20 Javascript
Javascript如何实现双指控制图片功能
2020/02/25 Javascript
mac安装scrapy并创建项目的实例讲解
2018/06/13 Python
python原类、类的创建过程与方法详解
2019/07/19 Python
python 实现朴素贝叶斯算法的示例
2020/09/30 Python
python文件路径操作方法总结
2020/12/21 Python
一款利用html5和css3实现的3D滚动特效的教程
2015/01/04 HTML / CSS
德国最大的设计师鞋网上商店:Budapester
2017/12/07 全球购物
美国领先的低折扣旅行网站:Hotwire
2019/01/19 全球购物
美国中西部家用医疗设备商店:Med Mart(轮椅、踏板车、升降机等)
2019/04/26 全球购物
食品安全责任书
2014/04/15 职场文书
《从现在开始》教学反思
2014/04/15 职场文书
节能环保标语
2014/06/12 职场文书
会计岗位说明书
2014/07/29 职场文书
群众路线教育实践活动学习笔记内容
2014/11/06 职场文书
初中差生评语
2014/12/29 职场文书