From 0a9943d3e7e1642720955cc68c0954254038d151 Mon Sep 17 00:00:00 2001 From: Pauan Date: Fri, 27 Mar 2026 20:48:53 -0700 Subject: [PATCH 1/3] Adding in new Krita Group Layer node --- __init__.py | 4 ++++ krita.py | 23 +++++++++++++++++++++++ nodes.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/__init__.py b/__init__.py index 08f2e47..77e5744 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, @@ -30,6 +33,7 @@ async def get_node_list(self) -> list[type[io.ComfyNode]]: krita.KritaSelection, krita.KritaImageLayer, krita.KritaMaskLayer, + krita.KritaGroupLayer, krita.Parameter, krita.KritaStyle, krita.KritaStyleAndPrompt, diff --git a/krita.py b/krita.py index 68c7beb..1ec5e09 100644 --- a/krita.py +++ b/krita.py @@ -259,6 +259,29 @@ def execute(cls, name: str): return io.NodeOutput(torch.ones(1, 512, 512)) +class KritaGroupLayer(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="ETN_KritaGroupLayer", + display_name="Krita Group Layer", + description="Returns a list of images / masks / names from a group layer.", + category="krita", + inputs=[ + io.String.Input("name", default="Group"), + ], + outputs=[ + 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, mode): + return io.NodeOutput([_placeholder_image()], [torch.ones(1, 512, 512)], [""]) + + _param_types = [ "auto", "number", diff --git a/nodes.py b/nodes.py index bf25b0a..9a39af2 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.String.Input("item"), + ], + outputs=[io.AnyType.Output()], + ) + + @classmethod + def execute(cls, list: list[Any], item: str): + 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): From c740163f05c9b3640fc0e7ac4ce63794854fcf57 Mon Sep 17 00:00:00 2001 From: Pauan Date: Thu, 2 Apr 2026 22:13:20 -0700 Subject: [PATCH 2/3] Removing Layer Group node and merging its behavior into Layer Image node --- __init__.py | 1 - krita.py | 53 +++++++++++++++++++++++++---------------------------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/__init__.py b/__init__.py index 77e5744..f34808c 100644 --- a/__init__.py +++ b/__init__.py @@ -33,7 +33,6 @@ async def get_node_list(self) -> list[type[io.ComfyNode]]: krita.KritaSelection, krita.KritaImageLayer, krita.KritaMaskLayer, - krita.KritaGroupLayer, krita.Parameter, krita.KritaStyle, krita.KritaStyleAndPrompt, diff --git a/krita.py b/krita.py index 1ec5e09..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): @@ -259,29 +279,6 @@ def execute(cls, name: str): return io.NodeOutput(torch.ones(1, 512, 512)) -class KritaGroupLayer(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ETN_KritaGroupLayer", - display_name="Krita Group Layer", - description="Returns a list of images / masks / names from a group layer.", - category="krita", - inputs=[ - io.String.Input("name", default="Group"), - ], - outputs=[ - 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, mode): - return io.NodeOutput([_placeholder_image()], [torch.ones(1, 512, 512)], [""]) - - _param_types = [ "auto", "number", From ca4e8c6bdac47a10355c7e7ae41fc941cbe9a5d9 Mon Sep 17 00:00:00 2001 From: Pauan Date: Thu, 2 Apr 2026 22:55:15 -0700 Subject: [PATCH 3/3] Now supports sending lists of any type --- nodes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodes.py b/nodes.py index 9a39af2..17dda57 100644 --- a/nodes.py +++ b/nodes.py @@ -42,13 +42,13 @@ def define_schema(cls): category="external_tooling", inputs=[ io.AnyType.Input("list"), - io.String.Input("item"), + io.AnyType.Input("item"), ], outputs=[io.AnyType.Output()], ) @classmethod - def execute(cls, list: list[Any], item: str): + def execute(cls, list: list[Any], item: Any): list = list.copy() list.append(item) return io.NodeOutput(list)