> 技术文档 > 前端使用pdf.js,pdf区域高亮展示(简单修改源码即可实现,仿ragflow文档块高亮渲染)_pdfjs

前端使用pdf.js,pdf区域高亮展示(简单修改源码即可实现,仿ragflow文档块高亮渲染)_pdfjs


前言

在处理 PDF 文档时,有时我们需要对特定区域进行高亮显示,以便快速定位和查看相关内容。PDF.js 是一个开源的 PDF 渲染库,通过修改其源码,我们可以实现 PDF 区域高亮预览的功能。本文将详细介绍如何通过修改 PDF.js 源码来实现这一功能。

需要事先说明的是,渲染位置是通过后端返回的position数组遍历去渲染的,本文的position坐标分别是页码,左边距坐标,右边距坐标,上边距坐标,下边距坐标,其实能根据返回值算出渲染的位置以及宽高即可,只是其他格式需要做适当修改。

正文

话不多说,直接进入正题,以下是可以实现的渲染效果:

思路

  1. 获取 PDF 页面信息:通过 PDF.js 的 API 获取当前 PDF 的页面信息,包括页面的视口(viewport)和页面视图(pageView)。

  2. 计算高亮区域坐标:根据传入的高亮区域坐标(相对于页面的原始坐标),将其转换为视口坐标。

  3. 绘制高亮矩形:使用 HTML5 的 Canvas 在页面上绘制高亮矩形,并将其添加到页面视图中。

  4. 跳转到第一个高亮区域所在页面:如果有高亮区域,自动跳转到第一个高亮区域所在的页面,方便用户查看。

核心代码实现

主要代码实现都在这个js文件中

highlightPositions 函数

该函数负责遍历传入的高亮区域位置数组,并调用 highlightOnPage 函数在对应的页面上绘制高亮矩形。如果存在高亮区域,还会自动跳转到第一个高亮区域所在的页面。】

function highlightPositions(positions) { // 确保 PDFViewerApplication 已经加载完成 if (!PDFViewerApplication.pdfViewer) { console.error(\'PDFViewerApplication is not initialized\') return } var firstPageNumber = null // 遍历 positions 数组,为每个位置绘制高亮矩形 positions.forEach(function (position, index) { var pageNumber = position[0] var x0 = position[1] var x1 = position[2] var top = position[3] var bottom = position[4] // 获取对应的 PDF 页面 var pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1) if (!pageView) { console.error(\'Page\', pageNumber, \'not found\') return } // 记录第一个高亮所在的页面编号 if (index === 0) { firstPageNumber = pageNumber } // 计算宽度和高度 var width = x1 - x0 var height = bottom - top // 绘制高亮矩形 highlightOnPage(pageView, x0, top, width, height) }) // 如果有高亮区域,跳转到第一个高亮所在的页面 if (firstPageNumber) { PDFViewerApplication.pdfViewer.scrollPageIntoView({ pageNumber: firstPageNumber, destArray: null, // 不指定具体位置,直接跳转到页面顶部 allowNegativeOffset: false, }) }}

highlightOnPage 函数

该函数负责在指定的页面上绘制高亮矩形。它会根据页面的视口信息将传入的坐标转换为视口坐标,然后使用 Canvas 绘制高亮矩形,并操作dom元素将其添加到页面视图中。

function highlightOnPage(pageView, x0, top, width, height) { // 确保页面已加载完成 if (!pageView || !pageView.pdfPage) { console.error(\'Page view is not ready\', pageView) return } // 获取页面的视口信息 const viewport = pageView.viewport // 将传入的坐标转换为视口坐标 const xViewport = x0 * viewport.scale const yViewport = top * viewport.scale const widthViewport = width * viewport.scale const heightViewport = height * viewport.scale // 创建一个 canvas 元素用于绘制高亮区域 const canvas = document.createElement(\'canvas\') const context = canvas.getContext(\'2d\') // 设置 canvas 的尺寸 canvas.width = widthViewport canvas.height = heightViewport // 设置高亮区域的样式 context.fillStyle = \'rgba(0, 255, 255, 0.2)\' // 蓝色半透明 // 绘制矩形(仅填充,不绘制边框) context.fillRect(0, 0, widthViewport, heightViewport) // 创建一个 div 用于放置 canvas const highlightLayer = document.createElement(\'div\') highlightLayer.style.position = \'absolute\' highlightLayer.style.left = xViewport + \'px\' highlightLayer.style.top = yViewport + \'px\' highlightLayer.style.width = widthViewport + \'px\' highlightLayer.style.height = heightViewport + \'px\' highlightLayer.appendChild(canvas) // 将高亮层添加到页面中 pageView.div.appendChild(highlightLayer)}

之后,我将调用方法放在function webViewerPageRendered中

 //获取链接 var urlPath = decodeURIComponent(window.location.href)  //从要渲染的pdf的URL获取position var index = urlPath.indexOf(\'&positions=\') if (index !== -1) { var positionsParam = urlPath.substr(index + 11) // 跳过 \'&positions=\' try {  var positions = JSON.parse(decodeURIComponent(positionsParam))  highlightPositions(positions) } catch (e) {  console.error(\'Error parsing positions:\', e) } }

而在vue中,我在组件中暴露showPdf方法供父组件调用,并接收position参数,当然,各位也可以一开始就把参数信息放在url中通过props一并传入,实现方法多种多样。

import { ref } from \'vue\'interface Props { url: string // 实际pdf文件地址}const props = defineProps()fileUrl = \'../../pdfjs/web/viewer.html?file=\' //替换为实际地址const pdfUrl = ref(\'\') // pdf文件地址const showPdf = (position?: any) => { // 如果 position 未定义或为空,则使用空数组 const positions = position || []; // 将高亮区域位置数组转换为 JSON 字符串并进行 URI 编码 const encodedPositions = encodeURIComponent(JSON.stringify(positions)); // 构造 PDF.js 查看器的 URL let url = `${fileUrl}${encodeURIComponent(props.url)}`; if (encodedPositions) { url += `&positions=${encodedPositions}`; } // 更新 pdfUrl 的值 pdfUrl.value = url;}defineExpose({ showPdf,})

注意事项

  1. 坐标系转换:传入的高亮区域坐标需要根据页面的视口信息进行转换,以确保高亮矩形的正确显示。

  2. 性能优化:在绘制大量高亮区域时,需要注意性能优化,避免对页面性能产生较大影响。

  3. 样式自定义:可以通过修改 highlightOnPage 函数中的样式设置,自定义高亮区域的颜色和透明度等。

总结

通过修改 PDF.js 源码,我们可以轻松实现 PDF 区域高亮预览的功能。本文提供的代码示例和实现思路可以作为参考,帮助你在实际项目中快速实现该功能。希望本文对你有所帮助!