Files
ComfyUI/custom_nodes/rgthree-comfy/py/image_resize.py
jaidaken f09734b0ee
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Includes 30 custom nodes committed directly, 7 Civitai-exclusive
loras stored via Git LFS, and a setup script that installs all
dependencies and downloads HuggingFace-hosted models on vast.ai.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 00:56:42 +00:00

118 lines
4.4 KiB
Python

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): # pylint: disable = invalid-name, missing-function-docstring
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 one dimension is 0, then calculate the desired value from the ratio of the set dimension.
# This also implies a 'contain' fit since the width and height will be scaled with a locked
# aspect ratio.
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"
# At this point, width and height are our output height, but our resize sizes will be different.
resized_width = width
resized_height = height
if fit == "crop":
# If we resize against the opposite ratio, then choose the ratio that has the overhang.
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 we resize against the opposite ratio, then choose the ratio that has the overhang.
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":
# First, we crop, then we pad; no need to check fit (other than not 'contain') since the size
# should already be correct.
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])