🍣

【前編】PowerPointの中身は「入れ子の箱」だった ── python-pptxでスライド構造を丸裸にする

に公開

PowerPointの中身は「入れ子の箱」だった ── python-pptxでスライド構造を丸裸にする【前編】

PowerPointファイルの拡張子を .zip に変えて解凍すると、中にはXMLファイルがずらりと並んでいる。
テキストも図形も画像も、すべてが 構造化されたデータ として格納されている。
python-pptx はこの構造を Python オブジェクトとして操作するライブラリだ。
前編では、PPTXの内部構造を探検し、python-pptx の基本操作、そして テンプレートという絶対に外せない概念 を押さえる。

先に要点

  • .pptx は ZIP 内に XML が詰まった構造化ファイル
  • 中身は Slide → Shape → TextFrame → Paragraph → Run の5層構造
  • python-pptx はこの階層を Python オブジェクトとして読み書きできる
  • テンプレートがないと、デザイン情報がゼロになる ── これが最大の落とし穴

この記事で分かること

  • PPTXファイルの内部構造と、python-pptx がそれをどう扱うか
  • スライドを走査して情報を抽出する実際のコード
  • 「テンプレートなし」だと何が起きるのか、なぜテンプレートが必須なのか
  • 後編(JSON変換+LLM連携)に向けた前提知識

今回使う Mermaid 図の種類

図の種類 用途
flowchart PPTXの内部構成、テンプレート有無の分岐
classDiagram PPTXの5層オブジェクト構造
sequenceDiagram python-pptx の読み取り処理フロー
stateDiagram-v2 テンプレート内のデザイン継承
mindmap python-pptx の機能全体像

1. PPTXファイルの正体 ── ZIP の中の XML 群

PowerPointファイルは、見た目はひとつの塊だが、実態は XMLファイルの集合体をZIPで圧縮したもの だ。

スライド本体(slide*.xml)とは別に、デザインを司る「マスター」「レイアウト」「テーマ」が独立したファイルとして存在している。この分離が、後述するテンプレートの概念に直結する。

python-pptx は、このZIP内のXML群を Python の Presentation オブジェクトに変換してくれる。開発者は XML を意識せずに、Python のオブジェクト操作だけでスライドを読み書きできる。


2. PPTXの5層構造 ── コードで辿る入れ子の箱

PPTXの中身は、マトリョーシカのような入れ子構造を持っている。python-pptx はこれを忠実にオブジェクトモデルとして表現する。

文字の装飾(太字・色・サイズ)は最下層の Run 単位で管理される。1段落の中で「ここだけ赤太字」にしたい場合、その部分が別の Run として分離される。

実際に走査するコード

この5層構造を、python-pptx で辿るコードはこうなる。

from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE

prs = Presentation("sample.pptx")

for slide in prs.slides:                          # レイヤー1: Slide
    for shape in slide.shapes:                     # レイヤー2: Shape
        print(f"シェイプ: {shape.name}, 種類: {shape.shape_type}")
        if shape.has_text_frame:
            tf = shape.text_frame                  # レイヤー3: TextFrame
            for para in tf.paragraphs:             # レイヤー4: Paragraph
                for run in para.runs:              # レイヤー5: Run
                    print(f"  テキスト: {run.text}")
                    print(f"  太字: {run.font.bold}, サイズ: {run.font.size}")

prs.slidesslide.shapesshape.text_frametf.paragraphspara.runs と、5層を順にネストして辿る。python-pptx のオブジェクトモデルがPPTXの内部構造とそのまま対応しているため、直感的に読める。

ここで重要なのが、Shape にはテキスト以外にも画像・図形・グラフなどがある という点だ。shape.shape_type で種類を判別し、MSO_SHAPE_TYPE.PICTURE なら画像処理、AUTO_SHAPE なら図形処理、というように分岐させる。


3. Shape の多様性 ── テキストだけではない

1枚のスライドに載っている「部品」は、すべて Shape として管理されている。

for shape in slide.shapes:
    shape_data = {
        "name": shape.name,
        "left": shape.left.pt, "top": shape.top.pt,
        "width": shape.width.pt, "height": shape.height.pt,
        "shape_type": shape.shape_type.name,
        "is_placeholder": shape.is_placeholder,
    }
    
    # 画像の場合
    if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
        image_bytes = shape.image.blob  # バイナリ画像データ
    
    # オートシェイプ(四角形、角丸など)の場合
    if shape.shape_type == MSO_SHAPE_TYPE.AUTO_SHAPE:
        shape_data["auto_shape_type"] = shape.auto_shape_type.name
    
    # プレースホルダーの場合
    if shape.is_placeholder:
        ph = shape.placeholder_format
        shape_data["placeholder"] = {"type": ph.type.name, "idx": ph.idx}

このコードは3つのことをしている。

  1. すべての Shape に共通する情報(名前、位置、サイズ、種類)を辞書に格納
  2. Shape の種類に応じた分岐 で、画像データやオートシェイプの形状を追加取得
  3. プレースホルダーかどうか を判定し、タイプとインデックスを記録

is_placeholder は特に重要だ。プレースホルダーとは、レイアウトで「ここにタイトルを入れてね」と予約された領域のこと。idx でどのプレースホルダーかを特定し、テキストを流し込む際の宛先になる。


4. テンプレートの3層構造 ── デザインの設計図

python-pptx を使ううえで 最も理解が必要な概念 がテンプレートだ。テンプレートの中には、3つの設計図が階層的に格納されている。

デザインは「テーマ → マスター → レイアウト → プレースホルダー」と段階的に継承される。レイアウトを選ぶだけで、テーマの配色やマスターのデザインルールが自動的に適用される。

テンプレートの構造を読み取るコード

後編で使う analyze_pptx() 関数は、このテンプレート構造も解析する。マスターとレイアウトの走査部分を抜粋する。

for master in prs.slide_masters:
    master_data = {"layouts": []}
    for layout in master.slide_layouts:
        layout_data = {"name": layout.name, "shapes": []}
        for shape in layout.shapes:
            shape_data = {
                "name": shape.name,
                "type": shape.shape_type.name,
                "is_placeholder": shape.is_placeholder
            }
            if shape.is_placeholder:
                ph_format = shape.placeholder_format
                shape_data["placeholder_type"] = PP_PLACEHOLDER(ph_format.type).name
            layout_data["shapes"].append(shape_data)
        master_data["layouts"].append(layout_data)

このコードは slide_mastersslide_layoutsshapes と辿り、各レイアウトがどんなプレースホルダーを持っているかを記録する。この情報があれば、「どのレイアウトを使い、どの idx にテキストを入れるか」をプログラム的に判断できる。


5. テンプレートなしだと何が起きるか

テンプレートなしだと、配色テーマ・フォント定義・カスタムレイアウトがすべて消える。プロが作ったPowerPointを再現するのは、テンプレートなしではほぼ不可能。

具体的に失われるもの:

要素 テンプレートあり テンプレートなし
フォント 游ゴシック、メイリオなど指定通り Calibri(日本語で文字化けリスク)
配色テーマ ACCENT_1〜6 が企業カラーに設定 Office 標準の地味な配色
レイアウト プロ設計のカスタムレイアウト多数 最低限の4種類のみ
装飾 背景画像、ロゴ、ヘッダー/フッター 一切なし

だから python-pptx でスライドを生成する際は 「テンプレートとなる .pptx を渡し、そのレイアウトに中身を流し込む」 のが鉄則になる。


6. python-pptx の全体像

python-pptx は「読み取り」「書き込み」「テンプレート活用」の3軸で整理できる。読み取りで得た情報を辞書に変換すれば、後編で扱うJSON化の土台になる。


一言で言うと何者か

python-pptx は、PowerPoint内部の5層構造を Python オブジェクトとして読み書きするライブラリ だ。ただし見た目の再現には テンプレートという設計図 が不可欠であり、テンプレートがなければ「中身はあるが見た目のない」骨だけのスライドしか作れない。

まとめ

  • PPTXの正体は ZIP内のXML群。python-pptx はそれを Python オブジェクトに変換する
  • 中身は Slide → Shape → TextFrame → Paragraph → Run の5層構造
  • Shape には画像・図形・プレースホルダーなど多様な種類があり、shape_typeis_placeholder で分岐する
  • テンプレートは「テーマ → マスター → レイアウト → プレースホルダー」の3層設計図。なしだとデザイン情報がゼロになる
  • テンプレートのレイアウトとプレースホルダーの idx を理解すれば、デザインを維持したまま中身を流し込める

後編では、この5層構造をまるごと JSON に変換する analyze_pptx() 関数のコードを読み解き、LLM にスライドを読ませて編集させるアプローチを実装レベルで解説する。


GitHub リポジトリ

この記事で解説しているコードの全体は、以下のリポジトリで公開しています。
pptx_processor.pyllm_handler.py、Streamlit アプリ、CLI 実行スクリプトなど、すべてのソースコードを参照できます。

https://github.com/Invest-AItech/pptx-json-converter


参考 PowerPoint の中身を、JSON で自由に。

PowerPoint をスライド単位で構造化 JSON に分解し、ブラウザ上で閲覧・コピー・ダウンロード・復元できる Web アプリ。Vertex AI Gemini と組み合わせた AI 編集もパスワード保護のゲート越しで提供。テーマ・マスター・画像まで JSON に埋め込む Shard+Index 形式で、AI が必要なスライドだけを触れる「二段階」パイプラインで実装。

https://invest-aitech-pptx.web.app/


後編はこちら → PowerPointをJSONに変換してLLMに読ませる ── 実装コードで理解するAIスライド編集【後編】

Discussion