Spaces:
Sleeping
Sleeping
| 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() |