You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于pdf.js的PDF查看器:鼠标框选提取文本功能实现求助

解决PDF.js iframe嵌入场景下矩形框选提取文本的问题

核心问题剖析

能绘制矩形但无法提取文本,核心原因有两个:

  1. iframe的跨域隔离限制:若主页面与iframe内PDF.js页面域名/端口不一致,主页面JS无法直接访问iframe内的PDF实例与文本数据。
  2. PDF.js默认用canvas渲染内容,常规DOM文本选区API(如window.getSelection())完全无效,必须调用PDF.js专属的文本定位API匹配矩形区域。

具体实现方案

第一步:确保iframe同域(或配置跨域许可)

同域场景直接跳过;不同域时,要么将PDF页面迁移至主站域名下,要么在PDF页面响应头添加Access-Control-Allow-Origin: 主页面域名,同时给iframe设置allow="same-origin"属性。

第二步:在PDF.js页面封装文本提取方法

不在主页面直接操作,而是在iframe内的PDF.js代码中添加坐标匹配文本的函数:

// 假设已初始化PDFViewerApplication
async function getTextInRect(x1, y1, x2, y2) {
  const page = PDFViewerApplication.page;
  if (!page) return '';
  
  // 转换页面坐标为PDF内部坐标(PDF原点在左下角,canvas在左上角)
  const viewport = page.getViewport({ scale: page.viewport.scale });
  const pdfX1 = Math.min(x1, x2) / viewport.scale;
  const pdfY1 = viewport.height - Math.max(y1, y2) / viewport.scale;
  const pdfX2 = Math.max(x1, x2) / viewport.scale;
  const pdfY2 = viewport.height - Math.min(y1, y2) / viewport.scale;

  // 获取页面文本内容
  const textContent = await page.getTextContent();
  let selectedText = '';

  // 遍历文本块,判断是否在矩形范围内
  textContent.items.forEach(item => {
    const itemX = item.transform[4];
    const itemY = item.transform[5];
    const itemWidth = item.width;
    const itemHeight = item.height;

    // 判断文本块与矩形是否有交集
    if (!(itemX + itemWidth < pdfX1 || itemX > pdfX2 || itemY + itemHeight < pdfY1 || itemY > pdfY2)) {
      selectedText += item.str;
    }
  });

  return selectedText;
}

// 暴露给主页面调用(同域场景生效)
window.getTextInRect = getTextInRect;

第三步:主页面传递坐标并获取文本

主页面完成矩形绘制后,将坐标(相对于iframe的canvas)传递给iframe,调用提取方法:

// 假设iframe元素id为pdfIframe,结果文本框id为resultText
const iframe = document.getElementById('pdfIframe');
const resultText = document.getElementById('resultText');

// 假设已通过鼠标事件获取矩形坐标:startX, startY, endX, endY
async function extractSelectedText() {
  try {
    // 转换坐标为iframe内部canvas的相对坐标
    const rect = iframe.getBoundingClientRect();
    const canvasX = startX - rect.left;
    const canvasY = startY - rect.top;
    const canvasEndX = endX - rect.left;
    const canvasEndY = endY - rect.top;

    // 调用iframe内的提取方法
    const text = await iframe.contentWindow.getTextInRect(canvasX, canvasY, canvasEndX, canvasEndY);
    resultText.value = text;
  } catch (err) {
    console.error('提取文本失败:', err);
  }
}

常见坑点排查

  • 禁止使用document.execCommand('copy')或常规选区API:PDF基于canvas渲染,无DOM文本节点,此类方法完全无效。
  • 确保PDF页面加载完成:调用getTextInRect前,需确认PDFViewerApplication.page不为空,可通过监听pagedisplayed事件判断:document.addEventListener('pagedisplayed', () => { /* 页面加载完成 */ })。
  • 坐标转换必须准确:PDF坐标原点在左下角,canvas在左上角,需用viewport.height翻转Y轴。

内容的提问来源于stack exchange,提问作者TheNates

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:06:39