如何在无iframe页面嵌入PDF.JS并修复文本层显示异常
Fixing PDF.js Text Layer Display Issues (Without Full Viewer)
我完全懂你的感受——PDF.js重构到pdfjsLib之后,轻量场景的文档确实不够完善,明明是应用这么广的库,想不依赖臃肿的viewer实现基础PDF显示+文本层功能,踩坑是真的闹心。你的文本层显示异常主要是几个细节没处理到位,咱们一步步来修复:
核心问题分析
你的代码里有几个关键问题导致文本层错位或无法正常显示:
- 定位单位缺失:给
top/left/width/height赋值时没加px单位,浏览器无法正确解析样式 - 文件读取方式过时:
readAsBinaryString已经被废弃,用arrayBuffer更稳定且符合PDF.js官方推荐 - 缩放未同步:canvas用了
scale:0.5,但文本层的缩放逻辑没跟上,导致错位 - 冗余参数干扰:手动传入
textDivs: []反而会影响文本层的自动生成逻辑
完整修复代码
HTML
<p>Select a PDF file:</p> <input id="reportInput" type="file" accept="application/pdf" onchange="displayReport()"/> <!-- 给容器加相对定位,确保文本层定位基准正确 --> <div id="reportWrapper" style="position: relative;"> <canvas id="reportCanvas"></canvas> <div id="reportTextLayer"></div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.js"></script>
CSS
#reportWrapper { position: relative; /* 可选:限制容器宽度,避免PDF过宽撑爆页面 */ max-width: 800px; } #reportTextLayer { position: absolute; top: 0; left: 0; overflow: hidden; opacity: 0.2; line-height: 1.0; /* 和canvas保持一致的缩放比例,确保对齐 */ transform: scale(0.5); transform-origin: top left; } #reportTextLayer > div { color: transparent; position: absolute; white-space: pre; cursor: text; transform-origin: 0% 0%; /* 调试时可以打开这个背景色,方便查看文本层位置,完成后可删除 */ /* background: rgba(255, 0, 0, 0.1); */ }
JavaScript
document.addEventListener('DOMContentLoaded', () => { pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.worker.js'; }); async function displayReport() { const file = document.getElementById('reportInput').files[0]; if (!file) return; // 改用arrayBuffer读取文件,替代已废弃的readAsBinaryString const arrayBuffer = await file.arrayBuffer(); const pdf = await pdfjsLib.getDocument({data: arrayBuffer}).promise; const page = await pdf.getPage(1); const scale = 0.5; const viewport = page.getViewport({scale}); const canvas = document.getElementById('reportCanvas'); const context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; const renderContext = { canvasContext: context, viewport }; await page.render(renderContext).promise; const textContent = await page.getTextContent(); const textLayer = document.getElementById('reportTextLayer'); // 每次渲染前清空文本层,避免多次上传PDF时文本叠加 textLayer.innerHTML = ''; // 移除冗余的textDivs参数,让函数自动生成文本元素 await pdfjsLib.renderTextLayer({ textContent, container: textLayer, viewport }); console.log("Page rendered with functional text layer!"); }
关键修改说明
- 定位基准优化:给
reportWrapper添加position: relative,让文本层相对于容器定位,不会因为页面滚动而错位 - 缩放同步处理:文本层直接通过
transform: scale(0.5)和canvas保持一致的缩放比例,比动态计算getBoundingClientRect更稳定 - 文件读取升级:用
arrayBuffer替代废弃的readAsBinaryString,这是PDF.js官方推荐的文件读取方式 - 冗余参数清理:移除
textDivs: [],让renderTextLayer自动生成文本div元素,避免干扰默认逻辑 - 文本层重置:每次渲染前清空文本层内容,防止多次上传PDF时文本叠加
修改完成后,文本层就能和canvas完美对齐,你可以正常选中文本,后续也能轻松给指定文本添加tooltip——只需要遍历textContent里的字符块,找到对应文本的div元素绑定事件即可。
内容的提问来源于stack exchange,提问作者JacopoStanchi
相关产品推荐
相关产品推荐

