若要使用 Python 從 PDF 中擷取圖片,通常會安裝像是 PyMuPDF 或 pdfplumber 這類的函式庫,逐一處理文件中的影像 XObject,然後將每張點陣圖寫入磁碟;瀏覽器工具則可以在單一本地 PDF 上執行相同的擷取作業,既不需要安裝 Python,也不必上傳檔案。這項工作在兩個環境中完全相同:在 PDF 內部定位影像字典、判斷其篩選器位元組實際代表的內容,然後寫入可用的影像檔。DCTDecode 串流本身就是 JPEG 承載內容,因此工具可以將原始位元組原封不動地儲存。單純的 FlateDecode 串流加上 8 位元 DeviceRGB 或 DeviceGray 像素,本身並非完整的影像檔,因此瀏覽器會在本地將其解壓縮,並編碼為一般應用程式都能開啟的 PNG 格式。至於其他更為特殊的格式,包括 JPX、JBIG2、LZW、索引色盤、CMYK、遮罩以及預測器鏈結等,則會被標示為略過,而不是以錯誤的色彩強制解碼。在 Python 程式碼路徑與瀏覽器路徑之間做選擇,主要取決於你需要多常執行這項工作,以及是否想在執行工作的機器上管理相依套件。

Python 或瀏覽器:為 PDF 圖片擷取選擇正確路徑
兩種方法檢查的是相同的底層機制:PDF 將影像儲存為稱為影像 XObject 的間接物件,每個物件都帶有一個篩選器項目,用來標示其編碼方式。Python 函式庫會公開這些物件,讓腳本可以讀取篩選器、解壓縮串流,然後儲存位元組。瀏覽器工具則透過 pdf-lib 執行相同的檢查,接著在目前的分頁中套用其支援的編碼政策。取捨並不在於品質——對於支援的編碼來說,兩種路徑會產生相同的檔案——而在於工作流程與額外負擔。
- 在未安裝 Python 的機器上,對單一文件執行一次作業,那麼瀏覽器工具的設定速度會比全新的虛擬環境更快。
- 在數百份文件上反覆執行作業、將其整合進資料處理流程,或是以程式化方式後處理每張圖片,則 Python 腳本可提供控制權、批次處理與可重現性。
- 需要的是包含文字與向量圖稿的整頁快照,而非原始的內嵌資產嗎?這時應該使用的是頁面轉換工具,而不是上述任何一種。
瀏覽器工具在 PDF 內部可辨識的內容
瀏覽器工具在 PDF 儲存影像資料的眾多方式中,只辨識兩種有限的情形。DCTDecode 是 PDF 規範中內嵌 JPEG 串流的名稱;這些位元組已經遵循 JPEG 檔案格式,因此工具會將其匯出為 JPG,而不重新渲染或重新壓縮,下載的檔案會與 PDF 內部儲存的影像承載內容完全一致。搭配 8 位元 DeviceRGB 或 DeviceGray 的 FlateDecode,則是經 zlib 壓縮的原始像素陣列。這些位元組本身並非獨立的影像檔,因此瀏覽器工具會使用 DecompressionStream 將其解壓縮,把像素放到本地畫布上,然後編碼為可供下載的 PNG。
其他所有情況都會刻意略過。下表摘要列出你會遇到的編碼方式,以及工具對各項的處理方式。
| 編碼方式或屬性 | 其意義 | 工具行為 |
|---|---|---|
| DCTDecode | 內嵌 JPEG 串流 | 匯出為 JPG,保留原始位元組 |
| FlateDecode,8 位元 DeviceRGB | 原始 RGB 像素,zlib 壓縮 | 解壓縮並編碼為 PNG |
| FlateDecode,8 位元 DeviceGray | 原始灰階像素,zlib 壓縮 | 解壓縮並編碼為 PNG |
| JPXDecode | JPEG 2000 串流 | 略過 |
| JBIG2 | 雙階影像壓縮 | 略過 |
| LZW、RunLength、CCITTFax | 其他壓縮篩選器 | 略過 |
| Indexed、CMYK、Separation、DeviceN | 非 RGB 色彩空間 | 略過 |
| 任何帶有軟遮罩或影像遮罩的影像 | 遮罩化影像 XObject | 略過 |
略過的項目會列在結果中,讓你可以清楚看到工具無法解碼的內容。這一點在 Adobe PDF Reference 中的影像字典與篩選器章節有相關說明,而大多數 Python 函式庫在遇到不支援的串流時所警告的,也是同一組情況。
在瀏覽器中從 PDF 取出圖片
- 開啟 從 PDF 擷取圖片,從你的裝置中選擇一個大小不超過 25 MB 的本地 PDF。
- 點擊「擷取圖片」,開始掃描檔案內部受支援的影像物件。掃描、解碼、PNG 編碼與下載檔案的建立,全都會在目前的分頁中完成。
- 等待掃描結束。工具會回報每張成功讀取的內嵌影像的格式與像素尺寸。
- 使用各項目旁的連結,個別下載支援的 JPG 或 PNG。
- 若結果清單中包含略過項目,請判斷是否需要改用其他工具取得整頁快照,或判斷這些略過的影像是否為你工作中的必要內容。
安全限制與略過規則
瀏覽器會在配置輸出緩衝區之前先套用嚴格的預算上限,以免單一影像耗盡分頁的記憶體。PDF 大小上限為 25 MB,單張影像的最長邊上限為 12,000 像素,單張影像的像素總數上限為 40 百萬像素,整份文件的像素總和上限為 100 百萬像素,解碼後 Flate 承載內容的上限為 100 MB。超過任何一項限制的 PDF,將不會對過大的資產產出部分下載;受影響的影像會被標示為略過。
重複的間接參照,也就是同一張影像出現在多個頁面上,只會被檢查一次並列出一次,如此一來,單一儲存的資產不會變成一組令人困惑的重複下載。受密碼保護、檔案結構損壞或異常複雜的 PDF 仍有可能失敗。此工具不會繞過加密、不會修復損壞檔案、不會驗簽章,也不會對來源文件是否可信做出聲明。當你需要的是嵌入於 PDF 中的照片、Logo、掃描檔或圖形,而且想要的是內嵌資產而非頁面截圖時,可以使用此工具。
何時整頁快照是更好的選擇
匯出內嵌影像物件與渲染整頁之間,確實存在一項實質的區別。上述瀏覽器工具尋找的是儲存在文件內部的影像資料。整頁快照工具則會將頁面上所有可見的內容,包括文字、向量圖稿,以及任何不屬於兩種支援情形的影像,渲染成一張點陣圖片。如果你的 PDF 內含 JPEG 2000 影像、CMYK 掃描檔,或是隱藏在軟遮罩之後的影像,整頁快照仍然能以視覺方式擷取它們,即使內嵌匯出路徑會將其略過。當你需要原始資產時,請使用內嵌匯出工具;當你需要完整的可見頁面時,請使用 PDF 轉 PNG 或 PDF 轉 JPG 轉換器。
你原本會改用的 Python 函式庫
如果你確實偏好程式碼路徑,在目前 Python PDF 影像擷取領域居主導地位的幾個函式庫,各自採取了略為不同的切入角度。PyMuPDF(以 fitz 匯入)速度快且涵蓋範圍廣;當你需要頁面快照時,它能將頁面渲染為 pixmap,同時也能逐一處理原始影像物件。pdfplumber 定位為帶有影像位置中繼資料的 PDF 解析器,並且能與 Pillow 良好搭配,用於輸出格式化。pypdf 是純 Python 的實作,沒有原生相依性,對直接的 DCT 擷取處理得相當好。pikepdf 建構於 C++ 的 QPDF 函式庫之上,能處理其他函式庫有時會拒絕處理的複雜串流與現代篩選器鏈結。
這些函式庫都會透過各自的 API 公開影像 XObject,並以各自的方式決定如何處理不支援的編碼。瀏覽器工具大致等同於 pypdf 的 DCTDecode 路徑,再加上 pdfplumber 的 FlateDecode RGB 與 Gray 路徑,並在任何畫布配置之前先套用安全預算上限。若想更深入了解其底層機制,可參考 pdf-lib PDFRawStream 原始碼,其中展示了在位元組被公開之前,如何解析串流的篩選器清單與解碼參數。
確認下載的影像與來源一致
由於此工具會完整保留 DCTDecode 的位元組,僅將簡單的 FlateDecode 像素重新編碼為 PNG,因此下載的檔案會與 PDF 內部承載的內嵌資產盡可能接近。下載完成後,請在任何影像檢視器中開啟該檔案,確認主體內容與你在頁面上所見相符,接著查看項目旁所列出的尺寸,並與檢視器所顯示的大小進行比對。如果檔案看起來不正確,來源 PDF 可能依賴軟遮罩、ICC 設定檔或此工具無法解碼的色彩空間;此時請改用整頁快照。如需進一步了解在需要單一高解析度資產時如何保留品質,在不損失品質的前提下從 PDF 複製影像指南中對各項取捨有詳細說明。
在確認資產相符之前,請將原始 PDF 與下載的檔案一併保留。臨時下載網址會在你選擇其他檔案或離開工具時釋出,因此請勿將其加入書籤供日後使用。
延伸閱讀:從 PDF 擷取頁面:初學者逐步指南。