|
import cairosvg |
|
import gradio as gr |
|
from PIL import Image |
|
import os |
|
import xml.etree.ElementTree as ET |
|
|
|
def initial_render(svg_file): |
|
"""Render SVG at a large size for preview and cropping.""" |
|
if svg_file is None: |
|
return None, None |
|
|
|
|
|
with open(svg_file.name, 'rb') as f: |
|
svg_content = f.read() |
|
|
|
|
|
temp_svg_path = "./temp.svg" |
|
with open(temp_svg_path, 'wb') as f: |
|
f.write(svg_content) |
|
|
|
|
|
output_path = "./initial_preview.png" |
|
cairosvg.svg2png( |
|
bytestring=svg_content, |
|
write_to=output_path, |
|
output_width=3000, |
|
output_height=3000 |
|
) |
|
|
|
|
|
preview_image = Image.open(output_path) |
|
return preview_image, temp_svg_path |
|
|
|
def final_convert(svg_path, crop_box, size_input): |
|
"""Convert SVG to PNG using either crop box or user-specified dimensions.""" |
|
if svg_path is None: |
|
return None, None |
|
|
|
|
|
with open(svg_path, 'rb') as f: |
|
svg_content = f.read() |
|
|
|
|
|
output_path = "./final_output.png" |
|
|
|
|
|
if size_input and size_input.strip(): |
|
try: |
|
width, height = map(int, size_input.split('x')) |
|
if width <= 0 or height <= 0: |
|
raise ValueError("Width and height must be positive") |
|
except ValueError: |
|
return gr.Warning("Invalid size format. Use 'width x height' (e.g., '800x600')"), None |
|
elif crop_box and 'left' in crop_box: |
|
left = crop_box['left'] |
|
top = crop_box['top'] |
|
width = crop_box['right'] - left |
|
height = crop_box['bottom'] - top |
|
else: |
|
|
|
width, height = 2000, 2000 |
|
|
|
|
|
cairosvg.svg2png( |
|
bytestring=svg_content, |
|
write_to=output_path, |
|
output_width=width, |
|
output_height=height |
|
) |
|
|
|
|
|
final_image = Image.open(output_path) |
|
return final_image, output_path |
|
|
|
with gr.Blocks() as bl: |
|
gr.Markdown("# SVG to PNG Converter with Custom Crop or Size") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
svg_input = gr.File(label="Upload SVG File", file_types=[".svg"]) |
|
preview_btn = gr.Button("Generate Preview") |
|
size_input = gr.Textbox( |
|
label="Output Size (width x height)", |
|
placeholder="e.g., 800x600 (optional, overrides crop)" |
|
) |
|
|
|
with gr.Column(): |
|
preview_output = gr.Image( |
|
type='pil', |
|
label="Preview (Draw a box to crop if no size specified)", |
|
interactive=True, |
|
tool="sketch", |
|
height=800 |
|
) |
|
crop_btn = gr.Button("Convert") |
|
final_output = gr.Image(type='pil', label="Final PNG", height=800) |
|
download_btn = gr.File(label="Download Final PNG") |
|
|
|
|
|
svg_state = gr.State() |
|
|
|
|
|
preview_btn.click( |
|
fn=initial_render, |
|
inputs=svg_input, |
|
outputs=[preview_output, svg_state] |
|
) |
|
|
|
|
|
crop_btn.click( |
|
fn=final_convert, |
|
inputs=[svg_state, preview_output, size_input], |
|
outputs=[final_output, download_btn] |
|
) |
|
|
|
bl.launch() |