Claude APIで生成した要約テキストをpython-pptxでスライド化する案件は増えているが、python-pptx 日本語フォント 文字化けで検索してここに来た人は、PowerPointで開くと文字が豆腐(□)になる、あるいは意図したフォントが反映されず明朝体やArialの代替書体で表示される、という症状に当たっているはずだ。原因は「python-pptx側の設定不足」と「変換・表示側のフォント不足」の2系統に分かれており、混同すると対処を誤る。この記事では両方を切り分けて、Claude APIの出力をそのままPPTX化する実装込みで解説する。

症状の切り分け:PowerPointで見るか、サーバーでPDF/画像化するか

まず「どこで」文字化けが起きているかを特定する。原因によって対処がまったく違う。

症状

主な原因

対処の方向性

Windows/MacのPowerPointで開くと豆腐(□)になる

そのPCに指定フォントがインストールされていない

指定フォントを汎用フォント(游ゴシック等OS標準)に変更、または埋め込み

PowerPointでは正常だが、LibreOffice等でPDF/画像に変換すると化ける

変換サーバーに日本語フォントが入っていない

サーバーへのフォントインストール+fontconfig設定

フォント名を指定したのに反映されない(デフォルト書体のまま)

python-pptxのrun.font.nameがlatin書体しか設定していない

XMLレベルでeast asian(東アジア文字)書体を明示指定

受託の現場で最も多いのは3番目のパターンで、次章で詳しく扱う。

原因1:run.font.nameはlatin書体しか設定していない

python-pptxのrun.font.name = "游ゴシック"という書き方は、OOXML上の<a:latin>タグ、つまり半角英数字用の書体しか設定していない。日本語の文字コードは<a:ea>(East Asian)タグの書体が優先して使われるため、a:eaを設定しないと、PowerPointはテーマフォントやOSのデフォルト書体で日本語を描画する。これが「フォント名を指定したのに反映されない」の正体だ。

OOXMLのフォント3系統

  • a:latin — 半角英数字・記号用
  • a:ea — 日本語・中国語・韓国語などの全角文字用
  • a:cs — アラビア語・ヘブライ語などの複合スクリプト用

python-pptxのfont.nameプロパティはa:latinしか触れないので、日本語を正しく制御するにはoxmlで直接a:eaa:csを書き込む必要がある。

解決コード:a:ea / a:csを明示指定するヘルパー関数

from pptx.util import Pt
from pptx.oxml.ns import qn

def set_japanese_font(run, font_name="Noto Sans JP", size=18):
    run.font.size = Pt(size)
    run.font.name = font_name  # a:latin(英数字用)

    rPr = run._r.get_or_add_rPr()

    # a:ea(東アジア文字用)を設定
    ea = rPr.find(qn('a:ea'))
    if ea is None:
        ea = rPr.makeelement(qn('a:ea'), {})
        rPr.append(ea)
    ea.set('typeface', font_name)

    # a:cs(複合スクリプト用、念のため揃える)
    cs = rPr.find(qn('a:cs'))
    if cs is None:
        cs = rPr.makeelement(qn('a:cs'), {})
        rPr.append(cs)
    cs.set('typeface', font_name)

このヘルパーを各runに適用すれば、PowerPoint上でもLibreOffice変換でも指定フォントが安定して当たるようになる。

原因2:サーバーに日本語フォントが入っていないと豆腐化する

Claude API連携をバックエンド(Linuxサーバー)で動かし、生成したPPTXをその場でPDFや画像プレビューに変換する構成では、OSに日本語フォント自体が存在しないため、フォント名の指定が正しくてもすべて豆腐(□)になる。これはpython-pptxの問題ではなく、LibreOffice headless変換側の環境問題だ。

Noto Sans JPのインストール手順(Ubuntu/Debian系)

# 日本語フォント一式をインストール
sudo apt-get update
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra

# フォントキャッシュを再構築
sudo fc-cache -fv

# インストール確認
fc-list | grep -i "noto sans cjk jp"

Dockerコンテナで変換処理を動かしている場合は、Dockerfileに同じapt-get installを追加し、イメージのビルド時点でフォントを含めておく。デプロイのたびにフォントが消える・忘れる事故を防げる。

Claude API生成テキストをPPTXに流し込む実装例

Claude APIで要約や台本を生成し、そのままスライドのテキストボックスに流し込む一連の処理は以下のようになる。API呼び出し部分で529エラー(過負荷)が出ることもあるため、その対処は別記事のClaude API 529エラー対処|過負荷時の再試行実装【26年8月】も合わせて参照してほしい。

import anthropic
from pptx import Presentation
from pptx.util import Pt
from pptx.oxml.ns import qn


def set_japanese_font(run, font_name="Noto Sans JP", size=18):
    run.font.size = Pt(size)
    run.font.name = font_name
    rPr = run._r.get_or_add_rPr()
    for tag in ('a:ea', 'a:cs'):
        el = rPr.find(qn(tag))
        if el is None:
            el = rPr.makeelement(qn(tag), {})
            rPr.append(el)
        el.set('typeface', font_name)


client = anthropic.Anthropic()
resp = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=500,
    messages=[{"role": "user", "content": "次の議事録を3行で要約してください。..."}],
)
summary_text = resp.content[0].text

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[1])
slide.shapes.title.text = "会議サマリー"
set_japanese_font(slide.shapes.title.text_frame.paragraphs[0].runs[0], size=28)

body_tf = slide.placeholders[1].text_frame
body_tf.text = summary_text
for para in body_tf.paragraphs:
    for run in para.runs:
        set_japanese_font(run, size=18)

prs.save("summary.pptx")

ポイントは、text_frame.text = summary_textで作られたrunにも、必ずset_japanese_fontを通すこと。改行を含む長文をClaude APIから受け取って複数paragraphに分割する場合も、すべてのparagraphのrunsにループを回す必要がある。

フォント埋め込みができない制約と代替策

python-pptxには、PowerPointの「フォントの埋め込み」機能(TrueTypeフォントをpptxファイル自体に同梱する機能)をプログラムから行うAPIが存在しない。これはpython-pptxがOOXMLの一部しかカバーしていない既知の制約で、フォント埋め込みが必須の配布物(相手先にNoto Sans JPが入っていない前提)を作る場合は、以下のいずれかで回避する。

  • PowerPoint上位互換の游ゴシック・メイリオなど、Windows標準搭載フォントを指定して埋め込み自体を不要にする
  • Windows環境でCOM自動化(pywin32)を使い、python-pptxで生成したファイルをPowerPoint本体で開いて「名前を付けて保存」時に埋め込みオプションを有効化する
  • 配布せず、サーバー側でPDF化してから渡す(PDFはフォントをグリフとして埋め込むため文字化けの心配がない)

受託案件でPPTX納品が必須の場合は、納品前にLibreOfficeで実際にPDF変換を試し、Noto Sans JPが正しく当たっているか目視確認するのが最も確実だ。

この記事に関連するアイテム

実際に使うものを選ぶ際の参考にどうぞ。

※ 本サイトはAmazonアソシエイト・プログラムの参加者です。紹介リンクを経由してご購入いただいた場合、手数料を受け取ることがあります。

まとめ

python-pptxの日本語文字化けは、①run.font.nameがa:latinしか設定しないためa:ea/a:csが未指定になる問題、②変換・表示環境に日本語フォントが入っていない問題、の2つが主因。前者はoxmlでa:eaa:csを明示指定するヘルパー関数で解決し、後者はサーバーへのNoto Sans JPインストールで解決する。Claude API連携でスライド自動生成を作り込む際は、この2点を最初に潰しておくと事故が減る。

業務自動化・スクレイピングの導入をご検討の方はnashiまでお問い合わせください。https://nashi-portfolio.netlify.app