如何让PDF.js渲染的PDF文本支持选中功能?
解决PDF.js模态框中PDF文本不可选中的问题
在模态框中使用PDF.js渲染PDF后,无法选中文本以提取内容,现有代码已尝试添加文本层但未生效,以下是具体解决思路和修正后的代码。
核心解决思路
- 修正文本层定位:给
.modal-body添加position: relative,让绝对定位的.textLayer能相对于模态框内容区域正确定位,避免脱离可视范围。 - 补充文本层必要样式:添加PDF.js文本层所需的基础样式,让文本透明显示但保持可选中状态,同时确保文本块的排版与Canvas渲染内容对齐。
- 异步处理文本内容:等待
page.getTextContent()的Promise完成后再渲染文本层,确保传入有效的文本数据。 - 清理旧文本层:每次切换页面时清空
.textLayer,避免旧内容残留干扰新页面的文本选择。 - 移除无效设置:删除对Canvas的
userSelect设置,因为文本选中依赖于上层的文本层而非Canvas本身。
修正后的完整代码
{% extends 'base.html' %} {% block title %}Get Started{% endblock %} {% block content %} <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> <style> #get-started-page { text-align: center; margin-top: 50px; /* Add margin-top for space */ } .get-started-card { margin: auto; margin-bottom: 50px; padding: 20px; text-align: left; /* Align text to the left */ } .get-started-btn { margin-top: 10px; /* Add margin-top for space below the input */ } .modal-body { display: flex; align-items: center; justify-content: center; height: 80vh; /* Adjust the height of the modal body */ overflow-y: auto; /* Enable vertical scrolling if content exceeds the modal height */ position: relative; /* 新增:让文本层相对此容器定位 */ } #the-canvas { max-width: 100%; /* Make sure the canvas doesn't exceed its container */ max-height: 100%; /* Make sure the canvas doesn't exceed its container */ } .textLayer { position: absolute; top: 0; left: 0; height: 100%; width: 100%; --scale-factor: 1; /* Set the --scale-factor CSS variable */ pointer-events: none; /* 让文本层不阻挡Canvas的交互,但文本仍可选中 */ } /* 新增:PDF.js文本层必要样式 */ .textLayer > div { color: transparent; /* 文本透明,只保留选中功能 */ position: absolute; white-space: pre; cursor: text; pointer-events: auto; /* 允许文本块接收鼠标事件 */ transform-origin: 0% 0%; } .textLayer ::selection { background: rgba(0, 0, 255, 0.3); /* 选中时的高亮样式 */ } </style> <section id="get-started-page"> <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card bg-dark text-white transparent-card get-started-card"> <div class="card-body"> <h2 class="text-center mb-4">Get Started with IntelliQuest</h2> <div class="mb-3 centerrrrr"> <label class="form-label">Upload PDF</label> <div> <input type="file" accept=".pdf" id="pdfInput" /> </div> <button type="button" class="btn btn-primary get-started-btn" id="uploadButton">Upload PDF</button> </div> </div> </div> </div> </div> </div> </section> <!-- Bootstrap Modal --> <div class="modal fade" id="pdfModal" tabindex="-1" aria-labelledby="pdfModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="pdfModalLabel">Full-size PDF (Page 1 of 1)</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <canvas id="the-canvas"></canvas> <div class="textLayer"></div> </div> <!-- Add navigation buttons inside the modal --> <div class="modal-footer"> <button type="button" class="btn btn-secondary" id="prevPageBtn">Previous Page</button> <button type="button" class="btn btn-secondary" id="nextPageBtn">Next Page</button> </div> </div> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.js" integrity="sha512-dfMpvQclalfL7nRtHdy4+U2GLYb2XJJOgGLgKibrbcbarI/ZLgCAaBCS6+AuWN0OtLn/zFpu+Cggd8TCBYx9Ag==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> // Set the worker source for PDF.js pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.js'; function handleUpload() { var fileInput = document.getElementById('pdfInput'); var uploadButton = document.getElementById('uploadButton'); uploadButton.addEventListener('click', function () { var file = fileInput.files[0]; if (file) { var pdfUrl = URL.createObjectURL(file); loadPdf(pdfUrl); } else { alert('Please select a PDF file for upload.'); } }); } function loadPdf(url) { pdfjsLib.getDocument(url).promise.then(function (pdfDoc_) { pdfDoc = pdfDoc_; var canvas = document.getElementById('the-canvas'); var textLayer = document.querySelector(".textLayer"); var ctx = canvas.getContext('2d'); var scale = 1; var numPages = pdfDoc.numPages; var pageNum = 1; function renderPage(num) { pdfDoc.getPage(num).then(function (page) { var viewport = page.getViewport({ scale: scale }); canvas.height = viewport.height; canvas.width = viewport.width; var renderContext = { canvasContext: ctx, viewport: viewport }; page.render(renderContext); // 清空旧文本层内容 textLayer.innerHTML = ''; // 异步获取文本内容后渲染文本层 page.getTextContent().then(function(textContent) { pdfjsLib.textLayer.render({ textContent: textContent, container: textLayer, viewport: viewport, textDivs: [] }); }); // 更新模态框标题的页码 document.getElementById('pdfModalLabel').textContent = `Full-size PDF (Page ${num} of ${numPages})`; }); } renderPage(pageNum); document.getElementById('prevPageBtn').addEventListener('click', function () { if (pageNum > 1) { pageNum--; renderPage(pageNum); } }); document.getElementById('nextPageBtn').addEventListener('click', function () { if (pageNum < numPages) { pageNum++; renderPage(pageNum); } }); var pdfModal = new bootstrap.Modal(document.getElementById('pdfModal')); pdfModal.show(); }); } handleUpload(); </script> {% endblock %}
额外说明
修正后,你可以直接选中PDF上的文本,若要将选中内容提取到控制台,可添加如下监听事件(放在handleUpload函数之后或合适位置):
document.addEventListener('mouseup', function() { var selectedText = window.getSelection().toString().trim(); if (selectedText) { console.log('选中的文本:', selectedText); } });
内容的提问来源于stack exchange,提问作者ItsCoder1092
相关产品推荐
相关产品推荐

