预览PDF
述语
在h5中预览PDF,最开始使用的是vue-PDF 发现在渲染PDF时 是 乱序渲染,不是从头渲染,而且 每次渲染都要读取一遍pdf流,这样如果在查看PDF 时, 假如在 PDF未渲染完某页 就返回时 会报错,导致下一次打开PDF 不会渲染出来。导致效果不好
所以 更改 PDF插件,使用PDFjs-dist,但是注意点还是要注意以上。
但是我还是觉得 将后台将pdf转换成图片的base64流,传给前台,前台直接渲染图片会更简单
基本代码
先下载pdfjs-dist
以下是预览PDF的组件,其中url可以是路径也可以是base流,
canvas 绘制
缺点:放大后会模糊
svg 绘制
canvas 按像素绘制 svg按弧度 转角...绘制
包含 canvas 绘制 和svg绘制 PDF
xml代码解读复制代码<template> <div class="view-wrapper"> <van-nav-bar title="查看PDF" left-arrow @click-left="goHome()" fixed /> <div class=''box'' style="background: #fff"> //-------------canvas 绘制 <div> <canvas v-for="page in pages" :id="''the-canvas''+page" :key="page"></canvas> </div> //----END //----------svg 绘制 <div class="view" id="canvas-wrap"></div> //----END </div> <van-loading v-show="loadding" type="spinner" /> </div> </template> <script> import PDFJS from ''pdfjs-dist''; import workerSrc from ''pdfjs-dist/build/pdf.worker.entry''; PDFJS.workerSrc = workerSrc; // PDFJS.GlobalWorkerOptions.workerSrc = ''https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.943/build/pdf.worker.min.js''; //请注意,这里的cdn worker地址是贴的网上的,并且签章那部分代码是没有注释的,直接拿去用是达不到效果的,我也没有现成的资源可提供,只是贴一下方法 export default { data() { return { pdfDoc: null, pages: 0, pdfUrl:'''', src:'''', loadding:true, file:true, isDestory:true } }, metaInfo: { meta: [ { name: ''viewport'', content: ''width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=5,user-scalable=yes'' } ] }, watch: { }, methods: { _renderPage (num) { // getPage 处理每个页面 // 返回单页内容实例(页面引索) pdf.getPage(index) this.pdfDoc.getPage(num).then((page) => { // canvas 绘制 PDF let canvas = document.getElementById(''the-canvas'' + num) let ctx = canvas.getContext(''2d''); ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false; let dpr = window.devicePixelRatio || 1 let bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1 let ratio = dpr / bsr // 返回页面内容(比例) page.getViewport({scale:2.0})语法改这么写 let viewport = page.getViewport({scale:screen.availWidth / page.getViewport({scale:1.0}).width});//这是让pdf文件的大小等于视口的大小 canvas.width = viewport.width * ratio canvas.height = viewport.height * ratio//这里会进行压缩,解决模糊问题 canvas.style.width = viewport.width + ''px'' canvas.style.height = viewport.height + ''px'' let renderContext = { canvasContext: ctx, viewport: viewport, transform: [ratio, 0, 0, ratio, 0, 0]//这里会进行放大,解决模糊问题 } const that = this page.render(renderContext).promise.then(function(){ // 防止 在 PDF未渲染完某页 就返回时 会报错,导致下一次打开PDF 不会渲染出来 if(that.isDestory){ console.log(''xuanran'') // page.getTextContent() if (that.pages > num) { that._renderPage(num + 1) } } }); //-----------END---------- //svg绘制 PDF /* svg实现方式 */ let viewport = page.getViewport({scale: vm.scale}) let container = document.createElement(''div'') container.id = ''canvas_'' + num container.className = ''pageContainer'' container.style.width = viewport.width + ''px'' container.style.height = viewport.height + ''px'' document.getElementById(''canvas-wrap'').appendChild(container) return page.getOperatorList().then(function(opList) { let svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs) return svgGfx.getSVG(opList, viewport).then(function(svg) { container.appendChild(svg) }) }) //-----------END---------- }) }, _loadFile (url) { // 获取整个 文档 PDFJS.getDocument({ url, // cMapUrl: ''https://unpkg.zhimg.com/pdfjs-dist@1.9.426/cmaps/'',//这里同样要引入字体解决水印问题,需自己提供 // 注意:如果PDF的水印是收费字体,则需要 通过cMapUrl引入对应的字体,如果是免费字体,则不需要引入字体 水印会直接渲染出来 cMapPacked: true }).promise.then((pdf) => { this.pdfDoc = pdf this.pages = this.pdfDoc.numPages this.loadding = false const that = this if(that.isDestory){ this.$nextTick(() => { this._renderPage(1) }) } },(err) => { if(err.name == ''MissingPDFException''){ this.$toast(''无效的PDF链接'') } // reject(err); }) } }, mounted() { this._loadFile(''http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf''); }, beforeDestroy(){ console.log(''destory'') this.isDestory = false this._renderPage = null } } </script> <style lang="scss" scoped> .view-wrapper { padding-top:1.22667rem; } .view-wrapper /deep/ .van-nav-bar .van-icon { color: #333; font-size: 18px; margin-right: 3px; } .view-wrapper /deep/ .van-loading { position: absolute; top: 50%; left: 46%; } </style>
引入pdfjs-dist 报错 总是引入不进来
ini代码解读复制代码const PDFJS = require(''pdfjs-dist'') PDFJS.GlobalWorkerOptions.workerSrc = require(''pdfjs-dist/build/pdf.worker.entry'')
有些字体加载不出来
如果pdf中有商用字体,对于商用字体,默认是不支持的,想要渲染出商用字体,需要引入对应的字体:一般是全部引入
rust代码解读复制代码cMapUrl: ''https://unpkg.zhimg.com/pdfjs-dist@1.9.426/cmaps/'', //这里同样要引入字体解决水印问题,需自己提供 // 注意:如果PDF的水印是收费字体,则需要 通过cMapUrl引入对应的字体,如果是免费字体,则不需要引入字体 水印会直接渲染出来 cMapPacked: true
查看 签章 电子签名
在node_moduels pdfjs-dist 的 pdf.worker.js 文件中,将以下代码注释:
ini代码解读复制代码if (data.fieldType === ''Sig'') { this.setFlags(AnnotationFlag.HIDDEN); }
缩放pdf
用的是 <meta name="viewport" content="width=device-width,initial-scale=1.0"> 在查看pdf页 设置 成可以缩放,在其他页面设置成不可以缩放
在vue中更改 html的meta 可以 通过v-meta插件 设置
css代码解读复制代码metaInfo: { //和data是平级 meta: [ { name: ''viewport'', content: ''width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=5,user-scalable=yes'' } ] },
contains 属性冲突
PDFJS 里给Aray添加了contains属性,Array.prototype.contains,所以如果在项目中同时添加contains属性会报错