@epam/pdf-highlighter-kit

中文文档
0.0.22发布于 2026/11/10Apache-2.0TypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 1万

具有智能突出显示和文本选择能力的高性能 PDF 查看器

中文使用文档
文档目录20 节
  1. 安装
  2. 快速启动
  3. 数据模型
  4. InputHighlightData
  5. 配置选项
  6. 查看器选项
  7. API 参考
  8. 主要方法
  9. 活动
  10. 高级使用
  11. 页面缩略图
  12. 自定义样式( 每高亮)
  13. 他们
  14. 有图标的标签( 如 Taller 图标)
  15. 反应集成
  16. 浏览器支持
  17. 所需资源
  18. 许可证
  19. 捐款
  20. 支助

PDF 高亮查看器

高性能的PDF取景器,具有智能突出显示和网络应用的文本选择能力.

npm version License PRs Welcome

开源项目 巴德尔Doc BadgerDoc


安装

npm install @epam/pdf-highlighter-kit pdfjs-dist

同伴依赖 : pdfjs-dist (见要求).

快速启动

import { PDFHighlightViewer } from '@epam/pdf-highlighter-kit';
import type { InputHighlightData } from '@epam/pdf-highlighter-kit';
import '@epam/pdf-highlighter-kit/styles/pdf-highlight-viewer.css';

// Create viewer instance
const viewer = new PDFHighlightViewer();

// Initialize with container element
const container = document.getElementById('pdf-container') as HTMLElement;

await viewer.init(container, {
  enableTextSelection: true,
  enableVirtualScrolling: true,
  bufferPages: 2,
  maxCachedPages: 10,
  interactionMode: 'hybrid',
});

// Load PDF document
await viewer.loadPDF('/path/to/document.pdf');

// Highlights
const highlights: InputHighlightData[] = [
  {
    id: 'term-001',
    bboxes: [
      // page is 1-based
      { page: 1, x1: 100, y1: 200, x2: 300, y2: 220 },
      { page: 3, x1: 80, y1: 140, x2: 260, y2: 160 },
    ],
    style: {
      backgroundColor: '#ffeb3b',
      opacity: 0.3,
      borderColor: '#d4c400',
      borderWidth: '1px',
    },
    label: 'Important Term',
    labelStyle: { fontSize: 11 },
    tooltipText: 'Important Term',
    metadata: {
      frequency: 5,
      tags: ['important', 'glossary'],
    },
  },
];

viewer.loadHighlights(highlights);

// Navigate to a highlight occurrence
viewer.goToHighlight('term-001', 0);

数据模型

InputHighlightData

每个亮点都带有自己的风格. 不需要类别.

标签 : 您可以添加可选 label 显示在亮点左侧,并冲向它。 默认情况下,标签使用亮点的颜色(从 style.borderColor 或者说 style.backgroundColor, (中文(简体) ), border: 1px solid,以及 padding: 2px 4px。用 labelStyle (例如:. fontSize, (中文(简体) ), color, (中文(简体) ), padding, (中文(简体) ), border) (中文(简体) ). 要隐藏标签边框, 设置 labelStyle: { border: 'none' } (默认边框除非被推翻,否则总是适用).

标签前的图标 : 可选设置 beforeIcon 改为内置 SVG 字符串(例如: 表格图标)在标签框内使图标出自文字的左边。 图标通过 currentColor启用 labelStyle.iconSize 以设置图标大小(例如). 14 或者说 '14px'和 labelStyle.iconColor 以设置图标颜色(例如). '#ff6b6b'; 如果 iconColor 未设置,图标使用标签文本颜色。 只能通过信任的 SVG 内容(例如从您的捆绑或 @tabler/icons); 在“与 Vite 反应”中, 您可以使用 import iconSvg from '@tabler/icons/icons/outline/alert-circle.svg?raw' 通过 iconSvg 作为 beforeIcon。 。 。 .

可缩放标签 : 设定 isLabelScalable: true 因此标签的大小(font, padding, 图标, 边框半径) 缩放; 标签与突出显示成正比 。 边框和轮廓厚度没有缩放(它们像亮点的轮廓一样固定)。 最佳用法为 labelStyle 数值 px 或数字.

export interface BBox {
  x1: number;
  y1: number;
  x2: number;
  y2: number;
  page: number;
}

export interface BBoxDimensions {
  width: number;
  height: number;
}

export type BBoxOrigin = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';

export type InteractionMode = 'select' | 'highlight' | 'hybrid';

export interface HighlightStyle {
  backgroundColor: string;
  borderColor?: string;
  borderWidth?: string;
  outline?: string;
  opacity?: number;
  hoverOpacity?: number;
  pulseAnimation?: boolean;
}

export interface HighlightLabelStyle {
  fontSize?: string | number;
  opacity?: number;
  color?: string;
  backgroundColor?: string;
  padding?: string;
  borderRadius?: string; // e.g. '2px' or shorthand '2px 2px 0 0'
  fontFamily?: string;
  fontWeight?: string | number;
  border?: string;
  borderColor?: string;
  borderWidth?: string;
  outline?: string;
  whiteSpace?: string;
  iconSize?: string | number; // size for beforeIcon (e.g. 14 or '14px')
  iconColor?: string;
  offsetLeft?: number;
  offsetTop?: number;
  outlineRight?: string;
}

export interface InputHighlightData {
  id: string;
  bboxes: BBox[];
  bboxOrigin?: BBoxOrigin;
  bboxSourceDimensions?: BBoxDimensions;
  style?: HighlightStyle;
  label?: string;
  beforeIcon?: string; // inline SVG string (trusted content only, e.g. Tabler icons)
  isLabelScalable?: boolean; // when true, label size scales with zoom (borders stay fixed)
  labelStyle?: HighlightLabelStyle;
  tooltipText?: string;
  metadata?: Record<string, any>;
}

若为 bboxSourceDimensions 提供每个 bbox 坐标根据实际页数重新计算:

scaledX = (x / bboxSourceDimensions.width) * actualPageWidth;
scaledY = (y / bboxSourceDimensions.height) * actualPageHeight;

优先权(最高至最低):

  • highlight.bboxOrigin 编号 : highlight.bboxSourceDimensions
  • 全局查看器选项( e)bboxOrigin, (中文(简体) ), bboxSourceDimensions(中文(简体) )

配置选项

查看器选项

export interface HighlightsConfig {
  enableMultilineHover?: boolean;
  defaultStyle?: HighlightStyle;
}

export interface ViewerOptions {
  // Enable text selection functionality
  enableTextSelection?: boolean;

  // Enable virtual scrolling for better performance
  enableVirtualScrolling?: boolean;

  // Number of pages to buffer above/below viewport
  bufferPages?: number;

  // Maximum number of pages to keep in cache
  maxCachedPages?: number;

  // Interaction mode: 'select' | 'highlight' | 'hybrid'
  interactionMode?: InteractionMode;

  // Performance mode (smaller frame budget)
  performanceMode?: boolean;

  // Enable accessibility helpers
  accessibility?: boolean;

  // Highlight UI config (style is per highlight)
  highlightsConfig?: HighlightsConfig;

  // Coordinate origin for incoming bbox values
  // Default: 'bottom-right'
  bboxOrigin?: BBoxOrigin;

  // Page dimensions for which bbox coordinates were calculated
  bboxSourceDimensions?: BBoxDimensions;

  // Only show these document page numbers (1-based). If empty or omitted, all pages are shown.
  selectedPages?: number[];
}

只显示所选页面 : 使用 selectedPages 以显示文档的子集(例如. [1, 3, 5] 或者说 [2, 4, 6, 8]) (中文(简体) ). 完整的PDF仍然被加载;只有列出的页面获得DOM容器并参与滚动和渲染. API中的页码(例如:. setPage,事件,要闻)仍然是物理文档的页码. 你可以通过 selectedPages 内 init 选项或每个负载通过 loadPDF(source, { selectedPages }); 后者覆盖了该负载的输入值. getTotalPages() 返回显示列表的长度,当 selectedPages 已经设定.

API 参考

主要方法

init(container: HTMLElement, config?: ViewerOptions): Promise<void>

用容器元素和可选配置初始化取景器.

loadPDF(source: string | ArrayBuffer | Blob, options?: LoadPDFOptions): Promise<void>

从 URL 或 ArrayBuffer 中装入 PDF 文档。 可选的第二个论点:

interface LoadPDFOptions {
  /** Only show these document page numbers (1-based). If empty or omitted, all pages are shown. */
  selectedPages?: number[];
}

示例 await viewer.loadPDF(url, { selectedPages: [1, 3, 5] }); 仅显示第1、第3和第5页。 何时 options.selectedPages 提供,它覆盖 ViewerOptions.selectedPages 为了这个负载.

loadHighlights(highlights: InputHighlightData[]): void

以所提供的列表替换当前亮点 .

addHighlight(highlight: InputHighlightData): void

增加一分亮度(递增更新).

removeHighlight(termId: string): void

删除其突出显示 id。 。 。 .

updateHighlightStyle(termId: string, stylePatch: Partial<HighlightStyle>, labelStylePatch?: Partial<HighlightLabelStyle>): void

由 id 更新突出显示样式( patch 合并) 。 可选通过 labelStylePatch 也可以更新标签样式.

goToHighlight(termId: string, occurrenceIndex?: number): void

导航到特定的突出显示事件 . occurrenceIndex 默认为 0。 。 。 .

nextHighlight(): void 编号 : previousHighlight(): void

按文档顺序浏览所有突出事件.

setPage(pageNumber: number): void

导航到一个特定的页面(1个基于).

zoomIn(): void 编号 : zoomOut(): void

在保留读取位置的同时缩放或退出 PDF 。 在浏览到一页后,突出显示或协调该目标在缩放时会停留在同一个取景点位置上,即使相邻的取景点占据了更多的取景点. 同一页和PDF-空间位置在连续的缩放变化中保持固定状态,包括当相邻页面在较小的尺度上变得更加明显时。 滚动或清晰的页面导航建立了一个新的锚. 页面检测使用实际的页面边框,包括对有混合页面大小的文档. 缩放承诺页面大小并一起滚动;上页图像在屏幕上保持缩放,直到新光栅准备好,而不改变加载指标的页面高度.

setZoom(value: ZoomMode | number): void

设定一个特定的缩放水平(例如:100%为1.0,150%为1.5). 读取位置保持不变 zoomIn() 财务报告和审定财务报表 zoomOut()。 。 。 .

getThumbnails(pageNumbers: number[], options?: ThumbnailOptions): Promise<Map<number, HTMLCanvasElement>>

给定的页码的 Render 页面缩略图( 最小) 。 回返a Map 的页码。 需要画布元素(例如用于绘图或自定义显示)时使用此功能. 选项 : maxWidth (目标宽度为px), scale (视图比例).

getThumbnailsDataUrl(pageNumbers: number[], options?: ThumbnailOptions): Promise<Map<number, string>>

与 getThumbnails 但返回数据 URL(例如用于 <img src="...">) (中文(简体) ). 选项包括 maxWidth, (中文(简体) ), scale, (中文(简体) ), format (单位:千美元)'image/jpeg' | 'image/webp' | 'image/png'),以及 quality (jpeg/webp为0–1). 缩略图被缓存; 重复调用同一页返回缓存结果 .

destroy(): void

清取并毁观相例.

活动

观众发布各种事件,你可以收听:

viewer.addEventListener('initialized', () => {
  console.log('Viewer initialized');
});

viewer.addEventListener('pdfLoaded', (e) => {
  console.log('PDF loaded. Total pages:', e.totalPages);
});

viewer.addEventListener('pageChanged', (e) => {
  console.log('Current page:', e.currentPage);
});

viewer.addEventListener('zoomChanged', (e) => {
  console.log('Zoom changed:', e.scale);
});

viewer.addEventListener('renderComplete', (e) => {
  console.log('Page rendered:', e.pageNumber);
});

viewer.addEventListener('renderError', (e) => {
  console.error('Render error:', e.pageNumber, e.error);
});

viewer.addEventListener('highlightsLoaded', (e) => {
  console.log('Highlights loaded:', e.count);
});

viewer.addEventListener('highlightHover', (e) => {
  console.log('Highlight hover:', e.termId, 'page', e.pageNumber, 'bbox', e.bboxIndex);
});

viewer.addEventListener('highlightBlur', (e) => {
  console.log('Highlight blur:', e.termId);
});

viewer.addEventListener('highlightClick', (e) => {
  console.log('Highlight clicked:', e.termId, 'page', e.pageNumber, 'bbox', e.bboxIndex);
});

viewer.addEventListener('navigationComplete', (e) => {
  console.log('Navigation complete:', e.termId, e.pageNumber, e.occurrenceIndex);
});

viewer.addEventListener('selectionChanged', (e) => {
  console.log('Text selected:', e.text);
  console.log('Pages:', e.pageNumbers);
  console.log('Overlapping highlights:', e.highlights); // array of bbox refs
});

viewer.addEventListener('selectionHighlighted', (e) => {
  console.log('Selection highlighted:', e.termId);
});

viewer.addEventListener('error', (e) => {
  console.error('Viewer error:', e);
});

事件有效载荷场可能包括: termId, (中文(简体) ), pageNumber, (中文(简体) ), bboxIndex,以及 bbox 根据事件类型.

高级使用

页面缩略图

// ThumbnailOptions: maxWidth?, scale?, format?, quality?
const pageNumbers = Array.from({ length: viewer.getTotalPages() }, (_, i) => i + 1);

// Option 1: get data URLs for <img src="...">
const dataUrls = await viewer.getThumbnailsDataUrl(pageNumbers, {
  maxWidth: 120,
  format: 'image/webp',
  quality: 0.85,
});
// dataUrls is Map<number, string> — use dataUrls.get(pageNum) in img src

// Option 2: get canvases for custom rendering
const canvases = await viewer.getThumbnails(pageNumbers, { maxWidth: 120 });
// canvases is Map<number, HTMLCanvasElement>

对于一页,通过一个数组: getThumbnailsDataUrl([5], options)。缩略图会在取景器内被缓存;重新打开面板不会重新发送,除非缓存被清除(例如装入了新的PDF后).

自定义样式( 每高亮)

const highlight: InputHighlightData = {
  id: 'note-001',
  bboxes: [{ page: 2, x1: 120, y1: 330, x2: 420, y2: 355 }],
  style: {
    backgroundColor: '#ffd54f',
    opacity: 0.25,
    borderColor: '#ff8f00',
    borderWidth: '1px',
    hoverOpacity: 0.6,
  },
  label: 'My note',
  labelStyle: { padding: '2px 6px', borderRadius: '4px' },
  tooltipText: 'My note',
};

viewer.addHighlight(highlight);

他们

取景者的颜色跟随DIAL聊天调色板. 每种颜色都是 --phk-* 读取匹配的 DIAL 主题变量的 CSS 变量(--bg-layer-base, (中文(简体) ), --text-primary, (中文(简体) ), --stroke-accent(中文(简体) ). 因此,在DIAL app内部,查看器遵循的是活动主题,包括黑暗;在其他地方它使用DIAL光调色板.

要重塑查看器的样式, 请覆盖任意 --phk-* 变量 :

.pdf-highlight-viewer,
.pdf-context-menu,
.pdf-tooltip {
  --phk-bg: #ffffff;
  --phk-accent: #0f766e;
  --phk-yellow: #facc15; /* protein highlights and search results */
}

名单排在首位 styles/pdf-highlight-viewer.css。 。 。 .

有图标的标签( 如 Taller 图标)

通过内置 SVG 字符串为 beforeIcon 在标签框内显示图标。 只使用可信任的内容 。 使用 Vite 可以导入 SVG 作为原始字符串 :

// Inline SVG string (e.g. from Tabler: import icon from '@tabler/icons/icons/outline/alert-circle.svg?raw')
const alertIconSvg =
  '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 8v4"/><path d="M12 16h.01"/><circle cx="12" cy="12" r="10"/></svg>';

const highlight: InputHighlightData = {
  id: 'alert-001',
  bboxes: [{ page: 1, x1: 100, y1: 200, x2: 300, y2: 220 }],
  style: { backgroundColor: '#ffeb3b', opacity: 0.3, borderColor: '#d4c400' },
  label: 'Important',
  beforeIcon: alertIconSvg,
  labelStyle: { fontSize: 11, iconSize: 14 },
  tooltipText: 'Important',
};

viewer.addHighlight(highlight);

反应集成

import { useEffect, useRef } from 'react';
import { PDFHighlightViewer } from '@epam/pdf-highlighter-kit';
import type { InputHighlightData } from '@epam/pdf-highlighter-kit';
import '@epam/pdf-highlighter-kit/styles/pdf-highlight-viewer.css';

export function PDFViewer({
  pdfUrl,
  highlights,
}: {
  pdfUrl: string;
  highlights: InputHighlightData[];
}) {
  const containerRef = useRef<HTMLDivElement>(null);
  const viewerRef = useRef<PDFHighlightViewer | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const viewer = new PDFHighlightViewer();
    viewerRef.current = viewer;

    (async () => {
      await viewer.init(containerRef.current!, {
        enableTextSelection: true,
        enableVirtualScrolling: true,
      });
      await viewer.loadPDF(pdfUrl);
      viewer.loadHighlights(highlights);
    })();

    return () => {
      viewer.destroy();
      viewerRef.current = null;
    };
  }, [pdfUrl]);

  useEffect(() => {
    viewerRef.current?.loadHighlights(highlights);
  }, [highlights]);

  return <div ref={containerRef} style={{ width: '100%', height: '100vh' }} />;
}

浏览器支持

  • Chrome/Edge(最新2个版本)
  • Firefox(最新2个版本)
  • Safari(最新2个版本)

所需资源

  • pdfjs-dist: ^ 5.4.149 ^ 6.0.0 (同龄人依赖关系)

许可证

阿帕奇 - 2.0

捐款

欢迎捐款! 请随意提交拉力请求.

支助

关于议题和问题,请使用GitHub问题页面.

版本与发布记录

@epam/pdf-highlighter-kit 共发布 18 个版本,首次发布于 2025/12/17;过去 12 个月发布了 18 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.0.22latest2026/11/103 天前
0.0.212026/11/058 天前
0.0.202026/11/049 天前
0.0.192026/09/112 个月前
0.0.182026/06/174 个月前
0.0.172026/06/164 个月前

关于 @epam/pdf-highlighter-kit 的常见问题

@epam/pdf-highlighter-kit 是什么?

具有智能突出显示和文本选择能力的高性能 PDF 查看器

如何安装 @epam/pdf-highlighter-kit?

在项目目录运行 npm install @epam/pdf-highlighter-kit,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:pdfjs-dist(^5.4.149 || ^6.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@epam/pdf-highlighter-kit 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@epam/pdf-highlighter-kit 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@epam/pdf-highlighter-kit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=14.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@epam/pdf-highlighter-kit 可以商用吗?

@epam/pdf-highlighter-kit 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@epam/pdf-highlighter-kit 的下载量有多少?

根据 npm 官方下载统计,@epam/pdf-highlighter-kit 在 2026/10/14 – 2026/11/12 这 30 天内被下载 10,308 次,日均约 344 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@epam/pdf-highlighter-kit 还在维护吗?

最新版本 0.0.22 发布于 2026/11/10(3 天前);至今共发布 18 个版本,其中过去 12 个月发布了 18 个;首次发布于 2025/12/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。