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

前言

在处理 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一并传入,实现方法多种多样。

<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>

注意事项

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

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

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

总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值