ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Python - python-pptx:PowerPoint資料の自動作成

初めに

 Pythonでは、python-pptx ライブラリを用いて、PowerPoint ファイル(.pptx)を作成、読み取り、更新することができます。このライブラリを使って PowerPoint 資料を自動作成したいと思います。

目標

  • 同じフォルダにある .pptx ファイルと同じデザインテンプレートの .pptx ファイルを作成する
  • 表紙、目次、企画案の説明、まとめのページがある .pptx ファイルを Python を実行することで作成する。

環境

fineworks-fine.hatenablog.com

 過去に Python の開発環境に関する記事を書いたので、開発環境がまだ整えられていない方はそちらをご覧ください。

python-pptx ライブラリをインストール

 まず、python-pptx ライブラリをインストールします。

 VSCode の TERMINAL に pip install python-pptx を入力し、実行します。


python-pptx ライブラリをインストールせずに、pptx モジュールを使おうとした場合

 python-pptx ライブラリをインストールせずに、次のコードを実行してみます。

from pptx import Presentation


 すると、ModuleNotFoundError: No module named 'pptx' とエラーが発生します。python-pptx ライブラリがインストールされているか、分からない場合はいったん上記のように python-pptx ライブラリを用いるコードを実行してみるとよいでしょう。

コード全文

from pptx import Presentation
from pptx.util import Inches
import os

def create_cover_slide(prs, title, subtitle):
    slide_layout = prs.slide_layouts[0]  # 0はタイトルスライドのレイアウト
    slide = prs.slides.add_slide(slide_layout)
    title_box = slide.shapes.title
    subtitle_box = slide.placeholders[1]
    title_box.text = title
    subtitle_box.text = subtitle

def create_table_of_contents(prs, sections):
    slide_layout = prs.slide_layouts[5]
    slide = prs.slides.add_slide(slide_layout)
    title_box = slide.shapes.title
    title_box.text = "Table of Contents"

    # 1つのテキストボックスを作成
    text_box = slide.shapes.add_textbox(Inches(1), Inches(1.5), Inches(8), Inches(0.5))
    text_frame = text_box.text_frame

    # 目次を作成
    for section in sections:
        p = text_frame.add_paragraph()
        p.text = f"{section['title']}: {section['page']}"

def create_content_slide(prs, title, content):
    slide_layout = prs.slide_layouts[5]
    slide = prs.slides.add_slide(slide_layout)
    title_box = slide.shapes.title

    # 1つのテキストボックスを作成
    content_box = slide.shapes.add_textbox(Inches(1), Inches(1.5), Inches(8), Inches(0.5))

    title_box.text = title
    content_box.text = content

def create_presentation(template_path, output_path):
    # 既存のテーマを指定してプレゼンテーションを作成
    prs = Presentation(template_path)

    # 表紙
    create_cover_slide(prs, "プロジェクト企画書", "2024年2月2日")

    # 目次
    sections = [
        {"title": "セクション1: はじめに", "page": 2},
        {"title": "セクション2: 企画の概要", "page": 3},
        {"title": "セクション3: 詳細な計画", "page": 5},
        {"title": "セクション4: まとめ", "page": 8},
    ]
    create_table_of_contents(prs, sections)

    # セクション1: はじめに
    create_content_slide(prs, "はじめに", "この企画書は...")

    # セクション2: 企画の概要
    create_content_slide(prs, "企画の概要", "プロジェクトの目的は...")

    # セクション3: 詳細な計画
    create_content_slide(prs, "詳細な計画", "具体的な計画は以下の通りです...")

    # セクション4: まとめ
    create_content_slide(prs, "まとめ", "プロジェクトの成果は...")

    # アウトプットファイルとして保存
    prs.save(output_path)

if __name__ == "__main__":
    current_directory = os.path.dirname(os.path.abspath(__file__))
    template_path = os.path.join(current_directory, "template.pptx")
    output_path = os.path.join(current_directory, "output.pptx")
    
    create_presentation(template_path, output_path)

コード解説

if __name__ == "__main__":

__name__Pythonグローバル変数で、モジュールやスクリプトの名前が格納されます・

  • モジュールが直接実行される場合は、__name__には"__main__"が格納される
  • モジュールが他のスクリプトやモジュールからインポートされるときは、__name__にはのモジュールやスクリプトの名前が格納される

 つまり、このスクリプトを直接実行した場合のみ実行し、他のスクリプトからこのモジュールをインポートした場合は、実行しないようになっています。

os モジュール
import os

# 現在のスクリプトやモジュールが存在するディレクトリのパスを取得
current_directory = os.path.dirname(os.path.abspath(__file__))

# テンプレートファイルのパスを構築
template_path = os.path.join(current_directory, "template.pptx")

# 出力ファイルのパスを構築
output_path = os.path.join(current_directory, "output.pptx")
  • os.path.abspath(__file__)__file__ によりこのファイルのファイルパスを取得し、それを os.path.abspath()絶対パスに変換する。
  • os.path.dirname() により指定されたパスからディレクトリ部分を取得する。現在のスクリプトやモジュールの絶対パスからディレクトリを取得している。
  • os.path.join(current_directory, "template.pptx") で現在のディレクトリと "template.pptx" というファイル名を結合し、テンプレートファイルの絶対パスを生成する。
  • os.path.join(current_directory, "output.pptx") で出力するファイルパスを生成する。
create_presentation() 関数
from pptx import Presentation

def create_presentation(template_path, output_path):
    # 既存のテーマを指定してプレゼンテーションを作成
    prs = Presentation(template_path)

    # 表紙
    create_cover_slide(prs, "プロジェクト企画書", "2024年2月2日")

    # 目次
    sections = [
        {"title": "セクション1: はじめに", "page": 2},
        {"title": "セクション2: 企画の概要", "page": 3},
        {"title": "セクション3: 詳細な計画", "page": 5},
        {"title": "セクション4: まとめ", "page": 8},
    ]
    create_table_of_contents(prs, sections)

    # セクション1: はじめに
    create_content_slide(prs, "はじめに", "この企画書は...")

    # セクション2: 企画の概要
    create_content_slide(prs, "企画の概要", "プロジェクトの目的は...")

    # セクション3: 詳細な計画
    create_content_slide(prs, "詳細な計画", "具体的な計画は以下の通りです...")

    # セクション4: まとめ
    create_content_slide(prs, "まとめ", "プロジェクトの成果は...")

    # アウトプットファイルとして保存
    prs.save(output_path)

 pptx.ファイルを作成、保存するための関数です。

 prs = Presentation(template_path)により .pptxファイルを読み込み、prs.save(output_path)output_path として保存しています。

 create_cover_slide() は表紙を作成する関数、create_table_of_contents() は目次を作成する関数、create_content_slide() は表紙や目次以外のスライドを作成する関数です。これらの関数は自分で定義しています。

prs.slide_layouts[]

 prs.slide_layouts[] では、下の画像のようにスライドのテンプレートを指定できます。


prs.slides.add_slide()

 prs.slides.add_slide() メソッドは、指定されたレイアウトの新しいスライドを作成します。

slide.shapes.title

 slide.shapes.title はカバースライド内のタイトルボックスを取得します。

slide.placeholders[]

 placeholder はコンテンツ (テキスト、グラフィックス、またはビデオ) のスライド上の事前に書式設定されたコンテナーで、点線で表示されている部分です。

 slide.placeholders[]プレースホルダーを指定できます。

作成されたファイル

表紙
目次
セクション1
セクション2
セクション3
セクション4

所感

 全自動で PowerPoint 資料を作成するのは難しいと思います。使うタイミングとしては、

  • すでに別ファイルに入力してあるテキストを流し込む
  • 同じデザインのテンプレートのものを使いまわす
  • 一部分だけ変更したファイルを複数作る

などの場合が考えられます。