【実務・中級編】【中級者】プレゼンテーション内の不要なスライドマスターや未使用レイアウトを自動検出してパージし、ファイルサイズをスリム化した状態で保存する軽量化マクロ – PowerPoint VBA解析バイブル

スポンサーリンク

【PowerPoint VBA】肥大化したスライドを極限まで軽量化する!「未使用マスター・レイアウト」自動パージ術

開発現場でよくある光景だ。
他部署から引き継いだり、様々な資料のパーツをコピペし続けたりした結果、「たった数枚のスライドなのに、ファイルサイズが数十MBもある」プレゼンテーション資料。

原因の多くは、スライドの背後に隠積した「ゴミデータ」にある。特に悪さをするのが、使われていない「スライドマスター」と「カスタムレイアウト」だ。これらはGUIの手動操作で削除しようにも、依存関係のチェックが面倒で、下手をするとデザインが崩れる地雷原と化している。

今回は、PowerPoint VBAのオブジェクトモデルを熟知したアーキテクトの視点から、この肥大化の元凶をロジカルに検出し、安全かつ爆速でパージ(削除)してファイルをスリム化するプロダクションコードを伝授する。

—

なぜPowerPointは肥大化するのか?(非効率な設計の正体)

PowerPointファイルを解凍したことがあるだろうか? 実はこのファイル、中身はただのZIPアーカイブ(OpenXML形式)だ。
ユーザーが資料を作るとき、以下のようなプロセスが無意識に行われている。

1. 外部の綺麗な資料からスライドをコピー&ペーストする。
2. その際、元の資料が持っていたスライドマスターやレイアウトが、ごっそり新しいファイルに持ち込まれる。
3. コピー元のスライドは後から削除しても、持ち込まれたマスターやレイアウトはファイル内に残留し続ける。

GUIでこれらを整理しようとすると、「このレイアウトは本当にどのスライドからも使われていないか?」を一枚一枚目視で確認するか、運任せで削除ボタンを押してエラーを食らうしかない。

これをVBAで完全自動化する。アプローチは極めてシンプルだ。
「全スライドが参照しているレイアウトのIDを収集し、ドキュメントに存在する全レイアウトと比較して、使われていないものを容赦なく削除する」。これだけだ。

—

バグを生まないための堅牢な設計方針

プロダクション環境で動かすマクロにおいて、以下の「地雷」を踏まない配慮が必要となる。

1. 参照切れ(Reference Error)の防止
スライドマスターやレイアウトを削除する際、PowerPointの内部インデックスがずれる。これを防ぐために、「コレクションの逆順ループ(後ろから削除)」を徹底する。
2. 保護されたマスターの保護
Office標準のマスターや、現在アクティブに描画で使用されているマスターを誤って消去すると、実行時エラー(エラー番号:-2147188160等)が発生する。これらを安全にハンドリングする。
3. セーフティセーブ(別名保存)
既存の重要なファイルを一発上書きして破壊するリスクを排除するため、処理後は自動的にサフィックス(`_slim.pptx`など)を付与して別名保存する設計とする。

—

コピペで使える!極限の軽量化プロダクションコード

以下のコードをVBAエディタ(`Alt + F11`)の標準モジュールに貼り付けて実行してほしい。実務で即座に使えるレベルの堅牢性とエラーハンドリングを実装している。

Option Explicit

‘ ==============================================================================
‘ 処理名 : PurgeUnusedMasterAndLayouts
‘ 概要 : 未使用のスライドマスターとレイアウトを自動検出し、ファイルサイズを圧縮する
‘ 著者 : 業務自動化チーフアーキテクト
‘ ==============================================================================
Public Sub PurgeUnusedMasterAndLayouts()
Dim targetPres As Presentation
Set targetPres = ActivePresentation

‘ 予期せぬエラーやファイル破損を防ぐため、処理開始前のファイルパスを確認
If targetPres.Path = “” Then
MsgBox “一度ファイルを保存してからマクロを実行してください。”, vbCritical, “エラー”
Exit Sub
End If

Dim originalSize As Double
Dim newSize As Double
originalSize = FileLen(targetPres.FullName) / 1024 / 1024

Dim startTime As Single
startTime = Timer

On Error GoTo ErrorHandler

‘ 画面描画を停止してパフォーマンスを極限まで引き上げる
Application.ScreenUpdating = False

Dim deletedLayoutCount As Long
Dim deletedMasterCount As Long
deletedLayoutCount = 0
deletedMasterCount = 0

‘ ————————————————————————–
‘ 1. 未使用レイアウトの特定と削除
‘ ————————————————————————–
Dim sld As Slide
Dim dictUsedLayouts As Object
Set dictUsedLayouts = CreateObject(“Scripting.Dictionary”)

‘ 全スライドが現在どのレイアウトを使用しているかハッシュに保持
For Each sld in targetPres.Slides
On Error Resume Next
Dim layoutName As String
layoutName = sld.CustomLayout.Name
If Err.Number = 0 Then
If Not dictUsedLayouts.Exists(sld.CustomLayout) Then
dictUsedLayouts.Add sld.CustomLayout, True
End If
End If
On Error GoTo ErrorHandler
Next sld

‘ マスターを逆順でループ(コレクション操作の鉄則)
Dim i As Long, j As Long
For i = targetPres.SlideMaster.Designs.Count To 1 Step -1
Dim currentDesign As Design
Set currentDesign = targetPres.SlideMaster.Designs(i)

‘ デザイン内のレイアウトを逆順で走査
For j = currentDesign.SlideMaster.CustomLayouts.Count To 1 Step -1
Dim targetLayout As CustomLayout
Set targetLayout = currentDesign.SlideMaster.CustomLayouts(j)

‘ スライドから参照されておらず、かつプレースホルダー等の保護対象外であるか判定
‘ ※先頭の主要レイアウト(タイトル、白紙など)は誤削除防止のため除外することも可能だが
‘ 今回は完全に使われていないものをターゲットとする
If Not dictUsedLayouts.Exists(targetLayout) Then
‘ 削除実行
targetLayout.Delete
deletedLayoutCount = deletedLayoutCount + 1
End If
Next j
Next i

‘ ————————————————————————–
‘ 2. 未使用スライドマスターの特定と削除
‘ ————————————————————————–
‘ スライドに使用されていないデザイン(マスター)を削除
For i = targetPres.Designs.Count To 1 Step -1
Dim dsn As Design
Set dsn = targetPres.Designs(i)

‘ このデザインのレイアウトが1つもスライドに使われていないかチェック
Dim isDesignUsed As Boolean
isDesignUsed = False

Dim cl As CustomLayout
For Each cl in dsn.SlideMaster.CustomLayouts
If dictUsedLayouts.Exists(cl) Then
isDesignUsed = True
Exit For
End If
Next cl

‘ 最低1つのマスター(先頭)はPowerPointの仕様上削除できない、または削除してはいけないため
‘ デザイン数が2つ以上ある場合のみ削除を試みる
If Not isDesignUsed And targetPres.Designs.Count > 1 Then
On Error Resume Next
dsn.Delete
If Err.Number = 0 Then
deletedMasterCount = deletedMasterCount + 1
End If
On Error GoTo ErrorHandler
End If
Next i

‘ ————————————————————————–
‘ 3. 最適化された状態で別名保存
‘ ————————————————————————–
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim parentDir As String, baseName As String, ext As String
parentDir = fso.GetParentFolderName(targetPres.FullName)
baseName = fso.GetBaseName(targetPres.Name)
ext = fso.GetExtensionName(targetPres.Name)

Dim savePath As String
savePath = parentDir & “\” & baseName & “_slim.” & ext

‘ 上書き確認をポップアップさせないためにDisplayAlertsを操作
Application.DisplayAlerts = False
targetPres.SaveAs savePath
Application.DisplayAlerts = True

Application.ScreenUpdating = True

‘ 処理結果の集計
newSize = FileLen(savePath) / 1024 / 1024
Dim reductionRate As Double
If originalSize > 0 Then
reductionRate = (1 – (newSize / originalSize)) 100
Else
reductionRate = 0
End If

‘ 完了レポート
MsgBox “軽量化メンテナンスが完了しました!” & vbCrLf & vbCrLf & _
“【削除結果】” & vbCrLf & _
“・不要レイアウト削除数: ” & deletedLayoutCount & ” 件” & vbCrLf & _
“・不要マスター削除数 : ” & deletedMasterCount & ” 件” & vbCrLf & vbCrLf & _
“【ファイルサイズ圧縮】” & vbCrLf & _
“・変更前: ” & Format(originalSize, “0.00”) & ” MB” & vbCrLf & _
“・変更後: ” & Format(newSize, “0.00”) & ” MB” & vbCrLf & _
“・圧縮率: ” & Format(reductionRate, “0.0”) & ” % DOWN” & vbCrLf & vbCrLf & _
“保存先: ” & savePath, vbInformation, “最適化完了”
Exit Sub

ErrorHandler:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub

—

コードのアーキテクチャ解説

このスクリプトが実務で耐えうる理由を、いくつか技術的な観点から補足しておく。

  • `Scripting.Dictionary` によるO(1)の高速検索

全スライド(例:数百枚)のレイアウト参照関係をチェックする際、愚直に配列やコレクションで走査すると$O(N^2)$のオーダーとなり処理が重くなる。Dictionaryオブジェクトを使うことで、参照チェックの計算量を劇的に削減し、一瞬で処理を終わらせている。

  • `Application.ScreenUpdating = False` の恩恵

PowerPoint VBAにおいて、オブジェクトの削除やデザインの変更のたびに画面描画(UIの再描画)走ると、数秒〜数十秒の無駄なロスが発生する。これを完全に封じることで、バックグラウンドで高速にパージ処理を完結させる。

  • 安全性(セーフティセーブ)の担保

オリジナルファイルを直接破壊するリスクを排除するため、自動的に `_slim.[拡張子]` というサフィックスを付与して別名保存する。これにより、万が一レイアウトの依存関係で想定外の挙動があった場合でも、オリジナルの安全性が完全に担保される。

—

チーフアーキテクトからの実務アドバイス

このマクロをチームメンバーに使わせる、あるいは全社のファイルサーバの定期バッチ(VBA単体ではなく外部のVBScriptやVB.NETからPowerPointをCOM操作して一括処理)に組み込むことで、ストレージの圧迫を防ぐだけでなく、「動作が重いプレゼン資料を開くたびにイライラする」という隠れた生産性ロスを根絶できる。

散らかったゴミデータを自動で片付け、常に軽快な状態でプレゼンに臨む――。
こうしたエンジニアリングの粋を取り入れた地道な自動化こそが、真の業務効率化をもたらすのだ。

タイトルとURLをコピーしました