import gradio as gr import vtracer import os import tempfile def image_to_svg(image, colormode, hierarchical, filter_speckle, color_precision, layer_difference, mode, corner_threshold, length_threshold, splice_threshold, path_precision): """ Converts an input image to an SVG string using vtracer. This function is triggered automatically when any of the input controls change. It now includes robust error handling to prevent the app from freezing. """ if image is None: return None, "Upload an image to see the SVG preview and code.", None input_path = image # Create a persistent temporary file that Gradio can access. with tempfile.NamedTemporaryFile(delete=False, suffix=".svg", mode='w', encoding='utf-8') as temp_output_file: output_path = temp_output_file.name try: # vtracer conversion call with all parameters from the UI. vtracer.convert_image_to_svg_py( input_path, output_path, colormode=colormode.lower(), hierarchical=hierarchical.lower(), mode=mode.lower(), filter_speckle=int(filter_speckle), color_precision=int(color_precision), layer_difference=int(layer_difference), corner_threshold=int(corner_threshold), length_threshold=float(length_threshold), splice_threshold=int(splice_threshold), path_precision=int(path_precision), max_iterations=10 ) # If successful, read the generated SVG content to display. with open(output_path, "r", encoding='utf-8') as f: svg_content = f.read() return output_path, svg_content, output_path # **THE FIX for Error Handling:** # Catch any exception from the vtracer process. except Exception as e: # Create a user-friendly error message. error_message = ( f"⚠️ Conversion Failed\n\n" f"An error occurred in the backend. This can happen with certain image types or extreme parameter values.\n\n" f"Please try adjusting the settings or use a different image.\n\n" f"Details: {str(e)}" ) # Return clean outputs and display the error message in the code block. # This prevents the app from getting stuck. return None, error_message, None # --- Gradio User Interface --- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo: with gr.Row(): with gr.Column(scale=1): image_input = gr.Image(type="filepath", label="Upload Your Image", sources=["upload", "clipboard"]) with gr.Column(scale=2): gr.Markdown( """ # IMG2SVG: Real-time SVG Converter This application converts raster images into clean, scalable vector graphics (SVG). **How to use:** 1. Upload an image. 2. Adjust the settings in the control panel below. 3. The SVG preview updates automatically when you change a setting. """ ) with gr.Row(variant="panel"): with gr.Column(scale=1): gr.Markdown("### Control Panel") with gr.Group(): gr.Markdown("#### Clustering") colormode = gr.Radio(["Color", "B/W"], value="Color", label="Color Mode") hierarchical = gr.Radio(["Stacked", "Cutout"], value="Stacked", label="Hierarchical Mode") filter_speckle = gr.Slider(0, 128, value=4, step=1, label="Filter Speckle (Cleaner)") # **THE FIX for Parameter Range:** # The vtracer backend panics if color_precision is 0. # The valid range is 1-8. This slider now enforces that constraint. color_precision = gr.Slider(1, 8, value=6, step=1, label="Color Precision (More accurate)") layer_difference = gr.Slider(0, 128, value=16, step=1, label="Gradient Step (Less layers)") with gr.Group(): gr.Markdown("#### Curve Fitting") mode = gr.Radio(["Spline", "Polygon", "Pixel"], value="Spline", label="Mode") corner_threshold = gr.Slider(0, 180, value=60, step=1, label="Corner Threshold (Smoother)") length_threshold = gr.Slider(0, 10, value=4.0, step=0.5, label="Segment Length (More coarse)") splice_threshold = gr.Slider(0, 180, value=45, step=1, label="Splice Threshold (Less accurate)") path_precision = gr.Slider(1, 8, value=3, step=1, label="Path Precision") with gr.Column(scale=2): gr.Markdown("### Result") with gr.Tabs(): with gr.TabItem("SVG Preview"): svg_image_output = gr.Image(label="Live SVG Preview", interactive=False) with gr.TabItem("SVG Code"): svg_text_output = gr.Code(label="Generated SVG Code", language="html", interactive=False) svg_file_output = gr.File(label="Download SVG") all_inputs = [ image_input, colormode, hierarchical, filter_speckle, color_precision, layer_difference, mode, corner_threshold, length_threshold, splice_threshold, path_precision ] all_outputs = [svg_file_output, svg_text_output, svg_image_output] for slider in [filter_speckle, color_precision, layer_difference, corner_threshold, length_threshold, splice_threshold, path_precision]: slider.release(fn=image_to_svg, inputs=all_inputs, outputs=all_outputs) for component in [image_input, colormode, hierarchical, mode]: component.change(fn=image_to_svg, inputs=all_inputs, outputs=all_outputs) demo.launch()