卡尼多隨筆

認識自我 • 感受世界 • 創造價值

0%

用 Python 將 PDF 文檔轉成 PNG 圖檔

想把 PDF 轉成圖檔,卻又擔心交給線上工具處理會不會有什麼安全上的疑慮?交給 Python 吧!

本篇大量包含解決問題的思考過程,想省略,裝完套件以後就直接跳到最後面吧!

上網找解決辦法

試著 google「pdf to png python」,找到了 pdf2image

A python (3.6+) module that wraps pdftoppm and pdftocairo to convert PDF to a PIL Image object

看起來,這就是我們要的!

安裝相關套件

本教學以 Mac 為例,其他作業系統的安裝方式請參見 PyPI 上面的說明

因為 pdf2image 是基於 Poppler 開發出來的,所以在安裝 pdf2image 前,先來裝 Poppler 吧!

  1. 打開 Terminal 或 iTerm 之類的終端機
  2. 輸入 brew 看有沒有裝 Homebrew,如果還沒裝就上網找資料裝一裝吧!
    不過 Poppler 的安裝頁面有提供我們裝 Homebrew 的指令,就看要不要直接用,或是另找其他安裝方式也行。
  3. 用 Homebrew 裝 Poppler:在終端機上輸入 brew install poppler 就行囉!
    (如果出現 Updating Homebrew... 可以用 Ctrl+C 跳過更新的程序,不然可能會卡很久)
  4. 用 pip 裝 pdf2image:pip install pdf2image

這樣相關套件就裝完囉,準備來使用吧!

簡單玩一下套件

畢竟之前沒弄過,不確定這符不符合我們的需求。
所以在嘗試解決問題之前,先小玩一下~
pdf2image 頁面有程式碼,就照上面的 code 試試:

  1. import pdf2image 相關套件

    1
    2
    3
    4
    5
    6
    from pdf2image import convert_from_path, convert_from_bytes
    from pdf2image.exceptions import (
    PDFInfoNotInstalledError,
    PDFPageCountError,
    PDFSyntaxError
    )
  2. 第一段程式碼看起來比較簡單,就試那個吧:(檔案的 path 記得要改,可以用相對路徑)

    1
    images = convert_from_path('/home/belval/example.pdf')
  3. images 不知道該怎麼用,就 print 出來看一下囉,print(images),輸出了這些:

    1
    2
    3
    4
    5
    [<PIL.PpmImagePlugin.PpmImageFile image mode=RGB size=1654x2339 at 0x115B32D90>,
    <PIL.PpmImagePlugin.PpmImageFile image mode=RGB size=1654x2339 at 0x115B99B50>,
    <PIL.PpmImagePlugin.PpmImageFile image mode=RGB size=1654x2339 at 0x115B99B90>,
    <PIL.PpmImagePlugin.PpmImageFile image mode=RGB size=1654x2339 at 0x115BA2BD0>,
    <PIL.PpmImagePlugin.PpmImageFile image mode=RGB size=1654x2339 at 0x115BA2FD0>]

    (list 裡面 PIL 的個數取決於 PDF 檔的頁數)

  4. PIL 是什麼東西啊?應該跟 image 有關吧?於是我 google「PIL Image」,找到了這篇
    看那篇文裡面的 code 有 from PIL import Image,該不會又要裝套件了吧⋯⋯
    不管,先試著直接 import PIL,發現可以欸,代表說本機端已經有 PIL 套件了!
    後來發現,原來在裝 pdf2image 時,它就幫我們裝好了 pillow (PIL)。

  5. 有點不務正業,來照剛剛那篇文試試 PIL 吧,說不定能有什麼新發現。

    1
    2
    3
    from PIL import Image
    im = Image.open("test.jpeg")
    im.save("test.png","png")

    還真的生成「test.png」了呢!那 im 又是什麼呢?好奇 print 一下,輸出了這個:

    1
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1500x1000 at 0x10D9FAE50>

    咦?這跟剛剛 images print 出來的東西很像欸,該不會⋯⋯

  6. 柳暗花明又一村:(承接剛剛的 images

    1
    2
    for i, image in enumerate(images):
    image.save(f'{i+1}.png', 'png') # 如果想從 1 開始數的話

    還真的可以欸😂

用套件解決問題

過程中有不懂或忘記的就 google 吧:

最後生出來的 code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pdf2image import convert_from_path, convert_from_bytes
from pdf2image.exceptions import (
PDFInfoNotInstalledError,
PDFPageCountError,
PDFSyntaxError
)
# from PIL import image # 後來發現不需要 import 這個
import os

for name in os.listdir("."): # 取得當前目錄下的所有檔名
if '.pdf' in name: # 只對 PDF 做處理
the_dir = f'{name[:-4]}' # 用 PDF 的檔名當作新資料夾的名稱
os.mkdir(the_dir) # 新建該檔名的資料夾
images = convert_from_path(f'{name}') # 將 PDF 轉成多個 PIL 相關物件
for i, image in enumerate(images): # 針對每個物件去做處理
image.save(f'{the_dir}/{i+1}.png', 'png') # 在新資料夾底下存成 PNG 檔

如此一來,就不必丟到網路上給別人處理了呢!


今天的分享就到這邊,我們下篇文見吧 😃