simple_node - chrisgoringe/Comfy-Custom-Node-How-To GitHub Wiki
A really simple custom node explained
Here's a custom node which has one (image) input and one (image) output, and simply inverts the image.
class SimpleCustomNode:
@classmethod
def INPUT_TYPES(cls):
return {
"required": { "image_in" : ("IMAGE", {}) },
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image_out",)
FUNCTION = "invert"
CATEGORY = "examples"
def invert(self, image_in):
image_out = 1 - image_in
return (image_out,)
The code defines the inputs (INPUT_TYPES
), the outputs (RETURN_TYPES
and RETURN_NAMES
), the actual function (FUNCTION
and invert
), and where to find it in the add nodes menu (CATEGORY
).
CATEGORY
is where the node will be found in the ComfyUI 'Add Node' menu. So the example above will put the custom node under a menu item 'examples'. You can do a path to get submenus (like CATEGORY = "examples/simple"
will make a submenu simple inside the menu examples (like "latent/inpaint" in the built in nodes).
FUNCTION
is the name of the function that the node will call when it is executed (in this case, invert
).
RETURN_TYPES
is a tuple of strings that specify the data type of the outputs. Notice that trailing comma in ("IMAGE",)
? That's because python would interpret ("IMAGE")
as a string, and then when that gets treated as an interator, it would give "I"
, then "M"
, then...
RETURN_NAMES
is a tuple of string that specify the name of the outputs. It's optional - if you don't provide RETURN_NAMES
, RETURN_TYPES
is used.
INPUT_TYPES
specifies the inputs, and this is the only complicated bit. Notice that it's a @classmethod
. The method returns a dictionary which must contain the key required
, and may also include optional
and hidden
. Each of these keys has, as it's value, another dictionary. This inner dictionary has one key-value pair for each input - the key are the names of the input nodes, and the values are a tuple (str, dict), where the string is the type of the input node, and the dict provides additional parameters (things like default values, min and max, etc..)
So in the example we specify one required input, named image_in
, which is an IMAGE (for which there are no additional parameters).
Then there's the function itself: invert
(as named in the FUNCTION
class attribute). It will be passed keyword arguments with names that match the input names specified in INPUT_TYPES
- so it's invert(self, image_in)
because image_in
was a key in the dictionary INPUT_TYPES returned. Required inputs will always be provided, optional ones will be provided if the input had something attached to it, hidden inputs will be provided if they are available.
The function returns a tuple matching (in order) the RETURN_TYPES
. Again, notice the trailing comma!
That's it. Now just deploy it.