| name | dwg-to-excel |
| description | Convert AutoCAD DWG files (1983-2026) to Excel databases using DwgExporter CLI. Extract layers, blocks, attributes, and geometry data without Autodesk licenses. |
DWG to Excel Conversion
Business Case
Problem Statement
AutoCAD DWG files contain valuable project data locked in proprietary format:
- Layer structures with drawing organization
- Block references with attribute data
- Text annotations and dimensions
- Geometric entities (lines, polylines, arcs)
- External references (xrefs)
Extracting this data typically requires AutoCAD licenses or complex programming.
Solution
DwgExporter.exe converts DWG files to structured Excel databases offline, without Autodesk licenses.
Business Value
- Zero license cost - No AutoCAD license required
- Legacy support - Reads DWG files from 1983 to 2026
- Data extraction - Layers, blocks, attributes, text, geometry
- PDF export - Generate drawings from DWG layouts
- Batch processing - Convert thousands of DWG files
Technical Implementation
CLI Syntax
DwgExporter.exe <input_dwg> [options]
Output Formats
| Output | Description |
|---|
.xlsx | Excel database with all entities |
.pdf | PDF drawings from layouts |
Supported Versions
| Version Range | Description |
|---|
| R12 (1992) | Legacy DWG |
| R14 (1997) | AutoCAD 14 |
| 2000-2002 | DWG 2000 format |
| 2004-2006 | DWG 2004 format |
| 2007-2009 | DWG 2007 format |
| 2010-2012 | DWG 2010 format |
| 2013-2017 | DWG 2013 format |
| 2018-2026 | DWG 2018 format |
Examples
DwgExporter.exe "C:\Projects\FloorPlan.dwg"
DwgExporter.exe "C:\Projects\FloorPlan.dwg" sheets2pdf
for /R "C:\Projects" %f in (*.dwg) do DwgExporter.exe "%f"
Get-ChildItem "C:\Projects\*.dwg" -Recurse | ForEach-Object {
& "C:\DDC\DwgExporter.exe" $_.FullName
}
Python Integration
import subprocess
import pandas as pd
from pathlib import Path
from typing import List, Optional, Dict, Any
from dataclasses import dataclass
from enum import Enum
class DWGEntityType(Enum):
"""DWG entity types."""
LINE = "LINE"
POLYLINE = "POLYLINE"
LWPOLYLINE = "LWPOLYLINE"
CIRCLE = "CIRCLE"
ARC = "ARC"
ELLIPSE = "ELLIPSE"
SPLINE = "SPLINE"
TEXT = "TEXT"
MTEXT = "MTEXT"
DIMENSION = "DIMENSION"
INSERT = "INSERT"
HATCH = "HATCH"
SOLID = "SOLID"
POINT = "POINT"
ATTRIB = "ATTRIB"
ATTDEF = "ATTDEF"
@dataclass
class DWGEntity:
"""Represents a DWG entity."""
handle: str
entity_type: str
layer: str
color: int
linetype: str
lineweight: float
start_x: Optional[] =
start_y: [] =
end_x: [] =
end_y: [] =
block_name: [] =
rotation: [] =
scale_x: [] =
scale_y: [] =
text_content: [] =
text_height: [] =
:
name:
base_point_x:
base_point_y:
entity_count:
is_dynamic:
attributes: []
:
name:
color:
linetype:
is_on:
is_frozen:
is_locked:
lineweight:
entity_count:
:
():
.exporter = Path(exporter_path)
.exporter.exists():
FileNotFoundError()
() -> Path:
dwg_path = Path(dwg_file)
dwg_path.exists():
FileNotFoundError()
cmd = [(.exporter), (dwg_path)]
export_pdf:
cmd.append()
result = subprocess.run(cmd, capture_output=, text=)
result.returncode != :
RuntimeError()
dwg_path.with_suffix()
() -> [[, ]]:
folder_path = Path(folder)
pattern = include_subfolders
results = []
dwg_file folder_path.glob(pattern):
:
output = .convert((dwg_file), export_pdf)
results.append({
: (dwg_file),
: (output),
:
})
()
Exception e:
results.append({
: (dwg_file),
: ,
: ,
: (e)
})
()
results
() -> pd.DataFrame:
xlsx_path = Path(xlsx_file)
xlsx_path.exists():
FileNotFoundError()
pd.read_excel(xlsx_file, sheet_name=)
() -> pd.DataFrame:
df = .read_entities(xlsx_file)
df.columns:
ValueError()
summary = df.groupby().agg({
:
}).reset_index()
summary.columns = [, ]
summary.sort_values(, ascending=)
() -> pd.DataFrame:
df = .read_entities(xlsx_file)
blocks = df[df[] == ]
blocks.empty:
pd.DataFrame(columns=[, ])
summary = blocks.groupby().agg({
:
}).reset_index()
summary.columns = [, ]
summary.sort_values(, ascending=)
() -> pd.DataFrame:
df = .read_entities(xlsx_file)
text_types = [, , ]
texts = df[df[].isin(text_types)]
texts.columns:
texts[[, , , ]].copy()
texts[[, , ]].copy()
() -> [, ]:
df = .read_entities(xlsx_file)
df.columns:
{}
df[].value_counts().to_dict()
() -> pd.DataFrame:
df = .read_entities(xlsx_file)
blocks = df[(df[] == ) &
(df[] == block_name)]
result_data = []
_, block blocks.iterrows():
block_handle = block[]
block_data = {
: block_handle,
: block.get(, ),
: block.get(, ),
: block.get(, )
}
col df.columns:
col.startswith():
block_data[col] = block.get(col)
result_data.append(block_data)
pd.DataFrame(result_data)
:
():
.exporter = exporter
() -> [, ]:
xlsx = .exporter.convert(dwg_file)
df = .exporter.read_entities((xlsx))
analysis = {
: dwg_file,
: (df),
: .exporter.get_layers((xlsx)).to_dict(),
: .exporter.get_entity_statistics((xlsx)),
: .exporter.get_blocks((xlsx)).to_dict()
}
df.columns df.columns:
analysis[] = {
: df[].(),
: df[].(),
: df[].(),
: df[].()
}
analysis
() -> [, ]:
xlsx1 = .exporter.convert(dwg1)
xlsx2 = .exporter.convert(dwg2)
df1 = .exporter.read_entities((xlsx1))
df2 = .exporter.read_entities((xlsx2))
layers1 = (df1[].unique()) df1.columns ()
layers2 = (df2[].unique()) df2.columns ()
{
: dwg1,
: dwg2,
: (df2) - (df1),
: (layers2 - layers1),
: (layers1 - layers2),
: (layers1 & layers2)
}
() -> pd.DataFrame:
df = .exporter.read_entities(xlsx_file)
df.columns df.columns:
pd.DataFrame()
df[] = (df[] / tolerance).() * tolerance
df[] = (df[] / tolerance).() * tolerance
duplicates = df[df.duplicated(
subset=[, , , ],
keep=
)]
duplicates.sort_values([, ])
() -> :
exporter = DWGExporter(exporter_path)
output = exporter.convert(dwg_file)
(output)
() -> []:
exporter = DWGExporter(exporter_path)
results = exporter.batch_convert(folder, include_subfolders)
[r[] r results r[] == ]
Output Structure
Excel Sheets
| Sheet | Content |
|---|
| Elements | All DWG entities with properties |
| Layers | Layer definitions |
| Blocks | Block definitions |
| Layouts | Drawing layouts/sheets |
Entity Columns
| Column | Type | Description |
|---|
| Handle | string | Unique entity handle |
| EntityType | string | LINE, CIRCLE, INSERT, etc. |
| Layer | string | Layer name |
| Color | int | Color index (0-256) |
| Linetype | string | Linetype name |
| Lineweight | float | Line weight in mm |
| X, Y, Z | float | Entity coordinates |
| BlockName | string | For INSERT entities |
| TextContent | string | For TEXT/MTEXT |
Quick Start
exporter = DWGExporter("C:/DDC/DwgExporter.exe")
xlsx = exporter.convert("C:/Projects/Plan.dwg")
print(f"Output: {xlsx}")
df = exporter.read_entities(str(xlsx))
print(f"Total entities: {len(df)}")
layers = exporter.get_layers(str(xlsx))
print(layers)
blocks = exporter.get_blocks(str(xlsx))
print(blocks)
texts = exporter.get_text_content(str(xlsx))
for _, row in texts.iterrows():
print(f"{row['Layer']}: {row.get('TextContent', 'N/A')}")
Common Use Cases
1. Layer Audit
exporter = DWGExporter()
xlsx = exporter.convert("drawing.dwg")
layers = exporter.get_layers(str(xlsx))
standard_layers = ['0', 'WALLS', 'DOORS', 'WINDOWS', 'DIMENSIONS']
non_standard = layers[~layers['Layer'].isin(standard_layers)]
print("Non-standard layers:", non_standard['Layer'].tolist())
2. Block Schedule
doors = exporter.extract_block_attributes(str(xlsx), "DOOR")
print(doors[['Block_Handle', 'Attr_DOOR_TYPE', 'Attr_DOOR_SIZE']])
3. Drawing Comparison
analyzer = DWGAnalyzer(exporter)
diff = analyzer.compare_drawings("rev1.dwg", "rev2.dwg")
print(f"Entities added: {diff['entity_count_diff']}")
print(f"New layers: {diff['layers_added']}")
Integration with DDC Pipeline
from dwg_exporter import DWGExporter, DWGAnalyzer
exporter = DWGExporter("C:/DDC/DwgExporter.exe")
xlsx = exporter.convert("project.dwg")
analyzer = DWGAnalyzer(exporter)
analysis = analyzer.analyze_drawing_structure("project.dwg")
print(f"Drawing: {analysis['file']}")
print(f"Entities: {analysis['total_entities']}")
print(f"Layers: {len(analysis['layers'])}")
print(f"Blocks: {len(analysis['blocks'])}")
Best Practices
- Check DWG version - Older files may have limited data
- Validate layer structure - Clean up before processing
- Handle external references - Bind xrefs if needed
- Batch overnight - Large files take time
- Verify entity counts - Compare with AutoCAD if possible
Resources