Slidevのスライドを、手で組み直さずに編集できるPPTXにする

Hero header with large Japanese headline '作り込んだ図まで 組み直さずに運ぶ' and branding: 'SLIDEV → POWERPOINT' on left and 'SIOS Tech.Lab' logo on the top right.

ども!Slidevで作った資料を、Agentに書かせた中身と会社のPowerPointテンプレへ合体させる検証を、ずっと続けている龍ちゃんです。

会社のPowerPointで資料を出そうとすると、たいてい同じところで詰まります。AIに作らせても、こちらが「これなら編集できる」と思って想像していたものより、ひとつ下のものが出てくるんですよね。結局、PowerPointを開いて1枚ずつ組み直すことになります。

資料自体はSlidevで書き続けたいんです。手元で見え方を確かめながら進められて、話の展開も文章のまま読めるので。書くのはSlidevのまま、出口だけPowerPointにできればいい、というのが今回の前提なんですよね。

その変換ができるようになりました。中身はAgentに書かせて、会社のテンプレはテンプレのまま使って、1枚のスライドの上で合体させます。

会社テンプレのままの見た目で、中身がテキストとして編集できて、図はカードごとに掴んで動かせるpptxが出ます。しかもそれを、デッキ丸ごと並列で書かせられます。 Agentに書かせるのは1枚ごとの中身だけで、ロゴやヘッダ、繰り返す枠は会社テンプレ側がそのまま持っています。

SlidevからPPTXへ渡す道はこれ一本ではありません。この記事は、中身はAgentに書かせ、会社のPowerPointテンプレはそのまま使って1枚のスライド上で合体させる道を切り出したものです。全体像はSlidevからPowerPointへ渡す道を整理した記事にあるので、自分に合う道から選びたい人はそちらへ。この記事だけで完結するので、そのまま読み進めても大丈夫です。

会社のPowerPointで出そうとすると、結局手で組み直す羽目になる

ゴールは、会社フォーマットのまま、中身が編集できる形で出すことです。PowerPointで出すということは、渡した相手が自由に配置を組み替えられるということで、それがPowerPointの価値です。だから画像を貼っただけのpptxは答えになりません。拡張子はPPTXでも、中身は組み替えられないからなんですよね。以前「Claude CodeでSlidevのスライドを作る話」で「配布用の最終形と割り切る」と書いたのは、配布して見てもらうだけの資料なら今も正しいと思っています。ただ、他の人が後から組み替える前提だと、その割り切りは通りません。以前「Marp と Slidev の使い分け」の最後に「他部署の人が中身を直接いじる用途なら、素直にPowerPointが正解」と書いたのがまさにこれで、今回はその前提の中の話です。

自由に組める中身を出そうとすると、結局OOXML(PowerPointのファイルの中身に入っているXMLです)を書くことになります。ところが、1から書くとなると、会社のロゴも配色も自分で全部書くことになるので、デッキ全体で統一を保つのが大変です。逆に会社テンプレに流し込めばブランドはそのまま乗りますが、今度は作り込んだ図の入れ先がありません。

会社ブランドと組み替えられる中身が両立しないことを示した図。左の道「1から自分でOOXMLを書く」は自由に組み替えられるが会社のロゴも配色も自分で書くことになり統一を保つのが大変なこと、右の道「会社テンプレに流し込む」はブランドは載るが作り込んだ図の入れ先がないことを表し、どちらの道も先で「結局PowerPointを開いて1枚ずつ手で組み直す」に合流している

つまり、PowerPointの価値を守ろうとするとブランドの統一が自分の肩に乗ってきて、会社ブランドを載せようとすると作り込んだ図が入らない。この二律背反にはまって、いつも同じところに着地するんですよね。PowerPointを開いて、1枚ずつ手で組み直す。デッキ1本ぶん、まるごとこれが起きます。

だからこそ、ここで発想を変えます。手で組み直すしかないと思っていたその中身、OOXMLで書ける形なんですよね。ということはAgentにも書かせられます。ただし、全部書かせるのは違います。

PowerPointの強みは、実は2つあります。ひとつは自由に配置して組み替えられることです。もうひとつは、テーマ・マスター・レイアウトで、繰り返す部分を揃える仕組みがもともと用意されていることです。この2つを、別々の担い手に割り当てます。ひとつはAgentに書かせます。もうひとつはテーマに委譲します。ロゴ・ヘッダ帯・フッター・ページ番号は、委譲すれば置くだけで出てくるので、Agentに振るのは、その1枚にしか出てこない図だけで済むんですよね。

委譲すれば、会社ブランドはテンプレ側がそのまま担保してくれますし、Agentに書かせる量そのものも減ります。担い手の割り当てを、合体後のスライドそのもので見てもらうのが早いです。

合体後のスライド1枚をPowerPointで開いた状態を、外から見た図。番号①(青枠)はテンプレートに委譲してAgentに描かせない領域で、ヘッダ帯・見出しの枠・ロゴ・フッター・ページ番号。番号②(オレンジ枠)はOOXMLでAgentに書かせる領域で、その1枚にしか出てこない中身の図。画像の下に①②の凡例を添えている

もうひとつ、時間の軸でも線が引けます。一度書けば使い回せるものと、デッキごとに書き直すものです。乗せる仕掛けは一度だけ書けばよくて、1枚ごとの中身は毎回書きます。

そして、この切り分けがそのまま「デッキ丸ごと並列で依頼できる」理由になります。Agentの持ち分が1枚の中身だけなら、1枚ぶんの仕事はもともと小さいんです。しかもSlidevで作ったデッキは、レイアウトとコンポーネントを使い回して組んであるので、中身もパターンの束になっています。そのうえで、1枚ごとが独立しています。だから1スライド=1ファイル=1エージェントで切って、デッキ丸ごとを同時に走らせられます。手描きで作ったPowerPointでも同じように切って投げることはできますが、1枚ごとの作りがばらばらだと1枚ぶんの仕事が小さくならないので、効きは落ちます。パターンが揃っているのは、Slidevで作ってあるからなんですよね。

AIにPPTXを書かせるなら、Anthropicが公式で出しているpptxスキルもあります。あのスキルの機械チェックは「PowerPointで開けるか」までを見る作りで、はみ出しや図のまとまり、フォントの指定は目視のレビューに回す前提なんですよね(日本語も想定の外で、安全に使えるフォントの一覧が全部欧文です)。この記事で足したのはその先で、合否を機械で出す層と、日本語と会社のテンプレの上で成立させるところになります。

2つの指示で、Agentに「描かせないもの」と「掴める形」を守らせる

線は引けました。あとは、その線をAgentにどう守らせるかです。やっているのは2つの指示で、どちらも「描く範囲を狭める」向きの話になります。

会社テンプレの領分は、再現させるのではなく描かせない

会社テンプレが既に描いているものは、Agentに描かせません。 ロゴ・ヘッダ帯・フッター・ページ番号のことです。ここをAgentに再現させると、テンプレ側の装飾と二重になって必ず崩れます。再現の精度を上げる話ではなく、描く範囲を切る話なんですよね。

指示として書いたのは、意図で言うと3つです。

  1. 描く領域と描かない領域を先に渡す。固定ヘッダは描かない、本文の描画領域はここからここまで、というのを座標で指定します。座標で渡すのは、枠を言葉で説明するとAgentごとに解釈がずれるからです。
  2. 見出しは自分で描かせない。テンプレのタイトル枠へこちらで流すので、本文の中に見出しを描き足させません。
  3. 色は決めたトークンだけを使わせる。生のHEX値を勝手に増やさせない、ということです。

どれも「描かせない・狭める」向きの指示で、そこがこの節の名前とそのまま一致しています。だから読者の側でも、自分の会社テンプレが何を描いているかを先に決めれば、そのまま当てはめられるはずです。

この描かせない指示がいちばん効くのは、並列で走らせたときです。何体ものAgentがそれぞれ勝手にヘッダを描いて微妙に揃わない、みたいな事故が、そもそも起きなくなるんですよね。崩れる余地のあるものを最初から描かせていないので、ブランドが崩れる心配もありません。

とはいえ、指示は守られたり守られなかったりします。なので、Agentが装飾を描こうとしても通らないように、描く口のほうを塞いであります(仕掛けの中身は付録に置きます)。

繰り返す要素なのに、会社テンプレ側に型が無い、という場合もあります。表紙や章扉のように全面を紺で覆う型が、手元の会社テンプレにはありませんでした。こういうときは、Agentに描かせる方へ寄せずに、会社テンプレのレイアウトとして型を1つ足します(触るのはファイルの4か所で、そこは付録の罠2に置きます)。テンプレを作り直すのではなく、テンプレが持っていないものだけ足す、という向きです。デッキが変わったときに差し替えるのも、図の中の配色(デッキ側)と、焼き足すレイアウトの地の色(テンプレ側)の2つだけで済みます。

掴める単位は、名指しで宣言させないと書かれない

もうひとつの指示です。PowerPointのスライドは、図形とテキストが1つずつ独立して置かれているだけの入れ物です。カードの角丸の背景も、その上に乗っている見出しも本文も、重ねて並べてあるだけで、互いに何の関係も持っていません。この状態で渡すと、受け取った人が「このカードだけ右に寄せたい」と思ったときに、背景だけが動いて文字が置き去りになります。組み替えられる形で渡す、というのは、見た目のまとまりが実体としても1つになっている、ということなんですよね。

そのまとまりは、Agentが「ここからここまでが1つのまとまり」と宣言して書くことで作られます。そしてこの宣言は、指示しないと書かれません。「Agentはグルーピングが苦手」という話ではなくて、名指しで要件に入れれば入るし、入れなければ書かれない、というだけの話です。

ただし、指示しても粒度までは揃いません。囲んだ中に図形が1つしか無いと、束ねる意味がないので束ねない仕様で、宣言はあるのにグループが1つもできない枚が出ます。カード1枚を掴んで動かせる粒度で出したいなら、「何を1つのまとまりとして囲むか」まで書いておくほうがいいと思います。

実際に手元のデッキで試してみた

まず1枚だけ、見てもらうのが早いです。会社の実物テンプレは外に出せないので、以降の画像は同じ構成で起こしたサンプルのテンプレで撮っています。

サンプルテンプレのヘッダ帯とロゴの下に、4つのステップカードの図が収まっている画面。タイトルはロゴと重ならずヘッダ帯の中に収まっている

1枚できたなら全部いけるはずだと思って、実際のセミナーデッキ2本で、フルデッキ分を全部やりました。まずは33枚のデッキの結果を、全枚まとめて置いておきます。

33枚のセミナーデッキを合体させた結果を一覧できるコンタクトシート。表紙・章扉は紺の全面レイアウトになっており、本文ページはサンプルテンプレのヘッダ帯・ロゴ・罫・フッターが揃っている

このデッキはパレットも構成も、さっきの1枚とはまったく別のものです。33枚のうち32枚をAgent32体に並列で新規著作させたところ、約8分で書き上がりました。残り1枚は、Agentに渡す手本として先に人が作ったものです。33枚すべて、合体そのものには成功しています。1枚ごとの中身が独立している、という線があったからこそ、32体に切って同時に投げられました。これは検証中に一度計測した実測値で、日常的に運用で回しているわけではありません。

念のため、まったく別のデッキでも同じことを試しています。最初の1枚を出した26枚のデッキで、既存のビルダ(1枚の中身を描くコードです)をそのまま流用して同じ1本に通しただけですが、こちらも問題なく合体できました。1本だけで、たまたま噛み合ったわけではなさそうです。

33枚のデッキのほうには、表紙や章扉のような暗い背景のスライドだけ下地の紺を別に用意して包む、という場合分けが1つだけ残っていました。これも、会社テンプレ側に紺の型を焼き足したことで、その場合分けごとテンプレ側へ移せています。合体の結果は1枚も変わっていません。

テキストは全部移る。図はカードごとに掴める

ここが一番でかいところです。最初の1枚を重ねてレンダーしたとき、Slidev側ではnavyのナビ帯だったところが、そのまま会社テンプレのヘッダとロゴに置き換わっていました。図のほうはそっくり移っている。この画面が出てきたときは、正直ちょっと感動しました。何がそんなに嬉しかったのかというと、この2つです。

  • テキストは全部移ります。 図の中の文字は、1つも画像になっていません。33枚のデッキだと、生のテキストのrunが451本。PowerPointで選んで、そのまま打ち直せます。
  • 図はグループのまま移ります。 しかも1スライド丸ごとで1つではなく、カード・行・ステップといった見た目のまとまりごとです。同じデッキで105グループ。掴んでドラッグすれば動きますし、まとめて縮めるのもできます。

渡した相手が自由に組み替えられる形で出す、というのが最初の要件でした。この2つが通っているので、渡した先で「ここだけ動かしたい」と言われても、その1枚を作り直す話にはならないんですよね。

どういう確認をしたのか

仕掛けを入れたからといって、毎回そのとおりに出るわけではありません。ただ、崩れるところはだいたい決まっていて、4つです。

  • 背景の装飾が二重に残る(Slidev側の装飾と会社テンプレの装飾が、両方出てしまう)
  • 図が本文枠からはみ出す、または縮みすぎて読めない大きさになる
  • ロゴや罫線、フッターとぶつかる
  • 文字が画像になっている(Agentには「画像にせずテキストで描け」と指示していますが、守られたかは見ないと分かりません)

崩れる場所が決まっているなら、確認の順番も決められます。しかも落ちたところをAgentに渡すガイドの側に書き戻しておけば、次から同じところでは落ちなくなるんですよね。この辺はAI様様ですね! 確認は3段で組んでいて、最後の1段が自分でPowerPointを開くところです。

合体したあとに通す3段のレビューを、上から順に並べた図。1段目はAgentが自分で見る段で、見ているのは絵。2段目は機械が測る段で、見ているのは寸法とXML。3段目は人が実機のPowerPointで開く段で、見ているのは中身が元と合っているか

1段目は、Agent自身に見させます。書いたものをそのまま画像に出して、元のスライドの画像と見比べて、はみ出しや重なり、欠落があれば自分で直させる。最大3回までのループです(画像に出すのはLibreOfficeにやらせています。コンテナにPowerPointが無いので)。AIに書かせるだけでなく、AIにレビューさせる段ですね。

2段目が機械です。さっきの4つを、そのまま監査項目にしてあります。Agentがよく失敗するところを観点として先に固定して、毎回同じ目で見させるので、役割としてはレビューに近いです(何をどう見ているかは付録に置きます)。機械に振ったのは、開いて眺めても分からないことだからです。背景が剥がしきれずに二重で残っていても、開いた絵はほとんど同じに見えます(実際、実機で「表示は問題ない」のに剥がし漏れだった版がありました)。図の中の文字が画像になっていても、絵として見るぶんには区別がつきません。縮めた結果として文字が読めない大きさになっていないかも、寸法を測らないと出てきません。

そして最後の段が、PowerPointで開いて自分が見るところです。前の2段はどちらも近似です。絵に出しているのはLibreOfficeで、機械が測っているのは寸法とXMLですから、フォントの出方も含めて最終の判定は実機でやります。実際には、Windowsのモバイル版ではないPowerPointで、3ファイルずつを2ラウンド、計6回開きました。1ラウンド目は会社テンプレ実物の版(26枚/33枚と、レイアウト見本7枚+合体サンプル3枚のデモ)で、修復ダイアログは出ず、文字も編集できてグルーピングも効いていました。ただ、このラウンドは中身のフォントがArialに落ちていました。2ラウンド目が、この記事の画像を撮っているのと同じサンプルテンプレの版(フォントを焼き込んだ26枚/33枚と、レイアウトを焼き足したテンプレ本体)で、こちらは修復なし・グルーピング可で、フォントもメイリオで出ています。

最後の段を自分でやっているのは、前の2段が見ているのが機構の健全性であって、中身の忠実度ではないからです。Agentが元と違う内容を描いてしまっても、機械のレビューは素通りします。丸投げが成立するのは「人が見なくて済むから」ではなくて、XMLの検分をしなくて済むぶん、絵の中身が合っているかどうかに集中できるから、という話なんですよね。

合体したあと、PowerPoint側で直すところは残る

一点留意事項として、完全に再現するわけではありません。「いや!できないんかい」って思いましたよね。でも安心してください。そんな深刻ではなく軽微な修正です。

合体させたあと、PowerPoint上でやる調整がいくつか出てきます。網羅した「残るのはこれだけ」という話ではなく、実際に手元で確かめたファイルの範囲で、こういう調整をすることになった、という紹介です。

実際に崩れているものを、先に見てもらいます。図は33枚デッキ側の1枚です(26枚の方はデッキを版で固定して回しているため、いまの書き出し画像と対応が取れなくなっていました)。

33枚デッキのあるスライドを、左に元のSlidevの表示、右に合体後のPowerPointの表示を並べた比較画面。右側はカードの文字が枠から数行分あふれ、アイコンが小さな色付きの丸に置き換わっている

右側は、カードの文字が枠から数行分あふれていて、アイコンも小さな色付きの丸に置き換わっています。これから書く調整のうち2つが、この1枚に一緒に写っています。

数でも出しておきます。33枚のデッキで、機械のレビューを全部通ったのは22枚でした。落ちた枚も、合体そのものには成功していて、引っかかっているのは、これから挙げる調整のほうです。なお、この記事に載せている画像はSlidevと同じ基準サイズのサンプルテンプレのものです。会社の実物テンプレは幅が狭いので、そちらだともう少し厳しく出ます。

アイコンは元と同じ絵にならない

元のデッキのアイコン(Font AwesomeやMaterial Iconsです)を、Agentは①②③や↻、≡のようなUnicodeの記号に置き換えたり、小さな色付きの図形に置き換えたりして描いています。ガイドでは「元のアイコンは描かない。省略するか、小さな色付きの図形で代替してよい」とだけ書いていて、代替の仕方までは決めていなかったので、枚によってどちらになるかはまちまちです。フォントを明示してあるので表示自体はされますが、元と同じ絵にはなりません。ここは調整で持っていける範囲だと思っていますが、元のアイコンにこだわるなら、PPTX側で差し替える作業が要ります。

紺で覆った表紙・章扉ではロゴが沈む

全面を紺で覆った表紙・章扉だけに出るものです。ロゴがラスタ画像のため、白抜きへの差し替えが必要で、そのままだとワードマークが沈んで見えることがあります。テキストの色を反転させるだけでは直らず、これはテンプレのアセット側の話です。ページの地の色によっては気にならない程度で、あまり大きな問題ではありません。

テンプレの幅が狭いと、密な1枚があふれる

手元の会社テンプレの実物は幅が狭く、Slidevの基準サイズよりひとまわり縮んで会社テンプレの本文枠に収まる形になっています。密なスライドだと、本文が枠の中で折り返しきれず、わずかにあふれることがあります。実感としては「完全にあふれたものはなかった」「折り返して多少あふれているなというのはある。許容範囲」「簡単に修正できそうなもの」という程度です。自分のテンプレがSlidevと同じ基準サイズなら、そもそも縮める必要がないので、ここは起きません。中央寄せのような細かい寄せの調整も、あふれと一緒にこの段で直しています。どちらもPowerPoint上で選んで直せる範囲です。

それでも、直すのは調整の範囲

機械のゲートは、実機で見るよりも厳しく出ます。可読性を見るゲートはNoto系のフォントの寸法で判定していて数枚を落としましたが、実機のPowerPointで実物テンプレの合体ファイルを開いた範囲では、ここまで顕在化せず、完全にあふれたものは1枚もありませんでした。見逃しているわけではなく、前段のふるいとして安全側に外れている、ということです。

直すのはPowerPoint上の調整であって、作り直しではありません。完全に同じものが出てくるわけではない、というのは正直に認めます。ただ、そこから先が調整で持っていける水準まで来ているのは、実際に触ってみて感じたところです。

自分はこの丸投げに乗る側か

軸は2つです。ひとつは、そもそも会社フォーマットで出す必要があるかどうかです。必要がないなら、PDFで配るなり、Slidevのまま見てもらうなりで足ります。もうひとつは、中身が繰り返す枠中心か、1枚ごとに作り込む図が主役かです。繰り返す枠が中心なら、会社テンプレへの流し込みで足ります。1枚モノが多いほど、今回のやり方が効いてくるんですよね。

振り分けたうえでの効能は、渡した先でテキストが打ち直せてカードごと動かせること、どの型のスライドも同じ1本を通ること、デッキが変わっても仕掛けを書き直さずに済むこと、機械が先にふるってくれるので通しで見るところに集中できること、です。

会社テンプレの詳しい機序が知りたい人はSlidevの中身を会社のPowerPointテンプレに入れる話へ。会社テンプレをそもそも持っていない人はSlidevのデザインを実測してPowerPointのテンプレをコードで作る話へ。逆に、会社のPowerPointの資料を持っていてSlidev側へ持っていきたい人には会社のPowerPointの資料をSlidevへ移す話という選択肢もあります。要件によってどの道を取るか迷う人はSlidevからPowerPointへ渡す道を整理した記事へどうぞ。

ただ確実にPPTXへ変換するのに時短になっています。しかも圧倒的に!!

まぁでもPPTXでほしいって言われることが少ないのですけども。依頼が来たら、いつでも出せる状態にはしてあります。

付録:手元で再現するための情報

ここから下は、同じことを自分の環境でやるための材料です。実際に踏んだ罠もそのまま置いておきます。

環境

Python 3.12 と python-pptx 1.0.2、lxml 6.1.1、会社テンプレ実物です。仮想環境を作らずに試すならuvが楽です。

uv run --with 'python-pptx==1.0.2' --with 'lxml==6.1.1' python merge.py

会社テンプレの実物が手元にない場合は、タイトルと本文のプレースホルダを持った本文レイアウトが1つあるpptxであれば、同じ手順を試せます。見た目までは同じになりませんが、仕掛けが動くところまでは確認できます。

Agentに渡したガイド

配るものはコードではありません。というより、コードを配る意味がないんですよね。中身を書くのはAgentなので、手元にAIがあるなら、渡すのは書かせ方だけで足ります。以下は並列で書かせた33枚のデッキ側に渡したもので、1エージェント=1スライドで指示していたのはこの7つです(26枚の方の21ビルダは別の検証から流用したので、このガイドの産物ではありません)。

  1. 描かない領域と描く領域: 固定ヘッダ(ネイビー帯+大見出し)は描かない。会社テンプレのガワに委譲されていて、見出しはこちらがTITLEプレースホルダへ流します。本文の描画領域は座標で指定します。
  2. with component(slide, "name"): でグルーピングを宣言: カード・行・列といった視覚のまとまりをこの構文で囲みます。合体するときにここがグループとして掴めるようになります。
  3. テキストは必ずテキストで描く: 画像化しません。ライブテキストとして残すのが目的です。
  4. 色はトークンだけを使う: 決められた色のトークンだけを使い、生のHEX値を増やしません。
  5. アイコンは描かない: 元のアイコンは省略するか、小さな色付きの図形で代替してよい、とだけ指示しています。
  6. 自己検証ループ: レンダーしてGround Truthの画像と見比べ、はみ出し・重なり・欠落があれば直して再実行します。最大3回まで。
  7. 完成例を1枚渡す: 動作確認済みのビルダを手本として1枚渡します。これが「手本1枚」の正体です。

このうち2つ目のグルーピングは、名指しで指示しないと入りません。ガイドに入れて書かせた33枚は、33枚とも宣言が入っていました。一方、宣言を要件に入れていなかった既存21ビルダの26枚は、宣言があったのが3枚だけで、残りは位置関係からの推測に回っています。指示しても粒度までは揃わず、33枚のうち3枚は、宣言はあるのにグループが1つもできませんでした。囲んだ中に図形が1つしか無いと、束ねる意味がないので束ねない仕様だからです。「何を1つのまとまりとして囲むか」まで書いておくほうがいいと思います。

02の付録「AIに変換器を書かせるときに渡したもの」と対になる話です。渡すのはコードではなく、領域の切り方と、守らせる約束と、自分で回せる検証です。

中身を器へ収める1本のコード(アダプタ)がやっていること

Agentが返してくるのは、その1枚の中身の図だけです。置き場所も寸法も、会社テンプレとの噛み合わせも決めているのは、間に挟んだ1本のコードで、これをアダプタと呼んでいます。1枚ごとにやっているのは、この6つです。

  1. 会社テンプレのレイアウトでスライドを起こす。ロゴ・ヘッダ帯・フッター・ページ番号は、ここで勝手に出てきます。
  2. 見出しをタイトルの枠へ流す。ロゴと重ならない幅に制限してから入れます。
  3. Slidev側の装飾は描かせない。会社テンプレの装飾と二重になるからです。装飾を描く箇所は決めたフック越しにしか通らないようにしてあるので、そのフックを空にしてから走らせます。
  4. 図の実寸を測って、本文枠へ縦横同じ倍率で写す。倍率は座標とサイズだけでなく、フォントサイズ・線の太さ・影にも同じ係数で焼き込みます。
  5. フォントを1つずつ焼き込む。会社テンプレ側に指定が無く、放っておくとArialに落ちるからです。
  6. まとまりをグループとして束ねる。カードや行の境界は、Agentが書いたコード側で宣言してもらったものを使います。掴んで動かせるのは、ここのおかげです。

あとは使わない本文プレースホルダを外して終わりです。型ごとに場合分けを書く必要もなく、表紙だから章扉だからと処理を切り替えることもありません。パレットも構成も違う2本のデッキを通しましたが、アダプタは1行も書き直していません。配色とレイアウトの色を差し替えただけです。

契約の実体

装飾を描く箇所を契約フック越しに通す、というのを最小の形で書くとこうなります。

# 契約側(figure_kit)
def chrome(slide, draw):          # ガワ描画の契約フック。既定は素通し
    draw(slide)

def background(slide, fill_xml):  # ビルダはこのヘルパを呼ぶ
    chrome(slide, lambda s: shape(s, H.decor_rect("bg", 0, 0, 1920, 1080, fill_xml)))

class component:                  # with で囲んだ範囲を1グループとして記録する
    ...

# ビルダ側
def build(slide, ctx):
    background(slide, H.solid_fill(NAVY900))   # chrome() を直接呼ばない(後述の罠3)
    with component(slide, "card0"):
        draw_card(slide, ctx)

# アダプタ側:モジュールの名前を差し替えるとガワだけ消える
figure_kit.chrome = lambda slide, draw: None

H.decor_rect()は図形のXMLを文字列で返すだけで、それをスライドに足すのがshape()です。ビルダがbackground()のようなヘルパ経由で呼ぶのがポイントで、ビルダの中でchrome()を直接呼ぶと、アダプタ側の差し替えが効きません(罠3)。

宣言が無いものを位置関係から当て推量で拾う、ということをしないのはchrome()の方だけです。chrome()はフック越しに呼ばれなければ何も描かないので、装飾を位置から推測することがありません。一方のcomponent()は、宣言が無ければ図形の位置関係から判断する容器包含の空間ヒューリスティクスにフォールバックします(大きい矩形を容器、その中に6割以上収まる矩形を子として束ねます)。26枚の内訳は、宣言があったのが3枚、位置関係からの推測に回ったのが23枚(うち2枚はどちらも効かず単体のまま)でした。ガイドで宣言させた33枚の方は、33枚とも宣言が正として使われています。

グループそのものはOOXMLの<p:grpSp>です。python-pptxにグループ化のAPIが無いので、アダプタが<p:grpSp>を1つ組み立てて、対象のシェイプをspTreeから外してその下へ移し替えています。offchOffextchExtを同じ値にした恒等変換なので、群を作っても座標もフォントも動きません(スケールは各シェイプに焼き込み済みなので、群に倍率を持たせる必要がない=罠1の裏返しです)。束ねるのは機械ゲートを算出したあとです。ゲートは個々のシェイプの矩形で測るので、群にする前に測る必要があります。

機械ゲートM1〜M4

  • M1 装飾剥がし: 会社テンプレの装飾(ロゴ・帯・フッター・ページ番号)以外の背景要素が残っていないか
  • M2 座標接合: Agentが書いた図が、会社テンプレの本文枠(BODY)に収まっていて、読める大きさかどうか
  • M3 共存: ロゴ・罫線・フッターと物理的にぶつかっていないか
  • M4 編集可能: 図の中の文字が、画像ではなく<a:t>という生のテキストのrunとして残っているか。判定は、図のシェイプをXMLとして開いて<a:t>要素を数えるのと、あわせて画像シェイプ(a:blip)が0件であることを見ます。runが1本でもあれば通してしまうと、ほとんどが画像でテキストが1本だけのスライドも合格になるので、この2つを対で見る必要があります

踏んだ罠

  1. グループ化した図形をそのまま一括スケールすると、幾何だけスケールされてフォントがスケールされないことがあります(実測。0.5倍のグループでテキストがほぼ原寸のまま残りました)。幾何とフォントを別々に手でスケールするやり方は、実機で二重にスケールされる恐れがあります。ここは未確認の推定です
  2. 会社テンプレにレイアウトを足すときは、レイアウト本体・そのrels・[Content_Types].xmlのOverride・スライドマスターのレイアウト一覧とrelsの4か所を触ります。暗い地の色にする場合は、テキスト色の反転もセットで必要です(複製元が白地前提なので、プレースホルダもページ番号もフッターも沈みます)
  3. 装飾の契約はヘルパ越しに呼ばせます。ビルダ側がfrom figure_kit import (...)のように名前を束縛していると、ビルダの中で直接フックを呼んでもアダプタ側の差し替えが効きません
  4. 全面を覆う装飾は、共存の判定から外します。背景そのものなので、外さないと共存ゲートが全滅します
  5. 恒真になってしまうゲートは、合格の根拠にしません(本文枠に収まっている・ロゴ等とぶつからない、という判定は、写像の作り方からして自動で真になるため)
  6. フォントは指定しないとデフォルト(Arial)に落ちます。会社テンプレはプレースホルダにフォントの指定が無く、テーマ・マスター側のArialに落ちるので、Agentが書く図の中のrunにも明示しないと、日本語も記号も置き換え任せになります
  7. 変換元のデッキはバージョンで固定します。デッキ側が動くと、同じコードでも結果が再現しません

並列Agentへの投げ方

上のガイドを1エージェント1スライド=1ファイルに割り当てて、並列で投げています。途中の確認はSlidevの中身を会社のPowerPointテンプレに入れる話Slidevのデザインを実測してPowerPointのテンプレをコードで作る話と同じ手順なので、そちらを見てください。

ではまた!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です