123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
import math
|
|
|
|
from comfy_api.latest import io
|
|
|
|
|
|
class ImageSizeCalculator(io.ComfyNode):
|
|
@classmethod
|
|
def define_schema(cls) -> io.Schema:
|
|
return io.Schema(
|
|
node_id="ImageSizeCalculator",
|
|
display_name="🐧 Image Size Calculator",
|
|
category="SuperNodes/Tools",
|
|
description="Calculates width and height based on an aspect ratio and a target dimension size, rounding to a specific multiple.",
|
|
inputs=[
|
|
io.Int.Input(
|
|
"aspect_w",
|
|
default=1,
|
|
min=1,
|
|
max=1024,
|
|
step=1,
|
|
tooltip="The width ratio of the desired aspect ratio (e.g., 16 for 16:9).",
|
|
),
|
|
io.Int.Input(
|
|
"aspect_h",
|
|
default=1,
|
|
min=1,
|
|
max=1024,
|
|
step=1,
|
|
tooltip="The height ratio of the desired aspect ratio (e.g., 9 for 16:9).",
|
|
),
|
|
io.Combo.Input(
|
|
"mode",
|
|
options=["max_size", "min_size", "megapixels"],
|
|
tooltip="Determines if the size applies to max/min dimension, or if target is total megapixels.",
|
|
),
|
|
io.Int.Input(
|
|
"size",
|
|
default=1024,
|
|
min=1,
|
|
max=32768,
|
|
step=1,
|
|
tooltip="The target length for the dimension specified by dimension mode.",
|
|
),
|
|
io.Float.Input(
|
|
"megapixels",
|
|
default=1.00,
|
|
min=0.01,
|
|
max=1024.0,
|
|
step=0.01,
|
|
tooltip="The target total megapixels when mode is 'megapixels'.",
|
|
),
|
|
io.Int.Input(
|
|
"multiple_of",
|
|
default=16,
|
|
min=1,
|
|
max=1024,
|
|
step=1,
|
|
tooltip="The final dimensions will be rounded to the nearest multiple of this value.",
|
|
),
|
|
],
|
|
outputs=[
|
|
io.Int.Output(
|
|
display_name="width", tooltip="The calculated width."
|
|
),
|
|
io.Int.Output(
|
|
display_name="height", tooltip="The calculated height."
|
|
),
|
|
io.Int.Output(
|
|
display_name="aspect_w", tooltip="Passthrough width aspect."
|
|
),
|
|
io.Int.Output(
|
|
display_name="aspect_h",
|
|
tooltip="Passthrough height aspect.",
|
|
),
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
def execute(
|
|
cls, aspect_w, aspect_h, mode, size, megapixels, multiple_of
|
|
) -> io.NodeOutput:
|
|
# Calculate aspect ratio
|
|
ratio = aspect_w / aspect_h
|
|
|
|
target_w = 0.0
|
|
target_h = 0.0
|
|
|
|
if mode == "max_size":
|
|
if aspect_w >= aspect_h:
|
|
# Width is the longest side
|
|
target_w = size
|
|
target_h = size / ratio
|
|
else:
|
|
# Height is the longest side
|
|
target_h = size
|
|
target_w = size * ratio
|
|
elif mode == "min_size":
|
|
if aspect_w <= aspect_h:
|
|
# Width is the shortest side
|
|
target_w = size
|
|
target_h = size / ratio
|
|
else:
|
|
# Height is the shortest side
|
|
target_h = size
|
|
target_w = size * ratio
|
|
elif mode == "megapixels":
|
|
target_pixels = megapixels * 1024 * 1024
|
|
target_h = math.sqrt(target_pixels / ratio)
|
|
target_w = target_h * ratio
|
|
|
|
# Round to nearest multiple, breaking exact ties downwards
|
|
final_w = math.ceil(target_w / multiple_of - 0.5 - 1e-9) * multiple_of
|
|
final_h = math.ceil(target_h / multiple_of - 0.5 - 1e-9) * multiple_of
|
|
|
|
# Ensure we don't return 0 if the size is very small relative to multiple_of
|
|
final_w = max(multiple_of, final_w)
|
|
final_h = max(multiple_of, final_h)
|
|
|
|
return io.NodeOutput(final_w, final_h, aspect_w, aspect_h)
|
|
|
|
|
|
NODE = [ImageSizeCalculator]
|