diff --git a/enums.py b/enums.py index 79e0550..11a3d0b 100644 --- a/enums.py +++ b/enums.py @@ -18,12 +18,37 @@ class __BaseEnum(_StrEnum): class RoundingPriority(__BaseEnum): + """ + Defines what resolution to prioritize, as well as which order to perform rounding in: + + + • desired - first, approximate resolutions are calculated for both initial and upscaled size; then, both are rounded. + In both cases, the rounded resolution is closest to the desired one, + but aspect ratio might differ the most between sizes. + • original - first, initial resolution is calculated and rounded; then, upscaled one is detected from it. + Upscaled resolution might differ the most from the desired aspect ratio, but it follows the ratio from + initial size as much as possible. + • upscaled - vice versa: first, the rounded upscaled resolution is calculated; + then, the initial one back-tracked from it. + """ DESIRED = 'desired' ORIGINAL = 'original' UPSCALED = 'upscaled' -class UpscaleTweakStrategy(__BaseEnum): +class UpscaledCropPadStrategy(__BaseEnum): + """ + If the upscaled resolution can't be achieved by uniform scaling of the initial-res, + how to tweak the image to get there: + + + • pad - upscale the image to fit it into the desired frame on one side, + then add missing pixels on the other one for outpaint. + • crop - upscale the image to fill the entire frame, then crop extra pixels on one side. + • nearest - automatically choose one of the above, to crop/pad the least number of pixels. + • exact-upscale - follow the provided upscale-value precisely. This is the only option + that uses it. Also, it's the only one that might require both outpainting and crop. + """ PAD = 'pad' CROP = 'crop' NEAREST = 'nearest' diff --git a/nodes_prims.py b/nodes_prims.py index 67a09be..6c83521 100644 --- a/nodes_prims.py +++ b/nodes_prims.py @@ -10,6 +10,10 @@ from inspect import cleandoc as _cleandoc from frozendict import deepfreeze as _deepfreeze from . import _meta +from .docstring_formatter import ( + format_docstring as _format_docstring, + format_object_docstring as _format_object_docstring +) from .enums import * # ---------------------------------------------------------- @@ -20,17 +24,7 @@ _res_priority_in_type = ( _res_priority_data_type, { 'default': RoundingPriority.DESIRED.value, - 'tooltip': ( - "Defines what resolution to prioritize, as well as which order to perform rounding in:\n\n" - "• desired - first, approximate resolutions are calculated for both initial and upscaled size; " - "then, both are rounded. In both cases, the rounded resolution is closest to the desired one, " - "but aspect ratio might differ the most between sizes.\n\n" - "• original - first, initial resolution is calculated and rounded; then, upscaled one is detected from it. " - "Upscaled resolution might differ the most from the desired aspect ratio, but it follows the ratio from " - "initial size as much as possible.\n\n" - "• upscaled - vice versa: first, the rounded upscaled resolution is calculated; then, the initial one " - "back-tracked from it." - ), + 'tooltip': _format_object_docstring(RoundingPriority), } ) _input_types_res_priority = _deepfreeze({ @@ -56,7 +50,7 @@ class BestResolutionPrimResPriority: """ NODE_NAME = 'BestResolutionPrimResPriority' CATEGORY = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = False @@ -78,22 +72,13 @@ class BestResolutionPrimResPriority: # ---------------------------------------------------------- -_up_strategy_data_type = UpscaleTweakStrategy.all_values() +_up_strategy_data_type = UpscaledCropPadStrategy.all_values() _up_strategy_data_type_set = set(_up_strategy_data_type) _up_strategy_in_type = ( _up_strategy_data_type, { - 'default': UpscaleTweakStrategy.PAD.value, - 'tooltip': ( - "If the upscaled resolution can't be achieved by uniform scaling of the initial-res, " - "how to tweak the image to get there:\n\n" - "• pad - upscale the image to fit it into the desired frame on one side, " - "then add missing pixels on the other one for outpaint.\n" - "• crop - upscale the image to fill the entire frame, then crop extra pixels on one side.\n" - "• nearest - automatically choose one of the above, to crop/pad the least number of pixels.\n" - "• exact-upscale - follow the provided upscale-value precisely. This is the only option that uses it. " - "Also, it's the only one that might require both outpainting and crop." - ), + 'default': UpscaledCropPadStrategy.PAD.value, + 'tooltip': _format_object_docstring(UpscaledCropPadStrategy), } ) _input_types_up_strategy = _deepfreeze({ @@ -115,11 +100,11 @@ def _up_strategy_verify(strategy: _t.Union[RoundingPriority, str]) -> str: class BestResolutionPrimUpStrategy: """ - 'strategy' selector for "Upscale Tweaks" node in "Best Resolution" pack. + 'strategy' selector for "Upscaled Crop/Pad" node in "Best Resolution" pack. """ NODE_NAME = 'BestResolutionPrimUpStrategy' CATEGORY = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = False diff --git a/nodes_simple.py b/nodes_simple.py index f54565f..1ab39ca 100644 --- a/nodes_simple.py +++ b/nodes_simple.py @@ -20,6 +20,7 @@ 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_init as _type_dict_step_init @@ -67,7 +68,7 @@ class BestResolutionSimple: """ NODE_NAME = 'BestResolutionSimple' CATEGORY = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = True @@ -141,7 +142,7 @@ class BestResolutionFromAspectRatio: """ NODE_NAME = 'BestResolutionFromAspectRatio' CATEGORY = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = True @@ -206,18 +207,19 @@ 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 = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = True diff --git a/nodes_upscale.py b/nodes_upscale.py index 82252f5..ce9fd77 100644 --- a/nodes_upscale.py +++ b/nodes_upscale.py @@ -19,6 +19,7 @@ from ._funcs import ( upscale_result_from_approx_wh as _upscale_result_from_approx_wh ) from . import _meta +from .docstring_formatter import format_docstring as _format_docstring from .enums import * from .nodes_simple import _input_types_area from .nodes_prims import _res_priority_in_type, _res_priority_verify @@ -76,18 +77,19 @@ class BestResolutionFromAreaUpscale: ... PLUS, account for the immediate upscale right away. + 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 = 'BestResolutionFromAreaUpscale' CATEGORY = _meta.category - DESCRIPTION = _cleandoc(__doc__) + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) OUTPUT_NODE = True