File size: 8,817 Bytes
5e2fbf6
 
 
 
 
 
71bf7b3
5e2fbf6
 
2a4cc69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e2fbf6
 
2a4cc69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e2fbf6
 
 
71bf7b3
2a4cc69
 
 
bb06cc3
2a4cc69
 
 
5e2fbf6
 
 
 
 
2a4cc69
5e2fbf6
 
 
 
 
 
 
 
 
 
 
 
 
2a4cc69
 
5e2fbf6
2a4cc69
 
5e2fbf6
2a4cc69
5e2fbf6
71bf7b3
2a4cc69
71bf7b3
53fb129
71bf7b3
2a4cc69
 
 
bb06cc3
2a4cc69
 
 
71bf7b3
 
 
2a4cc69
 
71bf7b3
2a4cc69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e2fbf6
57de3e4
2a4cc69
bb06cc3
2a4cc69
 
 
 
71bf7b3
 
2a4cc69
 
 
 
 
 
 
 
 
 
 
 
 
 
bb06cc3
57de3e4
2a4cc69
 
 
 
 
 
 
 
71bf7b3
2a4cc69
71bf7b3
2a4cc69
71bf7b3
 
 
 
 
2a4cc69
57de3e4
2a4cc69
 
 
57de3e4
53fb129
bb06cc3
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import io
import gradio as gr
from PIL import Image
import vtracer
import tempfile

# Unverändertes TRANSLATIONS-Wörterbuch...
TRANSLATIONS = {
    'en': {
        'title': '# Convert Image to SVG Vectors',
        'description': 'Upload an image and customize the conversion parameters. Click "Convert" to start.',
        'lang_label': 'Language',
        'image_label': 'Upload Image',
        'advanced_label': 'Advanced Settings',
        'color_mode_label': 'Color Mode',
        'hierarchical_label': 'Hierarchical',
        'mode_label': 'Mode',
        'filter_speckle_label': 'Filter Speckle',
        'color_precision_label': 'Color Precision',
        'layer_difference_label': 'Layer Difference',
        'corner_threshold_label': 'Corner Threshold',
        'length_threshold_label': 'Length Threshold',
        'max_iterations_label': 'Max Iterations',
        'splice_threshold_label': 'Splice Threshold',
        'path_precision_label': 'Path Precision',
        'convert_button': 'Convert',
        'output_svg_label': 'SVG Output',
        'download_svg_label': 'Download SVG'
    },
    'de': {
        'title': '# Bild in SVG-Vektoren umwandeln',
        'description': 'Laden Sie ein Bild hoch und passen Sie die Parameter an. Klicken Sie auf "Umwandeln", um zu starten.',
        'lang_label': 'Sprache',
        'image_label': 'Bild hochladen',
        'advanced_label': 'Erweiterte Einstellungen',
        'color_mode_label': 'Farbmodus',
        'hierarchical_label': 'Hierarchisch',
        'mode_label': 'Modus',
        'filter_speckle_label': 'Flecken filtern',
        'color_precision_label': 'Farbpräzision',
        'layer_difference_label': 'Ebenenunterschied',
        'corner_threshold_label': 'Eckenschwelle',
        'length_threshold_label': 'Längenschwelle',
        'max_iterations_label': 'Max. Iterationen',
        'splice_threshold_label': 'Spleißschwelle',
        'path_precision_label': 'Pfadpräzision',
        'convert_button': 'Umwandeln',
        'output_svg_label': 'SVG-Ausgabe',
        'download_svg_label': 'SVG herunterladen'
    }
}

# Unveränderte convert_image Funktion...
def convert_image(image, color_mode, hierarchical, mode, filter_speckle, 
                  color_precision, layer_difference, corner_threshold, 
                  length_threshold, max_iterations, splice_threshold, path_precision):
    """Converts an image to SVG using vtracer with customizable parameters."""
    if image is None:
        return None, None
        
    img_byte_array = io.BytesIO()
    image.save(img_byte_array, format='PNG')
    img_bytes = img_byte_array.getvalue()

    svg_str = vtracer.convert_raw_image_to_svg(
        image_data=img_bytes,
        colormode=color_mode.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),
        max_iterations=int(max_iterations),
        splice_threshold=int(splice_threshold),
        path_precision=int(path_precision)
    )

    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.svg', mode='w', encoding='utf-8')
    temp_file.write(svg_str)
    temp_file.close()
    
    preview_html = f"<div style='background-color:#f0f0f0; padding:10px; border-radius:5px;'>SVG successfully generated. Preview:<br><img src='/file={temp_file.name}' width='300'></div>"

    return preview_html, temp_file.name


with gr.Blocks() as vector_converter_interface:
    lang = 'en' # Start mit Englisch

    language_dropdown = gr.Dropdown(choices=['en', 'de'], value=lang, label=TRANSLATIONS[lang]['lang_label'], interactive=True)
    title = gr.Markdown(value=TRANSLATIONS[lang]['title'])
    description = gr.Markdown(value=TRANSLATIONS[lang]['description'])

    with gr.Row():
        with gr.Column(scale=1):
            image_input = gr.Image(type="pil", label=TRANSLATIONS[lang]['image_label'])
            
            # --- ÄNDERUNG 1: Variable für Accordion hinzugefügt ---
            advanced_accordion = gr.Accordion(TRANSLATIONS[lang]['advanced_label'], open=False)
            with advanced_accordion:
                color_mode_input = gr.Radio(choices=["Color", "Binary"], value="Color", label=TRANSLATIONS[lang]['color_mode_label'])
                hierarchical_input = gr.Radio(choices=["Stacked", "Cutout"], value="Stacked", label=TRANSLATIONS[lang]['hierarchical_label'])
                # ... restliche Inputs unverändert ...
                mode_input = gr.Radio(choices=["Spline", "Polygon", "None"], value="Spline", label=TRANSLATIONS[lang]['mode_label'])
                filter_speckle_input = gr.Slider(minimum=1, maximum=10, value=4, step=1, label=TRANSLATIONS[lang]['filter_speckle_label'])
                color_precision_input = gr.Slider(minimum=1, maximum=8, value=6, step=1, label=TRANSLATIONS[lang]['color_precision_label'])
                layer_difference_input = gr.Slider(minimum=1, maximum=32, value=16, step=1, label=TRANSLATIONS[lang]['layer_difference_label'])
                corner_threshold_input = gr.Slider(minimum=10, maximum=90, value=60, step=1, label=TRANSLATIONS[lang]['corner_threshold_label'])
                length_threshold_input = gr.Slider(minimum=3.5, maximum=10, value=4.0, step=0.5, label=TRANSLATIONS[lang]['length_threshold_label'])
                max_iterations_input = gr.Slider(minimum=1, maximum=20, value=10, step=1, label=TRANSLATIONS[lang]['max_iterations_label'])
                splice_threshold_input = gr.Slider(minimum=10, maximum=90, value=45, step=1, label=TRANSLATIONS[lang]['splice_threshold_label'])
                path_precision_input = gr.Slider(minimum=1, maximum=10, value=8, step=1, label=TRANSLATIONS[lang]['path_precision_label'])

            convert_button = gr.Button(value=TRANSLATIONS[lang]['convert_button'])

        with gr.Column(scale=1):
            svg_output = gr.HTML(label=TRANSLATIONS[lang]['output_svg_label'])
            file_output = gr.File(label=TRANSLATIONS[lang]['download_svg_label'])

    def update_language(language):
        t = TRANSLATIONS[language]
        return {
            language_dropdown: gr.update(label=t['lang_label']),
            title: gr.update(value=t['title']),
            description: gr.update(value=t['description']),
            image_input: gr.update(label=t['image_label']),
            # --- ÄNDERUNG 2: Korrekte Referenz auf die Accordion-Variable ---
            advanced_accordion: gr.update(label=t['advanced_label']),
            color_mode_input: gr.update(label=t['color_mode_label']),
            hierarchical_input: gr.update(label=t['hierarchical_label']),
            mode_input: gr.update(label=t['mode_label']),
            filter_speckle_input: gr.update(label=t['filter_speckle_label']),
            color_precision_input: gr.update(label=t['color_precision_label']),
            layer_difference_input: gr.update(label=t['layer_difference_label']),
            corner_threshold_input: gr.update(label=t['corner_threshold_label']),
            length_threshold_input: gr.update(label=t['length_threshold_label']),
            max_iterations_input: gr.update(label=t['max_iterations_label']),
            splice_threshold_input: gr.update(label=t['splice_threshold_label']),
            path_precision_input: gr.update(label=t['path_precision_label']),
            convert_button: gr.update(value=t['convert_button']),
            svg_output: gr.update(label=t['output_svg_label']),
            file_output: gr.update(label=t['download_svg_label']),
        }

    all_inputs = [
        image_input, color_mode_input, hierarchical_input, mode_input, 
        filter_speckle_input, color_precision_input, layer_difference_input, 
        corner_threshold_input, length_threshold_input, max_iterations_input, 
        splice_threshold_input, path_precision_input
    ]
    all_outputs = [svg_output, file_output]
    
    convert_button.click(fn=convert_image, inputs=all_inputs, outputs=all_outputs)
    
    # --- ÄNDERUNG 3: Accordion-Variable zur Output-Liste hinzugefügt ---
    ui_components_to_update = [
        language_dropdown, title, description, image_input, advanced_accordion,
        color_mode_input, hierarchical_input, mode_input, filter_speckle_input, 
        color_precision_input, layer_difference_input, corner_threshold_input, 
        length_threshold_input, max_iterations_input, splice_threshold_input, 
        path_precision_input, convert_button, svg_output, file_output
    ]
    language_dropdown.change(
        fn=update_language,
        inputs=language_dropdown,
        outputs=ui_components_to_update
    )

vector_converter_interface.launch()