# @epam/pdf-highlighter-kit 中文文档

规范地址：https://npmcn.com/package/%40epam/pdf-highlighter-kit/

版本：0\.0\.22
npm 元数据更新时间：2026-11-10T09:39:35.990Z
中文译文更新时间：2026-11-13T19:20:43.914Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40epam/pdf-highlighter-kit
原文对照：https://npmcn.com/package/%40epam/pdf-highlighter-kit/?lang=original
项目主页：https://github.com/epam/pdf-highlighter-kit#readme
源码仓库：https://github.com/epam/pdf-highlighter-kit

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：503 kB，80 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=14\.0\.0
- 运行依赖：0 个
- peer 依赖：pdfjs-dist ^5\.4\.149 \|\| ^6\.0\.0
- 首次发布：2025-12-17T11:52:07.572Z
- 最新版本发布：2026-11-10T09:39:35.566Z
- 近 30 天下载量：10308（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：18（近 12 个月 18 个）

## 中文简介

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

## 安装

```sh
npm install @epam/pdf-highlighter-kit
```

也可以使用：`pnpm add @epam/pdf-highlighter-kit`、`yarn add @epam/pdf-highlighter-kit`、`bun add @epam/pdf-highlighter-kit`

## README

# PDF 高亮查看器

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

[![npm version](https://img.shields.io/npm/v/@epam/pdf-highlighter-kit)](https://www.npmjs.com/package/@epam/pdf-highlighter-kit) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/epam/pdf-highlighter-kit/pulls)

开源项目 **巴德尔Doc** ![BadgerDoc](https://npmcn.com/package/%40epam/pdf-highlighter-kit/logo.svg)

* * *

## 安装

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

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

## 快速启动

```ts
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 字符串(例如: [表格图标](https://tabler.io/icons))在标签框内使图标出自文字的左边。 图标通过 `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` 或数字.

```ts
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 坐标根据实际页数重新计算:

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

优先权(最高至最低):

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

## 配置选项

### 查看器选项

```ts
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 文档。 可选的第二个论点:

```ts
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`

清取并毁观相例.

## 活动

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

```ts
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` 根据事件类型.

## 高级使用

### 页面缩略图

```ts
// 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后).

### 自定义样式( 每高亮)

```ts
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-*` 变量 :

```css
.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 作为原始字符串 :

```ts
// 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);
```

### 反应集成

```tsx
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 是什么？

具有智能突出显示和文本选择能力的高性能 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 和提交记录判断。

