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

how to extract images from pdf python
無需設定 Python 即可從 PDF 擷取圖片

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 取出圖片

  1. 開啟 從 PDF 擷取圖片,從你的裝置中選擇一個大小不超過 25 MB 的本地 PDF。
  2. 點擊「擷取圖片」,開始掃描檔案內部受支援的影像物件。掃描、解碼、PNG 編碼與下載檔案的建立,全都會在目前的分頁中完成。
  3. 等待掃描結束。工具會回報每張成功讀取的內嵌影像的格式與像素尺寸。
  4. 使用各項目旁的連結,個別下載支援的 JPG 或 PNG。
  5. 若結果清單中包含略過項目,請判斷是否需要改用其他工具取得整頁快照,或判斷這些略過的影像是否為你工作中的必要內容。

安全限制與略過規則

瀏覽器會在配置輸出緩衝區之前先套用嚴格的預算上限,以免單一影像耗盡分頁的記憶體。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 擷取頁面:初學者逐步指南。