百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

PDF.js Electron Viewer

yuyutoo 2025-01-21 22:38 1 浏览 0 评论

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[1] 模板开始 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[2]

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[3]

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[4]。效果如下:

使用 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[5]。效果如下:

使用 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 个人实践的经验分享,可关注公众号!

脚注

[1] electron-react-boilerplate: https://electron-react-boilerplate.js.org/

[2] Editor Configuration: https://electron-react-boilerplate.js.org/docs/editor-configuration

[3] Examples: https://mozilla.github.io/pdf.js/examples/

[4] Pdfjs/index.tsx: https://github.com/ikuokuo/electron-pdf-viewer/blob/main/src/renderer/pages/Pdfjs/index.tsx

[5] PdfViewer/index.tsx: https://github.com/ikuokuo/electron-pdf-viewer/blob/main/src/renderer/pages/PdfViewer/index.tsx

相关推荐

史上最全的浏览器兼容性问题和解决方案

微信ID:WEB_wysj(点击关注)◎◎◎◎◎◎◎◎◎一┳═┻︻▄(页底留言开放,欢迎来吐槽)●●●...

平面设计基础知识_平面设计基础知识实验收获与总结
平面设计基础知识_平面设计基础知识实验收获与总结

CSS构造颜色,背景与图像1.使用span更好的控制文本中局部区域的文本:文本;2.使用display属性提供区块转变:display:inline(是内联的...

2025-02-21 16:01 yuyutoo

写作排版简单三步就行-工具篇_作文排版模板

和我们工作中日常word排版内部交流不同,这篇教程介绍的写作排版主要是用于“微信公众号、头条号”网络展示。写作展现的是我的思考,排版是让写作在网格上更好地展现。在写作上花费时间是有累积复利优势的,在排...

写一个2048的游戏_2048小游戏功能实现

1.创建HTML文件1.打开一个文本编辑器,例如Notepad++、SublimeText、VisualStudioCode等。2.将以下HTML代码复制并粘贴到文本编辑器中:html...

今天你穿“短袖”了吗?青岛最高23℃!接下来几天气温更刺激……

  最近的天气暖和得让很多小伙伴们喊“热”!!!  昨天的气温到底升得有多高呢?你家有没有榜上有名?...

CSS不规则卡片,纯CSS制作优惠券样式,CSS实现锯齿样式

之前也有写过CSS优惠券样式《CSS3径向渐变实现优惠券波浪造型》,这次再来温习一遍,并且将更为详细的讲解,从布局到具体样式说明,最后定义CSS变量,自定义主题颜色。布局...

柠檬科技肖勃飞:大数据风控助力信用社会建设

...

你的自我界限够强大吗?_你的自我界限够强大吗英文

我的结果:A、该设立新的界限...

行内元素与块级元素,以及区别_行内元素和块级元素有什么区别?

行内元素与块级元素首先,CSS规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,分别为块级(block)、行内(inline)。块级元素:(以下列举比较常...

让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华
让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华

去年的两会期间,习近平总书记在参加人大会议四川代表团审议时,对治蜀兴川提出了明确要求,指明了前行方向,并带来了“祝四川人民的生活越来越安逸”的美好祝福。又是一年...

2025-02-21 16:00 yuyutoo

今年国家综合性消防救援队伍计划招录消防员15000名

记者24日从应急管理部获悉,国家综合性消防救援队伍2023年消防员招录工作已正式启动。今年共计划招录消防员15000名,其中高校应届毕业生5000名、退役士兵5000名、社会青年5000名。本次招录的...

一起盘点最新 Chrome v133 的5大主流特性 ?

1.CSS的高级attr()方法CSSattr()函数是CSSLevel5中用于检索DOM元素的属性值并将其用于CSS属性值,类似于var()函数替换自定义属性值的方式。...

竞走团体世锦赛5月太仓举行 世界冠军杨家玉担任形象大使

style="text-align:center;"data-mce-style="text-align:...

学物理能做什么?_学物理能做什么 卢昌海

作者:曹则贤中国科学院物理研究所原标题:《物理学:ASourceofPowerforMan》在2006年中央电视台《对话》栏目的某期节目中,主持人问过我一个的问题:“学物理的人,如果日后不...

你不知道的关于这只眯眼兔的6个小秘密
你不知道的关于这只眯眼兔的6个小秘密

在你们忙着给熊本君做表情包的时候,要知道,最先在网络上引起轰动的可是这只脸上只有两条缝的兔子——兔斯基。今年,它更是迎来了自己的10岁生日。①关于德艺双馨“老艺...

2025-02-21 16:00 yuyutoo

取消回复欢迎 发表评论: