持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
如何在 JavaScript 中读取本地 PDF 文件
在对我们的 PDF 文档进行任何操作之前,我们必须从用户那里获取文档。在浏览器中读取任何文件都可以通过FileReader
Web API 处理。
首先,我们将制作文件输入按钮,然后使用FileReader
Web API 处理上传的文件。
<input type="file" id="file-selector" accept=".pdf" onChange={onFileSelected} />
复制代码
由于 Filereader API 与回调一起使用,我发现 async/await 更加简洁且易于使用。因此,让我们创建一个辅助函数来将 Filereader 回调修改为 async/await。
function readFileAsync(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
复制代码
现在,当用户使用之前的文件输入上传文件时,我们会监听文件输入事件,然后使用此readFileAsync
函数读取文件。
此逻辑的实现在代码中如下所示:
const onFileSelected = async (e) => {
const fileList = e.target.files;
if (fileList?.length > 0) {
const pdfArrayBuffer = await readFileAsync(fileList[0]);
}
};
复制代码
如何提取 PDF 页面
至此,我们的 PDF 已上传并转换为 JavaScript ArrayBuffer
。当我们从 PDF 中提取一系列页面时,我们需要一个包含 PDF 的页码的数组。
在 JavaScript 中生成自然数数组并不难。所以我们创建了一个函数range()
来生成我们想要的所有索引。
我们必须提供起始页码和结束页码,然后此range()
函数可以生成具有适当页码的数组。
function range(start, end) {
let length = end - start + 1;
return Array.from({ length }, (_, i) => start + i - 1);
}
复制代码
在这里,我们在末尾添加 -1。你知道原因吗?是的——在编程中,索引从 0 开始,而不是 1。所以我们必须从每个页码中减去 -1 以获得我们想要的行为。
现在让我们开始本文的主要部分:提取。在进行任何工作之前,请导入 pdf-lib 库。
import { PDFDocument } from "pdf-lib";
复制代码
首先,我们加载ArrayBuffer
从上一个onFileSelected
函数中获得的 PDF。然后我们将 加载ArrayBuffer
到PDFDocument.load(arraybuffer)
函数中。这是我们用户提供的 PDF。为方便起见,我们将其称为pdfSrcDoc
。
现在我们将创建一个新的 PDF。从用户提供的文档中提取的所有 PDF 页面都合并到新文档中。我们使用该PDFDocument.create()
功能来做到这一点。为了使用方便,我们称之为pdfNewDoc
。
之后,我们使用该功能将所需的页面从其中复制pdfSrcDoc
到。然后我们将复制的页面添加到.pdfNewDoc``copyPages()``pdfNewDoc
要保存更改,请运行pdfNewDoc.save()
. 让我们创建一个调用extractPdfPage()
来重用逻辑的函数。函数内部的代码如下所示:
async function extractPdfPage(arrayBuff) {
const pdfSrcDoc = await PDFDocument.load(arrayBuff);
const pdfNewDoc = await PDFDocument.create();
const pages = await pdfNewDoc.copyPages(pdfSrcDoc,range(2,3));
pages.forEach(page=>pdfNewDoc.addPage(page));
const newpdf= await pdfNewDoc.save();
return newpdf;
}
复制代码
我们Uint8Array
从extractPdfPage()
函数中返回一个。
如何在浏览器中渲染 PDF
到目前为止,我们有Uint8Array
一个修改后的 PDF。要在浏览器中呈现它,我们必须将其转换为 Blob。
然后我们将用它制作一个 URL 并在 iframe 中呈现它。
如上所述,你还可以使用 pdfjs 库制作自定义 PDF 查看器。但是,如果你不需要这样的品牌和自定义,浏览器的默认 PDF 查看器就可以用于此目的。
function renderPdf(uint8array) {
const tempblob = new Blob([uint8array], {
type: "application/pdf",
});
const docUrl = URL.createObjectURL(tempblob);
setPdfFileData(docUrl);
}
复制代码
现在,你可以轻松地renderPdf()
在iframe
.
完整的代码示例
我在本教程中使用 Next.js。如果你使用其他框架或原生 JavaScript,结果将是相似的。这是这个项目的所有代码:
import { useState } from "react";
import { PDFDocument } from "pdf-lib";
export default function Home() {
const [pdfFileData, setPdfFileData] = useState();
function readFileAsync(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
function renderPdf(uint8array) {
const tempblob = new Blob([uint8array], {
type: "application/pdf",
});
const docUrl = URL.createObjectURL(tempblob);
setPdfFileData(docUrl);
}
function range(start, end) {
let length = end - start + 1;
return Array.from({ length }, (_, i) => start + i - 1);
}
async function extractPdfPage(arrayBuff) {
const pdfSrcDoc = await PDFDocument.load(arrayBuff);
const pdfNewDoc = await PDFDocument.create();
const pages = await pdfNewDoc.copyPages(pdfSrcDoc, range(2, 3));
pages.forEach((page) => pdfNewDoc.addPage(page));
const newpdf = await pdfNewDoc.save();
return newpdf;
}
// Execute when user select a file
const onFileSelected = async (e) => {
const fileList = e.target.files;
if (fileList?.length > 0) {
const pdfArrayBuffer = await readFileAsync(fileList[0]);
const newPdfDoc = await extractPdfPage(pdfArrayBuffer);
renderPdf(newPdfDoc);
}
};
return (
<>
<h1>Hello world</h1>
<input
type="file"
id="file-selector"
accept=".pdf"
onChange={onFileSelected}
/>
<iframe
style={{ display: "block", width: "100vw", height: "90vh" }}
title="PdfFrame"
src={pdfFileData}
frameborder="0"
type="application/pdf"
></iframe>
</>
);
}
复制代码
你现在可以使用 PDF 查看器上的下载按钮保存生成的 PDF。
结论
感谢你的阅读