Spaces:
Runtime error
Runtime error
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from PIL import Image, ImageStat
|
3 |
+
import numpy as np
|
4 |
+
import os
|
5 |
+
import math
|
6 |
+
import shutil
|
7 |
+
import random
|
8 |
+
|
9 |
+
def get_dominant_color(image):
|
10 |
+
"""Get the dominant color of an image or return None."""
|
11 |
+
try:
|
12 |
+
stat = ImageStat.Stat(image)
|
13 |
+
r, g, b = stat.mean[:3]
|
14 |
+
return int(r), int(g), int(b)
|
15 |
+
except:
|
16 |
+
return None
|
17 |
+
|
18 |
+
def resize_and_pad(image, target_size):
|
19 |
+
"""Resize the image and pad it to match target size."""
|
20 |
+
img = image.convert("RGB")
|
21 |
+
aspect_ratio = img.width / img.height
|
22 |
+
target_aspect_ratio = target_size[0] / target_size[1]
|
23 |
+
|
24 |
+
if aspect_ratio > target_aspect_ratio:
|
25 |
+
# Wider than target aspect ratio
|
26 |
+
new_width = target_size[0]
|
27 |
+
new_height = int(new_width / aspect_ratio)
|
28 |
+
else:
|
29 |
+
# Taller than target aspect ratio
|
30 |
+
new_height = target_size[1]
|
31 |
+
new_width = int(new_height * aspect_ratio)
|
32 |
+
|
33 |
+
img = img.resize((new_width, new_height), Image.ANTIALIAS)
|
34 |
+
|
35 |
+
# Determine padding color
|
36 |
+
dominant_color = get_dominant_color(img)
|
37 |
+
if dominant_color is None:
|
38 |
+
dominant_color = (255, 255, 255) if random.choice([True, False]) else (0, 0, 0)
|
39 |
+
|
40 |
+
# Create a new image with the determined background color
|
41 |
+
new_img = Image.new("RGB", target_size, dominant_color)
|
42 |
+
offset = ((target_size[0] - new_width) // 2, (target_size[1] - new_height) // 2)
|
43 |
+
new_img.paste(img, offset)
|
44 |
+
return new_img
|
45 |
+
|
46 |
+
def combine_images(images, target_size=(2048, 2048)):
|
47 |
+
"""Combine four images into a single one."""
|
48 |
+
num_images = len(images)
|
49 |
+
output_images = []
|
50 |
+
|
51 |
+
# Group images into chunks of 4
|
52 |
+
for i in range(0, num_images, 4):
|
53 |
+
group = images[i:i+4]
|
54 |
+
if len(group) < 4:
|
55 |
+
continue
|
56 |
+
|
57 |
+
# Resize and pad each image
|
58 |
+
resized_images = [resize_and_pad(img, (512, 512)) for img in group]
|
59 |
+
|
60 |
+
# Create a blank canvas
|
61 |
+
combined_img = Image.new("RGB", (1024, 1024), (0, 0, 0))
|
62 |
+
combined_img.paste(resized_images[0], (0, 0))
|
63 |
+
combined_img.paste(resized_images[1], (512, 0))
|
64 |
+
combined_img.paste(resized_images[2], (0, 512))
|
65 |
+
combined_img.paste(resized_images[3], (512, 512))
|
66 |
+
|
67 |
+
# Resize if the final size exceeds target
|
68 |
+
if combined_img.width > target_size[0] or combined_img.height > target_size[1]:
|
69 |
+
combined_img = combined_img.resize(target_size, Image.ANTIALIAS)
|
70 |
+
|
71 |
+
output_images.append(combined_img)
|
72 |
+
|
73 |
+
return output_images
|
74 |
+
|
75 |
+
def process_images(uploaded_images):
|
76 |
+
"""Main processing function."""
|
77 |
+
images = [Image.open(img) for img in uploaded_images]
|
78 |
+
combined_images = combine_images(images)
|
79 |
+
result_paths = []
|
80 |
+
|
81 |
+
# Save combined images
|
82 |
+
output_dir = "output_images"
|
83 |
+
os.makedirs(output_dir, exist_ok=True)
|
84 |
+
for idx, img in enumerate(combined_images):
|
85 |
+
output_path = os.path.join(output_dir, f"combined_{idx + 1}.png")
|
86 |
+
img.save(output_path)
|
87 |
+
result_paths.append(output_path)
|
88 |
+
|
89 |
+
# Create a ZIP file
|
90 |
+
zip_path = "combined_images.zip"
|
91 |
+
shutil.make_archive("combined_images", 'zip', output_dir)
|
92 |
+
|
93 |
+
return zip_path
|
94 |
+
|
95 |
+
# Gradio UI
|
96 |
+
interface = gr.Interface(
|
97 |
+
fn=process_images,
|
98 |
+
inputs=gr.inputs.File(file_types=[".png", ".jpg", ".jpeg"], label="Upload Images", type="file", multi=True),
|
99 |
+
outputs=gr.outputs.File(label="Download ZIP"),
|
100 |
+
title="Image Resizer and Combiner",
|
101 |
+
description="Upload multiple images. This tool will resize and pad them to match a consistent size, then combine every four images into one. The output will be resized if it exceeds 2048x2048, and all results are available as a ZIP file."
|
102 |
+
)
|
103 |
+
|
104 |
+
interface.launch()
|