"""빠른 DXF 크롭 렌더러 (LINE/ARC/CIRCLE/INSERT 분해/TEXT/MTEXT) 사용: python -I fastrender.py [width_px] 캐시: .cache.pkl (분해한 선분·글자) """ import sys, os, pickle, math, re sys.path.insert(0, 'pylib') import ezdxf import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.collections import LineCollection from matplotlib import font_manager f = sys.argv[1] x0, x1, y0, y1 = map(float, sys.argv[2:6]) out = sys.argv[6] wpx = int(sys.argv[7]) if len(sys.argv) > 7 else 2400 DARK = len(sys.argv) > 8 and sys.argv[8] == 'dark' cache = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cache_' + os.path.basename(f) + '.pkl') ACI = {1: 'red', 2: '#b8a000', 3: 'green', 4: '#00a0a0', 5: 'blue', 6: 'magenta', 7: 'black', 8: 'gray', 9: 'gray', 30: '#ff8000', 41: '#b08800'} ACID = {1: '#ff3030', 2: '#ffff00', 3: '#00e000', 4: '#00e0e0', 5: '#5080ff', 6: '#ff40ff', 7: '#ffffff', 8: '#aaaaaa', 9: '#aaaaaa', 30: '#ff9a1f', 41: '#e6c200'} FONT = re.compile(r'\\f[^;]*;') def color_of(e, doc): c = e.dxf.color if c == 256 or c is None: try: c = doc.layers.get(e.dxf.layer).dxf.color except Exception: c = 7 c = abs(c) return ACI.get(c, '#555555') def arc_pts(cx, cy, r, a0, a1, n=24): if a1 < a0: a1 += 360 return [(cx + r * math.cos(math.radians(a0 + (a1 - a0) * i / n)), cy + r * math.sin(math.radians(a0 + (a1 - a0) * i / n))) for i in range(n + 1)] def collect(doc): segs = []; texts = [] def walk(ents, depth=0): for e in ents: t = e.dxftype() col = color_of(e, doc) lay = e.dxf.layer if t == 'LINE': segs.append(((e.dxf.start.x, e.dxf.start.y), (e.dxf.end.x, e.dxf.end.y), col, lay)) elif t == 'ARC': p = arc_pts(e.dxf.center.x, e.dxf.center.y, e.dxf.radius, e.dxf.start_angle, e.dxf.end_angle) for a, b in zip(p[:-1], p[1:]): segs.append((a, b, col, lay)) elif t == 'CIRCLE': p = arc_pts(e.dxf.center.x, e.dxf.center.y, e.dxf.radius, 0, 360, 36) for a, b in zip(p[:-1], p[1:]): segs.append((a, b, col, lay)) elif t in ('LWPOLYLINE', 'POLYLINE'): try: pts = [(v[0], v[1]) for v in e.get_points()] if t == 'LWPOLYLINE' else [(v.dxf.location.x, v.dxf.location.y) for v in e.vertices] for a, b in zip(pts[:-1], pts[1:]): segs.append((a, b, col, lay)) except Exception: pass elif t == 'INSERT' and depth < 3: try: walk(e.virtual_entities(), depth + 1) except Exception: pass try: for a in e.attribs: if a.dxf.tag == 'RB_NO' or True: texts.append((a.dxf.insert.x, a.dxf.insert.y, a.dxf.text, a.dxf.height, ACI[3], 0)) except Exception: pass elif t == 'MTEXT': s = FONT.sub('', e.text).replace('{', '').replace('}', '').replace('\\P', '\n') texts.append((e.dxf.insert.x, e.dxf.insert.y, s, e.dxf.char_height, col, e.dxf.get('rotation', 0))) elif t == 'TEXT': texts.append((e.dxf.insert.x, e.dxf.insert.y, e.dxf.text, e.dxf.height, col, e.dxf.get('rotation', 0))) elif t == 'POINT': segs.append(((e.dxf.location.x - 20, e.dxf.location.y), (e.dxf.location.x + 20, e.dxf.location.y), col, lay)) walk(doc.modelspace()) return segs, texts if os.path.exists(cache) and os.path.getmtime(cache) > os.path.getmtime(f): segs, texts = pickle.load(open(cache, 'rb')) else: doc = ezdxf.readfile(f) segs, texts = collect(doc) pickle.dump((segs, texts), open(cache, 'wb')) fp = font_manager.FontProperties(fname=r'C:\Windows\Fonts\malgun.ttf') w = x1 - x0; h = y1 - y0 fig = plt.figure(figsize=(wpx / 100.0, wpx / 100.0 * h / w), dpi=100, facecolor=('#222831' if DARK else 'white')) ax = fig.add_axes([0, 0, 1, 1]) sel = [s for s in segs if max(s[0][0], s[1][0]) >= x0 and min(s[0][0], s[1][0]) <= x1 and max(s[0][1], s[1][1]) >= y0 and min(s[0][1], s[1][1]) <= y1] def rc(c): if not DARK: return c inv = {v: ACID[k] for k, v in ACI.items()} return inv.get(c, '#dddddd') lc = LineCollection([(s[0], s[1]) for s in sel], colors=[rc(s[2]) for s in sel], linewidths=0.6) ax.add_collection(lc) px_per_unit = wpx / w for x, y, s, hh, col, rot in texts: if x0 <= x <= x1 and y0 <= y <= y1: ax.text(x, y, s, fontproperties=fp, fontsize=max(4, hh * px_per_unit * 0.72), color=rc(col), rotation=rot, ha='left', va='bottom') ax.set_xlim(x0, x1); ax.set_ylim(y0, y1); ax.set_aspect('equal'); ax.axis('off') fig.savefig(out, dpi=100, facecolor=fig.get_facecolor()) print('ok', len(sel), out)