Pythonで画像をPDFに変換する

プログラミング

Pythonで画像をPDFに変換する

Pythonを使用して画像をPDFファイルに変換する方法は、いくつかのライブラリを利用することで実現できます。ここでは、代表的なライブラリであるPillowとreportlabを使った方法を中心に、その手順、応用、注意点などを解説します。

Pillowを用いた基本的な変換

Pillowは、Pythonで画像を扱うための強力なライブラリであり、画像ファイルの読み込み、加工、保存など、幅広い機能を提供します。Pillow単体で直接PDFに保存する機能は持っていませんが、画像を一度PillowのImageオブジェクトとして読み込み、その画像をreportlabなどのPDF生成ライブラリに渡すことで、PDFに埋め込むことができます。

Pillowのインストール

まず、Pillowをインストールします。コマンドプロンプトまたはターミナルで以下のコマンドを実行してください。

pip install Pillow

reportlabのインストール

次に、PDFを生成するためのライブラリであるreportlabをインストールします。

pip install reportlab

Pillowとreportlabを組み合わせた変換

以下は、Pillowで画像を読み込み、reportlabを使ってPDFに保存する基本的なコード例です。


from PIL import Image
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch

def image_to_pdf(image_path, output_pdf_path):
    try:
        # 画像をPillowで開く
        img = Image.open(image_path)
        img_width, img_height = img.size

        # PDFキャンバスを作成
        c = canvas.Canvas(output_pdf_path)

        # 画像のアスペクト比を維持したまま、PDFページに収まるようにサイズを調整
        # PDFのページサイズ(デフォルトはA4)に対して画像のサイズを計算
        page_width, page_height = c._pagesize
        aspect_ratio = img_height / img_width

        if img_width > page_width or img_height > page_height:
            if img_width / page_width > img_height / page_height:
                # 横幅を基準に縮小
                new_width = page_width
                new_height = page_width * aspect_ratio
            else:
                # 高さを基準に縮小
                new_height = page_height
                new_width = page_height / aspect_ratio
        else:
            # 画像がページサイズより小さい場合はそのまま
            new_width = img_width
            new_height = img_height

        # 画像をPDFに描画
        # 座標 (0, 0) は左下隅
        # 画像を中央に配置する場合の計算例
        x_offset = (page_width - new_width) / 2
        y_offset = (page_height - new_height) / 2
        c.drawInlineImage(img, x_offset, y_offset, width=new_width, height=new_height)

        # PDFを保存
        c.save()
        print(f"Successfully converted {image_path} to {output_pdf_path}")

    except FileNotFoundError:
        print(f"Error: Image file not found at {image_path}")
    except Exception as e:
        print(f"An error occurred: {e}")

# 使用例
# image_file = "your_image.jpg"  # 変換したい画像ファイルのパスを指定
# output_pdf = "output.pdf"     # 出力するPDFファイルのパスを指定
# image_to_pdf(image_file, output_pdf)

このコードでは、Image.open()で画像を読み込み、そのサイズを取得します。canvas.Canvas()でPDFドキュメントを作成し、drawInlineImage()メソッドを使って画像をPDFに描画します。画像のサイズ調整は、PDFのページサイズに合わせてアスペクト比を維持しながら行われます。

複数の画像を一つのPDFに変換する

複数の画像を順番に一つのPDFファイルにまとめることも一般的です。この場合、各画像に対してdrawInlineImage()を呼び出すことになります。

複数画像変換のコード例


from PIL import Image
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter # ページサイズとしてletterを選択

def images_to_pdf(image_paths, output_pdf_path):
    try:
        c = canvas.Canvas(output_pdf_path, pagesize=letter) # ページサイズを指定
        page_width, page_height = letter # 選択したページサイズを取得

        for image_path in image_paths:
            try:
                img = Image.open(image_path)
                img_width, img_height = img.size

                # 画像のアスペクト比を維持したまま、PDFページに収まるようにサイズを調整
                aspect_ratio = img_height / img_width

                if img_width > page_width or img_height > page_height:
                    if img_width / page_width > img_height / page_height:
                        new_width = page_width * 0.9 # 余白を考慮
                        new_height = page_width * aspect_ratio * 0.9
                    else:
                        new_height = page_height * 0.9 # 余白を考慮
                        new_width = page_height / aspect_ratio * 0.9
                else:
                    new_width = img_width
                    new_height = img_height

                # 画像をPDFに描画(中央配置)
                x_offset = (page_width - new_width) / 2
                y_offset = (page_height - new_height) / 2
                c.drawInlineImage(img, x_offset, y_offset, width=new_width, height=new_height)

                # 次の画像のために新しいページを追加(最初の画像以外)
                c.showPage()

            except FileNotFoundError:
                print(f"Warning: Image file not found at {image_path}. Skipping.")
            except Exception as e:
                print(f"An error occurred while processing {image_path}: {e}. Skipping.")

        # 最後のページを保存
        c.save()
        print(f"Successfully converted multiple images to {output_pdf_path}")

    except Exception as e:
        print(f"An error occurred during PDF creation: {e}")

# 使用例
# image_files = ["image1.jpg", "image2.png", "image3.jpeg"] # 変換したい画像ファイルのパスのリスト
# output_pdf_multiple = "output_multiple.pdf"
# images_to_pdf(image_files, output_pdf_multiple)

この例では、image_pathsというリストに画像ファイルのパスを格納し、ループ処理で各画像をPDFに描画しています。c.showPage()メソッドは、現在のページを終了し、次のページを開始するために使用されます。これにより、各画像が別々のページに配置されます。

ページサイズと余白の調整

reportlabでは、pagesizesモジュールからさまざまな標準ページサイズ(letter, A4, legalなど)を選択できます。また、画像を描画する際にx_offsetやy_offsetを調整することで、ページ内での配置を制御したり、余白を設けることができます。上記のコード例でも、画像サイズをページサイズの90%に収めるように調整することで、ある程度の余白を確保しています。

より高度なPDF生成:reportlabの活用

reportlabは単に画像を配置するだけでなく、テキスト、図形、表などを組み合わせて、より複雑なレイアウトのPDFを生成するための豊富な機能を提供します。

テキストの追加

画像の上にキャプションなどを追加したい場合、canvas.drawString()やcanvas.drawText()メソッドを使用します。

図形の描画

線(canvas.line())や矩形(canvas.rect())、円(canvas.circle())なども描画可能です。

フォントとスタイルの設定

reportlab.lib.fontsモジュールやcanvas.setFont()メソッドを使って、フォントの種類、サイズ、色などを設定できます。

その他のライブラリの利用

reportlab以外にも、PythonでPDFを生成するためのライブラリは存在します。

wkhtmltopdf と pdfkit

wkhtmltopdfは、HTML/CSSをPDFに変換するツールであり、Pythonからはpdfkitライブラリを経由して利用できます。WebページをPDF化するのに適していますが、画像のみを変換する場合は、一度HTMLを作成してからPDF化する手間がかかります。

fpdf2

fpdf2は、FPDFライブラリのフォークであり、比較的シンプルで使いやすいPDF生成ライブラリです。画像挿入機能も備わっています。

注意点と考慮事項

* **画像フォーマットの対応:** Pillowは多くの画像フォーマット(JPEG, PNG, GIF, BMP, TIFFなど)に対応していますが、使用するライブラリによっては特定のフォーマットしかサポートしていない場合があります。
* **画質とファイルサイズ:** 画像の解像度や圧縮率によっては、生成されるPDFのファイルサイズが大きくなることがあります。必要に応じて、画像をPDFに埋め込む前にリサイズしたり、圧縮したりすることを検討してください。
* **パフォーマンス:** 大量の画像を変換する場合や、高解像度の画像を扱う場合は、処理に時間がかかることがあります。
* **エラーハンドリング:** ファイルが見つからない、画像ファイルが破損しているなどのエラーが発生する可能性があるため、適切なエラーハンドリング(try-exceptブロックの使用)を行うことが重要です。
* **アスペクト比の維持:** 画像をPDFに配置する際に、アスペクト比を維持しないと画像が歪んで表示されます。適切なサイズ調整ロジックを実装することが不可欠です。

まとめ

Pythonで画像をPDFに変換する方法は、主にPillowとreportlabを組み合わせるのが一般的です。Pillowで画像を読み込み、reportlabでPDFドキュメントを作成して画像を埋め込むという流れになります。単一の画像から複数の画像まで、目的に応じて柔軟に処理を記述できます。PDFにテキストや図形を追加するなどの高度な機能もreportlabで実現可能です。変換にあたっては、対応フォーマット、画質、パフォーマンス、エラーハンドリングなどに注意を払うことで、より高品質なPDF生成が可能となります。