2、前端页面如何优雅的显示PDF(上):渲染页面

4,035 阅读2分钟

推荐阅读

准备工作

  1. 创建 react 项目:
create-react-app
  1. 在项目中添加 pdf.js 依赖
npm install pdfjs-dist || yarn add pdfjs-dist

使用 pdfjs-dist

关键的两个文件

  • pdf.js
  • pdf.worker.js

如何使用

import pdfjs from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;

这两个文件包含了获取、解析和展示PDF文档的方法,但是解析和渲染PDF需要较长的时间,可能会阻塞其它JS代码的运行。 为解决该问题,pdf.js依赖了HTML5引入的Web Workers——通过从主线程中移除大量CPU操作(如解析和渲染)来提升性能。

PDF.js的API都会返回一个Promise,使得我们可以优雅的处理异步操作。但是文档甚少,只能查找源码,浏览 github

++题外话:在看别人写的pdf渲染的项目使用 pdfjs-dist 的时候 这么写的++

 pdfjs.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.js');

通过 required 引入 pdf.worker 但是使用 create-react-app 创建的 react 项目在使用的时候不能够直接使用 required,如果这么使用会报这个错

image

查看源码就能够定位到问题原因:他的接受的必须是字符串

# 位置 pdf.js/src/display/worker_options.js Lines 27 to 34 in 4fe9260
/** 
  * A string containing the path and filename of the worker file. 
  * 
  * NOTE: The `workerSrc` option should always be set, in order to prevent any 
  *       issues when using the PDF.js library. 
  * @var {string} 
  */ 
 GlobalWorkerOptions.workerSrc = 

同样的可以使用 CND 的方式解决这个问题

pdfjs.GlobalWorkerOptions.workerSrc = "https://cdn.bootcss.com/pdf.js/2.2.228/pdf.worker.js";

渲染

  1. 创建 canvas 以便于渲染pdf
const canvasRef = useRef(null)

<canvas
    ref={canvasRef}
    width={window.innerWidth}
    height={window.innerHeight}
/>
  1. 添加渲染PDF的 js 代码
# 读取 PDF 文件
const loadingTask = pdfjs.getDocument(url);

# 获得到 PDF 对象
const pdf = await loadingTask.promise;

const firstPageNumber = 1;

# 读取到页面信息
const page = await pdf.getPage(firstPageNumber);

# 设置页面缩放
const scale = 1;
const viewport = page.getViewport({scale: scale});

# 以下写法清晰度更高
# const devicePixelRatio = window.devicePixelRatio;
# const viewport = page.getViewport({scale: scale * devicePixelRatio});


// Prepare canvas using PDF page dimensions
const canvas = canvasRef.current;

const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;

// Render PDF page into canvas context
const renderContext = {
    canvasContext: context,
    viewport: viewport
};
const renderTask = page.render(renderContext);

这样PDF就渲染到刚才我们写的canvas中,但是这段代码只能渲染第一页,通过改变 firstPageNumber 渲染不同的页面。

getDocument():用于异步获取PDf文档,发送多个Ajax请求以块的形式下载文档。它返回一个Promise,该Promise的成功回调传递一个对象,该对象包含PDF文档的信息,该回调中的代码将在完成PDf文档获取时执行。

getPage():用于获取PDF文档中的各个页面。

getViewport():针对提供的展示比例,返回PDf文档的页面尺寸。

render():渲染PDF。

这也写只能满足简单的翻页需求,如果增加别的需求,放大缩小,文本复制,就不能改满足。我们下节来编写如何能够==文本复制==。

源码地址:https://github.com/LiuSandy/react-pdf-render