vectorizar / app.py
victorestrada's picture
Update app.py
1e4860d verified
Raw History Blame Contribute Delete
5.38 kB
import io
import gradio as gr
from PIL import Image
import vtracer
import tempfile
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."""
# Convert Gradio image to bytes for vtracer compatibility
img_byte_array = io.BytesIO()
image.save(img_byte_array, format='PNG')
img_bytes = img_byte_array.getvalue()
# Perform the conversion
svg_str = vtracer.convert_raw_image_to_svg(
img_bytes,
img_format='png',
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)
)
# Save the SVG string to a temporary file
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.svg')
temp_file.write(svg_str.encode('utf-8'))
temp_file.close()
return gr.HTML(f'<svg viewBox="0 0 {image.width} {image.height}">{svg_str}</svg>'), temp_file.name
# Estilos: oculta el pie "Built with Gradio" y usa el azul del CRM en el bot贸n principal
css = """
footer { display: none !important; }
button.primary {
background: #159bd8 !important;
border-color: #5bb6d6 !important;
color: #fff !important;
}
button.primary:hover, button.primary:focus, button.primary:active {
background: #147191 !important;
border-color: #159bd8 !important;
}
h1 { font-size: 22px !important; }
.gradio-container { min-height: 0 !important; }
"""
# Embebido en un iframe (app.iagestion.com): avisa a la p谩gina padre del alto real del
# contenido para que el iframe crezca y no haya un segundo scroll.
# El scroll propio solo se oculta cuando el padre confirma con 'gradio_alto_ok' que est谩
# aplicando ese alto; si no hay respuesta, se conserva y nada queda inalcanzable.
head = """
<script>
(function () {
if (window.self === window.top) return;
var ultimo = 0;
function alto() {
return Math.max(
document.documentElement.scrollHeight,
document.body ? document.body.scrollHeight : 0
) + 16;
}
function enviarAlto(forzar) {
var a = alto();
if (!forzar && Math.abs(a - ultimo) < 4) return;
ultimo = a;
window.parent.postMessage({ tipo: 'gradio_alto', alto: a }, '*');
}
window.addEventListener('message', function (e) {
if (!e.data) return;
if (e.data.tipo === 'gradio_dame_alto') enviarAlto(true);
// El padre nos dimensiona: ya no necesitamos scroll propio
if (e.data.tipo === 'gradio_alto_ok') document.documentElement.style.overflow = 'hidden';
});
function arranca() {
enviarAlto(true);
try {
new ResizeObserver(function () { enviarAlto(false); }).observe(document.body);
new MutationObserver(function () { enviarAlto(false); }).observe(
document.body, { childList: true, subtree: true }
);
} catch (err) {}
setInterval(function () { enviarAlto(false); }, 1500);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', arranca);
} else {
arranca();
}
})();
</script>
"""
# Las opciones de los Radio son pares (etiqueta, valor): la etiqueta se muestra en castellano
# y el valor es el que espera vtracer.
iface = gr.Interface(
fn=convert_image,
inputs=[
gr.Image(type="pil", label="Subir imagen"),
gr.Radio(choices=[("Color", "Color"), ("Binario", "Binary")], value="Color", label="Modo de color"),
gr.Radio(choices=[("Apilado", "Stacked"), ("Recorte", "Cutout")], value="Stacked", label="Jerarqu铆a"),
gr.Radio(choices=[("Curvas", "Spline"), ("Pol铆gonos", "Polygon"), ("Ninguno", "None")], value="Spline", label="Modo"),
gr.Slider(minimum=1, maximum=10, value=4, step=1, label="Filtro de motas"),
gr.Slider(minimum=1, maximum=8, value=6, step=1, label="Precisi贸n de color"),
gr.Slider(minimum=1, maximum=32, value=16, step=1, label="Diferencia entre capas"),
gr.Slider(minimum=10, maximum=90, value=60, step=1, label="Umbral de esquinas"),
gr.Slider(minimum=3.5, maximum=10, value=4.0, step=0.5, label="Umbral de longitud"),
gr.Slider(minimum=1, maximum=20, value=10, step=1, label="Iteraciones m谩ximas"),
gr.Slider(minimum=10, maximum=90, value=45, step=1, label="Umbral de empalme"),
gr.Slider(minimum=1, maximum=10, value=8, step=1, label="Precisi贸n del trazado")
],
outputs=[
gr.HTML(label="Resultado SVG"),
gr.File(label="Descargar SVG")
],
title="Convertir imagen a vector SVG",
description="Sube una imagen y ajusta los par谩metros de conversi贸n seg煤n necesites.",
submit_btn="Convertir",
clear_btn="Limpiar",
allow_flagging="never",
css=css,
head=head,
)
iface.launch(show_api=False)