File size: 11,285 Bytes
5121904
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4308008
 
5121904
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import gradio as gr
from PIL import Image
import numpy as np

def create_empty_image():
    """
    Create an empty transparent image (512x512, RGBA mode).
    :return: Empty PIL.Image object.
    """
    return Image.new("RGBA", (512, 512), (0, 0, 0, 0))

def overlay_images(images, alphas, positions):
    """
    Overlay multiple semi-transparent layers and control their positions.
    :param images: List of uploaded images (PIL.Image objects).
    :param alphas: List of transparency values for each layer (floats between 0 and 1).
    :param positions: List of positions for each layer, format: [(x1, y1), (x2, y2), ...].
    :return: Overlayed image with transparent background, overlayed image with black background, and list of individual layer images.
    """
    if not images:
        return None, None, []

    # Create a transparent canvas (1024x1024)
    transparent_canvas = Image.new("RGBA", (1024, 1024), (0, 0, 0, 0))
    # Create a black canvas (1024x1024)
    black_canvas = Image.new("RGBA", (1024, 1024), (0, 0, 0, 255))
    layer_images = []  # Store individual layer images

    # Overlay each layer
    for i, img in enumerate(images):
        # Ensure the image is a PIL.Image object
        if not isinstance(img, Image.Image):
            img = create_empty_image()
        # Resize the layer to 512x512
        layer = img.convert("RGBA").resize((512, 512))
        # Set transparency
        layer = Image.fromarray(
            (np.array(layer) * np.array([1, 1, 1, alphas[i]])).astype(np.uint8)
        )
        # Get layer position
        x, y = positions[i]
        # Expand from bottom-left to top-right
        x_offset = x  # X coordinate starts from 0 and expands to the right
        y_offset = 1024 - y - layer.height  # Y coordinate starts from the bottom and expands upward
        # Paste the layer onto the transparent canvas
        transparent_canvas.paste(layer, (x_offset, y_offset), layer)
        # Paste the layer onto the black canvas
        black_canvas.paste(layer, (x_offset, y_offset), layer)

        # Generate individual layer image
        layer_canvas = Image.new("RGBA", (1024, 1024), (0, 0, 0, 0))
        layer_canvas.paste(layer, (x_offset, y_offset), layer)
        layer_images.append(layer_canvas)

    # If there are fewer than 4 layers, fill with empty images
    while len(layer_images) < 4:
        layer_images.append(create_empty_image())

    return transparent_canvas, black_canvas, layer_images

def crop_image(image, crop_x_min, crop_x_max, crop_y_min, crop_y_max):
    """
    Crop an image.
    :param image: Input image (PIL.Image object).
    :param crop_x_min: X-axis crop start point.
    :param crop_x_max: X-axis crop end point.
    :param crop_y_min: Y-axis crop start point.
    :param crop_y_max: Y-axis crop end point.
    :return: Cropped image (PIL.Image object).
    """
    if image is None:
        return None
    # Ensure the crop range is within the image dimensions
    x_min = max(0, min(crop_x_min, image.width))
    x_max = max(0, min(crop_x_max, image.width))
    y_min = max(0, min(crop_y_min, image.height))
    y_max = max(0, min(crop_y_max, image.height))
    # Crop the image
    return image.crop((x_min, y_min, x_max, y_max))

def update_output(image1, image2, image3, image4, alpha1, alpha2, alpha3, alpha4, x1, y1, x2, y2, x3, y3, x4, y4, crop_x_min, crop_x_max, crop_y_min, crop_y_max):
    """
    Update the output images.
    :param image1, image2, image3, image4: Uploaded images.
    :param alpha1, alpha2, alpha3, alpha4: Transparency values for each layer.
    :param x1, y1, x2, y2, x3, y3, x4, y4: Positions for each layer.
    :param crop_x_min: X-axis crop start point.
    :param crop_x_max: X-axis crop end point.
    :param crop_y_min: Y-axis crop start point.
    :param crop_y_max: Y-axis crop end point.
    :return: Cropped transparent background image, black background image, and individual layer images.
    """
    # Print logs to check the type and content of each input
    print("image1:", type(image1), image1)
    print("image2:", type(image2), image2)
    print("image3:", type(image3), image3)
    print("image4:", type(image4), image4)
    print("alpha1:", type(alpha1), alpha1)
    print("alpha2:", type(alpha2), alpha2)
    print("alpha3:", type(alpha3), alpha3)
    print("alpha4:", type(alpha4), alpha4)
    print("x1:", type(x1), x1)
    print("y1:", type(y1), y1)
    print("x2:", type(x2), x2)
    print("y2:", type(y2), y2)
    print("x3:", type(x3), x3)
    print("y3:", type(y3), y3)
    print("x4:", type(x4), x4)
    print("y4:", type(y4), y4)
    print("crop_x_min:", type(crop_x_min), crop_x_min)
    print("crop_x_max:", type(crop_x_max), crop_x_max)
    print("crop_y_min:", type(crop_y_min), crop_y_min)
    print("crop_y_max:", type(crop_y_max), crop_y_max)

    # If an image is None, use an empty image
    images = [
        image1 if image1 is not None else create_empty_image(),
        image2 if image2 is not None else create_empty_image(),
        image3 if image3 is not None else create_empty_image(),
        image4 if image4 is not None else create_empty_image()
    ]
    alphas = [alpha1, alpha2, alpha3, alpha4]  # Transparency list
    positions = [(x1, y1), (x2, y2), (x3, y3), (x4, y4)]  # Position list

    # Call the overlay function
    transparent_image, black_image, layer_images = overlay_images(images, alphas, positions)

    # Crop the output images
    transparent_image = crop_image(transparent_image, crop_x_min, crop_x_max, crop_y_min, crop_y_max)
    black_image = crop_image(black_image, crop_x_min, crop_x_max, crop_y_min, crop_y_max)
    layer_images = [crop_image(img, crop_x_min, crop_x_max, crop_y_min, crop_y_max) for img in layer_images]

    # Return 6 values (cropped transparent background image + black background image + 4 individual layer images)
    return [transparent_image, black_image] + layer_images

# Example data
example_images = [
    Image.open("芙宁娜_yellow.webp") if "芙宁娜_yellow.webp" else create_empty_image(),
    Image.open("妮露_blue.webp") if "妮露_blue.webp" else create_empty_image(),
    create_empty_image(),  # Layer 3 is an empty image
    create_empty_image()   # Layer 4 is an empty image
]
example_alphas = [1.0, 1.0, 1.0, 1.0]  # Example transparency values
example_positions = [(101, 0), (264, 0), (0, 0), (0, 0)]  # Example positions
example_crop_x = (160, 850)  # Example X-axis crop range
example_crop_y = (360, 1020)  # Example Y-axis crop range

# Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("## 🎨 Layer Overlay Application")
    gr.Markdown("Upload multiple semi-transparent layers (PNG format), set transparency and position, and generate the overlayed image.")

    with gr.Row():
        # Left column: Inputs
        with gr.Column():
            gr.Markdown("### Upload Layers")
            image1 = gr.Image(label="Layer 1", type="pil", image_mode="RGBA")
            image2 = gr.Image(label="Layer 2", type="pil", image_mode="RGBA")
            image3 = gr.Image(label="Layer 3", type="pil", image_mode="RGBA")
            image4 = gr.Image(label="Layer 4", type="pil", image_mode="RGBA")

            gr.Markdown("### Set Transparency")
            alpha1 = gr.Slider(0, 1, value=1, label="Layer 1 Transparency")
            alpha2 = gr.Slider(0, 1, value=1, label="Layer 2 Transparency")
            alpha3 = gr.Slider(0, 1, value=1, label="Layer 3 Transparency")
            alpha4 = gr.Slider(0, 1, value=1, label="Layer 4 Transparency")

            gr.Markdown("### Set Positions")
            with gr.Row():
                x1 = gr.Slider(0, 512, value=0, label="Layer 1 X Position")
                y1 = gr.Slider(0, 512, value=0, label="Layer 1 Y Position")
            with gr.Row():
                x2 = gr.Slider(0, 512, value=0, label="Layer 2 X Position")
                y2 = gr.Slider(0, 512, value=0, label="Layer 2 Y Position")
            with gr.Row():
                x3 = gr.Slider(0, 512, value=0, label="Layer 3 X Position")
                y3 = gr.Slider(0, 512, value=0, label="Layer 3 Y Position")
            with gr.Row():
                x4 = gr.Slider(0, 512, value=0, label="Layer 4 X Position")
                y4 = gr.Slider(0, 512, value=0, label="Layer 4 Y Position")

            gr.Markdown("### Set Crop Range")
            with gr.Row():
                crop_x_min = gr.Slider(0, 1024, value=0, label="X-axis Crop Start")
                crop_x_max = gr.Slider(0, 1024, value=1024, label="X-axis Crop End")
            with gr.Row():
                crop_y_min = gr.Slider(0, 1024, value=0, label="Y-axis Crop Start")
                crop_y_max = gr.Slider(0, 1024, value=1024, label="Y-axis Crop End")

            run_button = gr.Button("Generate Overlayed Image")

        # Right column: Outputs
        with gr.Column():
            gr.Markdown("### Overlay Results")
            transparent_output = gr.Image(label="Overlayed Image (Transparent Background)", type="pil")
            black_output = gr.Image(label="Overlayed Image (Black Background)", type="pil")
            gr.Markdown("### Individual Layer Images")
            layer1_image = gr.Image(label="Layer 1 Image", type="pil")
            layer2_image = gr.Image(label="Layer 2 Image", type="pil")
            layer3_image = gr.Image(label="Layer 3 Image", type="pil")
            layer4_image = gr.Image(label="Layer 4 Image", type="pil")

    # Bind events
    run_button.click(
        update_output,
        inputs=[
            image1, image2, image3, image4,  # Images
            alpha1, alpha2, alpha3, alpha4,  # Transparency
            x1, y1, x2, y2, x3, y3, x4, y4,  # Positions
            crop_x_min, crop_x_max,  # X-axis crop range
            crop_y_min, crop_y_max   # Y-axis crop range
        ],
        outputs=[transparent_output, black_output, layer1_image, layer2_image, layer3_image, layer4_image]
    )

    # Add examples
    gr.Examples(
        examples=[
            [
                example_images[0], example_images[1], example_images[2], example_images[3],  # Images
                example_alphas[0], example_alphas[1], example_alphas[2], example_alphas[3],  # Transparency
                example_positions[0][0], example_positions[0][1],  # Layer 1 position
                example_positions[1][0], example_positions[1][1],  # Layer 2 position
                example_positions[2][0], example_positions[2][1],  # Layer 3 position
                example_positions[3][0], example_positions[3][1],  # Layer 4 position
                example_crop_x[0], example_crop_x[1],  # X-axis crop range
                example_crop_y[0], example_crop_y[1]   # Y-axis crop range
            ]
        ],
        inputs=[
            image1, image2, image3, image4,  # Images
            alpha1, alpha2, alpha3, alpha4,  # Transparency
            x1, y1, x2, y2, x3, y3, x4, y4,  # Positions
            crop_x_min, crop_x_max,  # X-axis crop range
            crop_y_min, crop_y_max   # Y-axis crop range
        ],
        outputs=[transparent_output, black_output, layer1_image, layer2_image, layer3_image, layer4_image],
        fn=update_output,
        cache_examples=True
    )

# Launch the application
if __name__ == "__main__":
    demo.launch(share=True)