PDF.js:前端 PDF 预览、文本提取、检索、分页配置实战

介绍

PDF.js 是 Mozilla(火狐官方)2011年开源、全JS编写的PDF前端渲染引擎,无任何浏览器插件、无客户端软件依赖,依靠HTML5 Canvas/Web Worker/DOM在浏览器原生解析渲染PDF,火狐浏览器内置PDF阅读器底层就是PDF.js。

  • 开源协议:Apache2.0(免费商用、无版权限制)
  • 仓库:https://github.com/mozilla/pdf.js
  • 分发包:pdfjs-dist(生产使用打包产物)
  • 适用:Web网页预览PDF、后端文件预览系统、KKFileView前端内核、Vue/React内嵌PDF预览

对比传统PDF预览方案优势

方案 缺点 PDF.js优势
iframe直接打开PDF 依赖浏览器内核、UI不可定制、部分浏览器不兼容 完全自定义UI、跨浏览器统一表现
后端转图片预览 服务器算力消耗大、不能选文字/搜索 前端渲染、支持文本复制、全文检索
Adobe插件/NPAPI 现代浏览器已废弃、安全漏洞 纯前端、安全无插件

适用场景

  1. OA/档案系统网页在线PDF预览
  2. 文档管理系统前端预览(你做的文件智能体RAG预览)
  3. 浏览器在线打开本地PDF文件
  4. KKFileView、OnlyOffice预览备选前端渲染内核
  5. 移动端H5在线预览PDF

版本选择

  • 4.x/5.x/6.x(开发部署复杂,不推荐):内核改用mjs模块;本地Vite+FastAPI跨端口预览需配置MIME、改源码,适合Nginx同域部署项目。

  • 3.11.174 legacy(推荐):全文件js、白名单原生数组,只需添加前后端域名即可跨接口加载PDF,零额外配置,适配前后端分离本地调试。

项目选型:跨端口预览选3.11,正式同域上线可选4.x及以上。

三层架构

PDF.js整体分Core内核层、Display渲染API层、Viewer完整UI层三层,项目开发按需选用:

1.Core 内核层(底层解析引擎)

  • 职责:二进制PDF文件解析、PDF字典/流/字体/图像解码、PDF语法校验,不对外暴露稳定API,运行在Web Worker中
  • pdf.worker.js 就是Core打包产物,所有PDF解析任务在Worker子线程执行,不阻塞页面主线程渲染

2.Display 显示层(业务开发常用API层)

对外提供稳定API,开发者手动绘制Canvas自定义预览(自己做翻页、缩放UI),无自带工具栏,日常手写预览用这一层。
核心入口:getDocument() 加载PDF文档、pdfDoc.getPage() 获取单页、page.render() 绘制到Canvas。

3.Viewer 完整UI层(开箱即用阅读器)

基于Display封装一套完整PDF阅读器(web/viewer.html),自带:页码跳转、缩放、旋转、全文搜索、缩略图侧边栏、打印、下载、书签、批注面板,直接iframe引入即可快速实现完整预览,企业预览系统首选。

目录结构

pdfjs-dist/
├─ build/
│   ├─ pdf.js / pdf.min.js        # Display核心主库
│   └─ pdf.worker.js / min.js     # Core解析Worker脚本(必须单独部署)
└─ web/                            # Viewer完整阅读器UI资源
    ├─ viewer.html                # 阅读器入口页面
    ├─ viewer.js / viewer.css
    └─ locale/                     # 多语言包(含zh-CN中文)

两种接入方式

方式1:iframe引入Viewer(最简)

直接通过地址传PDF文件路径,自带全套工具栏,支持中文。

<!-- 1.本地部署web文件夹后使用 -->
<iframe src="./web/viewer.html?file=/static/test.pdf#locale=zh-CN" width="100%" height="800px"></iframe>
<!-- #locale=zh-CN 强制中文界面 -->
  • 参数:file=文件URL(文件需跨域允许,同域/后端代理接口)
  • 高级:可通过#page=3直接打开第3页、隐藏下载/打印按钮(修改viewer配置)

方式2:原生API手动渲染(自定义预览,无自带工具栏,Vue/React内嵌)

NPM引入(Vite/Webpack项目)

npm install pdfjs-dist
import * as pdfjsLib from 'pdfjs-dist/build/pdf'
import pdfWorker from 'pdfjs-dist/build/pdf.worker?url'
// 配置Worker
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker;
// 后续getDocument同上面代码

特性

  1. Web Worker异步解析:PDF解析全在子线程,超大PDF不会卡死页面,支持多PDF独立Worker隔离
  2. 中文PDF兼容:复杂内嵌字体需要引入cmap字体映射包(pdfjs-dist/cmaps目录),缺字会乱码
  3. 两种渲染模式:
    • Canvas模式:默认,像素渲染、兼容性最好
    • SVG模式:矢量渲染,文字可原生选中,性能略差
  4. 懒加载/分片加载:大PDF分段请求字节流,不用一次性下载全文件即可渲染首页
  5. 文本提取:精准提取每页文字,实现网页全文检索、复制PDF文字(后端转图片方案做不到)
  6. 批注解析:读取PDF内置注释、高亮、印章批注

常见问题&优化

1.中文乱码/缺字

引入cmap资源,配置cMapUrl:

getDocument({url:'xx.pdf',cMapUrl:'/cmaps/',cMapPacked:true})

2.跨域报错(后端PDF文件访问)

后端接口配置CORS跨域头,或前端通过同域代理接口转发PDF流。

3.超大PDF优化(几百MB)

开启分片rangeChunkSize、分页懒加载(只渲染可视区域页面)、禁用预加载全部页码。

4.Vite打包Worker报错

Worker路径用?url引入:import workerUrl from 'pdfjs-dist/build/pdf.worker?url'

局限性

  1. 不支持PDF编辑:仅解析渲染、提取文本,无法修改PDF内容(如需编辑用PDFKit、pdf-lib生成/修改)
  2. 加密PDF(用户密码加密)需要手动传入密码参数才能打开
  3. 超大PDF(1GB+)前端全量加载性能一般,建议后端分页预渲染缩略图+前端分页加载

原文出处:/show_1GW3Qhpl8DZG.html