パワーポイントのノート編集をマークダウンで

# はじまり

  とある勉強会で発表をすることになり、

  アウトラインを作って、がんばってそれらしいスライドを作ってみたものの、

  [PowerPoint](https://www.microsoft.com/ja-jp/microsoft-365/powerpoint)を殆ど使ったことないため、

  パワポのスピーカーノート編集で根を上げました

  世の中の人はどうやってるんや･･･

  と調べたところ、Pythonには「[python-pptx](https://python-pptx.readthedocs.io/)」というものがあり、

  どうやら、pptxを読み書きできるらしい。
  
  なんだ皆こういうの使ってるのか、ずるい！
  
  ということで私もやってみました。

# なにができるの

  簡単なPythonスクリプトを書くことで、

  ~~PowerPointでノート編集するという拷問から解放されます~~

  PowerPointの編集がPython経由で出来るようになり、

  PowerPointのノートを、
  
  VScodeやNotionで編集しPowerPointへ書き戻す、

  といった操作が簡単にできるようになりました。

# なにをやったの

  スクリプトを２つ作成しました

  一つは、pptxを開いて、スライドのすべてのページからタイトルとスピーカーノートを取り出し、

  マークダウン形式のテキストファイルへ出力する。

  もう一つは、タイトルとスピーカーノートが記述されたマークダウン形式のファイルを開き、

  pptxの同じタイトルのスライドへスピーカーノートを上書きする

  というスクリプトを作成しました。

# 導入

```text
実行環境 Python 3.12.0
```

  必要なパッケージをインストールします

```sh
py -m pip install python-pptx
```

# どうやって使ったの

  モジュールから呼び出したい関数をインポートします

```python
from pptx import Presentation
```

  インポートした関数は、pptxファイルを渡すと、

  Presentationオブジェクト形式として読み込みしてくれます

```python
Presentation(ファイル名)
```

  Presentationオブジェクトの細かい仕様は[正式なドキュメント](https://python-pptx.readthedocs.io/en/latest/)へお任せし、

  今回は必要としているのは、
  
  各スライドのタイトルとスライドに設定されたスピーカーノートです。

  まず、スライドへアクセスしたいので、
  
  slidesを探索します、各スライドのインスタンスには、
  
  タイトル、ノートへのアクセスが出来るようになっているので、必要な処理を行います

```python
p = Presentation(ファイル名)
for slide in p.slides:
  print(slide.shapes.title.text)
  print(slide.notes_slide.notes_text_frame.text)
```

  読み込むだけであれば、以上の処理が出来れば達成できます。

  ---

  変更し、保存する場合は、以下のようにメンバーを直接書き換え、
  
  保存を行うことでpptxの書き込みが出来ます。

```python
p = Presentation(ファイル名)
for slide in p.slides:
  slide.shapes.title.text = "new title"
  slide.notes_slide.notes_text_frame.text = "new note"
p.save("new ファイル名")
```

# 実物

``` export.py
from pptx import Presentation


def enum_slide(filename: str, callback: lambda slide: None):
    p = Presentation(filename)
    # 持っている全スライドをコールバックへ渡す
    for slide in p.slides:
        if slide.has_notes_slide and slide.notes_slide.notes_text_frame.text:
            callback(slide)


if __name__ == "__main__":
    basename = "filename"
    files = {
        "pptx": "{}.pptx".format(basename),
        "md": "{}_台本.md".format(basename),
    }
    # 書き込み先のファイルを開く
    with open(
        files["md"],
        "w",
        encoding="utf_8_sig",
    ) as f:
        # マークダウン形式で出力する

        def output(f, title, text: str):
            # タイトルとスピーカーノートをまとめて出力する
            f.write("\n## {}\n\n".format(title))
            t = text.lstrip().rstrip()
            f.write("{}\n".format(t))

        f.write("# {}\n".format("台本"))
        # パワーポイントを開いて、スライドをたどって各タイトルとスピーカーノートを出力へ渡す
        enum_slide(
            files["pptx"],
            lambda slide: output(
                f, slide.shapes.title.text, slide.notes_slide.notes_text_frame.text
            ),
        )
```

```import.py
from pptx import Presentation


def enum_slide(filename: str, callback: lambda slide: None):
    p = Presentation(filename)
    # 持っている全スライドをコールバックへ渡す
    for slide in p.slides:
        if slide.has_notes_slide and slide.notes_slide.notes_text_frame.text:
            callback(slide)
    return p


if __name__ == "__main__":
    basename = "filename"
    files = {
        "pptx": "{}.pptx".format(basename),
        "md": "{}_台本.md".format(basename),
    }

    notes = {}
    # md形式のテキストを辞書化する
    with open(
        files["md"],
        "r",
        encoding="utf_8_sig",
    ) as f:
        # '台本'を読み飛ばす
        f.readline()
        f.readline()

        key = None
        note = ""
        for line in f.readlines():
            if line.startswith("##"):
                if key:
                    notes[key] = note
                key = line[2:].strip()
                note = ""
            else:
                note += line
        if key:
            notes[key] = note

    def input(note, slide):
        t = note.lstrip().rstrip()
        slide.notes_slide.notes_text_frame.text = t

    # パワーポイントを開いてノートへ上書きする
    p = enum_slide(
        files["pptx"],
        lambda slide: input(notes[slide.shapes.title.text], slide),
    )
    p.save(files["pptx"])
```

# おわりに

  導入の結果、スクリプト書きがかなり捗りました、

  元々テキストエディタでの編集のみが目的だったのですが、

  Notionにそのまま放り込んでスマホで簡単に見直してみたり、

  VOICEVOXのような読み上げができるソフトに投げ込んで

  誤字脱字チェックなども出来、一粒で何度かおいしいと思いました。