0%

在 React / NextJs 中使用 PDF.js

需要在项目中用 pdf.js 预览 pdf 文件,并且将 pdf 文件转换为图片。

这儿以 React 为例

安装 pdfjs-dist,并且复制 pdf.worker.min.jspublic/ 文件夹中,当然这是我的做法,如果你有更高阶的什么动态加载,打包到项目里,可以研究试试

1
2
npm install pdfjs-dist
cp ./node_modules/pdfjs-dist/build/pdf.worker.min.js ./public/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// pages/index.js
import React, { useEffect, useRef } from 'react';

export default function App() {
const canvasRef = useRef(null);

useEffect(() => {
(async function () {
// We import this here so that it's only loaded during client-side rendering.
const pdfJS = await import('pdfjs-dist/build/pdf');
pdfJS.GlobalWorkerOptions.workerSrc =
window.location.origin + '/pdf.worker.min.js';
const pdf = await pdfJS.getDocument('example.pdf').promise;

const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.5 });

// Prepare canvas using PDF page dimensions.
const canvas = canvasRef.current;
const canvasContext = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;

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

return <canvas ref={canvasRef} style={{ height: '100vh' }} />;
}

Next.js配置

next.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {
future: {
webpack5: true
},
webpack: (config) => {
// load worker files as a urls with `file-loader`
config.module.rules.unshift({
test: /pdf\.worker\.(min\.)?js/,
use: [
{
loader: "file-loader",
options: {
name: "[contenthash].[ext]",
publicPath: "_next/static/worker",
outputPath: "static/worker"
}
}
]
});

return config;
}
};

根目录新建一个 pdf-worker.js

1
2
3
4
5
6
if (process.env.NODE_ENV === "production") {
// use minified verion for production
module.exports = require("pdfjs-dist/build/pdf.worker.min.js");
} else {
module.exports = require("pdfjs-dist/build/pdf.worker.js");
}

页面文件 pdf-viewer.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { useState } from "react";
// import default react-pdf entry
import { Document, Page, pdfjs } from "react-pdf";
// import pdf worker as a url, see `next.config.js` and `pdf-worker.js`
import workerSrc from "../pdf-worker";

pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;

export default function PDFViewer() {
const [file, setFile] = useState("./sample.pdf");
const [numPages, setNumPages] = useState(null);

function onFileChange(event) {
setFile(event.target.files[0]);
}

function onDocumentLoadSuccess({ numPages: nextNumPages }) {
setNumPages(nextNumPages);
}

return (
<div>
<div>
<label htmlFor="file">Load from file:</label>{" "}
<input onChange={onFileChange} type="file" />
</div>
<div>
<Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
{Array.from({ length: numPages }, (_, index) => (
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
))}
</Document>
</div>
</div>
);
}

调用

1
2
3
4
5
6
7
8
9
import dynamic from "next/dynamic";

const PDFViewer = dynamic(() => import("../components/pdf-viewer"), {
ssr: false
});

export default function PDF() {
return <PDFViewer />;
}

其他方法

React-PDF

参考文章