@langhe/pdf-sdk
v0.1.2
Published
朗阅 PDF SDK 提供 Web 端 PDF 在线预览、批注、保存、导出和授权能力,可通过 npm 包接入到业务系统中。
Readme
@langhe/pdf-sdk
朗阅 PDF SDK 提供 Web 端 PDF 在线预览、批注、保存、导出和授权能力,可通过 npm 包接入到业务系统中。
联系方式:微信号 13512039065
一、核心能力
| 能力 | 说明 |
| --- | --- |
| PDF 预览 | 支持 PDF 打开、分页渲染、滚动、缩放、旋转、页码跳转 |
| 大文件预览 | 支持大文档按需渲染,减少长期浏览时的内存占用 |
| 缩略图 | 支持缩略图列表、当前页高亮、点击跳页 |
| 搜索 | 支持关键词搜索、上一条 / 下一条、命中高亮 |
| 批注 | 支持高亮、下划线、删除线、文本、矩形、圆形、箭头、手写、折线、多边形、印章、签名 |
| 批注保存 | 支持读取、保存、回显批注数据 |
| 批注导出 | 支持导出批注 JSON |
| PDF 导出 | 支持导出带批注的 PDF 文件 |
| 框架接入 | 支持原生 JavaScript、React、Vue3、Vue2 |
| 授权 | 支持本地离线 licenseKey 校验,生产环境授权交付 |
二、安装
npm install @langhe/pdf-sdk @langhe/pdf-viewer如果项目使用 pnpm:
pnpm add @langhe/pdf-sdk @langhe/pdf-viewer入口说明:
| 包 | 说明 |
| --- | --- |
| @langhe/pdf-sdk | SDK 主入口 |
| @langhe/pdf-viewer | Viewer UI 和样式 |
| @langhe/pdf-react | React 组件封装 |
| @langhe/pdf-vue3 | Vue3 组件封装 |
| @langhe/pdf-vue2 | Vue2 组件封装 |
三、开发环境 licenseKey
下面的 licenseKey 仅用于本地开发和接入验证,支持 localhost、127.0.0.1、[::1],有效期至 2027-12-31 23:59:59 UTC。
export const LANGYUE_PDF_DEV_LICENSE_KEY =
'eyJ2ZXJzaW9uIjoxLCJsaWNlbnNlSWQiOiJMWS1QREYtMjAyNjA3MDQtSk5MSkhXIiwiY2xpZW50SWQiOiJsYW5neXVlLWRldiIsImNsaWVudE5hbWUiOiJMYW5neXVlIFBERiBTREsgRGV2ZWxvcG1lbnQiLCJwcm9kdWN0IjoibGFuZ3l1ZS1wZGYtc2RrIiwiZG9tYWlucyI6WyJsb2NhbGhvc3QiLCIxMjcuMC4wLjEiLCJbOjoxXSJdLCJpc3N1ZWRBdCI6IjIwMjYtMDctMDRUMTM6MzM6MDIuNzA5WiIsImV4cGlyZXNBdCI6IjIwMjctMTItMzFUMjM6NTk6NTkuMDAwWiIsIm1ldGFkYXRhIjp7ImNvbnRyYWN0Tm8iOiJERVYtTlBNLTIwMjYifX0.pbTSv0zG1mlv0gTuLM1-rfN6H7rJhpynXUEM89AiowlvmeDMltuN9d-kLLRo6uVzQEVfy0zRPHwmstHzSgEH9w'生产环境需要正式授权,请联系微信号 13512039065。
四、最小接入
页面准备容器:
<div id="pdf-viewer"></div>容器必须有明确宽高:
html,
body,
#pdf-viewer {
width: 100%;
height: 100%;
margin: 0;
}初始化 SDK:
import { createLangyuePDF } from '@langhe/pdf-sdk'
import '@langhe/pdf-viewer/style.css'
const viewer = await createLangyuePDF({
container: '#pdf-viewer',
document: {
src: '/files/example.pdf',
documentId: 'doc-001',
fileName: 'example.pdf'
},
user: {
id: 'u-001',
name: '张三'
},
licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
license: {
environment: 'development',
hostname: window.location.hostname,
failureStrategy: 'block'
}
})五、打开 PDF
打开 URL PDF:
await viewer.open({
src: '/api/files/doc-001.pdf',
documentId: 'doc-001',
fileName: '合同.pdf'
})打开二进制 PDF:
const response = await fetch('/api/files/doc-001')
const data = await response.arrayBuffer()
await viewer.open({
data,
documentId: 'doc-001',
fileName: '合同.pdf'
})六、批注数据接入
URL 接口模式
const viewer = await createLangyuePDF({
container: '#pdf-viewer',
document: {
src: '/files/doc-001.pdf',
documentId: 'doc-001'
},
user: {
id: 'u-001',
name: '张三'
},
licenseKey,
license: {
environment: 'production',
failureStrategy: 'block'
},
dataSource: {
loadUrl: '/api/documents/doc-001/annotations',
saveUrl: '/api/documents/doc-001/annotations',
headers: async () => ({
Authorization: `Bearer ${await getAccessToken()}`
})
}
})推荐加载接口返回:
{
"schemaVersion": "2.0",
"annotations": []
}回调模式
const viewer = await createLangyuePDF({
container: '#pdf-viewer',
document: {
src: '/files/doc-001.pdf',
documentId: 'doc-001'
},
dataSource: {
load: async context => {
return annotationService.load(context.document?.documentId)
},
save: async (annotations, context) => {
await annotationService.save(context.document?.documentId, {
annotations,
reason: context.reason
})
}
}
})七、常用方法
viewer.goToPage(3)
viewer.zoomIn()
viewer.zoomOut()
const annotations = viewer.getAnnotations()
await viewer.saveAnnotations()
await viewer.exportPdf({
fileName: '合同-带批注.pdf',
download: true
})
viewer.destroy()| 方法 | 说明 |
| --- | --- |
| open(input) | 打开 PDF |
| close() | 关闭当前 PDF |
| destroy() | 销毁 SDK 实例 |
| goToPage(pageNumber) | 跳转页码 |
| zoomIn() / zoomOut() | 放大 / 缩小 |
| search(query) | 搜索文本 |
| getAnnotations() | 获取批注 |
| setAnnotations(annotations) | 设置批注 |
| saveAnnotations() | 保存批注 |
| exportAnnotations() | 导出批注 JSON |
| exportPdf() | 导出带批注 PDF |
| getLicenseStatus() | 获取授权状态 |
八、事件监听
viewer.on('annotations:dirty', event => {
saveButton.disabled = !event.dirty
})
viewer.on('annotations:save', event => {
console.log('批注已保存', event.annotations.length)
})
viewer.on('error', event => {
console.error(event.error.code, event.error.message)
})
viewer.on('page:change', event => {
console.log(`${event.pageNumber} / ${event.pageCount}`)
})九、生产环境授权
生产环境必须传入正式 licenseKey。
const viewer = await createLangyuePDF({
container: '#pdf-viewer',
document: {
src: '/api/files/doc-001.pdf',
documentId: 'doc-001'
},
licenseKey: window.APP_CONFIG.langyuePdfLicenseKey,
license: {
environment: 'production',
hostname: window.location.hostname,
failureStrategy: 'block'
}
})授权校验在浏览器本地离线完成,不需要联网。
| 场景 | 行为 |
| --- | --- |
| 开发环境未传 licenseKey | 默认放行 |
| 生产环境未传 licenseKey | 阻止初始化 |
| licenseKey 无效 | 授权失败 |
| 域名未授权 | 授权失败 |
| 授权过期 | 授权失败 |
读取授权状态:
const status = viewer.getLicenseStatus()
console.log(status.valid, status.code, status.message)十、PDFium 资源部署
如需把资源放到 public 目录或 CDN,需要准备:
pdfium.wasm
PdfiumPreviewReaderWorker.js
PdfiumStreamingWorker.js配置资源路径:
await createLangyuePDF({
container: '#pdf-viewer',
document: { src: '/files/doc-001.pdf' },
resources: {
pdfium: {
baseUrl: '/assets/pdfium'
}
}
})生产环境检查:
| 检查项 | 要求 |
| --- | --- |
| wasm MIME | application/wasm |
| worker MIME | JavaScript 文件可以作为 module worker 加载 |
| 跨域 | CDN 场景需要配置 CORS |
| CSP | 如业务系统配置 CSP,需要允许 worker 和 wasm 加载来源 |
十一、React 接入
npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-react reactimport { useMemo } from 'react'
import { LangyuePDFReact } from '@langhe/pdf-react'
import '@langhe/pdf-viewer/style.css'
export function ContractViewer() {
const options = useMemo(() => ({
document: {
src: '/files/doc-001.pdf',
documentId: 'doc-001'
},
user: {
id: 'u-001',
name: '张三'
},
licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
license: {
environment: 'development'
}
}), [])
return (
<LangyuePDFReact
className="pdf-host"
options={options}
onReady={viewer => {
viewer.setCommentsSidebarVisible(true)
}}
/>
)
}十二、Vue3 接入
npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-vue3 vue<script setup lang="ts">
import { LangyuePDFVue3 } from '@langhe/pdf-vue3'
import '@langhe/pdf-viewer/style.css'
const options = {
document: {
src: '/files/doc-001.pdf',
documentId: 'doc-001'
},
user: {
id: 'u-001',
name: '张三'
},
licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
license: {
environment: 'development'
}
}
</script>
<template>
<LangyuePDFVue3 class="pdf-host" :options="options" />
</template>十三、Vue2 接入
npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-vue2 vue<template>
<LangyuePDFVue2
ref="viewer"
class="pdf-host"
:options="options"
@ready="handleReady"
/>
</template>
<script>
import { LangyuePDFVue2 } from '@langhe/pdf-vue2'
import '@langhe/pdf-viewer/style.css'
export default {
components: { LangyuePDFVue2 },
data() {
return {
options: {
document: {
src: '/files/doc-001.pdf',
documentId: 'doc-001'
},
user: {
id: 'u-001',
name: '张三'
},
licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
license: {
environment: 'development'
}
}
}
},
methods: {
handleReady(viewer) {
viewer.setCommentsSidebarVisible(true)
},
save() {
return this.$refs.viewer.saveAnnotations()
}
}
}
</script>十四、上线检查
| 检查项 | 说明 |
| --- | --- |
| npm 包 | 已安装 @langhe/pdf-sdk 和 @langhe/pdf-viewer |
| 样式 | 已引入 @langhe/pdf-viewer/style.css |
| 容器 | viewer 容器有明确宽高 |
| PDF 地址 | PDF URL 可访问,跨域和鉴权已处理 |
| documentId | 每份业务文档都有稳定唯一 ID |
| 用户信息 | 已传入当前登录用户 ID 和名称 |
| 批注接口 | 已完成批注读取和保存接口 |
| 授权 | 生产环境已配置正式 licenseKey |
| PDFium 资源 | wasm 和 worker 在生产环境不 404 |
| 页面销毁 | 路由切换或组件卸载时调用 viewer.destroy() |
十五、联系我们
正式授权、商务合作、接入支持请联系:
微信号:13512039065
