diff --git a/__init__.py b/__init__.py index 08f2e47..f34808c 100644 --- a/__init__.py +++ b/__init__.py @@ -5,6 +5,9 @@ class ExternalToolingNodes(ComfyExtension): async def get_node_list(self) -> list[type[io.ComfyNode]]: return [ + nodes.ListEmpty, + nodes.ListAppend, + nodes.DataList, nodes.LoadImageCache, nodes.SaveImageCache, nodes.LoadImageBase64, diff --git a/krita.py b/krita.py index 68c7beb..eadfe6e 100644 --- a/krita.py +++ b/krita.py @@ -222,6 +222,17 @@ def execute(cls, **kwargs): return io.NodeOutput(torch.ones(1, 512, 512), False, 0, 0) +class GroupMode(Enum): + flatten = "flatten" + all_children = "all children" + + +_group_mode_help = """ +Determines the behavior when a group layer is selected: +- flatten: the group is flattened into a single image +- all children: all child layers in the group (recursively) are returned as separate images""" + + class KritaImageLayer(io.ComfyNode): @classmethod def define_schema(cls): @@ -229,16 +240,25 @@ def define_schema(cls): node_id="ETN_KritaImageLayer", display_name="Krita Image Layer", category="krita", - inputs=[io.String.Input("name", default="Image")], + inputs=[ + io.String.Input("name", default="Image"), + io.Combo.Input( + "group_mode", + options=GroupMode, + default=GroupMode.flatten, + tooltip=_group_mode_help, + ), + ], outputs=[ - io.Image.Output(display_name="image"), - io.Mask.Output(display_name="mask"), + io.Image.Output(display_name="images", is_output_list=True), + io.Mask.Output(display_name="masks", is_output_list=True), + io.String.Output(display_name="names", is_output_list=True), ], ) @classmethod - def execute(cls, name: str): - return io.NodeOutput(_placeholder_image(), torch.ones(1, 512, 512)) + def execute(cls, name: str, group_mode: GroupMode): + return io.NodeOutput([_placeholder_image()], [torch.ones(1, 512, 512)], [""]) class KritaMaskLayer(io.ComfyNode): diff --git a/nodes.py b/nodes.py index bf25b0a..17dda57 100644 --- a/nodes.py +++ b/nodes.py @@ -17,6 +17,59 @@ from comfy_api.latest import io +class ListEmpty(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="ETN_ListEmpty", + display_name="Creates an empty list", + category="external_tooling", + inputs=[], + outputs=[io.AnyType.Output()], + ) + + @classmethod + def execute(cls): + return io.NodeOutput([]) + + +class ListAppend(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="ETN_ListAppend", + display_name="Appends an item to a list", + category="external_tooling", + inputs=[ + io.AnyType.Input("list"), + io.AnyType.Input("item"), + ], + outputs=[io.AnyType.Output()], + ) + + @classmethod + def execute(cls, list: list[Any], item: Any): + list = list.copy() + list.append(item) + return io.NodeOutput(list) + + +class DataList(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="ETN_DataList", + display_name="Converts a list into a data list", + category="external_tooling", + inputs=[io.AnyType.Input("list")], + outputs=[io.AnyType.Output(is_output_list=True)], + ) + + @classmethod + def execute(cls, list: list[Any]): + return io.NodeOutput(list) + + class LoadImageBase64(io.ComfyNode): @classmethod def define_schema(cls):