PDF.js 是基于 HTML5 解析与渲染 PDF 的 JavaScript 库,由 Mozilla 主导开源。

本文旨在介绍 PDF.jsElectron 里如何开始使用,实际尝试了用其 API 或嵌入 HTML 的几种方式。

从零准备项目

项目采用 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-viewer cd electron-pdf-viewer # 设定仓库
git remote set-url origin git@github.com:ikuokuo/electron-pdf-viewer.git
# 如果想合并成一个初始提交
# https://stackoverflow.com/a/23486788
git 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-eslint
code --install-extension dzannotti.vscode-babel-coloring
code --install-extension EditorConfig.EditorConfig

其他编辑器,可见 Editor Configuration

Ant Design

添加 antd 依赖:

npm install antd

之后,就可以快速布局页面了,如下:

PDF.js

添加 pdfjs 依赖:

npm install pdfjs-dist
npm 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 () => {
// 获取 doc
const loadingTask = pdfjsLib.getDocument(url);
const pdf = await loadingTask.promise; console.log(`PDF loaded, n=${pdf.numPages}`);
setNumPages(pdf.numPages); // 获取 page
const page = await pdf.getPage(1); // 获取 canvas const 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; // 渲染 page
const 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-any
eventBus.on('pagesloaded', (e: any) => {
console.log('pagesloaded');
console.log(e);
setNumPages(e.pagesCount);
});
eventBus.on('pagerendered', () => {
console.log('pagerendered');
}); // 创建 PDFViewer
const 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.git
cd pdf.js # 安装依赖
npm install -g gulp-cli
npm 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>
<iframe
className="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 个人实践的经验分享,可关注公众号!

PDF.js Electron Viewer的更多相关文章

  1. 用pdf.js实现在移动端在线预览pdf文件

    用pdf.js实现在移动端在线预览pdf文件1.下载pdf.js    官网地址:https://mozilla.github.io/pdf.js/ 2.配置    下载下来的文件包,就是一个demo ...

  2. pdf.js插件使用记录,在线打开pdf

    天记录一个js库:pdf.js.主要是实现在线打开pdf功能.因为项目需求需要能在线查看pdf文档,所以就研究了一下这个控件. 有些人很好奇,在线打开pdf文档浏览器不是支持吗.是的你说的都是现代浏览 ...

  3. pdf.js 打印出错

    两种方法:1.使用0.8.223版本的pdf.js2.viewer.js中 line 3642 PRINT_OUTPUT_SCALE=1,line 3639 pdfPage.getViewPort(2 ...

  4. pdf转为html查看pdf.js

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. pdf.js如何跨域读取pdf文件?

    今天,上线一个客户网站之后(使用的是广州新一代虚拟空间)发现在读取上传的pdf文件的时候读取错误,通过直接在浏览器输入文件地址的时候发现文件地址被重定向了(呵呵!),结果就是pdf文件源由本地直接变成 ...

  6. PDF.Js的使用—javascript中前端显示pdf文件

    PDF.Js的使用—javascript中前端显示pdf文件 写于2018/12/6 起因是一个图片展示页面需要展示pdf格式的文件,所以查了半天决定使用pdf.js,我也不求有多了解它,能实现我想要 ...

  7. PDF.js 详情解说

    pdf.js资源下载 点我下载 自定义默认加载的pdf资源 在web/view.js中我们可以通过DEFAULT_URL设置默认加载的pdf.通过上面代码我们也可以看出来可以通过后缀名来指定加载的pd ...

  8. 使用pdf.js在移动端预览pdf文档

    pdf.js 是一个技术原型主要用于在 HTML5 平台上展示 PDF 文档,无需任何本地技术支持. 在线演示地址:http://mozilla.github.com/pdf.js/web/viewe ...

  9. 在线浏览PDF之PDF.JS (附demo)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#skill 下载地址:http://mozilla.gith ...

随机推荐

  1. 用Docker搭建RabbitMq的普通集群和镜像集群

    普通集群:多个节点组成的普通集群,消息随机发送到其中一个节点的队列上,其他节点仅保留元数据,各个节点仅有相同的元数据,即队列结构.消费者消费消息时,会从各个节点拉取消息,如果保存消息的节点故障,则无法 ...

  2. jsonp初识

    我们在项目中对接口发起请求时会遇到一个跨域请求的问题,在这个时候,我们可以用一个较为简单的方法解决:jsonp 后端(以php为例): <?php header('Content-type: a ...

  3. vivo统一告警平台设计与实践

    一.背景 一套监控系统检测和告警是密不可分的,检测用来发现异常,告警用来将问题信息发送给相应的人.vivo监控系统1.0时代各个监控系统分别维护一套计算.存储.检测.告警收敛逻辑,这种架构下对底层数据 ...

  4. [atARC105D]Let's Play Nim

    先对$n$分奇偶两种情况考虑-- $n$为奇数,显然先手希望最终产生的$x_{1}\oplus x_{2}\oplus...\oplus x_{n}=0$ 对于后手,考虑构造:将最大的未被选择的$a_ ...

  5. [luogu5204]Train Tracking 2

    考虑一个位置的上界,即$bi=min(c_{i-k+1},c_{i-k+2},--,ci)$,那么每一个位置有两种方式:1.达到上界:2.未达到上界那么可以将权值相同的ci和bi提出来,由于权值不同的 ...

  6. 从一个简单的Delete删数据场景谈TiDB数据库开发规范的重要性

    故事背景 前段时间上线了一个从Oracle迁移到TiDB的项目,某一天应用端反馈有一个诡异的现象,就是有张小表做全表delete的时候执行比较慢,而且有越来越慢的迹象.这个表每次删除的数据不超过20行 ...

  7. 【CSP2019 D1T2】【括号树】

    题面 不再多说,想必大家都看过这个题 思路 我们可以手推几个满足条件的字符串 我们发现在这些字符串里 每个)都与离它最近的(的匹配 所以我们维护树上每个节点到根节点中没用使用过的(的位置(nl[n]) ...

  8. Codeforces 434E - Furukawa Nagisa's Tree(三元环+点分治)

    Codeforces 题面传送门 & 洛谷题面传送门 场号 hopping,刚好是我的学号(指 round 的编号) 注:下文中分别用 \(X,Y,K\) 代替题目中的 \(x,y,k\) 注 ...

  9. 【GS基础】植物基因组选择研究人员及数量遗传学发展一览

    目录 1.GS研究 2.数量遗传发展 GS应用主要在国外大型动物和种企,国内仍以学术为主.近期整理相关学术文献,了解到一些相关研究人员,记录下备忘查询,但不可能全面. 1.GS研究 Theo Meuw ...

  10. R语言与医学统计图形【4】直方图、金字塔图

    R语言基础绘图系统 基础图形--直方图.金字塔图 3.直方图 参数设置及比较. op <- par(mfrow=c(2,3)) data <- rnorm(100,10,5) hist(d ...