vue前端使用pdfjs与pdfdist-mergeofd 实现预览pdf并翻页,同时解决预览pdf显示模糊的问题
插件介绍
pdfdist-mergeofd插件的作用可查看这篇文章,同时使用ofdjs和pdfjs遇到的问题,和解决方法——懒加载
该插件主要是为了解决pdfjs和ofdjs同时使用时产生的兼容性问题,用法与pdfjs一致
实现预览pdf
<!-- 使用el-upload获取上传的文件 -->
<el-upload
ref="upload"
action
:accept="fileType"
:on-change="onChangeFile"
:before-upload="beforeFileUpload"
:show-file-list="false"
:auto-upload="false"
>
<el-button slot="trigger" type="primary">选择文件</el-button>
</el-upload>
<!-- 控制翻页 -->
<div v-if="pageCount" style="text-align: center">
<el-button :disabled="currentPage == 1" @click="clickPre">
上一页
</el-button>
<span>第{{ currentPage }} / {{ pageCount }}页</span>
<el-button :disabled="currentPage == pageCount" @click="clickNext">
下一页
</el-button>
</div>
<!-- html部分非常简单,创建一个canvas用于后续渲染即可 -->
<div
ref="canvasCont"
class="canvas-container"
>
<canvas ref="myCanvas" class="pdf-container"></canvas>
</div>
//这里是用的pdfdist-mergeofd,如果使用pdfjs,用法一致
import * as pdfJS from 'pdfdist-mergeofd'
pdfJS.GlobalWorkerOptions.workerSrc = require('pdfdist-mergeofd/build/pdf.worker.entry')
export default {
name: 'xxx',
data() {
return {
file: null,
//页面宽度,根据实际调整
pageWidth: 800,
//页面高度,根据实际调整
pageHeight: 1131,
//当前页数
currentPage: 0,
//总页数
pageCount: 0,
pdfSrc: null,
//尺寸限制
sizeLimit: 1 * 1024 * 1024,
//是否正在渲染页面,防止过快翻页
renderingPage: false,
}
},
methods: {
// 上传文件
async onChangeFile({ raw }) {
if (!this.beforeFileUpload(raw)) {
return
}
if (!raw) {
return
}
this.file = raw
if (raw.type === 'application/pdf') {
const reader = new FileReader()
this.currentType = 'pdf'
reader.onload = async e => {
this.pdfSrc = e.target.result
let data = atob(
reader.result.substring(reader.result.indexOf(',') + 1)
)
this.loadPdfData(data)
}
reader.readAsDataURL(raw)
}
},
loadPdfData(data) {
// 引入pdf.js的字体
let CMAP_URL = 'https://unpkg.com/pdfjs-dist@2.0.943/cmaps/'
//读取base64的pdf流文件
this.pdfData = pdfJS.getDocument({
data: data,
cMapUrl: CMAP_URL,
cMapPacked: true
})
this.renderPage(1)
},
// 上一页
clickPre() {
if (!this.renderingPage && this.currentPage && this.currentPage > 1) {
this.renderPage(this.currentPage - 1)
}
}
},
//下一页
clickNext() {
if (
!this.renderingPage &&
this.currentPage &&
this.currentPage < this.pageCount
) {
this.renderPage(this.currentPage + 1)
}
}
},
// 根据页码渲染相应的PDF
renderPage(num) {
this.renderingPage = true
this.pdfData.promise.then(pdf => {
this.pageCount = pdf.numPages
pdf.getPage(num).then(page => {
// 获取DOM中为预览PDF准备好的canvasDOM对象
let canvas = this.$refs.myCanvas
let ctx = canvas.getContext('2d')
// 获取页面比率
let ratio = window.devicePixelRatio || 1
console.log(ratio)
// 根据页面宽度和视口宽度的比率就是内容区的放大比率
let dialogWidth = this.$refs['canvasCont'].offsetWidth
let pageWidth = page.view[2] * ratio
let scale = dialogWidth / pageWidth
let viewport = page.getViewport({ scale: scale * 2 })
canvas.width = viewport.width * ratio
canvas.height = viewport.height * ratio
// 缩放比率
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
let renderContext = {
transform: [1, 0, 0, 1, 0, 0],
canvasContext: ctx,
viewport: viewport
}
page.render(renderContext).promise.then(() => {
this.renderingPage = false
this.currentPage = num
})
})
})
},
// 计算角度
_getRatio(ctx) {
let dpr = window.devicePixelRatio || 1
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1
return dpr / bsr
},
beforeFileUpload(file) {
const fileName = file.name
const fileType = this.fileType.split(',')
if (fileType.every(item => !fileName.endsWith(item))) {
this.$tip.warning(`请选择格式为${fileType.join('或')}类型的文件`)
return false
}
const { sizeLimit, sizeLimitWithUnit } = this
if (file.size > sizeLimit) {
this.$tip.warning(`文件大小不能超过${sizeLimitWithUnit},请重新选择`)
return false
}
return true
},
}
}
解决pdf显示模糊
很多文章介绍说调整显示区域大小,这样确实可以提高清晰度,当时当显示区域有限时就无法解决,因此解决方案采用将渲染canvas区域的scale翻倍,同时通过css的transform属性将区域大小设置成原来的一半。
这种方法的原理是增加渲染区域的物理像素数,从而提高图像的分辨率。
参考文章提高PDF预览的清晰度
.pdf-container {
transform: scale(0.5);
transform-origin: top left;
}
效果展示
这是修改之前显示pdf的质量
这是修改之后的质量,变清晰了许多