|
import gradio as gr |
|
from PIL import Image, ImageColor |
|
import os |
|
import zipfile |
|
import tempfile |
|
import shutil |
|
|
|
def parse_color(color_str): |
|
""" |
|
Parses a color string like "#ff0000", "red", or "rgba(255,0,0,1)" into an (R, G, B) tuple. |
|
""" |
|
try: |
|
if color_str.startswith("rgba"): |
|
rgba = color_str.strip("rgba() ").split(",") |
|
r = int(float(rgba[0])) |
|
g = int(float(rgba[1])) |
|
b = int(float(rgba[2])) |
|
return (r, g, b) |
|
else: |
|
return ImageColor.getrgb(color_str) |
|
except Exception as e: |
|
raise ValueError(f"Invalid color input: {color_str} ({e})") |
|
|
|
def recolor_icons(zip_file, selected_color): |
|
target_rgb = parse_color(selected_color) |
|
|
|
|
|
temp_input_dir = tempfile.mkdtemp() |
|
temp_output_zip = tempfile.NamedTemporaryFile(delete=False, suffix=".zip") |
|
temp_output_zip.close() |
|
|
|
try: |
|
|
|
with zipfile.ZipFile(zip_file, 'r') as zip_ref: |
|
zip_ref.extractall(temp_input_dir) |
|
|
|
|
|
for root, _, files in os.walk(temp_input_dir): |
|
for filename in files: |
|
if filename.lower().endswith('.png'): |
|
filepath = os.path.join(root, filename) |
|
image = Image.open(filepath).convert("RGBA") |
|
pixels = image.load() |
|
|
|
for y in range(image.height): |
|
for x in range(image.width): |
|
r, g, b, a = pixels[x, y] |
|
if a != 0: |
|
pixels[x, y] = (*target_rgb, a) |
|
|
|
image.save(filepath) |
|
|
|
|
|
with zipfile.ZipFile(temp_output_zip.name, 'w') as zip_out: |
|
for root, _, files in os.walk(temp_input_dir): |
|
for file in files: |
|
full_path = os.path.join(root, file) |
|
arcname = os.path.relpath(full_path, temp_input_dir) |
|
zip_out.write(full_path, arcname) |
|
|
|
return temp_output_zip.name |
|
|
|
finally: |
|
shutil.rmtree(temp_input_dir) |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("## π¨ PNG Icon Recolor Tool") |
|
gr.Markdown( |
|
"Upload a **ZIP** file of `.png` images and pick any color.\n" |
|
"All non-transparent pixels will be recolored to your chosen color.\n" |
|
"Transparency is preserved. Get a new ZIP to download." |
|
) |
|
|
|
with gr.Row(): |
|
zip_input = gr.File(label="π Upload ZIP of PNGs", file_types=[".zip"]) |
|
color_picker = gr.ColorPicker(label="π¨ Choose Color", value="#ffffff") |
|
|
|
output_zip = gr.File(label="β¬οΈ Download Recolored ZIP") |
|
submit_btn = gr.Button("π Recolor Icons") |
|
|
|
submit_btn.click(fn=recolor_icons, inputs=[zip_input, color_picker], outputs=output_zip) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |