【Python】PDF内の画像を一括抽出するスクリプト【D&D対応】

本ブログはアフィリエイト広告を利用しています

WEB / アプリ
WEB / アプリ
この記事は約8分で読めます。

とっちゃん@nyanco! です。

今回はドラッグ&ドロップして入力したPDFファイル内に配置されている画像を一括で抽出するPythonコードの共有です。

肉玉にゃんこ

今まではAdobeのPhotoshopでやってたけど、pythonの方がめちゃくちゃ早くて楽ですにゃ~

スポンサーリンク

コードの動作環境

  • OS:Windows11
  • Pythonバージョン:3.11.2
  • 別途必要ライブラリ:
    • tkinterdnd2:ドラッグ&ドロップ機能を実装するためのライブラリ
    • fitz (PyMuPDF):PDFファイルを操作し、画像を抽出するためのライブラリ
pip install tkinterdnd2
pip install PyMuPDF

PDF内の画像を一括抽出するスクリプト

早速ですがコードはこちら!

import tkinter as tk
from tkinter import ttk
from tkinterdnd2 import DND_FILES, TkinterDnD
import fitz  # PyMuPDF
import os
import sys

class PDFExtractorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF画像抽出ツール")
        self.root.geometry("400x300")

        self.setup_ui()

    def setup_ui(self):
        # ドラッグ&ドロップ領域
        self.drop_area = ttk.Label(self.root, text="PDFファイルをここにドラッグ&ドロップしてください", borderwidth=2, relief="groove")
        self.drop_area.pack(pady=20, padx=20, fill=tk.BOTH, expand=True)

        # ドラッグ&ドロップの設定
        self.drop_area.drop_target_register(DND_FILES)
        self.drop_area.dnd_bind('<<Drop>>', self.on_drop)

        # 抽出ボタン
        self.extract_button = ttk.Button(self.root, text="画像を抽出", command=self.extract_images)
        self.extract_button.pack(pady=10)

        # ステータス表示(折り返し対応)
        self.status_label = ttk.Label(self.root, text="", wraplength=350, justify="left")
        self.status_label.pack(pady=10, padx=10, fill=tk.X)

        # ウィンドウサイズ変更時にラベルの折り返し幅を調整
        self.status_label.bind("<Configure>", self.adjust_wraplength)

        self.pdf_path = None

    def adjust_wraplength(self, event):
        """ステータスラベルのwraplengthをウィンドウ幅に合わせて調整"""
        new_width = event.width - 20  # ラベルの幅に合わせて調整(余白を考慮)
        if new_width > 0:
            self.status_label.config(wraplength=new_width)

    def on_drop(self, event):
        file_path = event.data.strip('{}')
        try:
            # ファイルパスをデコード
            file_path = file_path.encode(sys.getfilesystemencoding()).decode('utf-8')
            if file_path.lower().endswith('.pdf'):
                self.pdf_path = file_path
                self.drop_area.config(text=f"選択されたPDF: {os.path.basename(self.pdf_path)}")
                self.status_label.config(text="PDFが読み込まれました。抽出ボタンを押してください。")
            else:
                self.status_label.config(text="エラー: PDFファイルをドロップしてください。")
        except Exception as e:
            self.status_label.config(text=f"エラー: ファイルの読み込みに失敗しました。{str(e)}")

    def extract_images(self):
        if not self.pdf_path:
            self.status_label.config(text="エラー: PDFファイルが選択されていません。")
            return

        try:
            pdf_file = fitz.open(self.pdf_path)
            num_of_pics = 0

            # PDFファイルのディレクトリを取得
            pdf_dir = os.path.dirname(self.pdf_path)
            pdf_filename = os.path.splitext(os.path.basename(self.pdf_path))[0]

            # 新しいフォルダを作成
            output_folder = os.path.join(pdf_dir, f"{pdf_filename}_images")
            os.makedirs(output_folder, exist_ok=True)

            for page_num, page in enumerate(pdf_file):
                images = page.get_images()
                for image in images:
                    num_of_pics += 1
                    xref = image[0]
                    img = pdf_file.extract_image(xref)
                    image_filename = f"page{page_num+1}_img{num_of_pics}.{img['ext']}"
                    image_path = os.path.join(output_folder, image_filename)
                    with open(image_path, "wb") as f:
                        f.write(img["image"])

            pdf_file.close()
            self.status_label.config(
                text=f"{num_of_pics}枚の画像を '{output_folder}' に抽出しました。"
            )
        except Exception as e:
            self.status_label.config(text=f"エラー: 画像の抽出に失敗しました。{str(e)}")

if __name__ == "__main__":
    root = TkinterDnD.Tk()
    app = PDFExtractorApp(root)
    root.mainloop()

コードは自動生成AI「perplexity」で作成したものを元にカスタマイズしています。

肉玉にゃんこ

自分用にカスタマイズする箇所は特になしなのですぐ使えますにゃ~

以下、具体的な使い方の流れですが、非常に簡単です。

▼pythonファイルを実行すると「PDF画像抽出ツール」という小さなウィンドウが表示されるので、ここに画像を抽出したいPDFをドラッグ&ドロップするだけです!

▼ちなみに今回はテストでこんな感じに青空の写真が4枚貼られているPDFで試してみます。

「PDFファイルをここにドラッグ&ドロップしてください」というエリアにPDFをドラッグ&ドロップします。

▼正常にPDFが読み込まれたら「画像を抽出」ボタンをクリックします。

▼ウィンドウ下部にこのようなメッセージが表示されたら抽出完了です!

肉玉にゃんこ

めちゃ早&楽ですにゃ~

▼PDFと同じフォルダに「PDFのファイル名_images」というフォルダが自動生成されているのでダブルクリックで開きます。

▼このように画像の抽出が確認できればOKです!

肉玉にゃんこ

複数ページのPDFでも、どのページにあった画像かファイル名で分かるようになってるので便利ですにゃ~

抽出される画像の解像度はPDF作成時の設定によるので、PDFによっては非常にファイルサイズが小さい画像が抽出されることもあります。

▼サクッとすぐに使えるように下記より.pyファイルのダウンロードも可能です(zip圧縮しています)。

→PDFの画像を一括抽出する.pyファイルをダウンロード

おわりに

本記事がどなたかの参考になれば幸いです。

今回は以上となります。
最後まで読んでいただきましてありがとうございました!
それではまた〜✧٩(ˊωˋ*)و✧

コメント