> 文章列表 > vue3项目使用pdf.js插件实现文本复制、文本搜索内容高亮展示

vue3项目使用pdf.js插件实现文本复制、文本搜索内容高亮展示

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

  1. 从官网下载pdf.js包
    下载地址:https://mozilla.github.io/pdf.js/getting_started/#download

  2. 引入pdf.js包
    可将pdf.js包 放到服务器上 如:http://xxxx:8080/static/pdfjs
    也可将pdf.js包直接解压在public文件夹下

  3. 使用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('请选择需要导出的算法')}},