前言
在处理 PDF 文档时,有时我们需要对特定区域进行高亮显示,以便快速定位和查看相关内容。PDF.js 是一个开源的 PDF 渲染库,通过修改其源码,我们可以实现 PDF 区域高亮预览的功能。本文将详细介绍如何通过修改 PDF.js 源码来实现这一功能。
需要事先说明的是,渲染位置是通过后端返回的position数组遍历去渲染的,本文的position坐标分别是页码,左边距坐标,右边距坐标,上边距坐标,下边距坐标,其实能根据返回值算出渲染的位置以及宽高即可,只是其他格式需要做适当修改。
正文
话不多说,直接进入正题,以下是可以实现的渲染效果:
思路
-
获取 PDF 页面信息:通过 PDF.js 的 API 获取当前 PDF 的页面信息,包括页面的视口(viewport)和页面视图(pageView)。
-
计算高亮区域坐标:根据传入的高亮区域坐标(相对于页面的原始坐标),将其转换为视口坐标。
-
绘制高亮矩形:使用 HTML5 的 Canvas 在页面上绘制高亮矩形,并将其添加到页面视图中。
-
跳转到第一个高亮区域所在页面:如果有高亮区域,自动跳转到第一个高亮区域所在的页面,方便用户查看。
核心代码实现
主要代码实现都在这个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一并传入,实现方法多种多样。
<script setup lang="ts">
import { ref } from 'vue'
interface Props {
url: string // 实际pdf文件地址
}
const props = defineProps<Props>()
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,
})
</script>
注意事项
-
坐标系转换:传入的高亮区域坐标需要根据页面的视口信息进行转换,以确保高亮矩形的正确显示。
-
性能优化:在绘制大量高亮区域时,需要注意性能优化,避免对页面性能产生较大影响。
-
样式自定义:可以通过修改
highlightOnPage
函数中的样式设置,自定义高亮区域的颜色和透明度等。
总结
通过修改 PDF.js 源码,我们可以轻松实现 PDF 区域高亮预览的功能。本文提供的代码示例和实现思路可以作为参考,帮助你在实际项目中快速实现该功能。希望本文对你有所帮助!