From d0a9973af8246d2eb107145366c30828b87bfe5a Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 04:01:33 +0500 Subject: [PATCH 1/9] `.gitignore`: update from template by `comfy node scaffold` --- .gitignore | 87 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 7bc0973..88f2525 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,7 @@ # Organized+extended by Lex-DRL: https://github.com/Lex-DRL/git-template-gamedev -# OS-generated -# ------------ -.DS_Store* -[Tt]humbs.db -[Dd]esktop.ini +# Common +# ---------------------------- # Temp files/folders: *.tmp @@ -15,6 +12,38 @@ # Programming - general *.log +# OS-generated - Windows +# ---------------------------- + +[Tt]humbs.db +[Dd]esktop.ini + +# OS-generated - Apple +# ---------------------------- + +.DS_Store* +.AppleDouble +.LSOverride + +# ... and thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + # =========================================================================== # # IDEs @@ -22,6 +51,15 @@ # JetBrains IDEs: PyCharm / Rider .idea/ +*.iml +*.ipr +*.iws + +# vscode +.vscode/ +.claude/ +.history/ +*.code-workspace # =========================================================================== # @@ -61,7 +99,13 @@ share/python-wheels/ *.egg-info/ .installed.cfg *.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. MANIFEST +*.manifest +*.spec # Installer logs pip-log.txt @@ -77,15 +121,44 @@ htmlcov/ nosetests.xml coverage.xml *.cover -*.py,cover +*,cover .hypothesis/ .pytest_cache/ cover/ +# Translations +*.mo +*.pot + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Cookiecutter +output/ +python_boilerplate/ +cookiecutter-pypackage-env/ + +# Frontend extension +node_modules/ +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* +node.zip + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + # =========================================================================== # # Repo-specific # =========================================================================== # -# add here example_node.py From 9eb5be11665d08f437dc58867a329a5ab4ddec85 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 04:33:38 +0500 Subject: [PATCH 2/9] `LICENSE.md`: LGPLv3 --- LICENSE.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0927556 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,157 @@ +### GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the +terms and conditions of version 3 of the GNU General Public License, +supplemented by the additional permissions listed below. + +#### 0. Additional Definitions. + +As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the +GNU General Public License. + +"The Library" refers to a covered work governed by this License, other +than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + +The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +#### 1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +#### 2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + +- a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or +- b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +#### 3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a +header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + +- a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the object code with a copy of the GNU GPL and this + license document. + +#### 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + +- a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. +- c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. +- d) Do one of the following: + - 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + - 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. +- e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +#### 5. Combined Libraries. + +You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + +- a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. +- b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + +#### 6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License "or any later version" applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, you +may choose any version of the GNU Lesser General Public License ever +published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. From 0281b848882bd37154ba4650be9728b40ab8a7b0 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 04:53:51 +0500 Subject: [PATCH 3/9] `README.md`: init --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0bb31c --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# ComfyUI-BestResolution + +Nodes for semi-automatic calculation of the best (most optimal) resolution: +- compatible with ANY model (from now or the future), +- accounting for upscale +- ... and (the required) pixel-step. From 462dc2248d851c11da9ad8fe97f0416b313660a6 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 04:54:30 +0500 Subject: [PATCH 4/9] dummy/scaffolding files --- __init__.py | 10 ++++++++++ nodes.py | 5 +++++ pyproject.toml | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 __init__.py create mode 100644 nodes.py create mode 100644 pyproject.toml diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..0d04432 --- /dev/null +++ b/__init__.py @@ -0,0 +1,10 @@ +# encoding: utf-8 +""" +""" + +from .nodes import * + +NODE_CLASS_MAPPINGS = {} +NODE_DISPLAY_NAME_MAPPINGS = {} + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/nodes.py b/nodes.py new file mode 100644 index 0000000..03ef0e8 --- /dev/null +++ b/nodes.py @@ -0,0 +1,5 @@ +# encoding: utf-8 +""" +""" + +import typing as _t diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dd0211e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "comfyui-bestresolution" +description = "Nodes for semi-automatic calculation of the best (most optimal) resolution, compatible with ANY model (from now or the future), accounting for upscale and pixel-step." +version = "0.0.1" +authors = [ + {name = "Lex Darlog"} +] +license = {file = "LICENSE.md"} +readme = "README.md" +dependencies = [] + +[project.urls] +Repository = "https://github.com/Lex-DRL/ComfyUI-BestResolution" +# Used by Comfy Registry https://comfyregistry.org + +[tool.comfy] +PublisherId = "lex-drl" +DisplayName = "ComfyUI-BestResolution" +Icon = "" From f5917feb1edada4ceca6e46fbd69188ced9615b8 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 09:29:20 +0500 Subject: [PATCH 5/9] `BestResolutionSimple` --- __init__.py | 8 ++++-- node_types.py | 34 ++++++++++++++++++++++++++ nodes.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 4 +-- requirements.txt | 1 + 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 node_types.py create mode 100644 requirements.txt diff --git a/__init__.py b/__init__.py index 0d04432..95aa1ed 100644 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,11 @@ from .nodes import * -NODE_CLASS_MAPPINGS = {} -NODE_DISPLAY_NAME_MAPPINGS = {} +NODE_CLASS_MAPPINGS = { + "BestResolutionSimple": BestResolutionSimple, +} +NODE_DISPLAY_NAME_MAPPINGS = { + "BestResolutionSimple": "Best-Res (simple)", +} __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/node_types.py b/node_types.py new file mode 100644 index 0000000..d8a5765 --- /dev/null +++ b/node_types.py @@ -0,0 +1,34 @@ +# encoding: utf-8 +""" +""" + +import typing as _t + +import sys as _sys + + +def number_type_dict(default: int = 512, min: int = 1, max: int = _sys.maxsize, step: int = 1) -> _t.Dict[str, int]: + """Prepare type-dict for an input int/float parameter.""" + + # sys.maxsize is Py3's closest equivalent to 'sys.maxint' from Py2 + return { + "default": default, + "min": min, + "max": max, + "step": step + } + + +def number_to_int(value: _t.Union[int, float], min: int = 1) -> int: + if not isinstance(value, int): + if isinstance(value, float): + sign = -1 if value < 0.0 else 1 + value = int(value * sign + 0.5) * sign + else: + value = int(value) + return max(value, min) + + +type_dict_step_init = number_type_dict(48) +type_dict_step_upscale1 = number_type_dict(128) +type_dict_res = number_type_dict(512) diff --git a/nodes.py b/nodes.py index 03ef0e8..2240a5a 100644 --- a/nodes.py +++ b/nodes.py @@ -3,3 +3,66 @@ """ import typing as _t + +from frozendict import deepfreeze + +from comfy.comfy_types.node_typing import IO as _IO + +from .node_types import * + + +def _round_abs(abs_value: _t.Union[int, float], step: int): + """ + Assuming both args are positive and ``step`` is already an int, detect the closest positive (non-zero) value + which is also divisible by step. + """ + n_steps = int(float(number_to_int(abs_value)) / step + 0.5) + n_steps = max(n_steps, 1) + return step * n_steps, n_steps + + +# Tiny optimization by reusing the same immutable dict: +_input_types_simple = deepfreeze({ + "required": { + "width": (_IO.INT, dict(type_dict_res, **{'tooltip': "Approximate width"})), + "height": (_IO.INT, dict(type_dict_res, **{'tooltip': "Approximate height"})), + "step": (_IO.INT, dict(type_dict_step_init, **{'tooltip': "Resolution must be divisible by this value"})), + }, + # "hidden": {}, + # "optional": {}, +}) + + +class BestResolutionSimple: + NODE_NAME = "BestResolutionSimple" + CATEGORY = "utils/resolution" + + # OUTPUT_NODE = True # TODO + + FUNCTION = "main" + RETURN_TYPES = (_IO.INT, _IO.INT) + RETURN_NAMES = ("width", "height") + + @classmethod + def INPUT_TYPES(cls): + return _input_types_simple + + def main(self, width: int, height: int, step: int): + step = number_to_int(step) + + width, n_steps_x = _round_abs(width, step) + height, n_steps_y = _round_abs(height, step) + + width = n_steps_x * step + height = n_steps_y * step + + text = f"{width} x {height}\n{n_steps_x} * {step} x {n_steps_y} * {step}" + print(f"text: {text}") + + # The following return format is snatched from built-in PreviewAny + # and easy_nodes.show_text from (https://github.com/andrewharp/ComfyUI-EasyNodes); + # doesn't seem to be documented anywhere 🤷🏻‍♂️ + return { + # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed + "result": (width, height) + } diff --git a/pyproject.toml b/pyproject.toml index dd0211e..c500b1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ ] license = {file = "LICENSE.md"} readme = "README.md" -dependencies = [] +dependencies = ["frozendict"] [project.urls] Repository = "https://github.com/Lex-DRL/ComfyUI-BestResolution" @@ -15,5 +15,5 @@ Repository = "https://github.com/Lex-DRL/ComfyUI-BestResolution" [tool.comfy] PublisherId = "lex-drl" -DisplayName = "ComfyUI-BestResolution" +DisplayName = "Best Resolution" Icon = "" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..302328f --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +frozendict From e218e15acc40539944424fca5736f3f93c807e0f Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 12:08:40 +0500 Subject: [PATCH 6/9] `BestResolutionFromAspectRatio` --- __init__.py | 2 + node_types.py | 2 +- nodes.py | 166 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 151 insertions(+), 19 deletions(-) diff --git a/__init__.py b/__init__.py index 95aa1ed..a298851 100644 --- a/__init__.py +++ b/__init__.py @@ -6,9 +6,11 @@ from .nodes import * NODE_CLASS_MAPPINGS = { "BestResolutionSimple": BestResolutionSimple, + "BestResolutionFromAspectRatio": BestResolutionFromAspectRatio, } NODE_DISPLAY_NAME_MAPPINGS = { "BestResolutionSimple": "Best-Res (simple)", + "BestResolutionFromAspectRatio": "Best-Res (ratio)", } __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/node_types.py b/node_types.py index d8a5765..f358e39 100644 --- a/node_types.py +++ b/node_types.py @@ -31,4 +31,4 @@ def number_to_int(value: _t.Union[int, float], min: int = 1) -> int: type_dict_step_init = number_type_dict(48) type_dict_step_upscale1 = number_type_dict(128) -type_dict_res = number_type_dict(512) +type_dict_res = number_type_dict(1024) diff --git a/nodes.py b/nodes.py index 2240a5a..2cd0c2d 100644 --- a/nodes.py +++ b/nodes.py @@ -4,6 +4,9 @@ import typing as _t +from inspect import cleandoc as _cleandoc +import sys as _sys + from frozendict import deepfreeze from comfy.comfy_types.node_typing import IO as _IO @@ -11,22 +14,64 @@ from comfy.comfy_types.node_typing import IO as _IO from .node_types import * -def _round_abs(abs_value: _t.Union[int, float], step: int): +_t_number = _t.Union[int, float] + + +def _round_abs(abs_value: _t_number, step: int): """ Assuming both args are positive and ``step`` is already an int, detect the closest positive (non-zero) value which is also divisible by step. """ - n_steps = int(float(number_to_int(abs_value)) / step + 0.5) + n_steps = int(float(abs_value) / step + 0.5) n_steps = max(n_steps, 1) return step * n_steps, n_steps +def _round_width_and_height_closest_to_the_ratio(width_f: _t_number, height_f: _t_number, step: int): + """3-pass detection of the best rounded resolution. Best = closest to the desired ratio.""" + desired_width_to_height_ratio = float(width_f) / height_f + + # First pass: directly from width_f and height_f + width, n_steps_x = _round_abs(width_f, step) + height, n_steps_y = _round_abs(height_f, step) + + # Second pass: try calculating one side from already rounded another one: + height_from_width, n_steps_y_from_x = _round_abs(float(width) / desired_width_to_height_ratio, step) + width_from_height, n_steps_x_from_y = _round_abs(float(height) * desired_width_to_height_ratio, step) + + # ... and select one of three options, closest to the perfect ratio: + closest_delta = abs((float(width) / height) - desired_width_to_height_ratio) + for w, n_x, h, n_y in [ + (width, n_steps_x, height_from_width, n_steps_y_from_x), + (width_from_height, n_steps_x_from_y, height, n_steps_y), + ]: + cur_delta = abs((float(w) / h) - desired_width_to_height_ratio) + if cur_delta < closest_delta: + closest_delta = cur_delta + width, n_steps_x = w, n_x + height, n_steps_y = h, n_y + + return width, n_steps_x, height, n_steps_y + + +_48_tooltip = ( + "The default 48 is (8 * 3 * 2), so it's a safe choice because:\n" + "- it's compatible with SD1.5/XL step (divisible by 8),\n" + "- it can be upscaled by x1.5 or x1.333 at the first iteration, which is optimal for latent-upscale,\n" + "- after x1.5 upscale, if you only do x2 later (it's OK for already high resolutions) - it will be divisible " + "by 3 AND 9, which might become handy at that point, where you'll probably use UltimateSDUpscale.\n\n" + "Other values worth trying first: 64, 96, 128." +) + # Tiny optimization by reusing the same immutable dict: _input_types_simple = deepfreeze({ "required": { - "width": (_IO.INT, dict(type_dict_res, **{'tooltip': "Approximate width"})), - "height": (_IO.INT, dict(type_dict_res, **{'tooltip': "Approximate height"})), - "step": (_IO.INT, dict(type_dict_step_init, **{'tooltip': "Resolution must be divisible by this value"})), + "width": (_IO.INT, dict(type_dict_res, **{"tooltip": "Approximate width"})), + "height": (_IO.INT, dict(type_dict_res, **{"tooltip": "Approximate height"})), + "step": (_IO.INT, dict(type_dict_step_init, **{"tooltip": ( + f"Both width and height will be divisible by this value - by rounding them " + f"to the closest appropriate resolution.\n\n{_48_tooltip}" + )})), }, # "hidden": {}, # "optional": {}, @@ -34,8 +79,87 @@ _input_types_simple = deepfreeze({ class BestResolutionSimple: + """ + The simplest node for easier selection of an optimal resolution: + only rounding performed, desired image size specified directly. + """ NODE_NAME = "BestResolutionSimple" CATEGORY = "utils/resolution" + DESCRIPTION = _cleandoc(__doc__) + + # OUTPUT_NODE = True # TODO + + FUNCTION = "main" + RETURN_TYPES = (_IO.INT, _IO.INT) + # RETURN_TYPES_TOOLTIPS = {} + RETURN_NAMES = ("width", "height") + + @classmethod + def INPUT_TYPES(cls): + return _input_types_simple + + def main(self, width: int, height: int, step: int): + step = number_to_int(step) + width, n_steps_x, height, n_steps_y = _round_width_and_height_closest_to_the_ratio(width, height, step) + + text = f"{width} x {height}\n{n_steps_x} * {step} x {n_steps_y} * {step}" + # print(f"text: {text}") + + # The following return format is snatched from built-in PreviewAny + # and easy_nodes.show_text from (https://github.com/andrewharp/ComfyUI-EasyNodes); + # doesn't seem to be documented anywhere 🤷🏻‍♂️ + return { + # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed + "result": (width, height) + } + + +_tooltip_aspect = ( + "Two aspects together define an aspect ratio (16:9, 4:3, etc).\n" + "Order doesn't matter: image orientation is defined by the 'landscape' toggle.\n\n" + "The specified aspect ratio is APPROXIMATE: step parameter has priority over the exact image proportions." +) + +_input_types_orient = deepfreeze({ + "required": { + "size": (_IO.INT, dict(type_dict_res, **{"tooltip": ( + "Approximate size of one of the image sides.\nWhich one - see the 'size_is_big' and 'landscape' toggles." + )})), + "step": _input_types_simple["required"]["step"], + "size_is_big": (_IO.BOOLEAN, { + "default": True, "label_on": "bigger", "label_off": "smaller", + "tooltip": "When ON, size parameter represents the bigger image side.\nWhen OFF, it specifies the smaller one." + }), + "landscape": (_IO.BOOLEAN, { + "default": True, "label_on": "landscape", "label_off": "portrait", + "tooltip": ( + "Specifies image orientation:\n\n" + "When ON, width is bigger (image is horizontal).\n" + "When OFF, height is bigger (image is vertical)." + ) + }), + "aspect_a": (_IO.FLOAT, { + "default": 16.0, "min": 1.0, "max": _sys.float_info.max, "step": 1.0, "round": 0.001, + "tooltip": _tooltip_aspect + }), + "aspect_b": (_IO.FLOAT, { + "default": 9.0, "min": 1.0, "max": _sys.float_info.max, "step": 1.0, "round": 0.001, + "tooltip": _tooltip_aspect + }), + }, + # "hidden": {}, + # "optional": {}, +}) + + +class BestResolutionFromAspectRatio: + """ + A more advanced node for easier selection of an optimal resolution: + image size specified indirectly - by one of the sides + aspect ratio. + """ + NODE_NAME = "BestResolutionFromAspectRatio" + CATEGORY = "utils/resolution" + DESCRIPTION = _cleandoc(__doc__) # OUTPUT_NODE = True # TODO @@ -45,23 +169,29 @@ class BestResolutionSimple: @classmethod def INPUT_TYPES(cls): - return _input_types_simple + return _input_types_orient + + def main(self, size: int, step: int, size_is_big: bool, landscape: bool, aspect_a: float, aspect_b: float): + aspect_a = max(float(aspect_a), 1.0) + aspect_b = max(float(aspect_b), 1.0) + aspect_big = max(aspect_a, aspect_b) + aspect_small = min(aspect_a, aspect_b) + + side_main_f = float(size) + side_secondary_f = side_main_f * ( + (aspect_small / aspect_big) if size_is_big else (aspect_big / aspect_small) + ) + + width_f = max(side_main_f, side_secondary_f) + height_f = min(side_main_f, side_secondary_f) + if not landscape: + # The opposite: height is bigger + width_f, height_f = height_f, width_f - def main(self, width: int, height: int, step: int): step = number_to_int(step) - - width, n_steps_x = _round_abs(width, step) - height, n_steps_y = _round_abs(height, step) - - width = n_steps_x * step - height = n_steps_y * step + width, n_steps_x, height, n_steps_y = _round_width_and_height_closest_to_the_ratio(width_f, height_f, step) text = f"{width} x {height}\n{n_steps_x} * {step} x {n_steps_y} * {step}" - print(f"text: {text}") - - # The following return format is snatched from built-in PreviewAny - # and easy_nodes.show_text from (https://github.com/andrewharp/ComfyUI-EasyNodes); - # doesn't seem to be documented anywhere 🤷🏻‍♂️ return { # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed "result": (width, height) From abef3f2cc02e3ba4074cb216edb75c96a716c6c3 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 15:50:06 +0500 Subject: [PATCH 7/9] `BestResolutionFromArea` --- __init__.py | 6 +- _funcs.py | 86 ++++++++++++++++++++++++++++ node_types.py | 10 ---- nodes.py | 155 +++++++++++++++++++++++++++----------------------- 4 files changed, 173 insertions(+), 84 deletions(-) create mode 100644 _funcs.py diff --git a/__init__.py b/__init__.py index a298851..d80379d 100644 --- a/__init__.py +++ b/__init__.py @@ -5,12 +5,14 @@ from .nodes import * NODE_CLASS_MAPPINGS = { - "BestResolutionSimple": BestResolutionSimple, + "BestResolutionFromArea": BestResolutionFromArea, "BestResolutionFromAspectRatio": BestResolutionFromAspectRatio, + "BestResolutionSimple": BestResolutionSimple, } NODE_DISPLAY_NAME_MAPPINGS = { - "BestResolutionSimple": "Best-Res (simple)", + "BestResolutionFromArea": "Best-Res (area)", "BestResolutionFromAspectRatio": "Best-Res (ratio)", + "BestResolutionSimple": "Best-Res (simple)", } __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/_funcs.py b/_funcs.py new file mode 100644 index 0000000..ff10eb0 --- /dev/null +++ b/_funcs.py @@ -0,0 +1,86 @@ +# encoding: utf-8 +""" +""" + +import typing as _t + + +_t_number = _t.Union[int, float] + + +def aspect_ratios_sorted(aspect_a: float, aspect_b: float, min_clamp: float = 1.0): + """Return aspect ratio in a standard form: 2 floats, both 1+, in descending order (16:9, not 9:16).""" + aspect_a = float(max(abs(aspect_a), min_clamp)) + aspect_b = float(max(abs(aspect_b), min_clamp)) + return (aspect_b, aspect_a) if aspect_b > aspect_a else (aspect_a, aspect_b) + + +def number_to_int(value: _t.Union[int, float], min: int = 1) -> int: + if not isinstance(value, int): + if isinstance(value, float): + sign = -1 if value < 0.0 else 1 + value = int(value * sign + 0.5) * sign + else: + value = int(value) + return max(value, min) + + +def round_abs(abs_value: _t_number, step: int): + """ + Assuming both args are positive and ``step`` is already an int, detect the closest positive (non-zero) value + which is also divisible by step. + """ + n_steps = int(float(abs_value) / step + 0.5) + n_steps = max(n_steps, 1) + return step * n_steps, n_steps + + +def round_width_and_height_closest_to_the_ratio(width_f: _t_number, height_f: _t_number, step: int): + """3-pass detection of the best rounded resolution. Best = closest to the desired ratio.""" + desired_width_to_height_ratio = float(width_f) / height_f + + # First pass: directly from width_f and height_f + width, n_steps_x = round_abs(width_f, step) + height, n_steps_y = round_abs(height_f, step) + + # Second pass: try calculating one side from already rounded another one: + height_from_width, n_steps_y_from_x = round_abs(float(width) / desired_width_to_height_ratio, step) + width_from_height, n_steps_x_from_y = round_abs(float(height) * desired_width_to_height_ratio, step) + + # ... and select one of three options, closest to the perfect ratio: + closest_delta = abs((float(width) / height) - desired_width_to_height_ratio) + for w, n_x, h, n_y in [ + (width, n_steps_x, height_from_width, n_steps_y_from_x), + (width_from_height, n_steps_x_from_y, height, n_steps_y), + ]: + cur_delta = abs((float(w) / h) - desired_width_to_height_ratio) + if cur_delta < closest_delta: + closest_delta = cur_delta + width, n_steps_x = w, n_x + height, n_steps_y = h, n_y + + return width, n_steps_x, height, n_steps_y + + +def simple_result_from_approx_wh(width_f: float, height_f: _t_number, step: int): + """Final part of the main func for simple (non-upscale) nodes - when desired float/height are already calculated""" + step = number_to_int(step) + width, n_steps_x, height, n_steps_y = round_width_and_height_closest_to_the_ratio(width_f, height_f, step) + + ar_desired = width_f / height_f + ar_real = float(width) / height + ar_text = ( + "AR: perfect match" + if abs(ar_desired - ar_real) < 0.0005 + else f"AR desired/real: {ar_desired:.3f}/{ar_real:.3f}" + ) + + text = ( + f"{width} x {height}\n" + f"{n_steps_x} * {step} x {n_steps_y} * {step}\n" + f"{ar_text}" + ) + return { + # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed + "result": (width, height, text) + } diff --git a/node_types.py b/node_types.py index f358e39..7d5e89c 100644 --- a/node_types.py +++ b/node_types.py @@ -19,16 +19,6 @@ def number_type_dict(default: int = 512, min: int = 1, max: int = _sys.maxsize, } -def number_to_int(value: _t.Union[int, float], min: int = 1) -> int: - if not isinstance(value, int): - if isinstance(value, float): - sign = -1 if value < 0.0 else 1 - value = int(value * sign + 0.5) * sign - else: - value = int(value) - return max(value, min) - - type_dict_step_init = number_type_dict(48) type_dict_step_upscale1 = number_type_dict(128) type_dict_res = number_type_dict(1024) diff --git a/nodes.py b/nodes.py index 2cd0c2d..400a794 100644 --- a/nodes.py +++ b/nodes.py @@ -5,6 +5,7 @@ import typing as _t from inspect import cleandoc as _cleandoc +from math import sqrt as _sqrt import sys as _sys from frozendict import deepfreeze @@ -12,46 +13,11 @@ from frozendict import deepfreeze from comfy.comfy_types.node_typing import IO as _IO from .node_types import * - - -_t_number = _t.Union[int, float] - - -def _round_abs(abs_value: _t_number, step: int): - """ - Assuming both args are positive and ``step`` is already an int, detect the closest positive (non-zero) value - which is also divisible by step. - """ - n_steps = int(float(abs_value) / step + 0.5) - n_steps = max(n_steps, 1) - return step * n_steps, n_steps - - -def _round_width_and_height_closest_to_the_ratio(width_f: _t_number, height_f: _t_number, step: int): - """3-pass detection of the best rounded resolution. Best = closest to the desired ratio.""" - desired_width_to_height_ratio = float(width_f) / height_f - - # First pass: directly from width_f and height_f - width, n_steps_x = _round_abs(width_f, step) - height, n_steps_y = _round_abs(height_f, step) - - # Second pass: try calculating one side from already rounded another one: - height_from_width, n_steps_y_from_x = _round_abs(float(width) / desired_width_to_height_ratio, step) - width_from_height, n_steps_x_from_y = _round_abs(float(height) * desired_width_to_height_ratio, step) - - # ... and select one of three options, closest to the perfect ratio: - closest_delta = abs((float(width) / height) - desired_width_to_height_ratio) - for w, n_x, h, n_y in [ - (width, n_steps_x, height_from_width, n_steps_y_from_x), - (width_from_height, n_steps_x_from_y, height, n_steps_y), - ]: - cur_delta = abs((float(w) / h) - desired_width_to_height_ratio) - if cur_delta < closest_delta: - closest_delta = cur_delta - width, n_steps_x = w, n_x - height, n_steps_y = h, n_y - - return width, n_steps_x, height, n_steps_y +from ._funcs import ( + aspect_ratios_sorted as _aspect_ratios_sorted, + number_to_int as _number_to_int, + simple_result_from_approx_wh as _simple_result_from_approx_wh +) _48_tooltip = ( @@ -77,6 +43,9 @@ _input_types_simple = deepfreeze({ # "optional": {}, }) +_return_types_simple = (_IO.INT, _IO.INT, _IO.STRING) +_return_names_simple = ("width", "height", "report") + class BestResolutionSimple: """ @@ -90,28 +59,16 @@ class BestResolutionSimple: # OUTPUT_NODE = True # TODO FUNCTION = "main" - RETURN_TYPES = (_IO.INT, _IO.INT) + RETURN_TYPES = _return_types_simple # RETURN_TYPES_TOOLTIPS = {} - RETURN_NAMES = ("width", "height") + RETURN_NAMES = _return_names_simple @classmethod def INPUT_TYPES(cls): return _input_types_simple def main(self, width: int, height: int, step: int): - step = number_to_int(step) - width, n_steps_x, height, n_steps_y = _round_width_and_height_closest_to_the_ratio(width, height, step) - - text = f"{width} x {height}\n{n_steps_x} * {step} x {n_steps_y} * {step}" - # print(f"text: {text}") - - # The following return format is snatched from built-in PreviewAny - # and easy_nodes.show_text from (https://github.com/andrewharp/ComfyUI-EasyNodes); - # doesn't seem to be documented anywhere 🤷🏻‍♂️ - return { - # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed - "result": (width, height) - } + return _simple_result_from_approx_wh(float(width), height, step) _tooltip_aspect = ( @@ -155,7 +112,7 @@ _input_types_orient = deepfreeze({ class BestResolutionFromAspectRatio: """ A more advanced node for easier selection of an optimal resolution: - image size specified indirectly - by one of the sides + aspect ratio. + image size selected indirectly - by one of the sides + aspect ratio. """ NODE_NAME = "BestResolutionFromAspectRatio" CATEGORY = "utils/resolution" @@ -164,35 +121,89 @@ class BestResolutionFromAspectRatio: # OUTPUT_NODE = True # TODO FUNCTION = "main" - RETURN_TYPES = (_IO.INT, _IO.INT) - RETURN_NAMES = ("width", "height") + RETURN_TYPES = _return_types_simple + RETURN_NAMES = _return_names_simple @classmethod def INPUT_TYPES(cls): return _input_types_orient def main(self, size: int, step: int, size_is_big: bool, landscape: bool, aspect_a: float, aspect_b: float): - aspect_a = max(float(aspect_a), 1.0) - aspect_b = max(float(aspect_b), 1.0) - aspect_big = max(aspect_a, aspect_b) - aspect_small = min(aspect_a, aspect_b) + aspect_big, aspect_small = _aspect_ratios_sorted(aspect_a, aspect_b) side_main_f = float(size) - side_secondary_f = side_main_f * ( + side_other_f = side_main_f * ( (aspect_small / aspect_big) if size_is_big else (aspect_big / aspect_small) ) - width_f = max(side_main_f, side_secondary_f) - height_f = min(side_main_f, side_secondary_f) + 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 - step = number_to_int(step) - width, n_steps_x, height, n_steps_y = _round_width_and_height_closest_to_the_ratio(width_f, height_f, step) + return _simple_result_from_approx_wh(width_f, height_f, step) - text = f"{width} x {height}\n{n_steps_x} * {step} x {n_steps_y} * {step}" - return { - # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed - "result": (width, height) - } + +_input_types_area = deepfreeze({ + "required": { + "square_size": (_IO.INT, dict(type_dict_res, **{"tooltip": ( + "The total resolution of the image would be the same as of a square with this side.\n" + "The width and height would be such to respect aspect ratio, but also be as close as possible to the " + "total number of pixels as in this square image.\n\n" + "- 512x512 square (SD 1.5): ~0.25 megapixels\n" + "- 1024x1024 square (SDXL): ~1 megapixel" + )})), + "step": _input_types_simple["required"]["step"], + "landscape": _input_types_orient["required"]["landscape"], + "aspect_a": _input_types_orient["required"]["aspect_a"], + "aspect_b": _input_types_orient["required"]["aspect_b"], + }, + # "hidden": {}, + # "optional": {}, +}) + + +class BestResolutionFromArea: + """ + 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. + """ + NODE_NAME = "BestResolutionFromArea" + CATEGORY = "utils/resolution" + DESCRIPTION = _cleandoc(__doc__) + + # OUTPUT_NODE = True # TODO + + FUNCTION = "main" + RETURN_TYPES = _return_types_simple + RETURN_NAMES = _return_names_simple + + @classmethod + def INPUT_TYPES(cls): + return _input_types_area + + def main(self, square_size: int, step: int, landscape: bool, aspect_a: float, aspect_b: float): + # square_size = 1024; step = 48; landscape = True; aspect_a = 9.0; aspect_b = 16.0 + aspect_big, aspect_small = _aspect_ratios_sorted(aspect_a, aspect_b) + aspect_x, aspect_y = (aspect_big, aspect_small) if landscape else (aspect_small, aspect_big) + + aspect_area = aspect_x * aspect_y + aspect_norm_scale = 1.0 / _sqrt(aspect_area) + aspect_x *= aspect_norm_scale + aspect_y *= aspect_norm_scale + # Now the two aspects produce a normalized rectangle - i.e., it's area is 1 + + square_size = _number_to_int(square_size) + width_f = aspect_x * square_size + height_f = aspect_y * square_size + + return _simple_result_from_approx_wh(width_f, height_f, step) From a6400e9d2b7610baaa3fa80ec61d0a9bf7e1414c Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 18:17:22 +0500 Subject: [PATCH 8/9] + add support for interactive report message (at the bottom of the node) --- _funcs.py | 30 ++++++++++++++++++++------- node_types.py | 1 + nodes.py | 56 ++++++++++++++++++++++++++++----------------------- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/_funcs.py b/_funcs.py index ff10eb0..1d0c561 100644 --- a/_funcs.py +++ b/_funcs.py @@ -1,9 +1,15 @@ # encoding: utf-8 """ +Internal utility functions. They're intended to be used only by the methods within nodes, +so they might expect the input arguments to already be pre-validated. """ import typing as _t +from math import sqrt as _sqrt + +from server import PromptServer as _PromptServer + _t_number = _t.Union[int, float] @@ -62,25 +68,35 @@ def round_width_and_height_closest_to_the_ratio(width_f: _t_number, height_f: _t return width, n_steps_x, height, n_steps_y -def simple_result_from_approx_wh(width_f: float, height_f: _t_number, step: int): +def simple_result_from_approx_wh(width_f: float, height_f: _t_number, step: int, unique_id: str = None): """Final part of the main func for simple (non-upscale) nodes - when desired float/height are already calculated""" step = number_to_int(step) width, n_steps_x, height, n_steps_y = round_width_and_height_closest_to_the_ratio(width_f, height_f, step) + square_side_f = _sqrt(float(width * height)) + square_side = int(square_side_f + 0.5) + square_side_text = ( + f"={square_side}x{square_side}" + if (square_side * square_side == width * height) + else f"~{square_side}x{square_side}" + ) + ar_desired = width_f / height_f ar_real = float(width) / height ar_text = ( "AR: perfect match" if abs(ar_desired - ar_real) < 0.0005 - else f"AR desired/real: {ar_desired:.3f}/{ar_real:.3f}" + else f"AR goal/real: {ar_desired:.3f}/{ar_real:.3f}" ) text = ( - f"{width} x {height}\n" + f"{width} x {height} ({square_side_text})\n" f"{n_steps_x} * {step} x {n_steps_y} * {step}\n" f"{ar_text}" ) - return { - # "ui": {"text": [text]}, # TODO: for some reason, it isn't displayed - "result": (width, height, text) - } + + if unique_id: + # Snatched from: https://github.com/comfyanonymous/ComfyUI/blob/27870ec3c30e56be9707d89a120eb7f0e2836be1/comfy_extras/nodes_images.py#L581-L582 + _PromptServer.instance.send_progress_text(text, unique_id) + + return width, height diff --git a/node_types.py b/node_types.py index 7d5e89c..8c6b2a2 100644 --- a/node_types.py +++ b/node_types.py @@ -1,5 +1,6 @@ # encoding: utf-8 """ +Pre-defined dictionaries for nice input types. """ import typing as _t diff --git a/nodes.py b/nodes.py index 400a794..d8fa255 100644 --- a/nodes.py +++ b/nodes.py @@ -1,5 +1,6 @@ # encoding: utf-8 """ +The actual nodes defined by the package. """ import typing as _t @@ -20,31 +21,32 @@ from ._funcs import ( ) -_48_tooltip = ( - "The default 48 is (8 * 3 * 2), so it's a safe choice because:\n" - "- it's compatible with SD1.5/XL step (divisible by 8),\n" - "- it can be upscaled by x1.5 or x1.333 at the first iteration, which is optimal for latent-upscale,\n" - "- after x1.5 upscale, if you only do x2 later (it's OK for already high resolutions) - it will be divisible " - "by 3 AND 9, which might become handy at that point, where you'll probably use UltimateSDUpscale.\n\n" - "Other values worth trying first: 64, 96, 128." -) - # Tiny optimization by reusing the same immutable dict: _input_types_simple = deepfreeze({ "required": { "width": (_IO.INT, dict(type_dict_res, **{"tooltip": "Approximate width"})), "height": (_IO.INT, dict(type_dict_res, **{"tooltip": "Approximate height"})), "step": (_IO.INT, dict(type_dict_step_init, **{"tooltip": ( - f"Both width and height will be divisible by this value - by rounding them " - f"to the closest appropriate resolution.\n\n{_48_tooltip}" + "Both width and height will be divisible by this value - by rounding them " + "to the closest appropriate resolution.\n\n" + "The default 48 is (8 * 3 * 2), so it's a safe choice because:\n" + "- it's compatible with SD1.5/XL downsampling factor (divisible by 8),\n" + "- it can be upscaled by x1.5 or x1.333 at the first iteration, which is optimal for latent-upscale,\n" + "- after x1.5 upscale, if you only do x2 later (it's OK for already high resolutions) - it will be divisible " + "by 3 AND 9, which might become handy at that point, where you'll probably use UltimateSDUpscale.\n\n" + "Other values worth trying first: 64, 96, 128." )})), }, - # "hidden": {}, + "hidden": { + "unique_id": "UNIQUE_ID", # used for text display at the bottom of the node + }, # "optional": {}, }) -_return_types_simple = (_IO.INT, _IO.INT, _IO.STRING) -_return_names_simple = ("width", "height", "report") +# _return_types_simple = (_IO.INT, _IO.INT, _IO.STRING) +# _return_names_simple = ("width", "height", "report") +_return_types_simple = (_IO.INT, _IO.INT) +_return_names_simple = ("width", "height") class BestResolutionSimple: @@ -56,7 +58,7 @@ class BestResolutionSimple: CATEGORY = "utils/resolution" DESCRIPTION = _cleandoc(__doc__) - # OUTPUT_NODE = True # TODO + OUTPUT_NODE = True FUNCTION = "main" RETURN_TYPES = _return_types_simple @@ -67,8 +69,8 @@ class BestResolutionSimple: def INPUT_TYPES(cls): return _input_types_simple - def main(self, width: int, height: int, step: int): - return _simple_result_from_approx_wh(float(width), height, step) + def main(self, width: int, height: int, step: int, unique_id: str = None): + return _simple_result_from_approx_wh(float(width), height, step, unique_id) _tooltip_aspect = ( @@ -104,7 +106,9 @@ _input_types_orient = deepfreeze({ "tooltip": _tooltip_aspect }), }, - # "hidden": {}, + "hidden": { + "unique_id": "UNIQUE_ID", + }, # "optional": {}, }) @@ -118,7 +122,7 @@ class BestResolutionFromAspectRatio: CATEGORY = "utils/resolution" DESCRIPTION = _cleandoc(__doc__) - # OUTPUT_NODE = True # TODO + OUTPUT_NODE = True FUNCTION = "main" RETURN_TYPES = _return_types_simple @@ -128,7 +132,7 @@ class BestResolutionFromAspectRatio: def INPUT_TYPES(cls): return _input_types_orient - def main(self, size: int, step: int, size_is_big: bool, landscape: bool, aspect_a: float, aspect_b: float): + def main(self, size: int, step: int, size_is_big: bool, landscape: bool, aspect_a: float, aspect_b: float, unique_id: str = None): aspect_big, aspect_small = _aspect_ratios_sorted(aspect_a, aspect_b) side_main_f = float(size) @@ -141,7 +145,7 @@ class BestResolutionFromAspectRatio: # The opposite: height is bigger width_f, height_f = height_f, width_f - return _simple_result_from_approx_wh(width_f, height_f, step) + return _simple_result_from_approx_wh(width_f, height_f, step, unique_id) _input_types_area = deepfreeze({ @@ -158,7 +162,9 @@ _input_types_area = deepfreeze({ "aspect_a": _input_types_orient["required"]["aspect_a"], "aspect_b": _input_types_orient["required"]["aspect_b"], }, - # "hidden": {}, + "hidden": { + "unique_id": "UNIQUE_ID", + }, # "optional": {}, }) @@ -181,7 +187,7 @@ class BestResolutionFromArea: CATEGORY = "utils/resolution" DESCRIPTION = _cleandoc(__doc__) - # OUTPUT_NODE = True # TODO + OUTPUT_NODE = True FUNCTION = "main" RETURN_TYPES = _return_types_simple @@ -191,7 +197,7 @@ class BestResolutionFromArea: def INPUT_TYPES(cls): return _input_types_area - def main(self, square_size: int, step: int, landscape: bool, aspect_a: float, aspect_b: float): + def main(self, square_size: int, step: int, landscape: bool, aspect_a: float, aspect_b: float, unique_id: str = None): # square_size = 1024; step = 48; landscape = True; aspect_a = 9.0; aspect_b = 16.0 aspect_big, aspect_small = _aspect_ratios_sorted(aspect_a, aspect_b) aspect_x, aspect_y = (aspect_big, aspect_small) if landscape else (aspect_small, aspect_big) @@ -206,4 +212,4 @@ class BestResolutionFromArea: width_f = aspect_x * square_size height_f = aspect_y * square_size - return _simple_result_from_approx_wh(width_f, height_f, step) + return _simple_result_from_approx_wh(width_f, height_f, step, unique_id) From c6d547c1ad6ac9e674108b71d3c8be13322fb451 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Sat, 5 Jul 2025 18:18:50 +0500 Subject: [PATCH 9/9] `README` + `pyproject` --- README.md | 30 ++++++++++++++++++++++++++++-- img/screenshot1.png | Bin 0 -> 106343 bytes pyproject.toml | 4 ++-- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 img/screenshot1.png diff --git a/README.md b/README.md index f0bb31c..a3405df 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,32 @@ # ComfyUI-BestResolution -Nodes for semi-automatic calculation of the best (most optimal) resolution: +QoL Nodes for semi-automatic calculation of the best (most optimal) resolution: - compatible with ANY model (from now or the future), -- accounting for upscale +- accounting for upscale (**TODO**, planned soon) - ... and (the required) pixel-step. + +![image](img/screenshot1.png) + +In case you didn't know, you can't just choose **any** arbitrary resolution for sampling. You need to ensure: +- both width and height are divisible by pre-defined latent scale factor (8 for both SD1.5 and SDXL); +- the overall resolution (aka megapixels) is as close to training dataset as possible. + +This pack lets you forget about crunching numbers and handles the calculation of optimal width/height for you, while still leaving control to you. It provides 3 main nodes: + +### Simple + +Just rounds width/height to the given step, ensuring the image **CAN** be converted to latent - both in initial generation and after some upscales. + +### From Aspect-Ratio + +You specify the desired aspect ratio, one of the sides, and orientation (landscape/portrait). The node detects the actual width/height. + +### From Area + +To my taste, **THE** safest and easiest approach to selecting the optimal sampling resolution. + +All you need to know is a side of square images the model was trained on (512 for SD1.5, 1024 for SDXL). The node handles the rest to ensure the total resolution (i.e., number of pixels) is as close to the training data as possible, while still respecting aspect ratio and step size. + +## Tooltips + +Each parameter is self-documented in detail - just hover mouse over it. If you're new to Comfy and Stable Diffusion, this might be especially helpful. diff --git a/img/screenshot1.png b/img/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..dc40f742d4dd6cf79ca5fa4deca340ba39cd127e GIT binary patch literal 106343 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�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