CDRマルチページ抽出の極致:オブジェクト・ライフサイクルを制御し、カタログデータを解体する
ベクターグラフィックスの自動化において、最も泥臭く、かつエンジニアの腕が試されるのは「巨大なマルチページ・ドキュメントの解体」である。
数百ページに及ぶ製品カタログ、あるいは数千のパーツが並ぶ図面データ。これらを「特定の条件」に基づいて切り分け、別個のファイルとして独立させる。単なるコピー&ペーストの自動化だと思っているなら、君は早々にCorelDRAWのメモリ消費と、COMオブジェクトの深い沼に沈むことになるだろう。
本稿では、CorelDRAW VBAを用いた「動的なページ抽出と独立保存」の極限の知見を共有する。
—
1. ページ操作における「破壊的変更」の罠
多くの初心者は、ループ内で `Page.Delete` や `Document.SaveAs` を安易に繰り返す。しかし、CorelDRAWのオブジェクトモデルにおいて、ページの削除や移動はインデックスの動的なシフトを引き起こす。また、巨大なドキュメントを開いたまま別名保存を繰り返せば、元ファイルのファイルポインタとメモリ空間は確実に汚染される。
アーキテクトの定石:
1. 非破壊抽出: 元ドキュメントは「読み取り専用」として扱う。
2. インデックスの事前解決: 抽出対象のページ番号を、処理の前に配列またはコレクションに確定させる。
3. ライフサイクルの分離: 「抽出元ドキュメント」と「書き出し用ドキュメント」のインスタンスを明確に管理し、処理ごとに明示的に破棄する。
—
2. パフォーマンスを極める:Windows APIと最適化フラグ
CorelDRAWのVBA実行速度を決定づけるのは、描画エンジンの更新停止である。`Application.Optimization` を `True` に設定するのは基本だが、シニアレベルでは、さらに一歩踏み込む。
‘ 画面更新の強制停止とイベントの抑制
Application.Optimization = True
Application.EventsEnabled = False
Application.ActiveDocument.BeginCommandGroup “Page Extraction”
さらに、ファイルパスの妥当性チェックやディレクトリ作成において、VBA標準の `Dir` 関数はネットワークパスで不安定になる。我々は Windows API (`shlwapi.dll`) を呼び出し、システムレベルでの堅牢性を確保する。
—
3. 実装:キーワード駆動型ページ抽出エンジン
以下のコードは、ページ名または特定のレイヤー名に「キーワード」が含まれるページのみを抽出し、独立したCDRとして保存するプロトタイプである。
Option Explicit
‘ Windows API: パス存在確認の高速化
Private Declare PtrSafe Function PathFileExistsW Lib “shlwapi.dll” (ByVal pszPath As LongPtr) As Long
”’
”’
Public Sub ExtractPagesByLogic()
Dim srcDoc As Document: Set srcDoc = ActiveDocument
If srcDoc Is Nothing Then Exit Sub
Dim targetKeyword As String
targetKeyword = “RELEASE” ‘ 抽出条件:ページ名またはレイヤー名に含まれる文字列
Dim exportPath As String
exportPath = srcDoc.FilePath & “Extracted_” & Format(Now, “yyyymmdd_hhnnss”) & “\”
‘ ディレクトリ作成(API等で事前に存在確認を推奨)
If Dir(exportPath, vbDirectory) = “” Then MkDir exportPath
‘ パフォーマンス最適化
On Error GoTo ErrorHandler
Optimization = True
EventsEnabled = False
Dim pg As Page
Dim targetPages As New Collection
Dim i As Integer
‘ Step 1: 抽出対象のインデックスを確定させる(逆順ループの必要なし)
For i = 1 To srcDoc.Pages.Count
Set pg = srcDoc.Pages(i)
If IsTargetPage(pg, targetKeyword) Then
targetPages.Add i
End If
Next i
‘ Step 2: 抽出と保存の実行
Dim pageIdx As Variant
Dim newDoc As Document
For Each pageIdx In targetPages
‘ 新規ドキュメントを一時的に作成
‘ 元ドキュメントと同じサイズ・設定を継承させる
Set pg = srcDoc.Pages(pageIdx)
Set newDoc = CreateNewDocumentFromPage(pg)
‘ ページ内容のコピー(レイヤー構造を維持したままコピー)
pg.Shapes.All.Copy
newDoc.ActivePage.Paste
‘ 独立したファイルとして保存
Dim fileName As String
fileName = exportPath & “Page_” & pageIdx & “_” & pg.Name & “.cdr”
‘ 保存オプションの設定(不要なメタデータを削り軽量化)
Dim saveOpt As New StructSaveAsOptions
With saveOpt
.Filter = cdrCDR
.IncludeICCProfile = False
.ThumbnailSize = cdr10KColorThumbnail
.Version = cdrCurrentVersion
End With
newDoc.SaveAs fileName, saveOpt
‘ 重要:ドキュメントを閉じ、メモリを解放する
newDoc.Close
Set newDoc = Nothing
Next pageIdx
MsgBox “抽出完了: ” & targetPages.Count & ” ページを処理しました。”, vbInformation
CleanExit:
Optimization = False
EventsEnabled = True
Application.Refresh
Exit Sub
ErrorHandler:
MsgBox “致命的エラー: ” & Err.Description, vbCritical
Resume CleanExit
End Sub
”’
”’
Private Function IsTargetPage(pg As Page, keyword As String) As Boolean
If InStr(1, pg.Name, keyword, vbTextCompare) > 0 Then
IsTargetPage = True
Exit Function
End If
Dim lyr As Layer
For Each lyr In pg.Layers
If InStr(1, lyr.Name, keyword, vbTextCompare) > 0 Then
IsTargetPage = True
Exit Function
End If
Next lyr
IsTargetPage = False
End Function
”’
”’
Private Function CreateNewDocumentFromPage(srcPage As Page) As Document
Dim d As Document
Set d = CreateDocument()
d.Unit = ActiveDocument.Unit
d.MasterPage.SetSize srcPage.SizeWidth, srcPage.SizeHeight
d.MasterPage.Orientation = srcPage.Orientation
Set CreateNewDocumentFromPage = d
End Function
—
4. 現場の知見:シニアエンジニアが配慮すべき点
オブジェクトの明示的破棄とガベージコレクション
VBAは参照カウント方式のメモリ管理を行う。`newDoc.Close` を呼んだ後、必ず `Set newDoc = Nothing` を実行すること。これを怠ると、バックグラウンドで `CorelDRW.exe` のプロセスがゴースト化し、最終的にシステム全体のメモリ不足を招く。特にループ内でのドキュメント生成は、最もリークしやすいポイントだ。
クリップボードの汚染問題
上記コードでは `pg.Shapes.All.Copy` を使用している。これは極めて高速だが、クリップボードを占有するため、ユーザーの他作業を阻害する。真にサイレントな処理を求めるなら、`ShapeRange.MoveToLayer` 等を用いて一時ドキュメントへ要素を移動させる手法もあるが、元ファイルを破壊しないためには、やはり「コピー」が最も安全な選択となる。
レガシー環境への配慮
CorelDRAW X8以前の環境では、`StructSaveAsOptions` のプロパティ名や列挙型が微妙に異なる場合がある。社内ツールとして配布する場合は、参照設定(Late Binding)への切り替えも検討すべきだ。`CreateObject(“CorelDRAW.Application”)` を利用することで、バージョン混在環境でも安定した動作を保証できる。
—
結びに代えて
ベクターデータの自動化は、単なる事務処理の効率化ではない。それは「情報の解像度」を維持したまま、大規模なデータを再構成するアーキテクチャの構築である。
今回紹介した動的抽出のロジックは、そのままPDF変換エンジンや、Web入稿システムの前処理へと応用が可能だ。コードの背後にある「オブジェクトの生存期間」を常に意識せよ。それが、付け焼き刃のスクリプト作者と、真のオートメーション・アーキテクトを分かつ境界線である。
