CorelDRAW VBA:バラバラのテキストフレームを「正しい読順」で結合する極限のアルゴリズム
CADや古のDTPデータからインポートした瞬間に絶望したことはないか? 数百ものテキストフレームが断片化し、読み順もバラバラ。これを手作業で整列させるのは、もはや「拷問」に近い。
今回は、CorelDRAWのオブジェクトモデルを深く理解したエンジニアが、「座標ベースのソート」によるテキスト統合アルゴリズムを授ける。単に結合するだけではない。実務で耐えうる堅牢性と、拡張性を考慮した設計だ。
—
1. なぜ単純なループではいけないのか?
多くの初学者は、`ActivePage.Shapes` をそのままループさせて結合しようとする。だが、これは罠だ。
CorelDRAWの内部構造において、オブジェクトのインデックスは「作成順(または重なり順)」に依存しており、「視覚的な読順」とは一切無関係である。
業務自動化において重要なのは、以下の2点だ。
1. 空間インデックスの構築: 座標(Y軸→X軸)に基づいた再マッピング。
2. メモリ管理: 大量オブジェクトの処理中にVBAをクラッシュさせないための、適切な参照解放と最適化。
—
2. 実装:読順判定アルゴリズム
以下のコードは、選択された複数のテキストフレームを「上から順、かつ同じ行なら左から順」にソートし、結合する。
Option Explicit
‘ ———————————————————
‘ 目的: 選択されたテキストフレームを読順(上→下、左→右)で結合
‘ ———————————————————
Public Sub RebuildTextFramesSequentially()
Dim s As Shape, sr As ShapeRange
Dim i As Long, j As Long
Dim tempShape As Shape
Dim combinedText As String
‘ 選択範囲がない場合のガード節
If ActiveSelection.Shapes.Count < 2 Then
MsgBox "結合対象のテキストフレームを2つ以上選択してください。"
Exit Sub
End If
' 1. ShapeRangeを配列に展開して座標ソート
' 本来はクイックソートを実装すべきだが、簡易的にバブルソートで解説
' ※数百個超える場合はコレクションとクイックソートを推奨
Dim shapes() As Shape
ReDim shapes(1 To ActiveSelection.Shapes.Count)
For i = 1 To ActiveSelection.Shapes.Count
Set shapes(i) = ActiveSelection.Shapes(i)
Next i
' 座標ソートアルゴリズム
' Y座標が大きい順、同じならX座標が小さい順
For i = 1 To UBound(shapes) - 1
For j = i + 1 To UBound(shapes)
If (shapes(i).Top < shapes(j).Top) Or _
(Abs(shapes(i).Top - shapes(j).Top) < 0.1 And shapes(i).Left > shapes(j).Left) Then
Set tempShape = shapes(i)
Set shapes(i) = shapes(j)
Set shapes(j) = tempShape
End If
Next j
Next i
‘ 2. テキストの抽出と統合
combinedText = “”
For i = 1 To UBound(shapes)
If shapes(i).Type = cdrTextShape Then
combinedText = combinedText & shapes(i).Text.Story & vbCrLf
‘ 不要になったフレームを削除(バックアップを取る場合はコメントアウト)
shapes(i).Delete
End If
Next i
‘ 3. 新規フレームの生成
Dim newText As Shape
Set newText = ActiveLayer.CreateParagraphText(0, 0, 100, 100, combinedText)
MsgBox “結合完了。全” & UBound(shapes) & “オブジェクトを統合しました。”
End Sub
—
3. プロダクション環境での「極限の知見」
座標の「ゆらぎ」を許容せよ
CADデータは完璧な水平・垂直ではないことが多い。`shapes(i).Top` を直接比較すると、0.001mmの差で順序が逆転する。
比較処理には必ず `Abs(A – B) < 許容値` という「浮動小数点比較」のイディオムを組み込むこと。これがバグを生まないエンジニアの矜持だ。
Undo/Redoの重要性
本スクリプトでは `shapes(i).Delete` を行っている。業務で運用する場合、予期せぬ事故を防ぐため、処理全体を `Optimization` で囲み、最後に `Undo` が1回で済むように設計する。
‘ 処理の高速化とUndoの最適化
Application.Optimization = True
‘ … 処理本体 …
Application.Optimization = False
ActiveWindow.Refresh
データベース連携のヒント
もしこのスクリプトを「多言語翻訳ワークフロー」の一部に組み込むなら、テキストを結合する際に、各フレームの元座標をCSVやJSONとして外部出力しておくことを強く勧める。翻訳後に再配置(リフロー)が必要になった際、この「座標マップ」が神のような威力を発揮するからだ。
—
最後に:自動化の真髄
「コピペで動くコード」を作るのは簡単だ。しかし、真のエンジニアは「このコードが数年後、別のデータソースで実行された時にどう振る舞うか」を想像する。
今回提供した座標ソートアルゴリズムは、UI上の並びを論理構造へ変換する極めて強力な武器になるはずだ。CorelDRAWのAPIは古いが、その分、安定している。限界まで使い倒し、繰り返される単純作業を過去のものにしてほしい。
健闘を祈る。
