PyMuPDFでPDFファイルの画像を抜き出す方法を紹介します。
資料作成を作成していて、PDFファイルに入っている図をたくさん使いたい・・・という場面がありました。
手作業で画像をコピーしたり、キャプションしても良かったのですが、使いたい図も多くて手作業も面倒だし、今後の事も考えてPythonでPDFファイル中の図を全部引っこ抜くということをやってみました。
PDFファイルにある図を使いたいとき、毎回PDFファイルを開いて探すというもの面倒です。図を抜き出しておいてpngやjpegで保存しておくと探したりコピーしたりする手間を省けますので、ぜひ参考にしてください。論文等から画像を取得しまくりたい!という場合とかに使えるかと思います。
PyMuPDFでPDFファイルから画像を抜き出す
PyMuPDFを使ってPDFから画像を抜き出す手順は以下のような感じです。
- get_images()またはget_page_images()を使って画像(イメージ情報)を取得する
- 取得した画像情報からxref(画像の場所を表すようなもの)を取得する
- extract_images(xref)で画像を抽出する
- 取得した画像をファイルに保存する
画像(イメージ)情報を取得する
画像を抜き出すためにはまず、PDFファイルに埋め込まれている画像情報を抜き出します。
画像情報を抜き出すにはPageオブジェクトのget_images()を使います。get_images()を実行すると配列返されます。
Pageオブジェクト.get_images()
または、Documentオブジェクトのget_page_images()を使います。get_page_images()には引数としてページ番号を渡します。
Documentオブジェクト.get_page_images(ページ番号)
import fitz
filename = "progit-ja.1016.pdf"
#PDFファイルを開く(Documentオブジェクトを取得)
pdf_file = fitz.open(filename)
#30ページ目を開く(Pageオブジェクトを取得)
page = pdf_file[29]
#get_images()で画像情報を取得
images = page.get_images()
#=> [(132, 133, 800, 683, 8, 'Indexed', '', 'I1', 'FlateDecode')]
#get_page_images()で画像情報を取得
images2 = pdf_file.get_page_images(0)
#=> [(132, 133, 800, 683, 8, 'Indexed', '', 'I1', 'FlateDecode')]
xrefを取得する
xrefは上のコードで示した、変数imagesまたはimages2の先頭に格納されています。images、images2はリストの中にタプルが格納された形式になっていますので、xrefを取り出すためには以下のようにします
xref = images[0][0]
#=> 132
xref2 = images2[0][0]
#=> 132
'''
もし1ページに複数画像がある場合は以下のようにリストに複数タプルが格納される
[(132, 133, 800, 683, 8, 'Indexed', '', 'I1', 'FlateDecode'),
(146, 147, 800, 556, 8, 'Indexed', '', 'I1', 'FlateDecode')]
xref_0 = iamges[0][0]
xref_1 = images[1][0]
'''
画像を抽出する
画像を抽出するにはDocumentオブジェクトのextract_image()を使います。先程述べたように、引数にはxrefを渡します
Documentオブジェクト.extract_image(xref)
extract_image()はDict(辞書)を返します。色々な値が入っていますが、キーの値が”image”となっている箇所が実際の画像の情報になります。
img = extract_image(xref)
'''
imgの中身
{'ext': 'png', 'smask': 133, 'width': 800, 'height': 683,
'colorspace': 1, 'bpc': 8, 'xres': 96, 'yres': 96, 'cs-name':
'Indexed(255,DeviceRGB)',
'image': b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03 ...省略}
'''
画像を保存する
img[“image”]の値はバイナリデータです。よって、open()のmode引数に”wb”を指定してファイルを開き、開いたファイルにバイナリデータを書き込みます。
with open("extracted.jpg", "wb") as f:
f.write(img["image"])
#Documentオブジェクトを閉じる
pdf_file.close()
PyMuPDFでPDFの画像をすべて抜き出す(コードの例)
説明した内容を使って、ProGitマニュアルの中にある画像をすべて抜き出してみます。
import fitz
filename = "progit-ja.1016.pdf"
pdf_file = fitz.open(filename)
num_of_pics = 0
for page in pdf_file:
images = page.get_images()
if not len(images) == 0:
for image in images:
num_of_pics += 1
xref = image[0]
img = pdf_file.extract_image(xref)
with open("extracted_image{}.png".format(num_of_pics), "wb") as f:
f.write(img["image"])
pdf_file.close()