pythonでPDFから画像の抽出する備忘録

pythonのPyPDF2を使ってPDFから画像(jpeg)を抽出したときに引っかかったところのメモ。

やりたかったこと

書籍をスキャンして自炊したPDFデータから画像データの抽出し、その画像を回転させて保存する。

やってみたこと

まずはPDFからの画像の抽出を下記のサイトを参考にやってみましたが…

そのままコードのコピペだと上手く行きませんでした。
'/Filter'が '/DCTDecode'だとサポート外?と言うことでgetDataメソッドがエラーになりにっちもさっちも行きません…
で、いろいろググってみるとgetDataではなく_dataでいけるようでした。(どこのサイトかは失念w)

import PyPDF2

pdf = PyPDF2.PdfFileReader('hogehoge.pdf')

xObject = pdf.pages[0]['/Resources']['/XObject'].getObject()

for obj in xObject:
    if xObject[obj]['/Subtype'] == '/Image':
        if xObject[obj]['/Filter'] == '/DCTDecode':
            img = open("hogehoge01.jpg","wb")
            img.write(xObject[obj]._data) # xObject[obj].getData()ではなく._data
            img.close()

画像の回転

次は画像の回転。
訳あってどうしても抽出した画像を回転させる必要があり、pythonで画層処理と言えば"Pillow"ライブラリーで行います。

上記サイトを参考に、rotateを使って回転します。
注意事項としては反時計回りに角度を指定することと、expand=True という引数を与えないと、回転前の縦横の大きさの中に画像を押し込めるのでその指定を忘れないこと。

from PIL import Image

img = Image.open('hogehoge01.jpg')         # 画像を読み込み
img_rotate = img.rotate(90, expand=True)   # 回転を画像して
img_rotate.save('hogehoge01_rotate.jpg')   # 保存

ちょっとした問題

さて、PDFから抽出した画像を回転して保存の流れは出来ましたが、ここで画像をファイルにいちいち保存してまた読み込んで回転してまた保存…、というのは流石にファイルアクセスが増えるのでどうだろう?と思い、またまたググってみましたが、どうやらBytesIOと言うのを使うと良いらしいと。

要するにファイルに保存するんでは無くBytesIOにいったん保存したことにする、感じでしょうか?

import io
from PIL import Image

img = io.BytesIO(xObject[obj]._data)     # PDFの画像データを一端BytesIOに保存
im = Image.open(img)                     # Pillowで読み込み
img_rotate = im.rotate(90, expand=True)  # 回転を画像して
img_rotate.save('hogehoge01.jpg')   # 保存

と言うことでまとめるとこんな感じでしょうか。

import PyPDF2
import io
from PIL import Image

pdf = PyPDF2.PdfFileReader('hogehoge.pdf')

xObject = pdf.pages[0]['/Resources']['/XObject'].getObject()

for obj in xObject:
    if xObject[obj]['/Subtype'] == '/Image':
        if xObject[obj]['/Filter'] == '/DCTDecode':
            img = io.BytesIO(xObject[obj]._data)     # PDFの画像データを一端BytesIOに保存
            im = Image.open(img)                     # Pillowで読み込み
            img_rotate = im.rotate(90, expand=True)  # 回転を画像して
            img_rotate.save('hogehoge01.jpg')        # 保存

あとは全ページループしてやれば全ての画像が保存できるようになると思います。

追記

使用バージョンを書いておきます。
python 3.7.2
PyPDF2 1.26.0
Pillow 5.4.1

この記事が気に入ったらサポートをしてみませんか?