|
|
import torch
|
|
|
import comfy.utils
|
|
|
import nodes
|
|
|
|
|
|
from .constants import get_category, get_name
|
|
|
|
|
|
|
|
|
class RgthreeImageResize:
|
|
|
"""Image Resize."""
|
|
|
|
|
|
NAME = get_name("Image Resize")
|
|
|
CATEGORY = get_category()
|
|
|
|
|
|
@classmethod
|
|
|
def INPUT_TYPES(cls):
|
|
|
return {
|
|
|
"required": {
|
|
|
"image": ("IMAGE",),
|
|
|
"measurement": (["pixels", "percentage"],),
|
|
|
"width": (
|
|
|
"INT", {
|
|
|
"default": 0,
|
|
|
"min": 0,
|
|
|
"max": nodes.MAX_RESOLUTION,
|
|
|
"step": 1,
|
|
|
"tooltip": (
|
|
|
"The width of the desired resize. A pixel value if measurement is 'pixels' or a"
|
|
|
" 100% scale percentage value if measurement is 'percentage'. Passing '0' will"
|
|
|
" calculate the dimension based on the height."
|
|
|
),
|
|
|
},
|
|
|
),
|
|
|
"height": ("INT", {
|
|
|
"default": 0,
|
|
|
"min": 0,
|
|
|
"max": nodes.MAX_RESOLUTION,
|
|
|
"step": 1
|
|
|
}),
|
|
|
"fit": (["crop", "pad", "contain"], {
|
|
|
"tooltip": (
|
|
|
"'crop' resizes so the image covers the desired width and height, and center-crops the"
|
|
|
" excess, returning exactly the desired width and height."
|
|
|
"\n'pad' resizes so the image fits inside the desired width and height, and fills the"
|
|
|
" empty space returning exactly the desired width and height."
|
|
|
"\n'contain' resizes so the image fits inside the desired width and height, and"
|
|
|
" returns the image with it's new size, with one side liekly smaller than the desired."
|
|
|
"\n\nNote, if either width or height is '0', the effective fit is 'contain'."
|
|
|
)
|
|
|
},
|
|
|
),
|
|
|
"method": (nodes.ImageScale.upscale_methods,),
|
|
|
},
|
|
|
}
|
|
|
|
|
|
RETURN_TYPES = ("IMAGE", "INT", "INT",)
|
|
|
RETURN_NAMES = ("IMAGE", "WIDTH", "HEIGHT",)
|
|
|
FUNCTION = "main"
|
|
|
DESCRIPTION = """Resize the image."""
|
|
|
|
|
|
def main(self, image, measurement, width, height, method, fit):
|
|
|
"""Resizes the image."""
|
|
|
_, H, W, _ = image.shape
|
|
|
|
|
|
if measurement == "percentage":
|
|
|
width = round(width * W / 100)
|
|
|
height = round(height * H / 100)
|
|
|
|
|
|
if (width == 0 and height == 0) or (width == W and height == H):
|
|
|
return (image, W, H)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if width == 0 or height == 0:
|
|
|
width = round(height / H * W) if width == 0 else width
|
|
|
height = round(width / W * H) if height == 0 else height
|
|
|
fit = "contain"
|
|
|
|
|
|
|
|
|
resized_width = width
|
|
|
resized_height = height
|
|
|
if fit == "crop":
|
|
|
|
|
|
if (height / H * W) > width:
|
|
|
resized_width = round(height / H * W)
|
|
|
elif (width / W * H) > height:
|
|
|
resized_height = round(width / W * H)
|
|
|
elif fit == "contain" or fit == "pad":
|
|
|
|
|
|
if (height / H * W) > width:
|
|
|
resized_height = round(width / W * H)
|
|
|
elif (width / W * H) > height:
|
|
|
resized_width = round(height / H * W)
|
|
|
|
|
|
out_image = comfy.utils.common_upscale(
|
|
|
image.clone().movedim(-1, 1), resized_width, resized_height, method, crop="disabled"
|
|
|
).movedim(1, -1)
|
|
|
OB, OH, OW, OC = out_image.shape
|
|
|
|
|
|
if fit != "contain":
|
|
|
|
|
|
|
|
|
if OW > width:
|
|
|
out_image = out_image.narrow(-2, (OW - width) // 2, width)
|
|
|
if OH > height:
|
|
|
out_image = out_image.narrow(-3, (OH - height) // 2, height)
|
|
|
|
|
|
OB, OH, OW, OC = out_image.shape
|
|
|
if width != OW or height != OH:
|
|
|
padded_image = torch.zeros((OB, height, width, OC), dtype=image.dtype, device=image.device)
|
|
|
x = (width - OW) // 2
|
|
|
y = (height - OH) // 2
|
|
|
for b in range(OB):
|
|
|
padded_image[b, y:y + OH, x:x + OW, :] = out_image[b]
|
|
|
out_image = padded_image
|
|
|
|
|
|
return (out_image, out_image.shape[2], out_image.shape[1])
|
|
|
|