180 lines
5.0 KiB
Python
180 lines
5.0 KiB
Python
# encoding: utf-8
|
|
"""
|
|
Simple (aka no-upscale) versions of nodes.
|
|
"""
|
|
|
|
from inspect import cleandoc as _cleandoc
|
|
from math import sqrt as _sqrt
|
|
|
|
from comfy_api.latest import io as _io
|
|
|
|
from . import _io_simple as _i
|
|
from ._io_simple import _io_override
|
|
from . import _meta
|
|
from . import _tooltips as _tt
|
|
from .__docstring_formatter import format_docstring as _format_docstring
|
|
from .funcs import (
|
|
aspect_ratios_sorted as _aspect_ratios_sorted,
|
|
number_to_int as _number_to_int,
|
|
float_width_height_from_area as _float_width_height_from_area,
|
|
simple_result_from_approx_wh as _simple_result_from_approx_wh
|
|
)
|
|
|
|
# ----------------------------------------------------------
|
|
|
|
class BestResolutionSimple(_io.ComfyNode):
|
|
"""
|
|
The simplest node for easier selection of an optimal resolution:
|
|
only rounding performed, desired image size specified directly.
|
|
"""
|
|
_schema = _io.Schema(
|
|
'BestResolutionSimple',
|
|
display_name="Best-Res (simple)",
|
|
category=_meta.category,
|
|
description=_format_docstring(_cleandoc(__doc__)),
|
|
|
|
inputs=[
|
|
_io_override(_i.res, 'width', tooltip="Approximate width"),
|
|
_io_override(_i.res, 'height', tooltip="Approximate height"),
|
|
_io_override(_i.step_init, 'step'),
|
|
],
|
|
|
|
hidden=[_io.Hidden.unique_id],
|
|
|
|
outputs=[
|
|
_io.Int.Output('WIDTH', display_name='width'),
|
|
_io.Int.Output('HEIGHT', display_name='height'),
|
|
],
|
|
|
|
is_output_node=True,
|
|
)
|
|
|
|
@classmethod
|
|
def define_schema(cls) -> _io.Schema:
|
|
return cls._schema
|
|
|
|
@classmethod
|
|
def execute(
|
|
cls,
|
|
width: int, height: int, step: int,
|
|
# show: bool,
|
|
) -> _io.NodeOutput:
|
|
return _io.NodeOutput(*_simple_result_from_approx_wh(
|
|
float(width), height, step,
|
|
# show,
|
|
unique_id=cls.hidden.unique_id, target_square_size=_sqrt(width * height)
|
|
))
|
|
|
|
# ----------------------------------------------------------
|
|
|
|
class BestResolutionFromAspectRatio(_io.ComfyNode):
|
|
"""
|
|
A more advanced node for easier selection of an optimal resolution:
|
|
image size selected indirectly - by one of the sides + aspect ratio.
|
|
"""
|
|
_schema = _io.Schema(
|
|
'BestResolutionFromAspectRatio',
|
|
display_name="Best-Res (ratio)",
|
|
category=_meta.category,
|
|
description=_format_docstring(_cleandoc(__doc__)),
|
|
|
|
inputs=[
|
|
_io_override(_i.res, 'size', tooltip=_tt.size_one_side),
|
|
_io_override(_i.step_init, 'step'),
|
|
_i.toggle_size_is_big,
|
|
_i.toggle_landscape,
|
|
_i.aspect_a,
|
|
_i.aspect_b,
|
|
],
|
|
|
|
hidden=[_io.Hidden.unique_id],
|
|
|
|
outputs=list(BestResolutionSimple._schema.outputs),
|
|
|
|
is_output_node=True,
|
|
)
|
|
|
|
@classmethod
|
|
def define_schema(cls) -> _io.Schema:
|
|
return cls._schema
|
|
|
|
@classmethod
|
|
def execute(
|
|
cls,
|
|
size: int, step: int, size_is_big: bool, landscape: bool, aspect_a: float, aspect_b: float,
|
|
# show: bool,
|
|
) -> _io.NodeOutput:
|
|
aspect_big, aspect_small = _aspect_ratios_sorted(aspect_a, aspect_b)
|
|
|
|
side_main_f = float(size)
|
|
side_other_f = side_main_f * (
|
|
(aspect_small / aspect_big) if size_is_big else (aspect_big / aspect_small)
|
|
)
|
|
|
|
width_f, height_f = (side_other_f, side_main_f) if side_other_f > side_main_f else (side_main_f, side_other_f)
|
|
if not landscape:
|
|
# The opposite: height is bigger
|
|
width_f, height_f = height_f, width_f
|
|
|
|
return _io.NodeOutput(*_simple_result_from_approx_wh(
|
|
width_f, height_f, step,
|
|
# show,
|
|
unique_id=cls.hidden.unique_id, target_square_size=_sqrt(width_f * height_f)
|
|
))
|
|
|
|
# ----------------------------------------------------------
|
|
|
|
class BestResolutionFromArea(_io.ComfyNode):
|
|
"""
|
|
The most efficient way of selecting an optimal resolution:
|
|
image size selected indirectly - by the total desired resolution (area) + aspect ratio.
|
|
|
|
|
|
Desired resolution (aka image area/megapixels/pixel count) is specified with a side of a square image. This isn't
|
|
accidental: most models disclose what image resolution they're trained on, and usually they're square:
|
|
- SD 1.5 - 512x512 pixels
|
|
- SDXL - 1024x1024 pixels
|
|
|
|
|
|
By simply providing this single number and setting your aspect ratio/orientation, you get the width and height to
|
|
produce the closest total resolution to the training set, while also respecting image proportions and step-rounding.
|
|
"""
|
|
_schema = _io.Schema(
|
|
'BestResolutionFromArea',
|
|
display_name="Best-Res (area)",
|
|
category=_meta.category,
|
|
description=_format_docstring(_cleandoc(__doc__)),
|
|
|
|
inputs=[
|
|
_io_override(_i.res, 'square_size', tooltip=_tt.size_square),
|
|
_io_override(_i.step_init, 'step'),
|
|
_i.toggle_landscape,
|
|
_i.aspect_a,
|
|
_i.aspect_b,
|
|
],
|
|
|
|
hidden=[_io.Hidden.unique_id],
|
|
|
|
outputs=list(BestResolutionSimple._schema.outputs),
|
|
|
|
is_output_node=True,
|
|
)
|
|
|
|
@classmethod
|
|
def define_schema(cls) -> _io.Schema:
|
|
return cls._schema
|
|
|
|
@classmethod
|
|
def execute(
|
|
cls,
|
|
square_size: int, step: int, landscape: bool, aspect_a: float, aspect_b: float,
|
|
# show: bool,
|
|
) -> _io.NodeOutput:
|
|
square_size: int = _number_to_int(square_size)
|
|
width_f, height_f = _float_width_height_from_area(square_size, landscape, aspect_a, aspect_b)
|
|
return _io.NodeOutput(*_simple_result_from_approx_wh(
|
|
width_f, height_f, step,
|
|
# show,
|
|
unique_id=cls.hidden.unique_id, target_square_size=square_size
|
|
))
|