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)