From 5c984dbe5c2fd111e53aee774b741d470b7b59db Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Fri, 3 Oct 2025 11:27:28 +0500 Subject: [PATCH] `node_crop_pad`: v3 --- node_crop_pad.py | 159 ++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 90 deletions(-) diff --git a/node_crop_pad.py b/node_crop_pad.py index 498a4ba..93887b3 100644 --- a/node_crop_pad.py +++ b/node_crop_pad.py @@ -3,116 +3,95 @@ Nodes to calculate crop / padding values (for out-paint). """ -import typing as _t - from inspect import cleandoc as _cleandoc -from frozendict import deepfreeze as _deepfreeze, frozendict as _frozendict +from comfy_api.latest import io as _io -from comfy.comfy_types.node_typing import IO as _IO - -from .funcs_crop_pad import upscaled_crop_pad as _upscaled_crop_pad +from . import _io_enum as _enums +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 .enums import * -from .nodes_prims import _up_strategy_in_type, _up_strategy_verify -from .nodes_upscale import _return_ttips_upscale -from .slot_types import ( - type_dict_res as _type_dict_res, - rel_pos_in_type as _rel_pos_in_type, - upscale_in_type as _upscale_in_type -) +from .funcs_crop_pad import upscaled_crop_pad as _upscaled_crop_pad # ---------------------------------------------------------- -_return_ttips_crop_pad = _frozendict({ - 'upscale': "The actual uniform upscale value to do.", - - 'do_crop': "Whether post-upscale crop needs to be done to get the specified resolution.", - 'crop_width': "Width for the post-upscale crop.", - 'crop_height': "Height for the post-upscale crop.", - 'crop_x': "X-offset for the post-upscale crop.", - 'crop_y': "Y-offset for the post-upscale crop.", - - 'do_padding': "Whether post-upscale padding and out-paint need to be done to get the specified resolution.", - 'pad_left': "Left padding for the post-upscale out-paint.", - 'pad_top': "Top padding for the post-upscale out-paint.", - 'pad_right': "Right padding for the post-upscale out-paint.", - 'pad_bottom': "Bottom padding for the post-upscale out-paint.", -}) -_input_types_crop_pad = _deepfreeze({ - 'required': { - 'upscale': (_IO.FLOAT, dict(_upscale_in_type[1], **{ - 'tooltip': f"Only used when {UpscaledCropPadStrategy.EXACT_UPSCALE!r} strategy selected." - })), - 'init_width': (_IO.INT, dict(_type_dict_res, **{'tooltip': _return_ttips_upscale['init_width']})), - 'init_height': (_IO.INT, dict(_type_dict_res, **{'tooltip': _return_ttips_upscale['init_height']})), - 'HD_width': (_IO.INT, dict(_type_dict_res, **{'tooltip': _return_ttips_upscale['HD_width'], 'default': 1536})), - 'HD_height': (_IO.INT, dict(_type_dict_res, **{'tooltip': _return_ttips_upscale['HD_height'], 'default': 1536})), - 'strategy': _up_strategy_in_type, - 'align_x': (_IO.FLOAT, dict(_rel_pos_in_type[1], **{ - 'tooltip': ( - "Where's the image pivot for horizontal alignment (which side stays in place during crop/out-paint):\n" - "0 - Left\n" - "0.5 - Center\n" - "1 - Right" - ), - })), - 'align_y': (_IO.FLOAT, dict(_rel_pos_in_type[1], **{ - 'tooltip': ( - "Where's the image pivot for vertical alignment (which side stays in place during crop/out-paint):\n" - "0 - Bottom\n" - "0.5 - Center\n" - "1 - Top" - ), - 'default': 0.0 - })), - }, - 'hidden': { - 'unique_id': 'UNIQUE_ID', - }, - # 'optional': {}, -}) - - -class BestResolutionUpscaledCropPad: +class BestResolutionUpscaledCropPad(_io.ComfyNode): """ If the original resolution can't be scaled to the higher one uniformly (i.e., without stretching), this node detects the appropriate values for cropping/out-painting. """ - NODE_NAME = 'BestResolutionUpscaledCropPad' - CATEGORY = _meta.category - DESCRIPTION = _format_docstring(_cleandoc(__doc__)) + _schema = _io.Schema( + 'BestResolutionUpscaledCropPad', + display_name="Upscaled Crop/Pad (Best-Res)", + category=_meta.category, + description=_format_docstring(_cleandoc(__doc__)), + inputs=[ + _io_override(_i.upscale, tooltip=f"Only used when {_enums.UpscaledCropPadStrategy.EXACT_UPSCALE!r} strategy selected."), + _io_override(_i.res, 'init_width', tooltip=_tt.init_width), + _io_override(_i.res, 'init_height', tooltip=_tt.init_height), - OUTPUT_NODE = True + _io_override(_i.res, 'HD_width', default=1536, tooltip=_tt.HD_width), + _io_override(_i.res, 'HD_height', default=1536, tooltip=_tt.HD_height), - FUNCTION = 'main' - RETURN_TYPES = ( - _IO.FLOAT, - _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, - _IO.BOOLEAN, _IO.INT, _IO.INT, _IO.INT, _IO.INT, + _enums.crop_pad_strategy_in, + + _io_override(_i.rel_pos, 'align_x', tooltip=( + "Where's the image pivot for horizontal alignment (which side stays in place during crop/out-paint):\n" + "0 - Left\n" + "0.5 - Center\n" + "1 - Right" + )), + _io_override(_i.rel_pos, 'align_y', default=0.0, tooltip=( + "Where's the image pivot for vertical alignment (which side stays in place during crop/out-paint):\n" + "0 - Bottom\n" + "0.5 - Center\n" + "1 - Top" + )), + ], + hidden=[_io.Hidden.unique_id], + outputs=[ + # In v3 schema, IDs must be unique between BOTH lists: inputs and outputs, so uppercase ID + `display_name`: + _io.Float.Output('UPSCALE', display_name='upscale', tooltip="The actual uniform upscale value to do."), + + # Once we have a single ID in the list, we need to specify all the display names. + # Without it, outputs will be drawn with their types. + _io.Boolean.Output('do_crop', display_name='do_crop', tooltip="Whether post-upscale crop needs to be done to get the specified resolution."), + _io.Int.Output('crop_width', display_name='crop_width', tooltip="Width for the post-upscale crop."), + _io.Int.Output('crop_height', display_name='crop_height', tooltip="Height for the post-upscale crop."), + _io.Int.Output('crop_x', display_name='crop_x', tooltip="X-offset for the post-upscale crop."), + _io.Int.Output('crop_y', display_name='crop_y', tooltip="Y-offset for the post-upscale crop."), + + _io.Boolean.Output('do_padding', display_name='do_padding', tooltip="Whether post-upscale padding and out-paint need to be done to get the specified resolution."), + _io.Int.Output('pad_left', display_name='pad_left', tooltip="Left padding for the post-upscale out-paint."), + _io.Int.Output('pad_top', display_name='pad_top', tooltip="Top padding for the post-upscale out-paint."), + _io.Int.Output('pad_right', display_name='pad_right', tooltip="Right padding for the post-upscale out-paint."), + _io.Int.Output('pad_bottom', display_name='pad_bottom', tooltip="Bottom padding for the post-upscale out-paint."), + ], + is_output_node=True, ) - RETURN_NAMES = tuple(_return_ttips_crop_pad.keys()) - OUTPUT_TOOLTIPS = tuple(_return_ttips_crop_pad.values()) @classmethod - def INPUT_TYPES(cls): - return _input_types_crop_pad + def define_schema(cls) -> _io.Schema: + return cls._schema - def main( - self, + @classmethod + def execute( + cls, upscale: float, init_width: int, init_height: int, HD_width: int, HD_height: int, - strategy: _t.Union[UpscaledCropPadStrategy, str], + strategy: _enums.UpscaledCropPadStrategy | str, align_x: float, align_y: float, # show: bool, - unique_id: str = None - ): - return _upscaled_crop_pad( - upscale, - init_width, init_height, HD_width, HD_height, - _up_strategy_verify(strategy), - align_x, align_y, - # show, - unique_id=unique_id + ) -> _io.NodeOutput: + return _io.NodeOutput( + *_upscaled_crop_pad( + upscale, + init_width, init_height, HD_width, HD_height, + _enums.UpscaledCropPadStrategy.validate(strategy), + align_x, align_y, + # show, + unique_id=cls.hidden.unique_id + ) )