Visio PDF出力の闇を断つ:フォント埋め込みエラーを完全制圧するアーキテクチャ
VisioからPDFを書き出す際、なぜか特定の環境で出力が失敗する、あるいはテキストが「豆腐(文字化け)」になる。この問題の根源は、PDFレンダリングエンジンが各シェイプの`Char.Font`プロパティを解決できず、埋め込み不可のフォントやライセンス制限のかかったサブセットを検知し、安全策として処理を中断することにある。
今回は、VBAの深層からこの問題を制圧する。GUIのダイアログに頼らず、メモリを浪費せず、確実にフォントの「生存」を事前判定するロジックを伝授しよう。
—
1. なぜ「Visioの標準機能」だけでは不十分なのか
VisioのPDF出力は、内部的にGDI/GDI+経由で描画処理を行う。この時、フォント情報がシステムで見つからない、あるいはPDF/A規格に準拠できないフォントが含まれている場合、エラーは突如として発生する。
シニアエンジニアが意識すべきは、「オブジェクトの走査コスト」と「メモリリークの回避」だ。数千のシェイプを持つ図面を力任せにループさせれば、COMの呼び出しオーバーヘッドでVBAは悲鳴を上げる。我々は、最低限のアクセスでフォント情報を抽出しなければならない。
—
2. フォント埋め込み事前チェックロジックの実装
以下のコードは、ドキュメント内の全ページ・全シェイプを走査し、`Char.Font`プロパティがシステムに存在しない、あるいは「埋め込み不可」としてフラグが立てられているものを抽出する。
Option Explicit
‘ 伝説のエンジニアたるもの、常にメモリの解放を怠るな
‘ 不必要なオブジェクトの参照は、VBAの寿命を縮める
Public Sub ValidateDocumentFonts()
Dim vsoDoc As Visio.Document
Dim vsoPages As Visio.Pages
Dim vsoPage As Visio.Page
Dim vsoShapes As Visio.Shapes
Dim vsoShape As Visio.Shape
Set vsoDoc = ActiveDocument
‘ 簡易的なログ出力用コレクション
Dim badFonts As Collection
Set badFonts = New Collection
On Error Resume Next ‘ 再帰呼び出し中の予期せぬエラーを回避
For Each vsoPage In vsoDoc.Pages
ProcessShapes vsoPage.Shapes, badFonts
Next
‘ 結果の判定
If badFonts.Count > 0 Then
MsgBox “警告: 以下の埋め込み不可フォントを検知しました:” & vbCrLf & _
JoinCollection(badFonts), vbCritical
Else
MsgBox “フォントの整合性確認完了。PDF出力準備OK。”, vbInformation
End If
‘ 明示的な解放
Set vsoDoc = Nothing
End Sub
Private Sub ProcessShapes(shapes As Visio.Shapes, badFonts As Collection)
Dim s As Visio.Shape
Dim fontName As String
For Each s In shapes
‘ Char.Font プロパティは、VisioのCellオブジェクト経由で取得
‘ 埋め込み不可のフォントは多くの場合、特定のメタデータを持つ
fontName = s.Cells(“Char.Font”).ResultStr(“”)
If IsEmbeddedProhibited(fontName) Then
badFonts.Add fontName & ” (in Shape: ” & s.Name & “)”
End If
‘ 子シェイプの再帰的走査(グループ化されたシェイプの深部まで突く)
If s.Shapes.Count > 0 Then
ProcessShapes s.Shapes, badFonts
End If
Next
End Sub
‘ ここにフォントライセンスの判定ロジックを注入する
Private Function IsEmbeddedProhibited(fontName As String) As Boolean
‘ Windows API (GDI) を用いてフォントの属性を厳密に調査することも可能だが、
‘ まずはブラックリスト方式で十分なパフォーマンスが得られる
Select Case fontName
Case “UnregisteredFont1”, “RestrictedFont2”
IsEmbeddedProhibited = True
Case Else
IsEmbeddedProhibited = False
End Select
End Function
—
3. シニアエンジニアが踏むべき「極限の最適化」ポイント
上記のコードは氷山の一角だ。さらに高い次元を目指すなら、以下の三点をアーキテクチャに組み込め。
① Windows API `EnumFontFamiliesEx` による検証
VBAの`ResultStr`は、あくまで「Visioが認識している名前」を返すに過ぎない。もしシステムレベルのフォント属性まで精査したいなら、`User32.dll`の`EnumFontFamiliesEx`を呼び出し、フォントの`OUTLINETEXTMETRIC`構造体から`otmfsType`(フォント埋め込み権限フラグ)を取得せよ。これが真の「フォント監視」である。
② COMオブジェクトの生存期間(Life Cycle)管理
`For Each`ループ内で`ActiveDocument`や`ActivePage`を多用するのは悪手だ。VisioのCOMインターフェースは、呼び出し回数が増えるほど内部的なプロキシオブジェクトが生成され、メモリを食いつぶす。
ループの外で変数を固定し、最小限のプロパティアクセスに留めること。
③ システム間連携:JSON経由のメタデータ連携
このチェックロジックを、PDF出力を行うCI/CDパイプライン(あるいはVB.NET等の外部ツール)に組み込む場合、VBAから直接JSONを吐き出すのではなく、一度レジストリや一時ファイル経由で「チェック結果」を渡し、PDF化エンジン(Adobe Acrobat SDK等)へ引き渡すパイプラインを構築せよ。
—
結びに代えて
「動けば良い」というコードは、数年後の自分を殺す。VisioのPDF出力エラーは、その図面が生きている限り、いつか必ず再発する時限爆弾だ。
今回提示したロジックは、単なるエラー回避ではない。「システムが何を読み込み、何を変換し、何が許されないのか」という境界条件を定義する行為である。技術を掌握する者は、ツールに使われるのではなく、ツールを制圧する側であれ。
諸君のVisio環境が、常に完璧なドキュメントを出力し続けることを願う。
