zoukankan      html  css  js  c++  java
  • PDF.js Electron Viewer

    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;
         100%;
        height: 100%;
      }
    }
    

    这里打开的 npm run static 提供的 HTTP 地址,效果如下:

    iframe 要打开本地 HTML 试了下没成,如果想在 Electron + React 下这么用,还要研究下怎么弄。

    最后

    PDF.js 可以说是 Web 渲染 PDF 的不二选择,很多 PDF Web Viewer 库都是基于它实现的。

    GoCoding 个人实践的经验分享,可关注公众号!

  • 相关阅读:
    如何在一个for语句中迭代多个对象(2.7)
    yield列表反转 islice切片(2.6)
    yield和生成器, 通过斐波那契数列学习(2.5)
    python实现线程池(2.4)
    LOJ 3120: 洛谷 P5401: 「CTS2019 | CTSC2019」珍珠
    瞎写的理性愉悦:正整数幂和与伯努利数
    bzoj 3328: PYXFIB
    LOJ 3119: 洛谷 P5400: 「CTS2019 | CTSC2019」随机立方体
    洛谷 P5345: 【XR-1】快乐肥宅
    LOJ 3089: 洛谷 P5319: 「BJOI2019」奥术神杖
  • 原文地址:https://www.cnblogs.com/gocodinginmyway/p/15693936.html
Copyright © 2011-2022 走看看