文章目录
- 一、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 = pdfjsWorkerimport pdf from '/images/file/11.pdf'const state = reactive<any>({ pdfPath: pdf, // 本地PDF文件路径放在/public中 pdfPages: '', // 页数 pdfWidth: '', // 宽度 pdfSrc: '', // 地址 pdfScale: 1.0, // 放大倍数})let pdfDoc: any = nullonMounted(() => { loadFile(state.pdfPath)})function loadFile(url: string) { PDF.getDocument(url).promise.then((p: any) => { pdfDoc = p const { numPages } = p state.pdfPages = numPages nextTick(() => { 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 || 1 const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1 const ratio = dpr / bsr const viewport = page.getViewport({ scale: state.pdfScale }) canvas.width = viewport.width * ratio canvas.height = viewport.height * ratio canvas.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) => { // 创建文本图层div const 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 = null if (window.createObjectURL !== undefined) { // basic url = window.createObjectURL(file) } else if (window.webkitURL !== undefined) { // webkit or chrome try { 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('请选择需要导出的算法') } },