File size: 3,167 Bytes
e289c5c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586e144
e289c5c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
from PIL import Image, ImageOps
import numpy as np
import cv2


def get_new_size_and_padding(old_w, old_h, target_ratio):
    old_ratio = old_w / old_h
    if old_ratio > target_ratio:
        # Image is wider than target: pad height
        new_w = old_w
        new_h = int(old_w / target_ratio)
        pad_top = (new_h - old_h) // 2
        pad_bottom = new_h - old_h - pad_top
        pad_left = pad_right = 0
    else:
        # Image is taller than target: pad width
        new_h = old_h
        new_w = int(old_h * target_ratio)
        pad_left = (new_w - old_w) // 2
        pad_right = new_w - old_w - pad_left
        pad_top = pad_bottom = 0
    return (new_w, new_h), (pad_left, pad_top, pad_right, pad_bottom)


def image_filler(img, padding):
    # Use OpenCV to blur the border region for a simple "image filler"
    np_img = np.array(img)
    h, w = np_img.shape[:2]
    pad_left, pad_top, pad_right, pad_bottom = padding

    # Create a blurred version of the image
    blurred = cv2.GaussianBlur(np_img, (51, 51), 0)

    # Create a new image with the blurred background
    new_h = h + pad_top + pad_bottom
    new_w = w + pad_left + pad_right
    result = np.zeros((new_h, new_w, 3), dtype=np.uint8)
    result[:, :] = blurred[0, 0]  # Fill with a color from the image

    # Place the blurred image in the background
    result[:, :] = blurred[0, 0]
    result[pad_top : pad_top + h, pad_left : pad_left + w] = np_img

    # Blend the edges for a smooth transition
    # (For simplicity, just use the blurred background)
    return Image.fromarray(result)


def resize_with_border(image, aspect_ratio, border_fill):
    # Parse aspect ratio
    w_ratio, h_ratio = map(int, aspect_ratio.split(":"))
    target_ratio = w_ratio / h_ratio

    # Ensure image is RGB
    image = image.convert("RGB")
    old_w, old_h = image.size

    (new_w, new_h), padding = get_new_size_and_padding(old_w, old_h, target_ratio)

    if border_fill == "White":
        # Use Pillow's expand with white fill
        result = ImageOps.expand(image, border=padding, fill=(255, 255, 255))
    else:
        # Use image filler (blurred border)
        result = image_filler(image, padding)

    # Resize to exact target size (optional, in case of rounding)
    result = result.resize((new_w, new_h), Image.LANCZOS)
    return result


aspect_ratios = ["1:1", "4:3", "16:9", "3:2", "21:9", "9:16"]

with gr.Blocks() as demo:
    gr.Markdown("# Image Resizer with Border Fill")
    with gr.Row():
        with gr.Column():
            image_input = gr.Image(type="pil", label="Upload Image")
            aspect_input = gr.Dropdown(
                aspect_ratios, value="1:1", label="Target Aspect Ratio"
            )
            fill_input = gr.Radio(
                ["White", "Image Filler"], value="White", label="Border Fill"
            )
            submit_btn = gr.Button("Resize Image")
        with gr.Column():
            image_output = gr.Image(type="pil", label="Resized Image")
    submit_btn.click(
        resize_with_border,
        inputs=[image_input, aspect_input, fill_input],
        outputs=image_output,
    )

demo.launch()