头图

PDF.js is a JavaScript library based on HTML5 to parse and render PDF, and is led by Mozilla to open source.

This article aims to introduce PDF.js in Electron , and actually tried several ways to use its API or embed HTML.

Prepare the project from scratch

The project is implemented using Electron React Antd PDF.js. The following is the process of preparing the project from scratch.

Electron React

Here use the electron-react-boilerplate template to start the Electron React project.

# 获取模板
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

Prepare the editor (VSCode):

code --install-extension dbaeumer.vscode-eslint
code --install-extension dzannotti.vscode-babel-coloring
code --install-extension EditorConfig.EditorConfig

For other editors, see Editor Configuration .

Ant Design

Add antd dependency:

npm install antd

After that, you can quickly layout the page, as follows:

PDF.js

Add pdfjs dependency:

npm install pdfjs-dist
npm install -D worker-loader

In addition, prepare the PDF sample into static/ , and simply use Python to provide HTTP access:

npm run static

For development and operation, the address of file://

PDF.js rendering

Use API

Use the API to render the page, see the official Examples .

1. Import the package

import * as pdfjsLib from 'pdfjs-dist/webpack';

2. Render the page

(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!');
})();

For the complete code, see Pdfjs/index.tsx . The effect is as follows:

Use Viewer API

Render with the Viewer API, which is in the path pdfjs-dist/web/pdf_viewer

1. Import the package

import * as pdfjsLib from 'pdfjs-dist/webpack';
import { PDFViewer, EventBus } from 'pdfjs-dist/web/pdf_viewer';
import 'pdfjs-dist/web/pdf_viewer.css';

2. Layout page

<div className="viewer">
  <div>url={url}</div>
  <div>numPages={numPages}</div>
  <div ref={hrRef} />
  <div ref={containerRef} className="container">
    <div className="pdfViewer" />
  </div>
</div>

Request absolute positioning:

.viewer {
  position: relative;

  .container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: scroll;
  }
}

3. Render 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);
})();

For the complete code, see PdfViewer/index.tsx . The effect is as follows:

Use Viewer HTML

PDF.js provides an online demonstration of viewer.html , but pdfjs-dist is not in 061b9bcb24d946. You have to compile the source code yourself.

The compiled result has been put into static/pdfjs/ , you can use Electron Window to open web/viewer.html?file=x.pdf or use iframe embed it.

If you recompile yourself, the process is as follows:

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 is also opened:

<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 opened here has the following effect:

iframe wants to open the local HTML, but it failed. If you want to use it under Electron + React, you have to study how to do it.

At last

PDF.js can be said to be the best choice for rendering PDF on the Web. Many PDF Web Viewer libraries are based on it.

GoCoding personal practice experience sharing, please follow the official account!

GoCoding
88 声望5 粉丝

Go coding in my way :)


« 上一篇
PDFium 渲染
下一篇 »
React MobX 开始