VisioのPDF出力における「用紙サイズとの戦い」に終止符を打つ
Visioの自動化において、最もエンジニアの精神を摩耗させるのは「PDF出力時のレイアウト崩れ」だ。GUIで設定すれば一瞬のことが、コードに落とし込んだ途端、プリンタドライバの制約や`PageSetup`オブジェクトの気まぐれな挙動によって、意図しない余白やA4固定のPDFが生成される。
特に、図面サイズが可変である場合、`PageSetup`のデフォルト値は設計者の意図を無視して暴走する。本稿では、この悪夢を断ち切り、図面サイズに完全追従するPDF出力を実現するための「アーキテクト級の解法」を提示する。
—
1. 原理:なぜ「図面サイズ」が無視されるのか
Visioの`ExportAsFixedFormat`メソッドは、背後で「プリンタの用紙設定」を継承する仕様になっている。つまり、コード上でページサイズを指定しても、プリンタ設定側が「A4」を主張していれば、PDFはそれに引きずられる。
これを解決するには、以下の3つの制約をプログラマティックに制御する必要がある。
1. SizeToFitPageプロパティの強制: 図面サイズをページに合わせる。
2. PageSizeの同期: `Page`オブジェクトの`PageWidth`と`PageHeight`を読み取り、`PageSetup`に直接流し込む。
3. プリンタ設定のバイパス: `visFixedFormatPDF`出力時に、用紙サイズの自動調整を明示的に強制する。
—
2. 実装:メモリ管理を徹底したPDF出力エンジン
以下に、メモリリークを許さないクリーンなVBAコードを示す。`Set`したオブジェクトは必ず`Nothing`で解放し、ループ処理での描画更新を`Application.ScreenUpdating`で抑制するのが鉄則だ。
‘ @description: Visio図面をページサイズに合わせてPDFへエクスポートする
‘ @version: 1.0.0
Public Sub ExportToFitPdf(ByVal targetDoc As Visio.Document, ByVal exportPath As String)
Dim vsoPage As Visio.Page
Dim vsoPageSetup As Visio.PageSetup
‘ 画面更新の停止(パフォーマンス最適化)
Application.ScreenUpdating = False
On Error GoTo Cleanup
Set vsoPage = targetDoc.Pages(1) ‘ 必要に応じてループ処理へ拡張
Set vsoPageSetup = vsoPage.PageSetup
‘ 重要:図面サイズをページサイズに強制同期させる
‘ これを行わないと、PDF出力時にトリミングや空白発生の温床となる
vsoPageSetup.SizeToFitPage
‘ PDF出力実行
‘ visFixedFormatPDF: PDF形式
‘ visDocExAll: 全ページ
‘ visDocExFlatten: レイヤー統合(必要に応じて調整)
targetDoc.ExportAsFixedFormat _
FixedFormat:=visFixedFormatPDF, _
OutputFileName:=exportPath, _
Intent:=visImageIntentPrint, _
PrintRange:=visDocExAll
Cleanup:
‘ オブジェクトの明示的解放(メモリ管理の鉄則)
If Not vsoPageSetup Is Nothing Then Set vsoPageSetup = Nothing
If Not vsoPage Is Nothing Then Set vsoPage = Nothing
Application.ScreenUpdating = True
If Err.Number <> 0 Then
MsgBox “エラー発生: ” & Err.Description, vbCritical
End If
End Sub
—
3. レガシー環境とアーキテクチャへの洞察
Windows APIによる「プリンタドライバ」の強制介入
もし上記のコードでも「余白」が制御できない場合、それはVisioの内部設定ではなく、OS側の規定のプリンタ設定が干渉している。そのような極限環境では、`Winspool.drv`を使用して、一時的にPDF出力用プリンタを「標準プリンタ」に切り替える必要がある。
`SetDefaultPrinter`関数を用いたAPI呼び出しを実装に組み込むことで、環境に依存しない安定した出力パイプラインを構築できる。
オブジェクトのライフサイクルとパフォーマンス
VBAにおける`Nothing`の代入は、単なるマナーではない。Visioは内部でCOMオブジェクトの参照カウントを管理しており、特に`PageSetup`のような深い階層のオブジェクトを放置すると、大規模なバッチ処理でメモリスタックが飽和する。
- 大規模図面の場合: `DoEvents`を適宜挿入し、Visioの描画エンジンに呼吸をさせること。
- システム間連携: PDF生成後にファイルシステムへアクセスする場合、`FileSystemObject`を利用して`Wait`処理を挟むべきだ。ファイルロックが発生している状態で後続の処理(メール送信やFTPアップロード)を走らせるのは、システム障害の典型的なパターンである。
—
結びに:エンジニアとしての矜持
Visio VBAは「古い技術」と揶揄されることもある。しかし、図面管理というビジネスの心臓部を担う以上、その挙動を完全に掌握し、予測可能なコードを書くことは、シニアエンジニアにとって避けて通れない美学である。
「なぜ動かないのか」と悩む時間はもう終わりだ。オブジェクトのライフサイクルを制御し、ドライバの挙動を読み解く。その先にこそ、自動化の真の安定がある。
君のコードが、今日もどこかのサーバーで正確な図面を生成し続けていることを願う。
