import gradio as gr import ezdxf import svgwrite import os import tempfile from pathlib import Path def dxf_to_svg_content(dxf_file_path): """DXF 파일을 SVG 내용으로 변환""" try: # DXF 파일 읽기 doc = ezdxf.readfile(dxf_file_path) msp = doc.modelspace() # 임시 SVG 파일 생성 temp_svg = tempfile.NamedTemporaryFile(mode='w', suffix='.svg', delete=False) # SVG 문서 생성 dwg = svgwrite.Drawing(temp_svg.name, size=('1000px', '1000px'), viewBox='0 0 1000 1000') # 모든 엔티티 처리 entity_count = 0 for entity in msp: entity_count += 1 if entity.dxftype() == 'LINE': # 직선 처리 start = entity.dxf.start end = entity.dxf.end dwg.add(dwg.line( start=(start.x, start.y), end=(end.x, end.y), stroke='black', stroke_width=1, fill='none' )) elif entity.dxftype() == 'LWPOLYLINE': # 폴리라인 처리 points = [] for point in entity.get_points(): points.append((point[0], point[1])) if len(points) > 1: polyline = dwg.polyline( points=points, stroke='black', stroke_width=1, fill='none' ) # 닫힌 폴리라인인지 확인 if entity.closed: polyline.attribs['stroke-linejoin'] = 'round' dwg.add(polyline) elif entity.dxftype() == 'CIRCLE': # 원 처리 center = entity.dxf.center radius = entity.dxf.radius dwg.add(dwg.circle( center=(center.x, center.y), r=radius, stroke='black', stroke_width=1, fill='none' )) elif entity.dxftype() == 'ARC': # 호 처리 center = entity.dxf.center radius = entity.dxf.radius start_angle = entity.dxf.start_angle end_angle = entity.dxf.end_angle import math start_x = center.x + radius * math.cos(math.radians(start_angle)) start_y = center.y + radius * math.sin(math.radians(start_angle)) end_x = center.x + radius * math.cos(math.radians(end_angle)) end_y = center.y + radius * math.sin(math.radians(end_angle)) large_arc = 1 if abs(end_angle - start_angle) > 180 else 0 sweep = 1 if end_angle > start_angle else 0 path_data = f"M {start_x} {start_y} A {radius} {radius} 0 {large_arc} {sweep} {end_x} {end_y}" dwg.add(dwg.path( d=path_data, stroke='black', stroke_width=1, fill='none' )) # SVG 파일 저장 dwg.save() return temp_svg.name, f"변환 완료! {entity_count}개의 엔티티를 처리했습니다." except Exception as e: return None, f"변환 실패: {str(e)}" def convert_multiple_dxf(dxf_files): """여러 DXF 파일을 각각 변환하여 개별 다운로드 가능하게 함""" if not dxf_files: return [], "DXF 파일들을 업로드해주세요." try: converted_files = [] converted_count = 0 error_files = [] for dxf_file in dxf_files: try: svg_file, message = dxf_to_svg_content(dxf_file.name) if svg_file: # 원본 파일명을 기반으로 새 파일명 생성 original_name = Path(dxf_file.name).stem new_svg_path = f"{original_name}.svg" # 임시 디렉토리에 복사 import shutil final_svg_path = os.path.join(tempfile.gettempdir(), f"converted_{original_name}.svg") shutil.copy2(svg_file, final_svg_path) converted_files.append(final_svg_path) converted_count += 1 # 원본 임시 파일 정리 os.unlink(svg_file) else: error_files.append(Path(dxf_file.name).name) except Exception as e: error_files.append(f"{Path(dxf_file.name).name} (오류: {str(e)})") status_message = f"✅ {converted_count}개 파일이 성공적으로 변환되었습니다." if error_files: status_message += f"\n❌ 실패한 파일들: {', '.join(error_files)}" return converted_files, status_message except Exception as e: return [], f"변환 실패: {str(e)}" # Gradio 인터페이스 생성 with gr.Blocks(title="DXF to SVG 변환기") as demo: gr.Markdown("# DXF to SVG 변환기") gr.Markdown("DXF 파일들을 SVG 형식으로 변환하여 각각 다운로드할 수 있습니다.") with gr.Row(): with gr.Column(scale=1): file_input = gr.File( label="DXF 파일들 업로드", file_count="multiple", file_types=[".dxf"], type="filepath" ) convert_btn = gr.Button("변환하기", variant="primary", size="lg") status_output = gr.Textbox(label="변환 상태", interactive=False, lines=3) with gr.Column(scale=2): gr.Markdown("### 변환된 SVG 파일들") gr.Markdown("변환이 완료되면 아래에서 각 파일을 개별적으로 다운로드할 수 있습니다.") # 최대 10개 파일까지 개별 다운로드 지원 file_outputs = [] for i in range(10): file_output = gr.File( label=f"변환된 파일 {i+1}", visible=False ) file_outputs.append(file_output) def update_outputs(dxf_files): """변환 결과를 개별 파일 출력으로 업데이트""" converted_files, status = convert_multiple_dxf(dxf_files) # 모든 출력을 초기화 outputs = [None] * 10 visibilities = [False] * 10 # 변환된 파일들을 출력에 할당 for i, file_path in enumerate(converted_files[:10]): # 최대 10개까지 outputs[i] = file_path visibilities[i] = True # 결과 반환: 상태 + 파일들 + 가시성 result = [status] for i in range(10): result.append(gr.File(value=outputs[i], visible=visibilities[i])) return result # 이벤트 연결 convert_btn.click( fn=update_outputs, inputs=[file_input], outputs=[status_output] + file_outputs ) if __name__ == "__main__": demo.launch()