こんにちは! Visio VBAの世界へようこそ。
マクロの記録ボタンを押して、生成されたコードを眺めるだけのステージはもう卒業です。今日からあなたを、Visioの深部を自在にコントロールする「真のエンジニア」へと引き上げましょう。
今回取り組むテーマは、現場で本当によくある悪夢、「VisioのPDF出力時のフォント埋め込みエラー」を、出力前にVBAで完全に事前ブロックする診断ロジックです。
「いざPDF化してクライアントに提出しようとしたら、文字化けを起こした」「特定のPCにしか入っていないフォントのせいで、PDFのエクスポートがサイレントに失敗する」。そんな絶望を味わったことはありませんか?
これを人力の目視チェックで防ぐのは不可能です。だからこそ、VBAの出番。出力の直前に、図面が抱える「フォントの爆弾」をコードで暴き出しましょう。
ここをクリアすれば、Visio VBAのオブジェクトモデルの本質が見えてきます。温かく、そして妥協のないプロの知見を授けますね。
—
なぜVisioのPDF出力はフォントでコケるのか?
Visioの図面(.vsdx)は、非常に自由度の高いキャンバスです。そのため、作成者のPCに入っているあらゆるローカルフォント(DynaFontや特殊なデザインフォント、あるいは古いTrueTypeフォントなど)が図形に紐づいてしまいます。
PDF/Aなどの厳格な規格や、異なる環境での閲覧を前提としたPDFを出力する際、Visioの内部エンジンは「フォントの埋め込み(Embedding)」を試みます。しかし、ライセンス上の制約(埋め込み禁止フラグ)があるフォントや、プリンタドライバが解釈できないフォントに当たると、出力がエラーで止まるか、無残に文字が抜け落ちるのです。
これを防ぐためには、「今、図面内のどこで、どんなフォントが使われているのか」をVBAで全走査し、危険なフォントをあらかじめ検知する必要があります。
—
Visio VBAにおけるフォント探索の「壁」
Visioでフォントを探索する際、初学者が最初にハマる罠があります。
それは、「テキストを持つ図形(Shape)だけでなく、スタイル(Style)、マスター(Master)、ページ設定(Page)など、あらゆる階層にフォントが潜んでいる」という事実です。
特に厄介なのが、マスターシェイプ(ステンシルからドラッグ&ドロップした図形の元ネタ)や、グループ化された子図形です。これらを再帰的(リスクルージブ)に舐め尽くすアルゴリズムを書く必要があります。
—
【実践】PDF出力前フォント診断プログラム
それでは、開発の現場でそのままコピペして使える、極上の実用コードを公開します。
VBAエディタ(`Alt + F11`)を開き、標準モジュールに貼り付けてください。
Option Explicit
‘ ==============================================================================
‘ 処理名 : 健全なPDF出力を担保するフォント事前診断エンジン
‘ 概要 : アクティブドキュメント内の全図形を走査し、PDF化の障害になり得る
‘ 未許可フォントや怪しいフォントを検知して警告を発する
‘ ==============================================================================
Public Sub PreflightFontCheckForPDF()
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape
Dim targetFontName As String
Dim fontCol As Collection
Dim i As Long
Dim hasError As Boolean
‘ エラーになりやすい「危険なフォント名」のブラックリスト(例:環境依存の特殊フォント等)
‘ ※社内規定やプロジェクトに応じてカスタマイズしてください
Dim dangerFonts As Variant
dangerFonts = Array(“HGS創英角ポップ体”, “HGP創英角ゴシックUB”, “MS明朝-Old”)
Set fontCol = New Collection
hasError = False
‘ 1. ドキュメント内の全ページ・全図形を走査してフォント名を収集
For Each vsoPage In ActiveDocument.Pages
‘ バックグラウンドページはスキップする場合の判定(必要に応じて)
If vsoPage.Background = False Then
For Each vsoShape in vsoPage.Shapes
Call ScanShapesRecursive(vsoShape, fontCol)
Next vsoShape
End If
Next vsoPage
‘ 2. 収集したフォントの検証
If fontCol.Count = 0 Then
MsgBox “テキストを持つ図形が見つかりませんでした。”, vbInformation, “事前診断完了”
Exit Sub
End If
Dim msg As String
msg = “【PDF出力前フォント診断結果】” & vbCrLf & “以下のフォントが使用されています:” & vbCrLf
‘ コレクションから一意のフォントリストを作成してチェック
Dim fontName As Variant
For Each fontName In fontCol
msg = msg & “・ ” & fontName & vbCrLf
‘ ブラックリストとの照合
For i = LBound(dangerFonts) To UBound(dangerFonts)
If CStr(fontName) = CStr(dangerFonts(i)) Then
hasError = True
msg = msg & ” ⇒ 【警告】このフォントはPDF埋め込みエラーを引き起こす可能性があります!” & vbCrLf
End If
Next i
Next fontName
‘ 3. 診断結果に基づく分岐
If hasError Then
msg = msg & vbCrLf & “【中止】安全なPDFを作成するため、該当フォントを標準的なもの(メイリオや游ゴシック等)に変更してください。”
MsgBox msg, vbCritical, “PDF出力前診断:エラー検出”
Else
msg = msg & vbCrLf & “【合格】PDF出力に適さない危険なフォントは検出されませんでした。エクスポートを実行します。”
‘ 診断がクリアできたらそのままPDF出力へ繋げる(例)
Dim pdfPath As String
pdfPath = ActiveDocument.Path & “Output_Checked.pdf”
‘ ※実際のPDF保存処理
‘ ActiveDocument.ExportAsFixedFormat visFixedFormatPDF, pdfPath, visRasterizeNone, visPrintAll
MsgBox msg, vbInformation, “PDF出力前診断:合格”
End If
End Sub
‘ ——————————————————————————
‘ サブルーチン : 図形を再帰的に走査する(グループ化やコンポーネント対策)
‘ ——————————————————————————
Private Sub ScanShapesRecursive(ByVal shp As Visio.Shape, ByRef col As Collection)
On Error GoTo ErrorHandler
‘ テキストが含まれている、あるいは文字フォントプロパティを持っている場合
If shp.Characters.Text <> “” Then
Dim fName As String
‘ 文字列全体のフォント名を取得(セルインデックスから取得する方法もあるが簡易的にCellから)
‘ ※VisioのCellsU(“Char.Font”)はフォントのインデックスを返すため、DocumentのFontsコレクションから名前を引く
Dim fontIndex As Integer
fontIndex = shp.CellsU(“Char.Font”).ResultIU
fName = ActiveDocument.Fonts(fontIndex).Name
‘ コレクションへの重複登録を防ぎながら追加
If Not IsInCollection(col, fName) Then
col.Add fName, fName
End If
End If
‘ もし図形がグループ(Group)であれば、その中の子図形(Shapes)を再帰的に掘り下げる
If shp.Type = visTypeGroup Then
Dim subShp As Visio.Shape
For Each subShp In shp.Shapes
Call ScanShapesRecursive(subShp, col)
Next subShp
End If
ErrorHandler:
‘ 個別図形の予期せぬプロパティエラーはスルーして処理を継続(堅牢性の確保)
Resume Next
End Sub
‘ ——————————————————————————
‘ 補助関数 : コレクションにすでに同じキーが存在するか判定する
‘ ——————————————————————————
Private Function IsInCollection(ByRef col As Collection, ByVal key As String) As Boolean
On Error Resume Next
Dim var As Variant
var = col(key)
If Err.Number = 0 Then
IsInCollection = True
Else
IsInCollection = False
End If
Err.Clear
End Function
—
コードの核心:ここがプロの技
1. `visTypeGroup` に対する再帰呼び出し
Visioで厄介なのは、ユーザーが図形をグループ化しているケースです。親図形だけを見ていても、子図形の中に眠る爆弾フォントは見つかりません。`ScanShapesRecursive` プロシージャのように、グループを見つけたら自らを再度呼び出す(再帰)構造にすることで、どんなに入れ子構造になった複雑な図面でも取りこぼしがなくなります。
2. `Char.Font` と `ActiveDocument.Fonts` の連携
Visioの図形が保持しているフォント情報は、名前そのものではなく「インデックス番号(数値)」です。これを人間が読めるフォント名(例:「Meiryo」など)に変換するために、`ActiveDocument.Fonts(fontIndex).Name` という名前解決のひと手間を入れています。ここを知っているかどうかが、初学者と中上級者の分水嶺です。
3. コレクションのキーを活用した「重複排除」
ひとつの図面の中で、同じフォントが何千回も使われていることはよくあります。それをそのまま配列やリストに入れると、診断メッセージが文字まみれになってしまいます。VBAの `Collection` オブジェクトの「キーが重複するとエラーになる」特性を逆手に取り、一意のフォントリストを美しく生成しています。
—
ここをクリアすれば、Visio VBAの基本はバッチリですよ!
このコードをあなたのVisio環境に組み込めば、単なる「お絵かきソフト」としてのVisioではなく、「データと品質を担保された図面管理システム」へと生まれ変わらせることができます。
エラーが出てから慌てて修正するのではなく、「エラーを未然に防ぐガードレール」をコードで構築する。これこそが、業務自動化エンジニアの醍醐味です。
ぜひ、実際の業務図面で試してみてください。あなたのVisioライフが、より知的でストレスフリーなものになることを確信しています。それでは、次のステップでお会いしましょう!
