83 lines
3.3 KiB
Python
83 lines
3.3 KiB
Python
from enum import Enum
|
|
from PIL import Image
|
|
|
|
|
|
class ResizeMode(Enum):
|
|
RESIZE = 0 # just resize
|
|
RESIZE_TO_FILL = 1 # crop and resize
|
|
RESIZE_TO_FIT = 2 # resize and fill
|
|
|
|
|
|
def resize_image(im: Image.Image, width: int, height: int, resize_mode=ResizeMode.RESIZE_TO_FIT):
|
|
"""
|
|
Resizes an image with the specified resize_mode, width, and height.
|
|
|
|
Args:
|
|
resize_mode: The mode to use when resizing the image.
|
|
0: Resize the image to the specified width and height.
|
|
1: Resize the image to fill the specified width and height, maintaining the aspect ratio, and then center the image within the dimensions, cropping the excess.
|
|
2: Resize the image to fit within the specified width and height, maintaining the aspect ratio, and then center the image within the dimensions, filling empty with data from image.
|
|
im: The image to resize.
|
|
width: The width to resize the image to.
|
|
height: The height to resize the image to.
|
|
upscaler_name: The name of the upscaler to use. If not provided, defaults to opts.upscaler_for_img2img.
|
|
"""
|
|
|
|
def resize(im: Image.Image, w, h):
|
|
return im.resize((w, h), resample=Image.LANCZOS)
|
|
|
|
if resize_mode == ResizeMode.RESIZE:
|
|
res = resize(im, width, height)
|
|
|
|
elif resize_mode == ResizeMode.RESIZE_TO_FILL:
|
|
ratio = width / height
|
|
src_ratio = im.width / im.height
|
|
|
|
src_w = width if ratio > src_ratio else im.width * height // im.height
|
|
src_h = height if ratio <= src_ratio else im.height * width // im.width
|
|
|
|
resized = resize(im, src_w, src_h)
|
|
res = Image.new("RGB", (width, height))
|
|
res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2))
|
|
|
|
else:
|
|
ratio = width / height
|
|
src_ratio = im.width / im.height
|
|
|
|
src_w = width if ratio < src_ratio else im.width * height // im.height
|
|
src_h = height if ratio >= src_ratio else im.height * width // im.width
|
|
|
|
resized = resize(im, src_w, src_h)
|
|
res = Image.new("RGB", (width, height))
|
|
res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2))
|
|
|
|
if ratio < src_ratio:
|
|
fill_height = height // 2 - src_h // 2
|
|
if fill_height > 0:
|
|
res.paste(resized.resize((width, fill_height), box=(0, 0, width, 0)), box=(0, 0))
|
|
res.paste(
|
|
resized.resize((width, fill_height), box=(0, resized.height, width, resized.height)),
|
|
box=(0, fill_height + src_h),
|
|
)
|
|
elif ratio > src_ratio:
|
|
fill_width = width // 2 - src_w // 2
|
|
if fill_width > 0:
|
|
res.paste(resized.resize((fill_width, height), box=(0, 0, 0, height)), box=(0, 0))
|
|
res.paste(
|
|
resized.resize((fill_width, height), box=(resized.width, 0, resized.width, height)),
|
|
box=(fill_width + src_w, 0),
|
|
)
|
|
|
|
return res
|
|
|
|
|
|
def flatten_image(im: Image.Image, bgcolor="#ffffff"):
|
|
"""replaces transparency with bgcolor (example: "#ffffff"), returning an RGB mode image with no transparency"""
|
|
|
|
if im.mode == "RGBA":
|
|
background = Image.new("RGBA", im.size, bgcolor)
|
|
background.paste(im, mask=im)
|
|
im = background
|
|
|
|
return im.convert("RGB")
|