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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:07:04