|
|
""" |
|
|
Any2SVG - Image to SVG Vectorization Tool |
|
|
|
|
|
A Gradio 6 application that converts raster images to SVG vector graphics. |
|
|
Supports MCP server integration for AI agent tool calling. |
|
|
|
|
|
Purpose: Convert any raster image (PNG, JPG, WebP, etc.) to SVG format |
|
|
Inputs: Image file, vectorization parameters |
|
|
Outputs: SVG file path or SVG content |
|
|
Examples: Logo vectorization, artwork conversion, icon generation |
|
|
Edge cases: Very large images, transparent backgrounds, gradients |
|
|
Errors: Invalid image format, file I/O errors |
|
|
""" |
|
|
|
|
|
import os |
|
|
import sys |
|
|
from pathlib import Path |
|
|
|
|
|
import gradio as gr |
|
|
from PIL import Image |
|
|
|
|
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent)) |
|
|
|
|
|
from dna.atoms.vectorizer import ( |
|
|
VectorizerConfig, |
|
|
image_to_svg_file, |
|
|
image_to_svg_string, |
|
|
validate_image, |
|
|
VectorizationError, |
|
|
InvalidImageError, |
|
|
) |
|
|
from dna.molecules.mcp_handler import get_output_directory, process_mcp_request |
|
|
|
|
|
|
|
|
def convert_image_to_svg( |
|
|
image: Image.Image, |
|
|
color_mode: str = "color", |
|
|
filter_speckle: int = 4, |
|
|
color_precision: int = 6, |
|
|
corner_threshold: int = 60, |
|
|
path_precision: int = 3, |
|
|
) -> tuple[str, str]: |
|
|
""" |
|
|
Convert a raster image to SVG vector graphics. |
|
|
|
|
|
Args: |
|
|
image: The input image to convert (PIL Image). |
|
|
color_mode: Vectorization mode - 'color' for full color, 'binary' for black/white. |
|
|
filter_speckle: Remove small artifacts (pixels). Higher = more filtering. |
|
|
color_precision: Color quantization bits (1-8). Lower = fewer colors. |
|
|
corner_threshold: Angle threshold for corner detection (degrees). |
|
|
path_precision: Decimal precision for path coordinates. |
|
|
|
|
|
Returns: |
|
|
Tuple of (svg_file_path, svg_content) - path to saved SVG and its content. |
|
|
|
|
|
Raises: |
|
|
ValueError: If image is None or invalid. |
|
|
IOError: If file operations fail. |
|
|
""" |
|
|
config = VectorizerConfig( |
|
|
color_mode=color_mode, |
|
|
filter_speckle=filter_speckle, |
|
|
color_precision=color_precision, |
|
|
corner_threshold=corner_threshold, |
|
|
path_precision=path_precision, |
|
|
) |
|
|
|
|
|
output_dir = get_output_directory() |
|
|
svg_path = image_to_svg_file(image, output_dir, config=config) |
|
|
|
|
|
with open(svg_path, "r", encoding="utf-8") as f: |
|
|
svg_content = f.read() |
|
|
|
|
|
return str(svg_path), svg_content |
|
|
|
|
|
|
|
|
def process_image( |
|
|
image: Image.Image, |
|
|
color_mode: str, |
|
|
filter_speckle: int, |
|
|
color_precision: int, |
|
|
corner_threshold: int, |
|
|
path_precision: int, |
|
|
) -> tuple[str, str, str]: |
|
|
""" |
|
|
Process an image and convert it to SVG format. |
|
|
|
|
|
Args: |
|
|
image: The input raster image to vectorize. |
|
|
color_mode: 'color' for full color output, 'binary' for black and white. |
|
|
filter_speckle: Speckle filter size to remove small artifacts (1-100). |
|
|
color_precision: Color precision bits for quantization (1-8). |
|
|
corner_threshold: Corner detection angle threshold in degrees (0-180). |
|
|
path_precision: Decimal precision for SVG path coordinates (1-8). |
|
|
|
|
|
Returns: |
|
|
Tuple of (status_message, svg_file_path, svg_preview_content). |
|
|
""" |
|
|
try: |
|
|
svg_path, svg_content = convert_image_to_svg( |
|
|
image=image, |
|
|
color_mode=color_mode, |
|
|
filter_speckle=filter_speckle, |
|
|
color_precision=color_precision, |
|
|
corner_threshold=corner_threshold, |
|
|
path_precision=path_precision, |
|
|
) |
|
|
|
|
|
status = f"✅ SVG saved to: {svg_path}" |
|
|
return status, svg_path, svg_content |
|
|
|
|
|
except Exception as e: |
|
|
error_msg = f"❌ Error: {str(e)}" |
|
|
return error_msg, "", "" |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks( |
|
|
title="Any2SVG - Image to SVG Converter", |
|
|
theme=gr.themes.Soft(), |
|
|
) as demo: |
|
|
gr.Markdown( |
|
|
""" |
|
|
# 🎨 Any2SVG - Image to SVG Converter |
|
|
|
|
|
Convert raster images (PNG, JPG, WebP, etc.) to scalable vector graphics (SVG). |
|
|
|
|
|
**Features:** |
|
|
- High-quality vectorization using vtracer |
|
|
- Configurable color modes and precision |
|
|
- MCP server support for AI agent integration |
|
|
""" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
input_image = gr.Image( |
|
|
label="Input Image", |
|
|
type="pil", |
|
|
sources=["upload", "clipboard"], |
|
|
) |
|
|
|
|
|
with gr.Accordion("Vectorization Settings", open=False): |
|
|
color_mode = gr.Radio( |
|
|
choices=["color", "binary"], |
|
|
value="color", |
|
|
label="Color Mode", |
|
|
info="'color' for full color, 'binary' for black/white", |
|
|
) |
|
|
filter_speckle = gr.Slider( |
|
|
minimum=1, |
|
|
maximum=100, |
|
|
value=4, |
|
|
step=1, |
|
|
label="Filter Speckle", |
|
|
info="Remove small artifacts (higher = more filtering)", |
|
|
) |
|
|
color_precision = gr.Slider( |
|
|
minimum=1, |
|
|
maximum=8, |
|
|
value=6, |
|
|
step=1, |
|
|
label="Color Precision", |
|
|
info="Color quantization bits (lower = fewer colors)", |
|
|
) |
|
|
corner_threshold = gr.Slider( |
|
|
minimum=0, |
|
|
maximum=180, |
|
|
value=60, |
|
|
step=1, |
|
|
label="Corner Threshold", |
|
|
info="Angle threshold for corner detection (degrees)", |
|
|
) |
|
|
path_precision = gr.Slider( |
|
|
minimum=1, |
|
|
maximum=8, |
|
|
value=3, |
|
|
step=1, |
|
|
label="Path Precision", |
|
|
info="Decimal precision for path coordinates", |
|
|
) |
|
|
|
|
|
convert_btn = gr.Button("🔄 Convert to SVG", variant="primary", size="lg") |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
status_output = gr.Textbox( |
|
|
label="Status", |
|
|
interactive=False, |
|
|
) |
|
|
svg_file_output = gr.File( |
|
|
label="Download SVG", |
|
|
) |
|
|
svg_preview = gr.Code( |
|
|
label="SVG Preview", |
|
|
language="html", |
|
|
lines=15, |
|
|
) |
|
|
|
|
|
|
|
|
convert_btn.click( |
|
|
fn=process_image, |
|
|
inputs=[ |
|
|
input_image, |
|
|
color_mode, |
|
|
filter_speckle, |
|
|
color_precision, |
|
|
corner_threshold, |
|
|
path_precision, |
|
|
], |
|
|
outputs=[status_output, svg_file_output, svg_preview], |
|
|
) |
|
|
|
|
|
|
|
|
gr.Examples( |
|
|
examples=[ |
|
|
["https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png"], |
|
|
], |
|
|
inputs=[input_image], |
|
|
label="Example Images", |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
@gr.api( |
|
|
inputs=[ |
|
|
gr.Image(type="pil"), |
|
|
gr.Textbox(value="color"), |
|
|
gr.Number(value=4), |
|
|
gr.Number(value=6), |
|
|
], |
|
|
outputs=[gr.Textbox(), gr.Textbox()], |
|
|
) |
|
|
def image_to_svg( |
|
|
image: Image.Image, |
|
|
color_mode: str = "color", |
|
|
filter_speckle: int = 4, |
|
|
color_precision: int = 6, |
|
|
) -> tuple[str, str]: |
|
|
""" |
|
|
Convert any raster image to SVG vector graphics. |
|
|
|
|
|
This tool accepts an image and returns the path to the generated SVG file |
|
|
along with the SVG content. The SVG is saved to the configured output directory. |
|
|
|
|
|
Args: |
|
|
image: The input raster image (PNG, JPG, WebP, etc.) to vectorize. |
|
|
color_mode: Vectorization mode - 'color' for full color, 'binary' for B&W. |
|
|
filter_speckle: Speckle filter size (1-100). Higher removes more artifacts. |
|
|
color_precision: Color precision bits (1-8). Lower means fewer colors. |
|
|
|
|
|
Returns: |
|
|
Tuple of (svg_file_path, svg_content). |
|
|
""" |
|
|
svg_path, svg_content = convert_image_to_svg( |
|
|
image=image, |
|
|
color_mode=color_mode, |
|
|
filter_speckle=int(filter_speckle), |
|
|
color_precision=int(color_precision), |
|
|
) |
|
|
return svg_path, svg_content |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
get_output_directory() |
|
|
|
|
|
|
|
|
demo.launch( |
|
|
mcp_server=True, |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=False, |
|
|
) |
|
|
|