import gradio as gr import subprocess import os import tempfile import datetime import ezdxf import cairosvg from huggingface_hub import upload_file def convert_image_to_dxf(image_file, output_folder=None, use_lines=False): try: # Validate input image if image_file is None: return "No image provided", None, None # Define output folder, using a temp directory if none is specified if not output_folder: output_folder = tempfile.mkdtemp() else: os.makedirs(output_folder, exist_ok=True) # Generate the date-based output file name current_date = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") image_path = image_file output_path = os.path.join(output_folder, f"{current_date}_output.dxf") debug_output_path = os.path.join(output_folder, f"{current_date}_debug.png") # Prepare the command arguments command_args = ["./SimpleImageToDxfHavePass"] # Add --use-lines if the checkbox is checked if use_lines: command_args.append("--use-lines") # Add other arguments command_args.extend([f"--imagePath={image_path}", f"--outputPath={output_path}", f"--debug-output={debug_output_path}"]) # Execute conversion command result = subprocess.run( command_args, check=True, capture_output=True ) # Log stdout for debugging print(result.stdout.decode('utf-8')) # Check if conversion was successful if not os.path.exists(output_path): return "Conversion failed: DXF file was not created.", None, None # Convert LWPOLYLINE to POLYLINE if necessary convert_lwpolylines_to_polylines(output_path) # Convert DXF to PNG for preview dxf_image_path = convert_dxf_to_image(output_path) # Prepare folder structure for upload date_folder = f"{current_date}" # Hugging Face token hf_token = os.getenv("HF_TOKEN") if not hf_token: return "Hugging Face token not found", None, None # Upload input image, output DXF, and optionally debug image to Hugging Face in a date-based folder uploaded_files = [] # Upload input image uploaded_input = upload_file( path_or_fileobj=image_path, path_in_repo=f"datasets/ArrcttacsrjksX/ImageToAutocadData/{date_folder}/{os.path.basename(image_path)}", repo_id="ArrcttacsrjksX/ImageToAutocadData", token=hf_token ) uploaded_files.append(uploaded_input) # Upload DXF output uploaded_dxf = upload_file( path_or_fileobj=output_path, path_in_repo=f"datasets/ArrcttacsrjksX/ImageToAutocadData/{date_folder}/{os.path.basename(output_path)}", repo_id="ArrcttacsrjksX/ImageToAutocadData", token=hf_token ) uploaded_files.append(uploaded_dxf) # If the checkbox is ticked, upload debug image if use_lines: uploaded_debug = upload_file( path_or_fileobj=debug_output_path, path_in_repo=f"datasets/ArrcttacsrjksX/ImageToAutocadData/{date_folder}/{os.path.basename(debug_output_path)}", repo_id="ArrcttacsrjksX/ImageToAutocadData", token=hf_token ) uploaded_files.append(uploaded_debug) # Return files directly for download in Gradio interface return dxf_image_path, uploaded_files except subprocess.CalledProcessError as e: error_msg = f"Error converting image to DXF: {e.stderr.decode('utf-8') if e.stderr else e}" return error_msg, None, None def convert_lwpolylines_to_polylines(dxf_file): """ Convert LWPOLYLINE entities to POLYLINE entities in the given DXF file. This is to ensure compatibility for rendering and image conversion. """ doc = ezdxf.readfile(dxf_file) # Find all LWPOLYLINE entities and convert them to POLYLINE entities for lwpline in doc.modelspace().query('LWPOLYLINE'): # Create a POLYLINE entity from the LWPOLYLINE's vertices vertices = lwpline.vertices() # Call the method to get vertices polyline = doc.modelspace().add_polyline2d(vertices) # Copy attributes from the LWPOLYLINE to the new POLYLINE polyline.dxf.layer = lwpline.dxf.layer polyline.dxf.color = lwpline.dxf.color # Delete the original LWPOLYLINE lwpline.destroy() # Save the modified DXF file doc.saveas(dxf_file) def convert_dxf_to_image(dxf_file): """ Convert DXF to an image (PNG format) for preview purposes. This function uses ezdxf and cairosvg to render a DXF file. """ try: doc = ezdxf.readfile(dxf_file) # Check the DXF content and print out basic details for debugging print(f"DXF content:\n{doc}") # Inspect DXF entities for entity in doc.modelspace(): print(f"Entity type: {entity.dxftype()}") # If the DXF contains basic line entities, we can proceed with rendering # Create a temporary SVG file to render the DXF content svg_file = tempfile.mktemp(suffix=".svg") doc.saveas(svg_file) # Convert SVG to PNG using cairosvg png_file = svg_file.replace(".svg", ".png") cairosvg.svg2png(url=svg_file, write_to=png_file) return png_file except Exception as e: print(f"Error converting DXF to image: {e}") return None def main(): with gr.Blocks() as demo: with gr.Tabs(): # Tab for conversion with gr.TabItem("Image to DXF"): gr.Markdown("# SimpleImageToDxfHavePass") # Input row for image and optional output folder with gr.Row(): image_input = gr.Image(type="filepath", label="Input Image (PNG/JPG)") output_folder = gr.Textbox(label="Output Folder (optional)", placeholder="Leave blank to use a temporary folder") # Checkbox to decide whether to use --use-lines use_lines_checkbox = gr.Checkbox(label="Use --use-lines for conversion", value=False) # Default is False # Outputs: DXF image preview and DXF file download link with gr.Row(): dxf_preview = gr.Image(type="filepath", label="DXF Preview Image") dxf_output = gr.File(label="DXF File Download") # Conversion button with event binding convert_btn = gr.Button("Convert to DXF") convert_btn.click( convert_image_to_dxf, inputs=[image_input, output_folder, use_lines_checkbox], outputs=[dxf_preview, dxf_output] ) # About tab with gr.TabItem("About"): gr.Markdown("This Gradio app allows users to convert an image to a DXF file using the SimpleImageToDxfHavePass command-line tool.") demo.launch(share=True) if __name__ == "__main__": try: subprocess.run(['chmod', '+x', './SimpleImageToDxfHavePass'], check=True) except subprocess.CalledProcessError as e: print(f"Error setting permissions: {e}") exit(1) main()