客戶端 PDF 處理:瀏覽器本機 PDF 工具如何運作
客戶端 PDF 工具做與伺服器 相同的工作,但在使用者的瀏覽器中。這個 頁面面向想了解架構的開發者和 IT 管理員:涉及哪些 瀏覽器 API、哪些函式庫做 繁重工作、檔案實際去了哪裡,以及 誠實的限制是什麼。IXPDF 是進行中的範例,但 模型適用於任何瀏覽器本機 PDF 工具。
管線
從檔案輸入到下載,無需伺服器
客戶端 PDF 操作的端對端 流程是:
- 檔案輸入。使用者將檔案拖放進放置區。瀏覽器給頁面一個
File物件(指向磁碟上檔案的指標,而非位元組本身)。 - 讀入記憶體。頁面呼叫
file.arrayBuffer()將位元組讀入頁面記憶體中的ArrayBuffer。這是檔案位元組存在於頁面中的唯一時刻;它們還不在 worker 中。 - 驗證。頁面在做任何事之前檢查檔案類型(magic bytes、副檔名)和大小。無效檔案在主執行緒上快速失敗,永遠不會到達 worker。
- 轉移至 Web Worker。頁面將
ArrayBuffer發送給 worker,使用可轉移轉移讓位元組移動(無拷貝)到 worker 的堆積區。主執行緒不再存取緩衝區。 - 在 worker 中處理。worker 呼叫 PDF 函式庫(pdf-lib、PDF.js 或編譯為 WASM 的 qpdf/mupdf)來解析和修改 PDF。這是繁重工作,在主執行緒之外執行以免 UI 凍結。
- 回傳結果。worker 產生新的
ArrayBuffer(或Blob)並回傳給主執行緒,同樣以可轉移方式。 - 提供下載。主執行緒將結果包進
Blob,呼叫URL.createObjectURL(blob)並透過<a download>元素提供下載。物件 URL 在下載開始後撤銷以避免記憶體洩漏。
在這個流程中,檔案在任何時候都不會離開 裝置。沒有 fetch、沒有XMLHttpRequest、沒有 包含檔案內容的 sendBeacon。頁面 進行的唯一網路請求是首次 載入頁面時的靜態資源(HTML、JS、CSS、字型)。
建構區塊
涉及的瀏覽器 API 和函式庫
客戶端 PDF 工具依賴一組小 瀏覽器 API 和一組小 JavaScript 函式庫。每個各司其職。
- File API——
File和Blob介面。file.arrayBuffer()將位元組讀入記憶體;new Blob([bytes], { type: 'application/pdf' })將位元組打包以下載。 - Web Workers——有自己堆積區的背景執行緒,無法存取 DOM。PDF 解析在這裡執行讓主執行緒保持回應。通訊透過
postMessage;ArrayBuffer可透過第二個引數轉移(移動,非拷貝)。 - URL.createObjectURL / URL.revokeObjectURL——產生指向記憶體中結果的臨時
blob:URL,讓<a download>元素能提供下載。URL 必須撤銷否則會洩漏。 - pdf-lib——純 JavaScript PDF 函式庫,可建立、修改和重新儲存 PDF。用於合併、分割、旋轉、浮水印、頁面操作和元資料編輯。不處理加密(已知限制——見下文)。
- PDF.js——Mozilla 的 PDF 渲染器,用於將頁面渲染到 canvas(用於 PDF 轉影像)和解析 pdf-lib 無法讀取的 PDF。
- WASM(可選)——用於將原生程式碼編譯為 WASM 在瀏覽器中以接近原生的速度執行的函式庫。qpdf 和 mupdf 可編譯為 WASM;IXPDF 對 pdf-lib 無法完成的操作選擇性地使用此路徑。
- CompressionStream——瀏覽器原生的串流壓縮 API(gzip、deflate)。對某些大小縮減路徑有用,無需交付 JS 壓縮函式庫。
為什麼用 worker
為什麼 PDF 解析不在主執行緒上執行
PDF 解析是 CPU 密集且 同步的——讀位元組、解碼物件、跟隨 交叉引用、建構記憶體中的樹。50 MB 的 PDF 可能需要數百 毫秒解析,200 MB 的可能 需要數秒。如果這工作在 主執行緒上執行,頁面在整個 期間凍結:沒有動畫、沒有捲動、沒有輸入。 瀏覽器可能顯示「頁面無回應」對話框。
將工作移到 Web Worker 解決了這個問題。主 執行緒保持回應;worker 在背景處理 PDF; 頁面顯示進度指示器並在 worker 回傳 結果時更新 UI。代價是 worker 無法 存取 DOM,因此所有 UI 工作必須在 結果回傳後在主執行緒上進行。
worker 也有自己的記憶體預算。轉移給 worker 的大型 PDF 存在 worker 的 堆積區,而非頁面的。這對 非常大的檔案很重要:頁面可以保持輕量,而 worker 持有重型緩衝區,且緩衝區在 worker 完成時釋放。
可轉移物件
移動位元組,而非拷貝
當 ArrayBuffer 在不轉移的情況下發送給 worker 時,位元組被拷貝—— worker 得到自己的副本,主執行緒 保留原始。對 100 MB 的 PDF, 這意味使用了 200 MB 記憶體且有 可察覺的拷貝時間。
解決方案是轉移清單:postMessage 的第二個引數。將 緩衝區列入轉移清單會將 位元組移動到 worker——主執行緒的 引用被分離(長度為零),worker 取得 所有權。無拷貝、無記憶體倍增。回傳 結果時也用同樣的方法。
這是個小細節,但在規模上很重要。 沒有可轉移物件,大檔案的 客戶端 PDF 處理將不切實際。
誠實的限制
瀏覽器無法做好的事
客戶端處理不是銀彈。 有些操作在 瀏覽器中難以或無法做好,誠實的 工具會說出來而非偽造。
- OCR。對掃描 PDF 進行光學字元辨識需要訓練好的模型和大量 CPU。瀏覽器 OCR 存在(Tesseract.js)但品質遠不如桌面 Tesseract 或雲端 OCR。IXPDF 將 OCR 標記為尚在研究。
- PDF 加密(密碼保護)。pdf-lib 尚不支援寫入加密 PDF。新增需要另一個函式庫或編譯為 WASM 的 qpdf。IXPDF 的保護 PDF 工具尚在研究。
- PDF 轉 Word/Excel/PowerPoint。將 PDF 轉換為可編輯的 Office 檔案是版面重建問題,需要後端。嘗試的瀏覽器函式庫產出低保真輸出。IXPDF 不提供這些轉換。
- AI 摘要/問答。需要模型和後端。2026 年無法在客戶端以可接受的品質完成。IXPDF 不提供 AI 功能。
- 非常大的檔案。瀏覽器分頁有記憶體預算(通常幾 GB)。2 GB 的 PDF 在大多數瀏覽器中會 OOM。伺服器端工具用串流處理;瀏覽器工具無法以同樣方式串流 PDF。
誠實的做法是在 UI 中將這些功能標記為Planned、Research Required 或Future Backend Candidate,而非 交付回傳空輸出並 假裝成功的假工具。這是本地優先工具和 內容農場「工具」頁面之間的界線。
為什麼重要
隱私屬性是結構性的,不是承諾
接下來閱讀