【上級者向け】VisioのPDF出力エンジンにおけるフォント埋め込みエラーを回避する設定
Visioによる図面自動化において、最大の鬼門の一つが「PDF出力時のフォント埋め込みエラーと文字化け」である。
開発環境のローカルPCでは完璧にレンダリングされるVSDXが、CI/CDサーバー、仮想デスクトップ(VDI)、あるいは権限が厳しく制限された無人実行のWindows Server上でバッチ処理された途端、豆腐文字(□)の乱舞や、`ExportAsFixedFormat` メソッドでの突然のCOMExceptionに砕け散る。この現象に直面し、徹夜でプリンタドライバのプロパティと格闘したエンジニアも少なくないだろう。
本稿では、Visioの内部レンダリングエンジンとOSのフォントサブシステムの関係性を解き明かし、VBAコードからこれを完全に制御・回避するための極限の知見を共有する。
—
1. 根本原因:なぜVisioのPDF出力はフォントでつまずくのか
Visioの `Document.ExportAsFixedFormat`(または `Document.SaveAs` によるPDF出力)は、内部で独自のGDI/XPSプリントパイプラインを起動する。ここで発生するトラブルの根源は以下の3点に集約される。
1. デバイスフォント置換とライセンス制限:
TrueType/OpenTypeフォントの `embeddable` フラグ(Typeface Embedding Permissions)が厳格に設定されている場合、VisioのバックグラウンドプロセスはそのフォントをPDFストリームにサブセット埋め込みできず、フォールバック先のゴシックや明朝に強制置換する。
2. サーバーOSのフォントキャッシュの欠落:
ヘッドレスなWindows Server環境では、ユーザーセッションがインタラクティブに確立されていない場合、GDIサブシステムがGDIフォントキャッシュを構築できず、Visioが要求したカスタムフォント(社内標準フォント等)を見失う。
3. COMオブジェクトのメモリリークとプリンタコンテキストの枯渇:
大量の図面をループ処理でPDF化する際、Visioのインスタンスやドキュメントオブジェクトの解放漏れが起きると、GDIリソース(ハンドル)が枯渇し、フォントレンダリングエンジンが例外を吐く。
—
2. 回避策のアーキテクチャ
この問題をコードレベルで完全に封じ込めるには、以下のアプローチを複合的に実装する必要がある。
- 完全修飾パスとレジストリ・セッション環境の考慮: 出力前に対象フォントがアプリケーションコンテキストから確実にロードされる状態を作る。
- PDFエクスポートオプションの厳密な指定: `pbPrintAllPages` や解像度の設定に加え、可能な限りベクトルを維持しつつフォントアウトラインを維持するパラメータチューニング。
- 堅牢なオブジェクトライフサイクル管理: `Nothing` 代入による即時解放とガベージコレクションの強制。
—
3. 実装コード:堅牢なPDFエクスポート・プロシージャ
以下に、実業務のバッチ処理やサーバーサイド連携に耐えうる、極限まで最適化されたVBAコードを示す。エラーハンドリングとオブジェクトの確実な解放を担保している。
Option Explicit
‘ —————————————————————–
‘ 輪郭保持型 PDFエクスポート・エンジン
‘ —————————————————————–
Public Sub ExportVisioToPdfRobust(ByVal targetVsdxPath As String, ByVal outputPdfPath As String)
Dim visApp As Visio.Application
Dim visDoc As Visio.Document
Dim lngCurrentAlerts As Long
‘ 1. 環境の堅牢化:UIアラートや警告ダイアログを完全抑制(無人実行必須)
lngCurrentAlerts = Application.AlertsMode
Application.AlertsMode = visAlertsNone
On Error GoTo ErrorHandler
‘ 2. Visioインスタンスの安全な取得・生成
‘ ※サーバーサイドでは新規プロセス起動が最も安全
Set visApp = New Visio.Application
visApp.Visible = False
visApp.ScreenUpdating = False
‘ 3. ドキュメントのオープン(読み取り専用、修復なし)
Set visDoc = visApp.Documents.OpenEx(targetVsdxPath, visOpenRO + visOpenNoWorkspace)
‘ 4. フォント埋め込みエラーを回避するための事前検証(オプション)
‘ ※必要に応じてカスタムフォントの存在チェックをここに挿入
‘ 5. PDFエクスポートの実行
‘ Visio.VisFixedFormatTypes.visFixedFormatPDF を使用
‘ パラメータ: 形式, 出力パス, 固定形式ターゲット(印刷/画面), ページ範囲指定
visDoc.ExportAsFixedFormat _
visFixedFormatPDF, _
outputPdfPath, _
visRasterizeNone, _ ‘ ベクター品質を維持しラスタライズを回避(フォント化け防止に有効)
visPrintAll
‘ 6. 正常終了処理
visDoc.Saved = True
visDoc.Close
Set visDoc = Nothing
visApp.Quit
Set visApp = Nothing
Application.AlertsMode = lngCurrentAlerts
Exit Sub
ErrorHandler:
‘ 異常系:メモリリークを防ぎつつエラーを上位に伝播
Dim errDesc As String
errDesc = Err.Description
On Error Resume Next
If Not visDoc Is Nothing Then
visDoc.Saved = True
visDoc.Close
Set visDoc = Nothing
End If
If Not visApp Is Nothing Then
visApp.Quit
Set visApp = Nothing
End If
Application.AlertsMode = lngCurrentAlerts
‘ 致命的エラーとして再送出
Err.Raise vbObjectError + 1000, “ExportVisioToPdfRobust”, _
“PDF出力中に致命的なエラーが発生しました: ” & errDesc & ” (ファイル: ” & targetVsdxPath & “)”
End Sub
—
4. チーフアーキテクトからの実践的アドバイス(運用上の極意)
1. サーバーOS(Windows Server)上の制約事項:
もしこのコードをWindows Serverのバックグラウンドサービスやタスクスケジューラ(「ユーザーがログオンしているかどうかにかかわらず実行する」)で動かす場合、セッション0の制約によりGDIフォントエンジンが正常に動作しないケースがある。これを回避するためには、実行ユーザーアカウントに一度インタラクティブログインさせ、対象フォントを「すべてのユーザー向け(For all users)」として正しくインストールしておく必要がある。
2. フォントの「埋め込み許可(Embeddability)」の確認:
OpenType/TrueTypeフォントのプロパティにある「印刷およびプレビュー(Print and preview)」の権限が「禁止」に設定されているフォントは、いかなるVBAコードを用いてもVisioのPDFエンジンで強制的に文字化けかエラーを引き起こす。社内標準フォントを採用する場合は、必ずフォントベンダーの再配布・埋め込みライセンスを確認すること。
3. 大量処理時のメモリマネジメント:
数百ファイルのバッチ変換を行う場合、上記のコード構造(ループ内で毎回 `New Visio.Application` を行い、完全に破棄する)を採用せよ。Visioのプロセスを常駐させたままでドキュメントを開閉し続けると、COMコンポーネントの内部キャッシュ肥大化により、中盤以降に必ずフォント関連のCOMException(0x80040338など)に直面することになる。
レガシーなシステムであっても、背後にあるアーキテクチャ(OSのセッション、GDI、フォントサブシステム)を正確に理解していれば、制御不能なエラーなど存在しない。この知見が、あなたの自動化パイプラインを強固なものにすることを願う。
