【入門編】【中級者】横向き(16:9)と縦向き(A4)が混在するスライドを自動判別し、向きごとに別々のPDFへ分割・保存する制御マクロ – PowerPoint VBA解析バイブル

スポンサーリンク
スポンサーリンク

カオスなスライドを秩序へ。横向き・縦向き混在プレゼンを自動判別してPDF分割保存する「極限の制御術」

こんにちは。自動化の深淵へようこそ。

「マクロの記録」ボタンを押して、記録されたコードを眺めては「これ、どういう意味なんだろう?」と首を傾げたことはありませんか? もしそうなら、あなたは今、プログラミングの「書き手」から「設計者(アーキテクト)」へと進化する境界線に立っています。

今日扱うテーマは、実務で直面する非常に「泥臭く、かつ厄介な問題」です。

「スライドの中に、横向き(16:9)のグラフ資料と、縦向き(A4)の報告書が混ざっている。これをバラバラのPDFとして一瞬で出力したい」

PowerPointの標準機能では、PDF出力は「プレゼンテーション全体」か「選択したスライド」のどちらかです。混在している場合、手作業で分割して保存するのは、エンジニアとしてのプライドが許さない……そんな状況を、VBAの力でエレガントに解決していきましょう。

1. アーキテクチャの設計図:どうやって「判別」し「仕分ける」か

いきなりコードを書き始めるのは、設計図なしでビルを建てるようなものです。まずは、頭の中に「ロジックの設計図」を描きましょう。

今回のミッションを達成するための戦略は、以下の3ステップです。

1. 検知(Detection): 各スライドの `Width`(幅)と `Height`(高さ)を比較し、どちらが大きいかを判定する。
2. 隔離(Isolation): 判別した向きごとに、新しい「空のプレゼンテーション」をメモリ上に用意する。
3. 複製と出力(Cloning & Export): 元のスライドを新しいプレゼンテーションへコピーし、最後にそれぞれをPDFとして書き出す。

ここで重要なのは、「元のファイルをいじらない」という設計思想です。元のファイルを直接操作してスライドを削除したりすると、万が一エラーが起きた時にデータが壊れるリスクがあります。新しいプレゼンテーションを「器」として用意する。これが、プロの仕事です。

2. 実装:向きを判別し、別々のPDFへ導くマスターコード

それでは、魂を込めたコードを公開します。このコードは、単に動くだけでなく、エラーに強く、メンテナンスしやすい構造を意識しています。

Option Explicit

''' <summary>
''' スライドの向きを自動判別し、横向き用と縦向き用のPDFに分割保存するメインルーチン
''' </summary>
Sub SplitPresentationByOrientation()
    Dim sourcePres As Presentation
    Dim landscapePres As Presentation
    Dim portraitPres As Presentation
    Dim sld As Slide
    Dim slideCount As Integer
    Dim folderPath As String
    Dim baseFileName As String
    
    ' 1. 環境のセットアップ
    Set sourcePres = ActivePresentation
    folderPath = sourcePres.Path & "\"
    ' ファイル名から拡張子を除いたものを取得
    baseFileName = Left(sourcePres.Name, InStrRev(sourcePres.Name, ".") - 1)
    
    ' 2. 新しいプレゼンテーション(器)の準備
    ' 横向き用と縦向き用の2つの「空のプレゼン」をメモリ上に作成します
    Set landscapePres = Presentations.Add(WithWindow:=msoFalse)
    Set portraitPres = Presentations.Add(WithWindow:=msoFalse)
    
    On Error GoTo ErrorHandler
    
    ' 画面更新を止めてパフォーマンスを向上させる(お作法)
    ' ※PowerPoint VBAにはExcelのような ScreenUpdating がないため、
    '   手動でウィンドウ操作を制御するのがコツです。

    Debug.Print "--- 分割処理を開始します ---"

    ' 3. スライドを一つずつ走査(ループ)
    For Each sld In sourcePres.Slides
        slideCount = sld.SlideIndex
        
        ' 【ここが核心】幅と高さを比較して向きを判定
        If sld.Parent.PageSetup.SlideWidth < sld.Parent.PageSetup.SlideHeight Then
            ' --- 縦向き(Portrait)の場合 ---
            Debug.Print "Slide " & slideCount & ": 縦向きを検知"
            CopySlideToPresentation sld, portraitPres
        Else
            ' --- 横向き(Landscape)の場合 ---
            Debug.Print "Slide " & slideCount & ": 横向きを検知"
            CopySlideToPresentation sld, landscapePres
        End If
    Next sld

    ' 4. PDFとして書き出し
    ' 横向きプレゼンを出力
    If landscapePres.Slides.Count > 0 Then
        landscapePres.ExportAsFixedFormat _
            Path:=folderPath & baseFileName & "_Landscape.pdf", _
            FixedFormatType:=ppFixedFormatTypePDF
    End If
    
    ' 縦向きプレゼンを出力
    If portraitPres.Slides.Count > 0 Then
        portraitPres.ExportAsFixedFormat _
            Path:=folderPath & baseFileName & "_Portrait.pdf", _
            FixedFormatType:=ppFixedFormatTypePDF
    End If

    MsgBox "完了しました!" & vbCrLf & "保存先: " & folderPath, vbInformation, "Success"

CleanUp:
    ' 5. 後始末(オブジェクトの解放)
    ' メモリを食いつぶさないよう、作成したプレゼンを閉じる
    On Error Resume Next
    landscapePres.Close
    portraitPres.Close
    Set landscapePres = Nothing
    Set portraitPres = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "Error"
    Resume CleanUp
End Sub

''' <summary>
''' スライドを別のプレゼンテーションへコピーする補助ルーチン
''' </summary>
''' <param name="targetSlide">コピー元のスライド</param>
''' <param name="destPres">コピー先のプレゼンテーション</param>
Private Sub CopySlideToPresentation(targetSlide As Slide, destPres As Presentation)
    Dim newSlide As Slide
    
    ' スライドをコピー
    targetSlide.Copy
    
    ' コピー先のプレゼンテーションの末尾に貼り付け
    ' Pasteメソッドは、スライドのレイアウトや書式を保持したまま貼り付けます
    destPres.Slides.Paste
    
    ' 貼り付けた直後のスライド(最後尾)を取得
    Set newSlide = destPres.Slides(destPres.Slides.Count)
    
    ' 【重要】貼り付け先のPageSetupをコピー元に合わせる
    ' これを行わないと、レイアウトが崩れる原因になります
    With newSlide.Parent.PageSetup
        .SlideWidth = targetSlide.Parent.PageSetup.SlideWidth
        .SlideHeight = targetSlide.Parent.PageSetup.SlideHeight
    End With
End Sub

3. エンジニアの視点:なぜこのコードは「強い」のか?

ただ動くだけのコードと、プロのコードの違いはどこにあるのか。このコードに込めた「極限の知見」を解説します。

① オブジェクトのライフサイクル管理

コードの最後に `CleanUp` セクションを設けています。`Presentations.Add` で作成したプレゼンテーションは、たとえ中身が空であっても、メモリ上に存在し続けます。大量の処理を繰り返す自動化ツールにおいて、これらを適切に `.Close` し、`Nothing` を代入して解放することは、「メモリリーク(メモリの無駄遣い)」を防ぐための鉄則です。

② レイアウト崩れを防ぐ「PageSetupの同期」

ここが今回の最も重要なテクニカルポイントです。
単に `Slide.Copy` して `Paste` するだけでは、貼り付け先のプレゼンテーションの基本設定(例えば16:9)に引きずられて、図形や文字が歪んでしまうことがあります。
`CopySlideToPresentation` 内で、コピー先の `PageSetup` をコピー元の `Width/Height` と強制的に同期させている点に注目してください。これにより、どんな比率のスライドが来ても、見た目を完璧に維持できます。

③ 堅牢なエラーハンドリング

`On Error GoTo ErrorHandler` を実装しています。自動化プログラムにおいて、最大の敵は「予期せぬ停止」です。例えば、ファイルが読み取り専用だったり、保存先フォルダに権限がなかったりする場合でも、エラーメッセージを表示して、必ず「後始末(CleanUp)」を通ってから終了するように設計しています。

4. 陥りやすい罠(ハマりポイント)

中級者への階段を登る皆さんに、あえて「落とし穴」を教えておきましょう。

  • 「スライドの向き」の判定ミス:

スライドの向きを `Orientation` プロパティだけで判定しようとすると、カスタムサイズのスライドで誤作動することがあります。今回のように `Width` と `Height` の数値比較を行うのが、最も確実で「嘘をつかない」判定方法です。

  • 貼り付け時のフォーマット:

`Paste` メソッドは非常に強力ですが、非常に複雑なアニメーションや特殊なアドインによる図形が含まれている場合、稀に挙動が不安定になることがあります。その場合は、一度 `Slide.Copy` ではなく、スライドそのものをインポートする手法を検討しますが、まずはこの方法が最も軽量です。

最後に:ここをクリアすれば、VBAの基本はバッチリです

「スライドを検知する」「新しい器を作る」「属性をコピーして同期させる」という一連の流れを理解できれば、あなたはもう「マクロの記録」の呪縛から解き放たれています。

プログラミングの本質は、「複雑な事象を、小さな論理の積み重ねに分解すること」にあります。

今回のコードをベースに、「ファイル名を日付にするには?」「特定のフォルダ内の全ファイルを処理するには?」と、少しずつ改造してみてください。その試行錯誤の先に、真の自動化エンジニアとしての道が開けています。

応援していますよ。さあ、次の自動化へ行きましょう!

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