diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index 07e1551f1..8916772a3 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -1253,6 +1253,12 @@ class Curve(ComfyTypeIO): if default is None: self.default = [(0.0, 0.0), (1.0, 1.0)] + def as_dict(self): + d = super().as_dict() + if self.default is not None: + d["default"] = {"points": [list(p) for p in self.default], "interpolation": "monotone_cubic"} + return d + DYNAMIC_INPUT_LOOKUP: dict[str, Callable[[dict[str, Any], dict[str, Any], tuple[str, dict[str, Any]], str, list[str] | None], None]] = {} def register_dynamic_input_func(io_type: str, func: Callable[[dict[str, Any], dict[str, Any], tuple[str, dict[str, Any]], str, list[str] | None], None]): diff --git a/comfy_extras/nodes_curve.py b/comfy_extras/nodes_curve.py new file mode 100644 index 000000000..fec3ebbda --- /dev/null +++ b/comfy_extras/nodes_curve.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from comfy_api.latest import ComfyExtension, io +from comfy_api.input import CurveInput, MonotoneCubicCurve, LinearCurve +from typing_extensions import override + + +class CurveEditor(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="CurveEditor", + display_name="Curve Editor", + category="utils", + inputs=[ + io.Curve.Input("curve"), + ], + outputs=[ + io.Curve.Output("curve"), + ], + ) + + @classmethod + def execute(cls, curve) -> io.NodeOutput: + if isinstance(curve, CurveInput): + return io.NodeOutput(curve) + raw_points = curve["points"] if isinstance(curve, dict) else curve + points = [(float(x), float(y)) for x, y in raw_points] + interpolation = curve.get("interpolation", "monotone_cubic") if isinstance(curve, dict) else "monotone_cubic" + if interpolation == "linear": + return io.NodeOutput(LinearCurve(points)) + return io.NodeOutput(MonotoneCubicCurve(points)) + + +class CurveExtension(ComfyExtension): + @override + async def get_node_list(self): + return [CurveEditor] + + +async def comfy_entrypoint(): + return CurveExtension() diff --git a/nodes.py b/nodes.py index 1ff2a0c51..79874d051 100644 --- a/nodes.py +++ b/nodes.py @@ -2038,32 +2038,6 @@ class ImagePadForOutpaint: return (new_image, mask.unsqueeze(0)) -class CurveEditor: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "curve": ("CURVE", {"default": {"points": [[0, 0], [1, 1]], "interpolation": "monotone_cubic"}}), - } - } - - RETURN_TYPES = ("CURVE",) - RETURN_NAMES = ("curve",) - FUNCTION = "execute" - CATEGORY = "utils" - - def execute(self, curve): - from comfy_api.input import CurveInput, MonotoneCubicCurve, LinearCurve - if isinstance(curve, CurveInput): - return (curve,) - raw_points = curve["points"] if isinstance(curve, dict) else curve - points = [(float(x), float(y)) for x, y in raw_points] - interpolation = curve.get("interpolation", "monotone_cubic") if isinstance(curve, dict) else "monotone_cubic" - if interpolation == "linear": - return (LinearCurve(points),) - return (MonotoneCubicCurve(points),) - - NODE_CLASS_MAPPINGS = { "KSampler": KSampler, "CheckpointLoaderSimple": CheckpointLoaderSimple, @@ -2132,7 +2106,6 @@ NODE_CLASS_MAPPINGS = { "ConditioningZeroOut": ConditioningZeroOut, "ConditioningSetTimestepRange": ConditioningSetTimestepRange, "LoraLoaderModelOnly": LoraLoaderModelOnly, - "CurveEditor": CurveEditor, } NODE_DISPLAY_NAME_MAPPINGS = { @@ -2201,7 +2174,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { # _for_testing "VAEDecodeTiled": "VAE Decode (Tiled)", "VAEEncodeTiled": "VAE Encode (Tiled)", - "CurveEditor": "Curve Editor", } EXTENSION_WEB_DIRS = {} @@ -2483,6 +2455,7 @@ async def init_builtin_extra_nodes(): "nodes_sdpose.py", "nodes_math.py", "nodes_painter.py", + "nodes_curve.py", ] import_failed = []