130 lines
4.8 KiB
Python
130 lines
4.8 KiB
Python
import ezdxf
|
|
import json
|
|
import os
|
|
import argparse
|
|
|
|
# Mappings from ezdxf integer enums to human-readable strings
|
|
MTEXT_ALIGNMENT_MAP = {
|
|
1: "TOP_LEFT", 2: "TOP_CENTER", 3: "TOP_RIGHT",
|
|
4: "MIDDLE_LEFT", 5: "MIDDLE_CENTER", 6: "MIDDLE_RIGHT",
|
|
7: "BOTTOM_LEFT", 8: "BOTTOM_CENTER", 9: "BOTTOM_RIGHT",
|
|
}
|
|
|
|
TEXT_HALIGN_MAP = {0: "LEFT", 1: "CENTER", 2: "RIGHT", 4: "MIDDLE"}
|
|
TEXT_VALIGN_MAP = {0: "BASELINE", 1: "BOTTOM", 2: "MIDDLE", 3: "TOP"}
|
|
|
|
|
|
def get_text_alignment(text_entity):
|
|
""" Determines the alignment string from a TEXT or MTEXT entity. """
|
|
if text_entity.dxftype() == 'MTEXT':
|
|
return MTEXT_ALIGNMENT_MAP.get(text_entity.dxf.attachment_point, "TOP_LEFT")
|
|
|
|
elif text_entity.dxftype() == 'TEXT':
|
|
# For TEXT, alignment is determined by halign and valign.
|
|
# The default (0, 0) is LEFT, BASELINE which we treat as BOTTOM_LEFT.
|
|
# If halign or valign is non-default, the align_point is used instead of insert.
|
|
halign = TEXT_HALIGN_MAP.get(text_entity.dxf.halign, "LEFT")
|
|
valign = TEXT_VALIGN_MAP.get(text_entity.dxf.valign, "BOTTOM")
|
|
|
|
if valign == "BASELINE": # Treat BASELINE as BOTTOM for simplicity
|
|
valign = "BOTTOM"
|
|
|
|
# Combine them, e.g., "MIDDLE_CENTER"
|
|
# For simple left-aligned text, it will be "BOTTOM_LEFT"
|
|
if halign == "LEFT":
|
|
return f"{valign}_LEFT"
|
|
elif halign == "RIGHT":
|
|
return f"{valign}_RIGHT"
|
|
else: # CENTER or MIDDLE
|
|
return f"{valign}_CENTER"
|
|
|
|
return "BOTTOM_LEFT" # Default fallback
|
|
|
|
|
|
def extract_dxf_entities(dxf_path):
|
|
"""
|
|
Extracts all LINE and TEXT/MTEXT entities from a DXF file and returns them
|
|
as a dictionary structured for JSON output.
|
|
|
|
Args:
|
|
dxf_path (str): The full path to the DXF file.
|
|
|
|
Returns:
|
|
dict: A dictionary containing lists of extracted line and text entities,
|
|
or None if the file cannot be processed.
|
|
"""
|
|
try:
|
|
doc = ezdxf.readfile(dxf_path)
|
|
msp = doc.modelspace()
|
|
except (IOError, ezdxf.DXFStructureError) as e:
|
|
print(f"Error reading DXF file at {dxf_path}: {e}")
|
|
return None
|
|
|
|
extracted_data = {
|
|
"lines": [],
|
|
"texts": []
|
|
}
|
|
|
|
# --- Extract LINE entities ---
|
|
for line in msp.query('LINE'):
|
|
extracted_data["lines"].append({
|
|
"start": (line.dxf.start.x, line.dxf.start.y),
|
|
"end": (line.dxf.end.x, line.dxf.end.y),
|
|
"layer": line.dxf.layer,
|
|
"color": line.dxf.color,
|
|
"linetype": line.dxf.linetype
|
|
})
|
|
|
|
# --- Extract TEXT and MTEXT entities ---
|
|
for text_entity in msp.query('TEXT MTEXT'):
|
|
alignment = get_text_alignment(text_entity)
|
|
|
|
if text_entity.dxftype() == 'TEXT':
|
|
text_content = text_entity.dxf.text
|
|
height = text_entity.dxf.height
|
|
# If text is aligned, its true position is align_point, not insert
|
|
if text_entity.dxf.halign != 0 or text_entity.dxf.valign != 0:
|
|
insert_point = (text_entity.dxf.align_point.x, text_entity.dxf.align_point.y)
|
|
else:
|
|
insert_point = (text_entity.dxf.insert.x, text_entity.dxf.insert.y)
|
|
|
|
elif text_entity.dxftype() == 'MTEXT':
|
|
text_content = text_entity.text # MTEXT uses a 'text' attribute
|
|
height = text_entity.dxf.char_height
|
|
insert_point = (text_entity.dxf.insert.x, text_entity.dxf.insert.y)
|
|
else:
|
|
continue
|
|
|
|
extracted_data["texts"].append({
|
|
"content": text_content,
|
|
"insert_point": insert_point,
|
|
"alignment": alignment,
|
|
"height": height,
|
|
"style": text_entity.dxf.style,
|
|
"layer": text_entity.dxf.layer,
|
|
"color": text_entity.dxf.color
|
|
})
|
|
|
|
return extracted_data
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Extract entities (lines, texts, mtexts) from a DXF file and save them to a JSON file.")
|
|
parser.add_argument("source_dxf", help="Path to the source DXF file.")
|
|
parser.add_argument("output_json", help="Path to the output JSON file.")
|
|
args = parser.parse_args()
|
|
|
|
print(f"Extracting entities from: {args.source_dxf}")
|
|
extracted_data = extract_dxf_entities(args.source_dxf)
|
|
|
|
if extracted_data:
|
|
try:
|
|
with open(args.output_json, 'w', encoding='utf-8') as f:
|
|
json.dump(extracted_data, f, ensure_ascii=False, indent=2)
|
|
print(f"Successfully extracted {len(extracted_data.get('lines', []))} lines and "
|
|
f"{len(extracted_data.get('texts', []))} text entities to: {args.output_json}")
|
|
except IOError as e:
|
|
print(f"Error: Could not write to output file {args.output_json}. Reason: {e}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|