File size: 3,636 Bytes
ad22797
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785cdf8
 
ad22797
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785cdf8
ad22797
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b73272f
 
ad22797
 
 
 
 
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
import gradio as gr
from PIL import Image, ImageStat
import numpy as np
import os
import shutil
import random

def get_dominant_color(image):
    """Get the dominant color of an image or return None."""
    try:
        stat = ImageStat.Stat(image)
        r, g, b = stat.mean[:3]
        return int(r), int(g), int(b)
    except:
        return None

def resize_and_pad(image, target_size):
    """Resize the image and pad it to match target size."""
    img = image.convert("RGB")
    aspect_ratio = img.width / img.height
    target_aspect_ratio = target_size[0] / target_size[1]

    if aspect_ratio > target_aspect_ratio:
        # Wider than target aspect ratio
        new_width = target_size[0]
        new_height = int(new_width / aspect_ratio)
    else:
        # Taller than target aspect ratio
        new_height = target_size[1]
        new_width = int(new_height * aspect_ratio)

    # Use Image.Resampling.LANCZOS instead of Image.ANTIALIAS
    img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)

    # Determine padding color
    dominant_color = get_dominant_color(img)
    if dominant_color is None:
        dominant_color = (255, 255, 255) if random.choice([True, False]) else (0, 0, 0)

    # Create a new image with the determined background color
    new_img = Image.new("RGB", target_size, dominant_color)
    offset = ((target_size[0] - new_width) // 2, (target_size[1] - new_height) // 2)
    new_img.paste(img, offset)
    return new_img

def combine_images(images, target_size=(2048, 2048)):
    """Combine four images into a single one."""
    num_images = len(images)
    output_images = []

    # Group images into chunks of 4
    for i in range(0, num_images, 4):
        group = images[i:i+4]
        if len(group) < 4:
            continue

        # Resize and pad each image
        resized_images = [resize_and_pad(img, (512, 512)) for img in group]

        # Create a blank canvas
        combined_img = Image.new("RGB", (1024, 1024), (0, 0, 0))
        combined_img.paste(resized_images[0], (0, 0))
        combined_img.paste(resized_images[1], (512, 0))
        combined_img.paste(resized_images[2], (0, 512))
        combined_img.paste(resized_images[3], (512, 512))

        # Resize if the final size exceeds target
        if combined_img.width > target_size[0] or combined_img.height > target_size[1]:
            combined_img = combined_img.resize(target_size, Image.Resampling.LANCZOS)

        output_images.append(combined_img)

    return output_images

def process_images(uploaded_images):
    """Main processing function."""
    images = [Image.open(img) for img in uploaded_images]
    combined_images = combine_images(images)
    result_paths = []

    # Save combined images
    output_dir = "output_images"
    os.makedirs(output_dir, exist_ok=True)
    for idx, img in enumerate(combined_images):
        output_path = os.path.join(output_dir, f"combined_{idx + 1}.png")
        img.save(output_path)
        result_paths.append(output_path)

    # Create a ZIP file
    zip_path = "combined_images.zip"
    shutil.make_archive("combined_images", 'zip', output_dir)

    return zip_path

# Gradio UI
interface = gr.Interface(
    fn=process_images,
    inputs=gr.Files(file_types=["image"], label="Upload Images"),
    outputs=gr.File(label="Download ZIP"),
    title="Image Resizer and Combiner",
    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."
)

interface.launch()