如何從 PDF 中提取頁面並使用 JavaScript 渲染它們(下)

語言: CN / TW / HK

theme: channing-cyan

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第21天,點選檢視活動詳情

如何在 JavaScript 中讀取本地 PDF 檔案

在對我們的 PDF 文件進行任何操作之前,我們必須從使用者那裡獲取文件。在瀏覽器中讀取任何檔案都可以通過FileReaderWeb API 處理。

首先,我們將製作檔案輸入按鈕,然後使用FileReaderWeb 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。然後我們將 載入ArrayBufferPDFDocument.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; }

我們Uint8ArrayextractPdfPage()函式中返回一個。

如何在瀏覽器中渲染 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 ( <>

Hello world


); } ```

你現在可以使用 PDF 檢視器上的下載按鈕儲存生成的 PDF。

結論

感謝你的閱讀