File size: 5,896 Bytes
c813a80 |
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 |
import gradio as gr
import re
import tempfile
from lxml import etree as ET
def create_icon_sheet(svg_files, columns, padding, background_color, sheet_width, transparent_background):
# Calculate dimensions
icons = []
max_icon_size = 0
for svg_file in svg_files:
# Verify the content is an SVG
try:
tree = ET.parse(svg_file.name)
root = tree.getroot()
if root.tag != '{http://www.w3.org/2000/svg}svg':
raise ValueError("File is not a valid SVG")
except ET.ParseError:
raise ValueError("File is not a valid SVG")
width = float(root.get('width', '0').replace('px', ''))
height = float(root.get('height', '0').replace('px', ''))
max_icon_size = max(max_icon_size, width, height)
icons.append(svg_file.name)
icon_size = max_icon_size + padding * 2
rows = (len(icons) + columns - 1) // columns
# Calculate scaling factor
scale_factor = sheet_width / (columns * icon_size)
# Adjust icon size and sheet height based on the scaling factor
scaled_icon_size = icon_size * scale_factor
sheet_height = rows * scaled_icon_size
# Create SVG root element
svg_ns = "http://www.w3.org/2000/svg"
# No need to register the namespace manually with lxml
svg = ET.Element("{%s}svg" % svg_ns, nsmap={None: svg_ns})
svg.set("width", str(sheet_width))
svg.set("height", str(sheet_height))
# Add background if not transparent
if not transparent_background:
rect = ET.SubElement(svg, "{%s}rect" % svg_ns)
rect.set("x", "0")
rect.set("y", "0")
rect.set("width", str(sheet_width))
rect.set("height", str(sheet_height))
rect.set("fill", background_color)
# Place icons
for i, svg_file in enumerate(icons):
row = i // columns
col = i % columns
x = col * scaled_icon_size
y = row * scaled_icon_size
# Read SVG content
with open(svg_file, 'r') as f:
svg_content = f.read()
# Remove XML declaration and DOCTYPE
svg_content = re.sub(r'<\?xml[^>]+\?>', '', svg_content)
svg_content = re.sub(r'<!DOCTYPE[^>]+>', '', svg_content)
# Parse the SVG content
icon_svg = ET.fromstring(svg_content)
# Create a group with the appropriate transform
icon_group = ET.SubElement(svg, "{%s}g" % svg_ns)
# Adjust viewBox if necessary
viewBox = icon_svg.get('viewBox')
if viewBox:
x_offset, y_offset, svg_width, svg_height = map(float, viewBox.split())
icon_scale_x = (scaled_icon_size - padding * 2 * scale_factor) / svg_width
icon_scale_y = (scaled_icon_size - padding * 2 * scale_factor) / svg_height
icon_scale = min(icon_scale_x, icon_scale_y)
translate_x = x + padding * scale_factor - x_offset * icon_scale
translate_y = y + padding * scale_factor - y_offset * icon_scale
transform = f"translate({translate_x},{translate_y}) scale({icon_scale})"
else:
width = float(icon_svg.get('width', '0').replace('px', ''))
height = float(icon_svg.get('height', '0').replace('px', ''))
icon_scale = min((scaled_icon_size - padding * 2 * scale_factor) / width, (scaled_icon_size - padding * 2 * scale_factor) / height)
transform = f"translate({x + padding * scale_factor},{y + padding * scale_factor}) scale({icon_scale})"
icon_group.set("transform", transform)
# Move the children of icon_svg into icon_group
for element in icon_svg.iterchildren():
icon_group.append(element)
# Write the SVG to a file
output_file = tempfile.NamedTemporaryFile(delete=False, suffix='.svg', mode='wb')
tree = ET.ElementTree(svg)
tree.write(output_file, xml_declaration=True, encoding='utf-8')
output_file.close()
return output_file.name
def icon_sheet_interface():
with gr.Blocks() as icon_sheet_app:
gr.Markdown("# Icon Sheet Generator")
with gr.Row():
svg_files = gr.File(label="Upload SVG Icons", file_count="multiple")
with gr.Row():
columns = gr.Slider(1, 10, value=4, step=1, label="Number of Columns")
padding = gr.Slider(0, 50, value=10, step=1, label="Padding (px)")
background_color = gr.ColorPicker(label="Background Color", value="#ffffff")
sheet_width = gr.Slider(100, 2000, value=1000, step=10, label="Sheet Width (px)")
transparent_background = gr.Checkbox(label="Transparent Background", value=False)
generate_btn = gr.Button("Generate Icon Sheet")
output = gr.File(label="Generated Icon Sheet")
def process_and_return(svg_files, columns, padding, background_color, sheet_width, transparent_background):
# Validate that all uploaded files are SVGs
for svg_file in svg_files:
if not svg_file.name.endswith('.svg'):
raise ValueError(f"Invalid file type: {svg_file.name}. Please upload only SVG files.")
temp_file = create_icon_sheet(svg_files, columns, padding, background_color, sheet_width, transparent_background)
return temp_file
generate_btn.click(process_and_return,
inputs=[svg_files, columns, padding, background_color, sheet_width, transparent_background],
outputs=output)
return icon_sheet_app
if __name__ == "__main__":
icon_sheet_app = icon_sheet_interface()
icon_sheet_app.launch()
|