What Is DXF?
DXF — Drawing Exchange Format — is an open CAD data format developed by Autodesk in 1982 to enable data interoperability between AutoCAD and other software. While Autodesk's native format is the binary DWG, DXF was designed as an openly documented, text-based alternative that any application could read and write without licensing fees or reverse engineering.
DXF files use the .dxf extension and come in two variants:
- ASCII DXF — Human-readable text, the most common form
- Binary DXF — Compact binary representation (rarely used; not widely supported)
Today, DXF is supported by virtually every CAD, CNC, laser cutting, and vector graphics application: AutoCAD, LibreCAD, QCAD, FreeCAD, Inkscape, CorelDRAW, SolidWorks (import), and hundreds of industrial tools.
DXF File Structure
An ASCII DXF file is organized as a sequence of group code / value pairs. Every piece of data is described by a numeric group code (type identifier) followed by its value on the next line:
0 ← group code (integer): entity type or keyword
LINE ← value: this is a LINE entity
8 ← group code 8: layer name
0 ← value: layer "0" (default layer)
10 ← group code 10: X coordinate of start point
100.0 ← value
20 ← group code 20: Y coordinate of start point
200.0 ← value
11 ← group code 11: X coordinate of end point
300.0 ← value
21 ← group code 21: Y coordinate of end point
400.0 ← value
0
ENDSEC
Major DXF Sections
A complete DXF file is divided into sections, each beginning with 0\nSECTION and ending with 0\nENDSEC:
| Section | Purpose |
|---|---|
HEADER |
Drawing-wide variables: units, limits, current layer, version ($ACADVER) |
CLASSES |
Application-defined classes (optional, needed for complex entities) |
TABLES |
Named tables: LTYPE (linetypes), LAYER, STYLE (text), VIEW, DIMSTYLE |
BLOCKS |
Block definitions (reusable symbol libraries) |
ENTITIES |
The actual drawing geometry: lines, circles, arcs, text, etc. |
OBJECTS |
Non-graphical objects: dictionaries, XDATA, extended data |
THUMBNAILIMAGE |
Optional preview bitmap |
EOF |
End of file marker |
Common Entity Types
| Entity | Group codes | Description |
|---|---|---|
LINE |
10/20/30 (start) + 11/21/31 (end) | Straight line segment |
CIRCLE |
10/20/30 (center) + 40 (radius) | Full circle |
ARC |
10/20/30 (center) + 40 (radius) + 50/51 (start/end angle) | Arc |
LWPOLYLINE |
90 (vertex count) + 10/20 per vertex | Lightweight 2D polyline |
TEXT |
10/20/30 (position) + 40 (height) + 1 (string) | Single-line text |
MTEXT |
10/20/30 + 40 (height) + 1 (content with RTF codes) | Multi-line text |
INSERT |
2 (block name) + 10/20/30 (position) | Block reference |
HATCH |
70 (hatch type) + boundary paths | Filled area |
DIMENSION |
Complex dimension entity with measurement | Dimension annotation |
SPLINE |
Control points + knot vectors | NURBS spline |
ELLIPSE |
10/20/30 (center) + 11/21/31 (major axis) + 40 (minor/major ratio) | Ellipse |
DXF Coordinate Systems and Units
DXF uses a right-handed 3D coordinate system. All coordinates are in whatever units the drawing uses — there is no built-in unit system. The $INSUNITS variable in the HEADER section records the intended unit: 1=inches, 2=feet, 4=mm, 5=cm, 6=m, 14=micrometers.
For 2D drawings (the most common case), Z coordinates are simply 0. The $LIMMIN and $LIMMAX header variables define the drawing limits (virtual paper bounds).
Important: DXF R12 (AutoCAD release 12, 1992) and DXF R2000/R2004/R2007/R2010/R2013/R2018 are all different versions with different capabilities. The $ACADVER header variable identifies the version: AC1009 = R12, AC1015 = R2000, AC1032 = R2018.
Working with DXF in Python: ezdxf
ezdxf is the leading Python library for reading and writing DXF files:
pip install ezdxf
Reading a DXF File
import ezdxf
def inspect_dxf(filepath: str) -> None:
"""Print all entities in a DXF file with their key properties."""
doc = ezdxf.readfile(filepath)
msp = doc.modelspace() # model space = main drawing area
print(f"DXF version: {doc.dxfversion}")
print(f"Units: {doc.header.get('$INSUNITS', 'not set')}")
print(f"Entities in model space: {len(msp)}")
print()
for entity in msp:
etype = entity.dxftype()
if etype == 'LINE':
print(f"LINE: ({entity.dxf.start.x:.2f}, {entity.dxf.start.y:.2f}) → "
f"({entity.dxf.end.x:.2f}, {entity.dxf.end.y:.2f})")
elif etype == 'CIRCLE':
c = entity.dxf.center
print(f"CIRCLE: center=({c.x:.2f},{c.y:.2f}), radius={entity.dxf.radius:.2f}")
elif etype == 'TEXT':
print(f"TEXT: '{entity.dxf.text}' at ({entity.dxf.insert.x:.2f}, "
f"{entity.dxf.insert.y:.2f})")
elif etype == 'LWPOLYLINE':
print(f"LWPOLYLINE: {len(entity)} vertices, closed={entity.closed}")
inspect_dxf('floor_plan.dxf')
Creating a DXF File
import ezdxf
from ezdxf.enums import TextEntityAlignment
def create_floor_plan_dxf(output_path: str) -> None:
"""Create a simple floor plan as DXF."""
doc = ezdxf.new('R2010') # DXF version
doc.header['$INSUNITS'] = 4 # millimeters
msp = doc.modelspace()
# Add layers
doc.layers.add('WALLS', color=7) # white/black
doc.layers.add('DOORS', color=5) # blue
doc.layers.add('ANNOTATIONS', color=2) # yellow
# Outer walls (rectangle: 8000mm × 6000mm)
msp.add_lwpolyline(
[(0, 0), (8000, 0), (8000, 6000), (0, 6000)],
close=True,
dxfattribs={'layer': 'WALLS', 'lineweight': 50},
)
# Interior wall
msp.add_line(
(4000, 0), (4000, 4000),
dxfattribs={'layer': 'WALLS', 'lineweight': 35},
)
# Door arc (900mm door, hinged at 4000,0)
msp.add_arc(
center=(4000, 0),
radius=900,
start_angle=0,
end_angle=90,
dxfattribs={'layer': 'DOORS'},
)
# Room labels
msp.add_text(
'Living Room',
dxfattribs={
'layer': 'ANNOTATIONS',
'height': 200,
'insert': (2000, 3000),
},
)
doc.saveas(output_path)
print(f"DXF saved: {output_path}")
create_floor_plan_dxf('floor_plan.dxf')
Measuring and Analyzing DXF Geometry
import ezdxf
import math
def analyze_dxf_geometry(filepath: str) -> dict:
"""Calculate total line length and circle count in a DXF file."""
doc = ezdxf.readfile(filepath)
msp = doc.modelspace()
total_line_length = 0.0
circle_count = 0
entity_counts = {}
for entity in msp:
etype = entity.dxftype()
entity_counts[etype] = entity_counts.get(etype, 0) + 1
if etype == 'LINE':
start = entity.dxf.start
end = entity.dxf.end
length = math.sqrt(
(end.x - start.x)**2 +
(end.y - start.y)**2 +
(end.z - start.z)**2
)
total_line_length += length
elif etype == 'CIRCLE':
circle_count += 1
return {
'entity_counts': entity_counts,
'total_line_length': round(total_line_length, 2),
'circle_count': circle_count,
}
result = analyze_dxf_geometry('part.dxf')
print(result)
DXF vs DWG: Which to Use?
| Aspect | DXF | DWG |
|---|---|---|
| Openness | Open specification (published by Autodesk) | Proprietary binary format |
| Human-readable | Yes (ASCII DXF) | No |
| File size | Larger (~2–5× DWG) | Compact |
| Software support | All CAD software | Autodesk products + compatibility layers |
| Feature completeness | Most 2D/3D features | Full AutoCAD feature set |
| 3D/parametric | Limited | Full 3D solid modeling support |
| Version lock-in | Version in header but widely compatible | Versions incompatible across major releases |
| Use case | Interoperability, CNC, laser cutting | Native AutoCAD storage |
For maximum interoperability — such as sending a drawing to a laser cutter, CNC router, or a colleague using different software — DXF is the clear choice. Save as DXF R12 for widest compatibility (limited to 2D), or DXF R2000/R2010 for 2D/3D with broader entity support.
DXF for CNC and Laser Cutting
When preparing DXF files for CNC machining or laser cutting:
- Use only closed polylines for cut paths — open polylines cause inconsistent results
- Set units explicitly (
$INSUNITSto mm or inches matching your machine) - Separate cut types by layer — e.g., layer "CUT" for through-cuts, "ENGRAVE" for engraving
- No construction lines or text unless the machine should engrave them
- DXF R12 or R2000 — most CNC controllers support one of these; check your machine's documentation
- Validate in LibreCAD or QCAD before sending — free tools that render DXF accurately
import ezdxf
def prepare_for_laser_cutting(input_dxf: str, output_dxf: str) -> None:
"""
Prepare a DXF for laser cutting:
- Keep only LWPOLYLINE and CIRCLE entities on layer CUT
- Remove all text, dimensions, and annotations
"""
doc = ezdxf.readfile(input_dxf)
msp = doc.modelspace()
to_delete = []
for entity in msp:
etype = entity.dxftype()
layer = entity.dxf.get('layer', '0').upper()
# Remove entities not on CUT layer or not a usable cut type
if layer != 'CUT' or etype not in ('LWPOLYLINE', 'CIRCLE', 'ARC', 'LINE'):
to_delete.append(entity)
for entity in to_delete:
msp.delete_entity(entity)
# Save as R2000 for broad CNC compatibility
doc.dxfversion = 'AC1015'
doc.saveas(output_dxf)
print(f"Cleaned DXF saved: {output_dxf}")
prepare_for_laser_cutting('design_with_annotations.dxf', 'laser_ready.dxf')
Related conversions
Frequent conversions across the catalogue: