File size: 5,850 Bytes
9e835dd
 
 
 
 
07ece8d
9e835dd
 
44bf299
c8e76d3
9e835dd
 
44bf299
9e835dd
abdd93e
07ece8d
c8e76d3
fe88f1f
 
9e835dd
fe88f1f
c8e76d3
fe88f1f
 
 
 
 
 
 
 
 
 
 
 
 
0fddbf9
fe88f1f
07ece8d
c8e76d3
fe88f1f
 
 
 
9e835dd
c8e76d3
 
fe88f1f
c8e76d3
 
 
 
 
 
 
 
 
fe88f1f
9e835dd
 
 
07ece8d
44bf299
 
 
 
 
 
 
 
0fddbf9
44bf299
 
 
 
0fddbf9
44bf299
 
9e835dd
07ece8d
9e835dd
44bf299
07ece8d
44bf299
07ece8d
 
 
3b263fa
c8e76d3
 
 
 
3b263fa
07ece8d
9e835dd
07ece8d
44bf299
07ece8d
 
 
 
 
 
9e835dd
44bf299
07ece8d
 
44bf299
07ece8d
44bf299
07ece8d
9e835dd
44bf299
0fddbf9
07ece8d
 
 
 
0fddbf9
07ece8d
0fddbf9
 
 
 
 
07ece8d
abdd93e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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()