Svelte中使用pdfjs-dist无法渲染PDF注释层求助
PDF.js渲染PDF时注释层(高亮文本)无法显示的问题
我需要渲染包含高亮文本注释层的PDF文件,使用pdfjs-dist可以正常展示PDF内容,但注释层(高亮文本形式)未能正确显示。试过其他库得到相同结果,目前唯一的解决办法是使用iframe,但我希望避免这种方式——因为打算集成PDF导航按钮,不想让iframe重载。
编辑:检查PDF文件后确认,问题并非出在覆盖层,而是注释层未正确渲染。
当前Svelte组件代码
<script lang="ts"> import { onMount } from 'svelte'; import * as pdfjs from 'pdfjs-dist'; import { Icon } from '@webcms/component-library'; export let currPage = 0; export let blob: Blob | undefined = undefined; export let hasErrors = false; let loaded = false; $: if (currPage) { scrollToPage(currPage); } pdfjs.GlobalWorkerOptions.workerSrc = new URL( 'pdfjs-dist/build/pdf.worker.js', import.meta.url ).toString(); let canvas: HTMLCanvasElement; let pdfDoc: pdfjs.PDFDocumentProxy | null = null; onMount(async () => { pdfDoc = null; if (blob) { let arryBuffer = await blob.arrayBuffer(); pdfjs .getDocument(arryBuffer) .promise.then(function (pdf) { pdfDoc = pdf; let viewer = document.getElementById('pdf-viewer'); for (let page = 1; page <= pdf.numPages; page++) { canvas = document.createElement('canvas'); canvas.className = 'pdf-page-canvas'; viewer?.appendChild(canvas); renderPage(page, canvas); } }) .catch((e) => { hasErrors = true; console.error(e); }); } loaded = true; }); /** * Scrolls to a specific page in the viewer. * * @param {number} pageNumber - The page number to scroll to. */ function scrollToPage(pageNumber: number) { const canvasElement = document.querySelector('.pdf-page-canvas:nth-child(' + pageNumber + ')'); if (canvasElement) { canvasElement.scrollIntoView(); } } /** * Renders a specific page of a PDF document onto a canvas element. * * @param {number} pageNumber - The page number to render. * @param {HTMLCanvasElement} canvas - The canvas element to render onto. */ function renderPage(pageNumber: number, canvas: HTMLCanvasElement) { pdfDoc?.getPage(pageNumber).then(function (page) { let viewport = page.getViewport({ scale: window.innerWidth < 1300 ? 1 : 2 }); let context = canvas.getContext('2d'); if (context) { canvas.width = viewport.width * 2; canvas.height = viewport.height * 2; context.scale(2, 2); page.render({ canvasContext: context, viewport: viewport }); if (pageNumber === currPage) { canvas.scrollIntoView(); } } }); } </script> {#if loaded} <div class="pdf-layout"> <div id="pdf-viewer" /> </div> {/if}
解决方案
pdfjs-dist默认不会自动渲染注释层,需要手动获取注释数据并绘制到canvas上。以下是修改后的核心逻辑:
1. 获取并渲染高亮注释
修改renderPage函数,在页面渲染完成后,获取页面的高亮注释,转换坐标后绘制到canvas上:
function renderPage(pageNumber: number, canvas: HTMLCanvasElement) { pdfDoc?.getPage(pageNumber).then(async function (page) { let viewport = page.getViewport({ scale: window.innerWidth < 1300 ? 1 : 2 }); let context = canvas.getContext('2d'); if (context) { canvas.width = viewport.width * 2; canvas.height = viewport.height * 2; context.scale(2, 2); // 先渲染页面内容,等待渲染完成 await page.render({ canvasContext: context, viewport: viewport }).promise; // 获取页面所有注释,筛选高亮类型 const annotations = await page.getAnnotations(); const highlightAnnotations = annotations.filter(anno => anno.subtype === 'Highlight'); // 设置高亮样式:半透明黄色,可按需调整 context.fillStyle = 'rgba(255, 255, 0, 0.3)'; highlightAnnotations.forEach(anno => { // 将PDF内部坐标转换为canvas显示坐标 const viewportRect = viewport.convertToViewportRectangle(anno.rect); // 绘制高亮矩形 context.fillRect( viewportRect[0], viewportRect[1], viewportRect[2] - viewportRect[0], viewportRect[3] - viewportRect[1] ); }); if (pageNumber === currPage) { canvas.scrollIntoView(); } } }); }
2. 关键说明
- 通过
page.getAnnotations()获取页面所有注释,利用subtype === 'Highlight'筛选出高亮注释 - 使用
viewport.convertToViewportRectangle()完成PDF内部坐标到canvas显示坐标的转换 - 高亮样式可自定义:调整
fillStyle的颜色值和透明度即可模拟不同的高亮效果 - 必须等待页面渲染完成后再绘制注释,避免被页面内容覆盖
内容的提问来源于stack exchange,提问作者JHM
相关产品推荐
相关产品推荐

