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()