vue3项目使用pdf.js插件实现文本复制、文本搜索内容高亮展示
文章目录
-
- 一、pdf.js介绍
- 二、实现pdf预览的两种方式
-
- 1、使用viewer.html
- 2、将PDF文件渲染成Canvas
一、pdf.js介绍
官网地址:http://mozilla.github.io/pdf.js/
PDF.js是基于HTML5技术构建的,用于展示可移植文档格式的文件(PDF),它可以在现代浏览器中使用且无需安装任何第三方插件。
pdf.js主要包含两个库文件
pdf.js:负责API解析
pdf.worker.js:负责核心解析
二、实现pdf预览的两种方式
1、使用viewer.html
-
从官网下载pdf.js包
下载地址:https://mozilla.github.io/pdf.js/getting_started/#download -
引入pdf.js包
可将pdf.js包 放到服务器上 如:http://xxxx:8080/static/pdfjs
也可将pdf.js包直接解压在public文件夹下 -
使用iframe标签显示pdf
1)若pdf.js包及pdf文件都在服务器上部署
<iframe :src="url" width="100%" height="100%" frameborder="0"></iframe>
pdfServerUrl = 'http://xxxx:8080/static/pdfjs/web/viewer.html'
pdfInfoUrl = 'http://xxxx:8080/XXX/getClausePdf?Code=1234'
url = `${pdfServerUrl}?file=${encodeURIComponent(pdfInfoUrl)}` // 调取接口返回文件流
2)若pdf.js包及pdf文件都在本地
<iframe :src="`/PDF.js/web/viewer.html?file=${pdf}` width="100%" height="100%" frameborder="0"></iframe><script>import pdf from '/images/file/11.pdf'
</script>
注:
此方法可以实现pdf的预览、全文搜索、搜索内容高亮展示、文本复制的功能
3)若要实现外部操作跳转到具体的某一页
需要修改viewer.js源码,添加一个可供页面跳转的参数page
<iframe :src="`/PDF.js/web/viewer.html?file=${pdf}&page=${pageNum}`` width="100%" height="100%" frameborder="0"></iframe><script>import pdf from '/images/file/11.pdf'const pageNum = 1
</script>
2、将PDF文件渲染成Canvas
安装
pnpm i pdfjs-dist // "pdfjs-dist": "^3.5.141"
在vue页面
<template><div id="pdf-container"><canvas v-for="page in state.pdfPages" :key="page" :id="`pdfCanvas${page}`" style="border-bottom:1px solid #d4d2d2" /></div>
</template>
import * as PDF from 'pdfjs-dist'
const pdfjsWorker = import('pdfjs-dist/build/pdf.worker.entry')
PDF.GlobalWorkerOptions.workerSrc = pdfjsWorker
import pdf from '/images/file/11.pdf'const state = reactive<any>({pdfPath: pdf, // 本地PDF文件路径放在/public中pdfPages: '', // 页数pdfWidth: '', // 宽度pdfSrc: '', // 地址pdfScale: 1.0, // 放大倍数
})
let pdfDoc: any = null
onMounted(() => {loadFile(state.pdfPath)
})
function loadFile(url: string) {PDF.getDocument(url).promise.then((p: any) => {pdfDoc = pconst { numPages } = pstate.pdfPages = numPagesnextTick(() => {renderPage(1) // 从第一页开始渲染})})
}
function renderPage(num: number) {pdfDoc.getPage(num).then((page: any) => {const canvas: any = document.getElementById(`pdfCanvas${num}`)const ctx = canvas.getContext('2d')const dpr = window.devicePixelRatio || 1const bsr= ctx.webkitBackingStorePixelRatio|| ctx.mozBackingStorePixelRatio|| ctx.msBackingStorePixelRatio|| ctx.oBackingStorePixelRatio|| ctx.backingStorePixelRatio|| 1const ratio = dpr / bsrconst viewport = page.getViewport({ scale: state.pdfScale })canvas.width = viewport.width * ratiocanvas.height = viewport.height * ratiocanvas.style.width = '100%'canvas.style.height = '100%'state.pdfWidth = `${viewport.width}px`ctx.setTransform(ratio, 0, 0, ratio, 0, 0)// 将 PDF 页面渲染到 canvas 上下文中const renderContext = {canvasContext: ctx,viewport,}page.render(renderContext)if (state.pdfPages > num)renderPage(num + 1)})
}
注:
此代码只能实现pdf预览功能,如果要文本复制,要使用Text-Layers渲染
使用到的函数解读
getDocument():用于异步获取PDf文档,发送多个Ajax请求以块的形式下载文档。它返回一个Promise,该Promise的成功回调传递一个对象,该对象包含PDF文档的信息,该回调中的代码将在完成PDf文档获取时执行。
getPage():用于获取PDF文档中的各个页面。
getViewport():针对提供的展示比例,返回PDf文档的页面尺寸。
render():渲染PDF。
如果要文本复制,需要将page.render(renderContext)修改为以下代码:
// 要引入组件
import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer.js'
import 'pdfjs-dist/web/pdf_viewer.css'
page.render(renderContext).then(() => {return page.getTextContent();
}).then((textContent) => {// 创建文本图层divconst textLayerDiv = document.createElement('div');textLayerDiv.setAttribute('class', 'textLayer');// 将文本图层div添加至每页pdf的div中pageDiv.appendChild(textLayerDiv);// 创建新的TextLayerBuilder实例var textLayer = new TextLayerBuilder({textLayerDiv: textLayerDiv,pageIndex: page.pageIndex,viewport: viewport}); textLayer.setTextContent(textContent); textLayer.render();
});
重点函数解读:
page.render():该函数返回一个当PDF页面成功渲染到界面上时解析的promise,我们可以使用成功回调来渲染文本图层。
page.getTextContent():该函数的成功回调会返回PDF页面上的文本片段。
TextLayerBuilder:该类的实例有两个重要的方法。setTextContent()用于设置page.getTextContent()函数返回的文本片段;render()用于渲染文本图层。
如果后端返回的是流的形式,就用此方法转一下
/* 流转成url*/getObjectURL(file) {let url = nullif (window.createObjectURL !== undefined) { // basicurl = window.createObjectURL(file)} else if (window.webkitURL !== undefined) { // webkit or chrometry {url = window.webkitURL.createObjectURL(file)} catch (error) {console.log(error)}} else if (window.URL !== undefined) { // mozilla(firefox)try {url = window.URL.createObjectURL(file)} catch (error) {console.log(error)}}return url},
下载
fileDownload() {if (this.src) {var tempLink = document.createElement('a')tempLink.style.display = 'none'tempLink.href = this.PDF // 解析好的地址tempLink.setAttribute('download', this.fileName)if (typeof tempLink.download === 'undefined') {tempLink.setAttribute('target', '_blank')}document.body.appendChild(tempLink)tempLink.click()document.body.removeChild(tempLink)window.URL.revokeObjectURL(this.PDF)} else {this.$message.error('请选择需要导出的算法')}},