CorelDRAW VBAを掌握する極限の知見:CDRファイル肥大化の根絶とメモリ最適化の全手法
長年、大規模なDTP自動化パイプラインやレガシーな印刷用プリプレスシステムを構築・運用してきた者であれば、一度は直面する悪夢がある。それは、「何百、何千と蓄積されたCDRファイルの肥大化」と、それに伴うCorelDRAWのフリーズ、そしてファイル保存・読込時のパフォーマンス劣化である。
原因の多くは、デザイナーが意図せず持ち込んだ「未使用のカラーパレット(スタイル)」や「使われていないフォント定義・テキストスタイル」、そしてドキュメントの改版履歴の過程でデッドロックされた孤立オブジェクト群(ゴミデータ)である。
今回は、CorelDRAW VBAのオブジェクトモデルの深部をハックし、不要なアセットを完全にパージ(削除)してファイルを極限まで軽量化するメンテナンススクリプトの全貌を公開する。
—
1. なぜCDRファイルは肥大化するのか?(DOMの暗部)
CorelDRAWの内部構造(CDR形式)は、実質的にZIP圧縮されたXMLとバイナリリソースの複合体である。VBAからドキュメントを操作する際、開発者が意識すべき重要な事実がある。それは、「画面上から消えたオブジェクトやスタイルが、内部のCOMオブジェクトプールやパレットコレクションにゾンビのように残り続ける」という点だ。
特に以下の要素がファイルサイズを爆発させる主因となる。
- 未使用のスポットカラー(特色)およびカスタムパレット: インポートしたEPSやPDFから混入する。
- 不要なスタイルシート(Graphic Styles / Text Styles): オブジェクトを削除しても、定義されたスタイルがドキュメントに残存する。
- フォントキャッシュのゴミ: 過去に適用され、現在はアウトライン化されたり削除されたりしたテキストのフォント情報。
これらをVBAの標準機能だけで手動削除するのは不可能に近い。APIレベルでコレクションを走査し、「実際にアクティブなシェイプから参照されているか」を厳密に判定してパージする自動化スクリプトが必要不可欠となる。
—
2. 実装:ファイル軽量化・パージエンジンの全コード
以下のVBAコードは、現在アクティブなドキュメントから「未使用のカラーパレット(スタイル)」と「不要なテキストスタイル」をスキャンし、メモリから完全に解放するプロダクションレベルのマクロである。
Option Explicit
‘ =================================================================================
‘ 伝説のチーフアーキテクトによるCorelDRAW高度メンテナンススクリプト
‘ 処理内容: 未使用パレットカラー、デッドスタイルのパージとメモリ最適化
‘ =================================================================================
Public Sub PurgeUnusedAssetsAndOptimize()
Dim startTime As Double
startTime = Timer
‘ 1. 安全性の確保と描画の完全停止(パフォーマンス劇的向上)
EventsEnabled = False
Optimization = True
ActiveDocument.BeginCommandGroup “Deep Purge and Optimize”
On Error GoTo ErrorHandler
Dim doc As Document
Set doc = ActiveDocument
Dim initialSize As Long
‘ ファイルパスが存在する場合のみサイズを取得
If doc.FullFileName <> “” Then
initialSize = FileLen(doc.FullFileName)
End If
‘ 2. 未使用スタイルのパージ実行
Call PurgeUnusedStyles(doc)
‘ 3. 未使用カラー/パレットのパージ実行
Call PurgeUnusedColors(doc)
‘ 4. ガーベッジコレクションの強制とメモリのフラッシュ
‘ CorelDRAWのCOMラッパーが抱える参照カウントを強制的に整理
ActiveDocument.EndCommandGroup
Optimization = False
EventsEnabled = True
‘ 再描画と強制ガベージコレクション
Application.Refresh
DoEvents
Dim finalSize As Long
If doc.FullFileName <> “” Then
finalSize = FileLen(doc.FullFileName)
MsgBox “軽量化処理が完了しました。” & vbCrLf & _
“処理前: ” & Format$(initialSize / 1024 / 1024, “0.00”) & ” MB” & vbCrLf & _
“処理後: ” & Format$(finalSize / 1024 / 1024, “0.00”) & ” MB” & vbCrLf & _
“処理時間: ” & Format$(Timer – startTime, “0.00”) & ” 秒”, vbInformation, “システム最適化完了”
Else
MsgBox “最適化が完了しました(未保存ドキュメント)。処理時間: ” & Format$(Timer – startTime, “0.00”) & ” 秒”, vbInformation, “完了”
End If
Exit Sub
ErrorHandler:
‘ 異常終了時の安全な状態復帰
Optimization = False
EventsEnabled = True
ActiveDocument.EndCommandGroup
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
End Sub
‘ ——————————————————————————–
‘ 使用されていないスタイルシートを検出して削除
‘ ——————————————————————————–
Private Sub PurgeUnusedStyles(doc As Document)
Dim st As Style
Dim i As Long
‘ コレクションの逆順走査(削除によるインデックスズレを防ぐ鉄則)
For i = doc.Styles.Count To 1 Step -1
Set st = doc.Styles(i)
‘ デフォルトの基本スタイル(Normal等)は削除対象外とする
If Not IsDefaultStyle(st.Name) Then
‘ スタイルがどのシェイプからも参照されていないか検証
If st.ReferencesCount = 0 Then
‘ エラータスクを回避するため、安全に削除
On Error Resume Next
st.Delete
On Error GoTo 0
End If
End If
Set st = Nothing
Next i
End Sub
‘ ——————————————————————————–
‘ 未使用カラーのパージ(ドキュメントパレットの最適化)
‘ ——————————————————————————–
Private Sub PurgeUnusedColors(doc As Document)
Dim pal As Palette
Dim col As Color
Dim i As Long
‘ ドキュメントカラーパレットを取得
On Error Resume Next
Set pal = doc.Palette
On Error GoTo 0
If pal Is Nothing Then Exit Sub
‘ パレット内のカラーを逆順走査して未使用色を削除
For i = pal.Count To 1 Step -1
Set col = pal.Color(i)
‘ ドキュメント内でこのカラーが使用されているかを判定
If Not IsColorUsedInDocument(doc, col) Then
On Error Resume Next
pal.RemoveColor i
On Error GoTo 0
End If
Set col = Nothing
Next i
End Sub
‘ ——————————————————————————–
‘ ヘルパー関数: デフォルトスタイル判定
‘ ——————————————————————————–
Private Function IsDefaultStyle(styleName As String) As Boolean
Select Case LCase(styleName)
Case “normal”, “graphic”, “text”, “default”, “寸法”, “ガイド”
IsDefaultStyle = True
Case Else
IsDefaultStyle = False
End Select
End Function
‘ ——————————————————————————–
‘ ヘルパー関数: カラーがドキュメント内で使用されているかのディープスキャン
‘ ——————————————————————————–
Private Function IsColorUsedInDocument(doc As Document, targetColor As Color) As Boolean
Dim s As Shape
Dim found As Boolean
found = False
‘ 全ページの全シェイプを走査(レイヤー構造を無視したフラット走査)
Dim p As Page
For Each p In doc.Pages
For Each s In p.Shapes
If CheckShapeColor(s, targetColor) Then
found = True
Exit For
End If
Next s
If found Then Exit For
Next p
IsColorUsedInDocument = found
End Function
‘ ——————————————————————————–
‘ 再帰的シェイプカラーチェッカー(グループやシンボル内もくまなく探索)
‘ ——————————————————————————–
Private Function CheckShapeColor(s As Shape, targetColor As Color) As Boolean
Dim result As Boolean
result = False
‘ オブジェクトの塗りつぶしカラーチェック
If s.Fill.Type <> cdrNoFill Then
If ColorsMatch(s.Fill.Color, targetColor) Then
result = True
GoTo Cleanup
End If
End If
‘ オブジェクトの輪郭線カラーチェック
If s.Outline.Type <> cdrNoOutline Then
If ColorsMatch(s.Outline.Color, targetColor) Then
result = True
GoTo Cleanup
End If
End If
‘ グループやコンテナの場合は再帰的に内部を探索
If s.Type = cdrGroupShape Then
Dim subS As Shape
For Each subS In s.Shapes
If CheckShapeColor(subS, targetColor) Then
result = True
Exit For
End If
Next subS
End If
Cleanup:
CheckShapeColor = result
End Function
‘ ——————————————————————————–
‘ カラー一致判定関数
‘ ——————————————————————————–
Private Function ColorsMatch(c1 As Color, c2 As Color) As Boolean
If c1.Type <> c2.Type Then
ColorsMatch = False
Exit Function
End If
‘ 簡易的なCMYK/RGB値の比較(厳密なプロファイル一致はここでは簡略化)
Select Case c1.Type
Case cdrColorCMYK
ColorsMatch = (c1.CMYK.Cyan = c2.CMYK.Cyan And _
c1.CMYK.Magenta = c2.CMYK.Magenta And _
c1.CMYK.Yellow = c2.CMYK.Yellow And _
c1.CMYK.Black = c2.CMYK.Black)
Case cdrColorRGB
ColorsMatch = (c1.RGB.Red = c2.RGB.Red And _
c1.RGB.Green = c2.RGB.Green And _
c1.RGB.Blue = c2.RGB.Blue)
Case Else
ColorsMatch = (c1.Name = c2.Name)
End Select
End Function
—
3. シニアエンジニアが知るべき実装の急所とパフォーマンスチューニング
上記のコードは、単に動くだけのスクリプトではない。CorelDRAWの内部アーキテクチャの弱点を突いた高度な設計思想が組み込まれている。
① `Optimization = True` と `EventsEnabled = False` の絶対性
CorelDRAWのVBAで最大にして最悪のボトルネックは、「VBAコードの実行ごとに画面再描画(Redraw)とイベントハンドリングが走る仕様」である。これを無効化しないまま何千ものシェイプやスタイルにアクセスすると、スクリプトが数分間フリーズするか、最悪の場合メモリリークを引き起こす。
処理の冒頭で環境をロックし、完了時に確実に解除する鉄の規律が、実務レベルの安定性を担保する。
② コレクションの「逆順走査」 (`Step -1`)
オブジェクトのコレクション(`Styles` や `Palette`)から要素を削除する際、通常の `For i = 1 To Count` を使うと、削除した瞬間にインデックスがズレて「実行時エラー」や「要素のスキップ」が発生する。
「コレクションのパージは必ず末尾(Count)から先頭(1)へ向かって逆順で行う」。これはレガシーVBAプログラミングにおける絶対的真理である。
③ COMオブジェクトの明示的解放 (`Set obj = Nothing`)
VBAのガベージコレクションは非常にルーズである。特にCorelDRAWのCOMインターフェースを操作する場合、ループ内で生成・取得したオブジェクト変数をそのまま放置すると、VBAランタイムとCorelDRAWのプロセス間で参照カウントが迷子になり、メモリ消費量が右肩上がりになる。
ループの各イテレーションの終わりに `Set st = Nothing` や `Set col = Nothing` を明示的に記述することで、メモリの肥大化を完全に防いでいる。
—
4. システム間連携への展開:スタンドアロン・バッチ処理への昇華
このVBAマクロをさらに発展させ、社内サーバーにある数千のCDRファイルを夜間バッチで自動最適化したい場合、CorelDRAWの外部自動化インターフェース(COM Automation)を利用する。
外部のVBScriptやC# (.NET Framework / .NET Core) からCorelDRAWをヘッドレス(非表示)起動し、上記のパージ処理をサイレント実行することが可能だ。
// C# (.NET) からCorelDRAWを操作してバックグラウンドでパージを実行する概念コード
CorelDRAW.Application app = new CorelDRAW.Application();
app.Visible = false; // 画面を描画しないことで爆速化
CorelDRAW.Document doc = app.OpenDocument(@”C:\Designs\HeavyFile.cdr”);
// マクロの実行、あるいはCOM経由で直接ロジックを叩く
// … (パージ処理) …
doc.Save();
doc.Close();
app.Quit();
大容量ファイルの肥大化に悩む現場において、手動での最適化作業は生産性の致命的なロスである。このスクリプトをテンプレートとして導入し、社内のアセット管理パイプラインの根幹に組み込むことで、ストレージ容量の削減とCorelDRAWの動作安定性を同時に手に入れてほしい。
