From c72a941d9d84a77b110b09c381c464f4b45c0087 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Wed, 23 Jul 2025 08:19:43 +0500 Subject: [PATCH 1/3] small refactor --- node_crop_pad.py | 11 +++++------ nodes_upscale.py | 2 -- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/node_crop_pad.py b/node_crop_pad.py index db8c74f..d996aaa 100644 --- a/node_crop_pad.py +++ b/node_crop_pad.py @@ -25,11 +25,6 @@ from .slot_types import ( # ---------------------------------------------------------- -_return_types_crop_pad = ( - _IO.FLOAT, - _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, - _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, -) _return_ttips_crop_pad = _frozendict({ 'upscale': "The actual uniform upscale value to do.", @@ -92,7 +87,11 @@ class BestResolutionUpscaledCropPad: OUTPUT_NODE = True FUNCTION = 'main' - RETURN_TYPES = _return_types_crop_pad + RETURN_TYPES = ( + _IO.FLOAT, + _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, + _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, + ) RETURN_NAMES = tuple(_return_ttips_crop_pad.keys()) OUTPUT_TOOLTIPS = tuple(_return_ttips_crop_pad.values()) diff --git a/nodes_upscale.py b/nodes_upscale.py index bff096b..06a60df 100644 --- a/nodes_upscale.py +++ b/nodes_upscale.py @@ -6,14 +6,12 @@ Advanced versions of nodes - with upscale. import typing as _t from inspect import cleandoc as _cleandoc -import sys as _sys from frozendict import deepfreeze as _deepfreeze, frozendict as _frozendict from comfy.comfy_types.node_typing import IO as _IO 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, upscale_result_from_approx_wh as _upscale_result_from_approx_wh From 35f9dc52276827291caaa3e1e755c155097ca036 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:30:40 +0500 Subject: [PATCH 2/3] `BestResolutionScale` --- CHANGELOG.md | 4 +++ __init__.py | 5 ++++ _funcs.py | 18 +++++++----- node_scale.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ slot_types.py | 1 + 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 node_scale.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c2df6e7..54f5d91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ - Add options for `crop/pad` node - to determine the order of [crop/pad] -> upscale -> [crop/pad]. - Add node for auto-detecting USDU-padding from initial res. +# v1.1.2 + +- New node: `Scale (Best-Res)` + # v1.1.1 - This `CHANGELOG.md` file. diff --git a/__init__.py b/__init__.py index e8a0590..05c566b 100644 --- a/__init__.py +++ b/__init__.py @@ -5,6 +5,7 @@ import typing as _t from .node_crop_pad import BestResolutionUpscaledCropPad +from .node_scale import BestResolutionScale from .nodes_prims import * from .nodes_simple import * from .nodes_upscale import * @@ -15,6 +16,8 @@ NODE_CLASS_MAPPINGS: _t.Dict[str, type] = { "BestResolutionFromAspectRatio": BestResolutionFromAspectRatio, "BestResolutionSimple": BestResolutionSimple, + "BestResolutionScale": BestResolutionScale, + "BestResolutionPrimCropPadStrategy": BestResolutionPrimCropPadStrategy, "BestResolutionPrimResPriority": BestResolutionPrimResPriority, @@ -26,6 +29,8 @@ NODE_DISPLAY_NAME_MAPPINGS: _t.Dict[str, str] = { "BestResolutionFromAspectRatio": "Best-Res (ratio)", "BestResolutionSimple": "Best-Res (simple)", + "BestResolutionScale": "Scale (Best-Res)", + "BestResolutionPrimCropPadStrategy": "Crop-Pad Strategy (Best-Res)", "BestResolutionPrimResPriority": "Priority (Best-Res)", diff --git a/_funcs.py b/_funcs.py index f701058..8509205 100644 --- a/_funcs.py +++ b/_funcs.py @@ -137,7 +137,7 @@ def _format_report_square_part( def format_report_simple( width_f: float, height_f: _t_number, step: int, width: int, n_steps_x: int, height: int, n_steps_y: int, - target_square_size: _t_number = None + target_square_size: _t_number = None, prefix: str = '', suffix: str = '', ) -> str: square_side_text = _format_report_square_part(width_f, height_f, width, height, target_square_size) @@ -150,16 +150,18 @@ def format_report_simple( ) return ( + f"{prefix}" f"{width}/{height}{square_side_text}\n" f"{n_steps_x} * {step} / {n_steps_y} * {step}\n" f"{ar_text}" + f"{suffix}" ) def simple_result_from_approx_wh( width_f: float, height_f: _t_number, step: int, show: bool = True, - unique_id: str = None, target_square_size: _t_number = None + unique_id: str = None, target_square_size: _t_number = None, status_prefix: str = '', status_suffix: str = '' ) -> ResultSimple: """Final part of the main func for simple (non-upscale) nodes - when desired width/height are already calculated.""" step = number_to_int(step) @@ -170,11 +172,13 @@ def simple_result_from_approx_wh( if not unique_id: return result - text = ( - format_report_simple(width_f, height_f, step, width, n_steps_x, height, n_steps_y, target_square_size) - if show - else None - ) + text = None + if show: + text = format_report_simple( + width_f, height_f, step, + width, n_steps_x, height, n_steps_y, + target_square_size, status_prefix, status_suffix + ) _show_text_on_node(text, unique_id) return result diff --git a/node_scale.py b/node_scale.py new file mode 100644 index 0000000..51e2533 --- /dev/null +++ b/node_scale.py @@ -0,0 +1,79 @@ +# encoding: utf-8 +""" +""" + +import typing as _t + +from inspect import cleandoc as _cleandoc +from math import sqrt as _sqrt + +from frozendict import deepfreeze as _deepfreeze + +from comfy.comfy_types.node_typing import IO as _IO + +from ._funcs import simple_result_from_approx_wh as _simple_result_from_approx_wh +from . import _meta +from .docstring_formatter import format_docstring as _format_docstring +from .slot_types import ( + type_dict_res as _type_dict_res, + type_dict_step_default as _type_dict_step_default, + upscale_in_type as _upscale_in_type +) + +_return_types = (_IO.INT, _IO.INT, _IO.FLOAT) +_return_names = ('width', 'height', 'scale') +_scale_type_dict = {k: v for k, v in _upscale_in_type[1].items() if k != 'tooltip'} +_scale_type_dict['min'] = 0.001 + +_input_types = _deepfreeze({ + 'required': { + 'width': (_IO.INT, _type_dict_res), + 'height': (_IO.INT, _type_dict_res), + 'step': (_IO.INT, _type_dict_step_default), + 'scale': (_IO.FLOAT, _scale_type_dict), + 'direction': (_IO.BOOLEAN, {'default': True, 'label_on': 'res * scale', 'label_off': 'res / scale', 'tooltip': ( + "Sometimes it's easier to specify scale by it's inverse: how much to scale DOWN by. This toggle controls that." + )}), + }, + 'hidden': { + 'unique_id': 'UNIQUE_ID', # used for text display at the bottom of the node + }, +}) + + +class BestResolutionScale: + """ + Scale width and height by the same value + round them. + """ + NODE_NAME = 'BestResolutionScale' + CATEGORY = _meta.category + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) + + OUTPUT_NODE = True + + FUNCTION = 'main' + RETURN_TYPES = _return_types + RETURN_NAMES = _return_names + + @classmethod + def INPUT_TYPES(cls): + return _input_types + + @staticmethod + def main( + width: int, height: int, step: int, scale: float, direction: bool, + # show: bool, + unique_id: str = None + ) -> _t.Tuple[int, int, float]: + scale = float(scale) + if not direction: + scale = 1.0 / scale + width_f = scale * width + height_f = scale * height + out_width, out_height = _simple_result_from_approx_wh( + width_f, height_f, step, + # show, + unique_id=unique_id, target_square_size=_sqrt(width_f * height_f), + status_suffix=f"\n({width}/{height}) * {scale:.3f} scale" + ) + return out_width, out_height, scale diff --git a/slot_types.py b/slot_types.py index d79a56a..1e8a860 100644 --- a/slot_types.py +++ b/slot_types.py @@ -23,6 +23,7 @@ def number_type_dict(default: int = 512, min: int = 1, max: int = _sys.maxsize, type_dict_res = number_type_dict(1024) +type_dict_step_default = number_type_dict(8) type_dict_step_init = number_type_dict(8*2*3) type_dict_step_upscale1 = number_type_dict(8*2*3*3) From cd228fa5d9601e563ac217b12ca4a40dbc5f0dd0 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:31:18 +0500 Subject: [PATCH 3/3] `v1.1.2` --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 260fe20..42057d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "best-resolution" description = "QoL nodes for semi-automatic calculation of the best (most optimal) sampling resolution \n• compatible with ANY model (from now or the future), \n• accounting for upscale... \n• ...and pixel-step." -version = "1.1.1" +version = "1.1.2" authors = [ {name = "Lex Darlog"} ]