PDF.js 是基于 HTML5 解析与渲染 PDF 的 JavaScript 库,由 Mozilla 主导开源。
本文旨在介绍 PDF.js 于 Electron 里如何开始使用,实际尝试了用其 API 或嵌入 HTML 的几种方式。
- 代码: https://github.com/ikuokuo/electron-pdf-viewer.git
从零准备项目
项目采用 Electron React Antd PDF.js 来实现,以下是从零准备项目的过程。
Electron React
这里用 electron-react-boilerplate 模板开始 Electron React 项目。
# 获取模板git clone --depth=1 \\https://github.com/electron-react-boilerplate/electron-react-boilerplate \\electron-pdf-viewercd electron-pdf-viewer# 设定仓库git remote set-url origin git@github.com:ikuokuo/electron-pdf-viewer.git# 如果想合并成一个初始提交# https://stackoverflow.com/a/23486788git config --global alias.squash-all \'!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f\'git squash-all "first commit"git push -u origin main
# 依赖npm install# 运行npm start# 打包npm run package
准备编辑器(VSCode):
code --install-extension dbaeumer.vscode-eslintcode --install-extension dzannotti.vscode-babel-coloringcode --install-extension EditorConfig.EditorConfig
其他编辑器,可见 Editor Configuration。
Ant Design
添加
antd
依赖:
npm install antd
之后,就可以快速布局页面了,如下:
PDF.js
添加
pdfjs
依赖:
npm install pdfjs-distnpm install -D worker-loader
此外,准备 PDF 样例进
static/
,简单用 Python 提供 HTTP 访问:
npm run static
用于开发运行,正式运行可用
file://
地址。
PDF.js 渲染
使用 API
用 API 渲染页面,可见官方 Examples。
1. 导入包
import * as pdfjsLib from \'pdfjs-dist/webpack\';
2. 渲染页面
(async () => {// 获取 docconst loadingTask = pdfjsLib.getDocument(url);const pdf = await loadingTask.promise;console.log(`PDF loaded, n=${pdf.numPages}`);setNumPages(pdf.numPages);// 获取 pageconst page = await pdf.getPage(1);// 获取 canvasconst scale = 1.5;const viewport = page.getViewport({ scale });// Support HiDPI-screens.const outputScale = window.devicePixelRatio || 1;const canvas = canvasRef.current;if (canvas == null) return;const context = canvas.getContext(\'2d\');canvas.width = Math.floor(viewport.width * outputScale);canvas.height = Math.floor(viewport.height * outputScale);canvas.style.width = `${Math.floor(viewport.width)}px`;canvas.style.height = `${Math.floor(viewport.height)}px`;const transform =outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;// 渲染 pageconst renderContext = {canvasContext: context,transform,viewport,};await page.render(renderContext);console.log(\'Page rendered!\');})();
完整代码,见 Pdfjs/index.tsx。效果如下:
使用 Viewer API
用 Viewer API 渲染,其在
pdfjs-dist/web/pdf_viewer
路径下。
1. 导入包
import * as pdfjsLib from \'pdfjs-dist/webpack\';import { PDFViewer, EventBus } from \'pdfjs-dist/web/pdf_viewer\';import \'pdfjs-dist/web/pdf_viewer.css\';
2. 布局页面
<div className="viewer"><div>url={url}</div><div>numPages={numPages}</div><div ref={hrRef} /><div ref={containerRef} className="container"><div className="pdfViewer" /></div></div>
要求
absolute
定位:
.viewer {position: relative;.container {position: absolute;top: 0;left: 0;right: 0;bottom: 0;overflow: scroll;}}
3. 渲染 PDF
const container = containerRef.current;if (container == null) return;if (hrRef.current) {container.style.top = `${hrRef.current.offsetTop}px`;}// 监听事件,必须传参 PDFViewer 为实例const eventBus = new EventBus(null);eventBus.on(\'pagesinit\', () => {console.log(\'pagesinit\');});// eslint-disable-next-line @typescript-eslint/no-explicit-anyeventBus.on(\'pagesloaded\', (e: any) => {console.log(\'pagesloaded\');console.log(e);setNumPages(e.pagesCount);});eventBus.on(\'pagerendered\', () => {console.log(\'pagerendered\');});// 创建 PDFViewerconst pdfViewer = new PDFViewer({container,eventBus,linkService: null,renderer: \'canvas\',l10n: null,});// 导入 Document(async () => {const loadingTask = pdfjsLib.getDocument(url);const pdf = await loadingTask.promise;pdfViewer.setDocument(pdf);})();
完整代码,见 PdfViewer/index.tsx。效果如下:
使用 Viewer HTML
PDF.js 提供了在线演示的
viewer.html
,不过
pdfjs-dist
里没有,要自己编译其源码。
编译结果已放进
static/pdfjs/
,可用 Electron Window 打开
web/viewer.html?file=x.pdf
或用
iframe
嵌入。
如果自己重新编译,过程如下:
git clone -b master --depth=1 https://github.com/mozilla/pdf.js.gitcd pdf.js# 安装依赖npm install -g gulp-clinpm install# 开发运行gulp server# http://localhost:8888/web/viewer.html# 编译发布gulp generic# build/generic/
iframe
嵌入的话,也是打开
web/viewer.html?file=x.pdf
:
<div className="viewerHTML"><div>pdfUrl={pdfUrl}</div><div>pdfWebViewerUrl={pdfWebViewerUrl}</div><iframeclassName="pdfViewer"title="PdfViewerHTML"src={`${pdfWebViewerUrl}?file=${pdfUrl}`}/></div>
.viewerHTML {.pdfViewer {border: none;width: 100%;height: 100%;}}
这里打开的
npm run static
提供的 HTTP 地址,效果如下:
iframe
要打开本地 HTML 试了下没成,如果想在 Electron + React 下这么用,还要研究下怎么弄。
最后
PDF.js 可以说是 Web 渲染 PDF 的不二选择,很多 PDF Web Viewer 库都是基于它实现的。
GoCoding 个人实践的经验分享,可关注公众号!