DXFファイルでは、LINEやCIRCLEのような標準図形だけでなく、追加アプリケーションが定義した独自エンティティや非図形オブジェクトを扱うことがあります。
そのクラス情報を記録するのがCLASSESセクションです。
CLASSESは図形の座標や形状を保存する場所ではありません。独自クラスのDXF名、C++クラス名、作成元アプリケーション、アプリケーションがない環境で許可する操作などを登録する場所です。
この記事では、CLASSレコードの識別情報、proxy capabilities flags、未知クラスを壊さない解析方法を整理します。
CLASSESセクションの役割
AutodeskのDXF仕様では、CLASSESセクションは、BLOCKS、ENTITIES、OBJECTSの各セクションにインスタンスが現れるアプリケーション定義クラスの情報を保持します。
基本的な関係は次のとおりです。
CLASSES
CLASSレコード
├── DXFレコード名
├── C++クラス名
├── アプリケーション名
└── プロキシ操作フラグ
ENTITIES / BLOCKS / OBJECTS
└── そのクラスのインスタンス
独自CADが標準DXFにはない図形を保存した場合、図形本体はENTITIESなどに現れ、登録情報はCLASSESに記録されます。ただし、独自オブジェクトの完全な処理ロジックが埋め込まれるわけではありません。
セクション全体の構造
CLASSESセクションは、通常のDXFセクションと同じくSECTIONとENDSECで囲まれます。
0
SECTION
2
CLASSES
0
CLASS
1
MY_CUSTOM_ENTITY
2
MyCustomEntity
3
MY_CUSTOM_APP
90
131
91
2
280
0
281
1
0
ENDSEC
コード0と値CLASSの組が1件のクラスレコードの開始です。次のコード0、またはENDSECまでがそのレコードに属します。
CLASSは描画エンティティではなく、クラス登録用のメタデータです。
CLASSレコードの主要グループコード
Autodesk仕様で定義される主要コードは次のとおりです。
| コード | 意味 |
|---|---|
| 0 | レコード種類CLASS |
| 1 | クラスのDXFレコード名 |
| 2 | C++クラス名 |
| 3 | アプリケーション名 |
| 90 | プロキシ機能フラグ |
| 91 | カスタムクラスのインスタンス数 |
| 280 | was-a-proxyフラグ |
| 281 | is-an-entityフラグ |
Autodeskは各フィールドを必須としています。欠損値を推測で補完せず、元データを保持したまま不完全なレコードとして報告します。
コード1・2・3でクラスを識別する
コード1は、DXF上でクラスを識別するレコード名です。
1
MY_CUSTOM_ENTITY
独自エンティティの実体では、コード0にこのDXF名が現れることがあります。
コード2は、ソフトウェア側のC++クラス名です。
2
MyCustomEntity
ObjectARXでもCLASS_NAMEとDXF_NAMEは別の引数であり、両者は同じ文字列である必要がありません。
| 値 | 主な用途 |
|---|---|
| DXFレコード名 | DXFファイル内のレコード識別 |
| C++クラス名 | 実装クラスとの結合・識別 |
コード3には、そのクラスを定義したアプリケーション名が入ります。
3
MY_CUSTOM_APP
クラス定義がロードされていない場合、この名称は警告情報に使われます。単純な実行ファイル名とは限らないため原文を保持します。
仕様上、コード1は一意です。一方、ezdxfは、実在ファイルで同じDXF名に異なるC++名が対応した例を報告しています。読み取り側ではコード1だけをキーにして上書きせず、コード1・2の組と順序付きレコードを保持すると安全です。
コード90はプロキシ機能フラグ
クラスを定義したアプリケーションがない環境では、独自オブジェクトがプロキシエンティティまたはプロキシオブジェクトとして扱われる場合があります。
コード90は、そのプロキシに許可する操作をビットの組み合わせで表します。
| 値 | 許可される操作 |
|---|---|
| 1 | 削除 |
| 2 | 変換 |
| 4 | 色変更 |
| 8 | レイヤー変更 |
| 16 | 線種変更 |
| 32 | 線種尺度変更 |
| 64 | 表示状態変更 |
| 128 | クローン |
| 256 | 線の太さ変更 |
| 512 | 印刷スタイル名変更 |
| 1024 | プロキシ警告ダイアログを無効化 |
| 32768 | R13形式プロキシ |
複数の操作を許可する場合は、各ビットの論理和として保存されます。
先ほどの例にある131は、
131 = 1 + 2 + 128
なので、削除、変換、クローンを許可する組み合わせです。
コード90を単なる列挙値として131専用の分岐へ入れるのではなく、各ビットを個別に判定します。また、将来または他製品固有の未知ビットを捨てないよう、元の整数も保存します。
コード91はインスタンス数
コード91は、カスタムクラスのインスタンス数です。
91
2
コード91だけを根拠に読み取り回数を決めず、各セクションを境界に従って解析し、実際の検出数と照合します。差があれば、宣言数、検出数、検索対象、使用した識別子を診断情報として残します。
コード280はwas-a-proxyフラグ
コード280は、DXFが作成された時点でクラスがロードされていなかったかを示します。
| 値 | 意味 |
|---|---|
| 0 | クラスがロードされていた |
| 1 | クラスがロードされておらず、プロキシだった |
コード90は許可操作、コード280は保存時の状態です。同じproxy真偽値へまとめると情報が失われます。
コード281はentityかobjectかを示す
コード281は、クラスのインスタンスが図形エンティティ側に存在できるかを示します。
| 値 | 主な配置先 |
|---|---|
| 1 | BLOCKSまたはENTITIES |
| 0 | OBJECTSのみ |
値が1ならAcDbEntity派生、0ならOBJECTS側の非図形オブジェクトです。ただし、1でも独自実装やプロキシグラフィックスがなければ形状を完全に復元できない場合があります。
CLASSレコードには通常ハンドルがない
ezdxfの内部資料では、CLASSはハンドルを持たず、エンティティデータベースにも格納されません。全レコードへコード5を要求せず、ハンドル索引とは別のクラス登録一覧で管理します。
PythonでCLASSレコードを解析する
順序付きタグ列からCLASSレコードを抽出し、コード90のビットを解析する例です。
from dataclasses import dataclass
from typing import Any
Tag = tuple[int, Any]
PROXY_CAPABILITIES = {
1: "erase",
2: "transform",
4: "color_change",
8: "layer_change",
16: "linetype_change",
32: "linetype_scale_change",
64: "visibility_change",
128: "clone",
256: "lineweight_change",
512: "plot_style_change",
1024: "disable_proxy_warning",
32768: "r13_proxy",
}
@dataclass
class DxfClass:
dxf_name: str
cpp_name: str
app_name: str
proxy_flags: int
instance_count: int
was_proxy: bool
is_entity: bool
raw_tags: list[Tag]
def first_value(tags: list[Tag], code: int) -> Any:
for tag_code, value in tags:
if tag_code == code:
return value
raise ValueError(f"required group code is missing: {code}")
def decode_proxy_flags(value: int) -> list[str]:
return [
name
for bit, name in PROXY_CAPABILITIES.items()
if value & bit
]
def parse_class(tags: list[Tag]) -> DxfClass:
if not tags or tags[0] != (0, "CLASS"):
raise ValueError("CLASS record must start with (0, 'CLASS')")
return DxfClass(
dxf_name=str(first_value(tags, 1)),
cpp_name=str(first_value(tags, 2)),
app_name=str(first_value(tags, 3)),
proxy_flags=int(first_value(tags, 90)),
instance_count=int(first_value(tags, 91)),
was_proxy=bool(int(first_value(tags, 280))),
is_entity=bool(int(first_value(tags, 281))),
raw_tags=tags.copy(),
)
sample_tags: list[Tag] = [
(0, "CLASS"),
(1, "MY_CUSTOM_ENTITY"),
(2, "MyCustomEntity"),
(3, "MY_CUSTOM_APP"),
(90, 131),
(91, 2),
(280, 0),
(281, 1),
]
dxf_class = parse_class(sample_tags)
print(dxf_class)
print(decode_proxy_flags(dxf_class.proxy_flags))
コード90が131なら、フラグ解析結果は次のようになります。
['erase', 'transform', 'clone']
実装では、解析済み属性だけでなくraw_tagsも保持します。未知コードや将来追加された値を理解できなくても、再出力時に破壊しにくくなるためです。
図面全体との対応を検査する
解析後は、必須コードの欠損、識別子の重複、コード281と配置先、コード91と実検出数を照合します。未知のDXF名と未解釈タグはRawデータに残し、不一致があっても自動削除せず診断と修復を分けます。
実装で起こりやすい失敗
CLASSESを実装コードと考える:保存されるのは登録情報です。- コード1と2を同一視する:DXF名とC++名は別の識別子です。
- コード90を列挙値として扱う:複数操作を組み合わせるビットフラグです。
- コード90と280を統合する:許可操作と保存時状態は別情報です。
CLASSにコード5を要求する:通常のハンドル付きオブジェクトとは異なります。- 未知クラスを削除する:理解できなくてもRawデータを保持します。
まとめ
DXFのCLASSESセクションは、アプリケーション定義クラスの登録情報を保持します。
コード1 → DXFレコード名
コード2 → C++クラス名
コード3 → アプリケーション名
コード90 → プロキシとして許可される操作
コード91 → インスタンス数
コード280 → 保存時にプロキシだったか
コード281 → entityかobjectか
CLASSESだけで独自オブジェクトの意味を完全には再現できません。識別情報とフラグを解析し、ENTITIES・BLOCKS・OBJECTSと照合しながら、未知データをRaw形式で残します。これにより、カスタムオブジェクトやプロキシを含む図面を安全に検査・中継できます。

