基于pdf.js的PDF查看器:鼠标框选提取文本功能实现求助
解决PDF.js iframe嵌入场景下矩形框选提取文本的问题
核心问题剖析
能绘制矩形但无法提取文本,核心原因有两个:
- iframe的跨域隔离限制:若主页面与iframe内PDF.js页面域名/端口不一致,主页面JS无法直接访问iframe内的PDF实例与文本数据。
- 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
相关产品推荐
相关产品推荐

