PyQT5によるPDFのJPGへの一括変換手法

PyQT5とPyPDF2を用いたPDF画像化の実装

この記事では、PythonのGUIライブラリであるPyQT5とPDF処理ライブラリのPyPDF2を組み合わせ、PDFファイルの全ページをJPEG画像形式に一括変換するアプリケーションの構築手法を解説します。ドキュメント内の画像抽出や内容の可視化を目的とした実用的なツール開発に焦点を当てています。

PDFレンダリングと画像出力の基本フロー

処理の核心となるのは、PDFのページデータを画像として読み込み、GUI上に表示後にファイル保存する一連の流れです。主な工程は以下の通りです。

  1. PyPDF2を用いたPDFファイルの読み込みとページ分割
  2. PyQT5のQGraphicsViewおよびQGraphicsSceneによるページの可視化
  3. QPixmapを経由したQImageオブジェクトへの変換
  4. 指定品質でのJPEGフォーマットへのエンコードと保存

サンプルコード: PDF読み込みと画像変換

import sys
from PyPDF2 import PdfReader
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
from PyQt5.QtGui import QPixmap, QImage

class PDFConverter:
    def __init__(self):
        self.app = QApplication(sys.argv)
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)

    def load_and_render(self, pdf_path):
        pdf_document = PdfReader(open(pdf_path, 'rb'))
        total_pages = len(pdf_document.pages)

        for idx in range(total_pages):
            page_obj = pdf_document.pages[idx]
            # 仮想のレンダリング: 実際には画像ライブラリの組み合わせが必要
            # ここではプレースホルダー
            page_image = self.render_page_to_image(page_obj)
            self.add_to_scene(page_image)

    def render_page_to_image(self, page):
        # 例: ページを画像としてレンダリングするロジック
        # 実際の実装では外部ライブラリ(e.g., pdf2image)の使用を検討
        from PIL import Image
        import io
        # 仮の画像生成
        img = Image.new('RGB', (800, 1100), color='white')
        return img

    def add_to_scene(self, pil_image):
        # PIL ImageをQPixmapに変換
        byte_arr = io.BytesIO()
        pil_image.save(byte_arr, format='PNG')
        pixmap = QPixmap()
        pixmap.loadFromData(byte_arr.getvalue())
        self.scene.addPixmap(pixmap)

    def save_as_jpeg(self, output_path, quality=85):
        # シーン全体を画像として保存
        view_rect = self.view.viewport().rect()
        scene_image = QImage(view_rect.size(), QImage.Format_RGB32)
        painter = QPainter(scene_image)
        self.view.render(painter)
        painter.end()
        scene_image.save(output_path, 'JPEG', quality)

if __name__ == '__main__':
    converter = PDFConverter()
    converter.load_and_render('sample.pdf')
    converter.view.show()
    converter.save_as_jpeg('output.jpg')
    sys.exit(converter.app.exec_())

GUIアプリケーションの構築例

ユーザーがファイルを選択し、変換設定を調整できる基本的なインターフェースの実装例を示します。

from PyQt5.QtWidgets import (QMainWindow, QPushButton, QFileDialog,
                             QLabel, QVBoxLayout, QWidget, QSpinBox)
from PyQt5.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.pdf_path = ''

    def init_ui(self):
        self.setWindowTitle('PDF to JPG Converter')
        self.resize(400,백)

        layout = QVBoxLayout()

        self.file_label = QLabel('ファイルが選択されていません')
        layout.addWidget(self.file_label)

        select_btn = QPushButton('PDFを選択')
        select_btn.clicked.connect(self.select_file)
        layout.addWidget(select_btn)

        self.quality_spin = QSpinBox()
        self.quality_spin.setRange(1, 100)
        self.quality_spin.setValue(90)
        self.quality_spin.setPrefix('品質: ')
        self.quality_spin.setSuffix('%')
        layout.addWidget(self.quality_spin)

        convert_btn = QPushButton('変換開始')
        convert_btn.clicked.connect(self.start_conversion)
        layout.addWidget(convert_btn)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def select_file(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self, 'PDFファイルを選択', '', 'PDF Files (*.pdf)')
        if file_name:
            self.pdf_path = file_name
            self.file_label.setText(f'選択済: {file_name}')

    def start_conversion(self):
        if not self.pdf_path:
            return
        # ここで変換ロジックを呼び出す
        quality = self.quality_spin.value()
        print(f'変換開始: {self.pdf_path}, 品質: {quality}')

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

画像処理におけるQPixmapとQImageの使い分け

表示に特化したQPixmapと、画像処理操作に適したQImageの違いを理解することが重要です。変換処理では以下のように使い分けます。

  • QPixmap: GUIウィジェット上への画像表示に最適化されており、ハードウェアアクセラレーションを活用できます。
  • QImage: ピクセルデータへの直接アクセスが可能で、形式変換やフィルタ処理などの画像処理に適しています。

保存前には、通常QPixmapをQImageに変換して処理を行います。

def convert_and_save(pixmap, filename, quality):
    # QPixmapからQImageへ変換
    temp_image = pixmap.toImage()
    # 必要に応じてフォーマット変換
    if temp_image.format() != QImage.Format_RGB32:
        temp_image = temp_image.convertToFormat(QImage.Format_RGB32)
    # JPEGで保存
    success = temp_image.save(filename, 'JPEG', quality)
    return success

バッチ処理の実装と考慮点

複数のPDFファイルを連続処理する場合は、進捗状況のフィードバックとエラー処理が不可欠です。スレッドを使用してGUIの応答性を維持する例を示します。

from PyQt5.QtCore import QThread, pyqtSignal

class ConversionWorker(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(list)

    def __init__(self, file_list, output_dir, quality):
        super().__init__()
        self.files = file_list
        self.output = output_dir
        self.quality_setting = quality

    def run(self):
        results = []
        total = len(self.files)
        for idx, pdf_file in enumerate(self.files):
            try:
                # 変換処理の実行
                success = self.convert_single(pdf_file)
                results.append((pdf_file, success))
            except Exception as e:
                results.append((pdf_file, str(e)))
            # 進捗を通知
            self.progress.emit(int((idx + 1) / total * 100))
        self.finished.emit(results)

    def convert_single(self, pdf_path):
        # 個別ファイルの変換ロジック
        # ...
        return True

このアプローチにより、大量のファイルを変換中でもユーザーインターフェースがフリーズすることを防ぎ、処理状況を可視化できます。

タグ: PyQt5 pypdf2 Python JPEG 画像処理

9月18日 09:14 投稿