PowerPointフォント置換の深淵:再帰的探索とオブジェクト管理の極意
多くのエンジニアが「PowerPointのフォント置換は標準機能で十分だ」と勘違いしている。だが、実務で数千スライドに及ぶレガシープレゼンテーションを扱う際、標準の「フォントの置換」ダイアログがどれほど無力か、君たちも痛感しているはずだ。
グループ化されたシェイプの深淵、マスターページに潜むゴースト、そしてテキストボックスの中に隠された不規則なフォント設定。これらを完全に制圧するには、VBAのオブジェクトモデルを解剖し、再帰アルゴリズムを用いてメモリの制約と戦うしかない。
今回は、システム管理者が「最後の一手」として頼るべき、堅牢かつ高速なフォント置換エンジンの設計思想を伝授する。
—
1. アーキテクチャの選定:なぜ「再帰」なのか
PowerPointのオブジェクトモデルにおいて、`Shapes`コレクションは入れ子構造を持つ。`GroupShapes`が存在する限り、単純なループ処理ではフォントの漏れが発生する。
パフォーマンスを最大化し、メモリリークを回避するための原則は以下の2点だ。
1. オブジェクトの明示的解放: `Set obj = Nothing`を徹底し、COMポインタの残骸によるメモリ肥大化を防ぐ。
2. 再帰的走査: グループ化の階層(Depth)に関わらず、全ての`TextFrame`を網羅する。
—
2. 実装:堅牢なフォント置換エンジン
以下に、プレゼンテーション全体を走査し、安全にフォントを入れ替えるためのコアコードを示す。
Option Explicit
‘ 伝説的な安定性を誇るフォント置換エンジン
Public Sub ReplaceFontEngine(ByVal oldFontName As String, ByVal newFontName As String)
Dim ppt As Presentation
Set ppt = ActivePresentation
‘ 1. スライドマスタとレイアウトを走査(ここが漏れると後で崩れる)
Dim master As Master
For Each master In ppt.SlideMaster.CustomLayouts
ProcessShapes master.Shapes, oldFontName, newFontName
Next master
ProcessShapes ppt.SlideMaster.Shapes, oldFontName, newFontName
‘ 2. 通常スライドの走査
Dim sld As Slide
For Each sld In ppt.Slides
ProcessShapes sld.Shapes, oldFontName, newFontName
Next sld
MsgBox “フォント置換完了: ” & oldFontName & ” -> ” & newFontName, vbInformation
End Sub
‘ 再帰的にShapesを掘り下げる処理
Private Sub ProcessShapes(shapes As shapes, oldFont As String, newFont As String)
Dim shp As Shape
For Each shp In shapes
‘ グループ化されている場合は再帰呼び出し
If shp.Type = msoGroup Then
ProcessShapes shp.GroupItems, oldFont, newFont
ElseIf shp.HasTextFrame Then
If shp.TextFrame.HasText Then
ReplaceInTextRange shp.TextFrame.TextRange, oldFont, newFont
End If
End If
‘ オブジェクトの明示的解放はVBAにおいて「礼儀」である
Set shp = Nothing
Next shp
End Sub
‘ テキスト範囲内のフォントをピンポイントで置換
Private Sub ReplaceInTextRange(tr As TextRange, oldFont As String, newFont As String)
Dim i As Long
‘ パフォーマンスを考慮し、Runs単位で判定
For i = 1 To tr.Runs.Count
If tr.Runs(i).Font.Name = oldFont Then
tr.Runs(i).Font.Name = newFont
End If
Next i
End Sub
—
3. シニアエンジニアのための極限の知見
メモリとパフォーマンスの境界線
VBAはガベージコレクションが強力ではない。特に数千枚のプレゼンテーションを処理する場合、`Shape`オブジェクトを不用意に保持し続けると、COMリソースの枯渇を招く。上記のコードでは、`ProcessShapes`内で都度`Set shp = Nothing`を明示しているが、これは大規模バッチ処理における「防御的プログラミング」の基本だ。
レガシー環境との共存(Windows APIの活用)
もし、フォントがシステムにインストールされているか事前に確認したい場合は、`EnumFontFamiliesEx`等のWindows APIを呼び出す必要がある。標準の`Font.Name`に存在しないフォントを代入してもエラーにはならないが、PowerPoint内部のフォントテーブルが汚染される可能性がある。本番環境への導入時は、`CreateFontIndirect`等を用いて、システムフォントの存在確認を行うラッパー関数を挟むことを推奨する。
なぜ「置換」ではなく「走査」なのか
標準機能の「フォントの置換」は、しばしば「テーマフォント」の定義と競合し、意図しないスタイル崩れを引き起こす。VBAで`TextRange.Runs`を直接叩く手法は、テーマフォントの設定を無視して個別に設定されたフォント(ローカルオーバーライド)を強制的に書き換えるため、「見た目の完全な一致」を保証する唯一の手段となる。
—
結びに
コードは単なる命令の羅列ではない。それは、複雑なオブジェクトモデルに対する「支配権の行使」だ。このスクリプトを君のツールボックスに加え、無意味な手作業から解放されることを願う。
技術の深淵を覗く者よ、次回のデバッグで会おう。
